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
40 if(args.length == 0)
41 result = m_facade.get(m_propertyName);
42
43 else if(args.length == 1 && args[0] instanceof String)
44 result = m_facade.get(m_propertyName, (String) args[0]);
45
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
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
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
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 }