Java servlet and Ajax uploading files progress bar - java

Currently, i using XmlHttpRequest to uploading files to the server using HTML5 capabilities.
There's progress bar:
xhr.upload.addEventListener('progress', function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
console.log(done);
});
... everything works fine, but it doesn't consider processing the file by server. So it shows 100% uploaded even when file weren't created yet.
The file receiver is Java servlet, which able to response only after return. So here's no way to count the percents left by its response.
Whether there are ways around it?

If the processing the server does takes a long time and you want to give feedback while it happens, here's a rough outline of a solution. This will take a while to implement so it's only really worth doing if the processing is slow.
Modify your servlet to do its work asynchronously, and return a 201 Accepted response to the client.
As the server processes the file, set the progress on an object, typically a ConcurrentHashMap injected with Spring if that's what you're using.
Expose an API that queries the current progress of the task without blocking for it to complete.
In your javascript, poll this API until the task completes, and show the progress.
You can return a tracking ID in the response at step 1 if you need to.

Related

Is it legal to write and close the response in JSP, then do some extra job?

I'm working on a web app, which is communicating with the server with AJAX requests. A special type of "close" request takes 5 secs, which the web app should just fire-and-forget, the result is irrelevant. Due to browser behaviors (only limited number of simultaneous AJAX requests are performed), a 5-sec request may stuck other AJAX requests, which is unacceptable.
The smart folks here in StackOverflow has adviced me to write a small server-side proxy, which the web app should call instead of the original 5-sec one. The proxy should response immediatelly, close response channel, then perform a HTTP request and wait for it, spending the 5 secs server-side, instead of client-side. (The original question is here: See Is there a way to perform fire-and-forget AJAX request? )
The server is a Tomcat with JSP, and I can write small JPS pages. (I'm not an experienced JSP ninja, but I don't afraid of Java.) My question is: is it legal to write such a JSP, or what's the best practice:
send the response,
close reply channel (is out.close() enough?), in order to end the AJAX request at client-side,
fire and process (actually: just drop response) a HTTP request "in background", which may take as long as 5 secs?
It's not (only) your browser you should worry about. Blocking a tomcat thread for 5s severly limits your max-users as well (how many requests per second do you need to handle ultimately?)
So making it "more" asynchronous in the server might make sense.
Doing it in JSP (with Sriplets?!) alone will noway be a robust implementation - but if you need to do it that way, you should think about starting the "work to do" in a separate Thread.
So instead of
<%
do_something_heavy();
%>
You'll do like
<%
new Thread(new Runnable() {
public void run() {
do_something_heavy();
}
}).start();
%>
There's other options as well (JMS, ExecutorService, Spring #Async...) but this should get you started quick.
First the best is to separate business logic from view: it means write java code on a servlet and delegate only the view aspect to the jsp.
To execute your task asynchronously in the servlet code you can:
Invoke a submit method of an ExecutorService
Make a call to a JMS
Manually create a thread and start it
Then you can forward to the jsp.
TIP: It is possible to assign an id to the long task and return it in the jsp with a link to monitor the status of the task.
Basically you do something like that:
Accept the request
Start asynchronously a thread to execute the long task
Return immediately without waiting for the long task termination
Or using an id:
Accept the request
Calculate the id of the task
Start asynchronously a thread to execute the long task with the desired id
Return immediately a link with the id of the long task without waiting for the termination

Are asynchronous servlets possible in Java 1.5?

