How to make a servlet respond to multiple requests? - java

I have a task that I want to wrap in a servlet to provide the ability to run the task remotely, by http request.
I know I can achieve this with REST API, but currently I assume (and please correct me if I'm wrong) that a simple servlet will do.
One of the things I want to achieve is that if a request to the servlet is made while another request is still processed, I'll get an appropriate response - "Task is already running".
I've built a simple servlet, using servlet-3.0, that calls the jar I want to run, but when I make 2 requests, the second one is not processed until the first one is finished.
EDIT:
My servlet is a simple http serlvet. service method overriden.
I have a system.out.println("a") in the start.
when I call the servlet in debug mode and then (while stopped at breakpoint) call it again, the message is printed only one time and printed the second time when I release the breakpoint and the first run finishes.

First of all, this does not seems like REST at all. If you really just want to spawn a (single) background task, make sure you do it in a separate worker thread, not the request thread.

Maybe you need a lock:
public class Task extends HttpServlet {
// for singleton
//private volatile boolean running = false;
// or try this:
public static boolean running = false;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
if(running){
PrintWriter out = response.getWriter();
out.println("running");
return;
}
synchronized(Task.class){
if(!running){
running = true;
// run the task
running = false;
}
}
}
}

Related

Hold HTTP servlet request threads for reloading business config object

I need to Hot load or Reload business configuration / object at runtime in http servlet.
Config object is generated by reading a file during servlet init(). I need to reload this object when file is changed / updated..
public void init() {
Config config = initializeConfigFile();
}
Task 1 would be to have a thread periodically monitor file contents and if changed re-create config object from changed file.. I think this can be achieved by having some hash like md5 on file contents.. check if new hash changed..
public void run() {
// Read file
// Generate hash of file contents
// Compare with previous hash
// If different set a flag to hold threads
// configFileChanged = true;
}
Task 2 hold request threads until new config object is created. As this happens at runtime there might be request threads already accessing old config object and I can't just swap the config object as this might produce unexpected behavior. So I need to wait until all the threads already accessing the old config are done.
So I need suggestions for task 2.. I have not explored much of java advanced threading and queue based API's
For now thinking of some queue which holds request threads.
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
if (configFileChanged) {
synchronized (ActionServlet.class) {
while (configFileChanged) {
if (queue.isEmpty) {
config = initializeConfigFile();
configFileChanged = false;
} else {
sleep(2000);
}
}
}
}
queue.insert(Thread.currentThread());
// perform task using config object
queue.remove();
}
Also suggest improvizations for task 1, if any..
Thanks..
Bad way for both tasks:
For task 1:
Checking file regularry is not a logical process while you can have an observer/monitor for the file, in other word, check the new config once the file is changed(file monitor using java.nio.file)
For task 2:
If and if the container is not configured/overridden to create new instance for each request. --> The default/std behavior is having ONE object of the Servlet, and invoke the instance for each request via a thread, so for this a synchronized void reload() method would help.
During the reload() method run, because it locks the Servlet object, All new requests will be hold till the reload() finishes it's job.
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
//servlet business
}
//the reload is called by the file monitor
//The synchronized method will hold all new requests
synchronized void reload(){/*applying new configs*/}
Besides having a file(external) observer might not look safe and logical, I suggest having an external applciation which monitors the file and informs the web context by calling a servlet(maybe /friends/reload_config) where there is a servlet mapped to /friends/reload_config which will call reload() method.
You may check the request ip in /friends/reload_config servlet in order to ensure the request is generated by local app(not from net)

writing junit test for specific scenario

I am trying to write junit for my java web application which uses older command line design pattern (no framework is used for this older application).
I have a scenario in my application.
When the application is deployed in a server, first the server will find the web.xml and load and run the TestDataServlet(servlet class configured in web.xml which extends http servlet) before everything gets deployed in the server.
This TestDataServlet in turn calls the TestRunnable class which is a thread which loads all the properties file (contans informaton about endpoint everything which is used in java classes of my application code) and intialize it before hitting the application in browser.
I am trying to write junit for this application by using one time step up which loads all the properties file before running my junit, so that I can test it easily.
Since my application is not using a framework, I was not able to do it as spring junit does it.
Since there anyway to do it? Could I able to run the TestDataServlet before running my junit class?
Any help is appreciated.
Modify your TestDataServlet to be able to process a request "isTestRunnableCompleted". Have the return be true or false.
In your JUnit test, implement the setup() method. Call the TestDataServlet to start the runnable. Then, in a while() loop inside the setup() method, every second, call the TestDataServlet to check "isTestRunnableCompleted". If it is "false", sleep for a second, and then allow the loop to make the call again. You may want to implement some sort of a timeout in the loop also just in case things go wrong.
Good luck.
public class TestDataServlet
{
public void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
// Look for some indicator in the request that the caller wants a "status"
// of the test data being set up
if ( request.getParameter( "isTestDataRunnableCompleted" ) != null )
{
boolean status = testDataRunnableThread.isAlive();
PrintWriter writer = response.getWriter();
writer.println( Boolean.toString( status ) );
writer.close();
}
else
{
// If we get here, then start the test data runnable thread
}
}
}

How do you to detect the end of a thread via ThreadId?

