Thursday Oct 18, 2012

JavaOne 2012 - What's new in Servlet 3.1: An Overview

Rajiv and I had presented the session CON6793, "What's new in Servlet 3.1: An Overview", on October 2 at JavaOne 2012, San Francisco. It was at 8:30 am. There were a lot of audiences even in the early morning. Most of the audiences know Servlet 3.0. And we have some good discussions after the talk. I have attached the pdf of presentation so that it can be shared with wider audiences.

Thursday Oct 21, 2010

Profiling GlassFish 3 with JProfiler

Recently, I investigated performance issues of GlassFish 3. I found that JProfiler 6 is a very handy tool. In this blog, I would like to share with you what I learnt. I would like to thank Dhiru Pandey and Suveen Nadipalli for their help. In the following, we will assume GlassFish 3 installed in $GLASSFISH_HOME and JProfiler 6 is running on Mac OS 10.5.8.

Set up GlassFish 3

Insert com.jprofiler.agent, com.jprofiler.agent.*, immediately after ${eclipselink.bootdelegation}, in org.osgi.framework.bootdelegation property in $GLASSFISH_HOME/glassfish3/glassfish/osgi/felix/conf/config.properties.nojaxb.

Note that if one were to debug the GlassFish Web Profile - they would need to change $GLASSFISH_HOME/glassfish3/glassfish/osgi/felix/conf/config.properties.

Issue 12364 is filed on this. Once this bug is fixed only config.properties will need to be modified.

Set up JProfile 6 with GlassFish 3

  1. Launch JProfiler.
  2. In Quickstart menu, choose "An application server, locally or remotely".
  3. Choose integration wizard: choose "Glassfish V3".
  4. Choose profiled application located: "On this computer".
  5. JVM settings: (vendor/version/mode). (Note that GlassFish 3 uses JDK "1.6.x".)
  6. Choose "Wait for connection from the JProfiler GUI".
  7. Locate the config file: $GLASSFISH_HOME/glassfish3/glassfish/domains/domain1/config/domain.xml.
  8. Locate the start script: $GLASSFISH_HOME/glassfish3/glassfish/bin/asadmin.
  9. Choose the jprofiler port: 8849 (default).
  10. Click "No".
  11. JProfile create a script asadmin_jprofiler in $GLASSFISH_HOME/glassfish3/glassfish/bin. In Mac, you may like to double check that the script has execution permission. Run chmod u+x $GLASSFISH_HOME/glassfish3/glassfish/bin/asadmin_jprofiler if necessary.
  12. Click "Start Center" > "Open Session" > Double click "Glassfish V3 on localhost" > Session Startup: "Cancel"
  13. Click "Session Settings" > "Filter Settings" > "Excluded"
    Make sure that you do not exclude the classes that you want to profile. For instance, I remove "com.sun.", "org.glassfish.", "org.apache.", "org.jvnet". Click "OK" to save it.
  14. Click "Start" for start profiling GlassFish 3.
  15. For collecting performance data, "CPU Views" > Press to record CPU data

Tips for Viewing and Analyzing Data

  1. For a given class, the most time consuming method is the first one. In general, one may like to look at the most expensive operation first.
  2. If one only interests only in profiling certain package, then one can enter the package name in "View Filters" text box near the bottom of the JProfile screen.
  3. One can export the tree view of the data into html by clicking "Export" in top menu bar.
  4. One can save the data for later comparison by clicking "Save Snapshot".
  5. One can open and compare several snapshots at the same time as follows:
    • "Session" > "Open Snapshot" > "New Window"
    • Select the snapshot data file (with extension .jps) > "Open"

Can we profile GlassFish 3 with JProfile 5?

One can profile GlassFish 3 with JProfile 5. The setup for GlassFish 3 is the same. The setup for JProfile 5 is as follows:
  1. Launch JProfiler.
  2. Close Quickstart if necessary.
  3. Click "Start Center" > "New Session".
  4. Fill in the following information and click "OK".
    • Enter the "Session name".
    • Choose "Session Type": Local.
    • Java VM: 1.6.x
    • Working Directory: $GLASSFISH_HOME/glassfishv3/glassfish/domains/domain1/config
    • VM arguments:-Dcom.sun.aas.installRoot=$GLASSFISH_HOME/glassfishv3/glassfish -Dcom.sun.aas.instanceRoot=$GLASSFISH_HOME/glassfishv3/glassfish/domains/domain1
    • Main class executable JAR: $GLASSFISH_HOME/glassfishv3/glassfish/modules/glassfish.jar
  5. Then repeat Step 12 to Step 15 of the setup for JProfile 6 above.

