20

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?

Oliver
  • 3,815
  • 8
  • 35
  • 63
  • Do you really want the process to start at "deployment" (i.e., a new EAR) or at startup (JEE server re-start)? – Matteo Aug 16 '13 at 13:37
  • 1
    Take a look at [this solution](http://stackoverflow.com/questions/14992602/how-to-call-a-function-while-running-a-java-web-application/17445847#17445847), it might be what you mean. – loulou Aug 16 '13 at 13:42
  • I simply would like to ensure that the synchronisation process will be started after the deployment or at server start. – Oliver Aug 18 '13 at 15:40

4 Answers4

28

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 */
  }

}
Dev
  • 11,919
  • 3
  • 40
  • 53
  • 1
    That package is wrong. Why no `@WebListener`? Are you googling answers for OP or so? – BalusC Aug 16 '13 at 14:02
  • @BalusC I didn't know about `@WebListener` I've always configured `ServletContextListeners` using `web.xml`. I'm not exactly sure how it works so I don't want to give wrong advice. Also which package did I get wrong? – Dev Aug 16 '13 at 14:05
  • @BalusC Found it. I don't know how I missed that wrong package name. Thanks for pointing that out. – Dev Aug 16 '13 at 15:04
  • `` needs `` closing tag – Marc Bouvier Dec 09 '16 at 09:44
9

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.

Oliver
  • 3,815
  • 8
  • 35
  • 63
  • why did you use a stateless bean and not a singleton, I am using singleton, and it works but i get time retries every minute, while the job is running ... which throw an error. – NimChimpsky Oct 08 '15 at 15:36
5

You can use the @Startup and @PostConstruct annotations to perform tasks on application startup.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • 1
    From my experience the `@PostConstruct` annotation should be only used for initialisation tasks which need only a few minutes. The synchronisation with an external system needs much longer. Therefore the synchronisation should not be bound to the initialisation of the bean itself. – Oliver Aug 18 '13 at 20:35
0

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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255