SeamFramework.orgCommunity Documentation

Chapter 22. Servlet event propagation

22.1. Servlet context lifecycle events
22.2. Application initialization
22.3. Servlet request lifecycle events
22.4. Servlet response lifecycle events
22.5. Servlet request context lifecycle events
22.6. Session lifecycle events
22.7. Session activation events

By including the Solder module in your web application (and performing the necessary listener configuration for pre-Servlet 3.0 environments), the servlet lifecycle events will be propagated to the CDI event bus so you can observe them using observer methods on CDI beans. Solder also fires additional lifecycle events not offered by the Servlet API, such as when the response is initialized and destroyed.

This category of events corresponds to the event receivers on the javax.servlet.ServletContextListener interface. The event propagated is a javax.servlet.ServletContext (not a javax.servlet.ServletContextEvent, since the ServletContext is the only relevant information this event provides).

There are two qualifiers provided in the org.jboss.solder.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet context.

The servlet context lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.ServletContextThe servlet context is initialized or destroyed
@Initializedjavax.servlet.ServletContextThe servlet context is initialized
@Destroyedjavax.servlet.ServletContextThe servlet context is destroyed

If you want to listen to both lifecycle events, leave out the qualifiers on the observer method:

public void observeServletContext(@Observes ServletContext ctx) {

    System.out.println(ctx.getServletContextName() + " initialized or destroyed");
}

If you are interested in only a particular lifecycle phase, use one of the provided qualifiers:

public void observeServletContextInitialized(@Observes @Initialized ServletContext ctx) {

    System.out.println(ctx.getServletContextName() + " initialized");
}

As with all CDI observers, the name of the method is insignificant.

These events are fired using a built-in servlet context listener. The CDI environment will be active when these events are fired (including when Weld is used in a Servlet container). The listener is configured to come before listeners in other extensions, so the initialized event is fired before other servlet context listeners are notified and the destroyed event is fired after other servlet context listeners are notified. However, this order cannot be not guaranteed if another extension library is also configured to be ordered before others.

The servlet context initialized event described in the previous section provides an ideal opportunity to perform startup logic as an alternative to using an EJB 3.1 startup singleton. Even better, you can configure the bean to be destroyed immediately following the initialization routine by leaving it as dependent scoped (dependent-scoped observers only live for the duration of the observe method invocation).

Here's an example of entering seed data into the database in a development environment (as indicated by a stereotype annotation named @Development).

@Stateless

@Development
public class SeedDataImporter {
    @PersistenceContext
    private EntityManager em;
    public void loadData(@Observes @Initialized ServletContext ctx) {
        em.persist(new Product(1, "Black Hole", 100.0));
    }
}

If you'd rather not tie yourself to the Servlet API, you can observe the org.jboss.solder.servlet.WebApplication rather than the ServletContext. WebApplication is a informational object provided by Solder that holds select information about the ServletContext such as the application name, context path, server info and start time.

The web application lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)WebApplicationThe web application is initialized, started or destroyed
@InitializedWebApplicationThe web application is initialized
@StartedWebApplicationThe web application is started (ready)
@DestroyedWebApplicationThe web application is destroyed

Here's the equivalent of receiving the servlet context initialized event without coupling to the Servlet API:

public void loadData(@Observes @Initialized WebApplication webapp) {

    System.out.println(webapp.getName() + " initialized at " + new Date(webapp.getStartTime()));
}

If you want to perform initialization as late as possible, after all other initialization of the application is complete, you can observe the WebApplication event qualified with @Started.

public void onStartup(@Observes @Started WebApplication webapp) {

    System.out.println("Application at " + webapp.getContextPath() + " ready to handle requests");
}

The @Started event is fired in the init method of a built-in Servlet with a load-on-startup value of 99999.

You can also use WebApplication with the @Destroyed qualifier to be notified when the web application is stopped. This event is fired by the aforementioned built-in Servlet during it's destroy method, so likely it should fire when the application is first released.

public void onShutdown(@Observes @Destroyed WebApplication webapp) {

    System.out.println("Application at " + webapp.getContextPath() + " no longer handling requests");
}

