I asked a question along similar lines yesterday as well. In that question I was suggested to have a global filter (which I already had).
So I have a JSP like below
....code...code
..tags...html...code
Object [] res = iBatisDAO.getReport_pging(null,null,0,null); //call to DB
...more code...
...tags...end
In the above code I am intentionally passing null's because I want it to fail and when it fails I want it to go to our centralized error page. I have the following in my web.xml
<error-page>
<exception-type>com.ibatis.common.jdbc.exception.NestedSQLException</exception-type>
<location>/errorpages/Error.jsp</location>
</error-page>
<error-page>
<exception-type>org.springframework.dao.DataAccessException</exception-type>
<location>/errorpages/Error.jsp</location>
</error-page>
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/errorpages/Error.jsp</location>
</error-page>
<error-page>
<exception-type>java.sql.SQLException</exception-type>
<location>/errorpages/Error.jsp</location>
</error-page>
<error-page>
<exception-type>org.springframework.jdbc.UncategorizedSQLException</exception-type>
<location>/errorpages/Error.jsp</location>
</error-page>
the 'control' comes to the above JSP via a global filter that I have. it has chain.doFilter() wrapped in try/catch block. When exception happens it redirects to Error.jsp.
When the error happens...it is not being caught by the centralized error page and neither is it caught by the filter. I think filter is not catching it because when filter 'calls' the jsp...there IS no error yet.
I know call to DB is BAD inside a JSP but I am dealing with lot of legacy code.
What can I do to have errors go to centralized error page in this scenario? Also, the JSP does not have the error page imported. I would not want the option of importing an error page to all JSP's I want to have a more general solution.
Exceptions in JSP cannot be handled nicely, because it's too late to change the response. JSP as being a view technology is responsible for the whole response at its own. It sends the response headers and the response content. When the response headers are sent, then it's a point of no return. Even a filter ain't going to help here.
Whenever an exception occurs halfway a JSP, then the response will be abruptly aborted and the client will face a blank or a halfbaked page and the exception can at highest only be logged to the server log. Maybe along an IllegalStateException: response already committed whenever an attempt is made to redirect/forward/display the error page while that's impossible, because the response is already committed.
In short: do not write raw Java code in JSP files. Put them in Java classes such as (in)direct in a Servlet. It get processed before the JSP get displayed. This way there's plenty of room to change the destination of the response.
If you insist in using JSP for business logic (which I do not recommend), then an alternative is to put all the business logic to the top of the JSP file, before any template text (HTML and so on) is to be sent to the response. If you're lucky, the servletcontainer will be able to change the response to an error page whenever an exception is been thrown.
You've undertaken a wrong approach. You must not have any logic processing code (business logic) in your JSP files. JSP is a view technology. Use servlets or some action/component framework (Struts2 / Spring MVC / JSF / etc.) to handle the business logic.
As for the filter approach - it is a good solution, but the filter must be mapped to /* (using <filter-mapping>):
<filter>
<filter-name>exceptionFilter</filter-name>
<filter-class>com.yourpackage.YourFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>exceptionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Related
I have written a servlet filter which is configured to be invoked for each url (/*). On the basis of some condition, if the condition is passed, I want to proceed normal execution by chain.doFilter(request,response), I also want to open same request URL with error message..
"say value entered in particular textbox is incorrect". Is this possible?
Do I have to use response.sendRedirect(request.getURL())? I hope I wont end up in infinite loop as I have configured filter on each URL. I am doing validation check on request parameter.
Just do the same as you'd do in a servlet: perform a forward.
request.getRequestDispatcher("/WEB-INF/some.jsp").forward(request, response);
A filter is by default not (re)invoked on a forward. Additional advantage is that the JSP reuses the same request and thus you can just set the validation error messages as a request attribute without the need for session or cookie based workarounds/hacks.
Unrelated to the concrete problem, this isn't entirely the right approach. Form-specific validation job should be performed in a servlet, not in a filter. If you'd like to keep your servlet(s) DRY, then look at the front controller pattern or just adopt a MVC framework which already offers a front controller servlet and decent validation out the box, such as JSF or Spring MVC.
I want to be able to return a specific jsp page from restful service given the page name as a PathParam. These pages will be added and removed by a different group of people after the application is deployed.
I believe using the Viewable object is a decent way to go (I'm open to a better/correct way.)
#GET
#Produces(MediaType.TEXT_HTML)
#Path("{page}")
public Response showJSP(#PathParam("page") String page) {
Viewable loadPage = null;
try {
loadPage = new Viewable("/" + page, null);
} catch (Exception e) {
return Response.status(404).build();
}
Response ret = Response.ok(loadPage).build();
// if (ret.getStatus() == 500){
// ret = Response.status(404).build();
// }
return ret;
}
The above is my experimental code and contains my attempts to handle the error.
This works fine as long as the page name is a valid jsp page. If I pass in an invalid page I get
500 Internal Server Error
java.io.IOException: The template name, /someWrongFileName, could not be resolved to a fully qualified template name.....
What I've figured out is this error is generated internal to the Viewable object so it's not throwing an exception and the Response of course is a valid page so checking for the 500 status doesn't work.
I can hack in several things that I'm pretty sure are wrong such as, I really do not want to toString the generated page and regex for the error text.
I would like to be able to detect that the page is invalid and simply return a 404.
Am I on the right path or is there a better way?
If I'm on the right path how do I detect the bad page name?
I've tried catching the error like you did but it seems pretty hard. I suppose the class was never intended to be used this way.
The Viewable interface lets you use JSPs as a means to visualize the representation of your application's resources. In general, the resource is represented by a POJO that you serialize to JSON, XML or pass to the Viewable constructor.
As far as I understand, what you're trying to do here is a little different. Your resources are the JSPs themselves and it seems you only want to make the pages available to clients, without passing any objects to the Viewable constructor.
The HTTP 404 error means that a resource can not be found. In your case (while treating the JSPs as resources), when the path to a JSP is incorrect, this is exactly what happens so I understand why you want to use the status code.
However, I think that the creators of the interface you're trying to use had a different opinion on the matter. They didn't see the JSPs as resources but as a tool to represent them. The construction of a view is seen here as a completely different thing. A matter internal to the server and something that should be hidden from the client. The client has to receive a response with an HTML string in it. How it happens should not matter at all. An HTTP 500 is totally understandable in such context.
If you only want to use GET requests to fetch the contents of your JSPs, you can just ignore the Viewable interface or even Jersey itself. If your web.xml is appropriately set, the pages should be accessible anyway. You don't have to pass a JSP name to an annotated method. Just use paths to the documents themselves. Custom 404s can be dealt with in web.xml as well.
Assume that you have a project called MyApp and deployed to the path <host>:<port>/MyApp
With the following structure of its Web pages directory.
-Web pages
|-META-INF
|-WEB-INF
|-error
|\-error404.jsp
|-package1
||-ResourceClass
||\-page1.jsp
|-pages
||-plainpage1.jsp
|\-plainpage2.jsp
\-index.jsp
Now, let's assume the web.xml looks like this:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/resources/ *</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/err/err404.jsp</location>
</error-page>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
You can use the Viewable interface to show a page for your actual resource. This is how the interface is supposed to be used. As a means to show a resource's html representation, not the resource itself.
package package1;
#Path("/")
public class ResourceClass {
#Path("/POJO/{id}")
#GET
public Response tryToGetBadView(#PathParam("id") String id) {
MyPOJOClass entity = null;
//fetch your POJO from database/file/whatever
return Response.ok().entity(new Viewable("page1",entity)).build();
}
}
You can get the appropriate view using a path like:
<host>:<port>/MyApp/resources/POJO/1
while also being able to get the plain JSPs without the help of Jersey Servlet Container. The files are there and they don't need any other representation than themselves. The path to your Jersey Servlet Container is specified as
<host>:<port>/resources/*
So you can omit the container and reach normal files from your Web Apps folder. Images, css and also JSPs.
Like this:
<host>:<port>/MyApp/pages/plainpage1.jsp
the same way you get
<host>:<port>/MyApp/index.jsp
and even a page that you'd normally use to construct a Viewable object (without the guarantee that it would work properly without passing a POJO)
<host>:<port>/MyApp/package1/ResourceClass/page1.jsp
For these "static" files, you'll get a 404 every time you pick a name of a non-existent page. The error page displayed will be the one specified in web.xml
This is how I'd do it. Using Jersey to serve plain JSPs seems like an overkill and brings unnecessary complication. If it's not what you meant, I suggest rethinking the design.
Notice that while Jersey is not used, the pages can still be accessed in a way you can consider RESTful.
If you really want to stick to your experimantal code, you can also try accessing the directories in your Web Pages folder using the IO API and checking manually whether the requested files exist. It'd be ugly but it might just work.
I found what I'm looking for in another post and modified my method below.
#GET
#Produces("text/html")
#Path("{page}")
public void showJSP(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("orderId") String orderId) throws ServletException, IOException {
request.getRequestDispatcher(page + ".jsp").forward(request, response);
}
This gives me my 404 that I'm looking for and all of my services still work.
If this is the 'wrong' way to do this I'm still open for ideas but for now it works.
I'm studying EJB3.
I have a session bean which provides services to create/update customer accounts.
This session bean offers services on the lines of:
public void addCustomer(Customer c);
public void updateCustomer(Customer c);
Ideally I'd like to have a single servlet: CustomerServlet and it would invoke the session beans that I have listed above.
Problem is that I have two JSPs: UpdateAccount.jsp and CreateAccount.jsp. Both of these JSPs have a form with a method POST and action "CustomerServlet".
How can I distinguish in a customer servlet which operation I should carry out: createAccount or updateAccount?
I guess the alternative is to have a separate servlet for each operation...
Thank you
I'm not really certain about the best practice for this but I have a couple of suggestions that might work:
If your form is being submitted using a submit button, you could distinguish the request on the basis of the value of the <button-name> parameter. So if your buttons had the values Update and Create and were named account-submit, by checking the value you get with request.getParameter('account-submit'), you'd be able to tell which button was clicked to generate this request. If you named them differently, you could also just check which of the two parameters was not null and you'd know which form submit you were handling.
Note that if you have only a single text field in your form and the user hits Enter instead of clicking the button, you'll get a null in your servlet! See my blog post about this behaviour.
Check the Referer header - I wouldn't really recommend this since you wouldn't always know the context of the deployed app, this value may not always be present and it can be easily spoofed.
Add another mapping for your servlet so that it's accessible at both http://myapp.example.com/context/create and http://myapp.example.com/context/update. You can then check the ServletPath (request.getServletPath()) to see what 'servlet' the request came in for. I'd probably go with this one since it seems the most robust to me but you might also want to add the other two checks just to make sure. In your web.xml, you'd want something like
<servlet>
<servlet-name>CreateUpdateServlet</servlet-name>
<servlet-class>my.package.CustomerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CreateUpdateServlet</servlet-name>
<url-pattern>/create</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CreateUpdateServlet</servlet-name>
<url-pattern>/update</url-pattern>
</servlet-mapping>
JSPs are Servlets, just in a different source code form, there is no reason to POST to a different Servlet, you can just POST back to the same JSP.
You don't need the servlet. JSPs (or Facelets) can talk directly to the beans via EL.
Does anybody know how to intercept a a4j request using a javax.servlet.Filter?
The interception must occur before FacesServlet be called (it's why I'm planning to do it using Filter).
I'd like to know which method will be executed on my backbean, cause I need to do a dynamic control first.
You'd like to determine the request headers for a marker of the a4j request. I don't do a4j, but if it is doing its work well, you should be able to determine it based on the X-Requested-With header.
String requestedWith = request.getHeader("X-Requested-With");
Then just determine in an if block if the value is the expected one for a4j requests and handle accordingly. Don't forget to continue the filter chain at end whenever neccessary.
if (requestedWith.equals(someAjax4jsfSpecificValue)) {
// Do your job.
}
chain.doFilter(request, response);
To get it to run, just map it on the <servlet-name> of the FacesServlet as it is currently definied in web.xml.
<filter-mapping>
<filter-name>yourFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
We would like to implement a "fault barrier" strategy for managing exceptions in our applications. One thing our applications have is the concept of a "passback" response, basically a no-op, which we'd like to return in preference to throwing 500, 400, etc. HTTP status codes - e.g. our external facing applications should always return a valid response, even if an underlying exception was thrown - we'd like to handle that internal to the application, and still return a valid noop response.
Our first implementation was a Servlet Filter which would wrap all requests in a try/catch block, and return the default return from the catch, e.g.:
try{
chain.doFilter()
} catch (Throwable t) {
generatePassbackResponse(HttpServletRequest req, HttpServletResponse res)
}
While this mostly works, and feels nice and clean (we can return nice text, set the content/type appropriately, etc.) the one problem seems to be that when an Exception is thrown the response still comes through with Status-Code: 500.
HttpServletResponse.setStatus(200) doesn't have an effect, and the javadoc does say it only applies on normal requests.
Our second implementation thought is we may have to forward to another page, or plug an errorPage into web.xml and manually sendError to that page - though we're interested in whether anyone has a specific recommendation.
There are two methods form setting the HTTP status of a response:
setStatus() will just set the status
sendError() will set the status and trigger the <error-page> mechanism
Javadoc for sendError says the response should be considered to be committed after calling sendError (this could explain the behavior of your appserver).
Implementing a custom HttpServletResponseWrapper would allow you to enforce the behavior you
need for sendError (and maybe buffer the whole request in memory, so that you can send "passbacks" for exceptions occurring after the point the request would be usually committed).
If I remember correctly, you should not be calling chain.doFilter() if you do not want anything else to process the request. The filter will get executed in every case, but chain.doFilter() will ensure that all other filters are called. In order to properly block an exception from getting to the user, you need to stop the request/response handling.
You could take a different route as well by using a framework like Spring and its Interceptors (just like a Filter). Spring gives you a lot of control over the Interceptors and how responses get handled. Granted, this is a bit heavy of a solution to your question.
In response to the comment, according to http://java.sun.com/products/servlet/Filters.html:
The most important method in the
Filter interface is the doFilter
method...This method usually performs
some of the following actions:
If the current filter is the last
filter in the chain that ends with the
target servlet, the next entity is the
resource at the end of the chain;
otherwise, it is the next filter that
was configured in the WAR. It invokes
the next entity by calling the
doFilter method on the chain object
(passing in the request and response
it was called with, or the wrapped
versions it may have created).
Alternatively, it can choose to block
the request by not making the call to
invoke the next entity. In the latter
case, the filter is responsible for
filling out the response.
The idea being that this "fault barrier" needs to stop all other filters from executing, and just handle the request/response in the manner it deems necessary.
Can you not just use the standard web.xml configuration:
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<location>/error.jsp</location>
<exception-type>java.lang.Exception</exception-type>
</error-page>
I cant see what else you're trying to do that this doesn't already cater for? If it's just the error code, then I think that you can set this using the response object.
The RESTEasy framework allows you to select what your response code will be using ExceptionMappers. It may be that you're reluctant to use it, but I've found it to be very quick and efficient.
The JBoss documentation covering ExceptionMappers
http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html_single/index.html#ExceptionMappers
My blog article showing a snippet of general purpose RESTEasy code
http://gary-rowe.com/agilestack/2010/08/22/my-current-development-stack/