View Javadoc

1   /*
2    * Copyright (C) 2003-2012 David E. Berry
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17   *
18   * A copy of the GNU Lesser General Public License may also be found at
19   * http://www.gnu.org/licenses/lgpl.txt
20   */
21  package org.synchronoss.cpo.meta.domain;
22  
23  import org.slf4j.*;
24  import org.synchronoss.cpo.*;
25  import org.synchronoss.cpo.helper.*;
26  import org.synchronoss.cpo.meta.CpoMetaDescriptor;
27  import org.synchronoss.cpo.meta.bean.CpoAttributeBean;
28  import org.synchronoss.cpo.transform.CpoTransform;
29  
30  import java.lang.reflect.*;
31  import java.util.*;
32  
33  public class CpoAttribute extends CpoAttributeBean {
34  
35    private static final Logger logger = LoggerFactory.getLogger(CpoAttribute.class);
36    protected static final String TRANSFORM_IN_NAME = "transformIn";
37    protected static final String TRANSFORM_OUT_NAME = "transformOut";
38    private String getterName_ = null;
39    private String setterName_ = null;
40    private Method getter_ = null;
41    private Method setter_ = null;
42    
43    //Transform attributes
44    private CpoTransform cpoTransform = null;
45    private Method transformInMethod = null;
46    private Method transformOutMethod = null;
47  
48    public CpoAttribute() {
49    }
50  
51    public CpoTransform getCpoTransform() {
52      return cpoTransform;
53    }
54  
55    public Method getTransformInMethod() {
56      return transformInMethod;
57    }
58  
59    public Method getTransformOutMethod() {
60      return transformOutMethod;
61    }
62  
63    public Class getSetterParamType() {
64      return getter_.getReturnType();
65    }
66   
67    public Class getGetterReturnType() {
68      return getter_.getReturnType();
69     }
70    
71    protected Method getGetter() {
72      return getter_;
73    }
74  
75    protected Method getSetter() {
76      return setter_;
77    }
78  
79    protected void setGetter(Method getter) {
80      getter_ = getter;
81    }
82  
83    protected void setSetter(Method setter) {
84      setter_ = setter;
85    }
86  
87    protected String getGetterName() {
88      return getterName_;
89    }
90  
91    protected String getSetterName() {
92      return setterName_;
93    }
94  
95    protected void setGetterName(String getterName) {
96      getterName_ = getterName;
97    }
98  
99    protected void setSetterName(String setterName) {
100     setterName_ = setterName;
101   }
102 
103   protected List<Method> findMethods(Class clazz, String methodName, int args, boolean hasReturn) throws CpoException {
104     List<Method> retMethods = new ArrayList<Method>();
105 
106     try {
107       Method[] methods = clazz.getMethods();
108 
109       // go through once and find the accessor methods that match the method name
110       for (Method m : methods) {
111         // The method name must match as well as the number of parameters and return types
112         if (!m.isSynthetic() && !m.isBridge() && m.getName().equals(methodName) && m.getParameterTypes().length == args) {
113           if ((!hasReturn && m.getReturnType() == java.lang.Void.TYPE) || (hasReturn && m.getReturnType() != java.lang.Void.TYPE)) {
114             retMethods.add(m);
115           }
116         }
117       }
118     } catch (Exception e) {
119       throw new CpoException("findMethod() Failed - Method Not Found: " + methodName);
120     }
121     return retMethods;
122   }
123 
124   protected String buildMethodName(String prefix, String base) {
125 
126     StringBuilder methodName = new StringBuilder();
127     methodName.append(prefix);
128     methodName.append(base);
129     methodName.setCharAt(3, Character.toUpperCase(methodName.charAt(3)));
130 
131     return methodName.toString();
132   }
133 
134   public void invokeSetter(Object instanceObject, CpoData cpoData) throws CpoException {
135     Logger localLogger = instanceObject == null ? logger : LoggerFactory.getLogger(instanceObject.getClass());
136 
137     try {
138       setter_.invoke(instanceObject, cpoData.invokeGetter());
139     } catch (IllegalAccessException iae) {
140       localLogger.debug("Error Invoking Setter Method: " + ExceptionHelper.getLocalizedMessage(iae));
141     } catch (InvocationTargetException ite) {
142       localLogger.debug("Error Invoking Setter Method: " + ExceptionHelper.getLocalizedMessage(ite));
143     }
144     
145   }
146 
147   public Object invokeGetter(Object obj) throws CpoException {
148     Logger localLogger = obj == null ? logger : LoggerFactory.getLogger(obj.getClass());
149 
150     try {
151       return getGetter().invoke(obj, (Object[])null);
152     } catch (IllegalAccessException iae) {
153       localLogger.debug("Error Invoking Getter Method: " + ExceptionHelper.getLocalizedMessage(iae));
154     } catch (InvocationTargetException ite) {
155       localLogger.debug("Error Invoking Getter Method: " + ExceptionHelper.getLocalizedMessage(ite));
156     }
157 
158     throw new CpoException("invokeGetter: Could not find a Getter for " + obj.getClass());
159   }
160 
161   private void dumpMethod(Method m) {
162     logger.debug("========================");
163     logger.debug("===> Declaring Class: " + m.getDeclaringClass().getName());
164     logger.debug("===> Method Signature: " + m.toString());
165     logger.debug("===> Generic Signature: " + m.toGenericString());
166     logger.debug("===> Method isBridge: " + m.isBridge());
167     logger.debug("===> Method isSynthetic: " + m.isSynthetic());
168     logger.debug("========================");
169   }
170 
171   static public boolean isPrimitiveAssignableFrom(Class clazz, Class paramClass) {
172 
173     // check to see if one is primitive and one is a possible wrapper
174     if (clazz.isPrimitive() ^ paramClass.isPrimitive()) {
175       // identify the prim and the wrapper
176       Class primClass, objClass;
177       if (clazz.isPrimitive()) {
178         primClass = clazz;
179         objClass = paramClass;
180       } else {
181         primClass = paramClass;
182         objClass = clazz;
183       }
184 
185       // Lets do a quick name check
186       if (objClass.getSimpleName().toLowerCase().startsWith(primClass.getSimpleName())) {
187         // go through the constructors of the wrapper to see if there one with a parameter type
188         // that is the same as the primitive
189         for (Constructor ctor : objClass.getConstructors()) {
190           Class[] types = ctor.getParameterTypes();
191           if (types.length > 0 && types[0].isAssignableFrom(primClass)) {
192             return true;
193           }
194         }
195       } else {
196         logger.debug("Wrapper Class:" + objClass.getName().toLowerCase() + "does not start with " + primClass.getName());
197       }
198     }
199 
200     return false;
201   }
202 
203   public void loadRunTimeInfo(CpoMetaDescriptor metaDescriptor, CpoClass cpoClass) throws CpoException {
204     StringBuilder failedMessage = new StringBuilder();
205     setGetterName(buildMethodName("get", getJavaName()));
206     setSetterName(buildMethodName("set", getJavaName()));
207 
208     try {
209       initTransformClass(metaDescriptor);
210     } catch (Exception ce2) {
211       failedMessage.append(ce2.getMessage());
212     }
213     if (cpoClass != null) {
214       try {
215         List<Method> methods = findMethods(cpoClass.getMetaClass(), getGetterName(), 0, true);
216         if (methods.isEmpty()){
217           failedMessage.append("loadRunTimeInfo: Could not find a Getter:" + getGetterName() + "(" + cpoClass.getName() + ")");
218         } else {
219           setGetter(methods.get(0));
220         }
221       } catch (CpoException ce1) {
222         failedMessage.append(ce1.getMessage());
223       }
224       try {
225         Class actualClass = getGetterReturnType();
226 
227         for (Method setter : findMethods(cpoClass.getMetaClass(), getSetterName(), 1, false)) {
228           if (setter.getParameterTypes()[0].isAssignableFrom(actualClass) || isPrimitiveAssignableFrom(setter.getParameterTypes()[0], actualClass)) {
229             setSetter(setter);
230           }
231         }
232         if (getSetter()==null){
233           failedMessage.append("loadRunTimeInfo: Could not find a Setter:" + getSetterName() + "(" + actualClass.getName() + ")");
234         }
235       } catch (Exception ce2) {
236         failedMessage.append(ce2.getMessage());
237       }
238     }
239     if (failedMessage.length() > 0) {
240       throw new CpoException(failedMessage.toString());
241     }
242   }
243 
244   protected void initTransformClass(CpoMetaDescriptor metaDescriptor) throws CpoException {
245     String className = getTransformClassName();
246     Class<?> transformClass = null;
247     Logger localLogger = className == null ? logger : LoggerFactory.getLogger(className);
248 
249     if (className != null && className.length() > 0) {
250       try {
251         transformClass = CpoClassLoader.forName(className);
252       } catch (Exception e) {
253         localLogger.error("Invalid Transform Class specified:<" + className + ">");
254         throw new CpoException("Invalid Transform Class specified:<" + className + ">:");
255       }
256 
257       Object transformObject;
258       try {
259         transformObject = transformClass.newInstance();
260       } catch (Exception e) {
261         localLogger.debug("Error Setting Transform Class: " + ExceptionHelper.getLocalizedMessage(e));
262         throw new CpoException(e);
263       }
264 
265       if (transformObject instanceof CpoTransform) {
266         cpoTransform = (CpoTransform)transformObject;
267         List<Method> methods = findMethods(transformClass, TRANSFORM_IN_NAME, 1, true);
268         if (methods.size() > 0) {
269           transformInMethod = methods.get(0);
270         }
271         methods = findMethods(transformClass, TRANSFORM_OUT_NAME, 1, true);
272         if (methods.size() > 0) {
273           transformOutMethod = methods.get(0);
274         }
275       } else {
276         localLogger.error("Invalid CpoTransform Class specified:<" + className + ">");
277         throw new CpoException("Invalid CpoTransform Class specified:<" + className + ">");
278       }
279     }
280   }
281 
282   @Override
283   public String toString() {
284     return this.getJavaName();
285   }
286 
287   public String toStringFull() {
288     return super.toString();
289   }
290 }