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:
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.
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.
JNDI names look like URLs. A typical name for a database pool is java:comp/env/jdbc/test. The scheme is a memory-based tree. is the standard location for Java configuration objects and 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.
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.
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 call finds the object at the specified subpath, like a filesystem lookup. Intermediate paths, like in the example above, are Context objects. There's a strong analogy between filesystem directories and JNDI Context objects.
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 method and save them in servlet instance variables.
resource-refFactory 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-ref in the <host> or in the <http-server>.More details are in the database config page. 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.
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. env-entryJNDI 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.
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 <host> context, it will be visible to all web-apps in the host.
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.
jndi-linkLinks a foreign JNDI context to the Resin JNDI context. For example, you can use to link in client EJBs from a foreign EJB container.
javax.sql.DataSourceConfigures a non-transactional JDBC data sources. More details are available on the database configuration page.
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.
javax.sql.XADataSourceConfigures a transactional JDBC data sources. More details are available on the database configuration page.
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.
javax.mail.SessionJavaMail sessions are configured with resource-ref. The session is created with using the properties defined in the init-param.
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. The elements configure the factory's properties using introspection. A 'foo' property expects a setFoo method, and a 'foo-bar' property expects a setFooBar property:
Once configured, the application will lookup the factory in 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.
|