Enjoy profiling GlassFish 3.

Friday Jun 11, 2010

Change Session Id on Authentication in GlassFish

Session fixation attack is a security vulnerabiltiy where the victim is tricked to login using the session given by a hacker, then the hacker can use the session after that.

Prior to GlassFish v3, one can mininize the exposure of session id in url encoding by specifying a session-properties in WEB-INF/sun-web.xml:

<sun-web-app>
  <session-config>
    <session-properties>
      <property name="enableURLRewriting" value="false" />
    </session-properties>
  </session-config>
</sun-web-app>

In GlassFish v3, with the support of Servlet 3.0, one can also achieve above by specifying the tracking-mode in WEB-INF/web.xml:

<web-app ...>
  ...
  <session-config>
    <tracking-mode>COOKIE</tracking-mode>
  </session-config>
</web-app>

Note that the default tracking-mode in GlassFish v3 is COOKIE and URL.

In GlassFish 3.0.1 and GlassFish 3.1, a security feature is ported from Tomcat. One can configure a web application so that the session id will be changed after authentication. This mininizes the session fixation attack. One can achieve this by configuring META-INF/context.xml in war file. For instance,

<?xml version="1.0" encoding="ISO-8859-1"?>
<Context>
  <Valve className="org.apache.catalina.authenticator.FormAuthenticator" changeSessionIdOnAuthentication="true"/>
</Context>

The above example used form based login. If BASIC is used, then the className should be org.apache.catalina.authenticator.BaseAuthenticator.

Wednesday Mar 17, 2010

Https outbound connection from GlassFish Enterprise Server v2 to Oracle GlassFish Server 3.0

Oracle GlassFish Server 3.0 is a Java EE 6 container. It uses JKS as keystore. In GlassFish Enterprise Server v2, it uses NSS. In this simple blog, we will show how to set up environments for https outbound connection from GlassFish v2 to Oracle GlassFish Server 3.0.
  1. Export the certificate from Oracle GlassFish Server 3.0 from JKS.
    Change to domain config directory where one can find cacerts.jks and run the following command:
    keytool -export -rfc -alias s1as -file s1asv3.cert -keystore cacerts.jks -storepass changeit
    Note that one should let keytool prompt for password rather than using -storepass. It is used here for illustration.
  2. Import the certificate to GlassFish Enterprise Server v2.
    Note that one need to use a different alias name "s1asv3" as there is already a certificate of name "s1as" in NSS db. Change to the domain config directory where one can find cert8.db and run the following command:
    certutil -A -n s1asv3 -d . -i s1asv3.cert -t "T,c,c"
    Restart the GlassFish Enterprise Server.
I find that the following jsp testing code is quite handy. It is included here for convenience:

