how to re-initialize java servlet on text file change - java

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

Related

ApplicationScoped bean across all sessions?

Hopefully I can make some sense, I've never done this particular task before.
I have an application where I want to create a bean on startup that has a scheduled task that runs every 30 minutes and updates a Map that is used by all sessions in the application. My initial thought was to create an ApplicationScoped bean for this task.
So the idea is this:
User A logs in. Stores value in his Map.
User B logs in. Stores value in his Map.
Process runs, updates all values in map.
User B and A will check their value constantly throughout the session.
Logout, remove value from map.
So right now it looks like this:
#ManagedBean(eager=true, name="monitor")
#ApplicationScoped
public class MyMonitor implements Serializable {
private static final long serialVersionUID = -1L;
private ScheduledExecutorService scheduler;
private HashMap<Integer, String> myDict;
#PostConstruct
public void init() {
myDict = new HashMap<Integer, String>();
myDict.put(1, "a");
myDict.put(2, "b");
myDict.put(3, "c");
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 30, TimeUnit.SECONDS);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
public class SomeDailyJob implements Runnable {
#Override
public void run() {
System.out.println("hello world");
}
}
public HashMap<Integer, String> getMyDict() {
return myDict;
}
public void setMyDict(HashMap<Integer, String> myDict) {
this.myDict = myDict;
}
}
In another class, I need to somehow retrieve the value from myDict based on key (this class is in the DAO layer, it is not a managed bean). I tried to instantiate this bean in that class:
public class MyDAO {
#ManagedProperty(value="#{myMonitor}")
private MyMonitor monitor;
}
And got:
WARNING: The web application [app] is still processing a request that has yet to finish
My questions are this:
Should I actually use an ApplicationScoped bean for this problem?
I do not have EJB.
I know I haven't added the synchronicity yet,
but is this safe? Can this actually work?
You can use a java.util.Timer for this. Define a class
import java.util.TimerTask;
public class Monitor extends TimerTask {
#Override
public void run() {
// do something
}
}
then your class may be refactored to something like (I removed other code to keep just the idea)
#ManagedBean(eager=true, name="monitor")
#ApplicationScoped
public class MyMonitor implements Serializable {
//runs as daemon thread
private final Timer timer = new Timer(true);
private Monitor monitor = new Monitor();
#PostConstruct
public void init() {
// period are in milliseconds
timer.scheduleAtFixedRate(monitor, 0, 30*1000);
}
#PreDestroy
public void destroy() {
timer.cancel();
}
}
This will help you also to move most of the update logic in the Monitor.run() separating it from the scheduler logic. I hope it helps.

Polling SQS using dropwizard

What I am trying to achieve:
I want to make a dropwizard client that polls Amazon SQS.
Whenever a message is found in the queue, it is processed and stored.
Some information about the processed messages will be available through an API.
Why I chose Dropwizard:
Seemed like a good choice to make a REST client. I need to have metrics, DB connections and integrate with some Java services.
What I need help with:
It is not very clear how and where the SQS polling will fit in a typical dropwizard application.
Should it be a managed resource? Or a console reporter console-reporter? Or something else.
You can use com.google.common.util.concurrent.AbstractScheduledService to create a consumer thread and add it to the dropwizard's environment lifecycle as ManagedTask. Following is the pseudocode -
public class YourSQSConsumer extends AbstractScheduledService {
#Override
protected void startUp() {
// may be print something
}
#Override
protected void shutDown() {
// may be print something
}
#Override
protected void runOneIteration() {
// code to poll on SQS
}
#Override
protected Scheduler scheduler() {
return newFixedRateSchedule(5, 1, SECONDS);
}
}
In Main do this -
YourSQSConsumer consumer = new YourSQSConsumer();
Managed managedTask = new ManagedTask(consumer);
environment.lifecycle().manage(managedTask);
As an alternative to RishikeshDhokare's answer, one can also go ahead with the following code which does not need to include additional jar as a dependency in your project to keep the uber jar as much lightweight as possible.
public class SQSPoller implements Managed, Runnable {
private ScheduledExecutorService mainRunner;
#Override
public void start() throws Exception {
mainRunner = Executors.newSingleThreadScheduledExecutor()
mainRunner.scheduleWithFixedDelay(this, 0, 100, TimeUnit.MILLISECONDS);
}
#Override
public void run() {
// poll SQS here
}
#Override
public void stop() throws Exception {
mainRunner.shutdown();
}
}
And in the run() of your Application class, you can register the above class as follows.
environment.lifecycle().manage(new SQSPoller());
You can use either scheduleWithFixedDelay() or scheduleAtFixedRate() depending upon your use case.

How to force to create a single thread using scheduledexecutorservice and avoid multithreading

I would like to execute the following JAVA code only once when I enter to welcome.jsp page.
welcome.jsp:
<%WeeklyScheduledMail wsm = WeeklyScheduledMail.INSTANCE;
wsm.startThread(); %>
So, if a user access to the website once the server is initiated, that code can be used once, and the other users who log in and access to welcome.jsp will not execute that JAVA code.
First, I tried to implement the Singleton pattern with enum, I thought it would be enough but it did not work. I also tried the Synchronized keyword for the methods but nothing...
I'm sure I did something wrong or there is a better way to do what I want to do.
Some portions of the code:
WeeklyScheduledMail.java:
public enum WeeklyScheduledMail{
INSTANCE;
public void startThread() {
ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
Runnable task = new TaskSendEmail();
int initialDelay = 0;
int periodicDelay = 10;
scheduler.scheduleAtFixedRate(task, initialDelay, periodicDelay,
TimeUnit.SECONDS);
}
}
TaskSendEmail.java:
public class TaskSendEmail implements Runnable{
public void run() {
System.out.println("Hello: "+System.currentTimeMillis());
}
}
You're looking into the incorrect concept to run application initialization code. JSPs and other resources exposed to the user aren't designed for this. Even if you can force some lazy initialization logic, there will still be avoidable overhead.
What you're looking for is provided by JavaEE: a context listener, which is invoked once on application startup to notify your application that the context has been initialized:
public class MyContextListener implements javax.servlet.ServletContextListener {
private static fWeeklyScheduledMail wsm =
weeklyScheduledMail.INSTANCE;
#Override
public void contextInitialized(ServletContextEvent sce) {
wsm.startThread();
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
wsm.stopThread();
}
}
This listener must then be registered in the web.xml deployment descriptor (under web-app):
<listener>
<listener-class>my.packg.MyContextListener</listener-class>
</listener>
The above code and configuration will cause your schedule to run once, when the application starts.

java threads and callbacks

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

Java API Designing issue in creating own API

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.

Categories