I just came to a scenario where this question popped on my head and I cannot find an answer, please suggest
We call the callback methods in a thread by any approach, my approach would be:
interface Callback {
void callback();
}
class MyThread implements Runnable {
Callback cb;
public MyThread(Callback cb) {
this.bc = cb;
}
public void run() {
// my task to do
this.cb.callback();
}
}
Example of a request made to a servlet on asynchronous mode,
Reference: https://docs.oracle.com/javaee/7/tutorial/doc/servlets012.htm
#WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest request,
HttpServletResponse response) {
response.setContentType("text/html;charset=UTF-8");
final AsyncContext acontext = request.startAsync();
acontext.start(new Runnable() {
public void run() {
String param = acontext.getRequest().getParameter("param");
String result = resource.process(param);
HttpServletResponse response = acontext.getResponse();
acontext.complete();
}
}
AsyncServlet adds asyncSupported=true to the #WebServlet annotation.
The rest of the differences are inside the service method.
request.startAsync() causes the request to be processed
asynchronously; the response is not sent to the client at the end of
the service method.
acontext.start(new Runnable() {...}) gets a new thread from the
container.
Question - Is it necessary that all callbacks will be made in multiple threads, when requests are made on asynchronous mode?
My answer is like .. It need not be, it basically depends on where the callback methods are defined, in one thread or multiple threads.
Please suggest
Related
I am using Tomcat 9.0 to run Java code on some data from a database.
I have a single servlet that is invoked by directly accessing x.x.x.x:8080/myapp/myservlet.
The length of time to complete is between 5 seconds - 1 minute.
The servlet returns a response right away, leaving it to continue processing in the background. I am not sure Tomcat is supposed to be used like this.
The problem is until the processing has actually finished, the web client cannot access x.x.x.x:8080/myapp/myservlet.
Each new web client can connect and invoke the servlet fine.
I simply want to invoke my java code as a background process in a fire and forget manner. Is this possible with Tomcat?
Any guidance would be great
Move you code in a Thread or an executor and use the servlet only to start and monitor the execution.
public class myservlet extends HttpServlet
{
...
Thread t = null;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();
if(t == null || !t.isAlive())
{
t = new Thread(new Runner());
t.setDaemon(true);
t.start();
out.write("Process started.\n");
}
else
out.write("Process running...\n");
}
public static class Runner implements Runnable
{
public void run()
{
// put your code here
}
}
}
I am using spring for out web application. One API does a lot of computation which looks like this.
void serviceMethod(){
fetchFromDB();
veryLongComputation1(); //1
veryLongComputation2(); //2
veryLongComputation3(); //3
}
My API takes a lot of time to run. Steps 1,2 and 3 takes lot of time because they have lot of computation and lot of IO (to db) too.
What I want is to return the response and run the 1,2,3 in a thread. But problem with that approach is if my application crashes, this code will never be executed.
Can someone suggest some approaches to encounter this problem? One thing to remember, there will be many instances of the application.
Java provides an async servlet to handle requests which takes long time to complete. The basic idea is Http thread in the servlet container triggers the computation and returns immediately whereas the response is sent only when the computation is complete. See the sample below
#WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet {
/* ... Same variables and init method as in SyncServlet ... */
#Override
public void doGet(HttpServletRequest request,
HttpServletResponse response) {
response.setContentType("text/html;charset=UTF-8");
final AsyncContext acontext = request.startAsync();
acontext.start(new Runnable() {
public void run() {
String param = acontext.getRequest().getParameter("param");
String result = resource.process(param);
HttpServletResponse response = acontext.getResponse();
/* ... print to the response ... */
acontext.complete();
}
}
The same thing in spring
#GetMapping(value = "/asyncNonBlockingRequestProcessing")
public CompletableFuture<String> asyncNonBlockingRequestProcessing(){
ListenableFuture<String> listenableFuture = getRequest.execute(new AsyncCompletionHandler<String>() {
#Override
public String onCompleted(Response response) throws Exception {
logger.debug("Async Non Blocking Request processing completed");
return "Async Non blocking...";
}
});
return listenableFuture.toCompletableFuture();
}
I am working on a project that includes communication between computer application and embedded devices over serial port in Master-Slave mode.
The application will serve as Master to multiple embedded devices working as Slaves.
The communication part is almost complete. But now, I am refactoring it as an API.
So, it can be used over multiple projects or by many developers with very less configurations.
I am not very good in API design, even it's the first time, I am creating an API.
Now, I am stuck on following issue:
Consider this scenario:
/*
* API Part
*/
public abstract class AbstractSlave {
// Some fields, constructor and other methods.
final void handle(Request request, Response response) {
// Some operations before starting worker thread.
SlaveWorker worker = new SlaveWorker(request, response);
worker.start();
}
}
public class SlaveWorker extends Thread {
// Constructor
#Override
public final void run() {
work(request, response);
}
public void work(Request request, Response response) {
}
}
AbstractSlave class starts a worker thread to work upon the request and response, so that long-running operations cannot cause the loss of upcoming responses from slaves.
Now, here is the "API usage part":
/*
* API Usage Part
*/
public class Slave extends AbstractSlave {
// Constructor
}
public class MyWorker extends SlaveWorker {
// Constructor
#Override
public void work(Request request, Response response) {
super.work(request, response);
// My work to be done upon request and response.
}
}
But as we can see, AbstractSlave creates SlaveWorker instances.
So, SlaveWorker work() method will be called, instead of MyWorker.
How to make AbstractSlave class to call MyWorker work() method?
NOTE:
As it's an API design, AbstractSlave would not know, there is a MyWorker class. So, MyWorker instances cannot be created directly in place of SlaveWorker.
handle() method of AbstractSlave can/meant not be overridden, because there are some operations, that need to be performed before starting worker thread.
I think the key point would be to let the client of your API create the instance of SlaveWorker (or any subclass), so that he can customize the work() method.
IMO you should provide a Worker interface in your API (interface is less constraining than an abstract class):
public interface Worker {
public void work(Request request, Response response);
}
And AbstractSlave's method should be like:
public abstract class AbstractSlave {
private final Worker worker;
public AbstractSlave(Worker worker) {
this.worker = worker;
}
final void handle(final Request request, final Response response)
// Some operations before starting worker thread.
Thread t = new Thread() {
public void run() {
worker.work(request, response);
}
};
t.start();
}
}
There are different ways to do this, but one way is to add a configureJob method to your AbstractSlaveand use this to tell your AbstractSlave class about MyWorker.
public class SlaveManager {
private Class workerClass = SlaveWorker.class;
public void configureJob(Class clazz){
workerClass = clazz;
}
final void handle(Request request, Response response) {
// Some operations before starting worker thread.
Worker worker = workerClass.newInstance();
worker.start(request, response);
}
}
public interface Worker {
public void work(Request request, Response response);
}
In your main method, just call SlaveManager::configureJob(MyWorker.class) before you call SlaveManager::handle().
Now, I've kept things simple above by using Object.newInstance() to create the Worker, but this is not a recommended general practice. It's more customary to use a WorkerFactory instead, but I didn't want to introduce a new class and a new design pattern in case you were unfamiliar with the Factory Pattern.
I am writing a Api that executes HTTP Request on a worker thread then call a method of a Callback-Handler when finish.
public class GriklyClient <E,T>{
private final IHttpRequest<E,T> request;
private final ResponseListener<T> response;
protected GriklyClient (IHttpRequest<E,T> request,ResponseListener<T> response)
{
this.request = request;
this.response = response;
}
/**
* Dispatch a thread to process
* HTTP Request.
*/
public void execute ()
{
Runnable thread = new Runnable()
{
public void run()
{
T result = (T) request.execute ();
response.response(result);
}
};
new Thread(thread).start();
}//end execute method
}
This is how a call to the ApI looks like:
Grikly grikly = new Grikly(developerKey);
grikly.addValidUserCredential(email,password);
grikly.fetchUser(1, new ResponseListener<User>() {
public void response(User result) {
// TODO Auto-generated method stub
System.out.println(result);
}
});
The problem I am having is Unit Testing. The Callback Handler is not being called in my Unit Test thus all my Test always pass even when they should fail.
private Grikly grikly = new Grikly (developerKey);
#Test
public void fetchUser ()
{
grikly.fetchUser(1, new ResponseListener<User>() {
public void response(User result) {
Assert.assertNotNull(result);
}
});
}//end fetchUser Test
How can I write a Unit test to test this Api?
Well, I guess your problem here is because your method fetchUser is an asynchonous method rather than a synchonous one which will not return until it have done its job.
So, the calling of grikly.fetchUser(... will return immediately(so does the test method fetchUser() w/o any sign of failure or success), while the 'lonely' thread you create in GriklyClient will keep running and finish its job by calling the callback method response in your new ResponseListener<User> and of course, nobody cares at that time.
IMO, either a CountdownLatch or a more general ReentrantLock with its Condition buddy can save your day. And tutorials talking about these two tools can be easily found using Google. Good luck with that.
EDIT:
On a second thought, if you wanna test the result that got passed to the callback method, it might be necessary to pass(or publish) it from the new thread you create to the test main thread(by save it to a lock guarded or volatile decorated field) and test it in the #Test annotated method, which in your case is the fetchUser().
I have a servlet that pulls data from a text file during initialization.
Now I am updating that text file with a cron job(say everyday at 10am) and want to reinitialize the servlet every time this particular file changes.
Second approach I can follow is to sync the reinitialization of the servlet to my cron job.
Kindly suggest on how to go about implementing either of the above two approaches.
thanks.
Don't get hold of it as instance variable of the servlet. Create a ServletContextListener which stores it in the application scope and runs a thread which updates it on every interval with help of ScheduledExecutorService.
E.g.
#WebListener
public class Config implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
Data data = new Data(); // Your class which reads and holds data upon construction.
event.getServletContext().setAttribute("data", data);
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Reloader(data), 0, 1, TimeUnit.DAYS);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
with this runnable
public class Reloader implements Runnable {
private Data data;
public Reloader(Data data) {
this.data = data;
}
#Override
public void run() {
data.reload();
}
}
It's accessible a random servlet.
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
Data data = (Data) getServletContext().getAttribute("data");
// ...
}
And even in a random JSP.
${data.something}
Have your servlet occasionally check the file for changes with a timer.
Googling "Java monitor file for changes" will present many examples, one of which you can find here: http://www.devdaily.com/java/jwarehouse/jforum/src/net/jforum/util/FileMonitor.java.shtml