001 /* 002 * Vestigo - The JDO/JPA Query Tool And Browser - http://vestigo.nightlabs.com 003 * Copyright © 2011-2012 NightLabs Consulting GmbH. All rights reserved. 004 * 005 * This program and all its libraries in the namespace "*.nightlabs.vestigo.*" 006 * are proprietary software. Their source codes are trade secrets and therefore 007 * must be kept confidential. 008 * 009 * The use of this software is subject to licence terms. 010 * 011 * Please see LICENCE.txt or 012 * http://vestigo.nightlabs.com/latest-stable/about/licence.html for 013 * more details. 014 * 015 * For further information, please contact NightLabs Consulting GmbH: 016 * http://nightlabs.com 017 */ 018 package org.cumulus4j.store.reflectionwrapper; 019 020 import java.lang.reflect.InvocationTargetException; 021 import java.lang.reflect.Method; 022 import java.util.Collections; 023 import java.util.HashMap; 024 import java.util.Map; 025 026 public abstract class ReflectionWrapper 027 { 028 private ClassLoader classLoader; 029 private volatile Class<?> wrappedClass; 030 private volatile Object wrappedObject; 031 032 public ReflectionWrapper(ClassLoader classLoader) 033 { 034 if (classLoader == null) 035 throw new IllegalArgumentException("classLoader == null"); 036 037 this.classLoader = classLoader; 038 } 039 040 public ReflectionWrapper(ReflectionWrapper persistenceEngineWrapper, Object wrappedObject) { 041 if (persistenceEngineWrapper == null) 042 throw new IllegalArgumentException("persistenceEngineWrapper == null"); 043 044 this.classLoader = persistenceEngineWrapper.getClassLoader(); 045 this.wrappedObject = wrappedObject; 046 if (wrappedObject != null) 047 wrappedClass = wrappedObject.getClass(); 048 } 049 050 protected ClassLoader getClassLoader() { 051 return classLoader; 052 } 053 054 protected String getWrappedClassName() 055 { 056 Class<?> clazz = wrappedClass; 057 if (clazz != null) 058 return clazz.getName(); 059 else 060 throw new UnsupportedOperationException("Lazy creation not implemented! The wrappedObject should have been created eagerly or this method should have been overridden!"); 061 } 062 063 public Class<?> getWrappedClass() 064 { 065 Class<?> clazz = wrappedClass; 066 if (clazz == null) { 067 try { 068 clazz = Class.forName(getWrappedClassName(), true, getClassLoader()); 069 } catch (ClassNotFoundException e) { 070 throw new ReflectionWrapperException(e); 071 } 072 wrappedClass = clazz; 073 } 074 return clazz; 075 } 076 077 protected Object createWrappedObject(Class<?> wrappedClass) 078 { 079 throw new UnsupportedOperationException("Lazy creation not implemented! The wrappedObject should have been created eagerly or this method should have been overridden!"); 080 } 081 082 public Object getWrappedObject() 083 { 084 Object object = wrappedObject; 085 if (object == null) { 086 Class<?> wrappedClass = getWrappedClass(); 087 synchronized (this) { 088 object = wrappedObject; 089 if (object == null) { 090 object = createWrappedObject(wrappedClass); 091 wrappedObject = object; 092 } 093 } 094 } 095 return object; 096 } 097 098 private Map<Integer, Method> methodID2Method = Collections.synchronizedMap(new HashMap<Integer, Method>()); 099 100 protected Object invokeStatic(int methodID, String methodName) 101 { 102 return invokeStatic(methodID, methodName, EMPTY_CLASS_ARRAY); 103 } 104 105 protected Object invokeStatic(int methodID, String methodName, Class<?> parameterType, Object parameter) 106 { 107 return invokeStatic(methodID, methodName, new Class<?>[] { parameterType }, parameter); 108 } 109 110 protected Object invokeStatic(int methodID, String methodName, Class<?> parameterType1, Class<?> parameterType2, Object ...parameters) 111 { 112 return invokeStatic(methodID, methodName, new Class<?>[] { parameterType1, parameterType2 }, parameters); 113 } 114 115 protected Object invokeStatic(int methodID, String methodName, Class<?> parameterType1, Class<?> parameterType2, Class<?> parameterType3, Object ...parameters) 116 { 117 return invokeStatic(methodID, methodName, new Class<?>[] { parameterType1, parameterType2, parameterType3 }, parameters); 118 } 119 120 /** 121 * Invoke a method on the wrapped class (not the wrapped object) in a static way. 122 * @param methodID identifier that must be unique within the subclass of {@link ReflectionWrapper}. 123 * For performance reasons, the {@link Method} instances are cached and the cache key is this <code>methodID</code> 124 * (rather than a long String comprising <code>methodName</code> and <code>parameterTypes</code>). 125 * @param methodName method name as passed to {@link Class#getMethod(String, Class...)}. 126 * @param parameterTypes parameter types as passed to {@link Class#getMethod(String, Class...)}. 127 * @param parameters parameters as passed to {@link Method#invoke(Object, Object...)}. 128 * @return the result of the method invocation as returned from {@link Method#invoke(Object, Object...)}. 129 */ 130 protected Object invokeStatic(int methodID, String methodName, Class<?>[] parameterTypes, Object ...parameters) 131 { 132 try { 133 Integer mID = methodID; 134 Method method = methodID2Method.get(mID); 135 if (method == null) { 136 method = getWrappedClass().getMethod(methodName, parameterTypes); 137 methodID2Method.put(mID, method); 138 } 139 140 Object result = method.invoke(null, parameters); 141 return result; 142 } catch (SecurityException e) { 143 throw new ReflectionWrapperException(e); 144 } catch (NoSuchMethodException e) { 145 throw new ReflectionWrapperException(e); 146 } catch (IllegalArgumentException e) { 147 throw new ReflectionWrapperException(e); 148 } catch (IllegalAccessException e) { 149 throw new ReflectionWrapperException(e); 150 } catch (InvocationTargetException e) { 151 throw new ReflectionWrapperException(e.getTargetException()); 152 } 153 } 154 155 private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; 156 157 /** 158 * Invoke a method on the wrapped object. This is a convenience method delegating to 159 * {@link #invoke(int, String, Class[], Object...)}. 160 * @param methodID identifier that must be unique within the subclass of {@link ReflectionWrapper}. 161 * @param methodName method name. 162 * @return the result of the method invocation. 163 */ 164 protected Object invoke(int methodID, String methodName) 165 { 166 return invoke(methodID, methodName, EMPTY_CLASS_ARRAY); 167 } 168 169 /** 170 * Invoke a method on the wrapped object. This is a convenience method delegating to 171 * {@link #invoke(int, String, Class[], Object...)}. 172 * @param methodID identifier that must be unique within the subclass of {@link ReflectionWrapper}. 173 * @param methodName method name. 174 * @param parameterType single parameter type. 175 * @param parameter single parameter. 176 * @return the result of the method invocation. 177 */ 178 protected Object invoke(int methodID, String methodName, Class<?> parameterType, Object parameter) 179 { 180 return invoke(methodID, methodName, new Class<?>[] { parameterType }, parameter); 181 } 182 183 /** 184 * Invoke a method on the wrapped object. This is a convenience method delegating to 185 * {@link #invoke(int, String, Class[], Object...)}. 186 * @param methodID identifier that must be unique within the subclass of {@link ReflectionWrapper}. 187 * @param methodName method name. 188 * @param parameterType1 first parameter type. 189 * @param parameterType2 second parameter type. 190 * @param parameters two parameters (corresponding to the two parameter types). 191 * @return the result of the method invocation. 192 */ 193 protected Object invoke(int methodID, String methodName, Class<?> parameterType1, Class<?> parameterType2, Object ...parameters) 194 { 195 return invoke(methodID, methodName, new Class<?>[] { parameterType1, parameterType2 }, parameters); 196 } 197 198 /** 199 * Invoke a method on the wrapped object. This is a convenience method delegating to 200 * {@link #invoke(int, String, Class[], Object...)}. 201 * @param methodID identifier that must be unique within the subclass of {@link ReflectionWrapper}. 202 * @param methodName method name. 203 * @param parameterType1 first parameter type. 204 * @param parameterType2 second parameter type. 205 * @param parameterType3 third parameter type. 206 * @param parameters three parameters (corresponding to the three parameter types). 207 * @return the result of the method invocation. 208 */ 209 protected Object invoke(int methodID, String methodName, Class<?> parameterType1, Class<?> parameterType2, Class<?> parameterType3, Object ...parameters) 210 { 211 return invoke(methodID, methodName, new Class<?>[] { parameterType1, parameterType2, parameterType3 }, parameters); 212 } 213 214 /** 215 * Invoke a method on the wrapped object. 216 * @param methodID identifier that must be unique within the subclass of {@link ReflectionWrapper}. 217 * For performance reasons, the {@link Method} instances are cached and the cache key is this <code>methodID</code> 218 * (rather than a long String comprising <code>methodName</code> and <code>parameterTypes</code>). 219 * @param methodName method name as passed to {@link Class#getMethod(String, Class...)}. 220 * @param parameterTypes parameter types as passed to {@link Class#getMethod(String, Class...)}. 221 * @param parameters parameters as passed to {@link Method#invoke(Object, Object...)}. 222 * @return the result of the method invocation as returned from {@link Method#invoke(Object, Object...)}. 223 */ 224 protected Object invoke(int methodID, String methodName, Class<?>[] parameterTypes, Object ...parameters) 225 { 226 try { 227 Integer mID = methodID; 228 Method method = methodID2Method.get(mID); 229 if (method == null) { 230 method = getWrappedClass().getMethod(methodName, parameterTypes); 231 methodID2Method.put(mID, method); 232 } 233 234 Object result = method.invoke(getWrappedObject(), parameters); 235 return result; 236 } catch (SecurityException e) { 237 throw new ReflectionWrapperException(e); 238 } catch (NoSuchMethodException e) { 239 throw new ReflectionWrapperException(e); 240 } catch (IllegalArgumentException e) { 241 throw new ReflectionWrapperException(e); 242 } catch (IllegalAccessException e) { 243 throw new ReflectionWrapperException(e); 244 } catch (InvocationTargetException e) { 245 throw new ReflectionWrapperException(e.getTargetException()); 246 } 247 } 248 }