Is it possible to change the Servlet request object while forwarding the request from one servlet to another? or a work around for achieving this?
I have 2 servlet's, Servlet1 and Servlet2 like for e.g. -
public class Servlet1 extends HttpServlet {
doPost(HttpServletRequest rq, HttpServletResponse rs) {
// do something meaningful, call other different web-apps/servlets
InputStream is1 = rq.getInputStream();
RequestDispatcher rd = getServletContext().getRequestDispatcher("/Servlet2");
rd.forward(rq, rs);
}
}
If I print the is1 it is something like -
-----Part2_324<?xml version="1.0" encoding="utf-8"?><Head><Body><Text>This is the first File</Text></Body></Head>-------Part2_65623
I dont care about this o/p, when later the request is to be forwarded to the Servlet2.
I have an xml file file2.xml, contents are -
<?xml version="1.0" encoding="utf-8"?><Head><Body><Top>Start</Top><Middle>Process</Middle><Bottom>End</Bottom></Body></Head>
I would like this to be as the request content for the Servlet2, as it cannot process the contents of is1, it is meant to be processing content of file2.xml.
There are pretty much no Attributes/Parameters set.
Is it possible to achieve this? I hope, the question is clear.
Thank you
The servlet spec forbids the substitution of one request for another when forwarding.
However, it does permit the forwarding of an HttpServletRequestWrapper, where the wrapper is wrapping the original request. So try and implement your logic as a subclass of HttpServletRequestWrapper, wrapping the original request, and overriding the various methods of HttpServletRequest as appropriate.
Related
I need to make a Servlet which will manage some information and, after that, will go to a Liferay 6.2 Portlet. Both in the same server.
I need the Servlet to send a parameter, but I don't want to send it GET, but POST method. So, I try to put it in the session to retrieve it from the Portlet.
At the Servlet, I have:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
request.getSession().setAttribute("param1", "TEST 1");
url = "http://myServer/";
response.sendRedirect(response.encodeRedirectURL(url));
} catch (Exception e) {
e.printStackTrace();
}
}
And at the Portlet I manage the information at render method, as I want to get param1 before I render the page:
public void render (RenderRequest renderRequest, RenderResponse renderResponse)
throws PortletException, IOException {
super.render(renderRequest, renderResponse);
//Try to retrieve from getOriginalServletRequest
HttpServletRequest servletReq = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(renderRequest));
String param1 = servletReq.getSession().getAttribute("param1").toString();
//Try to retrieve from getHttpServletRequest
HttpServletRequest servletReq_ = PortalUtil.getHttpServletRequest(renderRequest);
String param1_ = servletReq_.getSession().getAttribute("param1").toString();
}
As you can see, I tried to retrieve from getHttpServletRequest and from getOriginalServletRequest, but I always get the param1 null.
Any suggestion?
Thank you in advance!
Update question:
I'm being called from a third part, and I'm receiving a GET parameter I want to evaluate.
After that, and not rendering a page in the middle, I want to redirect to one or another Portlet, depending of that evaluation.
I need to send some personal information to those Portlets, so I want to send some parameters in POST method.
A Servlet doesn't fit as doesn't share session with Portlets.
I've tried to implement a landing Portlet, but the redirect can only be done in action phase, so I'd need to render a (empty) page before the redirect, don't like that part. Render phase doesn't allow redirect (even getting PortalUtil.getHttpServletResponse(), doesn't work)
Any suggestion? Thanks!
A servlet and a portlet will not share the same session. The portlet is living within the portal server, e.g. Liferay. The servlet is typically in its own web application, thus completely separated by design.
If you need to communicate between the two, here are two possible solutions/workarounds:
reimplement your servlet as a portlet, potentially utilizing the resource-phase of a portlet
use a request parameter instead of a session attribute
Edit after all of the comments:
It seems best to take a step back and look at the underlying problem - what is the problem that you're actually trying to solve? The content of your question is how you're trying to solve it, and obviously there are challenges. It looks like the problem needs a different solution in the first place.
My answer describes why your solution can't work, but that obviously doesn't help solving the underlying problem.
I have an ajax method on my servlet that could be running at the same time for the same user. Sorry if I use the wrong words to describe the problem but it's how I understand it so far (don't know much about threading).
Anyways here's the method
private void ajaxPartidas() throws ServletException, IOException {
//Variables necesarias
DataSource pool = (DataSource) session.get().getAttribute("pool");
Recibo registro = null;
int id = -1;
try{ id = Integer.parseInt(request.get().getParameter("id"));}catch(NumberFormatException e){}
if(id > 0){
registro = new Recibo(id);
if(!registro.obtener(pool))
registro = null;
registro.setPartidas(Partida.obtenerRegistros(pool, registro.getId()));
}
response.get().setContentType("application/json");
response.get().setHeader("Content-Type", "application/json; charset=utf-8");
response.get().getWriter().print((new Gson()).toJson(registro.getPartidas()));
}
This method is being called via ajax, it works fine the 1st time it gets called, but second time (on same id) and it returns a NullPointer on the getWriter() line. I've looked around and everyone seems to pinpoint the problem to threads. Now a little bit more of context would be that everytime the servlet enters in the
doPost(request, response)
I assign a threadlocal variable declared like so in the global vars
private static ThreadLocal<HttpServletResponse> response = new ThreadLocal<>();
and I assign it the response
Home.response.set(response);
in the doPost() method.
How would I go about making the getWriter() threadsafe?
Not sure why you're assigning the response to a class level ThreadLocal? Each new user generated request has a clean request and response object. getWriter and all methods on the servlet class are threadsafe as long as you follow the correct guidelines for using a Java Servlet. A general rule with Java Servlets is that as long as you don't use class level variables, you are thread-safe.
Instead of using a ThreadLocal, you need to pass the request and response objects as parameters to your ajaxPartidas method and then call it as you normally would. So your doPost method would look like this
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ajaxPartidas(request, response);
}
The concurrency issues are already handled by the Servlet class itself, you just need to write the business logic. See this answer in a similar thread for more details on using a Java Servlet with Ajax: https://stackoverflow.com/a/4113258/772385
Tomcat creates a new Request and Response for EVERY user request. So they are already threadsafe (unless you go in and create a new Thread). Besides, make sure you are passing "id" and is getting set properly. I think it's the "registro" object on the same line as getWriter() that's causing the NullPointerException.
I trying to do two things at once and I don't seem to find answers that can do both.
I'm trying this:
I want URLs ending in /user/{parameter} to be mapped to a JSP page user.jsp where I can access the parameter.
I find ways to pass parameters from the web.xml file to the JSP using this method
<init-param>
<param-name>someParam</param-name>
<param-value>itsValue</param-value>
</init-param>
And I find ways to create URL filters and map them to Java Servlets.
What I need is a combination. Also, what I found on passing URL parameters to Servlets wasn't too detailed either, so a good reference on that would also be more than welcome!
I want URLs ending in /user/{parameter} to be mapped to a JSP page user.jsp where I can access the parameter.
Map a servlet on /user/* and use HttpServletRequest#getPathInfo() to extract the path info.
E.g.
#WebServlet("/user/*")
public class UserServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo(); // "/{parameter}"
// ...
request.getRequestDispatcher("/WEB-INF/user.jsp").forward(request, response);
}
}
That's basically all. Use the usual String methods like substring() and/or split() to break down the path info in usable parts.
Use a base-url servlet to parse the URL and perform a conditional servlet forwarding to the appropriate JSP.
request.getRequestDispatcher().forward(JSPurl)
Let us say you have a URL branch /sales/. Under this URL branch, you would allow the following URLs to to be serviced by /implemented/usersales.jsp :
/sales/liquour/users/{region}
/sales/liquour/soft/users/{region}
/sales/toiletries/users/{type}
and the following URLs to be serviced by /implemented/products.jsp
- /sales/groceries/products/{section}
- /sales/groceries/meat/products/{region}
- /sales/groceries/vegetables/beans/products/{region}
You would have a web.xml servlet mapping for servlet class org.myorg.SalesHandler to be mapped to /sales/.
In the service method override in org.myorg.SalesHandler servlet class,
analyse the URL pattern (using regexp or otherwise) and then conditionally forward the request using
request.getRequestDispatcher().forward(JSPurl)
JAX-RS
But why would you do that when we have jax-rs?
How to forward from a JAX-RS service to JSP?.
JAX-RS may seem daunting at first, but it is actually very simple and intuitive to implement.
//Below is my servlet called HtmlTable. I am trying to implement shopping cart like functionality here. addingItems is another class that puts elements in a ArrayList. Whenever I add something from website I want AJAX request to just call the method jusAdding() not the processRequest method. so that when sufficient items are added to the ArrayList I can print it on the screen by calling aI.getItems() which will happen automatically when simply call the servlet. Is it possible?? If yes how should I write the URL in AJAX request.
public class HtmlTable extends HttpServlet {
addingItems aI = new addingItems();
public void jusAdding(HttpServletRequest request, HttpServletResponse response){
aI.addItemsInCart(request, response);
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
List<itemsCart> itemsInCart = aI.getItemsInCart();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet HtmlTable</title>");
out.println("</head>");
out.println("<body>");
//whatever content is in the itemsInCart will be displayed here in body tag
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
}
//forgive me if I am not clear. Let me know I'll update as per reader convenience.
You can't do that.
An HTTP request flowing through a Servlet will always go to the Servlet's service method. What you need is to use the service method as a controller, so it inspects the incoming request and calls jusAdding (or other methods) depending on the request's parameters.
Most likely, you will want to use an already-existing framework for doing that.
The following should give you more information, as well as some ideas how to go about doing so: How to use Servlets and Ajax?
None of your methods are going to be called by the container. You should start with the servlet specification (or at least the HttpServlet javadoc).
The container calls the service() method of your servlet, which in turn, for HttpServlet dispatches to the method corresponding to the request HTTP method: doGet(), doPost() etc. That's where you're supposed to hook your logic (overwrite one of those, or service() itself and put your code there).
In order to distinguish between a "full page request" and an "AJAX request", you need the client to include some discriminator in that call: some request parameter with distinct values, a different HTTP method or whatever. Once you have that, in your doGet() method for instance, you can check that discriminator and invoke either justAdd() or processRequest() according to the client request.
I need to grab a certain custom HTTP header value from every request and put it in WebSession so that it will be available on any WebPage later on. (I believe the Wicket way to do this is to have a custom class extending WebSession that has appropriate accessors.)
My question is, what kind of Filter (or other mechanism) I need to be able to both intercept the header and access the WebSession for storing the value?
I tried to do this with a normal Java EE Filter, using
CustomSession session = (CustomSession) AuthenticatedWebSession.get();
But (perhaps not surprisingly), that yields:
java.lang.IllegalStateException:
you can only locate or create sessions in the context of a request cycle
Should I perhaps extend WicketFilter and do it there (can I access the session at that point?), or is something even more complicated required?
Of course, please point it out if I'm doing something completely wrong; I'm new to Wicket.
I'd guess you need to implement a custom WebRequestCycle:
public class CustomRequestCycle extends WebRequestCycle{
public CustomRequestCycle(WebApplication application,
WebRequest request,
Response response){
super(application, request, response);
String headerValue = request.getHttpServletRequest().getHeader("foo");
((MyCustomSession)Session.get()).setFoo(headerValue);
}
}
And in your WebApplication class you register the custom RequestCycle like this:
public class MyApp extends WebApplication{
#Override
public RequestCycle newRequestCycle(Request request, Response response){
return new CustomRequestCycle(this, (WebRequest) request, response);
}
}
Reference:
Request cycle and request cycle
processor