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 }