I was using WebSphere Application Server, and it gives a platform initialization listener which is invoked when an app gets started. Now, I am using Apache Tomcat, but have not found such stuff, and what I'm trying to do is do some initialization work before the application begins to serve requests.
How should I do it by Apache Tomcat?
You create a Listener class what implement ServletContextListener like this:
package com.vy;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class StartStopListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("Servlet has been started.");
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("Servlet has been stopped.");
}
}
Add configuration information to WEB-INF\web.xml like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<listener>
<listener-class>com.vy.StartStopListener</listener-class>
</listener>
</web-app>
When run Tomcat, You will see result at console screen:
Servlet has been started.
Reference: http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContextListener.html
You can use ServletContextListener API. Please read this link. You can go and checkout this tutorial
You should write custom application start-up code in this method
#Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
}
Note : There will not be any issues while moving to another servers, if needed in future.
Related
Is there a way to run the Jersey servlet container (2.x) descriptor-less as a javax.servlet.Filter in a Servlet 3.x container? I need to serve static resources alongside my services and therefore need to use jersey.config.servlet.filter.forwardOn404 or jersey.config.servlet.filter.staticContentRegex which only work when run as a filter according to Javadoc
The property is only applicable when Jersey servlet container is configured to run as a javax.servlet.Filter, otherwise this property will be ignored.
I'd like to get rid of the web.xml completely
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>My-Webservice</display-name>
<filter>
<filter-name>Jersey Filter</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.foo.webservices.MyApplication</param-value>
</init-param>
</filter>
</web-app>
and have everything in my custom Applicationclass
#ApplicationPath(value = "/")
public class MyApplication extends ResourceConfig
{
public MyApplication()
{
packages("com.foo.webservices.services");
property(ServletProperties.FILTER_FORWARD_ON_404, true);
}
}
The official documentation (https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.3) doesn't state anything about filters unfortunately.
It's possible, but not gonna be as easy as just setting some config property. It would help if you understand a little about how it actually works. With Servlet 3.x, introduced a ServletContainerInitializer that we can implement to load servlets dynamically (this is discussed further here). Jersey has an implementation that it uses. But it follows the JAX-RS which says that the application should be loaded as a servlet. So Jersey doesn't doesn't offer any way around this.
We could write our own ServletContainerInitializer or we can just tap into Jersey's. Jersey has a SerletContainerProvider we can implement. We would need to register the servlet filter ourselves. The implementation would look something like this
#Override
public void preInit(ServletContext context, Set<Class<?>> classes) throws ServletException {
final Class<? extends Application> applicationCls = getApplicationClass(classes);
if (applicationCls != null) {
final ApplicationPath appPath = applicationCls.getAnnotation(ApplicationPath.class);
if (appPath == null) {
LOGGER.warning("Application class is not annotated with ApplicationPath");
return;
}
final String mapping = createMappingPath(appPath);
addFilter(context, applicationCls, classes, mapping);
// to stop Jersey servlet initializer from trying to register another servlet
classes.remove(applicationCls);
}
}
private static void addFilter(ServletContext context, Class<? extends Application> cls,
Set<Class<?>> classes, String mapping) {
final ResourceConfig resourceConfig = ResourceConfig.forApplicationClass(cls, classes);
final ServletContainer filter = new ServletContainer(resourceConfig);
final FilterRegistration.Dynamic registration = context.addFilter(cls.getName(), filter);
registration.addMappingForUrlPatterns(null, true, mapping);
registration.setAsyncSupported(true);
}
Once we have our implementation, we need to create a file
META-INF/services/org.glassfish.jersey.servlet.internal.spi.ServletContainerProvider
Which should be at the root of the class path. The contents of that file should be the fully qualified name of our implementation.
You can see a complete example in this GitHub Repo
I log some message to see the lifecycle of #ServerEndpoint. PostConstruct, onOpen, onClose are triggered in turns, but #PreDestroy is never triggered. Do I miss something?
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/")
public class ServerWebSocket {
#PostConstruct
public void initialize() {
System.out.println("PostConstruct");
}
#OnOpen
public void open(Session session) {
System.out.println("OnOpen");
}
#OnClose
public void close(Session session) {
System.out.println("OnClose");
}
#PreDestroy
public void destroy() {
System.out.println("PreDestroy");
}
}
I use GlassFish4 with bean.xml in WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
#OnOpen and #OnClose callbacks are triggered by the lifecycle of every WebSocket session.
There is no any CDI scope specified, which could be used with WebSocket endpoints. And this is ok, because it has it's own session.
So, why is #PostConstruct triggered? WebSocket specification says, that:
Websocket endpoints running in the Java EE platform must have full dependency injection support as described in the CDI specification.
And #PostConstruct API Doc points:
The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. ... This annotation MUST be supported on all classes that support dependency injection.
Why #PreDestroy then doesn't work? I think, Websocket endpoints behave like singletons, and #PreDestroy will be triggered during removing of the instance, which will occur just before application stop. You could check it in your environment by stopping application from the GlassFish administration console.
This question already has an answer here:
Using special auto start servlet to initialize on startup and share application data
(1 answer)
Closed 7 years ago.
I have web application in Java code, which uses servlets. My question is how to initialize some java class, which is not servlet. I understand that if the client connects - the servlet then prints the output. But only "if client connects".
Is it possible to run some threads before any connections are made?
EDIT:
Thanks to answers, right now I'm trying to do it this way:
the class:
package com.xsistema.filemanager.application;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
*
* #author Ernestas Gruodis
*/
public class ServerInit implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Initialized");
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Destroyed");
}
}
And the glassfish-web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<context-root>/file-manager</context-root>
<class-loader delegate="true"/>
<jsp-config>
<property name="keepgenerated" value="true">
<description>Keep a copy of the generated servlet class' java code.</description>
</property>
</jsp-config>
<listener>
<listener-class>
com.xsistema.filemanager.application.ServerInit
</listener-class>
</listener>
</glassfish-web-app>
And I getting this error while deploying the application:
Warning: Unsupported deployment descriptors element listener-class
value com.xsistema.filemanager.application.ServerInit.
What's wrong here?
EDIT2:
Can not delete this question, appeared to be duplicate (it has the answers already). But I found the solution:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.servlet.ServletContextEvent;
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
Very nice and easy, and working :)
The preferred way to do this is to install a ServletContextListener.
These get a chance to run code when the container starts up and shuts down.
If the code affects only a single servlet (or needs to initialize something private to that servlet object), you could also do the work in the init method of the servlet and make sure that the servlet is loaded even before a request is made (via the load-on-startup parameter).
You may run your code that initializes the other classes in the init() method of one of your servlets.
I have a Java EE application which should start a synchronization process with an external system once after its deployment.
How could I implement this requirement?
Below are listed a couple of popular methods for getting lifecycle callbacks in JavaEE apps.
Create a javax.servlet.ServletContextListener implementation
If you have a web component to your .ear file (embedded .war) or your deployment is a .war by itself you can add a ServletContextListener to your web.xml and get a callback when the server starts or is shutting down.
Example:
package com.stackoverflow.question
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
public class MyServletContextListener implements ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent contextEvent) {
/* Do Startup stuff. */
}
#Override
public void contextDestroyed(ServletContextEvent contextEvent) {
/* Do Shutdown stuff. */
}
}
and then add this configuration to your web.xml deployment descriptor.
$WAR_ROOT/WEB-INF/web.xml.
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee">
<listener>
<listener-class>com.stackoverflow.question.MyServletContextListener</listener-class>
</listener>
</web-app>
Create an EJB 3.1 #Startup Bean
This method uses an EJB 3.1 singleton to get a startup and shutdown callback from the server.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Startup;
import javax.ejb.Singleton;
#Singleton
#Startup
public class LifecycleBean {
#PostConstruct
public void init() {
/* Startup stuff here. */
}
#PreDestroy
public void destroy() {
/* Shutdown stuff here */
}
}
I tested the suggested solution which uses the #Startup and #PostConstruct annotations. It turned out that Glassfish does not complete the deployment of an application until all methods annotated with #PostConstruct have finished. So in my case the deployment would take from several minutes up to an hour.
But I figured out a different way to achive what I want. The best solution seems to be a timer callback method which cancels its timer after its execution.
#Stateless
public class SynchronisationService {
#Schedule(hour = "*", minute = "*", persistent = false)
protected void init(Timer timer)
{
doTheSync();
timer.cancel();
}
}
Using a non-persistent timer allows the timer to be re-created if the application server is restarted.
You can use the #Startup and #PostConstruct annotations to perform tasks on application startup.
Using a ServletContextListener, or a servlet that is initialized at startup, for example. Of course, this becomes much harder if you have multiple deployments of the application in a cluster, and only want this process to be run once.
This question already has an answer here:
Using special auto start servlet to initialize on startup and share application data
(1 answer)
Closed 7 years ago.
I would like to perform some action as soon as my application (Enterprise Application with Business Logic, EJB, and a Client, Web) is deployed.
For example I would like to make some entity in a persistent state, or otherwise create a file.
How can I do that?
Thanks.
Configure SerlvetContextListener and override contextInitilized()
in your web application description , web.xml
<web-app ...>
<listener>
<listener-class>com.someCompany.AppNameServletContextListener</listener-class>
</listener>
</web-app
package com.someCompany;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class AppNameServletContextListener implements ServletContextListener{
#Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
// do the things here
}
}
The "default" way is to have a servlet with an init() method. Then in the servlet-descriptor you mark this servlet as load-on-startup 1:
Example:
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
As soon as the servlet is deployed (which happens after the EJBs are deployed), that init() method is called and you can execute the task you want.
With present web application in your ear, the easiest and simplest would be to use ServletContextListener, otherwise in EJB 3.1 you could use automatic timers or startup singleton session beans.