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):
- GWTJettyPlusLauncher (ant)
Build with:ant build
. - GWTJettyPlusLauncher (mvn)
Build with:mvn install
.
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:
Here’s an Ant project for this trivial webapp: HelloJNDI
- edit the
build.xml
file to change the propertygwt.sdk
to where you have the GWT SDK locally installed. - build and run it in hosted mode with:
ant devmode
- follow the hosted mode instructions to cut and paste the url into your browser
12 Comments
swi · 06/09/2011 at 13:52
Hi,
i’m following you “Example WebApp”-howto. But it didn’t work for me.
The lookupMessage replays “null” and i don’t know why…
What you are make with the make with the GWTJettyPlusLauncher ? Must i add it to the libs? (I’m using eclipse with maven)
Greetz swi
Tadashi · 04/08/2012 at 07:53
Here is the Maven profile you need: jetty-alternateport org.mortbay.jetty jetty-maven-plugin ${jetty-version} 8081 18080 The stopPort is optional but I added in case you have two Maven jetty:run’s running at the same time on the same machine, the stopPort needs to be set to something other than the default on one of them.
Kathir · 07/09/2011 at 00:25
HI,
Nice article. Is it also possible to customize the java agent property for jetty. My application uses load time weaving and i have to pass javaagent argument during the gwt application startup. But the javaagent argument is ignored when i launch it.
David Parish · 02/10/2011 at 18:14
There is a missing step here. How do I tell GWT to use a different launcher? The easy way is just to replace their stock class with the modified class, but from your example (GWTJettPlusLauncher), I can tell there must be a way to specify a different launcher.
David Parish · 02/10/2011 at 18:37
I fixed this.To use the new launcher, modify your run configuration. In the arguments tab add:
-server org.mortbay.gwt.GWTJettyPlusLauncher
David Parish · 02/10/2011 at 18:52
I’m still missing something. I get a failure on startup:
[WARN] Failed startup of context org.mortbay.gwt.GWTJettyPlusLauncher$WebAppContextWithReload@16a799c1{/,C:Usersdparishworkspaceretainwar}
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.lookup(Unknown Source)
at org.mortbay.jetty.plus.webapp.EnvConfiguration.createEnvContext(EnvConfiguration.java:57)
at org.mortbay.jetty.plus.webapp.EnvConfiguration.configureDefaults(EnvConfiguration.java:101)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1200)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at org.mortbay.gwt.GWTJettyPlusLauncher$WebAppContextWithReload.doStart(GWTJettyPlusLauncher.java:476)
Debugging through the jetty code, it’s failing here:
compCtx = (Context)context.lookup (“java:comp”);
janb · 02/10/2011 at 23:41
David,
Check that you have the jetty-naming-6.1-SNAPSHOT.jar and jetty-plus-6.1-SNAPSHOT.jar in your WEB-INF/lib. Note that you can’t put them onto the classpath of the jvm that executes com.google.gwt.dev.DevMode (ie launches the launcher) because the google code makes the boot classloader the parent of jetty’s classloader, so there is no access to jars on the system classpath.
regards
Jan
Kiran · 19/10/2011 at 17:41
I followed the steps but its not working for me. When GWT hosted mod starts, I get a warning and then everything stops
[WARN] Configuration problem at
jdbc/myDS
javax.sql.DataSource
Container
java.lang.IllegalStateException: Nothing to bind for name javax.sql.DataSource/default
at org.mortbay.jetty.plus.webapp.Configuration.bindEntry(Configuration.java:259)
at org.mortbay.jetty.plus.webapp.Configuration.bindResourceRef(Configuration.java:98) at org.mortbay.jetty.plus.webapp.AbstractConfiguration.initResourceRef(AbstractConfiguration.java:262) at org.mortbay.jetty.plus.webapp.AbstractConfiguration.initWebXmlElement(AbstractConfiguration.java:161) at org.mortbay.jetty.webapp.WebXmlConfiguration.initialize(WebXmlConfiguration.java:289) at org.mortbay.jetty.plus.webapp.AbstractConfiguration.initialize(AbstractConfiguration.java:133) at org.mortbay.jetty.webapp.WebXmlConfiguration.configure(WebXmlConfiguration.java:222) at org.mortbay.jetty.plus.webapp.AbstractConfiguration.configure(AbstractConfiguration.java:113) at org.mortbay.jetty.webapp.WebXmlConfiguration.configureWebApp(WebXmlConfiguration.java:180) at org.mortbay.jetty.plus.webapp.AbstractConfiguration.configureWebApp(AbstractConfiguration.java:96) at org.mortbay.jetty.plus.webapp.Configuration.configureWebApp(Configuration.java:149) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1217) at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513) at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448) at org.mortbay.gwt.GWTJettyPlusLauncher$WebAppContextWithReload.doStart(GWTJettyPlusLauncher.java:475)
janb · 19/10/2011 at 23:19
Kiran, in web.xml cannot be found anywhere in the environment. Are you sure you have defined a Resource in WEB-INF/jetty-env.xml? Compare your project to the one in the HelloJNDI example might help.
This means that the name that is configured in the
cheers
Jan
Rastaman · 29/12/2012 at 11:22
Hi,
Thanks for the article, for the JNDI problem i had to add somewhere in the class :
static {
// Configure JNDI to use Jetty resolver
System.setProperty(“java.naming.factory.url.pkgs”,”org.mortbay.naming”);
System.setProperty(“java.naming.factory.initial”,”org.mortbay.naming.InitialContextFactory”);
}
HTH,
Ludo
GWT and JNDI | Eclipse | Syngu · 31/08/2011 at 05:35
[…] switched to using Jetty for its hosted mode (also known as development mode) back at GWT 1.6,… Read more… Categories: Eclipse Share | Related […]
GWT, Jetty, JNDI and Microsoft SQL Server: issue with getConnection | DIGG LINK · 17/02/2012 at 12:28
[…] information in a JNDI configuration file. Since the server GWT uses is Jetty, I have followed this tutorial which allows me to get some information from my jetty-web.xml and my web.xml under the war/WEB-INF […]
Comments are closed.