Table of Contents
Jetty supports java:comp/env lookups in web apps. This is an optional feature for which you need
to do some setup. However, if you are using the Hightide distribution of Jetty,
this feature is already fully enabled, so you can skip any setup steps, and just read the sections on how to put
objects into Jetty JNDI so that you can retrieve them at runtime.
If you are using the standard distribution of jetty, and want to enable JNDI for all your webapps, complete the steps in this section. If you need a more selective configuration, see Detailed Setup.
Edit the $JETTY_HOME/start.ini file.
Modify the Server OPTIONS to include plus, for example:
OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus
Near the bottom of the file, in the section on Configuration files, add the following line after
etc/jetty.xml:
etc/jetty-plus.xml
Save the file.
You can now start Jetty and use JNDI with your webapps. See the next section for information on how to add entries to the JNDI environment that Jetty can look up within webapps.
The following sections describe the fine points of configuring JNDI.
When deploying a webapp, Jetty has an extensible list of configurations that it applies to the webapp
in a specific order. These configurations do things like parse web.xml, set up the classpath
for the webapp, and parse WEB-INF/jetty-web.xml.
To use JNDI with Jetty, you need additional attributes that do things like read
WEB-INF/jetty-env.xml, set up a java:comp/env context, and hook up JNDI entries from the
environment into your webapp. The list below shows the two extra elements and the order you must use when you add
them:
<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> <!-- add for jndi --> <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item> <!-- add for jndi --> <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item> <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item> <!-- not needed for jetty-8 --> </Array>
This augmented list of Configurations for JNDI is predefined for you in the
etc/jetty-plus.xml file.
To have jetty use etc/jetty-plus.xml and therefore to enable JNDI for all webapps, edit the
$JETTY_HOME/start.ini file, and add the following line in the Configuration section near the bottom
of the file:
etc/jetty-plus.xml
Now skip down to the section, Adding JNDI Implementation Jars to the Jetty Classpath.
If you only want to use JNDI with specific webapps, read on.
If you have only a few webapps that you want to use with JNDI, you can apply the augmented list of configurations specifically to those webapps. To do that, create a context xml file for each webapp, and set up the configuration classes. Here's an example of how that should look:
<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> <!-- add for JNDI --> <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item> <!-- add for JNDI --> <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 you're ready for the next step, which is to put the JNDI Jars onto the jetty classpath, described in the next section, Adding JNDI Implementation Jars to the Jetty Classpath.
Now that you have the JNDI configuration for the webapp(s) set up, you need to ensure that the JNDI implementation Jars are on the Jetty classpath. These jars are optional, so are not there by default. You add these into the classpath by using startup time OPTIONS.
One way to do this is to supply it on the command line like so:
java -jar start.jar OPTIONS=plus
Another, more permanent way of doing this is to edit the $JETTY_HOME/start.ini file
and modify the OPTIONS section to include "plus":
OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus
You can now configure naming resources to reference in a web.xml file and access from within the
java:comp/env naming environment of the webapp during execution. Specifically, you can configure
support for the following web.xml elements:
env-entry/
resource-ref/
resource-env-ref/
Notice that Configuring env-entriesshows you how to set up overrides for
env-entry elements in web.xml, while Configuring resource-refs and resource-env-refsdiscusses how to configure support resources such as
javax.sql.DataSource.
You can also plug a JTA javax.transaction.UserTransaction implementation into Jetty so that
webapps can look up java:comp/UserTransaction to obtain a distributed transaction manager. See Configuring XA Transactions.
You can define your naming resources with three scopes:
jvm scope–the name is unique within the JVM.
server scope–the name is unique to the Server instance.
webapp scope–the name is unique to the WebAppContext instance.
See Setting JNDI Entries as Global or Scoped, which explains scoping, and shows you how to use it. Essentially, scoping ensures that JNDI bindings from one webapp do not interfere with the JNDI bindings of another–unless of course you want them to.
You can bind four types of object into Jetty JNDI:
An ordinary POJO instance.
A javax.naming.Reference instance.
An object instance that implements the javax.naming.Referenceable interface.
A link between a name as referenced in web.xml and as referenced in the
environment.
The binding for all of these object types follows the same pattern:
<New class=type of naming entry> <Arg>scope</Arg> <Arg>name to bind as</Arg> <Arg>the object to bind</Arg> </New>
The type of naming entry can be:
org.eclipse.jetty.plus.jndi.EnvEntry for env-entry.
org.eclipse.jetty.plus.jndi.Resource for all other type of resources.
org.eclipse.jetty.plus.jndi.Transaction for a JTA manager. For detailed information, see
the Configuring XA Transactions.
org.eclipse.jetty.plus.jndi.Link for link between a
web.xml resource name and a amingEntry.
For more information, see Configuring Links.
You can define naming entries in three places:
jetty.xml
WEB-INF/jetty-env.xml
context xml file
Naming entries defined in a jetty.xml file are scoped at either the JVM level or the
Server level. Naming entries in a jetty-env.xml file are scoped to the web app in which
the file resides. While you can enter JVM or Server scopes if you choose, we do not recommend doing so. In most
cases you define all naming entries that you want visible to a particular Server instance, or to the JVM as a
whole in a jetty.xml file. Entries in a context xml file are scoped at the level of the
webapp to which they apply, although once again, you can supply a less strict scoping level of Server or JVM if
you choose.
Sometimes it is useful to pass configuration information to a webapp at runtime that you either cannot or
cannot conveniently code into a web.xml env-entry. In such cases, you can use
org.eclipse.jetty.plus.jndi.EnvEntry, and even override an entry of the same name in
web.xml.
<New class="org.eclipse.jetty.plus.jndi.EnvEntry"> <Arg></Arg> <Arg>mySpecialValue</Arg> <Arg type="java.lang.Integer">4000</Arg> <Arg type="boolean">true</Arg> </New>
This example defines a virtual env-entry called mySpecialValue with value
4000 that is unique within the whole JVM. It is put into JNDI at
java:comp/env/mySpecialValue for every web app deployed. Moreover, the boolean
argument indicates that this value overrides an env-entry of the same name in
web.xml. If you don't want to override, then omit this argument, or set it to false.
See Setting JNDI Entries as Global or Scopedfor information on other scopes.
The Servlet Specification allows binding only the following object types to an
env-entry:
However, Jetty is a little more flexible and allows you to also bind custom POJOs, javax.naming.References and javax.naming.Referenceables. Be aware that if you take advantage of this feature, your web application is not portable.
To use the env-entry configured above, use code in your servlet/filter/etc., such as:
import javax.naming.InitialContext;
InitialContext ic = new InitialContext();
Integer mySpecialValue = (Integer)ic.lookup("java:comp/env/mySpecialValue");
You can configure any type of resource that you want to refer to in a web.xml file as a
resource-ref or resource-env-ref, using the
org.eclipse.jetty.plus.jndi.Resource type of naming entry. You provide the scope, the name of the object
(relative to java:comp/env) and a POJO instance or a javax.naming.Reference instance
or javax.naming.Referenceable instance.
The J2EE
Specification recommends that DataSources be stored in java:comp/env/jdbc, JMS connection
factories under java:comp/env/jms, JavaMail connection factories under
java:comp/env/mail and URL connection factories under java:comp/env/url. For
example:
Table 12.1. Storing DataSources
| Resource Type | Name in jetty.xml | Environment Lookup |
|---|---|---|
| javax.sql.DataSource | jdbc/myDB | java:comp/env/jdbc/myDB |
| javax.jms.QueueConnectionFactory | jms/myQueue | java:comp/env/jms/myQueue |
| javax.mail.Session | mail/myMailService | java:comp/env/mail/myMailService |
Here is an example of configuring a javax.sql.DataSource. Jetty can use any DataSource
implementation available on its classpath. In this example, the DataSource is from the Derby relational database, but you can use any implementation of a
javax.sql.DataSource. This example configures it as scoped to a web app with the id of
wac:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> ... <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id="wac"/></Arg> <Arg>jdbc/myds</Arg> <Arg> <New class="org.apache.derby.jdbc.EmbeddedDataSource"> <Set name="DatabaseName">test</Set> <Set name="createDatabase">create</Set> </New> </Arg> </New> </Configure>
The code above creates an instance of org.apache.derby.jdbc.EmbeddedDataSource, calls the
two setter methods setDatabaseName("test"), and setCreateDatabase("create"), and
binds it into the JNDI scope for the web app. If you do not have the appropriate resource-ref set
up in your web.xml, it is available from application lookups as
java:comp/env/jdbc/myds.
Here's an example web.xml declaration for the datasource above:
<resource-ref>
<res-ref-name>jdbc/myds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
To look up your DataSource in your servlet/filter/etc.:
import javax.naming.InitialContext;
import javax.sql.DataSource;
InitialContext ic = new InitialContext();
DataSource myDS = (DataSource)ic.lookup("java:comp/env/jdbc/myds");
java:comp/env. For database connection factories, this means that
the object you register as a Resource must implement the
javax.sql.DataSource interface.For more examples of datasource configurations, see JNDI Datasource Examples.
Jetty can bind any implementation of the JMS destinations and connection factories. You just need to ensure the implementation Jars are available on Jetty's classpath. Here is an example of binding an ActiveMQ in JVM connection factory:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> ... <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id='wac'/></Arg> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New> </Configure>
For more information, see ActiveMQ.
Jetty also provides infrastructure for access to javax.mail.Sessions from within an
application:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> ... <New id="mail" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id="wac"/></Arg> <Arg>mail/Session</Arg> <Arg> <New class="org.eclipse.jetty.jndi.factories.MailSessionReference"> <Set name="user">fred</Set> <Set name="password">OBF:1xmk1w261z0f1w1c1xmq</Set> <Set name="properties"> <New class="java.util.Properties"> <Put name="mail.smtp.host">XXX</Put> <Put name="mail.from">me@me</Put> <Put name="mail.debug">true</Put> </New> </Set> </New> </Arg> </New> </Configure>
The setup above creates an instance of the
org.eclipse.jetty.jndi.factories.MailSessionReference class, calls its setter methods
setUser("fred");, setPassword("OBF:1xmk1w261z0f1w1c1xmq"); to set up the authentication for
the mail system, and populates a set of Properties, setting them on the
MailSessionReference instance. The result is that an application can look up
java:comp/env/mail/Session at runtime and obtain access to a javax.mail.Session that has
the necessary configuration to permit it to send email via SMTP.
If you want to perform distributed transactions with your resources, you need a transaction
manager that supports the JTA interfaces that you can look up as
java:comp/UserTransaction in your webapp. Jetty does not ship with one as standard, but you can plug in
the one you prefer. You can configure a transaction manager using the JNDI Transaction object in a Jetty config
file. The following example configures the Atomikos transaction manager:
<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction"> <Arg> <New class="com.atomikos.icatch.jta.J2eeUserTransaction"/> </Arg> </New>
You can also use the Hightide distribution of jetty instead, which comes with the Atomikos transaction system pre-configured.
The name you set for your NamingEntry should be the same name you use for it in
web.xml. For example:
In a context xml file:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> ... <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id="wac"/></Arg> <Arg>jdbc/mydatasource</Arg> <Arg> <New class="org.apache.derby.jdbc.EmbeddedDataSource"> <Set name="DatabaseName">test</Set> <Set name="createDatabase">create</Set> </New> </Arg> </New> </Configure>
In web.xml:
<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.JNDITest</injection-target-class>
<injection-target-name>myDatasource</injection-target-name>
</injection-target>
</resource-ref>
You can refer to it in web.xml by a different name, and link it to the name in your
org.eclipse.jetty.plus.jndi.Resource by using an org.eclipse.jetty.plus.jndi.Link type of
NamingEntry. For the example above, you can refer to the jdbc/mydatasource resource as
jdbc/mydatasource1 as follows:
In a context xml file:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> ... <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id="wac"/></Arg> <Arg>jdbc/mydatasource</Arg> <Arg> <New class="org.apache.derby.jdbc.EmbeddedDataSource"> <Set name="DatabaseName">test</Set> <Set name="createDatabase">create</Set> </New> </Arg> </New> </Configure>
In a jetty-env.xml file:
<New id="map1" class="org.eclipse.jetty.plus.jndi.Link"> <Arg><Ref id='wac'/></Arg> <Arg>jdbc/mydatasource1</Arg> <!-- name in web.xml --> <Arg>jdbc/mydatasource</Arg> <!-- name in container environment --> </New>
And in web.xml:
<resource-ref>
<res-ref-name>jdbc/mydatasource1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<injection-target>
<injection-target-class>com.acme.JNDITest</injection-target-class>
<injection-target-name>myDatasource</injection-target-name>
</injection-target>
</resource-ref>
This can be useful when you cannot change web.xml but need to link it to a resource
in your deployment environment.
As previously stated, you can control the visibility of your JNDI naming entries within your JVM, Server
and WebAppContext instances. Naming entries at the jvm scope are visible by any application code, and are
available to bind to java:comp/env. Naming entries at the Server scope do not interfere with entries
of the same name in a different Server instance, and are available to bind to java:comp/env of any
web apps deployed to that Server instance. Finally, the most specific scope are entries at the webapp scope. An
entry of this type is only available to bind to java:comp/env of the web app in which it is
defined.
The first parameter to the NamingEntry controls the scope.
The jvm scope is represented by a null parameter:
<New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg></Arg> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New>
The Server scope is represented by referencing the related Server object:
<Configure id="Server" class="org.eclipse.jetty.Server"> ... <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id="Server"/></Arg> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New> </Configure>
The webapp scope is represented by referencing the related WebAppContext object:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> ... <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref id='wac'/></Arg> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New> </Configure>
As you can see, the most natural configuration files in which to declare naming entries of each scope are:
etc/jetty.xml file–jvm or Server scope>WEB-INF/jetty-env.xml file or a context xml file–webapp
scope