I've made a web application using Java, Struts and running over Apache Server and Tomcat. It would be very useful to be able to restart the application from the web. I don't want to restart Tomcat, only this webapp, the same way as Tomcat Manager does it.
Do you know how can I do it? If not, any way to simulate that behaviour (reload config.properties, make Hibernate init process, etc)?
Thank you a lot.
I took a quick look at the source code for the Tomcat Manager. It looks like there's a class that's part of the Tomcat source called "Container Servlet". From the javadocs:
A ContainerServlet is a servlet
that has access to Catalina internal
functionality, and is loaded from the
Catalina class loader instead of the
web application class loader.
A ContainerServlet automatically gets passed a wrapper that can be used to get the Context and Deployer -- and the Deployer has helpful methods such as start(String contextPath) and stop(String contextPath) that will do what you want.
So, what I think you would need to do is write your own servlet that inherits from ContainerServlet, and configure Tomcat to load your servlet using the Catalina class loader (look at how the Manager is configured to see how). Note that this is probably not going to be an option for you in a hosted environment.
Then your servlet could have, say, a button you press to reload the application. I recommend putting password-protection of some kind in front of that. :)
Just hit the URLs
http://<username>:<password>#<hostname>:<port>/manager/stop?path=/<context path>
to stop and
http://<username>:<password>#<hostname>:<port>/manager/start?path=/<context path>
to start. That simulates you using the manager application.
Tomcat Manager offers an http interface to start/stop an application and other tasks. There are Ant tasks that you can use to easily access these operations.
Related
I am writing a Springboot application embedding Tomcat as a Web Server.
At startup, some of my threads are ready (and so start doing their job) before Tomcat is. For many contraints I have, I want that these threads do nothing before Tomcat is ready
But I don't know how to decided to block/unblock my threads; to do so, I need to be informed of the Tomcat status. Is there:
a way to ask: isWebServerStarted()?
or a way to be notified asynchronously by a message saying: WEB_SERVER_IS_STARTED?
Thank you for help
FYI, I don't want to declare a kind of "private ReST endpoint" that my
application could try to reach in order to guess whether the webserver
is ready
Go with a ServletContextListener. Annotate your class with #WebListener and tell spring configuration about this listener by adding #ServletComponentScan annotation.
Basically I created some servlets on startup during the contextInitialized phase when my webapp starts up. But I need to be able to add servlets dynamically while the webapp is still running.
I'm starting to realize this may not be possible, so my next solution was to attempt to redeploy the webapp or restart tomcat. Is it possible to redeploy the app from inside the application? Or even add a servlet after the context has already been initialized?
At this point just being able to redeploy the .war would be enough.
As #JasonArmstrong says, you can trigger a reload using JMX Beans, which are available within the same JVM to any application. You can reload yourself or another application. I'll post code later on to show how to do that.
On the other hand, if all you want to do is deploy an additional servlet, you can do that using standard Java Servlet APIs.
The Java Servlet API ServletContext interface contains a method, addServlet, which allows you to deploy a new servlet. That, in combination with the return value from that method should allow you to deploy a new servlet after the application has been initialized.
For example (in a Servlet)
Servlet servlet = ...; // Make your servlet, here
ServletContext application = getServletContext();
ServletRegistration.Dynamic reg = application.addServlet("MyNewServlet", servlet);
reg.addMapping("/nyNewServlet");
UPDATE 2018-12-07
Apologies for the above text which has now been retracted. Everything about it is true except that you can't deploy new servlets (and, presumably, Filters and other things like that) after the context has been initialized.
== Back to original answer==
Or if you want to reload the context, you can still do it using JMX. The code looks something like this:
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
// Get the JVM's local "server" (there should be only one)
MBeanServer mbs = MBeanServerFactory.findMBeanServer(null).get(0);
// Create an "object name" that points to the application's
// context in Tomcat's MXBean tree. You might want to use
// jvisualvm or a similar MBean explorer to locate your
// application to get the exact right syntax for your context
// in the tree. Tomcat version may affect this value.
ObjectName objectName = new ObjectName("Catalina:j2eeType=WebModule,name=//localhost/contextname,J2EEApplication=none,J2EEServer=none");
// Invoke the "reload" method, which will
mbs.invoke(objectName, "reload", null, null);
The Manager app will allow you to update the application. You may also be able to do something with JMX MBeans.
The Manager app allows you to deploy and redeploy via update=true parameter. You can also start, stop, restart an app from there.
It’s not quite what you were looking for, but it’s pretty easy to set up.
I have some personal project where I am trying to share some class instance between webapp and a normal app. My project structure is something like below:
+ NormalApp
+ WebApp
I am starting the application from the NormalApp and I included WebApp using EmbeddedTomcat. Now I have a class named Notifier in WebApp. I want to use the instance of Notifier in NormalApp without losing it's state.
Could someone tell me how can I achieve this scenario?
I have some plan in mind like setting the Tomcat class loader to use Systems class loader. I tried it but couldn't able to achieve it. Is my understanding of this wrong?
Have you tried making your normal app like web components ? so your application will be available when tomcat start. And you can use System properties to pass parameters to the tomcat.
Another option is using Spring boot. Here is a tutorial
https://spring.io/guides/gs/spring-boot/
http://spring.io/guides/tutorials/bookmarks/
I have embedded Jetty container inside my main server and I also use Jersey 2.5 for handling REST resources.
everything seems to work well and now I would like to pass my server's context class into each of my REST resources.
I'm having hard time understanding how to do that...
If someone can provide full code example - it could be awesome!
Many thanks
What exactly do you mean when you say you have a Jetty container inside your "main server"? Are you programmatically executing Jetty within the application? Also, when you say "context" are you referring to the ServletContext?
I want to extend the users admin portlet that is located in the control panel. I hooked the jsp and wanted to use methods from the service builder that are in the same hook as the jsp.
The problem is that the jsp can not find the classes. So I copied the *-service.jar to the tomcat lib/ext folder and removed it from the hook when deploying it.
But that doesn't work. After a while I get an exception that says Cache is not alive or this web application instance has been stopped already.
Is there a way to use methods from my custom service builder in the hooked jsp ?
The approach you have taken is correct, i.e. to put the *-service.jar inside [TOMCAT_HOME]/lib/ext and removing the jar from the hook.
The error might be because the hook may not have been properly undeployed, you may get some idea from this forum post. So my suggestion would be to:
Undeploy the hook
Stop the server
Copy the jar to [TOMCAT_HOME]/lib/ext
Clear temp and work directory
Restart the server
Deploy the hook
Whenever you remove a jar from a plugin-project and then just deploy without undeploying the portlet, sometimes you may notice that the jar file may be still present in the deployed webapps/plugin-project's directory, and this might be the case here as well. Also, whenever you put something in the global classpath (i.e. [TOMCAT_HOME]/lib/ext) you need to restart the server.
Also, don't forget to import the class in the JSP :-), just in case ...