Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Jetty/Feature/Annotations"

< Jetty‎ | Feature
Line 2: Line 2:
  
 
|introduction =
 
|introduction =
 +
 +
{{Jetty TODO}}
 +
 
The [http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index.html Java Servlet 2.5 Specification] added the ability to inject [[Jetty/Feature/JNDI|JNDI]] resources into fields and methods of servlets, filters and listeners, and also to perform certain callbacks at various points in the lifecycle of a web application.
 
The [http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index.html Java Servlet 2.5 Specification] added the ability to inject [[Jetty/Feature/JNDI|JNDI]] resources into fields and methods of servlets, filters and listeners, and also to perform certain callbacks at various points in the lifecycle of a web application.
  

Revision as of 14:39, 23 April 2013



Introduction

Warning2.png
Some or all of this content remains to be ported to Jetty 9 Documentation.
If you are interested in migrating this content see our contribution guide or contact us.


The Java Servlet 2.5 Specification added the ability to inject JNDI resources into fields and methods of servlets, filters and listeners, and also to perform certain callbacks at various points in the lifecycle of a web application.

JNDI resource injection and the lifecycle callbacks can be specified entirely within the web.xml file, or alternatively marked up as annotations in your source code. You can even use a combination of annotations and web.xml declarations.

One important thing to be aware of is that the 2.5 Servlet Specification introduced a new attribute into the <web-app> element, the metadata-complete attribute. If true, then the web container will NOT search the webapp for source code annotations, and your web.xml file must contain all resources required. If false or not specified, then jetty is required to examine all servlets, filters and listeners in the webapp for annotations. Therefore, you can save startup time by using this attribute correctly - if you don't want to use annotations then ensure you mark metadata-complete="true", otherwise you will pay the penalty of the code examination.

Here's an example of setting this attribute:

<web-app 
   xmlns="http://java.sun.com/xml/ns/j2ee" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" 
   metadata-complete="false"
   version="2.5">

Feature

Set up

Annotation processing is not enabled by default by the standard jetty distribution, only by the jetty-hightide distribution. To enable annotation processing you will need to do some configuration file setup, and also add the OPTIONS for annotation to put the annotation-related jars onto the classpath.

First, lets define the configuration setup needed:

<Array id="plusConfig" type="java.lang.String">
  <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
  <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
  <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
  <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
  <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>        <!-- added for JNDI -->
  <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>       <!-- added for JNDI -->
  <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item> <!-- added for annotations -->
  <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
  <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
</Array>

The above is the basic set of configurations that need to be applied to a webapp upon deployment. You can apply these configurations to a specific webapp only, all webapps deployed by a particular deployer, or all webapps deployed into a server.

Idea.png
Tip:
$JETTY_HOME/etc/jetty-plus.xml comes pre-setup with these configurations, and applies them to all webapps deployed into a Server instance. Edit start.ini to add jetty-plus.xml, and then add "annotations" to the list of OPTIONS and you're done.


Applying the configurations to a single webapp

If you elect not to use $JETTY_HOME/etc/jetty-plus.xml, and want to enable annotation processing for only a single webapp, you will need to create a context xml file for that webapp and put the configurations definition into it. Here's an example, which will set up annotation processing for the webapp in $JETTY_HOME/webapps/my-cool-webapp:

<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
 
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
 
  <Array id="plusConfig" type="java.lang.String">
    <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
    <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item> <!-- added for JNDI -->
    <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>    <!-- added for JNDI -->
    <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item> <!-- added for annotations -->
    <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
  </Array>
 
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/my-cool-webapp</Set>
  <Set name="configurationClasses"><Ref id="plusConfig"/></Set>
 
</Configure>

Now add "annotations" to the OPTIONS definition in start.ini to get the annotation-processing related jars onto jetty's runtime classpath and you're ready to run.

Applying the configurations to webapps deployed by a deployer

If you'd like to restrict the usage of annotations to only a subset of your webapps, you can copy them into a directory, and then set up a WebAppDeployer for them which will apply the configurations. For example, suppose you have moved the webapps into the directory $JETTY_HOME/plus-webapps, you can create a new xml configuration file (remembering to add it to start.ini, or edit an existing xml file), and add:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
 
  <Array id="plusConfig" type="java.lang.String">
    <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
    <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>        <!-- added for JNDI -->
    <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>       <!-- added for JNDI -->
    <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item> <!-- added for annotations -->
    <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
  </Array>
 
  <Ref id="DeploymentManager">
      <Call name="addAppProvider">
        <Arg>
          <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
            <Set name="monitoredDirName"><Property name="jetty.home" default="." />/webapps-plus</Set>
            <Set name="configurationClasses"><Ref id="plusConfig"/></Set>
          </New>
        </Arg>
      </Call>
  </Ref>

Now add "annotations" to the OPTIONS definition in start.ini to get the annotation-processing related jars onto jetty's runtime classpath and you're ready to run.

Applying the configurations to all webapps in a server

This is the approach taken in $JETTY_HOME/etc/jetty-plus.xml. You can simply add it to your start.ini file. For your information, here's what the file looks like:

<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
 
