Browser timeout and page cannot be displayed - java

I have written within a JSP page to have Thread.sleep() for more than 1 hour. The JSP is deploayed on WebLogic server 9.2. I am trying to check the browser timeout and page cannot be displayed error.
As per the below documentation, the default timeout for IE6 is 60 seconds. However, I was testing the above JSP and did not get any timeout or page cannot be displayed even beyond 30 minutes. I am doing this to the user experience for a requirement that can take long time to execute. Thanks.
http://support.microsoft.com/kb/181050

If you want to run and control a long-running process, better let it run in its own Thread instead of the request's Thread. Store a reference to this Thread in the session scope so that the client can use ajaxical requests (using the same session!) to request the server side for the current progress (and automagically also to keep the session alive so that it doesn't timeout).
Here's a basic example of such a servlet:
package mypackage;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RunLongProcessServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
if ("XMLHttpRequest".equals(request.getHeader("x-requested-with"))) {
LongProcess longProcess = (LongProcess) request.getSession().getAttribute("longProcess");
response.setContentType("application/json");
response.getWriter().write(String.valueOf(longProcess.getProgress()));
} else {
request.getRequestDispatcher("runLongProcess.jsp").forward(request, response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
LongProcess longProcess = new LongProcess();
longProcess.setDaemon(true);
longProcess.start();
request.getSession().setAttribute("longProcess", longProcess);
request.getRequestDispatcher("runLongProcess.jsp").forward(request, response);
}
}
class LongProcess extends Thread {
private int progress;
public void run() {
while (progress < 100) {
try { sleep(1000); } catch (InterruptedException ignore) {}
progress++;
}
}
public int getProgress() {
return progress;
}
}
..which is mapped as follows:
<servlet>
<servlet-name>runLongProcess</servlet-name>
<servlet-class>mypackage.RunLongProcessServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>runLongProcess</servlet-name>
<url-pattern>/runLongProcess</url-pattern>
</servlet-mapping>
And here's a basic example of the JSP (with a little shot jQuery, an ajaxical JS framework which I by the way greatly recommend):
<!doctype html>
<html lang="en">
<head>
<title>Show progress of long running process with help of Thread and Ajax.</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(init);
function init() {
if (${not empty longProcess}) {
$.progress = 0;
checkProgress();
}
}
function checkProgress() {
$.getJSON('runLongProcess', function(progress) {
$('#progress').text(progress);
$.progress = parseInt(progress);
});
if ($.progress < 100) {
setTimeout(checkProgress, 1000);
}
}
</script>
</head>
<body>
<form action="runLongProcess" method="post">
<p>Run long process: <input type="submit"></p>
<p>Current status: <span id="progress">0</span>%</p>
</form>
</body>
</html>
Open it at http://localhost:8080/yourcontext/runLongProcess and click the button.
If this is a really, really long running process, you may improve "efficiency" by increasing the ajax intervals to 5 seconds or so so that the server doesn't feel getting DDOS'ed ;)
Hope this helps.

Your page may have returned some amount of data (such as headers) which convinced IE to leave the socket open and wait for more data.
To see what's actually going on, try running Wireshark (or Fiddler) on the machine with IE. You could also telnet to port 80 on your server and request the page manually (type in GET /path/to/your.jsp HTTP/1.0 followed by 2 line breaks).

I think you need to use AJAX technology to solve this kind of long operation problem, ask Server to maintain a connection over an hour is not an efficient decision.
What if more than hundred users connect to your server?
The concept of a simple AJAX solution is like this:
you start a timer using Javascript's setTimeInterval().
in timer's invocation, you compose a URL and use a XmlHttpRequest to request your server.
this async request will trigger(or just ask) a progress of a server-side back-end service.
every time the JS timer ticks, server-side should respond the progress(or result) to give user a visual response.
I think this is a better way to do your job. you can build this mechanism by your own or use some existing AJAX Framework like GWT, DWR even ZK to accomplish it.

Typically the "this page cannot be displayed" message occurs when the browser fails to make a connection to the host. In the scenario you've presented, the browser manages to make a connection and holds that connection open until the connection finishes or the server side hangs up.
If you are trying to test the functionality of the browser, you'll need to play some tricks on the network to have the connection fail. For example, firewall port 80 on your server such that it doesn't respond to any packets sent its way. The browser should leave the socket open for 60 seconds waiting for a response. When the response doesn't arrive the "this page cannot be displayed" message should be displayed.

Thanks for all your answers. We have a requirement where the users can wait longer. We are limiting the number of parallel requests by configuration in server (using Work Manager in WebLogic). If the number of parallel requests is more than the max no of threads, the requests are placed in queue. My questions if if the browser times out after 60 seconds as specified in the link - http://support.microsoft.com/kb/181050. We have done few tests and observing that page cannot be displayed message is displayed after 1 hour. We also checked response headers and no response content or response headers are returned back. So, we are not sure if either the server is timing our or browser is timing out. And also would like to check if IE6 times out after an hour or after 60 seconds as per the documentation.
Thanks

Related

Can I use Thread.sleep in a servlet to add random delays for the local server to answer my api call?

My deployed server has sometimes long response times, while working and developing at localhost all calls are really fast.
This has made my application enter unexpected behaviour once deployed a few times due to problems with resource loading taking too long.
I'd like to simulate in my local tests the bad connection with my real server, therefore I want to add a random delay to every request-response and my first thought was to use Thread.sleep in the servlet:
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//add delay before processing request
if (DELAY > 0){
int delay;
if (RANDOMIZE){
delay = Random.nextInt(DELAY);
} else {
delay = DELAY;
}
try {
Thread.sleep(delay);
} catch (InterruptedException e1) {
logger.error(e1);
}
}
...
However I have read that one should not use Thread.sleep() inside a servlet, but the context of such discouragement and their solutions are drastically different from my case, can I use thread.sleep() in this context?
EDIT: This is of course only for local and for the client to be strained a bit in the local tests... I just want to simulate the bad network I've encountered in reality!
I think this whole approach is flawed. I wouldn't introduce a random delay (how are you going to repeat test cases?). You can introduce a Thread.sleep(), but I wouldn't. Would this be in your production code ? Is it configurable ? What happens if it's accidentlally turned on in production ?
I would rather set up a test server with the exact characteristics of your production environment. That way you can not only debug effectively, but build a regression test suite that will allow you to develop effectively, knowing how the application will perform in production.
Perhaps the one concession to the above is to introduce network delays (as appropriate) between client and server if your users are geographically diverse. That's often done using a hardware device on the network and wouldn't affect your code or configuration.
I did this to get delay :
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("<meta http-equiv=\"Refresh\" content=\"3;url=home.jsp/\">");
}
Remember that in content=\"3;url=home.jsp/\", 3 is the delay seconds and home.jsp is the page you want to go to after the given seconds.

Long polling freezes browser and block other ajax request

