Chapter 22

Dynamic Registration and Servlet Container Initializers

Dynamic registration and the servlet container initializer were added to Servlet 3.0. The former is used for installing new web objects (servlets, filters, listeners) without reloading the application. The latter is especially useful for framework developers.

This chapter discusses both features and presents examples.

Dynamic Registration

To make dynamic registration possible, the following methods were added to the ServletContext interface to dynamically create a web object.

<T extends Filter> createFilter(java.lang.Class<T> clazz)
<T extends java.util.EventListener> createListener(
        java.lang.Class<T> clazz)
<T extends Servlet> createServlet(java.lang.Class<T> clazz)

For example, if MyServlet is a class that directly or indirectly implements javax.servlet.Servlet, you can instantiate MyServlet by calling createServlet:

Servlet myServlet = createServlet(MyServlet.class);

After you create a web object, you can add it to the ServletContext using one of these methods.

FilterRegistration.Dynamic addFilter(java.lang.String filterName, 
        Filter filter)
<T extends java.util.EventListener> void addListener(T t)
ServletRegistration.Dynamic addServlet(java.lang.String 
        servletName, Servlet servlet)

Alternatively, you can simultaneously create and add a web object to the ServletContext by calling one of these methods on the ServletContext.

FilterRegistration.Dynamic addFilter(java.lang.String filterName, 
        java.lang.Class<? extends Filter> filterClass)
FilterRegistration.Dynamic addFilter(java.lang.String filterName, 
        java.lang.String className)
void addListener(java.lang.Class<? extends java.util.EventListener> 
        listenerClass)
void addListener(java.lang.String className)
ServletRegistration.Dynamic addServlet(java.lang.String 
        servletName, java.lang.String className)
ServletRegistration.Dynamic addServlet(java.lang.String 
        servletName, java.lang.String className)

To create or add a listener, the class passed to the first addListener method override must implement one or more of the following interfaces:

  • ServletContextAttributeListener
  • ServletRequestListener
  • ServletRequestAttributeListener
  • HttpSessionListener
  • HttpSessionAttributeListener

If the ServletContext was passed to a ServletContextInitializer’s onStartup method, the listener class may also implement ServletContextListener. For information about the on startUp method and the ServletContextInitializer interface, see the section below.

The return value of the addFilter or addServlet method is either a FilterRegistration.Dynamic or a ServletRegistration.Dynamic.

Both FilterRegistration.Dynamic and ServletRegistration.Dynamic are subinterfaces of Registration.Dynamic. FilterRegistration.Dynamic allows you to configure a filter and ServletRegistration.Dynamic a servlet.

As an example, consider the dynamic-reg application that contains a servlet named FirstServlet and a listener called DynRegListener. The servlet is not annotated with @WebServlet, nor is it declared in the deployment descriptor. The listener registers the servlet dynamically and put it into use.

The FirstServlet class is given in Listing 22.1 and the DynRegListener class in Listing 22.2.

Listing 22.1: The FirstServlet class

package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstServlet extends HttpServlet {
    private static final long serialVersionUID = -6045338L;

    private String name;
    
    @Override
    public void doGet(HttpServletRequest request, 
            HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<!DOCTYPE html><html>"
                + "<head><title>First servlet</title></head><body>" 
                + name + "</body></head>");
    }   
    
    public void setName(String name) {
        this.name = name;
    }
}

Listing 22.2: The DynRegListener class

package listener;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;
import servlet.FirstServlet;

@WebListener
public class DynRegListener implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }

    // use createServlet to obtain a Servlet instance that can be
    // configured prior to being added to ServletContext
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();
        
        Servlet firstServlet = null;
        try {
            firstServlet = 
                servletContext.createServlet(FirstServlet.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        if (firstServlet != null && firstServlet instanceof 
                FirstServlet) {
            ((FirstServlet) firstServlet).setName(
                    "Dynamically registered servlet");
        }
        
        // the servlet may not be annotated with @WebServlet
        ServletRegistration.Dynamic dynamic = servletContext.
                addServlet("firstServlet", firstServlet);
        dynamic.addMapping("/dynamic");
    }
}

When the application starts, the container calls the listener’s contextInitialized method. As a result, an instance of FirstServlet gets created and registered and mapped to /dynamic. If everything goes well, you should be able to invoke FirstServlet with this URL.

http://localhost:8080/dynamic-reg/dynamic

Servlet Container Initializers

If you have used a Java web framework, such as Struts or Struts 2, you know that you need to configure your application before you can use the framework. Typically, you will need to tell the servlet container that you’re using a framework by modifying the deployment descriptor. For example, to use Struts 2 in your application, you add the following tags to the deployment descriptor:

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>
        org.apache.struts2.dispatcher.ng.filter.
StrutsPrepareAndExecuteFilter
    </filter-class>
</filter>

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

In Servlet 3.0 and later, this is no longer necessary. A framework can be packaged in such a way that initial registration of web objects happens automatically.

The brain of servlet container initialization is the javax.servlet.ServletContainerInitializer interface. This is a simple interface with only one method, onStartup. This method is called by the servlet container before any ServletContext listener is given the opportunity to execute.

The signature of onStartup is as follows.

void onStartup(java.util.Set<java.lang.Class<?>> klazz, 
        ServletContext servletContext)

Classes implementing ServletContainerInitializer must be annotated with @HandleTypes to declare the class types the initializer can handle.

As an example, the initializer.jar library accompanying this book contains a servlet container initializer that registers a servlet named UsefulServlet. Figure 22.1 shows the structure of initializer.jar.

Figure 22.1: The structure of initializer.jar

This library is a pluggable framework. There are two resources that are of importance here, the initializer class (initializer.MyServletContainerInitializer, printed in Listing 22.3) and a metadata text file named javax.servlet.ServletContainerInitializer. This text file must be placed under META-INF/services in the jar file. The text file consists of only one line, which is the name of the class implementing ServletContainerInitializer, and is given in Listing 22.4.

Listing 22.3: A ServletContainerInitializer

package initializer;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.HandlesTypes;
import servlet.UsefulServlet;

@HandlesTypes({UsefulServlet.class})
public class MyServletContainerInitializer implements
        ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> classes, ServletContext 
            servletContext) throws ServletException {
        
        System.out.println("onStartup");
        ServletRegistration registration = 
                servletContext.addServlet("usefulServlet", 
                "servlet.UsefulServlet");
        registration.addMapping("/useful");
        System.out.println("leaving onStartup");
    }
}

Listing 22.4: The javax.servlet.ServletContainerInitializer file

initializer.MyServletContainerInitializer

The main job of the onStartup method in MyServletContainerInitializer is to register web objects. In this example, there is only one such object, a servlet named UsefulServlet, which is mapped to the /useful pattern. In a large framework, registration instructions can come from an XML document, as in Struts and Struts 2.

The container-init application accompanying this chapter already contains a copy of initializer.jar in the WEB-INF/lib directory. To confirm that UsefulServlet is registered successfully when the application starts, direct your browser to this URL and see if you see some output from the servlet:

http://localhost:8080/container-init/useful

It is not hard to imagine that one day all frameworks will be deployed as plug-ins.

Summary

In this chapter you have learned two features for deploying applications and plug-ins on the fly. The first feature is dynamic registration, which allows you to dynamically add servlets, filters, and listeners without application restart. The second one is the servlet container initializer, which allows you to deploy plug-ins without changing the deployment descriptor of the user application. The servlet container initializer is particularly useful to framework developers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.114.125