<%@page import="java.io.\*, java.net.\*, javax.net.ssl.\*" %>
<%
    try {
        String host = request.getParameter("host");
        String port = request.getParameter("port");
        String urlStr = "https://" + host + ":" + port;
        out.println("Url = " + urlStr + "<hr>");
        URL url = new URL(urlStr);
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        BufferedReader in = null;
        in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line = "";
        while ((line = in.readLine()) != null) {
            out.println(line);
        
    } catch(Throwable ex) {
        out.println("<hr><pre>");
        ex.printStackTrace(new PrintWriter(out));
    }
%>

Note that one can read more about GlassFish Enterprise Server v2 and NSS in "Key Management and PKCS#11 Tokens in Sun Java System Application Server 8.1".

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 Mar 10, 2009

Using Jetty Bayeux Client in GlassFish v3

In Cometd environment, one can access cometd services through simple Javascript, Java API for Bayeux Protoc, DOJO, etc.

In the Grizzly Issue 174, developer amplus has contributed a first porting of Jetty Bayeux Java Client to Grizzly. A modification of the contribution has been checkin to Grizzly. The above client code is based on Jetty 6.1.11. Subsequently, various cometd bugs has been fixed in Grizzly 1.9.8 or later.

In this blog, we will describe how to use the Jetty Bayeux client in Grizzly with GlassFish v3.

Environment Setting

In this moment, comet support is turned off by default. The comet/cometd can be turned on in GlassFish v3 by adding the following property to corresponding http-listener. In our case, it is the http-listener-1.

    <property name="cometSupport" value="true">

Note that it is recommended that one should set the above property by using asadmin rather than directly editing the domain.xml. For instance,

    asadmin set server.http-service.http-listener.http-listener-1.property.cometSupport=true

Download the following jars and put it under $GLASSFISH_HOME/domains/domain1/lib:

  • grizzly-cometd-client-1.9.8.jar
  • cometd-bayeux-6.1.11.jar
  • jetty-6.1.11.jar
  • jetty-client-6.1.11.jar
  • jetty-util-6.1.11.jar
The first jar is from Grizzly repository. Note that you may like to get the correct Grizzly version working with your GlassFish v3. (For instance, one can find out the Grizzly version in MANIFEST.MF of web-glue.jar.) The remaining jars are from Jetty repository 6.1.11.

Finally, we have to start the server.

A Cometd client application using Jetty Bayeux client

In our example, we will create a web Bayeux Client for Cometd Chat Sample. It can be downloaded here.

One need to import Jetty's classes as follows:

    import org.mortbay.cometd.AbstractBayeux;
    import org.mortbay.cometd.client.BayeuxClient;
    import org.mortbay.jetty.client.HttpClient;
    import org.mortbay.thread.QueuedThreadPool;
    import org.mortbay.util.ajax.JSON;
    import dojox.cometd.Bayeux;
    import dojox.cometd.Client;
    import dojox.cometd.Message;
    import dojox.cometd.MessageListener;

Then one need to create a BayeuxClient in as follows:

  • Create a HttpClient.

        httpClient = new HttpClient();
        httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
        httpClient.setMaxConnectionsPerAddress(50);

  • Create a QueuedThreadPool for the HttpClient.

        QueuedThreadPool pool = new QueuedThreadPool();
        pool.setMaxThreads(50);
        pool.setDaemon(true);
        httpClient.setThreadPool(pool);

  • Start the HttpClient and create a BayeuxClient.

        httpClient.start();
        client = new BayeuxClient(httpClient, address, cometdUri) {
            public void deliver(Client from, Message message) {
                // do something
                super.deliver(from, message);
            }
        };

    where address is an InetSocketAddress and cometdUri is the cometd service uri.

  • Create a MessageListener for the BayeuxClient.

        MessageListener listener = new MessageListener() {
            public void deliver(Client fromClient, Client toClient, Message msg) {
                Object data = msg.get(AbstractBayeux.DATA_FIELD);
                if (data != null) {
                   // do something
               }
           }
        };
        client.addListener(listener);

    This listener is a no-op as we only use the client to send message in our case.

  • Start the BayeuxClient and subscribe the channel.

        client.start();
        client.subscribe(channel);

With the setup above, the JSON message can be published as follows:

    Object msg=new JSON.Literal("{\\"user\\":\\"" + name + "\\",\\"chat\\":\\"" + chat + "\\"}");
    client.publish(channel, msg, String.valueOf(mid.getAndIncrement()));

where msg is a JSON object associated to data.

Comparison with Java API for Bayeux Protocol

In this section, we will compare Jetty Bayeux client with the Java API for Bayeux Protocol. For convenience, I will summarize the Java API for Bayeux Protocol as follows:
  • Get the CometContext.

        CometEngine context = CometEngine.getEngine().getCometContext(channel);

  • Create the DeliverResponse.

        Map map = new HashMap();
        map.put(messageDataName, messageDataValue);
        Data data = new Data();
        data.setMapData(map);

        DeliverResponse deliverResponse = new DeliverResponse();
        deliverResponse.setChannel("/service/echo");
        deliverResponse.setClientId(clientId);
        deliverResponse.setData(data);
        deliverResponse.setLast(true);
        deliverResponse.setFollow(true);
        deliverResponse.setFinished(true);

    Note that in this moment, one has to setFinished(true) in addition to setLast(true).

  • Notify the deliverResponse

        context.notify(deliverResponse);

 Jetty Bayeux ClientJava API for Bayeux Protocol
Setupmore involvedsimple
Access Cometd Servicelocal and remotelocal
Clientin server and standlonein server
Construction of JSON messagessome explicitlyall use API

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.

Friday Sep 26, 2008

compression and compressionMinSize in GlassFish v3

In Enabling HTTP Compression in GlassFish, Jean-Francois discussed about compression in GlassFish. There are four properties to configure compression, namely:
  • compression
  • compressionMinSize (in OCTET)
  • compressableMimeType
  • noCompressionUserAgents
One can turn compression on and off by setting compression = force and compression = off respectively. And one can also turn on the compression if the content-length is unknown or known to be greater than a certain size. There are two properties related to this: compression and compressionMinSize. In this blog, we will discuss various ways to accomplish this scenario in GlassFish v3.

compression vs compressionMinSize

propertypossible value if setDefault
compressionon, force, off, integeroff
compressionMinSizeinteger2048

There are several possible combinations. We will summarize the behaviors of GlassFish v3 in the below table. In the following, α and β are integers.

compressioncompressionMinSizeResult
onβcompression with min size β
onnot setcompression with default min size (2048)
forceβ or not setcompression with no size constraint
αβ or not setcompression with min size α
off or not setβ or not setno compression

So, roughly speaking, whenever there is conflicting information between compression and compressionMinSize, the compression property will take precedence.

Since we use strict inequality to check for known content length, the following are equivalent:

  • compression = force
  • compression = on and compressionMinSize = any negative integer

How to test it?

If one has turned on compression in GlassFish, then one will get HTTP compression if the HTTP request is
  • using HTTP 1.1
  • with a HTTP header:
        Accept-Encoding: gzip
  • the content-length is unknown or greater than the compression minimum size
    (or compression = force)
One can confirm that there is a HTTP compression by using Firefox with Firebug. There will be a HTTP response header:
  • Content-Encoding: gzip
Note that one can also notice some changes in HTTP response for HTTP compression by using the http client posted in one of my previous blogs.

Thursday Aug 14, 2008

WEBDAV in GlassFish

WEBDAV (RFC 4918) protocol is a predecessor to HTTP/1.1 for management resources, etc. The WEBDAV code in GlassFish workspace is based on Tomcat. Jean-Francois blogged about this in 2006. WEBDAV Level 2 will be a supported feature in GlassFish v3. In this blog, we would provide additonal information about WEBDAV in GlassFish v3.

Configuration of WebDAVServlet

WEBDAV can be enabled by specifying the org.apache.catalina.servlets.WebdavServlet in web.xml for a given web application. Also, it can be enabled and configured globally in default-web.xml. One can configure WebDAVServlet by specifying the init-param as follows:

init-paramTypeDescriptionDefault
debugintdebug level0 (no debug)
listingsbooleanwhether one can list resourcesfalse
readonlybooleanwhether resources are readonlytrue

It is important to note that when listings is set to true or readonly is set to false, one must set up security constraints and turn on security manager.

WEBDAV Clients

I have verified that the following WEBDAV clients work with GlassFish v3:
  • Microsoft Word 2002 and 2003
      File > Open > the url
  • Internet Explorer 6 and 7
      File > Open (check "Open as Web Folder") > the url
    Note that under "Internet Options > Programs > HTML editor", we may like to set it to Microsoft Word above or Mircrosoft FrontPage.

Hand-On Examples on WEBDAV protocol

WEBDAV includes the following HTTP methods:
  • PROPFIND
  • PROPMATCH
  • MKCOL
  • GET
  • HEAD
  • POST
  • DELETE
  • PUT
  • COPY
  • MOVE
  • LOCK
  • UNLOCK
I find that it is a good exercise to send HTTP requests directly and see what happens there. For instance,
  • the following HTTP request copy index.html to index2.html:
    COPY /webdavtest/index.html HTTP/1.1
    Host: localhost
    Destination: http://localhost:8080/webdavtest/index2.html
    Connection: close
    
    
  • the following HTTP request delete the index2.html created above:
    DELETE /webdavtest/index2.html HTTP/1.1
    Host: localhost
    Connection: close
    
    
There are many ways to send http client requests to server. I find that it is quite handy to have the following Ruby script.


  #!/usr/bin/ruby
  
  require "socket"

  if ARGV.length != 3
      puts "ruby httpclient.rb <host> <port> <http request file>\\n"
      exit
  end

  host = ARGV[0];
  port = ARGV[1].to_i;
  filename = ARGV[2];

  socket = TCPSocket.open(host, port)

  file = File.new(filename)
  while line = file.gets
      command = line.chomp
      puts command + "\\r\\n"
      socket.write(command + "\\r\\n")
  end

  puts socket.readlines

  socket.close

Note that you may like to update the path of ruby or run the interpretator directly.

Tuesday Jul 15, 2008

Common Gateway Interface in GlassFish

Common Gateway Interface (CGI) supports dynamic contents in web environment. CGI programs are executable programs in the server platform with specific output. It can be a Bourne shell script, Perl script or even a C binary executable. It was very popular before the the appearance of Servlet, JSP and PHP. The CGI code in GlassFish workspace is based on Tomcat. In GlassFish v3, CGI will be a supported feature. Let us look at a very simple example.

Create a CGI script

In our example, we have a simple Perl program, hello, to print a hello message and the timestamp of the server.

    #!/bin/perl
    print "Content-type: text/html\n\n";
    print "Hello World: ";
    print scalar localtime;
    print "\n";

Enabling CGI processing and packaging the war file

The CGI processing can be enabled in a war file by adding CGIServlet et al in web.xml as follows:

  <web-app>
    <servlet>
      <servlet-name>cgi</servlet-name>
      <servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>cgi</servlet-name>
      <url-pattern>/cgi-bin/*</url-pattern>
    </servlet-mapping>
  </web-app>

In this case, one need to package the hello under the default cgiPathPrefix which is WEB-INF/cgi. For security, it is highly recommended that the contents / binaries of CGI programs should be prohibited from direct viewing or download.

Alternatively, one can enable CGI by uncommenting the corresponding sections in default-web.xml.

In our case, the CGI program can be invoked through http://localhost:8080/YOUR_CONTEXT/cgi-bin/hello .

Configuration of CGIServlet

One can configure CGIServlet by specifying the init-param as follows:

init-paramTypeDescriptionDefault
cgiPathPrefixStringsubdirectory containing the cgi programsWEB-INF/cgi
debugintdebug level0 (no debug)
executableStringexecutable for running the CGI scriptperl
parameterEncodingStringencoding use for parameterSystem.getProperty("file.encoding", "UTF-8")
passShellEnvironmentbooleanwhether to pass environment properties to CGI programfalse

CGI with native executables

GlassFish v3 CGI can work with native executables as follows:

  • set the init-param with name executable to be the empty String in web.xml
  • has exploded directory structure for the war in a directory, say /export/cgitest
  • make sure those executables has the executable bits set correctly
  • deploy the "directory" (not the "war"), for instance
    asadmin deploy /export/cgitest
Note that one works with the exploded directory structure rather than war file as the executable bits information is lost during the process of jar and unjar.

Friday Jul 11, 2008

Server Side Include in GlassFish

Server Side Include (SSI) allows including dynamic contents in html. SSI and CGI were very popular before the the appearance of JSP and PHP. The SSI code in GlassFish workspace is based on Tomcat. In GlassFish v3, SSI will be a supported feature. Let us look at a very simple example.

Create a SSI file

In our example, we create a index.shtml which
  • includes the content of header.html,
  • prints a Hello message with server side timestamp, and
  • executes a command say, uname (or any command in your operating system).
The page is as follows:

    <!--#include virtual="header.html"-->
    <br>Hello, it is <!--#echo var="DATE_LOCAL"-->.
    <br>Result: <!--#exec cmd="uname"-->

Note that the extension shtml is configurable in web.xml (see servlet-mapping below).

Enable SSI processing

The SSI processing can be enabled in a war file by adding SSIServlet et al in web.xml as follows:

  <web-app>
    <servlet>
      <servlet-name>ssi</servlet-name>
      <servlet-class>org.apache.catalina.ssi.SSIServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>ssi</servlet-name>
      <url-pattern>*.shtml</url-pattern>
    </servlet-mapping>

    <mime-mapping>
      <extension>shtml</extension>
      <mime-type>text/html</mime-type>
    </mime-mapping>
  </web-app>

One can find more details about the configuration of SSIServlet in the section below. Alternatively, one can enable SSI by uncommenting the corresponding sections in default-web.xml.

Note that the mime-mapping is to notify the browser that the result of shtml file is of content-type: text/html. If you don't specify this, then GlassFish will try to get the mime-type from default-web.xml or the default in the system.

Configuration of SSIServlet

One can configure SSIServlet by specifying the init-param as follows:

init-paramTypeDescriptionDefault
bufferedboolean (or String converted to boolean)whether the output should be bufferedfalse
debugintrepresents debug level0 (no debug)
expiresLongexpiration time in secondsdo not set "Expires" header in Http Response
inputEncodingStringencoding for SSI input if there is no URL content encoding specifiedserver platform encoding
isVirtualWebappRelativeboolean (or String converted to boolean)whether the "virtual" path of "#include" directive is relative to content-rootfalse (means relative to the given SSI file)
outputEncodingStringencoding for SSI outputUTF-8

Friday May 02, 2008

Java API for Bayeux Protocol

In Cometd environment, one communicates through Bayeux Protocol. The protocol is currently in 1.0 draft 1. GlassFish v3 has incorporated implementation of Bayeux from Grizzly. Jean Francois already has several good blogs on Cometd on Grizzly. In this blog, we are going to illustrate how to send a Bayeux message to a Cometd client by using Java API without writing any JSON code.

Basic set up

Download GlassFish v3 from GlassFish website. And add the following property to your http-listener in domain.xml as follows:

    <property name="cometSupport" value="true"/>

Start the server by "one" of the following:

  1. asadmin start-domain domain1
  2. java -jar glassfish-10.0-SNAPSHOT.jar

One also need a Cometd web application. In this blog, we will use the grizzly-cometd-echo sample. Just download the war file and deploy as follows:

    asadmin deploy grizzly-cometd-echo-1.7.3.2.war

Generate a Bayeux Message

In our example, we will generate a cometd message in a servlet, TestServlet.java. The cometdmsgtest.war file and source codes are available here.

  • As usual, one can get a CometContext as follows:

        CometEngine engine = CometEngine.getEngine();
        CometContext context = engine.getCometContext(contextPath);

    In our case, the contextPath is "/cometd/cometd" where the first "/cometd" is context root of the grizzly-cometd-echo.

  • One construct a Bayeux response message by using classes in package com.sun.grizzly.cometd.bayeux. The classes that we need to use are DeliverResponse and Data. It is constructed as follows:

        Map map = new HashMap();
        map.put(messageDataName, messageDataValue);
        Data data = new Data();
        data.setMapData(map);

        DeliverResponse deliverResponse = new DeliverResponse();
        deliverResponse.setChannel("/service/echo");
        //deliverResponse.setClientId("");
        deliverResponse.setData(data);
        deliverResponse.setLast(true);
        deliverResponse.setFollow(true);

    Note that

    • "/service/echo" is the channel name of grizzly-cometd-echo sample.
    • If one is not using an updated version of GlassFish, then one may need to call deliverResponse.setClientId("") to workaround a bug.
    • deliverResponse.setLast(true) indicates that this is the last Bayeux message in this Http response.
    • deliverResponse.setFollow(true) indicates that this is not the first Bayeux message in this Http response. In our case, the previous message is /meta/connect.

    Then one can send the Bayeux message as follows:

        context.notify(deliverResponse);

How to run the test

  • Use browser A1 to access the grizzly sample application by http://localhost:8080/cometd. One can type a message on the text box and see that it is echoed through Bayeux protocol.
  • Repeat the above in browser A2.
  • Use browser B to access the cometd message application by http://localhost:8080/cometdmsgtest. One can type a message in the text box and see that it appears in browser A1 and browser A2.
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