View Javadoc

1   package net.sf.jldapbeans.lang;
2   
3   import static org.apache.commons.lang.StringUtils.uncapitalize;
4   
5   import java.beans.PropertyChangeSupport;
6   import java.lang.reflect.Method;
7   
8   import net.sf.cglib.proxy.Callback;
9   import net.sf.cglib.proxy.CallbackHelper;
10  import net.sf.cglib.proxy.Enhancer;
11  import net.sf.cglib.proxy.MethodInterceptor;
12  import net.sf.cglib.proxy.MethodProxy;
13  import net.sf.cglib.proxy.NoOp;
14  import net.sf.jldapbeans.lang.annotation.LdapBean;
15  import net.sf.jldapbeans.lang.annotation.LdapModifier;
16  
17  import org.apache.commons.beanutils.DynaBean;
18  import org.apache.commons.beanutils.LazyDynaBean;
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  class LdapClassHelper extends CallbackHelper {
23  	
24  	private class GetProperty implements MethodInterceptor {
25  		private DynaBean m_facade;
26  		private String m_propertyName;
27  		
28  		public GetProperty(DynaBean backend, String propertyName) {
29  			if(backend == null) throw new NullPointerException("backend");
30  			m_facade = backend;
31  			m_propertyName = propertyName;
32  		}
33  		
34  		public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) 
35  		throws Throwable { 
36  			log.trace("Intercepting getter method for property [" + m_propertyName + "]");
37  			
38  			Object result = null;
39  			// Simple property
40  			if(args.length == 0)
41  				result = m_facade.get(m_propertyName);
42  			// Mapped property
43  			else if(args.length == 1 && args[0] instanceof String)
44  				result = m_facade.get(m_propertyName, (String) args[0]);
45  			// Indexed property
46  			else if(args.length == 1 && args[0].getClass() == Integer.TYPE)
47  				result = m_facade.get(m_propertyName, ((Integer) args[0]).intValue());
48  			if(result == null) throw new BeanProxyException(new NoSuchMethodException(m_propertyName));
49  			return result;
50  		}
51  		
52  	}
53  
54  	private class PropertyChangeSupportInterceptor implements MethodInterceptor {
55  	
56  		public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) 
57  		throws Throwable {
58  			proxy.invoke(m_propertyChangeSupport, args);
59  			return null;
60  		}
61  		
62  	}
63  	
64  	private enum PropertyKind { 
65  		INDEXED, MAPPED, SIMPLE 
66  	}
67  	
68  	private class SetProperty implements MethodInterceptor {
69  		private DynaBean m_facade;
70  		private String m_propertyName;
71  		
72  		public SetProperty(DynaBean backend, String propertyName) {
73  			if(backend == null) throw new NullPointerException("backend");
74  			m_facade = backend;
75  			m_propertyName = propertyName;
76  		}
77  		
78  		public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
79  		throws Throwable{
80  			log.trace("Intercepting setter method for property [" + m_propertyName + "]");
81  			
82  			Object oldValue = null;
83  			PropertyKind kind = null;
84  			
85  			// Simple property
86  			if(args.length == 1) {
87  				oldValue = m_facade.get(m_propertyName);
88  				m_facade.set(m_propertyName, args[0]);
89  				kind = PropertyKind.SIMPLE;
90  			}
91  			// Mapped property
92  			else if(args.length == 2 && args[0] instanceof String) {
93  				oldValue = m_facade.get(m_propertyName, (String) args[0]);
94  				m_facade.set(m_propertyName, (String) args[0], args[1]);
95  				kind = PropertyKind.MAPPED;
96  			}
97  			// Indexed property
98  			else if(args.length == 2 && args[0].getClass() == Integer.TYPE) {
99  				oldValue = m_facade.get(m_propertyName, (Integer) args[0]);
100 				m_facade.set(m_propertyName, (Integer) args[0], args[1]);
101 				kind = PropertyKind.INDEXED;
102 			}
103 			else throw new BeanProxyException("Property parameters not supported.");
104 			
105 			if(m_propertyChangeSupport != null)	 {
106 				if(kind.equals(PropertyKind.INDEXED))
107 					m_propertyChangeSupport.fireIndexedPropertyChange(
108 							m_propertyName, (Integer) args[0], oldValue, args[1]);
109 				else if(kind.equals(PropertyKind.MAPPED))
110 					m_propertyChangeSupport.fireIndexedPropertyChange(
111 							m_propertyName, ((String) args[0]).hashCode(), oldValue, args[1]);
112 				else m_propertyChangeSupport.firePropertyChange(m_propertyName, oldValue, args[0]);
113 			}
114 			
115 			return oldValue;
116 		}
117 		
118 	}
119 	
120 	private static final Log log = LogFactory.getLog(LdapClassHelper.class);
121 	
122 	protected static Object newInstance(LdapClass caller) 
123 	throws BeanInstantiationException {
124 		boolean found = false;
125 		for(Class<?> clazz : caller.getClasses()) { 
126 			if(clazz.getAnnotation(LdapBean.class).value().equals(LdapModifier.STRUCTURAL))
127 				found = true;
128 		}
129 		
130 		if(!found) 
131 			throw new BeanInstantiationException(caller, "LdapClass has not any STRUCTURAL objectClass!");
132 		
133 		log.trace("Instantiating a new LdapJB from LdapClass [" + caller.toString() + "]");
134 		
135 		try {
136 			LdapClassHelper helper = new LdapClassHelper(caller.getClasses());
137 			Enhancer enhancer = new Enhancer();
138 			enhancer.setSuperclass(helper.getSuperclass());
139 			enhancer.setInterfaces(caller.getClasses());
140 			enhancer.setCallbacks(helper.getCallbacks());
141 			enhancer.setCallbackTypes(helper.getCallbackTypes());
142 			enhancer.setCallbackFilter(helper);
143 			Object result = enhancer.create();
144 			helper.m_propertyChangeSupport = new PropertyChangeSupport(result);
145 			return result;
146 		}
147 		catch(Throwable t) {
148 			throw new BeanInstantiationException(caller, t);
149 		}
150 	}
151 	
152 	private DynaBean m_facade = null;
153 	
154 	private PropertyChangeSupport m_propertyChangeSupport;
155 	
156 	private LdapClassHelper(Class<?>[] interfaces) {
157 		super(LdapObject.class, interfaces);
158 	}
159 	
160 	protected Object getCallback(Method method) {
161 		Callback result = NoOp.INSTANCE;
162 		
163 		Class<?> declClass = method.getDeclaringClass();
164 		if(declClass.isAnnotationPresent(LdapBean.class)) {
165 			DynaBean facade = getFacade();
166 			if(method.getName().startsWith("get"))
167 				result = new GetProperty(facade, 
168 						uncapitalize(method.getName().substring("get".length())));
169 			else if(method.getName().startsWith("set"))
170 				result = new SetProperty(facade,
171 						uncapitalize(method.getName().substring("set".length())));
172 		}
173 		else {
174 			if(method.getName().equals("addPropertyChangeListener") ||
175 					method.getName().equals("removePropertyChangeListener"))
176 				result = new PropertyChangeSupportInterceptor();
177 		}
178 		
179 		log.trace("Found Callback type [" 
180 				+ result.getClass().getName() 
181 				+ "] for method name ["
182 				+ method.getName() 
183 				+ "] in LdapJB Class ["
184 				+ declClass.getName() + "]");
185 		
186 		return result;
187 	}
188 	
189 	protected DynaBean getFacade() {
190 		if(m_facade == null) 
191 			m_facade = new LazyDynaBean();
192 		return m_facade;
193 	}
194 	
195 	public Class<?> getSuperclass() {
196 		return LdapObject.class;
197 	}
198 	
199 }