AsyncContext in Servlet 3.0 infinite browser loading - java

I'm going to make streaming. I have .jsp file and at the end of .jsp file I include my Async Servlet using following code:
<jsp:include page = '/simple' flush = 'true' />
So I want when whole page is loaded to open an infinite Async request, which will handle Async response.
Here is my Servlet code:
public class SimpleAsyncServlet extends HttpServlet {
public static AsyncContext ctx;
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
ctx = req.startAsync();
ctx.setTimeout(0);
}
}
From other java classes I'm using the static SimpleAsyncServlet.ctx.getResponse.getWriter() to println some javascript code to current page. It is working without any problem, but browser keep showing that it's loading. According to Async idea page should be loaded and this Async Request should stay alive in background and..that's it, but no....browser keeps loading the page till forever (timeout is 0, cos I want to have infinite open reqeust)
Where am I wrong and how can I make this permanent request without this browser loading ?
P.S. I have tried to access my servlet direct from url (localhost.../simple) and then I see nothing printed on page. It keep loading till forever.

You are trying to achieve the impossible.
The browser will showing that the page is loading until it knows it has received the full request by one of the following methods:
it has received the number bytes stated in a Content-Length header
the connection is closed
it received an end chunk when using chunked encoding
Since you want an 'infinite' response, none of the three options above is ever going to happen.

Related

Java EE - Show page based on internal business logic

