<s1 title="JNDI: Resource Configuration">

<summarylist/>

<p>Applications can store factory objects and configuration variables
in a global naming tree using the JNDI API.    JNDI, the Java Naming and
Directory Interface, provides a global memory tree to store and lookup
configuration objects.  JNDI will typically contain configured Factory
objects.</p>

<p>JNDI lets applications cleanly separate configuration from the
implementation.  The application will grab the configured
factory object using JNDI and use the factory to find and create
the resource objects.  In a typical example, the application will
grab a database DataSource to create JDBC Connections.  Because the
configuration is left to the configuration files, it's easy for
the application to change databases for different customers.
</p>

<p>Some typical factory objects include:

<ul>
<li><a href="db-config.xtp">JDBC DataSource</a>
<li>EJB Home interfaces
<li><a href="jms.xtp">Java Messaging Service (JMS)</a> connection factories
<li>JavaMail connection factories
<li>Global configuration constants
</ul>

<s2 title="web-apps and JNDI Contexts">

<p>Resin organizes its resources into a tree, rooted in the
system classloader.  Each Resin context is associated with a classloader,
a JNDI context, and a set of resources (databases, JMS, EJB beans, etc.)</p>

<p>Child contexts inherit classes and resources from
the parent contexts.  For example, a database with a JNDI name
"java:comp/env/jdbc/foo" belonging to the foo.com virtual host would be
shared for all web-applications in that host.</p>

<p>When Resin detects class or configuration changes in a context, it
will reload that context and all child contexts.  This is how Resin
reloads an application when a servlet changes.</p>

<figure src="jndi_tree.gif"/>

<p>Each web-app gets its own JNDI copy.  So a web-app named /quercus
and a web-app named /cmp could each use java:comp/env/jdbc/test for a
database pool, but would use unique pools (probably using
different databases.)</p>

<p>This separation keeps web-apps from stepping on each other's toes
and also lets each virtual host use different databases.</p>

<p>The web-apps can share JNDI configuration from its host, and the
hosts can share JNDI configuration from the global server.  Each
web-app copies the host JNDI tree, and each host copies the server
JNDI tree.  So the web-app can't affect the host's JNDI, but it can
share the host's pools.</p>

<p>In Resin's configuration, the context determines where the JNDI
will be shared.  If the JNDI configuration is in the &lt;host>, it will
be shared across the entire host.  If it's in the &lt;web-app>, it
will only be used in the web-app.</p>

<deftable>
<tr><th>context<th>scope
<tr><td>http-server<td>shared across all applications
<tr><td>host<td>shared across the virtual host
<tr><td>web-app<td>specific to the servlet application (.war)
</deftable>

<example title='host and web-app specific configuration'>
...
&lt;host id='foo.com'>
  &lt;resource-ref res-ref-name='jdbc/foo'
                res-type='javax.sql.DataSource'>
    &lt;init-param driver-name="org.gjt.mm.mysql.Driver"/>
    &lt;init-param url="jdbc:mysql://localhost:3306/foo"/>
  &lt;/resource-ref>

  &lt;web-app id='/quercus'>
    &lt;resource-ref res-ref-name='jdbc/quercus'
                  res-type='javax.sql.DataSource'>
      &lt;init-param driver-name="org.gjt.mm.mysql.Driver"/>
      &lt;init-param url="jdbc:mysql://localhost:3306/quercus"/>
    &lt;/resource-ref>
  &lt;/web-app>
&lt;/host>
...
</example>

<p>In the previous example, the java:comp/env/jdbc/foo pool is shared
across all web-apps in foo.com, but the java:comp/env/jdbc/quercus
pool is only available in the /quercus web-app.</p>

</s2>

<s2 title='JNDI Names'>

<p>JNDI names look like URLs.  A typical name for a
database pool is java:comp/env/jdbc/test.  The <var/java:/> scheme is
a memory-based tree.  <var/comp/env/> is the standard location for
Java configuration objects and <var/jdbc/> is the standard location
for database pools.</p>

