Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

POJO-Based Solutions for LDAP Access: One Good, One Better : Page 2

Find out how to employ dependency injection, annotation, and aspect-oriented programming to enable POJO-based application development.


advertisement

Solution 1. Spring LDAP-Enabled

The next step is to read the data from the applications. The data access object (DAO) defines the abstraction for reading the configuration data:

public interface PropertyDAO { Object getProperty(String[] key, PropertyType type); }

For LDAP stored properties, the search key specifies the ordered list of CNs that uniquely identifies a particular LDAP entry. PropertyType is an enumeration of various return types that the calling application client expects of the property values.



The Java API for accessing LDAP suffers from similar shortcomings as JDBC. It forces you to deal with many mundane, low-level details. Spring LDAP, following a similar objective as Spring JDBC, simplifies the API by raising the abstraction level; it translates low-level checked exceptions into higher-level, Spring LDAP-defined runtime exceptions.

In this example, the LdapPropertyDAOImpl class implements the DAO interface using Spring LDAP (See Listing 1. DAO Implementation). LdapTemplate is the key class provided by Spring LDAP. The lookup method expects two parameters. The first is the DN, the second is an AttributesMapper that maps from LDAP attributes to the expected configuration data type. ATTRIBUTE_TYPE specifies the LDAP data schema.

The TypeConverter class uses Java reflection to convert String types to various Java built-in types:

public class TypeConverter { public static Object fromStringTo(PropertyType type, String value) { try { if (PropertyType.STRING.equals(type)) { return value; } else { Class<?> c = Class.forName((type.getFQCN())); Method m = c.getMethod("valueOf", String.class); Object obj = m.invoke(null, value); m = obj.getClass().getMethod(type.getPrimitiveType() + "Value"); return m.invoke(obj, (Object[])null); } } catch (Exception e) { throw new RuntimeException(e); } } public static Collection toStringCollection(Attribute attr) throws NamingException { return Collections.list(attr.getAll()); } }

You can add support for additional types such as Date if needed. The changes would be isolated to TypeConverter and PropertyType. This implementation handles only collections of type String. To work with collections of other types, you need to pass an extra parameter specifying the collection element type in the calling client application. The reason for this, as explained by the Java Tutorials, is that generics are implemented using type erasure—a process where the compiler removes the type parameters and type arguments information within a class or method.

The Account class demonstrates how to call the DAO to retrieve a configurable threshold value through LDAP:

public class Account { public void businessLogicUsingThreshold() { long threshold = getThreshold(); // business logic using the threshold ... } long getThreshold() { String[] key = new String[] { "dc", "com", "dc", "my-domain", "cn", "app1", "cn", "threshold"}; return ((Long)dao.getProperty(key, PropertyType.LONG)).longValue(); } public void setDao(PropertyDAO dao) { this.dao = dao; } private PropertyDAO dao; }

The getThreshold() implementation invokes the DAO's getProperty method to retrieve a property value of primitive type long. The first parameter is the LDAP property key, constructed with an array of Strings specifying the ordered list of CN that uniquely identifies the node in the LDAP tree. The second parameter indicates that the expected return type is long. Because the DAO interface returns the generic Object type, the return needs to be cast to the expected type.

This is a fairly good solution (see Figure 2 for class diagrams). There is a clear separation between the interface and the implementation, so that a different implementation—for example, one based on property files—can be substituted without affecting the client. The LDAP DAO implementation delegates to Spring LDAP's LdapTemplate class to handle low-level LDAP access details, which simplifies the implementation. For frequently accessed data such as various logging levels, you could improve the read performance by introducing caching at the DAO implementation level. An existing caching library, such as ehcache, provides flexible and high-performance caching.

Figure 2. Class Diagrams for Solution 1: Here are the major components that implement the DAO pattern, based on Spring LDAP.

Spring's DI feature makes the dependency on the DAO simply a property of the Account class. The Spring container handles the lifecycle of the DAO, which frees the Account class from the responsibilities of directly instantiating the DAO. This approach also removes the dependency on any particular DAO implementation. Because you can easily substitute different implementations, stubbing and mock-based unit testing are easier. Spring manages the LdapDAOImpl class's dependency on LdapTemplate in a similar fashion.

The Spring configuration specifies the dependency of Account on the DAO implementation, which in turn depends on LdapTemplate:

<beans> <bean id="account" class="Account"> <property name="dao"> <bean class="com.company.ldap.LdapPropertyDAOImpl"> <property name="ldapTemplate"> <bean class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource"/> </bean> </property> </bean> </property> </bean> … </beans>



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap