1
2
3
4
5
6
7 package org.weda.enhance.impl;
8
9 import java.lang.reflect.Method;
10 import java.util.Collection;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import net.sf.cglib.proxy.Callback;
18 import net.sf.cglib.proxy.CallbackFilter;
19 import net.sf.cglib.proxy.Enhancer;
20 import net.sf.cglib.proxy.Factory;
21 import net.sf.cglib.proxy.MethodInterceptor;
22 import net.sf.cglib.proxy.MethodProxy;
23 import net.sf.cglib.proxy.NoOp;
24 import org.apache.hivemind.schema.Translator;
25 import org.weda.enhance.HivemindObjectProvider;
26 import org.weda.enhance.ObjectEnhancer;
27 import org.weda.enhance.ObjectEnhancerException;
28 import org.weda.enhance.InjectObject;
29
30 /**
31 *
32 * @author Mikhail Titov
33 */
34 public class ObjectEnhancerImpl
35 implements ObjectEnhancer, MethodInterceptor
36 {
37 public static ObjectEnhancer INSTANCE = null;
38
39 private final static int NOOP_CALLBACK_INDEX = 1;
40 private final static int SERVICE_CALLBACK_INDEX = 0;
41
42 private Map<Method, EnhancedMethod> enhancedMethods =
43 new HashMap<Method, EnhancedMethod>();
44 private Set<Class> enhancedClasses = new HashSet<Class>();
45 private final Callback[] callbacks = new Callback[]{this, NoOp.INSTANCE};
46 private final Class[] callbackTypes =
47 new Class[]{this.getClass(), NoOp.class};
48 private HivemindObjectProvider objectProvider;
49
50 public void init(){
51 INSTANCE = this;
52 }
53
54 public synchronized Class enhanceClass(Class clazz)
55 throws ObjectEnhancerException
56 {
57 Class enhancedClass = clazz;
58 Set<Method> methods = new HashSet<Method>();
59 for (Method method: clazz.getMethods()){
60 InjectObject injectObject =
61 method.getAnnotation(InjectObject.class);
62 if (injectObject!=null){
63 if ( method.getParameterTypes().length==0
64 && !method.getReturnType().equals(Void.class))
65 {
66 EnhancedMethod info = new EnhancedMethod();
67 String objectRef = injectObject.value();
68 if (objectRef==null || objectRef.length()==0)
69 objectRef = "service:"+method.getReturnType().getName();
70 info.setCacheValue(injectObject.cacheValue());
71 info.setObjectReference(objectRef);
72 enhancedMethods.put(method, info);
73 methods.add(method);
74 }else
75 throw new ObjectEnhancerException(
76 String.format(
77 "Can't enhance method (%s) of class (%s) " +
78 "because of method has parameters " +
79 "or void result type."
80 , method.getName(), clazz.getName()));
81 }
82 }
83 if (methods.size()>0){
84 Enhancer enhancer = new Enhancer();
85 enhancer.setSuperclass(clazz);
86 enhancer.setCallbackFilter(new Filter(methods));
87 enhancer.setCallbackTypes(callbackTypes);
88 enhancedClass = enhancer.createClass();
89 enhancedClasses.add(enhancedClass);
90 }
91 return enhancedClass;
92 }
93
94 public Object newInstance(Class clazz) throws ObjectEnhancerException {
95 try{
96 Object obj = clazz.newInstance();
97 initObject(obj);
98 return obj;
99 }catch(Exception e){
100 throw new ObjectEnhancerException(
101 String.format(
102 "Can't create instance of class (%s)", clazz.getName())
103 , e);
104 }
105 }
106
107 public void initObject(Object object) throws ObjectEnhancerException {
108 if (enhancedClasses.contains(object.getClass()))
109 ((Factory)object).setCallbacks(callbacks);
110 }
111
112 public Object intercept(
113 Object object, Method method, Object[] object0
114 , MethodProxy methodProxy)
115 throws Throwable
116 {
117 EnhancedMethod info = enhancedMethods.get(method);
118 if (info.isCacheValue() && info.isValueCached())
119 return info.getValue();
120 else{
121 Object value =
122 objectProvider.getObject(
123 info.getObjectReference(), null);
124 if (info.isCacheValue())
125 info.setValue(value);
126 return value;
127 }
128 }
129
130 private static class Filter implements CallbackFilter {
131 private Set<Method> methods;
132
133 public Filter(Set<Method> methods){
134 this.methods = methods;
135 }
136
137 public int accept(Method method) {
138 return methods.contains(method)
139 ? SERVICE_CALLBACK_INDEX : NOOP_CALLBACK_INDEX;
140 }
141 }
142
143 private static class EnhancedMethod {
144 private boolean cacheValue;
145 private Object value;
146 private String objectReference;
147 private boolean valueCached;
148
149 public Object getValue() {
150 return value;
151 }
152
153 public void setValue(Object value) {
154 this.value = value;
155 valueCached = true;
156 }
157
158 public boolean isCacheValue() {
159 return cacheValue;
160 }
161
162 public void setCacheValue(boolean cacheValue) {
163 this.cacheValue = cacheValue;
164 }
165
166 public String getObjectReference() {
167 return objectReference;
168 }
169
170 public void setObjectReference(String objectReference) {
171 this.objectReference = objectReference;
172 }
173
174 public boolean isValueCached() {
175 return valueCached;
176 }
177
178 }
179
180 public void setObjectProvider(HivemindObjectProvider objectProvider) {
181 this.objectProvider = objectProvider;
182 }
183 }