Spring and JNDI

In Chapter 4, we discussed how JNDI represents the Dependency Pull style of IoC. In traditional J2EE applications, JNDI is used to access a variety of different resources, such as EJBs and JMS connection factories. At the basic level, Spring provides a mechanism, using JndiTemplate, to simplify the amount of code needed to perform a JNDI lookup. However, this does not overcome the major drawback of using the Dependency Pull style—the component is still responsible for obtaining its own dependencies, and it must maintain some kind of identifying information so it can do so. To overcome this, Spring provides the JndiObjectFactoryBean, an implementation of FactoryBean that allows resources bound in JNDI to be injected using DI.

In this section, we are going to look at three approaches for accessing resources stored in JNDI. First, we perform a traditional lookup without any Spring classes. Second, we perform a manual lookup again, this time using the JndiTemplate class to simplify the amount of code required. Finally, we use the JndiObjectFactoryBean to perform DI automatically. However, before we get started with these approaches, we need to examine the common code used by each.

About the JNDI Examples

For each of these JNDI lookup examples, we build a simple servlet that displays a message obtained from JNDI. The message is written out three times, each time using a different approach to retrieve the message. The core of this example is the MessageResolver interface, which is implemented by each of the three classes that retrieve the message from JNDI. The MessageResolver interface is shown in Listing 13-1.

Listing 13-1: The MessageResolver Interface

image from book
package com.apress.prospring.ch13.jndi;      public interface MessageResolver {          public String getMessage(); } 
image from book

As you can see, there is nothing special about this interface. The interesting part of this example comes in how the individual examples retrieve the JNDI resource.

The JndiDemoServlet

The MessageResolver interface simply provides a way to implement classes to return a message. The JndiDemoServlet class performs the actual writing of these messages, as shown in Listing 13-2.

Listing 13-2: The JndiDemoServlet Class

image from book
package com.apress.prospring.ch13.jndi;      import java.io.IOException; import java.io.PrintWriter;      import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;      import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;      public class JndiDemoServlet extends HttpServlet {          public static final String JNDI_NAME = "java:comp/env/message";          private ApplicationContext ctx;          public void init() throws ServletException {         ctx = new ClassPathXmlApplicationContext(                 "/WEB-INF/applicationContext.xml");     }          protected void doGet(HttpServletRequest request,             HttpServletResponse response) throws ServletException, IOException {              PrintWriter writer = response.getWriter();              writeWithBean("messageWriterTraditional", writer);         writeWithBean("messageWriterTemplate", writer);         writeWithBean("messageWriterFactoryBean", writer);     }          private void writeWithBean(String beanName, PrintWriter writer) {         MessageResolver traditional = (MessageResolver) ctx.getBean(beanName);         writer.write(traditional.getMessage());         writer.write("\n");     } }
image from book

JndiDemoServlet is a fairly basic servlet. We start by locating the Spring application context and then, using the writeWithBean() method, we invoke each of the three beans in sequence. Inside the writeWithBean() method, you can see that the message returned by the bean is written to the output stream (using the PrintWriter instance) and is followed by a new line. Notice also that we have defined a public static final field, JNDI_NAME, to hold the JNDI name for the resource that our components are looking for. This resource is defined using the <env-entry> tag in the servlet deployment descriptor, as shown in Listing 13-3.

Listing 13-3: Binding a JNDI Resource in web.xml

image from book
<?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>jndi</servlet-name>         <servlet-class>           com.apress.prospring.ch13.jndi.JndiDemoServlet</servlet-class>     </servlet>          <servlet-mapping>         <servlet-name>jndi</servlet-name>         <url-pattern>/jndi</url-pattern>     </servlet-mapping>          <env-entry>         <env-entry-name>message</env-entry-name>         <env-entry-value>Hello World!</env-entry-value>         <env-entry-type>java.lang.String</env-entry-type>     </env-entry> </web-app>
image from book

As you can see, we are binding the phrase "Hello World!" to the JNDI resource, so when we access the servlet, we expect to see three lines, each displaying "Hello World!" That covers how the messages are displayed; in the next three sections, we look at the different implementations of MessageResolver to see how the message is retrieved.

Traditional JNDI Approach

In this section, we demonstrate the traditional approach to looking up a resource using JNDI. The traditional approach to obtaining a resource from JNDI is to create an instance of InitialContext and then look up the resource using InitialContext.lookup(). Because we are operating inside a J2EE server, we do not need to set any environmental parameters for the InitialContext, but when we work with JNDI outside of an application server, this is necessary.

Listing 13-4 shows the TraditionalJndiMessageResolver class, an implementation of MessageResolver that does not use any Spring classes.

Listing 13-4: JNDI Access Using JNDI API

image from book
package com.apress.prospring.ch13.jndi;      import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException;      public class TraditionalJndiMessageResolver implements MessageResolver {          private String message;          public String getMessage() {         if (message == null) {             lookupMessage();         }         return message;     }          private void lookupMessage() {         try {             Context ctx = new InitialContext();             message = (String) ctx.lookup(JndiDemoServlet.JNDI_NAME);         } catch (NamingException ex) {             message = ex.getMessage();         }     } }
image from book

The bulk of the processing here is in the lookupMessage() method. As you can see, we create an instance of InitialContext and then we perform the lookup using InitialContext.lookup(). Both the InitialContext constructor and the lookupMessage() method are declared as throwing NamingException. In this example, we simply catch any NamingExceptions and set the error message as the message to be displayed.

Using JndiTemplate

In this section, we demonstrate the use of the JndiTemplate class to replace the traditional JNDI lookup code. Using JndiTemplate isn't drastically different from using the InitialContext class to perform the lookup, as shown in Listing 13-5.

Listing 13-5: Lookup Using JndiTemplate

image from book
package com.apress.prospring.ch13.jndi;      import javax.naming.NamingException;      import org.springframework.jndi.JndiTemplate;      public class JndiTemplateMessageResolver implements MessageResolver {          private String message;          public String getMessage() {         if (message == null) {             lookupMessage();         }         return message;     }          private void lookupMessage() {         JndiTemplate template = new JndiTemplate();              try {             message = (String) template.lookup(JndiDemoServlet.JNDI_NAME);         } catch (NamingException ex) {             message = ex.getMessage();         }     } }
image from book

As you can see, this implementation does not look much different from the previous one. Although the JndiTemplate constructor does not throw a NamingException, the lookup method does; we handle it in exactly the same way as we did in the previous implementation.

So why use JndiTemplate rather than InitialContext? Both classes can be configured using DI, although only JndiTemplate supports setter injection, so there is nothing to set them apart there. The main reason we would choose to use JndiTemplate over InitialContext is to take advantage of the callback functionality. JndiTemplate defines an execute() method that accepts an instance of JndiCallback. Using this method, you can perform a set of actions in the context of the JNDI Context object, all inside the callback handler. This provides an excellent way to encapsulate JNDI operations; indeed, JndiTemplate implements methods like lookup() using the execute() method. However, this feature is only for very specific cases, and in reality, we would always choose the following implementation over both JndiTemplate and InitialContext when performing a simple lookup.

Pro Spring
Pro Spring
ISBN: 1590594614
EAN: 2147483647
Year: 2006
Pages: 189

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net