I am trying to implement long polling in my Spring-MVC Web App but it freezes my browser and other request after 4-5 continues AJAX requests.I have no clue whats goin on here is my relevant code.
The controller method:(Server Side):-
#Asynchronous
#RequestMapping("/notify")
public #ResponseBody
Events notifyEvent(HttpServletRequest request) {
Events events = null;
try {
events = (Events) request.getSession(false).getServletContext().getAttribute("events");
System.out.println("Request Came from" + ((com.hcdc.coedp.safe.domain.User) request.getSession(false).getAttribute(Constants.KEY_LOGGED_IN_USER)).getLoginId());
if (!events.getTypeOfEvents().isEmpty()) {
System.out.println("Removing older entries");
events.getTypeOfEvents().clear();
}
while (!events.isHappend()) {
//Waiting for event to happen.
}
events = Events.getInstance();
events.setHappend(false);
request.getSession(false).getServletContext().setAttribute("events", events);
}catch (Exception e) {
e.printStackTrace();
}
return events;
}
The long-polling script(Client Side):-
$(document).ready(function() {
$.ajaxSetup({
async:true//set a global ajax requests as asynchronus
});
alert('Handler for .onload() called.');
waitForMsg();
});
function waitForMsg(){
xhr= $.ajax({
type: "POST",
url: '<%=request.getContextPath()%>/notification/notify',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
global:false,
success: function(data){ /* called when request to notifier completes */
/* Doing smthing with response **/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
UPDATE:
function updateFeed(event, data) {
var f=eval(data);
alert(f.typeOfEvents.length);
}
function catchAll(event, data, type) {
console.log(data);
alert("error");
console.log(type);
}
$.comet.connect('<%=request.getContextPath()%>/notification/notify');
$(document).bind('feed.comet', updateFeed);
$(document).bind('.comet', catchAll);
Neither alert box pops up..:(
Seems like you experienced the session file lock
For PHP
Use session_write_close() when you don't need session value
It seems you have an empty while loop in your browser code.. this is a very CPU instensive way to wait for an event.
If no events happen the client will kill the request after your desired timeout of 50 seconds. But I'm not sure if the server thread is killed too, or if it "whiles" on forever (unless there is an event). The next request will start a second server thread that hangs in the while loop too then. Maybe the amount of empty while loops is an overkill for the server, so that it stops accepting any more requests. So after some requests (that each triggered an endless server thread) the client waits forever on a new request.. because it can't be handled by the server.
ps: on success you commented to wait 1 second, but set the timeout to 10000 (10 seconds)
I've met similar problem, my browser was stucked somehow with AJAX requests. Hint: instead using waitForMsg() directly, try setTimeout("waitForMsg()",10).
FYI, here is a project that might help you: https://github.com/SeanOC/jquery.comet
In general, I would search for JavaScript comet APIs that can support web sockets if available on client / server with graceful fallback to long polling. The API should handle all the gory details, allowing you to focus on the application.
Here's a link to an old dojo article on the topic: http://dojotoolkit.org/features/1.6/dojo-websocket
Good luck.
You can try to rewrite the behaviour using jQuery deferred:
function setShortTimeout() {
setTimeout(waitForMsg, 1000);
}
function setLongTimeout() {
setTimeout(waitForMsg, 15000);
}
$(document).ready(function() {
$.ajaxSetup({
async:true//set a global ajax requests as asynchronus
});
alert('Handler for .onload() called.');
$.when(waitForMsg())
.done(successHandler, setShortTimeout)
.fail(errorHandler, setLongTimeout);
});
function waitForMsg(){
return $.ajax({
type: "POST",
url: '<%=request.getContextPath()%>/notification/notify',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
global:false
});
};
errorHandler and successHandler will be your success: and error: callbacks, which I omitted for clarity, with their setTimeout part removed (since it is now part of the deferred.done() and .fail() callbacks).
Let me know if it works.
I am a PHP developer but I met your problem and it could be the same behaviour. So I give you my 2 cents and hope it'll help you.
The line that does make me suspect a problem is :
events = (Events) request.getSession(false).getServletContext().getAttribute("events");
In PHP, sessions are stored in files, and if we are long-polling on a php script while the session is open, we meet a race condition problem.
The principle is quite simple :
When a request opens the session, file is locked until the session
is closed.
If other requests comes to the server, they will be locked until the
session is released from the previous request.
In a case of long polling, if the session is opened and not closed just after getting information (at least, just before waiting for events), all requests are just locked, you can't go anywhere else in the website if you're using sessions on other pages. Even if you open a new tab, because for one browser there is only one session, you're locked.
It may be this:
xhr= $.ajax({ (...)
in your waitForMsg function.
Try
var xhr = (...)
It may be that you are declaring xhr in the global object, thus making it impossible to respond to two different requests.

Multiple Connectors on a Jetty Server

I'm trying to run a Jetty Server that can have a number of people connect to the server and see a list of print outs. I want everybody who connects to see the same values printed out.
For instance, if I have a single list keeping track of the time and I want 5 or so people to be able to go to my website (e.g. localhost:8080/time) and have them all see what time it is every 30 seconds, how would i set that up?
What I have:
I am using Jetty.
I created a single server bound to port 8080.
I created my own handler that extends AbstractHandler
this writes to the screen saying when an event has transpired (i.e. 30 seconds have passed)
If two people connect to this page, they each see a print out every minute (that is it switches back and forth letting each person know when every other event has transpired)
If 3 people connect, only two can stay connected and the third just spins getting no output to the screen
I have not set up an Connectors of my own since my attempts to do so have been unsuccessful and i'm not sure how I understand if that is the solution to my problem.
Any help would be much appreciated and if anybody has some idea but needs some clarification on what I am doing I would be glad to give more details.
Thanks!
Handler code:
#Override
public void handle(String target, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException
{
httpServletResponse.setContentType("text/html;charset=utf-8");
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
request.setContextPath("/time");
request.setHandled(true);
while (true) {
synchronized(Main.list) {
while (!Main.list.isEmpty()) {
Double time = Main.list.get(0);
httpServletResponse.getWriter().println("<h1>The time now is " + time + "</h1>");
httpServletResponse.flushBuffer();
Main.list.remove(0);
}
try {
Main.list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
So the list object is a static ArrayList defined in the Main class that I wake up (i.e. notify) every 30 seconds. Hopefully this helps someone understand more what I am talking about as i'm not sure what I could change in the handler...
How are you feeding clients into your handler? Browsers have limits to the number of connections are made to to a particular host, perhaps your seeing that.
there is nothing intrinsically wrong that handler code aside from it being a generally odd thing to see in a handler

Session Destroyed; Print Message in JSP and Servlets

When a session has been destroyed, how do I print a message on a JSP that notifies the user? I'm using a class that implements HttpSessionListener.
When the session is destroyed, you can't do anything from the server side on anyway. At the point of session destroy there is no guarantee that you have valid request/response objects at your hands. Your best bet is to handle it fully at the client side, using for example JS. You can get the remaining lifetime of the current session by HttpSession#getMaxInactiveInterval() and you can use JavaScript's setTimeout() to run a function after some time.
<script>
setTimeout(function() {
document.getElementById('message').innerHTML = 'Session has timed out!';
}, ${pageContext.session.maxInactiveInterval} * 1000); // It returns seconds, but setTimeout expects milliseconds.
</script>
<div id="message"></div>

Setting up AJAX progress bar

Ok im new to AJAX. Kind of know about the lifecycle of a request, IE uses ActiveXObject stuff like that.
However now im faced with a real world problem. I have a servlet running in the background that performs a number of tasks and i would like to display a progress bar to show where the process is up to and to also show that something is actually happening.
So far in the server side i can calculate the number of processes that will take place before they begin, and easily enough add a counter to increment after each process completes - therefore enabling me to find the percentage i wish to show.
In terms of where i should output the data gathered from incrementing etc i'm not sure so far it is dormant as 2 integers in the processing java class.
Any help would be much appreciated.
So far i've taken a look at this and i guess thats kind of what im aiming for.
Cheers.
Basically, you'd like to store a reference to the task and inherently also its progress in the HTTP session (or in the Servlet context if it concerns an application wide task). This way you must be able to retrieve information about it on every HTTP request.
In JavaScript, you can use setTimeout() or setInterval() to execute a function after a certain timeout or at certain intervals. You can use this to repeatedly fire Ajax requests to request current status of the progress. Once the status is retrieved, e.g. in flavor of an integer with a max value of 100 (the percentage), just update some div representing a progressbar and/or the percentage text accordingly in the HTML DOM tree.
jQuery is very helpful in firing ajaxical requests and traversing/manipulating the HTML DOM tree like that. It minimizes the code verbosity and crossbrowser compatibility headaches.
Imagine that the doGet() of the servlet look like this:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String processId = "longProcess_" + request.getParameter("processId");
LongProcess longProcess = (LongProcess) request.getSession().getAttribute(processId);
int progress = longProcess.getProgress();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(String.valueOf(progress));
}
Then you can use it like follows:
function checkProgress() {
$.getJSON('progressServlet?processId=someid', function(progress) {
$('#progress').text(progress + "%");
$('#progress .bar').width(progress);
if (parseInt(progress) < 100) {
setTimeout(checkProgress, 1000); // Checks again after one second.
}
});
}

Categories

Resources