I am just a beginner in Java Web and I am exploring the pure Servlets and JSPs (with no frameworks). I am trying to build up a simple CRUD and I got stuck in an error that makes no sense at all (at least to me!).
Objective
I wanna build a simple CRUD with several Servlets containing the logics and database operations (controller) and JSPs to display the pages (views). I have already successfully build up a CustomerIndexServlet (route: /customers), which returns the list of records and a button to CustomerNewServlet (route: /customers/new) which SHOULD return a JSP with the form to create new records.
Issue
Calling CustomerNewServlet leads to a Page Not Found (404) and GlassFish prints the message PWC6117: File "null" not found in the console. By debugging the code, the error occurs when forwarding the request through RequestDispatcher. I don't understand! If I try to access the JSP directly (at http://localhost:8080/MyApp/customerForm.jsp), it returns OK (200). I even printed the path of JSP before forwarding to make sure it is the one expected!
#WebServlet(name = "NewCustomer", urlPatterns = {"/customers/new"})
public class NewCustomerServlet extends HttpServlet {
#Override
protected void doGet(
HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException {
System.out.println(request.getContextPath());
if (request.getSession().getAttribute("login") == null)
/*error*/ request.getRequestDispatcher(request.getContextPath()).forward(request, response);
else
/*error*/ request.getRequestDispatcher(request.getContextPath() + "/customerForm").forward(request, response);
}
}
And in server's console it is displayed:
Info: /MyApp
Server: PWC6117: File "null" not found
What am I doing wrong? Does it have something to do with the file locations and directories?
I figured out what happen and how redirection and forward deal with URI's... I'm gonna share the knowledge I've acquired:
response.sendRedirect(URL)
When using the sendRedirect() method, you are requesting the client to submit a new request to the passed URL. When using an absolute path, you have to concatenate the request.getContextPath() prefix to your URL, if you wanna target a resource within your application.
request.getRequestDispatcher(URL).forward(...)
When dispatching the request to another URL, it already uses application context. So using request.getContextPath() + "/customerForm.jsp" as target URL will only look for a resource in /AppName/AppName/customerForm.jsp. Then, omitting the getContextPath() call is enough to make my code work as expected.
Related
I have a requirement that I have to create a cookie on server side when page loads. In our AEM project I have a LocatorViewESBOfficeHelper.java file which is mapped to the JSP of the component (Say locateOffice). When page loads first time onGetData method of LocatorViewESBOfficeHelper.java is called.
In this method I want to create cookie using following code but I am unable to create it. When I use same create cookie code in a servlet and call it through ajax call, it successfully create cookie.
One possible reason could be when page is fully loaded, the response object could not have cookies. But I am unable to understand how to manage it.
You might have several problems.
Edit-Mode
You will not see session cookies in the editor, because your page is inside an iframe. Just do "View as published" (?wcmmode=disabled) to get your page directly in the browser window.
Wrong response object
The mapping LocatorViewESBOfficeHelper.java to the component sounds like someone tried to do some magic. Maybe your service doesn't get the real response object, but more a response wrapper. And the output of your service is somehow validated and written to the real response. In such cases, the http headers are often ignored.
Just create your own real AEM component, were the content is written by a SlingSafeMethodsServlet (registered via the resource type). If this works, you know where to go.
The following servlet does work good for me:
#Component(
service = Servlet.class,
property = {
SLING_SERVLET_RESOURCE_TYPES + "=/apps/myproject/components/cookie-test",
SLING_SERVLET_METHODS + "=GET",
SLING_SERVLET_EXTENSIONS + "=html"
})
public class CookieTestServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(#Nonnull SlingHttpServletRequest request, #Nonnull SlingHttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("<h2>Cookie Test</h2>");
Cookie cookie = new Cookie("alex", "this-is-a-test-" + (System.currentTimeMillis() % 10000));
response.addCookie(cookie);
}
}
Response buffer already flushed
The HttpServletResponse is more like a buffered Writer or OutputStream. You can only add http headers (or cookies) as long as the response output buffer was not flushed yet.
To verify this, either use the test component on a smaller page or simply increase in the OSGi configs the buffer to something real high (e.g. 1MB - but on your local instance only). Therefore go to the web console / OSGi / Configuration / Apache Felix Jetty Based Http Service / Response buffer size
(http://localhost:4502/system/console/configMgr/org.apache.felix.http)
I don't recommend to change it in production. So you should find another way to be early in the content generation. As most extreme workaround you could use a Sling request filter.
Opt-Out-Filter
If your project uses the Adobe Granite Opt-Out Service, then you might have to whitelist your cookie in the OSGi configuration. By default this service should not do anything.
Try Other Alternatives
As alternative I would propose:
Use a Sling Filter
Create the Cookie front-end with JavaScript
I hope one of my ideas might point you in the right direction.
Alex
The problem is: I have a page1.jsp which is submitted and forwarded to page2.jsp. The problem is that the forwarded output should be only the content in page2.jsp, instead of that is showing me content from page1.jsp and immediately the content from page2.jsp
I'm using requestDispatcher.forward(String) but i don know why is this happening
PS: I'm using JE 1.4
Well it seems you have got the method signature incorrect . As per the javaee 1.4 API:
public void forward(ServletRequest request,ServletResponse response)
throws ServletException,
java.io.IOException
Hence your code should be :
RequestDispatcher dispatcher = request.getRequestDispatcher("page2.jsp);
dispatcher.forward( request, response );
Better , you can use the <jsp:forward> standard action.
The JSP that contains the action stops processing, clears its buffer, and forwards the request to the target resource. Note that the calling JSP should not write anything to the response prior to the action.
Suggested Reading:
How to avoid Java Code in JSP-Files?
Yes, yet another url shortener written in java, because I wanted my own, and because why not. Currently everything works, just not they way I want to to. In short, there is only one servlet mapped to "/" in the entire project. There are no frameworks involved, or anything fancy, this is just a basic Servlet "project". on doPost a new shortUrl is created, and you get a JSON response. On doGet, if the URL is "/*{any_valid_short_url}" then a redirect is sent (below).
response.sendRedirect("longUrlString")
The issue I am having is with the index page, when the same doGet is called, I check the requested path, if it is "/" then currently, I use a FileInputStream and stream the index.html page out via response.getOutputStream(), which is pretty hacky in my opinion. I would like to use a requestDispatcher instead, however when I do try to implement that (below) I get into a re-direct loop, and the servlet container (jetty or tomcat) stack overflow's.
getServletContext().getRequestDispatcher("/index.html").forward(req, res);
Is there something that I am mis-understanding about how this is being done? The project is currently hosted on my github page. https://github.com/justinmburrous/ShortUrl
You need to make this check more narrower, because for all requests this condition is true and hence for all requests are forwarded to 'index.html' again and again
if(requestedPath.equals("/")){
//tried with multiple variations of /index.html, renamed to jsp, etc...
RequestDispatcher dispatcher = request.getRequestDispatcher("index.html");
dispatcher.forward(request, response);
}
Edit:
Since your servlet is mapped as default servlet , all forwards or request will be handled by this Servlet.
You should map the url to more specific range.
RequestDispatcher - forward - produces infinite loop
Okay, I have figured this one out with thanks to How to access static resources when mapping a global front controller servlet on /*
My github page has the working code along with the Filter, modified servlet and web.xml for.
I am currently implementing an OpenID Relying Party (RP) and Identity Provider (IdP) with Java HttpServlets using the OpenID4Java library. I have run into trouble getting two servlets to communicate with each other. I believe the problem I am having is to do more with how Servlets behave, however I have included info about my application for a better sense as to what is happening.
The scenario is as follows:
Servlet #1 (my RP) sends a request to Servlet #2 (my IdP) as follows:
httpResp.sendRedirect(authReq.getDestinationUrl(true));
Essentially authReq = a message with various OpenID specific parameters. By invoking getDestinationUrl(true) it encodes the request into a url to send via a GET.
Servlet #2 catches the above GET in its doGet method. It parses the information, and crafts a reply to send back to Servlet #1 in the following fashion:
String responseText = processRequest(httpReq, httpResp);
httpResp.setContentType("text/html");
OutputStream outputStream = httpResp.getOutputStream();
//
outputStream.write(responseText.getBytes());
outputStream.close();
My problem is, this response never makes it back to Servlet #1. I would expect that when Server #1 receives the response from Servlet #2 that its' doGet or doPost method would catch the message. However neither case happens.
Any advice would be greatly appreciated.
Thanks!
The response of 2nd servlet will directly go on client side i think because its is the original client right? Your 1st servlet is just redirecting the request.
So, if you want to communicate between servlets, Use URLConnection or Apache HttpClient to communicate with 2nd servlet.
You can also make JSP instead of 2nd servlet, then pass you data from 1st servlet to that JSP. That JSP's response will be sent to client then. After all you can do all logic in JSP what you can in servlet.
Hope this helps.
parth.
If you want two servlets to communicate with each other within an application, you can use the ServletContext object and share data via ServletContext.setAttribute and ServletContext.getAttribute and RequestDispatcher obtained via HttServletRequest or ServletContext
In your case can the Servlet#2 be invoked directly by the client? If not then you should probably refactor the processRequest(request, response) into a Utility class or a library. Which in turn can be called by both Servlet#1 and Servlete#2.
response.sendRedirect sends a redirect (301 moved permenently, ithink) to the browser. So your servlet actually sends a response to browser with 301 and then browser makes a request to servlet#2 again.
You can use RequestDispatcher to include your second servlet's response. In this way, the control returns to the first servlet after the method completes.
RequestDispatcher dispatcher = request.getRequestDispatcher(authReq.getDestinationUrl(true));
dispatcher.include(request, response);
However, with this, the response generated by the called servlet will be sent to the browser. If you want your calling servlet to capture the message from called servlet without sending to browser, you can either create a response wrapper (A wrapper writing the contents in a string) and pass this wrapper when you include the second servlet or better you can share the data in either of the scopes (Preferably 'request' scope): You can set the data in the request scope in called servlet and you can retrieve it in the calling servlet after include() completes.
When you redirect, you are telling the browser to make a new request for the URL. So there will be new request/response objects created as if you had clicked on a link in your page.
Hope this helps.
I have a simple (Servlet, JSP, and JSTL) web app whose main functionality is displaying images retrieved from a back-end server. The controller servlet forwards the user to a JSP that in turn uses another Servlet to display the resulting image on that same JSP. Further down, the JSP has a line similar to:
<img src="<c:out value='${imageURL}'/>" alt="image view" border="1">
which invokes a GET request on the image-generating servlet causing it to generate the image.
My question is: how do I handle Exceptions thrown by this image-generating servlet?
I already have an error page defined (in web.xml) to handle ServletException within my web app but this doesn't work for this image-generating Servlet, and results in the following errors showing up in my Tomcat server logs:
SEVERE: Exception Processing ErrorPage[exceptionType=javax.servlet.ServletException, location=/WEB-INF/ExceptionPage.jsp]
java.lang.IllegalStateException: Cannot reset buffer after response has been committed
What's my recourse in this situation?
I'd like to be able to handle Exceptions thrown from this image-generating Servlet, and display some error on the main UI or forward the user to another error page.
You can't change the response to redirect to an error page while sending the response. It's already too late to change the entire response then. You can't ask those already sent bytes back from the client side. That's what the IllegalStateException stands for here. It's a point of no return.
Best what you can do is to just log the exception, or to rewrite the code so that it doesn't write any bit to the response (also not setting the response headers) while the business logic hasn't finished its task yet. Once you've determined that the business logic didn't throw any exception, then start writing (and thus indirectly also committing) the response. If the business logic has thrown an exception while the response isn't touched yet, then you can just safely throw it through so that it ends up in an error page. Although in case of an image servlet, you may also want to stream some standard 404.gif to the response instead. This because you can't display another HTML (error) page in an <img> element and you also can't change the URL of the parent JSP/HTML page as well since that concerns a different request.
According to the servlet API no servlet should call the getWriter() and getOutputStream() on the same response object as it causes the IllegalStateException. Usually this is the source of this exception. If you're outputing binary data like and image file you should use getOutputStream().
Looks like the problem you have is within your ExceptionPage.jsp, not your servlet code.
And this
java.lang.IllegalStateException:
Cannot reset buffer after response has
been committed
Means that you've already have tried to send a response.
Probably you've opened an output stream directly and wrote some data to it. Once you've done it you cannot try to set headers and such on a response ( they are already on their way to the client ).
You need to do a better state management. Best way to do this is to separate request preprocessing from the response generation. Once you are writing response, you can only do or die. For this, check that you are not catching IOExceptions from the response output, wrapping them to ServletException and redirect them to your error page. You really cannot handle them in the context of the current request.
First, identify why the Illegal State exception is being thrown. Rather than dealing with a thrown exception, you probably just want to fix your code so that it goes away.
You should catch the exception and forward the request using RequestDispatcher to the required page:
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// The following piece of code results in NumberFormatException which will
// be detected by the container. The RequestDispatcher object will forward
// the same request to the other resource, here the file: forwardedJSP.jsp
try {
int test = Integer.parseInt("abc");
} catch (NumberFormatException nfe) {
RequestDispatcher rd = request.getRequestDispatcher("/forwardedJSP.jsp");
rd.forward(request, response);
}}