1 2 3 package org.quilt.cl; 4 5 import java.io.*; 6 import java.lang.reflect.Method ; 7 import java.util.*; 8 9 import org.apache.bcel.Constants; 10 import org.apache.bcel.classfile.*; 11 import org.apache.bcel.generic.*; 12 13 39 public class ClassFactory { 40 41 private static ClassFactory instance = new ClassFactory(); 42 private String interfaces[] = new String [] { 43 "org.quilt.cl.RunTest" }; 44 45 46 private ClassFactory() { } 47 48 53 public static ClassFactory getInstance() { 54 return instance; 55 } 56 66 public InputStream getResourceAsStream( final String resName ) { 67 String className = 68 resName.substring(0, resName.indexOf(".class")); 69 className = className.replace( File.separatorChar, '.'); 70 71 try { 72 PipedInputStream returnStream = 73 new PipedInputStream(); 74 PipedOutputStream outputStream = 75 new PipedOutputStream( returnStream ); 76 ClassGen clazz = ClassFactory.getInstance(). 77 makeClass( className, resName); 78 clazz.getJavaClass().dump( outputStream ); 79 return returnStream; 80 } catch (IOException exception) { 81 System.out.println("Unable to return Resource as InputStream."); 83 exception.printStackTrace(); 84 return null; 85 } 86 } 87 107 public ClassGen makeClass( String className, String fileName ) { 108 ClassGen newClass = 109 new ClassGen( className, "java.lang.Object", fileName, 110 Constants.ACC_PUBLIC, interfaces); 111 112 MethodGen constructor = makeConstructor( newClass ); 113 newClass.addMethod( constructor.getMethod() ); 114 115 MethodGen testMethod = makeMethod( newClass ); 116 org.apache.bcel.classfile.Method m = testMethod.getMethod(); 117 118 newClass.addMethod( m ); 119 120 return newClass; 121 } 122 129 public MethodGen makeConstructor( ClassGen clazz ) { 130 InstructionFactory factory = 131 new InstructionFactory( clazz ); 132 133 InstructionList instructions = new InstructionList(); 134 135 instructions.append( new ALOAD(0) ); 136 instructions.append( factory.createInvoke( 137 "java.lang.Object", "<init>", Type.VOID, 138 new Type[0], Constants.INVOKESPECIAL ) ); 139 instructions.append( new RETURN() ); 140 141 MethodGen returnMethod = 142 new MethodGen( Constants.ACC_PUBLIC, Type.VOID, 143 new Type[0], new String [0], 144 "<init>", clazz.getClassName(), 145 instructions, clazz.getConstantPool() ); 146 147 returnMethod.setMaxStack(); 148 return returnMethod; 149 } 150 169 public MethodGen makeMethod( ClassGen clazz ) { 170 String className = clazz.getClassName(); 171 String reflectMeth = "mg" + className.substring( 172 "test.data.Test".length() ); 173 int underscore = reflectMeth.indexOf('_'); 174 if (underscore > 0 ) { 175 reflectMeth = reflectMeth.substring(0, underscore); 176 } 177 InstructionList instructions = null; 178 List catchBlocks = new ArrayList(); 179 180 MethodGen synthMethod = null; 181 try { 182 Method method = 183 this.getClass().getMethod( reflectMeth, 184 new Class [] { ClassGen.class } ); 185 synthMethod = 186 (MethodGen) method.invoke( this, 187 new Object [] { clazz }); 188 } catch (Exception e) { 189 if (! (e instanceof NoSuchMethodException ) ) { 190 e.printStackTrace(); 191 } 192 System.out.println( 193 "WARNING: ClassFactory using Default bytecode for " 194 + className ); 195 synthMethod = mgDefault( clazz ); 196 } 197 synthMethod.setMaxStack(); if (reflectMeth.compareTo("test.data.TestNPEWithCatch") == 0 ) { 200 CodeExceptionGen cegs[] = synthMethod.getExceptionHandlers(); 201 if (cegs.length != 1) { 202 System.out.println ("INTERNAL ERROR: " + reflectMeth 203 + "\n should have one exception handler, has " 204 + cegs.length); 205 } 206 } 207 return synthMethod; 209 } 210 225 public MethodGen mgDefault( ClassGen clazz) { 226 InstructionList instructions = new InstructionList(); 227 instructions.append( new ICONST( 2 )); 228 instructions.append( new IRETURN() ); 229 230 MethodGen returnMethod = 231 new MethodGen( Constants.ACC_PUBLIC, 232 Type.INT, 233 new Type[] { Type.INT }, 234 new String [] { "x" }, 235 "runTest", 236 clazz.getClassName(), 237 instructions, 238 clazz.getConstantPool()); 239 240 return returnMethod; 241 } 242 256 public MethodGen mgIfThen( ClassGen clazz ) { 257 InstructionList instructions = new InstructionList(); 258 instructions.append( new ILOAD( 1 )); 259 260 InstructionList thenClause = new InstructionList(); 261 thenClause.append( new ICONST( 3 )); 262 thenClause.append( new IRETURN() ); 263 264 InstructionList elseClause = new InstructionList(); 265 elseClause.append( new ICONST( 5 )); 266 elseClause.append( new IRETURN() ); 267 268 InstructionHandle elseHandle = 269 instructions.append( elseClause ); 270 InstructionHandle thenHandle = 271 instructions.append( thenClause ); 272 instructions.insert( elseHandle, new IFGT( thenHandle )); 273 274 MethodGen returnMethod = 275 new MethodGen( Constants.ACC_PUBLIC, 276 Type.INT, 277 new Type[] { Type.INT }, 278 new String [] { "x" }, 279 "runTest", 280 clazz.getClassName(), 281 instructions, 282 clazz.getConstantPool()); 283 284 return returnMethod; 285 } 286 297 public MethodGen mgNPENoCatch( ClassGen clazz ) { 298 InstructionFactory factory = new InstructionFactory( clazz ); 299 InstructionList instructions = new InstructionList(); 300 Type argTypes[] = new Type[1]; 301 302 argTypes[0] = Type.INT; 303 304 instructions.append( new ACONST_NULL() ); 305 instructions.append( new ICONST( 0 )); 306 instructions.append( factory.createInvoke( clazz.getClassName(), 307 "runTest", 308 Type.INT, 309 argTypes, 310 Constants.INVOKEVIRTUAL)); 311 312 instructions.append( new ICONST( 0 )); 313 instructions.append( new IRETURN() ); 314 315 MethodGen returnMethod = 316 new MethodGen( Constants.ACC_PUBLIC, 317 Type.INT, 318 new Type[] { Type.INT }, 319 new String [] { "x" }, 320 "runTest", 321 clazz.getClassName(), 322 instructions, 323 clazz.getConstantPool()); 324 325 return returnMethod; 326 } 327 340 public MethodGen mgNPEWithCatch( ClassGen clazz ) { 341 InstructionFactory factory = new InstructionFactory( clazz ); 342 InstructionList instructions = new InstructionList(); 343 344 Type argTypes[] = new Type[1]; 345 346 argTypes[0] = Type.INT; 347 348 ObjectType npeType = new ObjectType( 349 "java.lang.NullPointerException" ); 350 instructions.append( new ACONST_NULL() ); 351 instructions.append( new ICONST( 0 )); 352 instructions.append( factory.createInvoke( clazz.getClassName(), 353 "runTest", 354 Type.INT, 355 argTypes, 356 Constants.INVOKEVIRTUAL)); 357 358 instructions.append( new ICONST( -1 )); 359 instructions.append( new IRETURN() ); 360 361 InstructionHandle handler = 362 instructions.append( new ICONST( 3 )); 363 instructions.append( new IRETURN() ); 364 365 MethodGen returnMethod = 368 new MethodGen( Constants.ACC_PUBLIC, 369 Type.INT, 370 new Type[] { Type.INT }, 371 new String [] { "x" }, 372 "runTest", 373 clazz.getClassName(), 374 instructions, 375 clazz.getConstantPool()); 376 CodeExceptionGen ceg = 378 returnMethod.addExceptionHandler(instructions.getStart(), 380 handler.getPrev(), handler, 381 npeType ); 382 383 returnMethod.addException("java.lang.NullPointerException"); CodeExceptionGen cegs[] = returnMethod.getExceptionHandlers(); 387 388 if (ceg != cegs[0]) { 390 System.out.println( 391 " INTERNAL ERROR: exception handler added not found"); 392 } 393 return returnMethod; 395 } 396 410 public MethodGen mgSelect( ClassGen clazz ) { 411 412 InstructionList instructions = new InstructionList(); 413 instructions.append( new ILOAD( 1 )); 414 InstructionHandle caseHandles[] = new InstructionHandle[3]; 415 int caseMatches[] = new int[3]; 416 417 for (short i = 0; i < 3; i++) { 418 InstructionList caseList = new InstructionList(); 419 caseList.append( new SIPUSH( (short) (2*i + 1) )); 420 caseList.append( new IRETURN() ); 421 422 caseHandles[i] = instructions.append( caseList ); 423 caseMatches[i] = i + 1; 424 } 425 InstructionList dCase = new InstructionList(); 426 dCase.append( new SIPUSH( (short) 2 )); 427 dCase.append( new IRETURN() ); 428 InstructionHandle dHand = instructions.append( dCase ); 429 430 instructions.insert( caseHandles[0], 431 new LOOKUPSWITCH( caseMatches, 432 caseHandles, 433 dHand )); 434 MethodGen returnMethod = 435 new MethodGen( Constants.ACC_PUBLIC, 436 Type.INT, 437 new Type[] { Type.INT }, 438 new String [] { "x" }, 439 "runTest", 440 clazz.getClassName(), 441 instructions, 442 clazz.getConstantPool()); 443 444 return returnMethod; 445 } 446 473 public MethodGen mgWhile( ClassGen clazz ) { 474 InstructionList instructions = new InstructionList(); 475 instructions.append( new ILOAD( 1 )); 476 InstructionHandle ifHandle = 477 instructions.append( new DUP() ); 478 479 InstructionHandle loopHandle = 480 instructions.append( new ICONST( 1 ) ); 481 instructions.append( new ISUB() ); 482 instructions.append( new GOTO( ifHandle )); 483 484 InstructionHandle retHandle = 485 instructions.append( new IRETURN() ); 486 487 instructions.insert( loopHandle, new IFLE( retHandle )); 488 489 MethodGen returnMethod = 490 new MethodGen( Constants.ACC_PUBLIC, 491 Type.INT, 492 new Type[] { Type.INT }, 493 new String [] { "x" }, 494 "runTest", 495 clazz.getClassName(), 496 instructions, 497 clazz.getConstantPool()); 498 499 return returnMethod; 500 } 501 } 502 | Popular Tags |