<document>

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.

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.

Some typical factory objects include:

- JDBC DataSource
- EJB Home interfaces
- Java Messaging Service (JMS) connection factories
- JavaMail connection factories
- Global configuration constants

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.)

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.

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.

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.)

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

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.

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

<deftable>
context scope
http-server shared across all applications
host shared across the virtual host
web-app specific to the servlet application (.war)
</deftable> ... <host id='foo.com'> <database name='jdbc/foo'> <driver-class>org.gjt.mm.mysql.Driver</driver-class> <driver-url>jdbc:mysql://localhost:3306/foo</driver-url> </database> <web-app id='/quercus'> <database name='jdbc/quercus'> <driver-class>org.gjt.mm.mysql.Driver</driver-class> <driver-url>jdbc:mysql://localhost:3306/quercus</driver-url> </database> </web-app> </host> ...

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.

The previous example was meant to illustrate the concept of how JNDI objects belong to a certain context, for more realistic examples of configuring and using databases see the Databases topic.

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

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.

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

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.

import javax.naming.InitialContext; import javax.naming.Context; ... Context ic = new InitialContext(); DataSource pool = (DataSource) ic.lookup("java:comp/env/jdbc/test");

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.

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

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

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 init() method and save them in servlet instance variables.

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); } } ... }

Factory configuration, including configuration for database pooling. 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 in the <host> or in the <server>.

More details are in the configuration documentation for the tag. page.

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.

More details are in the configuration documentation for the tag.

Links a foreign JNDI context to the Resin JNDI context. For example, you can use jndi-link to link in client EJBs from a foreign EJB container.

More details are in the configuration documentation for the tag.

Configures a non-transactional JDBC data sources. More details are available on the database configuration page.

Configures a transactional JDBC data sources. More details are available on the database configuration page.

JavaMail sessions are configured with resource. The session is created with Session.getInstance using the properties defined in the init-param.

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

The resource element can configure any bean-based object. A new instance of the bean is created from the name of the class specified with type. To make this work, the class must have a public zero-arg constructor.

You code your java class to accept bean-style setters. You can then use Bean-style initialization or init-param elements to configure the factory's properties using introspection. A 'foo' property expects a setFoo method, and a 'foo-bar' property expects a setFooBar property.

An example of a custom JNDI object that uses bean-style initialization is the jndi-appconfig tutorial.

The following is a short example using init-param: 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; } ... } <resource jndi-name='custom/MyBean'> <type>test.MyBean</type> <init-param foo='a string'> <init-param bar='613'> </resource>

The application uses the standard jndi API to find the resource with the jndi name java:comp/env/custom/MyBean. needed application objects. As long as a class follows the bean patterns (at minimum a public, zero-arg constructor, and setXXX mthods for properties), it can be configured in `resource`.

</document>