I'm implementing an enterprise application with Java EE on Glassfish server. I need to my application to execute some logic to show the proper output for a specific subset of URLs.
Problem description:
My web pages folder has this structure:
Web Pages
Protected
- CorrectPage.xhtml
- A.xhtml
- B.xhtml
- Index.xhtml
I want the user to access the URL:
/Protected/CorrectPage.xhtml
But the user must not be able to access the following URLs:
/Protected/A.xhtml
/Protected/B.xhtml
When the URL /Protected/CorrectPage.xhtml is entered I want to execute some logic and depending on the outcome of this logic I want to show either A.xhtml, or B.xhtml, without any visible URL changes (redirects).
Solutions tried so far:
I thought about using a servlet mapped to /Protected/*.xhtml while leaving the Faces Servlet deal with any other URL in my application.
and having :
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if(*Requested URL is /Protected/CorrectPage.xhtml*) {
if(logic())
*Show A.xhtml*
else
*Show B.xhtml*
} else
*Show 404*
My issue is that I don't know how to implement the Show A.xhtml. I basically want to print to the client my xhtml page.
I also thought about solving this last issue by using the response PrintWriter.
PrintWriter pw = response.getWriter();
But than again this doesn't solve my issue since I don't know how to print the xhtml file while also having the evaluation of the expression language contained in it.
Conclusion
Any help is extremely appreciated. Even if that means changing something in the structure I proposed. Naturally if the creation of a servlet isn't the correct solution for my issues I will leave that track.
I'm interested only in the outcome the user will experience.
Thanks in advance
You may use request.getRequestDispatcher("/protected/page[A|B]").forward(request, response)

Struts 1 Action Return Success After Downloading a Binary File

I know how to download a binary file from my web app by setting the response header and copying the binary file to the response's outputstream. But what I'm having trouble with is returning success so the page will reload. If I return success I will get the error:
java.lang.IllegalStateException: getOutputStream() has already been
called for this response
See the below code example. This will download the file and then throw the exception. Is there a way to restore the response?
public ActionForward export(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
//tell browser program going to return an application file
//instead of html page
response.setContentType("application/force-download");
response.setHeader("Content-Disposition","attachment;filename=temp.csv");
IOUtils.copy(new FileInputStream("/path to some file"), response.getOutputStream());
response.flushBuffer();
return mapping.findForward("success");
}
I don't believe you can do a redirect or reload after a file download. This is more of an HTTP restriction, not something specific to Struts 1.
It takes one HTTP response to download a file to a browser, and one HTTP response to reload the page. You are attempting to do both from the same HTTP request, which simply isn't possible. A request cannot have more than one response.
In much the same way, you can't issue a redirect after you've served a page to the user, unless the page itself contains a <meta refresh="..."> element or some JavaScript that does a reload. Both approaches essentially create another HTTP request, but neither approach is open to you because it's not possible to do either with a file download.
In short, it's not possible to do what you are asking for.
You can set response.setHeader("Refresh", "1"); according to this article:
http://users.polytech.unice.fr/~buffa/cours/internet/POLYS/servlets/Servlet-Tutorial-Response-Headers.html
But it doesn't work when you close browser file download popup.

Servlet: Cannot forward after response has been committed

I'm working on servlet page that renders content based on geo-location, and I want to use both sendRedirect and forward together; e.g; you browse example.com/aPage.jsp from France; first I want the servlet to redirect you to example.com/fr/aPage.jsp and then forward you to the resources page.
This is what I have in my servlet:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
....
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
// after redirect forward the resources page
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
...
}
But I get:
java.lang.IllegalStateException: Cannot forward after response has been committed
I know the error appears because I can't use both sendRedirect and forward one after another, but I don't know how to achieve what I want (as described above) without this.
any help?
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
// after redirect forward the resources page
After that line , Your response start writing to clinet.
And you are trying to add additional data to it.
The server has already finished writing the response header and is writing the body of the content, and which point you are trying to write more to the header - of course it cant rewind.
So,Thumb rule while dealing with servlet is
Finish your logic before redirect or forward add return statement.So execution ends there .
When you call
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
you are sending your client a 302 HTTP status code with the location to redirect to. Your client then needs to make a new HTTP request to that location. Whichever Servlet is supposed to handle the path REDIRECT_URL_BASED_ON_GEO should then use the RequestDispatcher to forward to the resource described by RESOURCES_PAGE.
To better explain your exception
java.lang.IllegalStateException: Cannot forward after response has been committed
a committed response is a response where HTTP headers are already sent. If we look at your code
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
After this line, you've already sent the response along with the headers (302).
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
After these lines, you're asking the resource RESOURCES_PAGE to finish processing the request. That includes writing HTTP headers and body. But the request has already been processed and a response has already been sent, so it will fail, throwing the exception.
You have to be aware that a redirect is a complete response to the browser and the browser will in turn issue a new request to the url you redirected to. Even though you can't really sse it when dealing with the browser you always have to be aware that this is what happens.
Now, if you use the same controller for the second request you have to check wether a redirect is necessary or you can now do the forward instead.
if (!path.startsWith(locationPrefix)) {
response.sendRedirect(locationPrefix + path);
return;
} else {
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
return;
}
Of course it would be nicer to have a distinct controller per request, but depending of url structure and framework this is not always possible.
Once you redirect, the servlet you're working on is no longer in control. You need to get the servlet that is the target of the redirect to recognize the correct condition to forward and then call forward there, with similar code:
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
Even if it's the same servlet, it's a new invocation of the servlet's doGet( or other similar method.

send data from servlet java to jsp

I'm doing a project in java in which I implemented a chat, everything works perfectly only when I receive messages I can not print the web page.
In my Servlet I have a callback method that is invoked when messages arrive, in fact if you see mold them in the console, but if you are sending them to the jsp using the RequestDispatcher can not get them to see.
I would like to know if there is a system that the jsp page listens for a callback method in the servlet?
Obviously, this system should not be constantly invoke the class I have something absurd like that.
So that I can print the messages I receive.
This is my code I put a comment where I should print eventually find in jsp page, or do a redirect by passing parameters post or get
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String strJid = (String) request.getParameter("jid");
String strMessage = (String) request.getParameter("textMessage");
Connection connection = (Connection)getServletContext().getAttribute("classConnection");
ChatManager chatManager = connection.getChatManager();
Chat newChat = chatManager.createChat(strJid, new MessageListener(){
#Override
public void processMessage(Chat chat, Message message){
//from here I have to print the message.getBody () in jsp page,
//how can I do? I'm happy also reload the page and pass as a parameter to get or post
}
});
try{
newChat.sendMessage(strMessage);
}
catch(XMPPException e){
System.out.println("Errore invio messaggio");
}
}
To implement a callback method in your servlet to receive chat messages is the wrong approach. A servlet will be called once for a browser request, creates the HTML page and send it back to the browser. After that there is no such kind of a connection between the servlet and the web page.
In traditional web programming all communication between browser and server is intiated by the client. There is no way for the server to send a message to the client. Workarounds are long polling requests.
But nowadays you can use Websockets. There are several frameworks supporting Websockets both for client and server side. One of them is Atmosphere. Their tutorial is a chat application.

Can we somehow change the url in addressbar after dispatching request from servlet to jsp

I am having a weird problem here, and I am really stuck, need to get this work badly.
so i have a page say index.jsp with a link say "a href=servlet?id=10". when I click on this link it will go to doGet() on my servlet and here is the code in my servlet.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("id");
// search database and create an arraylist
if(//user logged in)
address = "s/results.jsp";
else
address = "results.jsp";
// set arraylist in session object
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request,response);
}
So the above code works fine but after request forwarding, my browser shows the url as
http://localhost/project/servlet?id=10.
I don't want the above url as i am forwarding to two different jsp's based on the user login status one is in 's' folder and other is outside of that.
if user is logged in then i forward to 's/results.jsp' and if user is not logged in i am forwarding to 'results.jsp'.
in case of s/results.jsp i am accessing resources like images and scripts from outside of 's' folder by using ../ in the results.jsp.
as url is not changing to s/results.jsp , i am unable to access the resources with '../'
and as i am using jsp pagination , when i click next the url is changing to s/results.jsp
and in that case i am able to access resources using ../
one solution in my mind is to copy all resources in s folder , but that would increase
redundancy.
one other solution in my mind is to create two different servlets for two jsp's
but i don't know where to put the servlet so that it can access resources outside of s folder with ../
is their any other good way i can do the task..
I have tried to find information about this but haven't been able to figure it out.
Any help will be very much appreciated.
You have basically instructed your webbrowser to send a request to exactly that URL. The forward does not change the URL. It is entirely server side. Apart from using response.sendRedirect() instead -which would trash the current request, including all of its attributes, and create a brand new request on the given URL-, you could also just change your link to <a href="results?id=10">, or when the user is logged in, to <a href="s/results?id=10">.
<a href="${user.loggedin ? 's/' : ''}results?id=10">
Finally alter the servlet mapping accordingly so that it get invoked on those URLs.
<url-pattern>/results</url-pattern>
<url-pattern>/s/results</url-pattern>
You'll only miss the JSP extension. But JSPs which are to be used by a dispatcher belong in /WEB-INF folder anyway so that they cannot be viewed by the enduser directly without invoking the servlet first. You also end up with nicer URLs.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("id");
// search database and create an arraylist
if(//user logged in)
address = "s/results.jsp";
else
address = "results.jsp";
// set arraylist in session object
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request,response);
}
in the above code instead of using request dispatcher,
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request,response);
we can try with
response.sendRedirect(request.getContextPath()+"/address");

Categories

Resources