1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.ep.db4o.javassist;
18
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Modifier;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import javassist.CannotCompileException;
27 import javassist.ClassPool;
28 import javassist.CtClass;
29 import javassist.CtConstructor;
30 import javassist.CtField;
31 import javassist.CtMethod;
32 import javassist.CtNewMethod;
33 import net.ep.db4o.activator.TransparentActivation;
34 import net.ep.db4o.annotations.NoEnhancement;
35
36 import com.db4o.activation.ActivationPurpose;
37 import com.db4o.activation.Activator;
38 import com.db4o.internal.Platform4;
39 import com.db4o.reflect.ReflectClass;
40 import com.db4o.reflect.ReflectField;
41 import com.db4o.reflect.ReflectMethod;
42 import com.db4o.reflect.Reflector;
43 import com.db4o.reflect.core.ConstructorSupport;
44 import com.db4o.reflect.core.ReflectConstructor;
45 import com.db4o.reflect.core.ReflectConstructorSpec;
46 import com.db4o.reflect.jdk.JavaReflectClass;
47 import com.db4o.reflect.jdk.JdkConstructor;
48 import com.db4o.reflect.jdk.JdkMethod;
49 import com.db4o.reflect.jdk.JdkReflector;
50
51 @SuppressWarnings("unchecked")
52 public class JVSTClass implements JavaReflectClass {
53
54 public static final String ACTIVATOR_FIELD = "_activator";
55
56 private ReflectConstructorSpec _constructorSpec;
57
58
59
60 private final Class _enhancedClass;
61
62 private final Class _realClazz;
63
64 private final JVSTReflector _jVSTreflector;
65
66 private final Reflector _reflector;
67
68 private boolean _threadLocal;
69
70 private PersistOnMethodPolicy _persistPolicy;
71
72 private ActivateOnMethodPolicy _activatePolicy;
73
74 private boolean _ignoreNullActivator;
75
76 private static final boolean debug = false;
77
78 public JVSTClass(Reflector reflector, JVSTReflector jreflector,
79 ClassPool pool, Class clazz, boolean threadLocal, boolean ignoreNullActivator,
80 PersistOnMethodPolicy persistPolicy, ActivateOnMethodPolicy activatePolicy) {
81 if (reflector == null) {
82 throw new NullPointerException();
83 }
84 if (jreflector == null) {
85 throw new NullPointerException();
86 }
87 _jVSTreflector = jreflector;
88 _reflector = reflector;
89 _realClazz = clazz;
90 _threadLocal = threadLocal;
91 _ignoreNullActivator = ignoreNullActivator;
92 _persistPolicy = persistPolicy;
93 _activatePolicy = activatePolicy;
94 _constructorSpec = ReflectConstructorSpec.UNSPECIFIED_CONSTRUCTOR;
95 try {
96 CtClass cClass = pool.get(_realClazz.getName());
97 String ext = "TA$" + Long.toHexString(System.currentTimeMillis());
98 if (_threadLocal)
99 ext = "L" + ext;
100 if (_ignoreNullActivator)
101 ext = "I" + ext;
102 CtClass _extClass = pool.makeClass(_realClazz.getName() + "_" + ext, cClass);
103
104 CtField activatorField = null;
105 if (_threadLocal) {
106 activatorField = new CtField(pool.get("java.lang.ThreadLocal"),
107 ACTIVATOR_FIELD, _extClass);
108 _extClass.addField(activatorField);
109
110 } else {
111 activatorField = new CtField(pool.get(Activator.class.getName()),
112 ACTIVATOR_FIELD, _extClass);
113 _extClass.addField(activatorField);
114
115 }
116
117 _extClass.setSuperclass(cClass);
118 _extClass.addInterface(pool.get(TransparentActivation.class.getName()));
119 CtMethod bindMethod = null;
120 if (_threadLocal) {
121 bindMethod = CtNewMethod.make(
122 " public void bind(com.db4o.activation.Activator activator) { if ("
123 + ACTIVATOR_FIELD + " == null) " + ACTIVATOR_FIELD
124 + " = new ThreadLocal();" + ACTIVATOR_FIELD
125 + ".set(activator);}", _extClass);
126
127 } else {
128 bindMethod = CtNewMethod.make(
129 " public void bind(com.db4o.activation.Activator activator) { "
130 + ACTIVATOR_FIELD + " = activator;}", _extClass);
131
132 }
133 _extClass.addMethod(bindMethod);
134
135 List<String> extendedMethods = new ArrayList<String>();
136 enhanceMethods(cClass, _extClass, extendedMethods);
137
138 while (!cClass.getSuperclass().getName().startsWith("java")) {
139 cClass = cClass.getSuperclass();
140 enhanceMethods(cClass, _extClass, extendedMethods);
141 }
142 boolean hasPublic = false;
143 List<CtConstructor> consToDeclare = new ArrayList<CtConstructor>();
144 CtConstructor defaultCons = null;
145 for (CtConstructor cons : _extClass.getSuperclass()
146 .getDeclaredConstructors()) {
147 hasPublic = hasPublic
148 || javassist.Modifier.isPublic(cons.getModifiers());
149 if (javassist.Modifier.isProtected(cons.getModifiers())
150 || javassist.Modifier.isPublic(cons.getModifiers()))
151 consToDeclare.add(cons);
152 if (javassist.Modifier.isPublic(cons.getModifiers())
153 && cons.getParameterTypes() == null)
154 defaultCons = cons;
155 }
156 for (CtConstructor cons : consToDeclare) {
157 CtConstructor newCons = new CtConstructor(cons.getParameterTypes(),
158 _extClass);
159 newCons.setBody("super($$);");
160 newCons.setModifiers(javassist.Modifier.setPublic(cons.getModifiers()));
161 _extClass.addConstructor(newCons);
162 }
163 _extClass.makeClassInitializer();
164 _enhancedClass = _extClass.toClass();
165
166 _extClass.freeze();
167 } catch (Exception ex) {
168 ex.printStackTrace();
169 throw new RuntimeException("Error while enhancing "
170 + _realClazz.getName(), ex);
171 }
172 }
173
174 private void enhanceForActivation(CtClass cClass, CtClass extClass,
175 List<String> extendedMethods) throws CannotCompileException {
176 }
177
178 private void enhanceMethods(CtClass cClass, CtClass extClass,
179 List<String> extendedMethods) throws CannotCompileException {
180 enhanceForActivation(cClass, extClass, extendedMethods);
181 for (CtMethod method : cClass.getDeclaredMethods()) {
182 String methodID = method.getName() + "." + method.getSignature();
183
184
185
186
187
188
189 if (doEnhanceMethod(method) && !extendedMethods.contains(methodID)) {
190 CtMethod extMethod = CtNewMethod.delegator(method, extClass);
191 String activationPurpose = null;
192 if (_activatePolicy != null && _activatePolicy.doActivate(method)) {
193 activationPurpose = "READ";
194 }
195 if (_persistPolicy != null && _persistPolicy.doPersist(method)) {
196 activationPurpose = "WRITE";
197 }
198 if (activationPurpose != null) {
199 String debugCode = "System.out.println(\"activating "
200 + activationPurpose + " in " + method.getName()
201 + " activator: \" + " + ACTIVATOR_FIELD + " + \" \");";
202 String activatorGetterCode = ACTIVATOR_FIELD;
203 if (_threadLocal) {
204 activatorGetterCode = "((com.db4o.activation.Activator)"
205 + ACTIVATOR_FIELD + ".get())";
206 }
207 String testCode = "if (" + activatorGetterCode + " == null) throw new NullPointerException(\"Activator field not binded\");";
208 String activateCode = activatorGetterCode + ".activate("
209 + ActivationPurpose.class.getName() + "." + activationPurpose
210 + ");";
211 if (_ignoreNullActivator) {
212 testCode = "";
213 activateCode = "if (" + activatorGetterCode + " != null) {" + activateCode +" }" ;
214 }
215 if (debug)
216 extMethod.insertBefore("{ " + debugCode + testCode + activateCode + "}");
217 else
218 extMethod.insertBefore("{ " + testCode + activateCode + " }");
219
220 extClass.addMethod(extMethod);
221 extendedMethods.add(methodID);
222 }
223 }
224 }
225 }
226
227 public static boolean doEnhanceMethod(CtMethod method) {
228 int mods = method.getModifiers();
229 return !Modifier.isStatic(mods) && !Modifier.isNative(mods)
230 && !Modifier.isFinal(mods) && !Modifier.isAbstract(mods)
231 && !Tools.hasAnnotation(method, NoEnhancement.class);
232 }
233
234 public ReflectClass getComponentType() {
235 return _reflector.forClass(_realClazz.getComponentType());
236 }
237
238 private ReflectConstructor[] getDeclaredConstructors() {
239 try {
240 Constructor[] constructors = _enhancedClass.getDeclaredConstructors();
241 ReflectConstructor[] reflectors = new ReflectConstructor[constructors.length];
242 for (int i = 0; i < constructors.length; i++) {
243 reflectors[i] = new JdkConstructor(_reflector, constructors[i]);
244 }
245 return reflectors;
246 } catch (NoClassDefFoundError exc) {
247 return new ReflectConstructor[0];
248 }
249 }
250
251 public ReflectField getDeclaredField(String name) {
252
253 try {
254 return createField(_realClazz.getDeclaredField(name));
255 } catch (Exception e) {
256 return null;
257 } catch (NoClassDefFoundError e) {
258 return null;
259 }
260 }
261
262 private ReflectField createField(Field field) {
263 return new JVSTField(_reflector, field);
264 }
265
266 public ReflectField[] getDeclaredFields() {
267 try {
268 Field[] fields = _realClazz.getDeclaredFields();
269 ReflectField[] reflectors = new ReflectField[fields.length];
270 for (int i = 0; i < reflectors.length; i++) {
271 reflectors[i] = createField(fields[i]);
272 }
273 return reflectors;
274 } catch (NoClassDefFoundError exc) {
275 return new ReflectField[0];
276 }
277
278 }
279
280 public ReflectClass getDelegate() {
281 return this;
282 }
283
284 public Class getJavaClass() {
285 return _realClazz;
286 }
287
288 public ReflectMethod getMethod(String methodName, ReflectClass[] paramClasses) {
289 try {
290 Method method = _realClazz.getMethod(methodName, JVSTReflector
291 .toNative(paramClasses));
292 if (method == null) {
293 return null;
294 }
295 return new JdkMethod(method, reflector());
296 } catch (Exception e) {
297 return null;
298 }
299 }
300
301 public String getName() {
302 return _realClazz.getName();
303 }
304
305 public ReflectClass getSuperclass() {
306 return _jVSTreflector.forClass(_realClazz.getSuperclass());
307 }
308
309 public boolean isAbstract() {
310 return Modifier.isAbstract(_realClazz.getModifiers());
311 }
312
313 public boolean isArray() {
314 return _realClazz.isArray();
315 }
316
317 public boolean isAssignableFrom(ReflectClass type) {
318
319
320 return _realClazz.isAssignableFrom(JdkReflector.toNative(type));
321 }
322
323 public boolean isCollection() {
324 return _reflector.isCollection(this);
325 }
326
327 public boolean isInstance(Object obj) {
328 return _realClazz.isInstance(obj);
329 }
330
331 public boolean isInterface() {
332 return _realClazz.isInterface();
333 }
334
335 public boolean isPrimitive() {
336 return _realClazz.isPrimitive();
337 }
338
339 public Object newInstance() {
340 createConstructor();
341 return _constructorSpec.newInstance();
342 }
343
344 public Reflector reflector() {
345 return _jVSTreflector;
346 }
347
348 public Object[] toArray(Object obj) {
349 return null;
350 }
351
352 @Override
353 public String toString() {
354 return "Proxy class for " + _realClazz + " (" + _enhancedClass.getName() + ")";
355 }
356
357 public ReflectConstructor getSerializableConstructor() {
358 Constructor serializableConstructor = Platform4.jdk()
359 .serializableConstructor(_enhancedClass);
360 if (serializableConstructor == null) {
361 return null;
362 }
363 return new JdkConstructor(_reflector, serializableConstructor);
364 }
365
366 private void createConstructor() {
367 if (!_constructorSpec.canBeInstantiated().isUnspecified()) {
368 return;
369 }
370 _constructorSpec = ConstructorSupport.createConstructor(this,
371 _enhancedClass, _jVSTreflector.configuration(),
372 getDeclaredConstructors());
373 }
374
375 public boolean ensureCanBeInstantiated() {
376 createConstructor();
377 return !_constructorSpec.canBeInstantiated().definiteNo();
378 }
379
380 public Object nullValue() {
381 return _jVSTreflector.nullValue(this);
382 }
383
384 public Class getEnhancedClass() {
385 return _enhancedClass;
386 }
387
388 }