I have an HTML page with 3 input fields, when the user clicks the submit button, a AJAX request is made using jQuery to a servlet with the conetnts of the 3 fields.
When the requests arrives in the server (my servlet), I need to create a thread for each input field, and manage this thread pool, put them in order.
For example; If thread 1 finishes earlier, then thread 2 should print the response to the client, before the next thread. I'm currently using a sleep method in each thread with a random sleep time, to determine the time each thread should take.
On the client side, in the HTML, I've an element to show the response.
To send the information to the client, I just need to call PrintWriter.write on the servlet side.
The problem that I'm having is that the information of each thread appears at client side at the same time.
The output only appears on client side after all the threads have finished.
For example; I have thread a which took 200ms, a thread b which took 300ms, and a thread c which took 100ms.
The result on client side will only appear after 300ms, for example the result would be the string "cab".
So I have the following JavaScript function on my HTML page:
$.ajax({
type : 'get',
url : 'ServletResponse2',
data : {
"name1" : name1,"name2" : name2, "name3" : name3
},
success : function(xhr,data) {
console.log("xhr:"+xhr);
console.log("xhr text:"+xhr.responseText);
console.log("data:"+data);
console.log("data2:"+data.data);
$("#listResponse2").append("<li>" + xhr);
$("#listResponse2").append("</li>");
},
complete : function(xhr,data) {
response = xhr.responseText;
console.log("exception:"+response);
$("#listResponse").append("<li>" + response);
$("#listResponse").append("</li>");
},
error : function(e) {
console.log("exception:"+e);
}
});
Then, in the servlet, I have this get method calling a executor service, which calls a Class Worker Thread which implements Runnable:
protected void doGet(HttpServletRequest request,HttpServletResponse response)
{
ExecutorService executor= Executors.newFixedThreadPool(3);
PrintWriter out=null;
response.setCharacterEncoding("UTF-8");
String name1 = request.getParameter("name1");
String name2 = request.getParameter("name2");
String name3 = request.getParameter("name3");
String name="";
for (int i = 1; i < 4; i++) {
name=request.getParameter("name"+i);
try {
out = response.getWriter();
Runnable worker = new WorkerThread("" + name,response);
executor.execute(worker);
} catch (IOException e) {
e.printStackTrace();
}
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
out.print(name);
}
In the WorkerThread.java, I created a run() method which is writing the response for each servlet, I even used the out.flush() and response.flushbuffer() methods.
public class WorkerThread implements Runnable {
private String command;
PrintWriter out;
HttpServletResponse response;
public WorkerThread(String s,HttpServletResponse sresponse){
this.command=s;
this.response=sresponse;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);
try {
out = response.getWriter();
out.write(command);
out.flush();
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
processCommand();
System.out.println(Thread.currentThread().getName()+" End.");
}
private void processCommand() {
try {
Long time=(long)(Math.random() * 5000);
Thread.sleep(time);
System.out.println("Thread.getName():"+Thread.currentThread().getName()+"|comand:"+command+"|time:"+ time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public String toString(){
return this.command;
}
}
I also tried to use a Callabe in the executor service instead of a Runnable, but the result was the same. Can anyone tell me what I'm doing wrong, and why the result of the threads is arriving at the same time to the client?
Well no matter what you do in your servlet you are using HTTP protocol between a client, the browser and a server, the java application.
The protocole says : browser prepares and send a request, and the servers gets the request, and elaborates and send a response : one response per request.
The three threads write in the same reponse. Hopefully, your the 3 threads run one at a time and each write little to the response, if not you could have output of threads intermixed. And your servlet kindly waits the end of the threads to terminate, if not the servlet container would have closed the response before the threads have time to write anything.
You did not say what you were trying to achieve, I suppose you wanted to test asynchronous loading of information. For that you need multiple requests : one to initialize the operation, and one for each piece of information, the servlet using the session to register what it has transmitted and what remains, or the client side identifying the pieces it wants. But a detailed workthrough is far beyond what I can put in this answer ...
In fact when in a browser you see pages coming pieces by pieces it is exactly what happens : a first request for the HTML part, then optionally others for css, jsp, images, videos.
Related
I have method in class MyClassB which is triggered asynchronously from a method of MyClassA:
public void getProductCall()
{
new Thread(new Runnable() {
#Override
public void run() {
try {
productRequest = service.createS4ProductRequest(getRepriceItems());
//Below is a rest call to another system
String response = pricing.getS4ProductResponse(quote.getAssetQuoteNrAndVrsn(), productRequest);
//I'm using the below 2 lines to check from ClassA's method to see if this process has ended
setProductResponse(response);
productPriceProcessEnded=true;
} catch (Exception e) {
productPriceErrorOccured=true;
e.printStackTrace();
}
}
}).start();
}
This is the piece of code in MyClassA i used to check if the above method is complete.
for(int i=0;i<1000000000;i++)
{
if(!networkAsynCalls.isListPriceErrorOccured())
{
if(networkAsynCalls.isListPriceprocessEnded())
{
return networkAsynCalls.getListReponse();
}
else
{
Thread.sleep(250);
continue;
}
}
else
return null;
}
instead of using this random for loop can i use some inbuilt method or service pool or something ?
Because,
1) This thread on method is in another class
2) In class MyClassB i have few more methods like this, so i need to check the status of all the methods in MyClassA
Thanks for any help.
If I undestand what you're trying to do is dispatch some code to be ran asynchronously, then be able to wait until it is completed (successfully or failed). If that's the case, you should take a look at Futures.
Here is an example based on the Javadoc:
FutureTask<String> future =
new FutureTask<String>(new Callable<String>() {
public String call() {
// do stuff
return "result";
}});
This code creates an object "future" that can be invoked to execute searcher.search(target). At this point, the code is not executed at all. You simply have an object representing a computation that may be executed asynchronously. To do so, you'd call:
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(future);
This snippet created an Executor (which is a fixed pool of 5 threads), then handed over the future to it for execution. The executor will run the computation from Future asynchronously.
Future offers some methods (see the Javadoc) to wait until completion, cancel, check completion status, etc. For example,
String result = future.get();
will block, waiting for the result indefinitely. A get(10, TimeUnit.SECONDS) will wait for 10 seconds and if the future has not completed, throw.
I have created a POST endpoint using DropWizard.
#POST
#Timed
public String runPageSpeed(#RequestParam String request) {
try {
JSONObject requestJSON = new JSONObject(request);
JSONArray urls = requestJSON.getJSONArray("urls");
process(urls); // this takes around 10 minutes to complete
return "done";
} catch (Exception e) {
throw new WebApplicationException("failed", Response.Status.INTERNAL_SERVER_ERROR);
}
}
process(urls); takes around 10 minutes to complete, so if we call this endpoint, it takes more than 10 minutes to get the response.
I want process(urls); to run in the background after receiving the URLs from the request and immediately return a response to the user.
I tried the following code using threads:
#POST
#Timed
public String runPageSpeed(#RequestParam String request) {
try {
JSONObject requestJSON = new JSONObject(request);
JSONArray urls = requestJSON.getJSONArray("urls");
Thread thread = new Thread() {
public void run() {
process(urls); // this takes around 10 minutes to complete
}
};
thread.start();
return "done";
} catch (Exception e) {
throw new WebApplicationException("failed", Response.Status.INTERNAL_SERVER_ERROR);
}
}
This works, but are there any issues if I use this approach, especially at a high volume?
DropWizard users should promote using CompletableFuture for async handling as it is the safest for handling background processing. With CompletableFuture you can move the heavyweight task to a background thread and simultaneously continue with the lightweight task thus can also send back a response to the client.
#POST
#Timed
public String runPageSpeed(#RequestParam String request) {
try {
JSONObject requestJSON = new JSONObject(request);
JSONArray urls = requestJSON.getJSONArray("urls");
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
// perform heavyweight task
process(urls); // this takes around 10 minutes to complete
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// perform lightweight task
return "done";
} catch (Exception e) {
throw new WebApplicationException("failed",
Response.Status.INTERNAL_SERVER_ERROR);
}
}
CompletableFuture helps in every aspects whether its using the return value of first complex task into second function or notifying on failure with the vast variety of methods it provides
runAsync()
supplyAsync()
thenApply()
thenAccept()
thenRun()
exceptionally()
handle()
You can also chain the CompletableFuture using thenCompose() and thenCombine() which is used when one task is dependent upon others.
I'm using Cucumber to test my service when it is deployed to a container. The request contains a URL the service calls when the operation is successful. What is a good way to create a Cucumber test that waits for the Http callback? The Gherkin script would look something like.
Scenario: Process Order
Given An Order has been submitted
When the Order is processed
Then the order process service calls back with a successful status message
What would the Java glue code look like?
Here's the solution I came up with using an embedded http server. In the OrderSteps.java glue code I added a class used to start the server on another thread.
private static class Callback implements Runnable
{
public void run()
{
HttpServer server;
try
{
server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/callback", new CallbackHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
catch (IOException e)
{
logger.debug("HTTP server loop failure.", e);
}
}
static class CallbackHandler implements HttpHandler
{
#Override
public void handle(HttpExchange t) throws IOException
{
// Read the message and set the global variable
// which informs the main test thread a callback
// has been received.
InputStream is=t.getRequestBody();
byte[] buf=new byte[1000];
int len=is.read(buf);
OrderSteps.receivedCallback=new String(buf,0,len);
String response = "Callback received.";
t.sendResponseHeaders(200, response.length());
// Send response
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
Then in the OrderSteps class, in the step/method that publishes the Order, the server thread is started and then the order is submitted. This guarantees the server will receive the callback, since it is listening before the order is submitted.
// Start a listener for the callback.
Thread callbackThread = new Thread(new Callback());
callbackThread.start();
In the step/method that checks if the callback was received, there's a loop checking the static variable to see if it has been set.
// Allow 5 seconds for the callback to occur.
for (int i = 0; i < 5; i++)
{
if (receivedCallback != null) {
break;
}
Thread.sleep(1000);
}
if (receivedCallback == null) fail("Callback was not received.");
assertEquals("Expected callback message", receivedCallback);
I am confused with Async feature introduced in Servlet 3.0 spec
From Oracle site (http://docs.oracle.com/javaee/7/tutorial/doc/servlets012.htm):
To create scalable web applications, you must ensure that no threads
associated with a request are sitting idle, so the container can use
them to process new requests.
There are two common scenarios in which a thread associated with a
request can be sitting idle.
1- The thread needs to wait for a resource to become available or process data before building the response. For example, an application
may need to query a database or access data from a remote web service
before generating the response.
2- The thread needs to wait for an event before generating the response. For example, an application may have to wait for a JMS
message, new information from another client, or new data available in
a queue before generating the response.
The first item happens a lot (nearly always, we always query db or call a remote webservice to get some data). And calling an external resource will always consume some time.
Does it mean that we should ALWAYS use servelt async feature for ALL our servelts and filter ?!
I can ask this way too, if I write all my servelts and filters async, will I lose anything (performance)?!
If above is correct the skeleton of ALL our servlets will be:
public class Work implements ServletContextListener {
private static final BlockingQueue queue = new LinkedBlockingQueue();
private volatile Thread thread;
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
ServiceFecade.doBusiness();
AsyncContext context;
while ((context = queue.poll()) != null) {
try {
ServletResponse response = context.getResponse();
PrintWriter out = response.getWriter();
out.printf("Bussiness done");
out.flush();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
context.complete();
}
}
} catch (InterruptedException e) {
return;
}
}
}
});
thread.start();
}
public static void add(AsyncContext c) {
queue.add(c);
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
thread.interrupt();
}
}
I am creating a j2me application which is interacting with a database on a server. Therefore I launch a thread to connect to the server. I handle all my command actions in a separate class which implements CommandListener.
When I try to get the response the server returned I get an empty String. I have tried waiting for the thread that connects to the server to return but this makes the application unresponsive.
Below is the code I am using.
//my network worker class.
public class NetworkConnector implements Runnable {
//constructor
public NetworkConnector(String url){
//url =>server url to connect to.
Thread thread = new Thread(this);
thread.start();
}
private String serverReply="";
private String url="
//method to connect to the server and return the
//response from the server.
public String sendData(String serverUrl) {
//open streams to connect to the Server.
httpConn = (HttpConnection)
Connector.open(serverUrl,Connector.READ_WRITE, true);
httpConn.setRequestMethod(HttpConnection.GET);
inStream = httpConn.openInputStream();
int read;
while ((read = inStream.read()) != -1) {
sb.append((char) read);
}
return sb.toString();
}
public String getServerReply() {
//serverReply is a class variable.
return serverReply;
}
public void run(){
//call the send method that connects to the server.
serverResponse = sendData(Url);
}
} //end of connector class.
// this class is where all my Command Actions are
//implemented.
public class CommandActionController implements
CommandListener, DataReceiver {
public void commandAction(Command cmd, Displayable d) {
//networkMgr => is the worker class that makes
//connection to the server.
networkMgr = new NetworkConnector("http://localhost
/JsonPhp/login.php?uname=" + loginUserInfo.userName +
"&passwd=" + loginUserInfo.password);
//here am getting the response from the server.
String serverResponse = networkMgr.getServerReply();
//at this point the ServerReponse String is Empty =>
//yet the server is supposed to return some String.
System.out.println("xxxxxxxxxxxxxxxxxx
ServerResponse =" + serverResponse);
}
}//end of CommandListener class.
Your expectations about serverResponse value are wrong; it can be empty at the moment when you attempt to obtain it in commandAction with the code snippet in the question.
In order to get non-empty value, you need to redesign method NetworkConnector.getServerReply() to make it properly wait until thread finishes and server response is indeed obtained.
If you do that, however, you will also have to redesign CommandActionController to keep user interface responsive - your testing with "waiting for the thread that connects to the server" has shown just that.
Redesigned code should just launch the server connect thread and exit the commandAction as soon as possible (possibly changing to some "wait screen" to let user see what happens). Next screen update should be triggered only after server response is obtained.
Consider studying a tutorial specifically targeted on explaining how to properly design this kind applications - Networking, User Experience, and Threads:
This article explains how your MIDlet can make network connections without compromising your user interface. It includes six iterative examples that illustrate multithreaded networking and the use of a wait screen...
Here is how I'd do without java.util.concurrent:
Result handleRequest(){
final String url = // get url
Work work = new Work(url):
Thread t = new Thread(work);
t.start();
// do other stuff
if(t.isAlive()){
// still running
}
// this waits until the work is done
// and it will be safe to access work.result after
// this call has returned.
t.join();
return work.result;
}
and then
class Work implements Runnable{
final String url;
Result result;
public void run(){
this.result = // do your network stuff
}
}
You shouldn't start a thread in the constructor. Also, runnable are meant to be passed to threads. The easiest (and the "proper") way of doing this would be as follows:
Implement a Callable instead of a Runnable.
Use a ExecutorService instead of a Thread
Use Future object to do the processing asynchronously/be responsive to user
Here is a simple example.
class Stuff {
final ExecutorService exec =
Executors.newCachedExecutorService(// please see doc);
Result process(String url){
Future<Result> future = exec.submit(new Work(url));
// do some other stuff
if(future.isDone()){
// return result?
}
return future.get(); // this call will wait until result is available
}
}
and then
class Work implements Callable<Result> {
final String url;
Result call() throws Exception {
// do your network stuff here
return result;
}
}
See documentation of java.util.concurrent.ExecutorService.submit(), java.util.concurrent.Future and java.util.concurrent.Callable for details.