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-entries
shows you how to set up overrides for
env-entry
elements in web.xml
, while Configuring resource-refs
and resource-env-refs
discusses 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 Scoped for 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 11.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