This category of events corresponds to the event receivers on the javax.servlet.ServletRequestListener interface. The event propagated is a javax.servlet.ServletRequest (not a javax.servlet.ServletRequestEvent, since the ServletRequest is the only relevant information this event provides).

There are two qualifiers provided in the org.jboss.solder.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet request and a secondary qualifier to filter events by servlet path (@Path).

The servlet request lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.ServletRequestA servlet request is initialized or destroyed
@Initializedjavax.servlet.ServletRequestA servlet request is initialized
@Destroyedjavax.servlet.ServletRequestA servlet request is destroyed
@Default (optional)javax.servlet.http.HttpServletRequestAn HTTP servlet request is initialized or destroyed
@Initializedjavax.servlet.http.HttpServletRequestAn HTTP servlet request is initialized
@Destroyedjavax.servlet.http.HttpServletRequestAn HTTP servlet request is destroyed
@Path(PATH)javax.servlet.http.HttpServletRequestSelects HTTP request with servlet path matching PATH (drop leading slash)

If you want to listen to both lifecycle events, leave out the qualifiers on the observer:

public void observeRequest(@Observes ServletRequest request) {

    // Do something with the servlet "request" object
}

If you are interested in only a particular lifecycle phase, use a qualifier:

public void observeRequestInitialized(@Observes @Initialized ServletRequest request) {

    // Do something with the servlet "request" object upon initialization
}

You can also listen specifically for a javax.servlet.http.HttpServletRequest simply by changing the expected event type.

public void observeRequestInitialized(@Observes @Initialized HttpServletRequest request) {

    // Do something with the HTTP servlet "request" object upon initialization
}

You can associate an observer with a particular servlet request path (exact match, no leading slash).

public void observeRequestInitialized(@Observes @Initialized @Path("offer") HttpServletRequest request) {

    // Do something with the HTTP servlet "request" object upon initialization
    // only when servlet path /offer is requested
}

As with all CDI observers, the name of the method is insignificant.

These events are fired using a built-in servlet request listener. The listener is configured to come before listeners in other extensions, so the initialized event is fired before other servlet request listeners are notified and the destroyed event is fired after other servlet request listeners are notified. However, this order cannot be not guaranteed if another extension library is also configured to be ordered before others.

The Servlet API does not provide a listener for accessing the lifecycle of a response. Therefore, Solder simulates a response lifecycle listener using CDI events. The event object fired is a javax.servlet.ServletResponse.

There are two qualifiers provided in the org.jboss.solder.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet response and a secondary qualifier to filter events by servlet path (@Path).

The servlet response lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.ServletResponseA servlet response is initialized or destroyed
@Initializedjavax.servlet.ServletResponseA servlet response is initialized
@Destroyedjavax.servlet.ServletResponseA servlet response is destroyed
@Default (optional)javax.servlet.http.HttpServletResponseAn HTTP servlet response is initialized or destroyed
@Initializedjavax.servlet.http.HttpServletResponseAn HTTP servlet response is initialized
@Destroyedjavax.servlet.http.HttpServletResponseAn HTTP servlet response is destroyed
@Path(PATH)javax.servlet.http.HttpServletResponseSelects HTTP response with servlet path matching PATH (drop leading slash)

If you want to listen to both lifecycle events, leave out the qualifiers.

public void observeResponse(@Observes ServletResponse response) {

    // Do something with the servlet "response" object
}

If you are interested in only a particular one, use a qualifier

public void observeResponseInitialized(@Observes @Initialized ServletResponse response) {

    // Do something with the servlet "response" object upon initialization
}

You can also listen specifically for a javax.servlet.http.HttpServletResponse simply by changing the expected event type.

public void observeResponseInitialized(@Observes @Initialized HttpServletResponse response) {

    // Do something with the HTTP servlet "response" object upon initialization
}

If you need access to the ServletRequest and/or the ServletContext objects at the same time, you can simply add them as parameters to the observer methods. For instance, let's assume you want to manually set the character encoding of the request and response.

public void setupEncoding(@Observes @Initialized ServletResponse res, ServletRequest req) throws Exception {

    if (this.override || req.getCharacterEncoding() == null) {
        req.setCharacterEncoding(encoding);
        if (override) {
            res.setCharacterEncoding(encoding);
        }
    }
}

