How to kill non-daemon threads created by library when quitting? - java

My application is running in tomcat, every time I stop tomcat it warns me there are lots of threads fail to shutdown. These threads are created by libraries my application use, I have no idea how to kill them. This issue leads tomcat process still live after I call bin/shutdown.sh shipped with tomcat.
can anybody help? thanks

Those libraries should also expose corresponding "shutdown", "stop", etc. methods you will need to call. Check their respective documentations or source.
You can also use jConsole or VisualVM to see what threads are alive after you try to shutdown your machine. If you're lucky your libraries will name them intelligently (RMQ doesn't by default, for instance), and you can tell what's left.

You can use a class that implements ServletContextListener and annotate it with #WebListener() (or indicate it's a listener in web.xml for earlier versions of Tomcat).
The interface has two methods contextInitialized and contextDestroyed where you can - in your implementation - do initialization and cleanup of any libraries or classes that might be spawning threads or otherwise need special tending. A Java Servlet Container like Tomcat will call both of the methods as part of a webapps start/stop life-cycle. Example:
#WebListener()
public class RestartListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
//some initialization code here
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
MemcachedManager.shutdown();
}
}

Related

stopping threads gracefully

I am using ScheduledExecutorService for scheduling a thread. I wonder what happens when JBoss is shut down? Does it kill all the threads that are started within the server, including the the one I scheduled? Do I have to do it manually using ScheduledFuture, and cancel the thread when ServletContext is destroyed?
There are two methods:
java.util.concurrent.ExecutorService.shutdown()
java.util.concurrent.ExecutorService.shutdownNow()
JBoss won't call any of these unless you do it in method which will be called upon shutdown. For web applications you have the chance to do it in javax.servlet.ServletContextListener.contextDestroyed(ServletContextEvent).
Of course this is the JavaEE/Servlets way. You can hide it by using e.g. Spring Framework. By creating org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler you'll get shutting down for free (this class implements org.springframework.beans.factory.DisposableBean). See the details here.

JBoss AS 7 - After Startup initialization

Is there any way to catch an event/implements a Class, or something like that, to detect that JBoss (AS7) is up and running and all applications has been deployed ?
I made a StartupServlet (which extends HttpServlet) because i need to call a local web service to initialize the system. But because my application is not fully deployed my call for the web service (in the StartupServlet) ends in a "404 Not Found error".
I tried to use a <listener>...</listener> on the web.xml but it's not working.
You can try using a Startup EJB, like explained here:
#Singleton
#Startup
public class StartupBean {
#PostConstruct
private void startup() { ... }
#PreDestroy
private void shutdown() { ... }
}
However the bean will not detect whether your applications are deployed, only that the current application - the one containing the bean - is deployed and started. Since the #PostConstruct method is called very early, you cannot rely on any other beans or services being available.
EDIT: Jboss also has a native management API. AFAIK it can also be used to query deployments. Unfortunately it's documentation is not really impressive, but perhaps you can figure it out.
According to my understanding, you do not need to detect when all application was deployed, you need to understand only if your application was deployed. To do it you should define ServletContextListener:
http://docs.oracle.com/javaee/5/api/javax/servlet/ServletContextListener.html#contextInitialized%28javax.servlet.ServletContextEvent%29
Than you can catch when it deployed:
public void contextInitialized(ServletContextEvent sce)
{
servletContext = sce.getServletContext();
}

Deploying Java Application As Servlet

