1 54 package org.logicalcobwebs.cglib.proxy; 55 56 import java.io.ObjectStreamException ; 57 import java.lang.reflect.*; 58 import java.util.*; 59 import org.logicalcobwebs.cglib.core.*; 60 import org.logicalcobwebs.asm.ClassVisitor; 61 import org.logicalcobwebs.asm.Label; 62 import org.logicalcobwebs.asm.Type; 63 64 class EnhancerEmitter extends ClassEmitter { 65 private static final String CONSTRUCTED_FIELD = "CGLIB$CONSTRUCTED"; 66 67 private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS"; 68 69 private static final Type ILLEGAL_STATE_EXCEPTION = 70 TypeUtils.parseType("IllegalStateException"); 71 private static final Type ILLEGAL_ARGUMENT_EXCEPTION = 72 TypeUtils.parseType("IllegalArgumentException"); 73 private static final Type THREAD_LOCAL = 74 TypeUtils.parseType("ThreadLocal"); 75 private static final Type FACTORY = 76 TypeUtils.parseType("org.logicalcobwebs.cglib.proxy.Factory"); 77 78 private static final Signature CSTRUCT_NULL = 79 TypeUtils.parseConstructor(""); 80 private static final Signature SET_THREAD_CALLBACKS = 81 TypeUtils.parseSignature("void " + SET_THREAD_CALLBACKS_NAME + "(org.logicalcobwebs.cglib.proxy.Callback[])"); 82 private static final Signature NEW_INSTANCE = 83 TypeUtils.parseSignature("Object newInstance(org.logicalcobwebs.cglib.proxy.Callback[])"); 84 private static final Signature MULTIARG_NEW_INSTANCE = 85 TypeUtils.parseSignature("Object newInstance(Class[], Object[], org.logicalcobwebs.cglib.proxy.Callback[])"); 86 private static final Signature SINGLE_NEW_INSTANCE = 87 TypeUtils.parseSignature("Object newInstance(org.logicalcobwebs.cglib.proxy.Callback)"); 88 private static final Signature COPY_NEW_INSTANCE = 89 TypeUtils.parseSignature("Object newInstance()"); 90 private static final Signature COPY_MULTIARG_NEW_INSTANCE = 91 TypeUtils.parseSignature("Object newInstance(Class[], Object[])"); 92 private static final Signature SET_CALLBACK = 93 TypeUtils.parseSignature("void setCallback(int, org.logicalcobwebs.cglib.proxy.Callback)"); 94 private static final Signature GET_CALLBACK = 95 TypeUtils.parseSignature("org.logicalcobwebs.cglib.proxy.Callback getCallback(int)"); 96 private static final Signature SET_CALLBACKS = 97 TypeUtils.parseSignature("void setCallbacks(org.logicalcobwebs.cglib.proxy.Callback[])"); 98 99 private static final Signature THREAD_LOCAL_GET = 100 TypeUtils.parseSignature("Object get()"); 101 private static final Signature THREAD_LOCAL_SET = 102 TypeUtils.parseSignature("void set(Object)"); 103 104 private Class [] callbackTypes; 105 106 public EnhancerEmitter(ClassVisitor v, 107 String className, 108 Class superclass, 109 Class [] interfaces, 110 CallbackFilter filter, 111 Class [] callbackTypes, 112 boolean useFactory) throws Exception { 113 super(v); 114 if (superclass == null) { 115 superclass = Object .class; 116 } 117 this.callbackTypes = callbackTypes; 118 119 begin_class(Constants.ACC_PUBLIC, 120 className, 121 Type.getType(superclass), 122 (useFactory ? 123 TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) : 124 TypeUtils.getTypes(interfaces)), 125 Constants.SOURCE_FILE); 126 127 List clist = new ArrayList(Arrays.asList(superclass.getDeclaredConstructors())); 128 CollectionUtils.filter(clist, new VisibilityPredicate(superclass, true)); 129 if (clist.size() == 0) { 130 throw new IllegalArgumentException ("No visible constructors in " + superclass); 131 } 132 Constructor[] constructors = (Constructor[])clist.toArray(new Constructor[clist.size()]); 133 134 List methods = new ArrayList(); 138 ReflectUtils.addAllMethods(superclass, methods); 139 140 List interfaceMethods = new ArrayList(); 141 if (interfaces != null) { 142 for (int i = 0; i < interfaces.length; i++) { 143 if (interfaces[i] != Factory.class) { 144 ReflectUtils.addAllMethods(interfaces[i], interfaceMethods); 145 } 146 } 147 } 148 Set forcePublic = MethodWrapper.createSet(interfaceMethods); 149 methods.addAll(interfaceMethods); 150 CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true)); 151 CollectionUtils.filter(methods, new DuplicatesPredicate()); 152 removeFinal(methods); 153 154 Map groups = new HashMap(); 155 Map indexes = new HashMap(); 156 for (Iterator it = methods.iterator(); it.hasNext();) { 157 Method method = (Method)it.next(); 158 int index = filter.accept(method); 159 if (index >= callbackTypes.length) { 160 throw new IllegalArgumentException ("Callback filter returned an index that is too large: " + index); 161 } 162 indexes.put(method, new Integer (index)); 163 Object gen = CallbackUtils.getGenerator(callbackTypes[index]); 164 List group = (List)groups.get(gen); 165 if (group == null) { 166 groups.put(gen, group = new ArrayList(methods.size())); 167 } 168 group.add(method); 169 } 170 171 declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null, null); 172 emitMethods(groups, indexes, forcePublic); 173 emitConstructors(constructors); 174 emitSetThreadCallbacks(); 175 176 if (useFactory) { 177 int[] keys = getCallbackKeys(); 178 emitNewInstanceCallbacks(); 179 emitNewInstanceCallback(); 180 emitNewInstanceMultiarg(constructors); 181 emitNewInstanceCopy(); 182 emitNewInstanceMultiargCopy(constructors); 183 emitGetCallback(keys); 184 emitSetCallback(keys); 185 emitSetCallbacks(); 186 } 187 end_class(); 188 } 189 190 static void setThreadCallbacks(Class type, Callback[] callbacks) { 191 try { 193 Method setter = type.getDeclaredMethod(SET_THREAD_CALLBACKS_NAME, new Class []{ Callback[].class }); 194 setter.invoke(null, new Object []{ callbacks }); 195 } catch (NoSuchMethodException e) { 196 throw new IllegalArgumentException (type + " is not an enhanced class"); 197 } catch (IllegalAccessException e) { 198 throw new CodeGenerationException(e); 199 } catch (InvocationTargetException e) { 200 throw new CodeGenerationException(e); 201 } 202 } 203 204 private void emitConstructors(Constructor[] constructors) { 205 for (int i = 0; i < constructors.length; i++) { 206 Signature sig = ReflectUtils.getSignature(constructors[i]); 207 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, 208 sig, 209 ReflectUtils.getExceptionTypes(constructors[i]), 210 null); 211 e.load_this(); 212 e.dup(); 213 e.load_args(); 214 e.super_invoke_constructor(sig); 215 e.push(1); 216 e.putfield(CONSTRUCTED_FIELD); 217 for (int j = 0; j < callbackTypes.length; j++) { 218 e.load_this(); 219 e.dup(); 220 e.getfield(getThreadLocal(j)); 221 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET); 222 e.checkcast(Type.getType(callbackTypes[j])); 223 e.putfield(getCallbackField(j)); 224 225 e.getfield(getThreadLocal(j)); 227 e.aconst_null(); 228 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 229 } 230 e.return_value(); 231 e.end_method(); 232 } 233 } 234 235 private int[] getCallbackKeys() { 236 int[] keys = new int[callbackTypes.length]; 237 for (int i = 0; i < callbackTypes.length; i++) { 238 keys[i] = i; 239 } 240 return keys; 241 } 242 243 private void emitGetCallback(int[] keys) { 244 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_CALLBACK, null, null); 245 e.load_this(); 246 e.load_arg(0); 247 e.process_switch(keys, new ProcessSwitchCallback() { 248 public void processCase(int key, Label end) { 249 e.getfield(getCallbackField(key)); 250 e.goTo(end); 251 } 252 public void processDefault() { 253 e.pop(); e.aconst_null(); 255 } 256 }); 257 e.return_value(); 258 e.end_method(); 259 } 260 261 private void emitSetCallback(int[] keys) { 262 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_CALLBACK, null, null); 263 e.load_this(); 264 e.load_arg(1); 265 e.dup(); 266 e.load_arg(0); 267 e.process_switch(keys, new ProcessSwitchCallback() { 268 public void processCase(int key, Label end) { 269 e.getfield(getThreadLocal(key)); 271 e.swap(); 272 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 273 e.checkcast(Type.getType(callbackTypes[key])); 274 e.putfield(getCallbackField(key)); 275 e.goTo(end); 276 } 277 public void processDefault() { 278 e.pop2(); 280 e.pop(); 281 } 282 }); 283 e.return_value(); 284 e.end_method(); 285 } 286 287 private void emitSetCallbacks() { 288 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_CALLBACKS, null, null); 289 emitSetThreadCallbacks(e); 290 e.load_this(); 291 e.load_arg(0); 292 for (int i = 0; i < callbackTypes.length; i++) { 293 e.dup2(); 294 e.aaload(i); 295 e.checkcast(Type.getType(callbackTypes[i])); 296 e.putfield(getCallbackField(i)); 297 } 298 e.return_value(); 299 e.end_method(); 300 } 301 302 private void emitNewInstanceCallbacks() { 303 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null, null); 304 e.load_arg(0); 305 e.invoke_static_this(SET_THREAD_CALLBACKS); 306 emitCommonNewInstance(e); 307 } 308 309 private void emitNewInstanceCopy() { 310 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, COPY_NEW_INSTANCE, null, null); 311 emitCopyCallbacks(e); 312 emitCommonNewInstance(e); 313 } 314 315 private void emitCopyCallbacks(CodeEmitter e) { 316 for (int i = 0; i < callbackTypes.length; i++) { 317 e.getfield(getThreadLocal(i)); 318 e.load_this(); 319 e.getfield(getCallbackField(i)); 320 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 321 } 322 } 323 324 private void emitCommonNewInstance(CodeEmitter e) { 325 e.new_instance_this(); 326 e.dup(); 327 e.invoke_constructor_this(); 328 e.return_value(); 329 e.end_method(); 330 } 331 332 private void emitNewInstanceCallback() { 333 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SINGLE_NEW_INSTANCE, null, null); 334 switch (callbackTypes.length) { 335 case 0: 336 break; 338 case 1: 339 e.getfield(getThreadLocal(0)); 340 e.load_arg(0); 341 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 342 break; 343 default: 344 e.throw_exception(ILLEGAL_STATE_EXCEPTION, "More than one callback object required"); 345 } 346 emitCommonNewInstance(e); 347 } 348 349 private void emitNewInstanceMultiarg(Constructor[] constructors) { 350 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, MULTIARG_NEW_INSTANCE, null, null); 351 e.load_arg(2); 352 e.invoke_static_this(SET_THREAD_CALLBACKS); 353 emitCommonMultiarg(constructors, e); 354 } 355 356 private void emitNewInstanceMultiargCopy(Constructor[] constructors) { 357 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, COPY_MULTIARG_NEW_INSTANCE, null, null); 358 emitCopyCallbacks(e); 359 emitCommonMultiarg(constructors, e); 360 } 361 362 private void emitCommonMultiarg(Constructor[] constructors, final CodeEmitter e) { 363 e.new_instance_this(); 364 e.dup(); 365 e.load_arg(0); 366 EmitUtils.constructor_switch(e, constructors, new ObjectSwitchCallback() { 367 public void processCase(Object key, Label end) { 368 Constructor constructor = (Constructor)key; 369 Type types[] = TypeUtils.getTypes(constructor.getParameterTypes()); 370 for (int i = 0; i < types.length; i++) { 371 e.load_arg(1); 372 e.push(i); 373 e.aaload(); 374 e.unbox(types[i]); 375 } 376 e.invoke_constructor_this(ReflectUtils.getSignature(constructor)); 377 e.goTo(end); 378 } 379 public void processDefault() { 380 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Constructor not found"); 381 } 382 }); 383 e.return_value(); 384 e.end_method(); 385 } 386 387 private void emitMethods(Map groups, final Map indexes, final Set forcePublic) throws Exception { 388 for (int i = 0; i < callbackTypes.length; i++) { 389 declare_field(Constants.ACC_PRIVATE, getCallbackField(i), Type.getType(callbackTypes[i]), null, null); 390 declare_field(Constants.PRIVATE_FINAL_STATIC, getThreadLocal(i), THREAD_LOCAL, null, null); 391 } 392 393 Set seenGen = new HashSet(); 394 CodeEmitter e = begin_static(); 395 for (int i = 0; i < callbackTypes.length; i++) { 396 e.new_instance(THREAD_LOCAL); 397 e.dup(); 398 e.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL); 399 e.putfield(getThreadLocal(i)); 400 401 CallbackGenerator gen = CallbackUtils.getGenerator(callbackTypes[i]); 402 if (!seenGen.contains(gen)) { 403 seenGen.add(gen); 404 final List fmethods = (List)groups.get(gen); 405 CallbackGenerator.Context context = new CallbackGenerator.Context() { 406 public Iterator getMethods() { 407 return fmethods.iterator(); 408 } 409 public int getIndex(Method method) { 410 return ((Integer )indexes.get(method)).intValue(); 411 } 412 public void emitCallback(CodeEmitter e, int index) { 413 emitCurrentCallback(e, index); 414 } 415 public int getModifiers(Method method) { 416 int modifiers = Constants.ACC_FINAL 417 | (method.getModifiers() 418 & ~Constants.ACC_ABSTRACT 419 & ~Constants.ACC_NATIVE 420 & ~Constants.ACC_SYNCHRONIZED); 421 if (forcePublic.contains(MethodWrapper.create(method))) { 422 modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC; 423 } 424 return modifiers; 425 } 426 public String getUniqueName(Method method) { 428 return method.getName() + "_" + fmethods.indexOf(method); 429 } 430 }; 431 gen.generate(this, context); 432 gen.generateStatic(e, context); 433 } 434 } 435 e.return_value(); 436 e.end_method(); 437 } 438 439 private void emitSetThreadCallbacks() { 440 CodeEmitter e = begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC, 441 SET_THREAD_CALLBACKS, 442 null, 443 null); 444 emitSetThreadCallbacks(e); 445 e.return_value(); 446 e.end_method(); 447 } 448 449 private void emitSetThreadCallbacks(CodeEmitter e) { 450 for (int i = 0; i < callbackTypes.length; i++) { 451 e.getfield(getThreadLocal(i)); 452 e.load_arg(0); 453 e.aaload(i); 454 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 455 } 456 } 457 458 private void emitCurrentCallback(CodeEmitter e, int index) { 459 e.load_this(); 460 e.getfield(getCallbackField(index)); 461 e.dup(); 462 Label end = e.make_label(); 463 e.ifnonnull(end); 464 e.load_this(); 465 e.getfield(CONSTRUCTED_FIELD); 466 e.if_jump(e.NE, end); 467 e.pop(); 468 e.getfield(getThreadLocal(index)); 469 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET); 470 e.checkcast(Type.getType(callbackTypes[index])); 471 e.mark(end); 472 } 473 474 private static String getCallbackField(int index) { 475 return "CGLIB$CALLBACK_" + index; 476 } 477 478 private static String getThreadLocal(int index) { 479 return "CGLIB$TL_CALLBACK_" + index; 480 } 481 482 private static void removeFinal(List list) { 483 CollectionUtils.filter(list, new Predicate() { 484 public boolean evaluate(Object arg) { 485 return !Modifier.isFinal(((Method)arg).getModifiers()); 486 } 487 }); 488 } 489 } 490 | Popular Tags |