1) Introduction
Spring provides support to access objects from the JNDI Repository. This article will begin with the JNDI concepts along with a sample JNDI Application. Then it will proceed with the various core supporting classes available in Spring for JNDI Integration. Following that, practical samples would be given to make things clear. The pre-requisite for this article is some basic introductory knowledge in Spring which can be got by reading the article in javabeat Introduction to Spring Web Framework.
also read:
2) JNDI
2.1) Introduction
JNDI stands for Java Naming and Directory interface. It is a specification and API that can be used to access any type directory service. For example, a particular implementation of JNDI specification can be used to access the LDAP Repository. JNDI is used heavily by the J2EE Applications to store Application specific data and business objects.
Imagine the case of a J2EE Application, where it is having a Web module and a EJB Module. A Web module is used to handle the Http Request from the Browser client, process it and then will return the Http Response back to the client. It basically will contain a collection of Servlet components and JSP’s. The Web module may use the EJB module for accessing the Enterprise Beans for data manipulation. Suppose, say that we want to store data that is common to both Web and EJB Module. Where we can store this information, in the Web Module or in the EJB Module?. It doesn’t make sense to store the data in any of the Modules, because the data is a common data and it is not particularly restricted to any of the Modules.
Here comes the JNDI Repository. The Application Server Container will provide an implementation for the JNDI Repository for storing the global data (data that is common across the modules) and the clients (either the Enterprise Beans, or the Servlets or even the Application client) can use the JNDI API to query the information available in the JNDI Repository. It is also possible to store the Business Objects (like Session Beans, Message Driven beans) in the JNDI Repository. In this case, a Servlet may be the client in getting a reference to the Enterprise Bean from the Repository. It is not necessary for an Application Developer to manually store the Business Objects into the JNDI Repository as the Container will take care of all these things, like constructing the JNDI Tree, storing the Business objects etc.
3) JNDI Sample
3.1) Introduction
Let us see an example of how to store and access the information stored in the JNDI Repository. This sample Application stores two entries (one is of type String and the other one is of type Integer) in the JNDI Repository. The client is going to be the servlet which makes use of the JNDI Api for accessing the information in the JNDI Repository.
3.2) Jndi Access Servlet
The Servlet class makes use of the InitialContext
for accessing the JNDI information. The method lookup()
queries for the value of the string that is passed as a key. Then it makes use of the normal PrintWriter
class to send the information back to the Browser client.
JndiAccessServlet.java
package javabeat.net.articles.spring.jndi.introduction; import java.io.*; import javax.naming.*; import javax.servlet.http.*; public class JndiAccessServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { InitialContext context = null; String welcomeMessage = null; Integer maxSessionCount = null; try{ context = new InitialContext(); welcomeMessage = (String)context.lookup( "java:comp/env/welcomeMessage"); maxSessionCount = (Integer)context.lookup( "java:comp/env/maxSessionCount"); } catch (NamingException exception){ exception.printStackTrace(); } PrintWriter writer = response.getWriter(); writer.write("Data read from JNDI Respository :"); writer.write("Welcome Message -->" + welcomeMessage); writer.write("Max Session Count-->" + maxSessionCount); writer.close(); } }
3.3) Web Configuration File
The following is the configuration file for the Web Application. It defines the various servlet definition(s) along with the JNDI Entries. Let us have a look into that file,
web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>JndiAccessServlet</servlet-name> <servlet-class> javabeat.net.articles.spring.jndi.introduction.JndiAccessServlet< /servlet-class> </servlet> <servlet-mapping> <servlet-name>JndiAccessServlet</servlet-name> <url-pattern>/jndiServlet</url-pattern> </servlet-mapping> <env-entry> <env-entry-name>welcomeMessage</env-entry-name> <env-entry-value>Hello All</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry> <env-entry> <env-entry-name>maxSessionCount</env-entry-name> <env-entry-value>1000</env-entry-value> <env-entry-type>java.lang.Integer</env-entry-type> </env-entry> </web-app>
The first section in the Xml file defines a Servlet by name jndiAccessServlet
. The servlet-mapping
tag says that the Servlet can be accessed through the URL '/jndiServlet'
. The rest of the section contains the definition of the JNDI Entries. The tag env-entry
defines an environmental entry in the JNDI Repository. The name of the entry, along with its type and value are given in the form of env-entry-name
, env-entry-type
and env-entry-value
tags.
4) Spring’s JNDI Support
4.1) Introduction
In this section, we will have a look over the various core classes/interfaces available in Spring for JNDI support. The following classes are going to be dealt in this section,
- JndiTemplate
- JndiCallback
- JndiObjectFactoryBean
We will look into the above classes one by one.
4.2) Jndi Template
A Jndi Template provides a simplified interface for performing various operations like lookup, binding and rebinding in the JNDI Repository. There isn’t much difference in using this JndiTemplate
class versus the traditional way of accessing the JNDI using the InitialContext
class. However, the only advantage of using this class is that it provides a method for executing custom lookup logic through call-back mechanisms which will be covered in the subsequent sections.
The following code snippet creates a JndiTemplate object for querying the JNDI Repository,
JndiTemplate template = new JndiTemplate();
When the client of the JNDI Repository is within the same container, then the above code will work fine. What if the client Application is a remote client? In such a case, we have to specify the information (like JNDI URL, username and password) while creating the JndiTemplate
object. This can be achieved through the following code,
Properties props = new Properties(); // Populate JNDI specific information here. pros.put("Key", "Value"); JndiTemplate template = new JndiTemplate(); template.setEnvironment(props);
The operations that can be performed over the JNDI Repository are querying, binding and re-binding. These are achieved through the methods lookup()
, bind()
and rebind()
respectively.
template.bind("SomeKey", "SomeValue"); … String value = (String)template.lookup("SomeKey"); template.rebind("SomeKey", "SomeValue");
4.3) Jndi Callback
Spring provides support for encapsulating the JNDI operation (like lookup, bind and rebind) as a command object. Thereby it can be reused as many times as required. For example, say that the JNDI operation wants to be logged, then we can define a new class implementing the JndiCallback
interface and overriding the doInContext()
method.
To make this custom logic to get executed, we have to call the JndiTemplate.execute()
by passing an argument of type JndiCallback
. This call-back mechanism is certainly powerful as the whole logic of JNDI operation is confined to a single unit thereby leading the way to do any type of customization like logging, caching etc.
4.4) Jndi Object Factory Bean
This Factory bean is responsible for querying the information from the JNDI Repository. Usage of this factory bean is as simple as making configuration in the Spring’s Configuration file. Example of using this Factory Bean is given in the later samples section. The default strategy for this Factory Bean is to lookup all the JNDI objects and cache it. However, this can be modified by specifying the properties (“lookupOnStartup” and “cache”) to appropriate values.
Even this can be done programmatically like the following,
JndiObjectFactoryBean bean = ….; bean.setLookupOnStartup(false); bean.setCache(false);
5) JNDI and Spring Configuration – Example
5.1) Introduction
In this section, we will look at code snippets for the support classes in Spring for JNDI Integration.
5.2) Making use of JndiTemplate class
As we have already seen, making using of JndiTemplate
class for accessing the JNDI Repository is no different than using the InitialContext
class. The following Servlet makes use of JndiTemplate
class for querying the JNDI Repository.
ServletUsingJndiTemplate.java
package javabeat.net.articles.spring.jndi.introduction; import java.io.*; import javax.naming.*; import javax.servlet.http.*; import org.springframework.jndi.JndiTemplate; public class ServletUsingJndiTemplate extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { JndiTemplate template = new JndiTemplate(); String welcomeMessage = null; Integer maxSessionCount = null; try{ welcomeMessage = (String)template.lookup( "java:comp/env/welcomeMessage"); maxSessionCount = (Integer)template.lookup( "java:comp/env/maxSessionCount"); }catch(NamingException exception){ exception.printStackTrace(); } PrintWriter writer = response.getWriter(); writer.write("Data read from JNDI Respository using Jndi Template:"); writer.write("Welcome Message -->" + welcomeMessage); writer.write("Max Session Count-->" + maxSessionCount); writer.close(); } }
To invoke this Servlet, add the following entries in the web.xml
file,
web.xml
<servlet> <servlet-name>ServletUsingJndiTemplate</servlet-name> <servlet-class> javabeat.net.articles.spring.jndi.introduction.ServletUsingJndiTemplate </servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletUsingJndiTemplate</servlet-name> <url-pattern>/jndiServletUsingJndiTemplate</url-pattern> </servlet-mapping>
5.3) Using the Callback Mechanism
The Jndi Callback mechanism provides a way for encapsulating the operations related to JNDI into a single unit and thereby makes it callable from various places. The following sample shows the usage of this interface,
CustomJndiAccessForLogging.java
package javabeat.net.articles.spring.jndi.introduction; import javax.naming.Context; import javax.naming.NamingException; import org.springframework.jndi.JndiCallback; import org.springframework.jndi.JndiTemplate; public class CustomJndiAccessForLogging implements JndiCallback { private String key; public CustomJndiAccessForLogging(String key) { this.key = key; } public Object doInContext(Context context) throws NamingException { System.out.println("Start lookup operation"); Object value = context.lookup(key); System.out.println("End lookup operation"); return value; } }
In the above class, we have added logging support whenever an JNDI operation is invoked. However for the above code to work, we have to use the JndiTemplate.execute()
method as shown below,
JndiTemplate template = new JndiTemplate(); CustomJndiAccessForLogging callback = new CustomJndiAccessForLogging("key"); Object result = template.execute(callback);
5.4) Configuring the Jndi Object Factory Bean
In this final section, we will see how to configure the Jndi Object Factory Bean for getting the information from JNDI Repository. Let us first represent a class for holding the values fetched from the Repository. The following code is the class definition for the same,
InfoFromJndi.java
package javabeat.net.articles.spring.jndi.introduction; public class InfoFromJndi { private String welcomeMessage; private Integer maxSessionCount; public String getWelcomeMessage(){ return welcomeMessage; } public void setWelcomeMessage(String welcomeMessage){ this.welcomeMessage = welcomeMessage; } public Integer getMaxSessionCount(){ return maxSessionCount; } public void setMaxSessionCount(Integer maxSessionCount){ this.maxSessionCount = maxSessionCount; } }
Now, let us define the configuration file with the aim of populating the two properties welcomeMessage
and maxSessionCount
for the above class. Let us have a look at the following configuration file,
spring-jndi.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd"> <bean id="infoFromJndi" > <property name="welcomeMessage"> <bean> <property name="jndiName"> <value>java:comp/env/welcomeMessage</value> </property> </bean> </property> <property name="maxSessionCount"> <bean> <property name="jndiName"> <value> java:comp/env/maxSessionCount</value> </property> </bean> </property> </bean> </beans>
Note that a new bean instance of type InfoFromJndi
with name 'infoFromJndi'
is created. Now the two properties 'welcomeMessage'
and 'maxSessionCount'
has to be populated with the values taken from JNDI. To make this possible, we have defined the property tag representing the property
tag with the attribute name
pointing to 'welcomeMessage'
but we haven’t given the 'value'
attribute. Instead, we have defined a nested Jndi Object Factory bean whose property name should point to the JNDI name, so that the value of this property can be fetched from the JNDI and the same can be assigned to the outer 'welcomeMessage'
property. Same is the case for the 'maxSessionCount'
property.
6) Conclusion
We have seen the introductory details for the various forms of support for Spring-JNDI Integration available in Spring. Using Spring for accessing the JNDI objects is very simple as it involves adding relevant information in the configuration file. The advantage of using Spring over the regular JNDI API is that we can take the full support of features like IOC and Dependency injection which will be available by default with Spring.
also read: