How to debug missing resource/reference on xhmtl? - debugging

Sometimes I get an exception on my filter, in line:
chain.doFilter(request, response);
And, after a long search, I'll discover that some xhtml file referenced in another xhtml file was missing, or was not declared in faces-config.xml.
And I search the problem by deleting the elements of the xhtml file and see where the exception stops to occur.
Is there a better way to debug this?

Add an exception handler factory that handles the exceptions, and redirect or forward to an error page or login page.
Good logging in this will help you find the error easily and help you fix the issue sooner.
web.xml:
<factory>
<exception-handler-factory>com.framework.exceptionmgmt.CustomExceptionHandlerFactory</exception-handler-factory>
</factory>
factory:
#Override
public ExceptionHandler getExceptionHandler() {
return new CustomExceptionHandler(wrapped.getExceptionHandler());
}
/**
* Returns the wrapped factory.
*/
#Override
public ExceptionHandlerFactory getWrapped() {
return wrapped;
}
handler:
#Override
public void handle() throws FacesException {
for (final Iterator<ExceptionQueuedEvent> it = getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();) {
Throwable t = it.next().getContext().getException();
System.out.println("Exception in page: "+t.getMessage());
while ((t instanceof FacesException || t instanceof EJBException || t instanceof ELException) && t.getCause() != null) {
t = t.getCause();
}
if (t instanceof FileNotFoundException || t instanceof ViewExpiredException) {
final ExternalContext externalContext = facesContext.getExternalContext();
final Map<String, Object> requestMap = externalContext.getRequestMap();
try {
// Log the information in the logs
String message;
if (t instanceof ViewExpiredException) {
final String viewId = ((ViewExpiredException) t).getViewId();
message = "View is expired. <a href='/ifos" + viewId + "'>Back</a>";
} else {
message = t.getMessage(); // beware, don't leak internal
// info!
}
requestMap.put("errorMsg", message);
try {
HttpServletRequest origRequest = (HttpServletRequest) facesContext.getExternalContext()
.getRequest();
String requestedURL = origRequest.getRequestURL().toString();
resetResponse(facesContext);
redirectToCorrectPage(origRequest.getContextPath()+"/error.xhtml",facesContext);
} catch (final IOException e) {
}
facesContext.responseComplete();
} finally {
it.remove();
}
}else{
try {
resetResponse(facesContext);
Map<String, Object> sessnMap = FacesContext
.getCurrentInstance().getExternalContext()
.getSessionMap();
// For checking whether user is logged in or not If not then redirect to login page instead of error page
Boolean isUserLoggedIn = (Boolean) sessnMap
.get("isUserLoggedIn");
if (isUserLoggedIn == null || !isUserLoggedIn) {
redirectToCorrectPage(
((HttpServletRequest) facesContext
.getExternalContext().getRequest()).getContextPath()
+ "/error.xhtml",
facesContext);
} else {
redirectToCorrectPage(
((HttpServletRequest) facesContext
.getExternalContext().getRequest()).getContextPath()
+ "/error.xhtml",
facesContext);
}
} catch (final IOException e) {
}finally {
it.remove();
}
facesContext.responseComplete();
}
}

Related

Spring boot application filter response body

I am working on a spring boot application. I want to modify the response of the request by request body field "Id".
I have implemented below, but still getting just the name in the output while implementing.Any suggestions on implementing below would be helpful:
Below is the requestBody:
{
"id" : "123"
}
In response, I want to append that field to response id(fieldname from request body).
responseBody:
{
"name" : "foo123" //name + id from request
}
MyCustomFilter:
public class TestFilter implements Filter {
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(baos);
MultiReadHttpServletRequest wrapper = new MultiReadHttpServletRequest((HttpServletRequest) request);
MyRequestWrapper req = new MyRequestWrapper(wrapper);
String userId = req.getId();
chain.doFilter(wrapper, new HttpServletResponseWrapper(res) {
#Override
public ServletOutputStream getOutputStream() throws IOException {
return new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps)
);
}
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps))
);
}
});
String responseBody = baos.toString();
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(responseBody);
String name = node.get("name").astext();
((ObjectNode) node1).put("name", name + userId);
chain.doFilter(wrapper, res);
}
MyRequestWrapper:
public class MyRequestWrapper extends HttpServletRequestWrapper {
private ServletInputStream input;
public MyRequestWrapper(ServletRequest request) {
super((HttpServletRequest)request);
}
public String getId() throws IOException {
if (input == null) {
try {
JSONObject jsonObject = new JSONObject(IOUtils.toString(super.getInputStream()));
String userId = jsonObject.getString("id");
userId = userId.replaceAll("\\D+","");
return userId;
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}
MultiReadHttpServletRequest.java
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
private byte[] body;
public MultiReadHttpServletRequest(HttpServletRequest request) {
super(request);
try {
body = IOUtils.toByteArray(request.getInputStream());
} catch (IOException ex) {
body = new byte[0];
}
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
}
#Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStream() {
ByteArrayInputStream wrapperStream = new ByteArrayInputStream(body);
#Override
public boolean isFinished() {
return false;
}
#Override
public boolean isReady() {
return false;
}
#Override
public void setReadListener(ReadListener readListener) {
}
#Override
public int read() throws IOException {
return wrapperStream.read();
}
};
}
}
Any suggestions are appreciated. TIA.
Nte: After update i am not able to see the updated response as output. I am still seeing just the name but not id appended to it.
The one issue I see with your own implementation of ServletRequest is that you call super.getInputStream() instead of request.getInputStream(). Your own request is empty by default, that's why you're getting time out exception. You have to delegate a call to the actual request:
public class MyRequestWrapper extends HttpServletRequestWrapper {
private ServletInputStream input;
public MyRequestWrapper(ServletRequest request) {
super((HttpServletRequest)request);
}
public String getId() throws IOException {
if (input == null) {
try {
JSONObject jsonObject = new JSONObject(IOUtils.toString(/*DELETEGATE TO ACTUAL REQUEST*/request.getInputStream()));
String userId = jsonObject.getString("id");
userId = userId.replaceAll("\\D+","");
return userId;
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}

#Retryable is not working when calling from a method

Below is my application class. The flow is like the DEToken class from here and from DEToken I call RestConnection where I have the #retryable method.
#SpringBootApplication
#EnableRetry
public class SpringBootTrfficApplication implements CommandLineRunner {
Enter code here
#Autowired
DEToken deToken;
#Autowired
SyncService syncService;
public static void main(String[] args) {
SpringApplication.run(SpringBootTrfficApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
deToken.getToken();
}
}
DEToken class: from getToken I am calling RestConnect where I have the #Retrable method:
#Service
public class DEToken {
private Logger logger = LogManager.getLogger(getClass());
#Autowired
RestConnection restConnection;
#Autowired
private Environment env;
public String accessToken;
public void getToken() {
System.out.println("hello from get token");
//String getJsonPayload = "{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
//env.getProperty("provider.ins") + "}}}";
//String str = restConnection.restPost(
// env.getProperty("rest.de.url"), getJsonPayload);
try {
String getJsonPayload =
"{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
env.getProperty("provider.ins") + "}}}";
StringBuffer tokenResult =
restConnection.restPost(env.getProperty("rest.de.url"),
getJsonPayload);
System.out.println(tokenResult);
JSONObject xmlJSONObj = XML.toJSONObject(tokenResult.toString());
JSONObject registration = new JSONObject();
if (xmlJSONObj.has("Registration")) {
registration = xmlJSONObj.getJSONObject("Registration");
if (registration.has("accessToken")) {
accessToken = registration.get("accessToken").toString();
}
else
logger.info("no accessToken from DE");
}
else
logger.info("no Registration object from DE");
}
catch (Exception e) {
logger.error("Exception while fetching accesstoken from DE ");
logger.error(e.getMessage());
}
}
}
My REST connection class where I have retryable method:
#Service
public class RestConnection {
private Logger logger = LogManager.getLogger(getClass());
#Autowired
private Environment env;
public void setBaseUrl(String value, String ip) {
//baseUrl = value;
HttpsURLConnection.setDefaultHostnameVerifier(
(hostname, session) -> hostname.equals(ip));
}
/*
* REST post call
*/
#Retryable(value = {IOException.class, ConnectException.class},
maxAttempts = 4,
backoff = #Backoff(5000))
public StringBuffer restPost(String restUrl, String payload) {
StringBuffer sb = new StringBuffer();
HttpURLConnection conn = null;
try {
URL url = new URL(restUrl);
String protocol = url.getProtocol();
if (protocol.toLowerCase().equals("http")) {
conn = (HttpURLConnection)url.openConnection();
}
else if (protocol.toLowerCase().equals("https")) {
//setTrustedCert();
conn = (HttpsURLConnection)url.openConnection();
}
else {
logger.info("Protocol is neither HTTP nor HTTPS");
}
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("version", env.getProperty("de.version"));
conn.setRequestProperty("accessToken", env.getProperty("access.token"));
conn.setRequestProperty("requestHost", env.getProperty("server.de.host"));
conn.setRequestProperty("requestPort", env.getProperty("server.port"));
conn.setRequestProperty("requestProtocol",
env.getProperty("server.de.protocol"));
PrintWriter pout =
new PrintWriter(
new OutputStreamWriter(
conn.getOutputStream(), "UTF-8"),
true);
pout.print(payload);
pout.flush();
pout.close();
InputStream isi = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(isi);
int numCharsRead1;
char[] charArray1 = new char[1024];
while ((numCharsRead1 = isr.read(charArray1)) > 0) {
sb.append(charArray1, 0, numCharsRead1);
}
isr.close();
isi.close();
}
catch (MalformedURLException e) {
logger.error("MalformedURLException in restAccessTokenPOST..." +
e.getMessage());
//e.printStackTrace();
}
catch (IOException e) {
logger.error("IOException in restAccessTokenPOST..." +
e.getMessage());
e.printStackTrace();
}
catch (Exception e) {
logger.error("Exception in restAccessTokenPOST..." +
e.getMessage());
e.printStackTrace();
}
finally {
if (null != conn)
conn.disconnect();
}
return sb;
}
#Recover
public String helpHere(ConnectException cause) {
System.out.println("Recovery place! ConnectException");
return "Hello";
}
#Recover
public String helpHere(IOException cause) {
System.out.println("Recovery place! ArithmeticException");
return "Hello";
}
#Recover
public String helpHere(Exception cause) {
System.out.println("Recovery place! Exception");
return "Hello";
}
#Recover
public String helpHere() {
System.out.println("Recovery place! Exception");
return "Hello";
}
#Recover
public String helpHere(Throwable cause) {
System.out.println("Recovery place! Throwable");
return "Hello";
}
}
Considering you see your function restPost() implementation,
#Retryable(value = {IOException.class, ConnectException.class},
maxAttempts = 4,
backoff = #Backoff(5000))
public StringBuffer restPost(String restUrl, String payload) {
try {
// Your code
}
catch(IOException ex){ // These catch block handles the exception
// and nothing to throw to retryable.
}
catch(MalformedURLException ex){ // More catch blocks that you
// define to handle exception.
}
}
Here you handle all of the exceptions that can be a cause to revoke the retry and recover methods.
Note: Recoverable methods only execute when a exception is thrown, not handled by any try-catch block.
Whatever exception is raised by method restPost() is handled by the method try-catch block itself and there are no exceptions that had been rethrow by a catch block.
Now, Spring-Retry is unable to get any exception (because it is handled by the method try-catch block). So, no recovery method will be executed.
Solution: you should remove those catch blocks from the method definition on which you want to perform retry or recover.
Please do the needful and it will work like a charm... :)

Spring Integration: Custom Splitter with Header Enrichment

Is it possible to have an implementation of a message splitter that can return an Iterator AND add custom header information?
For instance if I have the following class
public class CsvFileToIteratorSplitter extends AbstractMessageSplitter {
#Override
protected Object splitMessage(Message<?> message) {
Object payload = message.getPayload();
Assert.isInstanceOf(File.class, payload, "Expected java.io.File in the message payload");
try {
InputStream source = new FileInputStream((File) payload);
BufferedReader reader = new BufferedReader(new InputStreamReader(source));
String header = reader.lines().findFirst().orElse(null);
return MessageBuilder.withPayload(reader.lines().iterator())
.setHeaderIfAbsent("HEADER", header)
.build();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
Then I can add to the header but the payload is actually an instance of Iterator and the split fails
If I modify so that the class is now
public class CsvFileToIteratorSplitter extends AbstractMessageSplitter {
#Override
protected Object splitMessage(Message<?> message) {
log.debug("{}", message.toString());
Object payload = message.getPayload();
Assert.isInstanceOf(File.class, payload, "Expected java.io.File in the message payload");
try {
InputStream source = new FileInputStream((File) payload);
BufferedReader reader = new BufferedReader(new InputStreamReader(source));
return reader.lines().iterator();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
The split works but I lose the header info.
Is there any way to have a functioning split with the ability to add to the header?
You should return an Iterator<MessageBuilder<String>> ...
#SpringBootApplication
public class So44604817Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(So44604817Application.class, args);
context.getBean("in", MessageChannel.class).send(new GenericMessage<>(new File("/tmp/foo.txt")));
context.close();
}
#Bean
#Splitter(inputChannel = "in")
public MySplitter splitter() {
MySplitter splitter = new MySplitter();
splitter.setOutputChannelName("out");
return splitter;
}
#Bean
public MessageChannel out() {
return new MessageChannel() {
#Override
public boolean send(Message<?> message) {
return send(message, -1);
}
#Override
public boolean send(Message<?> message, long timeout) {
System.out.println(message);
return true;
}
};
}
public static class MySplitter extends AbstractMessageSplitter {
#SuppressWarnings("resource")
#Override
protected Object splitMessage(Message<?> message) {
Object payload = message.getPayload();
Assert.isInstanceOf(File.class, payload, "Expected java.io.File in the message payload");
try {
InputStream source = new FileInputStream((File) payload);
final BufferedReader reader = new BufferedReader(new InputStreamReader(source));
final String header = reader.lines().findFirst().orElse(null);
final Iterator<String> iterator = reader.lines().iterator();
Iterator<MessageBuilder<String>> builderIterator = new Iterator<MessageBuilder<String>>() {
private String next;
#Override
public boolean hasNext() {
if (this.next != null) { // handle multiple hasNext() calls.
return true;
}
if (!iterator.hasNext()) {
try {
reader.close();
}
catch (IOException e) {
e.printStackTrace();
}
return false;
}
else {
this.next = iterator.next();
// Handle empty last line
if (next.length() == 0 && !iterator.hasNext()) {
try {
reader.close();
}
catch (IOException e) {
e.printStackTrace();
}
return false;
}
return true;
}
}
#Override
public MessageBuilder<String> next() {
String line = this.next;
this.next = null;
return MessageBuilder
.withPayload(line).setHeaderIfAbsent("HEADER", header);
}
};
return builderIterator;
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
}
Note that your skip(1) is incorrect, since the first line has already been consumed from the reader.
With file:
FOO,BAR
foo,bar
baz.qux
result:
GenericMessage [payload=foo,bar, headers={sequenceNumber=1, HEADER=FOO,BAR, correlationId=42ce2e1f-5337-1f75-d4fe-0d7f366f76f1, id=94e98261-fd49-b4d0-f6a0-3181b27f145b, sequenceSize=0, timestamp=1497713691192}]
GenericMessage [payload=baz.qux, headers={sequenceNumber=2, HEADER=FOO,BAR, correlationId=42ce2e1f-5337-1f75-d4fe-0d7f366f76f1, id=c0b1edd6-adb9-3857-cb7c-70f603f376bc, sequenceSize=0, timestamp=1497713691192}]
JIRA Issue INT-4297 to add this functionality to FileSplitter.

Spring Security Custom AuthenticationProvider Login post give 302 error

I have implement custom AuthenticationProvider spring login security. When i post it using its /login url it gives me 302 HTTP status code. whats the issue in that i have on custom filter for every request for handle every request
Filter
public class AppFilter implements Filter {
private Logger logger = Logger.getLogger(AppFilter.class);
private CommonService commonService;
public AppFilter() {}
public void destroy() {}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
try {
if (httpServletRequest.getRequestURI().contains("/resources/")) {
filterChain.doFilter(httpServletRequest, servletResponse);
}
else {
HttpSession session = httpServletRequest.getSession();
if(session != null && session.getAttribute(CommonConstant.XXX) == null) {
List<Map<String, Object>> clientDetails = commonService.getXXX(XX);
if (clientDetails != null && !clientDetails.isEmpty()){
session.setAttribute(CommonConstant.CLIENT_SESSION_DATABEAN, clientSessionDataBean);
}
}
HttpServletRequest request = new CustomHttpServletRequestWrapper(httpServletRequest);
filterChain.doFilter(request, servletResponse);
}
} catch (Exception e) {
logger.error(httpServletRequest.getRequestURI(), e);
servletRequest.getRequestDispatcher("/WEB-INF/views/common/unauthorized-access.jsp").forward(servletRequest, servletResponse);
}
}
public void init(FilterConfig arg0) throws ServletException {
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(arg0.getServletContext());
commonService = ctx.getBean(CommonService.class);
}
class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> allReqParam;
public CustomHttpServletRequestWrapper(HttpServletRequest request) throws Exception {
super(request);
allReqParam = new TreeMap<String, String[]>();
if(ServletFileUpload.isMultipartContent(request)) {
allReqParam = request.getParameterMap();
List<FileItem> multipartItems = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem multipartItem : multipartItems) {
if (multipartItem.isFormField()) {
processFormField(multipartItem, allReqParam);
} else {
processFileField(multipartItem, request);
}
}
} else {
Map<String, String[]> reqParamMap = super.getParameterMap();
if(reqParamMap != null && !reqParamMap.isEmpty()) {
for(Entry<String, String[]> entry : reqParamMap.entrySet()) {
String paramName = entry.getKey();
String[] paramValue = entry.getValue();
identifyHiddenFields(paramName, paramValue);
}
}
}
}
/**
* Process multipart request item as regular form field. The name and value of each regular
* form field will be added to the given parameterMap.
* #param formField The form field to be processed.
* #param parameterMap The parameterMap to be used for the HttpServletRequest.
* #throws Exception
*/
private void processFormField(FileItem formField, Map<String, String[]> parameterMap) throws Exception {
String name = formField.getFieldName();
String value = formField.getString();
String[] values = null;
if(parameterMap != null && !parameterMap.isEmpty()) {
values = parameterMap.get(name);
}
if (values == null) {
identifyHiddenFields(name, new String[] {value});
} else {
int length = values.length;
String[] newValues = new String[length + 1];
System.arraycopy(values, 0, newValues, 0, length);
newValues[length] = value;
allReqParam.put(name, newValues);
identifyHiddenFields(name, newValues);
}
}
/**
* Process multipart request item as file field. The name and FileItem object of each file field
* will be added as attribute of the given HttpServletRequest. If a FileUploadException has
* occurred when the file size has exceeded the maximum file size, then the FileUploadException
* will be added as attribute value instead of the FileItem object.
* #param fileField The file field to be processed.
* #param request The involved HttpServletRequest.
* #throws IOException
*/
private void processFileField(FileItem fileField, HttpServletRequest request) throws IOException {
request.setAttribute(fileField.getFieldName(), fileField);
allReqParam.put(fileField.getFieldName(), new String[] {fileField.toString()});
}
private void identifyHiddenFields(String paramName, String[] paramValue) throws Exception {
if(paramName.startsWith("hidden")) {
String[] tParamVal = new String[paramValue.length];
for(int i=0; i < paramValue.length; i++) {
tParamVal[i] = AppCryptoUtil.decryptHV(paramValue[i]);
}
allReqParam.put(paramName.substring(6), tParamVal);
} else {
allReqParam.put(paramName, paramValue);
}
}
#Override
public String getParameter(final String name) {
String[] strings = allReqParam.get(name);
if (strings != null) {
return strings[0];
}
return super.getParameter(name);
}
#Override
public Map<String, String[]> getParameterMap() {
return Collections.unmodifiableMap(allReqParam);
}
#Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(getParameterMap().keySet());
}
#Override
public String[] getParameterValues(final String name) {
return getParameterMap().get(name);
}
}
}

Spring MVC - calling methods in #ResponseBody

I am Spring MVC beginner and I want to call rest in #ResponseBody. My external node server doesn't react on that method. I don't got message about request in my server console. Without UserRest it works. I would be grateful for your help
#Controller
public class AjaxController {
#RequestMapping(value= "user", method=RequestMethod.GET)
public #ResponseBody String login (){
UserRest ur = new UserRest();
Response r = ur.getUserName(2);
Gson gs = new Gson();
String str = gs.toJson(r);
return str;
}
}
Response getUserName(int userID){
Response response = new Response();
StringBuilder total = new StringBuilder();
try {
URL url = new URL(Properties.SERVER_SECURE_URL + "users/" + userID);
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setDoOutput(false);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("GET");
urlConnection.setRequestProperty("Authorization","1Strajk");
response.setMessageCode(urlConnection.getResponseCode());
if(response.getMessageCode()==Response.MESSAGE_OK) {
InputStream in = urlConnection.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = r.readLine()) != null) {
total.append(line);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(!total.toString().isEmpty()){
response.setObject(total.toString());
}
urlConnection.disconnect();
}
return response;
}
I resolve it. I forgot about SSL connection. Before calling rest I called that method:
public class SSLUtils {
public static void trustEveryone() {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
} catch (Exception e) { // should never happen
e.printStackTrace();
}
}
}

Resources