Talking Java Servlets here... I'm working on creating my own "Per Request Context" and I was looking to tie the "Per Request Context" object to the Thread.currentThread().getId() value.
Instead of passing around this context object everywhere I was planning on checking the current threadid when a user calls a function that is Per Request based and automatically getting the Context object out of a hashtable for that threadId.
I would use the code this like..
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
MyFramework.EnterContext();
try {
// do stuff here that leads to other classes on the same thread
// Access current context via static MyFramework.getCurrentContext()
}
finally { MyFramework.ExitContext(); }
}
However I would like to protect my application automatically from any potential user that does not call ExitContext(). In C# there is an event handler on the thread object for onexit...(think I wrong on this) is there some way to detect or poll when a thread exits? I'm currently storing only the threadId (long).
Any ideas?
unfortunatelly, there is no such feature built in for threads in Java. Besides, thread id is only guaranteed to be unique at any one time, but may be reused eventually when the thread dies (from the docs). however, the servlet framework that you are using may be implementing such feature (just a speculation).
i would recommend you implement a servlet filter, and tell your users to include it in their web.xml. with this you can be sure the client code always gets correctly wraped in your thread context.
A ThreadLocal seems to fit your use perfectly. A ThreadLocal object can provide a way to store a variable per thread. The internal workings of this class are very much of what you describe, it uses a map to give thread-local variables.
Something like this should do the trick:
private static final ThreadLocal<UserContext> userContext = new ThreadLocal<UserContext>();
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyFramework.EnterContext();
try {
UserContext context = userContext.get();
//if you used the set method in this thread earlier
//a thread local context would be returned using get
}
finally { MyFramework.ExitContext(); }
}
As for your other problem, you can use an observer pattern and notify when the thread completes its task.

in servlet I want to have a response.print() while another thread is running

I have a cumbersome object which has to work in background , I create a servlet which will call this object and for running the object I've implemented the Runnable interface inside my servlet like following :
public class myObject extends HttpServlet implements Runnable
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
res.print("<br/> running...");
res.flush(); //doens't help
Thread t = new Thread(this);
t.run();
}
public void run()
{
res.print("<br/> running...");
res.flush();//doesn't helper either
cumbersomeObject.workHard();
}
}
How can I print this simple line and then send 200 status to user and my servlet work in background happily ever after?
Change t.run() to t.start(), your thread is not running in background, but blocking in foreground. BTW how does this compile? How can run() access res variable?
However it looks like you are trying to send some data to a user via res response object from a thread. This won't work, see HttpServletResponse seems to periodically send prematurely for a detailed discussion.
You're making a fundamental mistake. The HTTP servlet request and response objects are tied to the current HTTP request thread. Once this thread finishes (i.e. when the HTTP request/response finished), then the associated HTTP servlet request and response objects are trashed and completely useless. So if you use those objects in a different thread after the initial HTTP request/response finishes, then you'll get exceptions in all colors because they point nowhere to.
Manually spawning new thread on a per-request basis is also a terribly bad idea. Threads are not cheap and definitely not unlimited available. Rather use a pool of 5~10 threads or something. If you have such a thread pool, then you could just submit a task to it, associate it with some unique key in the HTTP session or maybe even in a database along the logged-in user ID. You can then just poll in every subsequent request if the task is finished or not (i.e. it has stored the result there where you'd expect to see it).

Finishing a HttpServletResponse but continue processing

I have a situation that seems to fit the Async Servlet 3.0 / Comet situation but all I need to do is return a 200 response code (or other) after accepting the incoming parameters.
Is there a way for a HttpServlet to complete the http request/response handshake and yet continue processing?
Something like...
doPost( req, response ) {
// verify input params...
response.setStatus( SC_OK );
response.close();
// execute long query
}
EDIT: Looking at the javax.servlet package - the proper phrasing to my question is
How do I commit a response?
as in Servlet.isCommitted()
Here's how I've handled this situation:
When the app starts up, create an ExecutorService with Executors.newFixedThreadPool(numThreads) (there are other types of executors, but I suggest starting with this one)
In doPost(), create an instance of Runnable which will perform the desired processing - your task - and submit it to the ExecutorService like so: executor.execute(task)
Finally, you should return the HTTP Status 202 Accepted, and, if possible, a Location header indicating where a client will be able to check up on the status of the processing.
I highly recommend you read Java Concurrency in Practice, it's a fantastic and very practical book.
On possibility for your servlet to accept a request for processing in the background, is for the servlet to hand off processing to a separate thread which then executes in the background.
Using Spring, you can invoke a separate Thread using the a TaskExecutor. The advantage of using spring over standard JDK 5 java.util.concurrent.Executor is that if you're on application servers that need to use managed threads (IBM websphere or Oracle weblogic), you can use the WorkManagerTaskExecutor to hook into the CommonJ work managers.
Another alternative would be to move the long query logic into a Message Driven Bean or Message Driven POJO (Spring JMS can help here) and let the servlet simply post a message on a JMS queue. That would have the advantage that should the load on your web container become too great because of your long running query, you could easily move the MDB onto a different (dedicated) system.
You can continue processing in a separate Thread.
The response is commited once you return from doPost() method.
This example can help
void doPost(){
// do something
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
// processing after response
}
});}

Categories