Just a quick intro before I launch in to the details. I'm what would be described as a veteran C++ programmer and as a consequence never had any experience with Java hence this submission for information from that that know, so please be gentle.
But I have created a Servlet that executes a long running process. Via the JNI bindings this process produces feedback via a static callback function. Now depending on how long the process runs for this callback can be executed 100s of times. What I want to do is provide the user with this information or at least some of it, so that that know progress is being made.
I am willing to roll up my sleeves and write an applet for the interface as this would also allow me to display the results when the process has finished as well as the feedback. However, I'm not convinced that this can even be done. Am I right?
Or, is there a way I can 'push' the feedback results and actual results back to an applet, or do I need to adopt another approach using sockets or similar?
If you search the web for "progress indicator" you'll find several techniques for implementing this.
Joined: Aug 21, 2010
Thanks for the input but a progress bar is of no use in this instance as I do not know how long the task will take. The process can take anything from 2 to 10 minutes to complete depending on the complexity of the numbers being crunched.
Also, my main issue is getting the feedback from the number cruncher running on the server (via the servlet) to the client who of course could be anywhere in the world.
Progress bars do not have to indicate a percentage, they can simply indicate... progress. And as long as you can query the process from Java, getting feedback to the client is easy, just like a progress bar that *does* indicate an absolute value.
Author and all-around good cowpoke
I know progress bars do not have to reflect a percentage, I have used them in C++ land. Your next point is the point in question: it is querying the process and getting the values back to the client that I am having issues with.
The 'Number cruncher' lives on the Server and is a legacy system by a third party. It is interfaced to the Servlet using JNI Interfaces provided in a DLL that I load in the Servlet. So I guess it is on the requesting thread! Only as I do not know any better.
Anyway, using these Interfaces I can hook in my static callback functions. Within the callbacks I can write to system.out so I know that the callbacks are being called.
But I don't want the output from the callback in System.out I want them 'pushed' back to the client applet and have it display them on the UI.
Can I assume from your comments that I should move the number crunching to a new ? (I don't know what) and call this with the parameters passed in from doPost(). If this sounds sensible then what do I create to do the crunching and how do I tie, the number crunchers output to the calling applet?
I'm not asking anyone to write this I just want sound and sensible advice from my peers and those that know a lot more than I do on the subject. I hope you understand.
Author and all-around good cowpoke
Joined: Mar 22, 2000
I would certainly put ALL of the code involved in invoking the "number cruncher" in a separate class executing its own Thread.
Make this a class that can be tested outside the servlet environment so it can be thoroughly tested without the complications of servlets. I typically write a main method which accepts command line parameters to set up a test run.
Your applet can connect to a servlet which will start the number cruncher job and have to have functions to check on the progress and relay the current status. This will involve repeated request/response cycles as no request should wait more than a few seconds.
(I'm not sure if the applet part was because it was assumed it was necessary, or if it's an actual requirement. Just to keep things clear, it's not necessary from a technical standpoint, and if you don't need what they bring to the table, I wouldn't use one.)
Just to summarize some of the things that have been hinted at but not explicitly said:
With Servlets you don't usually 'Push' the status of long running tasks to the client. Instead the client has to 'Pull' the data. This is because HTTP is a Request/Response cycle - Clients Request info, Server Responds with it. These cycles are intended to be short, and making them long can cause trouble by clogging the server with open connections.
So to get the status of any long task on a web-based app you generally have the client make multiple request to the server asking for the status. Then when the status is done, the client asks for results.
So in your situation you have a DLL which has the work to do in it. What has been suggested is a normal Java object (not connected to a Servlet), let's call it a Manager, which starts the work and keeps track of its status and results. The Java object would provide methods to tell the Manager when to start the work, as well as methods to ask the Manager what the current status is, and get the results when appropriate. When you are ready you then add the Servlet layer which provides a Client-visible means of calling those methods. You may have one Servlet which creates the Manager object and calls the method which starts the work, a second Servlet which gets the already-made Manager object and calls a method to get the status, and writes the status to the response. A third servlet might then call the Manager's results method and send that as a response.
Your client would then manage calling the Servlets at the proper time (pseudo code):
(For the OP: DWR must be configured to use Comet, otherwise it's pseudo-push. Plus Comet may not be the best solution under all circumstances.)
Joined: Aug 21, 2010
Well things are becoming clearer so thank you all for your input, I do appreciate it. I will now take some time to go and do some reading to see what ideas I get, but I will no doubt be back at some point.
In the mean time just one more thing. Due to the potential load on the server and the possibility of what I would call 'cross contamination' is there a way to isolate one number cruncher from another?
Since this solution is web based there is of course nothing stopping anyone from running multiple instances but I can take care of this using session management. However what I do not want is the data inputs, feedback or data output from the number cruncher 'contaminating' each other and being sent to the wrong user.
What would be the best approach / method / pattern to manage this, remembering of course that the callbacks are static. Ideally I need to instantiate totally autonomous instances of the number cruncher.
Bill Moo wrote:Since this solution is web based there is of course nothing stopping anyone from running multiple instances but I can take care of this using session management. However what I do not want is the data inputs, feedback or data output from the number cruncher 'contaminating' each other and being sent to the wrong user.
Can you get the operating system's process ID of the number crunching process? Maybe you could associate this with the session object in order to prevent the cross contamination. If you could also retrieve this ID from the callback function, you could determine exactly which process was invoking the callback.
[quote=Bill Moo]What would be the best approach / method / pattern to manage this, remembering of course that the callbacks are static. Ideally I need to instantiate totally autonomous instances of the number cruncher.[/quote]
Sure. Just keep a reference to the number cruncher in the user's session. (If you meant you were using static methods when you said the callbacks were "static", then don't do that.)
Joined: Aug 21, 2010
Paul Clapham wrote:Sure. Just keep a reference to the number cruncher in the user's session. (If you meant you were using static methods when you said the callbacks were "static", then don't do that.)
I don't have any choice in the matter, that is the way the legacy API defines them so I am kind of stuck with it.