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
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
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
112
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
120 if(attr == null) continue;
121
122
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
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 }