As with all CDI observers, the name of the method is insignificant.

Rather than having to observe the request and response as separate events, or include the request object as an parameter on a response observer, it would be convenient to be able to observe them as a pair. That's why Solder fires an synthetic lifecycle event for the wrapper type ServletRequestContext. The ServletRequestContext holds the ServletRequest and the ServletResponse objects, and also provides access to the ServletContext.

There are two qualifiers provided in the org.jboss.solder.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet request context and a secondary qualifier to filter events by servlet path (@Path).

The servlet request context lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)ServletRequestContextA request is initialized or destroyed
@InitializedServletRequestContextA request is initialized
@DestroyedServletRequestContextA request is destroyed
@Default (optional)HttpServletRequestContextAn HTTP request is initialized or destroyed
@InitializedHttpServletRequestContextAn HTTP request is initialized
@DestroyedHttpServletRequestContextAn HTTP request is destroyed
@Path(PATH)HttpServletRequestContextSelects HTTP request with servlet path matching PATH (drop leading slash)

Let's revisit the character encoding observer and examine how it can be simplified by this event:

public void setupEncoding(@Observes @Initialized ServletRequestContext ctx) throws Exception {

    if (this.override || ctx.getRequest().getCharacterEncoding() == null) {
        ctx.getRequest().setCharacterEncoding(encoding);
        if (override) {
            ctx.getResponse().setCharacterEncoding(encoding);
        }
    }
}

You can also observe the HttpServletRequestContext to be notified only on HTTP requests.

Since observers that have access to the response can commit it, an HttpServletRequestContext observer that receives the initialized event can effectively work as a filter or even a Servlet. Let's consider a primitive welcome page filter that redirects visitors to the start page:

public void redirectToStartPage(@Observes @Path("") @Initialized HttpServletRequestContext ctx)

        throws Exception {
    String startPage = ctx.getResponse().encodeRedirectURL(ctx.getContextPath() + "/start.jsf");
    ctx.getResponse().sendRedirect(startPage);
}

Now you never have to write a Servlet listener, Servlet or Filter again!

This category of events corresponds to the event receivers on the javax.servlet.http.HttpSessionListener interface. The event propagated is a javax.servlet.http.HttpSession (not a javax.servlet.http.HttpSessionEvent, since the HttpSession is the only relevant information this event provides).

There are two qualifiers provided in the org.jboss.solder.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the session.

The session lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.http.HttpSessionThe session is initialized or destroyed
@Initializedjavax.servlet.http.HttpSessionThe session is initialized
@Destroyedjavax.servlet.http.HttpSessionThe session is destroyed

If you want to listen to both lifecycle events, leave out the qualifiers. Note that omitting all qualifiers will observe all events with a HttpSession as event object.

public void observeSession(@Observes HttpSession session) {

    // Do something with the "session" object
}

If you are interested in only a particular one, use a qualifier

public void observeSessionInitialized(@Observes @Initialized HttpSession session) {

    // Do something with the "session" object upon being initialized
}

As with all CDI observers, the name of the method is insignificant.

This category of events corresponds to the event receivers on the javax.servlet.http.HttpSessionActivationListener interface. The event propagated is a javax.servlet.http.HttpSession (not a javax.servlet.http.HttpSessionEvent, since the HttpSession is the only relevant information this event provides).

There are two qualifiers provided in the org.jboss.solder.servlet.event package (@DidActivate and @WillPassivate) that can be used to observe a specific lifecycle phase of the session.

The session activation events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.http.HttpSessionThe session is initialized or destroyed
@DidActivatejavax.servlet.http.HttpSessionThe session is activated
@WillPassivatejavax.servlet.http.HttpSessionThe session will passivate

If you want to listen to both lifecycle events, leave out the qualifiers. Note that omitting all qualifiers will observe all events with a HttpSession as event object.

public void observeSession(@Observes HttpSession session) {

    // Do something with the "session" object
}

If you are interested in only one particular event, use a qualifier:

public void observeSessionCreated(@Observes @WillPassivate HttpSession session) {

    // Do something with the "session" object when it's being passivated
}

As with all CDI observers, the name of the method is insignificant.