I have a servlet that does a lot of file IO to a network share and therefore runs long. I want to implement a progress bar on the front end instead of a simple spinner gif so the user knows something is actually happening and it's not just "stuck."
I'm running Java 1.5 on Websphere 6.1 and there's no upgrading in sight. I know with the Servlet 3.0 spec, asynchronous servlet support is built-in, but I'm wondering if there is a workaround or something similar where I can fake it to look asynchronous?
I make a simple ajax call using jQuery:
$.ajax({
url: "/servlet.action",
success: function(json, status, xhr) {
alert("success");
}
});
Can the servlet periodically send status updates back to the client as it makes its way through the process, or should the client make periodic status requests to the servlet (or another servlet that has access to the main servlet's status)?
I cannot upgrade the versions of Java and/or Websphere at this time.
I found a workaround for this:
Send an asynchronous request to start the process. This servlet updates a static object with the status of the processing. (like a Map of some kind of session/request identifier → process status)
Periodically send another asynchronous request to a different servlet with access to that static object and return the current status. The status could be a number (% complete), a String (status message), or an Object that contains a bunch of information.
Then the periodic request can handle the status and update a progress bar or something.
This can be done in any type of servlet container with any Java version.

How to continue on client when heavy server computation is done

This might be a simple problem, but I can't seem to find a good solution right now.
I've got:
OldApp - a Java application started from the command line (no web front here)
NewApp - a Java application with a REST api behind Apache
I want OldApp to call NewApp through its REST api and when NewApp is done, OldApp should continue.
My problem is that NewApp is doing a lot of stuff that might take a lot of time which in some cases causes a timeout in Apache, and then sends a 502 error to OldApp. The computations continue in NewApp, but OldApp does not know when NewApp is done.
One solution I thought of is fork a thread in NewApp and store some kind of ID for the API request, and return it to OldApp. Then OldApp could poll NewApp to see if the thread is done, and if so - continue. Otherwise - keep polling.
Are there any good design patterns for something like this? Am I complicating things? Any tips on how to think?
If NewApp is taking a long time, it should immediately return a 202 Accepted. The response should contain a Location header indicating where the user can go to look up the result when it's done, and an estimate of when the request will be done.
OldApp should wait until the estimate time is reached, then submit a new GET call to the location. The response from that GET will either be the expected data, or an entity with a new estimated time. OldApp can then try again at the later time, repeating until the expected data is available.
So The conversation might look like:
POST /widgets
response:
202 Accepted
Location: "http://server/v1/widgets/12345"
{
"estimatedAvailableAt": "<whenever>"
}
.
GET /widgets/12345
response:
200 OK
Location: "http://server/v1/widgets/12345"
{
"estimatedAvailableAt": "<wheneverElse>"
}
.
GET /widgets/12345
response:
200 OK
Location: "http://server/v1/widgets/12345"
{
"myProperty": "myValue",
...
}
Yes, that's exactly what people are doing with REST now. Because there no way to connect from server to client, client just polls very often. There also some improved method called "long polling", when connection between client and server has big timeout, and server send information back to connected client when it becomes available.
The question is on java and servlets ... So I would suggest looking at Servlet 3.0 asynchronous support.
Talking from a design perspective, you would need to return a 202 accepted with an Id and an URL to the job. The oldApp needs to check for the result of the operation using the URL.
The thread that you fork on the server needs to implement the Callable interface. I would also recommend using a thread pool for this. The GET url for the Job that was forked can check the Future object status and return it to the user.

How to create Ajax request that gets information as the servlet runs?

I have a form that creates an account and a servlet that handles the request.
However, the process to create this account is a long process and I want to create something like a status bar or a progress bar. Heres the POST:
$.post("createAccount.jsp", function(data) { $("#status").text(data);
});
And the servlet would continuously print data like "creating x..." then "creating y" as the servlet runs. Is there a way to accomplish this or maybe another way to tackle this issue?
Thanks
Http works on a request-response model. You send a request, and server responds back. After that Server doesn't know who are you?!
It's like Server is a post-office that doesn't know your address. You
go to it and get your letters.It doesn't come to your home for
delivering letters.
If you want constant notifications from server, You can either use Web Sockets(Stack Overflow also uses Web Sockets) or use `AJAX Polling' mechanisms,
which sends an AJAX request to the server and waits for server to
respond. On retrieval of response,it generates another AJAX request
and keep on doing the same until server stops generating new data.
Read this for an explanation of AJAX Polling techniques
You could have your account creation servlet update a database or context attribute as it creates the account.
You could have a separate AJAX request to a different servlet that sends back to the webpage the most recent development found in the database or context attribute. You would then poll your server with that AJAX request every so many fractions of a second(or relevant time interval depending on how long of a task it is to create an account) to get all the updates.

Showing a progress bar when downloading a file from the server

I need to show a progress bar to the user who requests a file to download. I am using J2EE application to generate the file. User will submit the form data to get the file. The server takes all the submitted data manipulates, generates and sends a PDF file back to Client.
So I want to show a progress bar to the user till the file comes to the Client side.
Is there any way to do this ?
If I understand you well, you want to show a progress bar until your server is ready to send a file, not to show the progress of the file beeing downloaded.
If that is true, you're dealing with a tough excercise. A reliable progressbar needs to know (pretty exact) what you're doing and how long it will take. In your case, there are lots of unreliable factors (one of them, maybe the biggest, is the web itself).
So most developers use some kind of an "endless" animation to display "work in progress".
update
Based on your comment, the easiest way to display a "work in progress" animation would look like
$.ajax({
url: "/myscripts/myserverscript",
type: "POST",
data: {
foo: "bar"
},
dataType: "text",
beforeSend: function(xhr){
// display a progress animation
},
complete: function(xhr, status){
// hide the animation
}
...
});
In the case of a single request. You may also setup a global ajax event handler for both (.ajaxStart() and .ajaxStop()) to setup the show/hide functionallity.
References: .ajax(), .ajaxStart(), .ajaxStop()
progress bar for server side file generation:
We assume that the server needs many seconds to generate the file. This event is triggered by the original request, a blocking operation. When this finishes the file will have been generated and it'll be dispatched back to the client.
At the same time you want, via other requests (ajax), to be calling the server and getting a percentage back for the file which is currently being generated for the particular user.
The glue parts here are:
when the original request is generating the file it needs to store the progress in frequent intervals (i.e every 10%). Storing this data in the http session will work OK.
the other requests (ajax) simply need to be able to pull this information out of the http session
synchronizing (serializing access) on the http session, something that some web apps commonly do, is out of the question, since the other requests (ajax) would simply block until the original request finished
on the client side it's all html+javascript to provide the interaction you need (animated progress bar). Even if the intervals are very rough (jumping from 10% to 20% to 30%) you can animate the bar with jQuery. I've done it once in the past and it looks great.
progress bar for file download:
it's best to leave this to the browser's native dialog.
In Java you just wrap a javax.swing.ProgressMonitorInputStream around the input stream, but be aware that unless the server is sending in chunked streaming mode the display won't really mean anything, as the entire response will have been read into memory before the first byte is delivered to Java.
Using XMLHttpRequest you can download file and show progress.
showProgressBar();
var xhr = new XMLHttpRequest();
xhr.open("GET", 'https://upload.wikimedia.org/wikipedia/commons/d/dd/Big_%26_Small_Pumkins.JPG', true);
xhr.responseType = "blob";
xhr.onprogress = function (e) {
console.log(e.loaded / e.total * 100);//shows downloaded percentage
setProgressBarPercentage(e.loaded / e.total * 100);
}
xhr.onload = function () {
hideProgressBar();
var urlCreator = window.URL || window.webkitURL;
var url = urlCreator.createObjectURL(this.response);
var link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', 'FILENAME');
link.click();
}
xhr.send();

Categories