Friday Dec 04, 2009

An Example of Porting Grizzly Comet to Servlet 3.0

Grizzly Comet is a very powerful feature in GlassFish v2 and GlassFish v3. It provides a framework for writing many interesting applications. However, the same application will not run in other servlet containers (without Grizzly). One can resolve this by porting the code to use asynchronous API in Servlet 3.0 as in the glassfish sample, asyn-request-war, code AjaxCometServlet.java. In this case, the application would be able to run in all Servlet 3.0 containers.

In this blog, I will discuss the former by using AjaxCometServlet.java. Even though, some details are specified to the chat example, the principle is general. There are two main steps:

Mark the servlet as asynchronous

One can achieve this by using one of the following:
  • specifying the asyncSupported in @WebServlet,
    for instance, @WebServlet(urlPatterns = {"/chat"}, asyncSupported = true)
  • adding <async-supported>true</async-supported> under corresponding <servlet> in web.xml

Modify the servlet code

ServletUsing Grizzly CometUsing Asynchronous API in Servlet 3.0
instance variablesString contextPath
  • Thread, notifierThread
  • Queue of AsyncContext, queueBlockingQueue of message, messageQueue

    Queue<AsyncContext> queue = new ConcurrentLinkedQueue<AsynContext>();
    BlockingQueue messageQueue = new LinkedBlockingQueue();

init method
  • register contextPath in CometEngine
  • set expiration time

    contextPath = config.getServletContext().getContextPath() + "/chat";
    CometContext context = CometEngine.getEngine().register(contextPath);
    context.setExpirationDelay(5 \* 60 \* 1000);

