| 1 | /* |
| 2 | * Copyright 2007 brunella ltd |
| 3 | * |
| 4 | * Licensed under the LGPL Version 3 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * |
| 7 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 8 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 11 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 12 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 13 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 14 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 15 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 16 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| 17 | * THE POSSIBILITY OF SUCH DAMAGE. |
| 18 | */ |
| 19 | package sf.qof.util; |
| 20 | |
| 21 | import static sf.qof.codegen.Constants.TYPE_boolean; |
| 22 | |
| 23 | import java.lang.reflect.Method; |
| 24 | import java.lang.reflect.Modifier; |
| 25 | |
| 26 | import net.sf.cglib.core.ClassEmitter; |
| 27 | import net.sf.cglib.core.CodeEmitter; |
| 28 | import net.sf.cglib.core.Constants; |
| 29 | import net.sf.cglib.core.DebuggingClassWriter; |
| 30 | import net.sf.cglib.core.Signature; |
| 31 | |
| 32 | import org.objectweb.asm.ClassWriter; |
| 33 | import org.objectweb.asm.Label; |
| 34 | import org.objectweb.asm.Type; |
| 35 | |
| 36 | /** |
| 37 | * Factory class to create a delegator object for a given delegatee class. |
| 38 | * |
| 39 | * <p> |
| 40 | * The factory creates wrappers for each public non-final method of the |
| 41 | * delegatee class. Once any of these methods is called the delegatee factory is |
| 42 | * used to initialize the delegatee object. The delegatee class must have a |
| 43 | * default constructor. |
| 44 | * </p> |
| 45 | * <p> |
| 46 | * The delegatee factory must implement a static <code>initialize</code> |
| 47 | * method with the first argument being the delegatee object and the other |
| 48 | * arguments matching the types of the <code>constructorParameters</code>: |
| 49 | * </p> |
| 50 | * |
| 51 | * <pre> |
| 52 | * public class PersonDelegateeFactory { |
| 53 | * public static void initialize(Person personDelegatee, Integer id) { |
| 54 | * String name = getNameForId(id); |
| 55 | * personDelegatee.setName(name); |
| 56 | * } |
| 57 | * } |
| 58 | * |
| 59 | * // create a delegator for person and pass it the id of 1 |
| 60 | * Person person = DelegatorFactory<Person>(Person.class, |
| 61 | * PersonDelegateeFactory.class, 1); |
| 62 | * // person is instanziated but not initialized |
| 63 | * // a call to getName() or any other public method of person for the first time |
| 64 | * // calls PersonDelegateeFactory.initialize(person, 1) |
| 65 | * String name = person.getName(); |
| 66 | * // person is initialized now |
| 67 | * </pre> |
| 68 | * |
| 69 | * <p> |
| 70 | * Initialization of delegator objects is thread-safe. |
| 71 | * </p> |
| 72 | * <p> |
| 73 | * <code>DelegatorFactory</code> can be used to implement lazy initialization |
| 74 | * of objects |
| 75 | * </p> |
| 76 | * <p> |
| 77 | * The generated delegatee objects super class is the delegatee class. |
| 78 | * </p> |
| 79 | */ |
| 80 | public class DelegatorFactory { |
| 81 | |
| 82 | /** |
| 83 | * Returns an instance of a delegator object for a delegatee class. |
| 84 | * |
| 85 | * @param <T> |
| 86 | * type of the delegatee object |
| 87 | * @param delegateeClass |
| 88 | * class of the delegatee object |
| 89 | * @param delegateeFactory |
| 90 | * factory to initialize the delegatee object |
| 91 | * @param constructorParameters |
| 92 | * parameters that are passed to the delegatee factory |
| 93 | * @return delegator object instance |
| 94 | */ |
| 95 | @SuppressWarnings("unchecked") |
| 96 | public static <T> T create(Class<T> delegateeClass, Class<?> delegateeFactory, Object... constructorParameters) { |
| 97 | Class<T> delegatorClass = (Class<T>) ClassGenerationCache.getCachedClass(delegateeClass, delegateeFactory); |
| 98 | if (delegatorClass == null) { |
| 99 | try { |
| 100 | // create new class |
| 101 | delegatorClass = createClass(delegateeClass, delegateeFactory, constructorParameters); |
| 102 | |
| 103 | // put the newly created class |
| 104 | ClassGenerationCache.putCachedClass(delegatorClass, delegateeClass, delegateeFactory); |
| 105 | } catch (Throwable e) { |
| 106 | ClassGenerationCache.putCachedClass(null, delegateeClass, delegateeFactory); |
| 107 | throw new RuntimeException(e); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // create instance |
| 112 | Class[] constructorParameterTypes = new Class[constructorParameters.length]; |
| 113 | for (int i = 0; i < constructorParameters.length; i++) { |
| 114 | constructorParameterTypes[i] = constructorParameters[i].getClass(); |
| 115 | } |
| 116 | try { |
| 117 | return delegatorClass.getConstructor(constructorParameterTypes).newInstance(constructorParameters); |
| 118 | } catch (Throwable e) { |
| 119 | throw new RuntimeException(e); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | private static <T> Class<T> createClass(Class<T> delegateeClass, Class<?> delegateeFactory, |
| 124 | Object... constructorParameters) throws Exception { |
| 125 | |
| 126 | ClassWriter cw = new DebuggingClassWriter(true); |
| 127 | ClassEmitter ce = new ClassEmitter(cw); |
| 128 | |
| 129 | String className = delegateeClass.getName() + "$" + delegateeFactory.getName() + "$Delegator"; |
| 130 | if (className.startsWith("java")) { |
| 131 | className = "$" + className; |
| 132 | } |
| 133 | |
| 134 | Type[] delegateeInterfaces = getInterfaceTypes(delegateeClass); |
| 135 | |
| 136 | ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, Type.getType(delegateeClass), delegateeInterfaces, |
| 137 | "<generated>"); |
| 138 | |
| 139 | createConstructorAndFields(ce, delegateeClass, constructorParameters); |
| 140 | |
| 141 | createInitializeMethod(ce, delegateeFactory, delegateeClass, constructorParameters); |
| 142 | createMethods(ce, delegateeClass); |
| 143 | |
| 144 | ce.end_class(); |
| 145 | |
| 146 | ClassLoader classLoader = delegateeClass.getClassLoader(); |
| 147 | if (classLoader == null) { |
| 148 | classLoader = DelegatorFactory.class.getClassLoader(); |
| 149 | } |
| 150 | |
| 151 | return DefineClassHelper.defineClass(className, cw.toByteArray(), classLoader); |
| 152 | } |
| 153 | |
| 154 | private static void createConstructorAndFields(ClassEmitter ce, Class<?> delegateeClass, |
| 155 | Object[] constructorParameters) { |
| 156 | ce.declare_field(Constants.ACC_PRIVATE, "$$initialized", TYPE_boolean, false, null); |
| 157 | for (int i = 0; i < constructorParameters.length; i++) { |
| 158 | ce.declare_field(Constants.ACC_PRIVATE, "$$" + i, Type.getType(constructorParameters[i].getClass()), null, null); |
| 159 | } |
| 160 | |
| 161 | Signature sigConstructor = new Signature("<init>", Type.VOID_TYPE, getTypes(constructorParameters)); |
| 162 | CodeEmitter co = ce.begin_method(Constants.ACC_PUBLIC, sigConstructor, null, null); |
| 163 | co.load_this(); |
| 164 | co.invoke_constructor(ce.getSuperType(), new Signature("<init>", "()V")); |
| 165 | // store constructor parameters |
| 166 | for (int i = 0; i < constructorParameters.length; i++) { |
| 167 | co.load_this(); |
| 168 | co.load_arg(i); |
| 169 | co.putfield("$$" + i); |
| 170 | } |
| 171 | co.return_value(); |
| 172 | co.end_method(); |
| 173 | } |
| 174 | |
| 175 | private static void createMethods(ClassEmitter ce, Class<?> delegateeClass) { |
| 176 | for (Method method : delegateeClass.getMethods()) { |
| 177 | createMethod(ce, delegateeClass, method); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | private static void createInitializeMethod(ClassEmitter ce, Class<?> delegateeFactory, Class<?> delegateeClass, |
| 182 | Object[] constructorParameters) { |
| 183 | CodeEmitter co = ce.begin_method(Constants.ACC_PRIVATE + Constants.ACC_SYNCHRONIZED, new Signature("$initialize", |
| 184 | "()V"), null, null); |
| 185 | co.load_this(); |
| 186 | co.getfield("$$initialized"); |
| 187 | Label labelInitialized = co.make_label(); |
| 188 | co.if_jump(CodeEmitter.NE, labelInitialized); |
| 189 | |
| 190 | co.load_this(); |
| 191 | co.push(true); |
| 192 | co.putfield("$$initialized"); |
| 193 | co.load_this(); |
| 194 | String desc = "(L" + Type.getType(delegateeClass).getInternalName() + ";"; |
| 195 | for (int i = 0; i < constructorParameters.length; i++) { |
| 196 | desc += "L" + Type.getType(constructorParameters[i].getClass()).getInternalName() + ";"; |
| 197 | } |
| 198 | desc += ")V"; |
| 199 | for (int i = 0; i < constructorParameters.length; i++) { |
| 200 | co.load_this(); |
| 201 | co.getfield("$$" + i); |
| 202 | } |
| 203 | co.invoke_static(Type.getType(delegateeFactory), new Signature("initialize", desc)); |
| 204 | |
| 205 | co.mark(labelInitialized); |
| 206 | |
| 207 | co.return_value(); |
| 208 | co.end_method(); |
| 209 | } |
| 210 | |
| 211 | private static void createMethod(ClassEmitter ce, Class<?> delegateeClass, Method method) { |
| 212 | if (Modifier.isFinal(method.getModifiers())) { |
| 213 | return; |
| 214 | } |
| 215 | Signature methodSignature = ReflectionUtils.getMethodSignature(method); |
| 216 | CodeEmitter co = ce.begin_method(Constants.ACC_PUBLIC, methodSignature, getTypes(method.getExceptionTypes()), null); |
| 217 | // call delegatee |
| 218 | co.load_this(); |
| 219 | co.getfield("$$initialized"); |
| 220 | Label labelInitialized = co.make_label(); |
| 221 | co.if_jump(CodeEmitter.NE, labelInitialized); |
| 222 | co.load_this(); |
| 223 | co.invoke_virtual_this(new Signature("$initialize", "()V")); |
| 224 | co.mark(labelInitialized); |
| 225 | co.load_this(); |
| 226 | int num = method.getParameterTypes().length; |
| 227 | for (int i = 0; i < num; i++) { |
| 228 | co.load_arg(i); |
| 229 | } |
| 230 | co.super_invoke(); |
| 231 | co.return_value(); |
| 232 | co.end_method(); |
| 233 | } |
| 234 | |
| 235 | private static Type[] getInterfaceTypes(Class<?> clazz) { |
| 236 | Class<?>[] interfaces = clazz.getInterfaces(); |
| 237 | return getTypes(interfaces); |
| 238 | } |
| 239 | |
| 240 | private static Type[] getTypes(Class<?>[] classes) { |
| 241 | Type[] types = new Type[classes.length]; |
| 242 | for (int i = 0; i < classes.length; i++) { |
| 243 | types[i] = Type.getType(classes[i]); |
| 244 | } |
| 245 | return types; |
| 246 | } |
| 247 | |
| 248 | private static Type[] getTypes(Object[] objs) { |
| 249 | Type[] types = new Type[objs.length]; |
| 250 | for (int i = 0; i < objs.length; i++) { |
| 251 | types[i] = Type.getType(objs[i].getClass()); |
| 252 | } |
| 253 | return types; |
| 254 | } |
| 255 | } |