View Javadoc

1   package net.sf.jldapbeans.lang;
2   
3   import java.beans.BeanInfo;
4   import java.beans.Introspector;
5   import java.beans.PropertyDescriptor;
6   import java.lang.reflect.Method;
7   import java.util.ArrayList;
8   import java.util.Enumeration;
9   import java.util.Hashtable;
10  import java.util.List;
11  import java.util.Vector;
12  
13  import javax.naming.Context;
14  import javax.naming.Name;
15  import javax.naming.NamingException;
16  import javax.naming.directory.Attribute;
17  import javax.naming.directory.Attributes;
18  import javax.naming.ldap.*;
19  import javax.naming.spi.DirObjectFactory;
20  
21  import net.sf.jldapbeans.lang.LdapClass;
22  import net.sf.jldapbeans.lang.annotation.*;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  /***
28   * The <code>LdapBeanFactory</code> is the entry point of the mechanism that retrieves
29   * an object from the LDAP directory, instantiates a java bean and fills its
30   * properties with the attribute values from the LDAP object.
31   * 
32   * @author <a href="mailto:alonsoft@users.sf.net">A. Alonso Domínguez</a>
33   * @version 1.0 $ Revision 01-nov-2005 :: alonso $
34   * 
35   * @see javax.naming.spi.DirObjectFactory
36   */
37  public class LdapBeanFactory implements DirObjectFactory {
38  	private static final Log log = LogFactory.getLog(LdapBeanFactory.class);
39  	
40  	/***
41  	 * Reads the <tt>objectClass</tt> attribute to get an array of strings
42  	 * 
43  	 * @param objectClass An instance of <tt>javax.naming.directory.Attribute</tt> which 
44  	 *                    represents the values of the <tt>objectClass</tt> attribute.
45  	 * @return An array of strings with the <tt>objectClass</tt> names.
46  	 * @throws NamingException
47  	 */
48  	protected String[] getObjectClasses(Attribute objectClass) throws NamingException {
49  		Vector<String> objClsVector = new Vector<String>();
50  		Enumeration<?> e = objectClass.getAll();
51  		while(e.hasMoreElements()) {
52  			String value = (String) e.nextElement();
53  			objClsVector.addElement(value);
54  		}
55  		return objClsVector.toArray(new String[objClsVector.size()]);
56  	}
57  	
58  	public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env) { return null; }
59  	
60  	/***
61  	 * Entry point from <code>DirObjectFactory</code> that starts the process of retrieving
62  	 * <code>LdapBean</code>s from the server.
63  	 * 
64  	 * @param obj Object received from the ldap server.
65  	 * @param name Name of the context
66  	 * @param ctx The <code>LdapContext</code> of the object
67  	 * @param env Actual environment
68  	 * @param attrs <code>Attributes</code> of the context
69  	 * @return A <code>LdapBean</code> initialized and ready to use
70  	 * @throws Exception
71  	 */
72  	public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env,
73  	Attributes attrs) throws Exception {
74  		if(!(ctx instanceof LdapContext)) return null;
75  		if(name.toString().equals("cn=Subschema")) return null;
76  		
77  		log.debug("Retrieving LdapBean for name [" + name + "]");
78  		String[] objectClass = getObjectClasses(attrs.get("objectClass"));
79  		
80  		LdapClass ldapClass = LdapClass.forName(objectClass);
81  		Object bean = ldapClass.newInstance();
82  		initialize(bean, attrs, ldapClass);
83  		((LdapObject) bean).contextualize(new LdapName(name.toString()), (LdapContext) ctx);
84  		return bean;
85  	}
86  	
87  	/***
88  	 * Initializes the bean properties from an instance of <tt>javax.naming.directory.Attributes</tt>.
89  	 * 
90  	 * @param bean The bean to be initialized
91  	 * @param attrs Attributes from LDAP directory to be set in the bean
92  	 * @param ldapClass The <tt>LdapClass</tt> of the bean. 
93  	 */
94  	private void initialize(Object bean, Attributes attrs, LdapClass ldapClass)
95  	throws Exception {
96  		// Remember the properties already initialized
97  		List<String> done = new ArrayList<String>();
98  		
99  		for(Class<?> clazz : ldapClass.getClasses()) {
100 			try {
101 				BeanInfo bi = Introspector.getBeanInfo(clazz);
102 				for(PropertyDescriptor property : bi.getPropertyDescriptors()) {
103 					// If we had already initialized this property then continue the loop
104 					if(done.contains(property.getName())) continue;
105 					
106 					Method read = property.getReadMethod(), write = property.getWriteMethod();
107 					
108 					if(!read.isAnnotationPresent(LdapAttribute.class)) continue;
109 					LdapAttribute ldapAttr = read.getAnnotation(LdapAttribute.class);
110 					
111 					// Now, we do a search through the different possible names of the attribute,
112 					// the process stop when the retrieved value from the LDAP directory is not null
113 					boolean propDone = false;
114 					for(String attrID : ldapAttr.name()) {
115 						if(propDone) break;
116 						
117 						if(attrID.equals("[undefined]")) attrID = property.getName();
118 						Attribute attr = attrs.get(attrID);
119 						// If attribute id is not found continue, (may show a warn message) 
120 						if(attr == null) continue;
121 						
122 						// Moment to retrieve the LdapAttribute's value
123 						Object value = null;
124 						if(!LdapModifier.isSingleValue(ldapAttr.value())) {
125 							List<Object> valueList = new ArrayList<Object>();
126 							Enumeration<?> e = attr.getAll();
127 							while(e.hasMoreElements())
128 								valueList.add(e.nextElement());
129 							value = valueList;
130 						}
131 						else value = attr.get();
132 						
133 						// If we got a not null value, then initialize the corresponding property
134 						if(value != null) {
135 							log.debug("Initializing property [" + property.getName() 
136 									+ "] with value [" + value + "]");
137 							write.invoke(bean, new Object[]{ value });
138 							done.add(property.getName());
139 							propDone = true;
140 						}
141 					}
142 					
143 					if(!propDone)
144 						log.warn("Property not initialized [" + property.getName() + "]");
145 				}
146 			}
147 			catch(Exception e) {
148 				log.fatal("Unexpected exception intializing LDAP Bean class [" + clazz + "]", e);
149 				throw e;
150 			}
151 		}
152 	}
153 		
154 }