create and start a notifierThread to consume message from messageQueue

    Runnable notifierRunnable = new Runnable() {
    public void run() {
        ...
        cMessage = messageQueue.take();
        for (AsyncContext ac : queue) {
            try {
                PrintWriter acWriter = ac.getResponse().getWriter();
                acWriter.println(cMessage);
                acWriter.flush();
            } catch(IOException ex) {
                queue.remove(ac);
        ...
    };
    notifierThread = new Thread(notifierRunnable);
    notifierThread.start();

doGet method
  • create a CometHandler<PrintWriter>
  • attach the response writer to the CometHandler
  • register contextPath in CometEngine
  • add the CometHandlerto CometContext

    ... // code for ChatListenerHandler is omitted
    ChatListnerHandler handler = new ChatListnerHandler();
    handler.attach(writer);
    CometContext context = CometEngine.getEngine().register(contextPath);
    context.addCometHandler(handler)

  • create a AsyncContext
  • set timeout
  • create an AsyncListener and add to AsyncContext
  • add the AsyncContext to queue

    final AsyncContext ac = req.startAsync();
    ac.setTimeout(10 \* 60 \* 1000);
    ac.addListener(new AsyncListener() {
        ...
    };
    queue.add(ac);

doPost methodcall context.notify(message);put the message into the messageQueue
destroy method 
  • clean up the queue
  • interrupt the notifierThread

    queue.clear();
    notifierThread.interrupt();

Note that asynchronous API in Servlet 3.0 are, in fact, quite easy to use. In this scenario, some coding is need for the notification thread. If you don't want to manage the thread that notify, you can take look at Atmosphere.

Thursday Oct 29, 2009

Follow up on Servlet 3.0 Security Annotations

In May 2009, I discussed the Servlet 3.0 security annotations in one of my blogs, Servlet 3.0 Security Annotations. At that time, the annotations were defined similar to those in EJB. During the discussion in JSR 315 expert group, two issues were identified as follows:
  1. In JSR 250, type level annotations only apply to methods declared in that class, not those inherited. This is an issue for servlets as they extend javax.servlet.http.HttpServlet.
  2. The doGet method et al may not correspond to http method GET et al as the logic can be overrided in service method of the servlet.

Thanks to Ronald Monzilo for discussions in Servlet 3.0 security. The following is the update on Servlet 3.0 security annotations:

  • As in servlet 2.5, @DenyAll, @PermitAll, @RolesAllowed will not apply to servlets. @TransportProtected will not be added to JSR 250.
  • The following new annotations will be added to javax.servlet.annotation:
    • ServletSecurity
    • HttpConstraint
    • HttpMethodConstraint
    Note that @ServletSecurity is a type level annotation and the rests are used as parameters in @ServletSecurity.
  • With the above new annotations, one can resolve the issue mentioned above. In addition, it covers the new use case where one want to have security constraint for extended http methods only, for instance FOO.

In this blog, I will illustrate how those annotation work. For convenient of readers of my previous blogs, I will first illustrate the four scenarios mentioned in my previous blog, Servlet 3.0 Security Annotations with the new annotations. Then I have an additional example.

Example 1: For all Http Methods

@WebServlet("/myurl")
@ServletSecurity(@HttpConstraint(rolesAllowed={"javaee"}))
public class TestServlet extends HttpServlet {
    ...
}

In this case, all http methods are protected and accessible only by users with role javaee.

Example 2: Http Method Level

@WebServlet("/myurl")
@ServletSecurity(httpMethodConstraints={ @HttpMethodConstraint("GET"),
    @HttpMethodConstraint(value="POST", rolesAllowed={"javaee"}),
    @HttpMethodConstraint(value="TRACE", emptyRoleSemantic=ServletSecurity.EmptyRoleSemantic.DENY) })
public class TestServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
GETall can access GET method
POSTonly authenticated users with role javaee can access POST method
TRACEno one can access TRACE method

Example 3: A General Constraint for all Http methods with some Exceptional Cases

@WebServlet("/myurl")
@ServletSecurity(value=@HttpConstraint(rolesAllowed={"javaee"}),
    httpMethodConstraints={ @HttpMethodConstraint(value="POST", rolesAllowed={"staff"}),
    @HttpMethodConstraint("TRACE") })
public class TestServlet extends HttpServlet {
    ...

    protected void doPost(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
POSTonly authenticated users with role staff can access POST method
TRACEall can access TRACE method
methods other than POST and TRACEonly authenticated users with role javaee can access
Note that in the previous definitions, the exceptional cases must be the standard http methods. There is no such restriction for the new annotations as illustrated by the Example 5 below.

Example 4: Https and protected for a given role

@WebServlet("/myurl")
@ServletSecurity(value=@HttpConstraint(
    transportGuarantee=ServletSecurity.TransportGuarantee.CONFIDENTIAL),
    httpMethodConstraints={ @HttpMethodConstraint(value="TRACE", transportGuarantee=ServletSecurity.TransportGuarantee.NONE, rolesAllowed={"javaee"}) })
public class TestServlet extends HttpServlet {
    ...

    protected void doTrace(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {

        ...
    }
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
TRACEHttps is supported. It just is not required. Only authenticated users with role javaee can access TRACE method
methods other than TRACErequire https

Example 5: Protect FOO only

@WebServlet("/myurl")
@ServletSecurity(value=@HttpConstraint,
    httpMethodConstraints={ @HttpMethodConstraint(value="FOO", rolesAllowed={"javaee"}) })
public class TestServlet extends HttpServlet {
    ...
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
FOOonly authenticated users with role javaee can access POST method
methods other than FOOall can access

Thursday May 07, 2009

Servlet 3.0 web-fragment.xml

In JSR 315: Java Servlet 3.0 Specification, web-fragment.xml is introduced for pluggability of library jars which are packaged under WEB-INF/lib. The content of web.xml and web-fragment.xml are almost the same. One can define servlets, filters and listeners there. One can also specify metadata-complete=true in a given web-fragment.xml. In the latter case, the annotation processing of classes in that jar would be skipped. With web-fragment.xml, library jars can be self-contained and provide web related metadata information.

The basic differences of web.xml and web-fragment.xml are summarized in the following table:

 web.xmlweb-fragment.xml
LocationWEB-INF of the war fileMETA-INF directory of JAR file inside WAR file's WEB-INF/lib
Ordering related element<absolute-ordering><ordering>

Ordering of web fragments

If there are more than one web-fragment jars, then one may like to specify the order of processing web-fragment.xml and annotations. This is important. For instance, filters will be executed in the order specified in web.xml. Similary for listeners. In Servlet 3.0, <absolute-ordering> is introduced in web.xml and <ordering> is introduced in web-fragment.xml. The ordering of web-fragments is specified in the following priority:
  • from <absolute-ordering> in web.xml if it exists
  • from <ordering> for each web-fragment.xml if it exists
  • otherwise unspecified

absolute-ordering in web.xml

The <absolute-ordering> in web.xml provides a way to specify the ordering of loading web-fragment.xml and annotation processing of web fragment. For instance,
<web-app>
    ...
    <absolute-ordering>
        <name>A</name>
         <others/>
        <name>B</name>
    <absolute-ordering>
</web-app>
In the above example, the web fragment A would be processed first and web fragment B would be processed last. Note the name A and B are specified in name element of web-fragment.xml (see examples below).

ordering in web-fragment.xml

If there is no <absolute-ordering> in web.xml, then one would look at <ordering> in web-fragment.xml. The details are described in section 8.2.3 of Servlet 3.0 spec. Let us look at some examples.
  • There is only one jar having <ordering> in web-fragment.xml.
    <web-fragment>
        <name>A</name>
        ...
        <ordering>
            <before>
                <others/>
            </before>
        </ordering>
    </web-fragment>
    In this case, web-fragment A would be processed first.

  • There are two jars having <ordering> in web-fragment.xml, namely
    web-fragment A:
    <web-fragment>
        <name>A</name>
        ...
        <ordering>
            <before>
                <others/>
            </before>
        </ordering>
    </web-fragment>

    web-fragment B:

    <web-fragment>
        <name>B</name>
        ...
        <ordering>
            <before>
                <others/>
            </before>
        </ordering>
    </web-fragment>
    Both web-fragment A and B would like to be processed first. In this case, one only guarantee that both A and B are processed before other web-fragments. But the ordering of A and B are not determined, that is arbitrary in this case.

  • There are two jars having <ordering> in web-fragment.xml, namely
    web-fragment A:
    <web-fragment>
        <name>A</name>
        ...
        <ordering>
            <before>
                <others/>
            </before>
        </ordering>
    </web-fragment>

    web-fragment B:

    <web-fragment>
        <name>B</name>
        ...
        <ordering>
            <after>
                <name>A</name>
            </after>
            <before>
                <others/>
            </before>
        </ordering>
    </web-fragment>
    In this case, A would be processed first, then followed by B, and then other web-fragments.
If one would like to have a deterministic ordering, then I would recommend to use absolute-ordering in web.xml.

Monday May 04, 2009

Servlet 3.0 Security Annotations

Update: The security annotations have been changed. The updated information can be found in my blog, Follow up on Servlet 3.0 Security Annotations.

In Servlet 2.5, only @DeclareRoles and @RunAs are supported in servlets. And @DenyAll, @PermitAll, @RolesAllowed are only supported for EJBs. In JSR 315: Java Servlet 3.0 Specification, @DenyAll, @PermitAll, @RolesAllowed will be supported in servlets. Furthermore, it supports JSR 250: Common Annotations for the Java Platform MR1:

  • @TransportProtected, a new annotation indicates whether the transport is confidential or none.
  • @DenyAll will also be available at the TYPE level.

The mapping of the @DenyAll, @PermitAll, @RolesAllowed and @TransportProtected to security constraint are described in Chapter 13.4.1 of Servlet 3.0 specification. These annotations can be applied to:

  • the servlet class
  • one of the following methods in HttpServlet:
    • doDelete
    • doGet
    • doHead
    • doOptions
    • doPost
    • doPut
    • doTrace
Note that method level authorization annotations (@DenyAll, @PermitAll, @RolesAllowed) override those in class level for the associated http method. Similarly, method level @TransportProtected overrides the one in class level.

In this blog, we illustrate the usages of these annotations by examples.

Example 1: Type Level

@WebServlet("/myurl")
@RolesAllowed("javaee")
public class TestServlet extends HttpServlet {
    ...
}

In this case, all http methods are protected and accessible only by users with role javaee.

Example 2: Method Level

@WebServlet("/myurl")
public class TestServlet extends HttpServlet {
    @PermitAll
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }

    @RolesAllowed("javaee")
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }

    @DenyAll
    protected void doTrace(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
GETall can access GET method
POSTonly authenticated users with role javaee can access POST method
TRACEno one can access TRACE method

Example 3: Type and Method Level

@WebServlet("/myurl")
@RolesAllowed("javaee")
public class TestServlet extends HttpServlet {
    ...

    @RolesAllowed("staff")
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }

    @PermitAll
    protected void doTrace(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {
        ...
    }
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
POSTonly authenticated users with role staff can access POST method
TRACEall can access TRACE method
methods other than POST and TRACEonly authenticated users with role javaee can access

Example 4: @TransportProtected and @RolesAllowed

@WebServlet("/myurl")
@TransportProtected
public class TestServlet extends HttpServlet {
    ...

    @TransportProtected(false)
    @RolesAllowed("javaee")
    protected void doTrace(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {

        ...
    }
}

The behaviors of the above servlet can be summarized as follows:

Http methodBehavior
TRACEno https, only authenticated users with role javaee can access TRACE method
methods other than TRACErequire https

Tuesday Dec 02, 2008

Servlet 3.0 Annotations

The JSR 315: Java Servlet 3.0 Specification expert group is in the process of making Public Review available. You can look at Rajiv's blog for more details. The reference implementation is available in GlassFish v3 nightly build. In Servlet 3.0, for ease of development, several new annotations are defined. These annotations are resided in the package javax.servlet.annotation. They are intended to provide meta data only. In other words, one still need to extend the corresponding class or implement the corresponding interface.

Now, one can have Servlet, Filter and ServletContextListener in a war file without web.xml. In this blog, I will discuss the following annotations:

  • @WebServlet
  • @ServletFilter
  • @WebServletContextListener

Servlet Annotation ( @WebServlet )

In JSR 315, one can specify the servlet meta data by using @WebServlet. For instance,

    @WebServlet(name="mytest",
        urlPatterns={"/myurl"},
        initParams={ @InitParam(name="n1", value="v1"), @InitParam(name="n2", value="v2") })
    public class TestServlet extends javax.servlet.http.HttpServlet {
        ....
    }

In this example, the class TestServlet is a servlet as it extends HttpServlet. The @WebServlet provides the following meta data:

  • the name of the servlet, mytest, corresponds to <servlet-name> under <servlet> in web.xml
  • the url pattern of the servlet, /myurl, corresponds to <url-pattern> under <servlet-mapping> in web.xml
  • initialization parameters of the servlet, n1=v1, n2=v2, corresponds to <init-param> under <servlet> in web.xml
      <init-param>
        <param-name>n1</param-name>
        <param-value>v1</param-value>
      </init-param>
      <init-param>
        <param-name>n2</param-name>
        <param-value>v2</param-value>
      </init-param>
    Note that in this case, @InitParam is used to specify the name/value pairs.

Servlet Filter Annotation ( @ServletFilter )

One can specify the servlet filter meta data by using @ServletFilter. For instance,

    @ServletFilter(urlPatterns={"/myurl"}.
        initParams={ @InitParam(name="mesg", value="my filter") })
    public class TestFilter implements javax.servlet.Filter {
        ....
        public void init(FilterConfig filterConfig) throws ServletException {
            ....
        }

        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            ....
        }

        public void destroy() {
            ....
        }
    }

In this example, the class TestFilter is a servlet filter as it implements Filter. The @ServletFilter provides the following meta data:

  • the url pattern of the filter applied, /myurl
  • initialization parameter of the filter, mesg=my filter, corresponds to <init-param> under <filter> in web.xml
    Note that in this case, @InitParam is used to specify the name/value pairs.

Servlet Context Listener Annotation ( @WebServletContextListener )

One can specify the servlet content listener met data by using @WebServletContextListener. For instance,

    @WebServletContextListener
    public class TestServletContextListener implements javax.servlet.ServletContextListener {
        ....
        public void contextInitialized(ServletContextEvent sce) {
            ....
        }

        public void contextDestroyed(ServletContextEvent sce) {
            ....
        }
    }

In this example, the class TestServletContextListener is a servlet context listener as it implements ServletContextListener. The @WebServletContextListener provides the meta data that this is a servlet context listener in a given war file.

About

Shing Wai Chan

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today