View Javadoc

1   package org.lsst.ccs.utilities.beanutils;
2   
3   import java.lang.reflect.Constructor;
4   import java.lang.reflect.Method;
5   import java.util.ArrayList;
6   import java.util.HashMap;
7   import java.util.LinkedHashMap;
8   import java.util.List;
9   
10  /**
11   * Super classes of all Bean "proxies" : that is class the offer a bean "vision"
12   * of a non-bean class.
13   * @author bamade
14   */
15  public abstract class BeanProxyFor<T> implements BeanFor<T> {
16  
17      protected class ProxyAgent {
18          class Descriptor {
19              boolean get;
20              boolean set;
21              boolean assigned;
22              Method setMethod;
23              Method getMethod;
24              Object value;
25              public String toString(){
26                  return "get=" + get
27                          + ";set=" + set
28                          + ";assigned=" + assigned
29                          + (set? ";" + setMethod.getName(): "")
30                          + (get? ";" + getMethod.getName(): "") ;
31  
32              }
33          }
34  
35          //TODO: put in a cache!
36          HashMap<String, Descriptor> delegateMethods = new HashMap<String, Descriptor>();
37          LinkedHashMap<String, Descriptor> ctorArgs = new LinkedHashMap<String, Descriptor>();
38          Constructor<T> minimumCtor;
39          int nbArgsCtor;
40          int nbArgsSet;
41  
42          ProxyAgent() {
43              String beanName = BeanProxyFor.this.getClass().getCanonicalName();
44              String className = beanName.replace("Bean", "");
45              try {
46                  Class klass = Class.forName(className);
47                  // first we scan the get and set of the object
48                  Method[] methods = klass.getMethods();
49                  for (Method method : methods) {
50                      String name = method.getName();
51                      if (name.startsWith("set")) {
52                          String propertyName = name.replace("set", "").toLowerCase();
53                          Descriptor descriptor = delegateMethods.get(propertyName);
54                          if (descriptor == null) {
55                              descriptor = new Descriptor();
56                              delegateMethods.put(propertyName, descriptor);
57                          }
58                          descriptor.set = true;
59                          descriptor.setMethod = method;
60  
61                      } else if (name.startsWith("get")) {
62                          String propertyName = name.replace("get", "").toLowerCase();
63                          Descriptor descriptor = delegateMethods.get(propertyName);
64                          if (descriptor == null) {
65                              descriptor = new Descriptor();
66                              delegateMethods.put(propertyName, descriptor);
67                          }
68                          descriptor.get = true;
69                          descriptor.getMethod = method;
70                      }
71                  }
72                  //TODO: create bogus
73                  Constructor[] constructors = klass.getConstructors();
74                  for (Constructor constructor : constructors) {
75                      CriticalCtor minimumDesc = (CriticalCtor) constructor.getAnnotation(CriticalCtor.class);
76                      if (minimumDesc != null) {
77                          this.minimumCtor = constructor;
78                          String[] names = minimumDesc.value();
79                          this.nbArgsCtor = names.length;
80                          ctorArgs = new LinkedHashMap<String, Descriptor>(this.nbArgsCtor);
81                          for (String name : names) {
82                              Descriptor descriptor = new Descriptor();
83                              descriptor.set = descriptor.get = true;
84                              ctorArgs.put(name.toLowerCase(), descriptor);
85                          }
86                          return; //!!!!!!
87                      }
88                      //TODO: check what if no critical Ctor?
89                  }
90                  // then we create bogus get/set just for the bean and for use by minimum constructor
91              } catch (RuntimeException exc) {
92                  throw exc;
93              } catch (Exception e) {
94                  throw new WrappedException(e);
95              }
96              //System.out.println(className);
97          }
98  
99          /**
100          * if all arguments in ctorArgs have been set then creates the delegate
101          *
102          * @return
103          */
104 
105         private boolean checkForDelegateCreation() {
106             if (delegate != null) return false;
107             if (nbArgsCtor == nbArgsSet) {
108                 List<Object> listArgs = new ArrayList<Object>(nbArgsCtor);
109                 for (Descriptor desc : ctorArgs.values()) {
110                     listArgs.add(desc.value);
111                 }
112                 Object[] args = listArgs.toArray();
113                 try {
114                     delegate = minimumCtor.newInstance(args);
115                     for (Descriptor descriptor : delegateMethods.values()) {
116                     //System.out.println("-> " + descriptor);
117                         if (descriptor.assigned && descriptor.set) {
118                             try {
119                                 descriptor.setMethod.invoke(delegate, descriptor.value);
120                             } catch (Exception exc) {
121                                 throw new WrappedBeanMethodInvocationException(
122                                         exc, descriptor.setMethod, descriptor.value);  //CHANGE and get Logger
123                             }
124                         }
125                     }
126                 } catch (RuntimeException e) {
127                     throw e ;
128                 } catch (Exception e) {
129                     throw new WrappedBeanMethodInvocationException(e, minimumCtor, args);  //CHANGE and get Logger
130                 }
131                 return true;
132             }
133             return false;
134         }
135 
136         /**
137          * will consult ctorArgs:
138          * if present and object not created -> assigns value
139          * if all assigned create object
140          * <p/>
141          * consuls delegate methods
142          * -> if present and object created -> forwards value
143          * -> if present and not ctorArgs and not created -> assigns locally
144          * -> else fails
145          *
146          * @param proptyName
147          * @param value
148          */
149         public void setProperty(String proptyName, Object value) {
150             methodsCalled = true;
151             String propertyName = proptyName.toLowerCase();
152             Descriptor descriptor;
153             if (delegate == null) {
154                 // is it known as  a ctor argument?
155                 descriptor = ctorArgs.get(propertyName);
156                 if (descriptor != null) {
157                     // if yes then
158                     descriptor.value = value;
159                     if (!descriptor.assigned) this.nbArgsSet++;
160                     descriptor.assigned = true;
161                     // we try to create the object
162                     boolean created = checkForDelegateCreation();
163                     if (created) return;
164                 } else {
165                     descriptor = delegateMethods.get(propertyName);
166                     if (descriptor != null) {
167                         descriptor.value = value;
168                         descriptor.assigned = true;
169                     } else {
170                         throw new UnsupportedOperationException("set" + proptyName);
171                     }
172                 }
173 
174             } else { //object has been created
175                 descriptor = delegateMethods.get(propertyName);
176                 if ((descriptor != null) && descriptor.set) {
177                     try {
178                         descriptor.setMethod.invoke(delegate, value);
179                     } catch (Exception e) {
180                         throw new WrappedBeanMethodInvocationException(e, descriptor.setMethod, value);
181                     }
182                 } else {
183                     throw new UnsupportedOperationException("set" + proptyName);
184                 }
185 
186             }
187         }
188 
189         public Object getProperty(String proptyName) {
190             methodsCalled = true;
191             String propertyName = proptyName.toLowerCase();
192 
193             Descriptor descriptor;
194             if (delegate == null) {
195                 descriptor = ctorArgs.get(propertyName);
196                 if ((descriptor != null) && descriptor.get) { //get always true! bu who knows?
197                     return descriptor.value;
198                 } else { //superfluous but clearer!
199                     descriptor = delegateMethods.get(propertyName);
200                     if ((descriptor != null) && descriptor.get) { //get always true! bu who knows?
201                         return descriptor.value;
202                     } else {
203                         throw new UnsupportedOperationException("get" + proptyName);
204                     }
205                 }
206 
207             } else {// object exists
208                 descriptor = delegateMethods.get(propertyName);
209                 if ((descriptor != null) && descriptor.get) { //get always true! bu who knows?
210                     try {
211                         return descriptor.getMethod.invoke(delegate);
212                     } catch (Exception e) {
213                         throw new WrappedBeanMethodInvocationException(e, descriptor.getMethod);
214                     }
215                 } else {
216                     throw new UnsupportedOperationException("get" + proptyName);
217                 }
218             }
219             //return null ;
220         }
221     }
222 
223 
224     protected final ProxyAgent agent;
225     protected T delegate;
226     protected boolean methodsCalled;
227 
228     public BeanProxyFor() throws WrappedException {
229         agent = new ProxyAgent();
230     }
231 
232     public BeanProxyFor(T delegate) throws WrappedException {
233         this.delegate = delegate;
234         agent = new ProxyAgent();
235     }
236 
237     public T get() {
238         return this.delegate;
239     }
240 
241 }