1 17 18 package org.apache.avalon.fortress.impl.factory; 19 20 import org.apache.bcel.Constants; 21 import org.apache.bcel.classfile.JavaClass; 22 import org.apache.bcel.classfile.Method; 23 import org.apache.bcel.generic.ClassGen; 24 import org.apache.bcel.generic.Type; 25 import org.apache.bcel.util.ClassLoaderRepository; 26 import org.apache.bcel.util.Repository; 27 28 33 34 35 final class BCELWrapperGenerator 36 37 { 38 42 private Repository m_repository = null; 43 44 48 private static final String WRAPPER_CLASS_SUFFIX = "$BCELWrapper"; 49 50 53 private static final String WRAPPER_SUPERCLASS_NAME = "java.lang.Object"; 54 55 58 private static final String WRAPPER_CLASS_INTERFACE_NAME = 59 WrapperClass.class.getName(); 60 61 65 private final BCELCodeGenerator m_codeGenerator; 66 67 70 private ClassGen m_classGenerator = null; 71 72 76 private final BCELClassLoader m_bcelClassLoader; 77 78 81 private final class BCELClassLoader extends ClassLoader 82 83 { 84 89 private byte[] m_byteCode = null; 90 91 97 public BCELClassLoader( final ClassLoader parent ) 98 { 99 super( parent ); 100 } 101 102 106 public BCELClassLoader() 107 { 108 super(); 109 } 110 111 115 protected Class findClass( final String name ) throws ClassNotFoundException 116 { 117 if ( name.endsWith( WRAPPER_CLASS_SUFFIX ) ) 120 { 121 return super.defineClass( 122 name, 123 getByteCode(), 124 0, 125 getByteCode().length ); 126 } 127 128 return super.findClass( name ); 129 } 130 131 143 private void setByteCode( final byte[] byteCode ) 144 throws IllegalArgumentException 145 { 146 if ( byteCode == null || byteCode.length == 0 ) 147 { 148 final String message = 149 "Parameter byteCode must neither be <null> nor empty."; 150 throw new IllegalArgumentException ( message ); 151 } 152 153 m_byteCode = byteCode; 154 } 155 156 162 private void clearByteCode() 163 { 164 m_byteCode = null; 165 } 166 167 173 private byte[] getByteCode() 174 { 175 return m_byteCode; 176 } 177 } 179 182 public BCELWrapperGenerator() 183 { 184 m_codeGenerator = new BCELCodeGenerator(); 185 ClassLoader contextClassLoader = 186 Thread.currentThread().getContextClassLoader(); 187 m_repository = new ClassLoaderRepository( contextClassLoader ); 188 m_bcelClassLoader = 189 new BCELClassLoader( contextClassLoader ); 190 } 191 192 194 public synchronized Class createWrapper( final Class classToWrap ) throws Exception 195 { 196 if ( classToWrap == null ) 197 { 198 final String message = "Class to wrap must not be <null>."; 199 throw new IllegalArgumentException ( message ); 200 } 201 202 final Class [] interfacesToImplement = 204 AbstractObjectFactory.guessWorkInterfaces( classToWrap ); 205 206 final JavaClass javaClassToWrap = lookupClass( classToWrap ); 208 final JavaClass[] javaInterfacesToImplement = 209 lookupClasses( interfacesToImplement ); 210 211 final String wrapperClassName = 213 classToWrap.getName() + WRAPPER_CLASS_SUFFIX; 214 215 Class generatedClass; 216 synchronized ( Type.class ) 217 { 218 m_classGenerator = 220 new ClassGen( 221 wrapperClassName, 222 WRAPPER_SUPERCLASS_NAME, 223 null, 224 Constants.ACC_FINAL 225 |Constants.ACC_PUBLIC 226 |Constants.ACC_SUPER, 227 extractInterfaceNames( interfacesToImplement ) ); 228 229 m_codeGenerator.init( 231 wrapperClassName, 232 WRAPPER_SUPERCLASS_NAME, 233 javaClassToWrap, 234 m_classGenerator ); 235 236 final byte[] byteCode = buildWrapper( javaInterfacesToImplement ); 237 m_bcelClassLoader.setByteCode( byteCode ); 238 generatedClass = m_bcelClassLoader.loadClass( wrapperClassName ); 239 m_bcelClassLoader.clearByteCode(); 240 } 241 242 return generatedClass; 243 } 244 245 254 private JavaClass lookupClass( final Class clazz ) throws Exception 255 { 256 String className = clazz.getName(); 257 try 258 { 259 JavaClass jClazz = m_repository.findClass( className ); 260 if ( jClazz == null ) 261 return m_repository.loadClass( className ); 262 else 263 return jClazz; 264 } catch ( ClassNotFoundException e ) { return null; } 265 } 266 267 276 private JavaClass[] lookupClasses( final Class [] classes ) throws Exception 277 { 278 final JavaClass[] javaClasses = new JavaClass[classes.length]; 279 for ( int i = 0; i < classes.length; ++i ) 280 { 281 javaClasses[i] = lookupClass( classes[i] ); 282 } 283 284 return javaClasses; 285 } 286 287 294 private String [] extractInterfaceNames( final Class [] interfaces ) 295 { 296 final String [] ifaceNames = new String [interfaces.length + 1]; 297 for ( int i = 0; i < interfaces.length; ++i ) 298 { 299 ifaceNames[i] = interfaces[i].getName(); 300 } 301 ifaceNames[ifaceNames.length - 1] = WRAPPER_CLASS_INTERFACE_NAME; 303 304 return ifaceNames; 305 } 306 307 314 private byte[] buildWrapper( final JavaClass[] interfacesToImplement ) throws Exception 315 { 316 m_classGenerator.addField( m_codeGenerator.createWrappedClassField() ); 318 319 m_classGenerator.addMethod( m_codeGenerator.createDefaultConstructor() ); 321 322 m_classGenerator.addMethod( 324 m_codeGenerator.createWrappedClassAccessor() ); 325 326 Method[] interfaceMethods = m_codeGenerator.createImplementation( interfacesToImplement ); 328 329 for ( int j = 0; j < interfaceMethods.length; ++j ) 330 { 331 m_classGenerator.addMethod( interfaceMethods[j] ); 332 } 333 334 return m_classGenerator.getJavaClass().getBytes(); 335 } 336 } 337 | Popular Tags |