What is an 'error dispatch' in servlet processing? - java

The javadoc of the javax.servlet.AsyncContext interface says:
In the event that an asynchronous operation has timed out, the
container must run through these steps:
Invoke, at their onTimeout method, all AsyncListener instances registered with the ServletRequest on which the asynchronous
operation was initiated.
If none of the listeners called complete() or any of the dispatch() methods, perform an error dispatch with a status code
equal to HttpServletResponse.SC_INTERNAL_SERVER_ERROR.
If no matching error page was found, or the error page did not call complete() or any of the dispatch() methods, call complete().
But I couldn't find the meaning of "error dispatch" anywhere.
In fact there was an Apache bug that exclaimed the same. (In their exact words: "I haven't seen the def. of 'error dispatch', too")
But of course, there must be a clear definition for this and how to use it.
Does anyone know?

Dispatches made by the container during exceptions/errors are called error dispatches. These are usually dispatches to error pages. There is no way to directly do an error dispatch as I know it.
A request that has come through an error dispatch will have dispatcher type set to DispatcherType.ERROR. (In the servlet's service method code, you can get the dispatch type using getDispatcherType())
The following six request scoped attributes will also be set in error dispatches.
"javax.servlet.error.exception"
"javax.servlet.error.exception_type"
"javax.servlet.error.message"
"javax.servlet.error.request_uri"
"javax.servlet.error.servlet_name"
"javax.servlet.error.status_code"
So if you have an error page to which the container redirects errors, you know you can read those six attributes for more information.
http://docs.oracle.com/javaee/6/api/javax/servlet/DispatcherType.html
http://docs.oracle.com/javaee/6/api/javax/servlet/RequestDispatcher.html
You can setup an error dispatch by using tag in deployment descriptor (web.xml). For example if you added an error-page tag for 404 error code, then the container will dispatch to that page when a page not found error occurs. In that error page, you can use code like request.getAttribute("javax.servlet.error.message") to retrieve details about the error. Example ...
web.xml :
<web-app>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
</web-app>
error.jsp :
<!DOCTYPE html>
<html>
<head>
<title>404 Error</title>
</head>
<body>
The page was not found. You requested <%= request.getAttribute("javax.servlet.error.message") %> but it was not found. Sorry.
</body>
</html>
In the above sample application, if a client requested page is not found or you use response.sendError("404", "...") somewhere, the container will do an error dispatch to error.jsp.
The JSP error handling mechanism (using "errorPage" and "isErrorPage" page directives) also applies here.

Another information which is not directly related to the question but which I have seen not clearly mentioned in almost all places, including the answer above is that the error dispatch is technically NOT "redirect", it's rather internal forward. For beginners this might seem confusing as its usually written all over as "container does the redirect to the error page". So the moment your container sees an http error code / uncaught exception being sent by any of the resource it begins to look into the web xml to see if there are any handler defined and if present then it appropriately forwards the request to that resource using a request dispatcher. Then obviously all the information mentioned in the above answer applies.
If some one however wants to do an redirect, they can do so in filter or servlet or from anywhere they have response object available.

Related

Hide JSPs from FacesContext

I have a JSF application with a Servlet Filter configured for a urlPattern of /faces/*.
I want to hide a JSP from faces context so that it won't go through the Servlet Filter.
So I kept it under WebContent folder of my project as WebContent/Error.jsp and declared like the following in the web.xml:
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/Error.jsp</location>
</error-page>
But my Error.jsp never gets picked up. Instead I see 404 Page not found error.
To be more clear, I want my Error.jsp page URL to be:
http://localhost:8080/myappname/Error.jsp
But it is only reachable by:
http://localhost:8080/myappname/faces/Error.jsp
The same is the case when I declare any view-id in the faces-config.xml. Where do I keep the error JSP if I want to hide it from faces context?
Based on the information given so far, it looks as it should just work fine. You don't have a <dispatcher>ERROR</dispatcher> on the filter, so the filter should not be invoked at all whenever the NPE is thrown.
Apparently the NPE got wrapped up in another exception because it's been thrown at an illogical place such as bean's constructor instead of a normal bean action method. In such case, JSF would rethrow it as a ManagedBeanCreationException. The container would get it instead of the NPE and thus won't be able to locate the error page. In the container's default HTTP 500 error page, you should read the topmost exception of the stacktrace in order to determine the right exception to define an error page for.
Please keep in mind that runtime exceptions like NPEs are developer errors (bugs!), not production errors and that they should be fixed ASAP. I'd personally just use a global HTTP 500 error page for this kind of bugs:
<error-page>
<status-code>500<status-code>
<location>/errors/generic.jsp</location>
</error-page>
For more specific, real production exceptions, you can always declare a more specific error page:
<error-page>
<exception-type>com.example.YourDatabaseAccessException</exception-type>
<location>/errors/database.jsp</location>
</error-page>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/errors/sessionexpired.jsp</location>
</error-page>
If you define a filter and declear that in your web.xml, all the request will go through that filter, unless you define the filter mapping.
I think you can define a filter mapping in your web.xml as following:
<filter>
<filter-name>URLFilter</filter-name>
<filter-class>the filter class in your source code</filter-class>
</filter>
<filter-mapping>
<filter-name>URLFilter</filter-name>
<url-pattern>/some pages</url-pattern>//skip error.jsp here
</filter-mapping>
this is not tested, but just an inspiration.
edit: you can find out more from Oracle site
To me it doesn't sound like the Faces filter has anything to do with this issue. Can you reach http://localhost:8080/myappname/Error.jsp with the filter completely disabled? If not, then perhaps there is some issue with the Error.jsp file itself?
It's hard to say without seeing the code itself.

Custom 500 error page using JSF - is the full error message available?

In my web.xml the 500 error is handled by a JSF page:
<error-page>
<error-code>500</error-code>
<location>/errorpage.html</location>
</error-page>
If the container handles a 500 error and calls this JSF page, is there a request parameter or body content in the request which contains the full error message?
So for example if I use this code in a Servlet to provide a error description with the 500 error:
response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR, "Some error message");
is there a standard way to get the text "Some error message" from the request?
It's available as request attribute with the key of RequestDispatcher#ERROR_MESSAGE which is "javax.servlet.error.message". So, this should do:
<p>The error message is: #{requestScope['javax.servlet.error.message']}</p>
(note: I'm assuming that you're using Facelets; for JSP you'd have to put it in <h:outputText>)

Most efficient JSF 1.2 navigation by java

I've got a dropdown on my index.xhtml JSF front page. The associated code/commandButton looks like this:
<h:selectOneMenu id="nodes" value="#{MyBacking.chosenNode}">
<f:selectItems value="#{MyBacking.nodes}" />
</h:selectOneMenu>
<a4j:commandButton value="Retrieve" styleClass="ctrlBtn"
id="retrieveBtn" style="margin-bottom: 2px;"
onclick="#{rich:component('nodeLoadWait')}.show()" # modal
action="#{MyBacking.redirect}"
image="/img/btnRetrieve26.png" />
action was set to 'hello' previously, and in my faces-context.xml:
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-outcome>hello</from-outcome>
<to-view-id>/nodeMgmt.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
When action was set to 'hello', clicking the retrieve button worked OK in that faces would handle the nav and MyBacking.setChosenNode method would assign all the necessary data, so that the content of nodeMgmt.xhtml would be displayed fully populated.
However, if the initial activity caused by the user clicking retrieve times out, the web page would hang even though the bean detects the time out, and I'd like to redirect the user to a 'timed out' page.
In order to handle the backing bean returning a timedout message (the error detection for which is already present when 'inside' the app), I thought rather than using the faces-context.xml file, I would handle it internally.
I found FacesContext.getCurrentInstance().getExternalContext().redirect but the JSF 1.2 javadoc does not feature this. Perhaps it's because it's not featured? It redirects though which is confusing. Why no documentation on this method?
Nonetheless, it redirects me to the page, but renders without taking into account the data instantiated by the bean during the initial request. The bean is in request scope currently. The relevant code in the bean is
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("nodeMgmt.jsf");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Is using a backend java call the best way to do this kind of redirection?
If not, is it best to use faces-context.xml? If so, how?
While we're here - can anyone direct me to a good reading resource for FacesContext.getCurrentInstance().getExternalContext() usage which has decent examples about how to do simple navigation with data cos I'm having trouble locating one.
Cheers
I found FacesContext.getCurrentInstance().getExternalContext().redirect but the JSF 1.2 javadoc does not feature this. Perhaps it's because it's not featured? It redirects though which is confusing. Why no documentation on this method?
There certainly is.
JSF 1.1: ExternalContext#redirect()
Java EE 5 (JSF 1.2): ExternalContext#redirect()
Java EE 6 (JSF 2.0): ExternalContext#redirect()
Probably you was reading the wrong javadoc. The one of FacesContext perhaps?
Nonetheless, it redirects me to the page, but renders without taking into account the data instantiated by the bean during the initial request. The bean is in request scope currently.
A redirect instructs the browser to fire a brand new HTTP request. So all request scoped beans from the old request will be garbaged and reinitialized in the new request. If you'd like to retain the request, you'd like to use a forward instead (which JSF by default uses), but this isn't going to work on ajax-initiated requests as it will stick to the same page anyway. Only a response with a redirect will force Ajax to change the window location using JavaScript.
If you want to retain some parameters in the new request, you'd have to pass them as request parameters. E.g.
externalContext.redirect("nodeMgmt.jsf?foo=bar");
and set them as managed property in the bean.

http status 404 : the required resource is not found

I creat a web application using eclipse and tomcat7 I had the following code in the html file and the java servlet class
in the html file:
<form action="UserAccessServlet" method = "get">
in the servlet class I had
#WebServlet ("/UserAccessServlet")
then I just made some small changes (new println statements) but it shows no effect I changed the server name with the following peice of code
html file: <form action="SQA_Servlet" method = "get">
java class: #WebServlet ("/SQA_Servlet")
but it seems that no reload take place and I got the following error:
HTTP Status 404 - /SQA_Learning/SQA_Servlet
--------------------------------------------------------------------------------
type Status report
message /SQA_Learning/SQA_Servlet
description The requested resource (/SQA_Learning/SQA_Servlet) is not available.
I tried clean the module, refresh, close the reopen the project with the same result
I replaced #WebServlet ("/SQA_Servlet") with #WebServlet(urlPatterns={"/SQA_Servlet"})
and still have no effect.. any suggestion.
The WebServlet name attribute cannot start with a /. Rather do,
#WebServlet("UserAccessServlet")
or leave it blank (if you want the WebServlet to use the name of your Servlet class name. Example:
#WebServlet
public class UserAccessServlet extends HttpServlet {
//Do stuff
}
I would recommend declaring your WebServlet annotations fully like in this example.
I'm not sure when and in what for conditions you are receiving this error. But if you are deploying to tomcat, the following might occur:
Assuming your webapp is called "my.webapp" resulting in my.webapp.war
assuming you have a Servlet "servlet1" which performs action1 => #WebServlet(urlPatterns = "/action1") (note the slash in front of action1)
Assuming you are calling this action with a html form:
<form action="/action1" method="GET"> this might not work because of the slash in front of action1
When it's there tomcat will redirect to localhost:8080/action1?..
while it should redirect to localhost:8080/my.project/action1?..
Solution alter the html so the form looks like:
<form action="action1" method="GET">, don't change the #WebServlet(urlPatterns = "/action1")
Hope this helps someone!

what's the right technique to redirect an Exception from a Servlet to a default error JSP?

I need to have a default error JSP page which is shown when an exception is thrown by the servlet, and that page will show the stacktrace..
How do I do that?? is there a right technique (provided by the API) or I have to do it manually?? I mean, sending the exception thrown as an attribute and then dealing with it by myself??
Thanks
You can configure the exception type and the JSP page to handle in web.xml, e.g:
<error-page>
<exception-type>UnhandledException</exception-type>
<location>UnhandledException.jsp</location>
</error-page>
There's an Oracle article here on the subject:
http://www.oracle.com/technology/sample_code/tech/java/codesnippet/servlets/HandlingServletExceptions/HandlingServletExceptions.html

Categories