View Javadoc

1   /*
2    * DefaultObjectEnchancer.java
3    *
4    * Created on 9 Май 2006 г., 3:04
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 }