<Configure id="Server" class="org.eclipse.jetty.server.Server">
 <Array id="plusConfig" type="java.lang.String">
    <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
    <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
    <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
    <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
    <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
  </Array>
 
  <Call name="setAttribute">
    <Arg>org.eclipse.jetty.webapp.configuration</Arg>
    <Arg>
        <Ref id="plusConfig"/>
    </Arg>
  </Call>
</Configure>

Now add "annotations" to the OPTIONS definition in start.ini to get the annotation-processing related jars onto jetty's runtime classpath and you're ready to run.


Servlet 2.5 Annotations

  • @Resource equivalent to resource-ref, resource-env-ref, env-entry and message-destination-ref in web.xml
  • @Resources declares java:comp/env name linkages for reference by JNDI lookups
  • @PostConstruct equivalent to post-construct in web.xml
  • @PreDestroy equivalent to pre-destroy in web.xml
  • @RunAs equivalent to run-as in web.xml

Resource Injections

Resource injections make available an object from JNDI as the value of a field or method parameter of a servlet, filter or listener class.

We'll look at a couple of small examples of how to declare them in web.xml and how to declare them in code, but for more in-depth information, you should consult the Common Annotations for the Java Platform Specification (JSR250), the Servlet 2.5 Specification (JSR154) and the JavaEE Specification v5 (JSR244).

Here is a small example of the injection of a DataSource resource via a web.xml declaration:

  <resource-ref>
    <res-ref-name>jdbc/mydatasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <injection-target>
      <injection-target-class>com.acme.MyServlet</injection-target-class>
      <injection-target-name>myDatasource</injection-target-name>
    </injection-target>
  </resource-ref>

This example shows that the resource named java:comp/env/jdbc/mydatasource will be injected by Jetty into the the field named myDatasource or the method named setMyDatasource(javax.sql.DataSource) in the instance of the class com.acme.MyServlet before it goes into service.

The equivalent injection using an annotation on the field instead would be:

import javax.sql.DataSource;
import javax.annotation.Resource;
import javax.servlet.http.HttpServlet;
 
public class MyServlet extends HttpServlet
{
    @Resource (name="jdbc/mydatasource", type=DataSource.class)
    private DataSource foo;
 
}

The equivalent as an annotation on the method would be:

import javax.sql.DataSource;
import javax.annotation.Resource;
import javax.servlet.http.HttpServlet;
 
public class MyServlet extends HttpServlet
{
    private DataSource foo;
 
    @Resource (name="jdbc/mydatasource", type=DataSource.class)
    private void setMyDatasource (DataSource ds)
    {
        foo = ds;
    }
 
}

Lifecycle callbacks: PostConstruct PreDestroy

The Servlet 2.5 Specification (JSR154) also introduces the concept of lifecycle callbacks. These are of two types: a post-construction callback, and a pre-destruction callback. The former will be invoked after all resource injections have been performed on an instance of a managed class (eg servlet, filter or listener) but before it goes into service. The latter is invoked just before the container removes the instance from service. Let's look at how you might declare these callbacks in a web.xml file:

<post-construct>
    <lifecycle-callback-class>com.acme.MyServlet</lifecycle-callback-class>
    <lifecycle-callback-method>myPostConstructMethod</lifecycle-callback-method>
</post-construct>
 
<pre-destroy>
    <lifecycle-callback-class>com.acme.MyServlet</lifecycle-callback-class>
    <lifecycle-callback-method>myPreDestroyMethod</lifecycle-callback-method>
</pre-destroy>

The above example would invoke the method myPostConstructMethod() on the instance of the class com.acme.MyServlet before the servlet is put into service, and would invoke the method myPreDestroyMethod() on the instance before it goes out of service.

Here's how the annotations would look instead:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServlet;
 
public class MyServlet extends HttpServlet
{
    @PostConstruct
    private void myPostConstructMethod ()
    { 
        System.err.println("PostConstruct called");
    }
 
    @PreDestroy
    private void myPreDestroyMethod ()
    {
        System.err.println("PreDestroy called");
    }
}

Security:RunAs

The @RunAs annotation is equivalent to the run-as element in web.xml: it is a role which is propagated as the security identity in calls to EJBs.

Here's an example of a web.xml declaration:

  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.acme.MyServlet</servlet-class>
    <run-as>special</run-as>
  </servlet>

Here is the equivalent as an annotation:

import javax.annotation.security.RunAs;
import javax.servlet.http.HttpServlet;
 
@RunAs("special")
public class MyServlet extends HttpServlet 
{
}

Security: DeclareRoles

The @DeclareRoles annotation is equivalent to declaring security-role elements in web.xml.

Here's an example of web.xml security-roles:

 <security-role>
    <role-name>server-administrator</role-name>
 </security-role>
 <security-role>
    <role-name>user</role-name>
 </security-role>

Here's how they would look as an annotation instead:

import javax.annotation.security.DeclareRoles;
import javax.servlet.http.HttpServlet;
 
@DeclareRoles({"server-administrator", "user"})
public class MyServlet extends HttpServlet 
{
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {  
        boolean result = request.isUserInRole("server-administrator");
    }
}

Back to the top