1 17 18 package org.apache.avalon.fortress.impl.factory; 19 20 import org.apache.bcel.Constants; 21 import org.apache.bcel.classfile.Field; 22 import org.apache.bcel.classfile.JavaClass; 23 import org.apache.bcel.classfile.Method; 24 import org.apache.bcel.generic.*; 25 26 import java.util.HashSet ; 27 import java.util.Set ; 28 29 39 40 public final class BCELCodeGenerator 41 { 42 46 55 private static final String WRAPPED_CLASS_FN = "m_wrappedClass"; 56 57 61 private static final String ACCESSOR_METHOD_NAME = "getWrappedObject"; 62 63 66 private String m_wrapperClassName; 67 68 71 private String m_wrapperSuperclassName; 72 73 77 private JavaClass m_classToWrap; 78 79 83 private Type m_classToWrapType; 84 85 89 private ClassGen m_classGenerator; 90 91 95 private ConstantPoolGen m_constPoolGenerator; 96 97 101 private final InstructionList m_instructionList = new InstructionList(); 102 103 107 private InstructionFactory m_instructionFactory; 108 109 112 private boolean m_isInitialized = false; 113 114 117 public BCELCodeGenerator() 118 { 119 } 121 122 public void init( 123 final String wrapperClassName, 124 final String wrapperSuperclassName, 125 final JavaClass classToWrap, 126 final ClassGen classGenerator ) 127 throws IllegalArgumentException 128 { 129 if ( classToWrap == null ) 130 { 131 final String message = "Target class must not be <null>."; 132 throw new IllegalArgumentException ( message ); 133 } 134 if ( classToWrap.isAbstract() || !classToWrap.isClass() ) 135 { 136 final String message = 137 "Target class must neither be abstract nor an interface."; 138 throw new IllegalArgumentException ( message ); 139 } 140 if ( classGenerator == null ) 141 { 142 final String message = "ClassGenerator must not be <null>."; 143 throw new IllegalArgumentException ( message ); 144 } 145 146 m_wrapperClassName = wrapperClassName; 147 m_wrapperSuperclassName = wrapperSuperclassName; 148 m_classToWrap = classToWrap; 149 m_classToWrapType = new ObjectType( m_classToWrap.getClassName() ); 150 m_classGenerator = classGenerator; 151 m_constPoolGenerator = m_classGenerator.getConstantPool(); 152 m_instructionFactory = 153 new InstructionFactory( m_classGenerator, m_constPoolGenerator ); 154 155 m_isInitialized = true; 156 } 157 158 170 public Field createWrappedClassField() throws IllegalStateException 171 { 172 if ( !isInitialized() ) 173 { 174 final String message = 175 "BCELMethodFieldImplementationGenerator is not initialized."; 176 throw new IllegalStateException ( message ); 177 } 178 179 final FieldGen fg = 180 new FieldGen( 181 Constants.ACC_PRIVATE, 182 m_classToWrapType, 183 WRAPPED_CLASS_FN, 184 m_constPoolGenerator ); 185 186 return fg.getField(); 187 } 188 189 204 public Method createDefaultConstructor() throws IllegalStateException 205 { 206 if ( !isInitialized() ) 207 { 208 final String message = 209 "BCELMethodFieldImplementationGenerator is not initialized."; 210 throw new IllegalStateException ( message ); 211 } 212 final MethodGen mg = 213 new MethodGen( 214 Constants.ACC_PUBLIC, 215 Type.VOID, 216 new Type[]{m_classToWrapType}, 217 new String []{"classToWrap"}, 218 "<init>", 219 m_wrapperClassName, 220 m_instructionList, 221 m_constPoolGenerator ); 222 223 m_instructionList.append( 224 InstructionFactory.createLoad( Type.OBJECT, 0 ) ); 225 m_instructionList.append( 226 m_instructionFactory.createInvoke( 227 m_wrapperSuperclassName, 228 "<init>", 229 Type.VOID, 230 Type.NO_ARGS, 231 Constants.INVOKESPECIAL ) ); 232 m_instructionList.append( 233 InstructionFactory.createLoad( Type.OBJECT, 0 ) ); 234 m_instructionList.append( 235 InstructionFactory.createLoad( Type.OBJECT, 1 ) ); 236 m_instructionList.append( 237 m_instructionFactory.createFieldAccess( 238 m_wrapperClassName, 239 WRAPPED_CLASS_FN, 240 m_classToWrapType, 241 Constants.PUTFIELD ) ); 242 m_instructionList.append( InstructionFactory.createReturn( Type.VOID ) ); 243 mg.setMaxStack(); 244 mg.setMaxLocals(); 245 246 return extractMethod( mg ); 247 } 248 249 262 public Method createWrappedClassAccessor() throws IllegalStateException 263 { 264 if ( !isInitialized() ) 265 { 266 final String message = 267 "BCELMethodFieldImplementationGenerator is not initialized."; 268 throw new IllegalStateException ( message ); 269 } 270 271 final MethodGen mg = 272 new MethodGen( 273 Constants.ACC_PUBLIC, 274 Type.OBJECT, 275 Type.NO_ARGS, 276 new String []{ 277 }, 278 ACCESSOR_METHOD_NAME, 279 m_classToWrap.getClassName(), 280 m_instructionList, 281 m_constPoolGenerator ); 282 283 m_instructionList.append( 284 InstructionFactory.createLoad( Type.OBJECT, 0 ) ); 285 m_instructionList.append( 286 m_instructionFactory.createFieldAccess( 287 m_wrapperClassName, 288 WRAPPED_CLASS_FN, 289 m_classToWrapType, 290 Constants.GETFIELD ) ); 291 m_instructionList.append( 292 InstructionFactory.createReturn( Type.OBJECT ) ); 293 294 mg.setMaxStack(); 295 mg.setMaxLocals(); 296 297 return extractMethod( mg ); 298 } 299 300 320 public Method createMethodWrapper( MethodDesc meth ) 321 throws IllegalArgumentException , IllegalStateException 322 { 323 if ( !isInitialized() ) 324 { 325 final String message = 326 "BCELMethodFieldImplementationGenerator is not initialized."; 327 throw new IllegalStateException ( message ); 328 } 329 if ( meth.name == null 330 || meth.returnType == null 331 || meth.parameterTypes == null 332 || meth.exceptionNames == null ) 333 { 334 final String message = "None of the parameters may be <null>."; 335 throw new IllegalArgumentException ( message ); 336 } 337 338 final MethodGen mg = 339 new MethodGen( 340 Constants.ACC_PUBLIC, 341 meth.returnType, 342 meth.parameterTypes, 343 null, 344 meth.name, 345 m_wrapperClassName, 346 m_instructionList, 347 m_constPoolGenerator ); 348 349 for ( int i = 0; i < meth.exceptionNames.length; i++ ) 351 { 352 mg.addException( meth.exceptionNames[i] ); 353 } 354 355 m_instructionList.append( 357 InstructionFactory.createLoad( Type.OBJECT, 0 ) ); 358 m_instructionList.append( 359 m_instructionFactory.createFieldAccess( 360 m_wrapperClassName, 361 WRAPPED_CLASS_FN, 362 m_classToWrapType, 363 Constants.GETFIELD ) ); 364 365 short stackIndex = 1; 367 for ( int i = 0; i < meth.parameterTypes.length; ++i ) 369 { 370 m_instructionList.append( 371 InstructionFactory.createLoad( meth.parameterTypes[i], stackIndex ) ); 372 stackIndex += meth.parameterTypes[i].getSize(); 373 } 374 375 findImplementation( meth ); 376 377 m_instructionList.append( 380 m_instructionFactory.createInvoke( 381 meth.implementingClassName, 382 meth.name, 383 meth.returnType, 384 meth.parameterTypes, 385 Constants.INVOKEVIRTUAL ) ); 386 387 m_instructionList.append( InstructionFactory.createReturn( meth.returnType ) ); 389 390 mg.setMaxStack(); 391 mg.setMaxLocals(); 392 393 return extractMethod( mg ); 394 } 395 396 private void findImplementation( MethodDesc meth ) 397 { 398 JavaClass currentClass = m_classToWrap; 399 400 while ( null != currentClass && null == meth.implementingClassName ) 401 { 402 Method[] methList = currentClass.getMethods(); 403 404 for (int i = 0; i < methList.length; i++) 405 { 406 boolean isEqual = methList[i].isPublic() && !methList[i].isAbstract(); 407 isEqual = isEqual && methList[i].getName().equals(meth.name); 408 isEqual = isEqual && methList[i].getReturnType().equals(meth.returnType); 409 isEqual = isEqual && methList[i].getArgumentTypes().length == meth.parameterTypes.length; 410 Type[] parameterTypes = methList[i].getArgumentTypes(); 411 for (int j = 0; isEqual && j < parameterTypes.length; j++) 412 { 413 isEqual = isEqual && parameterTypes[j].equals(meth.parameterTypes[j]); 414 } 415 416 if (isEqual) 417 { 418 meth.implementingClassName = currentClass.getClassName(); 419 meth.isFinal = methList[i].isFinal(); 420 } 421 } 422 423 currentClass = currentClass.getSuperClass(); 424 } 425 426 if (null == meth.implementingClassName) 427 { 428 throw new IllegalStateException ("No concrete class for the requested method: " + meth.toString()); 429 } 430 } 431 432 451 public Method createMethodWrapper( final Method methodToWrap ) 452 throws IllegalArgumentException , IllegalStateException 453 { 454 if ( methodToWrap == null ) 455 { 456 final String message = "Method parameter must not be <null>."; 457 throw new IllegalArgumentException ( message ); 458 } 459 460 return createMethodWrapper( new MethodDesc( methodToWrap ) ); 461 } 462 463 474 public Method[] createImplementation( final JavaClass[] interfacesToImplement ) 475 throws Exception 476 { 477 if ( interfacesToImplement == null ) 478 { 479 final String message = "Interface to implement must not be <null>."; 480 throw new IllegalArgumentException ( message ); 481 } 482 if ( !isInitialized() ) 483 { 484 final String message = 485 "BCELInterfaceImplementationGenerator is not initialized."; 486 throw new IllegalStateException ( message ); 487 } 488 final Set gmList = new HashSet (); 489 490 final MethodDesc[] interfaceMethods = extractMethods( interfacesToImplement ); 491 for ( int i = 0; i < interfaceMethods.length; ++i ) 492 { 493 final MethodDesc im = interfaceMethods[i]; 494 495 if ( im.name.equals( "<clinit>" ) ) 497 { 498 continue; 499 } 500 501 final Method generatedMethod = 502 createMethodWrapper( im ); 503 504 gmList.add( generatedMethod ); 505 } 506 507 return (Method[]) gmList.toArray( new Method[gmList.size()] ); 508 } 509 510 521 private Method extractMethod( final MethodGen mg ) 522 { 523 final Method m = mg.getMethod(); 524 m_instructionList.dispose(); 525 return m; 526 } 527 528 533 private boolean isInitialized() 534 { 535 return m_isInitialized; 536 } 537 538 551 static MethodDesc[] extractMethods( final JavaClass interfacesToImplement[] ) 552 throws Exception 553 { 554 if ( interfacesToImplement == null ) 555 { 556 final String message = "JavaClass[] parameter must not be <null>."; 557 throw new NullPointerException ( message ); 558 } 559 560 Set methods = new HashSet (); 561 for (int x = 0; x < interfacesToImplement.length; x++) 562 { 563 JavaClass iface = interfacesToImplement[x]; 564 if ( !iface.isInterface() ) 565 { 566 final String message = "JavaClass parameter must be an interface"; 567 throw new IllegalArgumentException ( message ); 568 } 569 570 extractMethods( iface, methods ); 571 } 572 573 return (MethodDesc[]) methods.toArray( new MethodDesc[]{} ); 574 } 575 576 private static final void extractMethods( final JavaClass interfaceToImplement, final Set methods ) 577 { 578 Method[] meth = interfaceToImplement.getMethods(); 579 for ( int m = 0; m < meth.length; m++ ) 580 { 581 MethodDesc desc = new MethodDesc(meth[m]); 582 methods.add( desc ); 583 } 584 } 585 586 private static final class MethodDesc 587 { 588 final String name; 589 final Type returnType; 590 final Type[] parameterTypes; 591 String [] exceptionNames; 592 boolean isFinal; 593 String implementingClassName; 594 595 MethodDesc( Method meth ) 596 { 597 this(meth.getName(), meth.getReturnType(), meth.getArgumentTypes(), 598 (null == meth.getExceptionTable() ) ? new String [0] : meth.getExceptionTable().getExceptionNames()); 599 } 600 601 MethodDesc(String name, Type returnType, Type[] parameterTypes, String [] exceptionNames) 602 { 603 this.name = name; 604 this.returnType = returnType; 605 this.parameterTypes = parameterTypes; 606 this.exceptionNames = exceptionNames; 607 isFinal = false; 608 } 609 610 public boolean equals(Object o) 611 { 612 MethodDesc other = (MethodDesc)o; 613 boolean isEqual = name.equals(other.name); 614 isEqual = isEqual && returnType.equals(other.returnType); 615 isEqual = isEqual && parameterTypes.length == other.parameterTypes.length; 616 617 for (int i = 0; isEqual && i < parameterTypes.length; i++) 618 { 619 isEqual = isEqual && parameterTypes[i].equals(other.parameterTypes[i]); 620 } 621 622 return isEqual; 623 } 624 625 public int hashCode() 626 { 627 int hash = name.hashCode(); 628 hash >>>= 5; 629 hash ^= returnType.hashCode(); 630 631 for (int i = 0; i < parameterTypes.length; i++) 632 { 633 hash >>>= parameterTypes.length; 634 hash ^= parameterTypes[i].hashCode(); 635 } 636 637 return hash; 638 } 639 640 public String toString() 641 { 642 StringBuffer str = new StringBuffer (returnType.getSignature()); 643 str.append( " " ).append( name ).append( "(" ); 644 645 for(int i = 0; i < parameterTypes.length; i++) 646 { 647 str.append(parameterTypes[i].toString()); 648 if (i > 0) str.append(","); 649 } 650 651 str.append("),").append((isFinal) ? "f" : "v"); 652 653 return str.toString(); 654 } 655 } 656 } 657 | Popular Tags |