How to call HTML / JSP code from Java Thread - java

In my web application, I have a JSP page to which allows a user to upload a CSV file.
When user submits this upload form, control goes to a Struts2 action,
from this action I am starting a new Java thread which handles the reading and processing of this CSV.
I don't want to block the view of application as CSV can be very large so thread handles the uploading and reading of CSV
and action returns to some confirmation view page.
Now I want to notify user when thread completes its execution and uploading of file is done.
As soon as thread finishes its execution, I want to pop a javascript alert in my web app
with a message "Upload complete. Click here to view".
My current approach(not good) is to pass session object to thread and set a completion flag in thread.
Action
//----
new Thread(new UploadThread(session)).start();
//----
UploadThread.java
//----
try {
//Reading and processing CSV
} catch() {
//Exception handling
} finally {
//Set flag in every case
session.setAttribute("uploadFlag","true");
}
//----
In the meantime, I set a JS method from one of my JSPs to execute in every 5 seconds. In every 5 secs,
this method checks "uploadFlag" from session and if its value is set, it pops javascript alert.
This is working but session object should not be in Thread.
Is there some way to achieve this alert from Thread's finally block.
I did some googling and found these SO posts-
Open local html page - java and
Getting java gui to open a webpage in web browser
Apart from these I've tried to use java.net.URL + openConnection and HttpClient also.
But all these return output of target URL in stream.
Kindly suggest.

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

How to run a process in background and redirect a jsp page

I am using Jsp and servlets. In one of my jsp page I will call a .sh file which will execute for 2-3 minutes and after the process is completed It will redirect to another jsp page.
My problem is the user has to wait for 2-3 mins and then after the process completion only he is re-directed to the next page. I don't want this to happen I want to start that process which must run in background and I want the page to be redirected immediatly.
process.jsp page
FileWriter fileWriter = new FileWriter(file3,true);
BufferedWriter bufferFileWriter = new BufferedWriter(fileWriter);
fileWriter.append(userid+"\t"+movie_id[i]+"\t"+ratings[i]);
fileWriter.append('\n');
bufferFileWriter.close();
Process p=Runtime.getRuntime().exec("/home/yoganandhd/project.sh");
p.waitFor();
response.sendRedirect("login.jsp");
In the above code, to execute project.sh it will take 3 mins where it will do some datamining process and then only it is getting redirected to the login.jsp page.
My requirement is the user cannot wait for 3 mins, he must be redirected to the next page immediatly by running the project.sh at the background.
I am a fresher I dont know much about java can anyone say how can I acheive this?
Can I acheive this using thread? If yes how?
Someone please explain me with an example of same scenario.
You can create a new thread and execute the shellscript separately.
public class MyThread extends Thread {
public void run(){
Process p=Runtime.getRuntime().exec("/home/yoganandhd/project.sh");
p.waitFor();
}
}
Now invoke this thread from your actual flow as below, instead of invoking the job directly.
MyThread myThread = new MyThread();
myThread .start();

Press a button to carry out an async http get request and flash success on current page if successful (http.OK)

I have a button in play framework web app that links to a routes.Application.refresh
I need it to trigger a separate HTTP GET request say,
http://somehost/restful/refresh?id=123
If the GET request results in a success/200 response, then flash a success note onto the current page where the button we pressed lives. How can I do this?
Here is the myapp.controller.Application.java :-
public static Result refresh() {
flash("success", "cache refreshed successfully on somehost");
return GO_HOME ;
}
The flash part is not really that interesting when doing ajax, it is more for full page reload and then showing it in a play template.
Normally you would write a js callback in your ajax logic that will react on a success (or error) and shows the ui-component that you want the user to get as feedback. This can be done in a million ways, one example would be using jquery.

How can i write a loading page with play framework

I would like to implement a page that be displayed to the user whilst a system command is run. As soon as the command completes the user should be routed to another page.
What are some strategies to implement this?
(A solution without javascript would be ideal)
It can definitely be done. You want to look at Asynchronous programming with HTTP in the documentation, it explains how to do this in a non-blocking way. You will need a little bit of javascript for the redirecting part though.
And I don't know what you mean with "system command" but you probably want to create a job for it, so you can trigger it with a request. You can then poll it until it's finished and then redirect the user. But really the documentation does an infinitely better job at explaining it then I'm doing now.
Here's an example of a controller action where I assume your system command returns some kind of String output for the user. When the Job is completed it will sent a response to the user, thus triggering the success handler in the javascript example.
public static void executeSystemCommand(String input) {
Promise<String> outputPromise = new SystemCommandJob(input).now();
String output = await(outputPromise);
renderText(output);
}
Basically if you're using jQuery's $.ajax you can use the complete event to poll the data (just do the request again if it didn't succeed within the timeout time) and use the success/done event to redirect the user when the application responds to indicate that the "system command" is done running.
Example of a function you could use:
function poll(){
$.ajax({
url: "/systemcommand",
success: function(data){
// redirect to next page here
document.location.href = '/output'
},
complete: poll,
timeout: 20000
});
};
There is also a great example on long polling in javascript on StackOverflow.

Processing a large file with a web service

I have web service method that is supposed to process a very large file and output several files to the server. However, this web service will just timeout and there will be no way for the invoker to get the CREATED status. I am just wondering whether there is a way to run the processing job (starting a new thread or something) and return the status without waiting for the process to be done.
public Response processFile(InputStream inputStream){
//I want to process the file here
//but I dont want the invoker to wait for that process to finish
//I just want the response to be returned right away
return Response.status(Response.Status.CREATED).build();
}
The file comes from the input stream, right? So if you'll send back a CREATED status (effectually closing the connection) you might sever the connection before you receive the entirety of the input file?
That's what i thought anyways... In which case you'll just want to set the timeout to a lengthier value.
If that's not the case, then i guess it would be fine to start a new thread, process everything there in good time and send back the CREATED status.

Categories