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.
Related
I have a scenario where from one page in AEM, I need to call another AEM page in the same application and I need to pass some hidden parameters. I choose to do it via POST and below are the steps which I followed:
From page "A", I did a form submission via POST to the sling servlet and passed some parameters.
2. In the servlet, using request dispatcher I redirected the same request and response to a different page in doPost method using the following code snippet:
request.getRequestDispatcher("/content/company/en/apps/welcomepage.html").forward(request, response);
When I run the code, I am able to call the servlet through form submission but I am not able to redirect to a new page. I see the below error in logs:
18.10.2017 14:41:00.802 ERROR [127.0.0.1 [1508352060795] POST /bin/rap/welcomepage HTTP/1.1] org.apache.sling.servlets.post.impl.operations.ModifyOperation Exception during response processing.
javax.jcr.nodetype.ConstraintViolationException: No matching property definition: appointmentTypeId = platform001d
at org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate.setProperty(NodeDelegate.java:522)
at org.apache.jackrabbit.oak.jcr.session.NodeImpl$35.perform(NodeImpl.java:1375)
at org.apache.jackrabbit.oak.jcr.session.NodeImpl$35.perform(NodeImpl.java:1363)
at org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.perform(SessionDelegate.java:208)
at org.apache.jackrabbit.oak.jcr.session.ItemImpl.perform(ItemImpl.java:112)
at org.apache.jackrabbit.oak.jcr.session.NodeImpl.internalSetProperty(NodeImpl.java:1363)
If I try the same code in doGet method it works fine. Also if I use response.sendRedirect("/content/company/en/apps/welcomepage.html") it works fine too. But the problem with this is it initiates it as a new request to the page and it looses all the parameters which I get from the form submission. Could someone please let me know like how can I redirect a request to a page in AEM via POST since I need to pass some hidden parameters whic should not be visible in the url ?
Here is the way I understand your question
User visits page "A"
User fills a form, then submits.
Your custom servlet handles the submitted POST request and calls:
request.getRequestDispatcher("/content/company/en/apps/welcomepage.html").forward(request, response);
You get the ConstraintViolationException
Why do you get this exception?
Since you are using forward the POST request is forwarded to /content/company/en/apps/welcomepage.html that node is most likely of type cq:Page, which has constraints on which properties can be added. Think of it as a simple post request trying to store parameters on the cq:Page node.
What can you do?
Since I don't understand your use-case and particularly why you need to preserve the submit params, I cannot recommend a specific solution. However, since you don't want the parameters in the URL, here is a potential solution you can try:
In your servlet handler, see those hidden params to cookies on the response.
use response.sendRedirect("/content/company/en/apps/welcomepage.html")
On any of the components in /content/company/en/apps/welcomepage.html, you can get the request cookies and process them however you like. same way you wanted to process those hidden params.
Now the flow becomes:
User visits page "A"
User fills a form, then submits.
Your custom servlet handles the submitted POST request, adds your special params to cookies on the response, then calls response.sendRedirect("/content/company/en/apps/welcomepage.html")
User's browser receives a 301 response with the cookies, sets the cookies in the browser then requests "/content/company/en/apps/welcomepage.html"
Your components handle the request and get the params from the cookies, then retuns the appropriate response.
I am sending url to another server through response.sendRedirect() method and it is generating pdf for me. I am passing all the parameters but one of the parameter data is exceeding length due to which browser is not able to handle it and request is getting blocked.
I know through Post method we can hide url Parameters and response.sendRedirect() uses GET method. Is there any POST method like sendRedirect through which we can access another server url directly through servlet? Thanks in advance.
With response.sendRedirect(newUrl) you send back a HTTP status 302 with a new Location=newUrl in response header. Thus, you cannot force browser to make POST instead of GET method.
What you could do is to consume a pdf file from within your server code and return it to the client, hiding thus from client the actual target location. You can then build any request with method and parameters you want to the new location if it accept it.
See, for example, this tutorial how to make a request to another server from your servlet http://www.mkyong.com/java/how-to-send-http-request-getpost-in-java/
I'm writing a web page using java servlets. When the user subscribes he will receive an email with the activation link. Currently the servlet redirects the user (using the request dispatcher) to the thank you page after it sends the email and this takes some time. I would like to redirect the user to the page before the email is created and sent and then have the email creation performed by another servlet without the user having to wait. Is this possible? How can I call a servlet from within another servlet after using the request dispatcher.forward method? Is that possible? If not, then what is the best way to do what I want? Thanks.
There are in fact 2 different problems in your question :
you want to redirect to another page
you want to continue processing after the redirection
It is simple to redirect to another URL from a servlet, just call :
response.sendRedirect("url?param=value");
For the second part, it seems that it is possible to continue processing in servlet after sending the response to the client. From my test on a Tomcat 7 servlet container, you can do so if ContentLength is set to 0 (as body is empty) and the output stream is closed. I could never have a confirmation from servlet specs, but as I wrote above it works on Tomcat :
response.sendRedirect("url?param=value");
response.setContentLength(0);
response.getOutputStream().close();
// continue after connection with client is closed
// generate and send email
To call another servlet from a servlet, you donot use request.getRequestDispatcher("xxx").forward(req,res); but rather you use response.sendRedirect("servletname or path to the servlet");
You can also add parameters to the response.SendRedirect("xxx"); so that the recieving would use that parameters to sent the email.
To add parameters to the response.sendRedirect
response.sendRedirect("<servletname>?email="+email); this will expose the user's email address with the new url.
Based on your question, you can do something like this:
request.getRequestDispatcher("page/to/display/user").forward(req,res);
session.setAttribute("email","username of user");
response.sendRedirect("servlet/to/redirect");
EDIT:
You can create a method with boolean which will redirect the user to the thank you page, when successful, then process the email:
public boolean redirect(HttpServlet request, HttpServlet){
response.sendRedirect("<servletname>");
return true;
}
In the Servlet:
if(redirect){
processEmail(parameters);
}
END EDIT
Then in the servlet that you want to send the email, you use the session to get the email that was added to the response.
String email = (String) session.getAttribute("email");
Hope this helps.
Based on your description you would like to return message to the user and then process 'in the background' email request. It shouldn't be done via other servlet. If you have Java EE server with JMS support, that is typical task for JMS and MDB. Your servlet would just put the message email sending request to the queue and returning message to the user. MDB would pick up that message and process it, and send the email.
Method with spawning is doable as you tested and should work in most of servers, however it is discouraged. See some discussion here Why spawning threads in Java EE container is discouraged?
In Java EE 7 you will have support for it via concurrency utilities - Concurrency Utilities tutorial
I have a legacy Java webapp that does MANY redirects and forwards. I'm trying to find a way in a ServletFilter to differentiate GET requests from those server side redirects and GET requests that come from the client side.
I was hoping to do that by adding an attribute as a flag, to the header before the redirect/forward is sent and then read it in the ServletFilter to route it accordingly.
I tried request.setAttribute("myflag", "yes") before the redirect and request.getAttribute("myflag") in the ServletFilter. All I got were null values.
Can I modify headers server side and read those modifications server side?
Thanks in advance for any tips.
You can use a HttpServletRequestWrapper, there is a comprehensive tutorial on how to do that here:
http://vangjee.wordpress.com/2009/02/25/how-to-modify-request-headers-in-a-j2ee-web-application/
don't use request.setAttribute()/request.getAttribute() , it's scopes on forwards.
you can use Cookies.
If your application sets a request attribute and then forwards the request, the filter (if executed) on the forwarded URI will see the request attribute values.
In contrast, if the application sets a request attribute and then issues a redirect on the response, the browser issues a new HTTP request to the next URI - so previous request object attributes are not persisted and you'll get null values.
You could use this technique to determine which requests were redirects vs forwards.
For example:
Servlet A executed at URI /webapp/a calls request.setAttribute("forward", Boolean.TRUE) and then response.sendRedirect("/webapp/b")
If you have a servlet filter mapped to /webapp/b, in the scenario above, request.getAttribute("forward") will be null.
If, however, /webapp/a asks RequestDispatcher to forward to /webapp/b, then the call to request.getAttribute("forward") within the servlet filter's doFilter() will yield Boolean.TRUE because the request object is the same. It can then deduce that the request was forwarded (or included) and not a redirect OR a direct GET request to /webapp/b.
I'm new to Java Servlet programming and have a question about how to handle POST response from other servers (not user's POST request) using Servlet programming.
Suppose my application needs to consult another server in order to process user's request. I need to
send an asynchronous POST request (i.e. specify a redirect_uri in the POST request body) to the other server;
handle the POST response from the other server;
present some result to the user.
I think I need one Servlet to handle user's request and send a POST request to the other server, and I need another Servlet (since the POST request is asynchronous) to handle the POST response from the other server. My specific questions are:
What's the best way to send a POST request in this case? For example, using HttpUrlConnection?
How to handle a POST response in a Servlet? It confused me because a servlet is supposed to handle "request" not "response" but in this case the incoming message is indeed a POST response from the other server. In particular, if you can point me the relevant API/method that would be really helpful. For example, in doPost()? How to get the POST response body? (I assume we can get it from HttpServletRequest object).
Thanks very much!
Yue
I did not understand the term 'POST Response'.However may be you are talking about servlet chaining scenario if I understood your requirement correctly.
Servlet Chaining means the output of one servlet act as a input to
another servlet. Servlet Aliasing allows us to invoke more than one
servlet in sequence when the URL is opened with a common servlet
alias. The output from first Servlet is sent as input to other Servlet
and so on. The Output from the last Servlet is sent back to the
browser. The entire process is called Servlet Chaining.
Example of Servlet Chaining