<p>Other URL schemes are allowed as well, including
RMI (rmi://localhost:1099) and LDAP.  Many applications, though will
stick to the java:comp/env tree.</p>

<deftable>
<tr><th>name<th>meaning
<tr><td>java:comp/env<td>Configuration environment
<tr><td>java:comp/env/jdbc<td>JDBC DataSource pools
<tr><td>java:comp/env/ejb<td>EJB remote home interfaces
<tr><td>java:comp/env/cmp<td>EJB local home interfaces (non-standard)
<tr><td>java:comp/env/jms<td>JMS connection factories
<tr><td>java:comp/env/mail<td>JavaMail connection factories
<tr><td>java:comp/env/url<td>URL connection factories
<tr><td>java:comp/UserTransaction<td>UserTransaction interface
</deftable>

</s2>

<s2 title='JNDI API'>

<p>The vast majority of applications will only need the following simple
pattern to lookup objects using JNDI.  Since the JNDI objects are
typically configured in the web.xml or resin.conf, servlets will
typically look up their DataSources or EJB objects once in the init()
method.  By looking up the object once, the application can avoid any
JNDI overhead for normal requests.
</p>

<example title='Looking up a DataSource'>
import javax.naming.InitialContext;
import javax.naming.Context;

...

Context env = (Context) new InitialContext().lookup("java:comp/env");
DataSource pool = (DataSource) env.lookup("jdbc/test");
</example>

<p><var/new InitialContext()/> returns the initial context for the
current web-app.  As explained above, each application has its own
independent JNDI namespace.  So applications and virtual hosts will
not conflict with each other's JNDI names.
</p>

<p>The <var/lookup(subpath)/> call finds the object at the specified
subpath, like a filesystem lookup.  Intermediate paths, like
<var/env/> in the example above, are Context objects.  There's a
strong analogy between filesystem directories and JNDI Context
objects.</p>

<deftable>
<tr><th>call<th>meaning
<tr><td>new InitialContext()<td>A new pointer to the root context
<tr><td>context.lookup("subpath")<td>Finds the object or context at the named path beneath the current context
</deftable>

<p>Applications will generally cache the results of the JNDI lookup.
Once configured, factory objects don't change so they can be saved to avoid
the JNDI lookup.  For example, EJB Home and DataSource factories
don't change once they've been configured.  A well-designed application
will lookup the DataSource once and cache it for the next call.
Servlets, for example, will often lookup the DataSource or EJB Home in the
<var/init()/> method and save them in servlet instance variables.
</p>

<example title='Caching a DataSource in a Servlet init()'>
package qa;

import javax.servlet.*;
import javax.naming.*;

public class MyServlet extends GenericServlet {
  DataSource dataSource;

  public void init()
    throws ServletException
  {
    try {
      Context env = new InitialContext().lookup("java:comp/env");
      dataSource = (DataSource) env.lookup("jdbc/test");
    } catch (Exception e) {
      throw new ServletException(e);
    }
  }

  ...
}
</example>

</s2>

<s2 title="JNDI configuration">

<s3 title="resource-ref">
<p>Factory configuration, including configuration for
database pooling.  <var/resource-ref/> puts
the DataSource in a JNDI context and also in the ServletContext.
Each web-app can configure its own database pool.  Resin can also
share a common pool by putting the resource-ref in the &lt;host> or in
the &lt;http-server>.</p>

<p>More details are in the <a href='db-config.xtp'>database config</a>
page.</p>

<p>The driver can be in WEB-INF/lib or WEB-INF/classes, although it's
a better idea to put it in the global classpath or resin-2.0.x/lib.</p>

<deftable>
<tr><th>Attribute<th>Meaning
<tr><td>res-ref-name<td>JNDI path attribute to store the pool.  The
path is relative to java:comp/env.
<tr><td>res-type<td>javax.sql.DataSource or javax.sql.XADataSource for database pools
<tr><td>init-param<td>initialization parameters (Resin 1.2)
<tr><td>init-class<td>Class containing init params (Map or Hashtable) (Resin 1.2.4)
<tr><td>bean-name<td>optional bean class to be used as a resource (Resin 1.2)
</deftable>

<p><var/init-param/> sets bean properties of the data source.
You can look at the com.caucho.sql.DBPool JavaDoc for its interface.
Unknown parameters are used to set the driver properties.  So you can
set any driver-specific property in the init-param.</p>

</s3>

<s3 title="env-entry">
<p>JNDI parameter configuration.  The env-entry configuration
is similar to the init-param for servlets, but is accessible to any
Java class in the application without needing to pass along a context.</p>

<deftable>
<tr><th>Attribute<th>Meaning
<tr><td>env-entry-name<td>JNDI path attribute to store the variable.  The path is relative to java:comp/env.
<tr><td>env-entry-type<td>Java type of the variable
<tr><td>env-entry-value<td>The variable value.
</deftable>

<p>The example configuration stores a string in java:comp/env/greeting.
Following the J2EE spec, the env-entry-name is relative to
java:comp/env.  If the env-entry is in the &lt;host> context, it will
be visible to all web-apps in the host.</p>

<example title="Example resin.conf fragment">
&lt;env-entry>
  &lt;env-entry-name>greeting&lt;/env-entry-name>
  &lt;env-entry-type>java.lang.String&lt;/env-entry-type>
  &lt;env-entry-value>Hello, World&lt;/env-entry-value>
&lt;/env-entry>
</example>

<p>The following servlet fragment is a typical use in a servlet.  The
servlet only looks up the variable once and stores it for later use.
</p>

<example title="GreetingServlet.java">
import java.io.*;
import javax.naming.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class TestServlet extends HttpServlet {
  private String greeting;

  public void init()
    throws ServletException
  {
    try {
      Context env = (Context) new InitialContext().lookup("java:comp/env");
      greeting = (String) env.lookup("greeting");
    } catch (NamingException e) {
      throw new ServletException(e);
    }
  }

  ...
}
</example>

</s3>

<defun title="jndi-link" version="Resin 1.2">
<p>Links a foreign JNDI context to the Resin JNDI context.
For example, you can use <var/jndi-link/> to link in client EJBs from
a foreign EJB container.</p>

<deftable>
<tr><th>Attribute<th>Description.
<tr><td>jndi-name<td>JNDI path attribute to bind the link
<tr><td>property-file<td>jndi.property to use to obtain the Context.
<tr><td>jndi-factory<td>Class name of an InitialContextFactory used to
create the bean.
<tr><td>init-param<td>Properties to be used to get the initial
context.
<tr><td>jndi-lookup<td>JNDI path for the foreign context.
</deftable>

<example title="Linking a WebLogic EJB client bean">
&lt;jndi-link>
  &lt;jndi-name>java:comp/env/ejb/traderHome&lt;/jndi-name>
  &lt;jndi-factory>weblogic.jndi.WLInitialContextFactory&lt;/jndi-factory>
  &lt;init-param java.naming.provider.url="t3://localhost:7001"/>
  &lt;jndi-lookup>statelessSession.TraderHome&lt;/jndi-lookup>
&lt;/jndi-link>
</example>

</defun>
</s2>

<s2 title="Known JNDI Object Factories">

<s3 title='javax.sql.DataSource'>

<p>Configures a non-transactional JDBC data sources.  More details are
available on the <a href="db-config.xtp">database configuration</a> page.
</p>

<deftable title='init-param values'>
<tr><th>Attribute<th>Meaning
<tr><td>driver-name<td>The Java classname of the driver.
<tr><td>url<td>The driver specific database url.
<tr><td>data-source<td>A reference to an XADataSource or PooledDataSource.
</deftable>

<p>Here's a sample minimal resin.conf fragment to bind a DBPool-based
database to the JNDI path "java:comp/env/jdbc/test".  The examples
below show how that JNDI path will be used.</p>

<example title="Sample resin.conf fragment">
&lt;resource-ref>
  &lt;res-ref-name>jdbc/test&lt;/res-ref-name>
  &lt;res-type>javax.sql.DataSource&lt;/res-type>
  &lt;init-param driver-name="com.caucho.jdbc.mysql.Driver"/>
  &lt;init-param url="jdbc:mysql-caucho://localhost:3306/test"/>
&lt;/resource-ref>
</example>

</s3>

<s3 title='javax.sql.XADataSource'>

<p>Configures a transactional JDBC data sources.  More details are
available on the <a href="db-config.xtp">database configuration</a> page.</p>

<deftable title='init-param values'>
<tr><th>Attribute<th>Meaning
<tr><td>driver-name<td>The Java classname of the driver.
<tr><td>url<td>The driver specific database url.
</deftable>

<p>Here's a sample minimal resin.conf fragment to bind a transactional
DBPool-based database to the JNDI path "java:comp/env/jdbc/test".  The examples
below show how that JNDI path will be used.
</p>

<example title="Sample resin.conf fragment">
&lt;resource-ref>
  &lt;res-ref-name>jdbc/test&lt;/res-ref-name>
  &lt;res-type>javax.sql.XADataSource&lt;/res-type>
  &lt;init-param driver-name="com.caucho.jdbc.mysql.Driver"/>
  &lt;init-param url="jdbc:mysql-caucho://localhost:3306/test"/>
&lt;/resource-ref>
</example>

</s3>

<s3 title='javax.mail.Session'>

<p>JavaMail sessions are configured with resource-ref.  The session is
created with <var/Session.getInstance/> using the properties
defined in the init-param.</p>

<example>
&lt;resource-ref res-ref-name='mail/MySession'
              res-type='javax.mail.Session'>
  &lt;init-param mail.transport.protocol='smtp'>
  &lt;init-param mail.host='localhost'>
  &lt;init-param mail.user='harry'>
&lt;/resource-ref>
</example>

</s3>

</s2>

<s2 title="Custom Factories">

<p>The resource-ref element can configure any bean-based factory.
A new instance of the bean will be created from the specified
class-name.  To make this work, the factory class must have a
public zero-arg constructor.</p>

<p>The <var/init-param/> elements configure the factory's
properties using introspection.  A 'foo' property expects a
setFoo method, and a 'foo-bar' property expects a setFooBar property:
</p>

<example title='custom.MyBean'>
package custom;

public class MyBean {
  private String foo;
  private int bar;

  public void setFoo(String foo)
  {
    this.foo = foo;
  }

  public void setBar(int bar)
  {
    this.bar = bar;
  }

  ...
}
</example>

<example title='Configuration for custom.MyBean'>
&lt;resource-ref res-ref-name='custom/MyBean'
              class-name='test.MyBean'>
  &lt;init-param foo='a string'>
  &lt;init-param bar='613'>
&lt;/resource-ref>
</example>

<p>Once configured, the application will lookup the
factory in <var/java:comp/env/custom/MyBean/> and use it to create
any needed application objects.  As long as the class follows the
bean patterns, it can be configured in resource-ref.
</p>

</s2>
</s1>
