Friday, October 1, 2010

Programmatic instantiation of Components like servlets, filters, and listeners

With programmatic definition, we can instantiate components programmatically and then configure them. Servlet 3.0 Specification supports dynamic instantiation of servlets and filters.

In this example, we will see how you might programmatically instantiate servlets, filters, and listeners.

@WebListener
public class MyServletContextListener implements ServletContextListener {

public void contextInitialized(ServletContextEvent sce) {
LOG.info("Context Listener Initialized");
doProgrammaticRegistration(sce.getServletContext());
}

private void doProgrammaticRegistration(ServletContext sc) {

// servlet definition
ServletRegistration.Dynamic dynaServlet = sc.addServlet(
"MyProgrammaticServlet",
"com.servlets.MyProgrammaticServlet");
dynaServlet.addMapping("/myprogrammaticservlet");

// filter definition
FilterRegistration.Dynamic dynaFilter = sc.addFilter(
"MyProgrammaticFilter",
"com.filters.MyProgrammaticFilter");
EnumSet dispatcherType = EnumSet.of(
DispatcherType.REQUEST, DispatcherType.FORWARD);
dynaFilter.addMappingForServletNames(dispatcherType, true,
"MyProgrammaticServlet");
}
}

As shown, during context initialization, we instantiate a new servlet and returned class ServletRegistration.Dynamic instance is used to configure the appropriate servlet mapping. We do the similar steps with a filter. These steps are similar to what would have happened when a servlet container encountered the <servlet>, <servlet-mapping>, <filter> and <filter-mapping> elements in a web deployment descriptor.

As it can be seen in the next code listings, the servlet and filter are rather straightforward. Since the configuration occurs programmatically, they do not even need any annotations to be used.

//Note: not even an annotation is required
public class MyProgrammaticFilter implements Filter {
private final Logger LOG = Logger.getLogger("MyProgrammaticFilter");

public void destroy() { }

public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws ServletException, IOException {

LOG.info("Filtering: " + ((HttpServletRequest)req).getRequestURI());
chain.doFilter(req, resp);
}

public void init(FilterConfig config) throws ServletException {
LOG.info("Filter: " + "Initializing ProgrammaticFilter");
}
}

//Note: not even an annotation is required.
public class MyProgrammaticServlet extends HttpServlet {
private final Logger LOG = Logger.getLogger("MyProgrammaticServlet");

protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
LOG.info("Within request : " + getServletName());
String html = "Added programmatically (no annotation/web.xml entries): " + new Date();

response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println(html);
}
}

Hope this will help.

Servlet 3.0 Annotations

Servlet 3.0 Specification has a number of new features and one of them is annotation. When an application loads, all classes into the application are examined for presence of the annotations. When these annotations are found on a particular class, the container registers instances of the classes as Listeners, Servlets, or Filters based on the annotation.
Servlet 3.0 Specification Annotations are as follows.

* @WebServlet
* @WebFilter
* @WebInitParam
* @WebListner
* @MultipartConfig

@WebServlet
This annotation is used to define a Servlet component in a web application and defines the metadata about the servlet being declared.
Classes annotated with @WebServlet annotation must extend javax.servlet.http.HttpServlet class.
@WebServlet annotation annotation has the following attributes.
* name
* description
* value
* urlPatterns
* initParams
* loadOnStartup
* asyncSupported
* smallIcon
* largeIcon
Note: the spec mandates either value or urlPatterns attribute be specififed.

Example:
@WebServlet(name = "myservlet", urlPatterns = { "/myservlet" })
public class MyServletExample extends HttpServlet {
}

@WebFilter
This annotation is used to define a filter in web application. The classes annotated with @WebFilter annotation must implement javax.servlet.Filter interface.
The @WebFilter annotation has the following attributes
* filterName
* description
* displayName
* initParams
* servletNames
* value
* urlPatterns
* dispatcherTypes
* asyncSupported

Example:
@WebFilter(filterName="samplefilter", urlPatterns={"/foo/*", "/bar"})
public class MyServletSampleFilter implements Filter {
}

@WebInitParam
This annotation is used to specify any init parameters that must be passed to the Servlet or the Filter.
The annotation defines the following attributes:
* name
* value
* description

Example:
@WebServlet(value="/hello",
initParams = {
@WebInitParam(name="name1", value="Hello "),
@WebInitParam(name="name2", value=" World!")
})
public class MyHelloServletExample extends HttpServlet {
}

@WebListner
This annotation is used to define a listener. The @WebListener annotation is used to register the following types of listeners
1. Context Listener (javax.servlet.ServletContextListener)
2. Context Attribute Listener (javax.servlet.ServletContextAttributeListener)
3. Servlet Request Listener (javax.servlet.ServletRequestListener)
4. Servlet Request Attribute Listener (javax.servlet.ServletRequestAttributeListener)
5. Http Session Listener (javax.servlet.http.HttpSessionListener)
6. Http Session Attribute Listener (javax.servlet.http.HttpSessionAttributeListener)

@WebListener is the easiest to use. Registering ServletContextListener.

Example:
@WebListener()
public class MySampleContextListner extends ServletContextListner {
public void contextInitialized(ServletContextEvent event) {
//do some thing on application init
}

public void contextDestroyed(ServletContextEvent event) {
//do some thing on application destroy
}
}

@MultipartConfig
Servlet 3.0 specification comes with the built in file upload support. This annotation, when specified on a Servlet, indicates that the request it expects is of type mime/multipart. The HttpServletRequest object of the corresponding servlet makes available the mime attachments via the getParts and getPart methods to iterate over the various mime attachments.

The @MultipartConfig annotation can be used to specify the location where the files can be stored, maximum size of the file being uploaded, maximum request size and the size threshold after which the file will be written to the disk. There is any equivalent element in web.xml that can be used for the same purpose.

@MultipartConfig annotation declares the following attributes:
* location
* maxFileSize
* maxRequestSize
* fileSizeThreshold

Example:
@WebServlet(name="UploadServlet", urlPatterns={"/upload"})
@MultipartConfig(location="d://tmp")
public class MyServletExample extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//target directory and location are the same.
req.getPart("content").write("file.txt");
}
}

Hope this will help.