Category: GWT

  • GWT and JNDI

    Many folks want to use some features beyond the bare servlet basics with GWT, such as JNDI lookups. It’s not hard to set up, but there are a couple of steps to it so here’s a detailed guide.
    Since GWT switched to using Jetty for its hosted mode (also known as development mode) back at GWT 1.6, lots of people have been asking how to use features such as JNDI lookups in their webapps.  Several people have posted helpful instructions, perhaps the best of them being from Nicolas Wetzel in this thread on Google Groups, and from Henning on his blog (in German).
    In this blog post, we’ll put all these instructions together in the one place, and give you a couple of projects you can download to get you started faster. You might want to skip down to the downloadable projects.

    Customizing the GWT Launcher

    The first step is to customize the JettyLauncher provided by GWT.  Unfortunately, at the time of writing (GWT2.3.0) you cannot customize by extension due to the use of final inner classes and private constructors. Therefore, you will need to copy and paste the entire class in order to make the necessary and trivial modifications to enable JNDI.
    You can find the source of the JettyLauncher.java class inside the gwt-dev.jar in your local installation of the GWT SDK.  Here’s a link to the jar from Maven Central Repository for convenience: gwt-dev-2.3.0.jar.  Unjar it, and copy the com/google/gwt/dev/shell/jetty/JettyLauncher.java class to a new location and name.
    Edit your new class and paste in this declaration:

    public static final String[] DEFAULT_CONFIG_CLASSES =
    {
        "org.mortbay.jetty.webapp.WebInfConfiguration",    //init webapp structure
        "org.mortbay.jetty.plus.webapp.EnvConfiguration",  //process jetty-env
        "org.mortbay.jetty.plus.webapp.Configuration",     //process web.xml
        "org.mortbay.jetty.webapp.JettyWebXmlConfiguration",//process jetty-web.xml
    };

    This declaration tells Jetty to setup JNDI for your web app and process the various xml files concerned.  Nearly done now. All you need to do is now apply these Configuration classes to the WebAppContext that represents your web app. Find the line that creates the WebAppContext:

    WebAppContext wac = createWebAppContext(logger, appRootDir);

    Now, add this line straight afterwards:

    wac.setConfigurationClasses(DEFAULT_CONFIG_CLASSES);

    Build your new class and you’re done. To save you some time, here’s a small project with the class modifications already done for you (variants for Ant and Maven):

    Modifying your Web App

    Step 1

    Add the extra jetty jars that implement JDNI lookups to your web app’s WEB-INF/lib directory. Here’s the links to version 6.1.26 of these jars – these have been tested against GWT 2.3.0 and will work, even though GWT is using a much older version of jetty (6.1.11?):

    Step 2

    Now you can create a WEB-INF/jetty-env.xml file to define the resources that you want to link into your web.xml file, and lookup at runtime with JNDI.
    That’s it, you’re good to go with runtime JNDI lookups in GWT hosted mode. Your webapp should also be able to run without modification when deployed into standalone Jetty. If you deploy to a different container (huh?!), then you’ll need to define the JNDI resources appropriately for that container (but you can leave WEB-INF/jetty-env.xml in place and it will be ignored).

    If You’re Not Sure How To Define JNDI Resources For Jetty…

    The Jetty 6 Wiki contains instructions on how to do his, but here’s a short example that defines a MySQL datasource:
    In WEB-INF/jetty-env.xml:

    <New id="DSTest" class="org.mortbay.jetty.plus.naming.Resource">
        <Arg>jdbc/DSTest</Arg>
        <Arg>
         <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
           <Set name="Url">jdbc:mysql://localhost:3306/databasename</Set>
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
         </New>
        </Arg>
    </New>

    Now link this into your web app with a corresponding entry in your WEB-INF/web.xml:

    <resource-ref>
        <description>My DataSource Reference</description>
        <res-ref-name>jdbc/DSTest</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

    Of course, you will also need to copy any jars required by your resources – in this case the MySQL jar – into your WEB-INF/lib.
    You can then lookup the JNDI resource inside your servlet, filter etc:

    import javax.naming.InitialContext;
    import javax.sql.DataSource;
    InitialContext ic = new InitialContext();
    DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/DSTest");
    

    An Example WebApp

    An example usually helps, so I’ve put together a silly, tiny webapp that does a JNDI lookup. It is based on the standard GWT “Hello World” webapp that is generated by default by the GWT webAppCreator script. This webapp does an RPC call to a servlet to get a message incorporating the name entered by the user. I’ve simply modified the message that is returned to also include an extra sentence obtained by doing a java:com/env lookup.
    Here’s my WEB-INF/jetty-env.xml:

    <Configure id='wac' class="org.mortbay.jetty.webapp.WebAppContext">
      <!-- An example EnvEntry that acts like it was defined in web.xml as an env-entry -->
      <New class="org.mortbay.jetty.plus.naming.EnvEntry">
        <Arg>msg</Arg>
        <Arg type="java.lang.String">A bird in the hand is worth 2 in the bush </Arg>
        <Arg type="boolean">true</Arg>
      </New>
    

    This defines the equivalent of an <env-entry> outside of web.xml. In fact, the boolean argument set to “true” means that it would override the value of an <env-entry> of the same name inside WEB-INF/web.xml. This is actually most useful when used in a Jetty context xml file for the webapp instead of WEB-INF/jetty-env.xml, as it would allow you to define a default value inside WEB-INF/web.xml and then customize for each deployment in the context xml file (which is external to the webapp). For this example, we could have just as well defined the <env-entry> in WEB-INF/web.xml instead, but I wanted to show you a WEB-INF/jetty-env.xml file so you have an example of where to define your resources.
    Here’s the extra code that does the lookup inside of GreetingServletImpl.java:

      private String lookupMessage (String user) {
        try {
            InitialContext ic = new InitialContext();
            String message = (String)ic.lookup("java:comp/env/msg");
            return message +" "+user;
        } catch (Exception e) {
            return e.getMessage();
        }
      }
    

    Running the built project in hosted mode and hitting the url http://127.0.0.1:8888/HelloJNDI.html?gwt.codesvr=127.0.0.1:9997 I see:
    Screen shot of webapp in action.
    Here’s an Ant project for this trivial webapp: HelloJNDI

    1. edit the build.xml file to change the property gwt.sdk to where you have the GWT SDK locally installed.
    2. build and run it in hosted mode with: ant devmode
    3. follow the hosted mode instructions to cut and paste the url into your browser

    Resource Listing