I have a java application that up until now was run as a stand alone java application (i.e. executable jar). I now need to deploy it in Tomcat as a servlet. It doesn't need to actually process any HTTP requests though, but it needs to be started using tomcat.
What are the steps required to convert the project so that it can be deployed in Tomcat? I'm using maven as a build tool and Java 1.5.
I understand that you want to run this app on server's startup. The best way would be implementing ServletContextListener and run the app in the contextInitialized() method. E.g.
public class Config implements ServletContextListener {
private YourApp yourApp;
public void contextInitialized(ServletContextEvent event) {
yourApp = new YourApp();
yourApp.start();
}
public void contextDestroyed(ServletContextEvent event) {
yourApp.shutdown();
}
}
Register this in web.xml as follows:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
That's it. No need to wrap it in flavor of a HttpServlet as you aren't going to fire HTTP requests on it.
You however need to ensure that it runs in its own thread, otherwise it would block the startup. If it doesn't, then wrap it in a Runnable and execute it using ExecutorService.
I'm assuming that your app is continuously running and you have an app/web server already (e.g. Tomcat/Jetty), such that it's making your life easy to deploy into it. Given that, you need to:
extend an AbstractHttpServlet class and in particular the init() method. This would start your app.
build a web.xml that references this and sets the load-on-startup attribute to 1 (or at least non-zero)
build a .war from this and deploy it
Step 2 ensures that the init() method is called upon deployment/server reboot, and so you don't have to respond to HTTP requests (a normal startup trigger for a servlet).
It may be simpler and more appropriate to use something like javaservicewrapper, and wrap it up to be a Windows service or similar.

Clean up after servlet if init() failed

I have an Initializer class that implements the ServletContextListener interface. In its contextInitialized() method, I initialize some global classes that have to be destroyed, otherwise the servlet cannot be unloaded.
However, when the servlet's init() method throws a ServletException, the contextDestroyed() method never gets called --> resources are not release --> servlet does not get unloaded by Tomcat (it remains in "running" state even though its init method never finished).
My question is this - how do I cleanup the resources in this case?
Bonus: why does the servlet even get to "running" state? I understand from the documentation that it's not supposed to be running unless the init() method finishes successfully.
Edit - I think this is because each status line displayed in Tomcat Manager represents an entire war, and not a servlet. A war may contain several servlets, with some succeeding to start and others not. The Initializer is called when the container starts, and its destroy is called only when the entire container is dropped. This leads to a related question - is there a similar built-in way to monitor the state of individual servlets?
(I'm aware I can write custom code to monitor the servlet, either via JMX, or not, but that's out of the scope of
this question).
As far as I can tell there's absolutely no way to do so without an external request. ServletContextListener gives you the correct signal (when all servlets have been initialized - successfully or not), but you can't enumerate all servlets in the context to test their status because the relevant ServletContext methods were deprecated and now return an empty enumerator.
In short, the only way to do this is via a nonstandard API; in particular, it's almost trivial to do this with Tomcat's JMX API, which is the course I'd recommend.
In real world the init() should never fail. If it fails, then it is a programming error which the developer is supposed to fix. The appserver webcontainer has nothing to do with it. The servlet will simply be kept unavailable.
What container are you running?
Tomcat for example does support JMX. You can always write your own JMX-beans.

Spring: Is there a simple non-web tutorial?

I'm attempting to create a Spring application (NOT web application) to perform some simple tasks. Eventually they will hook up with some other Spring apps around the network, but for now I'm keeping it simple. I have a CheckForNewItems class (extending Timer) which is configured to run every 10 seconds.
I can confirm it runs by calling it programmatically:
public class Tester {
public static ApplicationContext context;
private void loadContext() {
String filename = "beans.xml";
context = new FileSystemXmlApplicationContext(filename);
}
public static void main(String[] args) {
Tester test = new Tester();
test.loadContext();
CheckNewItemsTask task = (CheckNewItemsTask)context.getBean("checkNewItemsTask");
}
}
Running this works as expected, task.run() gets called every 10 seconds. Now I need to work out how to deploy this to either a JBoss or Tomcat server, in such a way that it automatically starts running the task.
Most of the tutorials I've found only describe how to get Spring MVC and servlets running, not a standalone application. Does anyone know better?
Cheers, Rob.
You don't need JBoss or Tomcat to do that. If the app is headless and you have no intention of adding a UI, consider jsvc for unix or procrun on windows. If you need the ability to monitor and control an app and do not need a proper UI for doing that, you might want to look at JMX. This will work on a daemon without the rest of the Java EE stack.
If you have a maven project and want an easy way to turn it into a deployable daemon app, you can use maven appassembler to automate the process of creating a deployable daemon, setting up a directory structure of the app, scripts to start and stop, libraries and config files.
You need a servlet that is set to autostart on deployment. The servlet can then call into your "Tester" class to trigger your "standalone" initialization process.
If you don't have a servlet (or potentially some other server related process) reference your code, then your initialization process will never be run.

Categories