private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ... scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery
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 scoped to the 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, omit this
argument, or set it to false
.
The Servlet Specification allows binding only the following object
types to an env-entry
:
java.lang.String
java.lang.Integer
java.lang.Float
java.lang.Double
java.lang.Long
java.lang.Short
java.lang.Character
java.lang.Byte
java.lang.Boolean
That being said, 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; public class MyClass { public void myMethod() { 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 storing DataSources 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. DataSource Declaration Conventions
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 refid="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; public class MyClass { public void myMethod() { InitialContext ic = new InitialContext(); DataSource myDS = (DataSource)ic.lookup("java:comp/env/jdbc/myds"); ... } }
Careful! When configuring Resources, ensure that the type of
object you configure matches the type of object you expect to look up in
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 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 refid='wac'/></Arg> <Arg>jms/connectionFactory</Arg> <Arg> <New class="org.apache.activemq.ActiveMQConnectionFactory"> <Arg>vm://localhost?broker.persistent=false</Arg> </New> </Arg> </New> </Configure>
The entry in web.xml
would be:
<resource-ref> <res-ref-name>jms/connectionFactory</res-ref-name> <res-type>javax.jms.ConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref>
TODO: put in an example of a QUEUE from progress demo
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 refid="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>
This setup creates an instance of the
org.eclipse.jetty.jndi.factories.MailSessionReference
class, calls
its setter methods 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.
You can set the password to be plain text, or use Jetty's Secure Password Obfuscation (OBF:) mechanism to make the config file a little more secure from prying eyes. Remember that you cannot use the other Jetty encryption mechanisms of MD5 and Crypt because they do not allow you to recover the original password, which the mail system requires.
If you want to perform distributed transactions with your resources,
you need a transaction manager that supports the JTA
interfaces, and 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>
Generally, the name you set for your Resource
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 refid="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>
However, 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
. For the example above, you
can refer to the jdbc/mydatasource
resource as
jdbc/mydatasource1
as follows:
In a context xml file declare jdbc/mydatasource
:
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg><Ref refid="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>
Then in a WEB-INF/jetty-env.xml
file, link the
name jdbc/mydatasource
to the name you want to reference it
as in web.xml
, which in this case is
jdbc/mydatasource1
:
<New id="map1" class="org.eclipse.jetty.plus.jndi.Link"> <Arg><Ref refid='wac'/></Arg> <Arg>jdbc/mydatasource1</Arg> <!-- name in web.xml --> <Arg>jdbc/mydatasource</Arg> <!-- name in container environment --> </New>
Now you can refer to jdbc/mydatasource1
in the
web.xml
like this:
<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 a JNDI resource directly in
the web.xml
but need to link it to a specific
resource in your deployment environment.
See an error or something missing? Contribute to this documentation at Github!