Using JndiObjectFactoryBean

In this section, we look at the JndiObjectFactoryBean that allows JNDI lookups to be configured declaratively. The implementation of MessageResolver that uses JndiObjectFactoryBean to locate the JNDI message resource is much simpler than the previous implementations. The reason for this is that JndiObjectFactoryBean acts as an adapter between the world of JNDI lookup and the world of Spring DI. For this reason, our JndiObjectFactoryBeanMessageResolver class is, as shown in Listing 13-6, designed to receive the message via DI; in fact, it does not perform any JNDI lookup.

Listing 13-6: The JndiObjectFactoryBeanMessageResolver Class

image from book
package com.apress.prospring.ch13.jndi;      import java.util.Hashtable;      public class JndiObjectFactoryBeanMessageResolver implements MessageResolver {          private String message;          public String getMessage() {         return message;     }          public void setMessage(String message) {         this.message = message;     } }
image from book

As you can see, this class has no dependency on InitialContext or JndiTemplate; the value for the message property can come from anywhere. In this case, however, it comes from JNDI. The bulk of the heavy lifting for JndiObjectFactoryBeanMessageResolver is done in the configuration shown in Listing 13-7.

Listing 13-7: Using JndiObjectFactoryBean

image from book
<bean        >         <property name="message">             <bean >                 <property name="jndiName">                     <value>message</value>                 </property>                 <property name="resourceRef">                     <value>true</value>                 </property>             </bean>         </property>     </bean> 
image from book

Here you can see that we are injecting the value for the message property using the JndiObjectFactoryBean. JndiObjectFactoryBean is configured with the name of the JNDI resource to look up (which should be a type that is compatible with the type of property you are injecting into). In this case, we set the jndiName property to message, but remember that the full JNDI name is java:comp/env/message. By setting the resourceRef property to true, we are informing JndiObjectFactoryBean that this resource is stored in the application environment and as such, it should be prefixed with java:comp/env/ if required.

Running the Example

To run this example, we simply compile all the classes and wrap them up in a WAR file that is deployed into JBoss 3.2.5. Although we do not show this here, you can find the build script for this example in the code download that accompanies this book (you can find it in this chapter's folder of the Downloads section of the Apress website at www.apress.com).

If we point our browser to http://localhost:8080/ch13/jndi, we get the output shown in Figure 13-1.

image from book
Figure 13-1: Running the JNDI example

As you can see, we get the desired output from each MessageResolver implementation, but we need to use differing levels of effort to create each implementation, and we get differing levels of coupling in the resulting implementations.

Other JNDI Operations

The most common operation using JNDI, especially in a J2EE context, is to look up a resource. However, in some cases, you may need to bind a new resource into the tree, rebind a resource that already exists, or unbind a resource completely. For these operations, you have two options. JndiObjectFactoryBean is not applicable in these circumstances because it performs lookups only. This leaves you with InitialContext and JndiTemplate. Both classes can perform lookup, bind, rebind, and unbind operations on the JNDI tree. As we mentioned earlier, the JndiTemplate class does offer the benefit of being able to execute JNDI operations using the callback mechanism. This allows you to wrap operations involving JNDI in distinct command objects that implement the JndiCallback interface.

Which Approach to Use?

With JndiTemplate and InitialContext offering such similar feature sets, you may find determining which approach to use for a given task confusing. Certainly, when you look up resources in JNDI, you should opt to use JndiObjectFactoryBean. By using JndiObjectFactoryBean, you get all the benefits of DI and you don't have to write any lookup code whatsoever. By choosing one of the other options when you perform a lookup, you are losing the flexibility offered by DI and are needlessly coupling your component to JNDI—not to mention creating extra work for yourself.

For operations such as bind, rebind, and unbind, you can choose between JndiTemplate and InitialContext. We prefer to use JndiTemplate because it offers all the same features as InitialContext but also offers the ability to encapsulate reusable JNDI-related logic in command objects that implement JndiCallback. Listing 13-8 shows a simple example of this that performs a bulk lookup of messages from JNDI.

Listing 13-8: Using JndiCallback

image from book
package com.apress.prospring.ch13.jndi;      import javax.naming.Context; import javax.naming.NamingException;      import org.springframework.jndi.JndiCallback; import org.springframework.jndi.JndiTemplate;      public class BulkLookupBean {          private static final String MESSAGE1 = "java:/comp/env/message1";          private static final String MESSAGE2 = "java:/comp/env/message2";          private static final String MESSAGE3 = "java:/comp/env/message3";          private static final String MESSAGE4 = "java:/comp/env/message4";          public void doLookup() {         String[] names = new String[] { MESSAGE1, MESSAGE2, MESSAGE3, MESSAGE4 };                  JndiTemplate template = new JndiTemplate();              try {             String[] messages = (String[]) template                     .execute(new BulkLookupCallback(names));         } catch (NamingException ex) {             ex.printStackTrace();         }     }          private class BulkLookupCallback implements JndiCallback {              private String[] names;              public BulkLookupCallback(String[] names) {             this.names = names;         }              public Object doInContext(Context ctx) throws NamingException {             String[] messages = new String[names.length];                  for (int x = 0; x < names.length; x++) {                 messages[x] = (String) ctx.lookup(names[x]);             }                  return messages;         }     } }
image from book

Here you can see that we have created an implementation of JndiCallback that looks up a given set of JNDI names and returns a String[] that corresponds to the values stored under these names. InitialContext provides no functionality similar to this, so for complex JNDI operations, JndiTemplate provides a useful way to compartmentalize your code.



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

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