Running a Java daemon with a GWT front-end served by embedded Jetty
Greetings, coders,
Background Info and Code
I am trying to create a daemon-type program (e.g., it runs constantly, polling for things to do) that is managed by a GWT application (servlets in a WAR) which is in turn served by an embedded Jetty server (using a WebAppContext
). I'm having problems making the GWT application aware of the daemon object.
For testing things, I currently have two projects: The daemon and embedded Jetty server in one (EmbJetTest
), and the GWT application in another (DefaultApp
). This is the current state of the code:
First, EmbJetTest
creates an embedded Jetty server like so, using a ServletContextListener
to inject the daemon object into the web application co开发者_开发知识库ntext:
EmbJetTest.server = new Server(8080);
// Create and start the daemon
Daemon daemon = new Daemon();
Thread thread = new Thread(daemon);
thread.start();
// war handler
WebAppContext waContext = new WebAppContext();
waContext.setContextPath("/webapp");
waContext.setWar("./apps/DefaultApp.war");
waContext.addEventListener(new DaemonLoader(daemon));
// Add it to the server
EmbJetTest.server.setHandler(waContext);
EmbJetTest.server.setThreadPool(new QueuedThreadPool(10));
// Start the server; join() blocks until we shut down
EmbJetTest.server.start();
EmbJetTest.server.join();
// Stop the daemon thread
daemon.stopLoop();
Daemon
is a very simple object with a couple properties, at the moment. DaemonLoader
is the following ServletContextListener
implementation:
private Daemon daemon;
public DaemonLoader(Daemon daemon)
{
this.daemon = daemon;
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
arg0.getServletContext().setAttribute("daemon", this.daemon);
}
Then, in one of my servlets in the GWT application, I have the following code:
Daemon daemon = (Daemon) this.getServletContext().getAttribute("daemon");
However, when I visit localhost:8080/webapp/* and invoke the servlet, this code throws a ClassCastException
, even though the classes are of the same type. This StackOverflow answer indicates that this is because the two classes are loaded with different classloaders.
Question
My question is twofold.
- Am I even on the right track here? Am I going about this completely the wrong way? Something tells me I am, but I can't think of another way to make the daemon available to both applications. Is there a better way to communicate with the daemon from the GWT application? Should the GWT app own the daemon and somehow start the daemon itself? The daemon needs to run even if no one visits the one of the GWT app's servlets--how could I do this?
- If I am on the right track, how can I get around the classloader issue?
Thanks in advance.
Why not just run the functionality of the daemon in a separate thread within the GWT web application ? That way you'll avoid all the classloading grief (as you've found out, apps in different .war
files run within their own classloaders).
Just create a servlet for your daemon alongside your existing servlets (in the same .war
), and start/stop the thread on servlet initialisation and destruction.
Well, in case anyone is interested, I actually managed to solve the classloader issue--originally, I placed the compiled Daemon.class in the GWT app's WEB-INF/classes folder. I deleted this file and now it appears that the GWT app uses the Daemon class from the EmbJetTest project.
That being said, I think Brian's answer is much more noteworthy. :)
精彩评论