View Javadoc
1 /* 2 Copyright (c) 2003, Laurent Caillette. 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without modifica- 6 tion, are permitted provided that the following conditions are met: 7 8 1. Redistributions of source code must retain the above copyright notice, 9 this list of conditions and the following disclaimer. 10 11 2. Redistributions in binary form must reproduce the above copyright notice, 12 this list of conditions and the following disclaimer in the documentation 13 and/or other materials provided with the distribution. 14 15 3. The end-user documentation included with the redistribution, if any, must 16 include the following acknowledgment: "This product includes software 17 written by Laurent Caillette." 18 Alternately, this acknowledgment may appear in the software itself, if 19 and wherever such third-party acknowledgments normally appear. 20 21 4. The name "Laurent Caillette" must not be used to endorse or 22 promote products derived from this software without 23 prior written permission. For written permission, please contact 24 laurent.caillette@laposte.net 25 26 5. Products derived from this software may not be called 27 "Laurent Caillette", nor may "Laurent Caillette" appear 28 in their name, without prior written permission of the 29 author. 30 31 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 32 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 33 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 34 AUTHOR (LAURENT CAILLETTE) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 36 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 37 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 40 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 */ 42 package tweed.system.interceptor; 43 import java.io.IOException; 44 import java.io.OutputStream; 45 import java.lang.reflect.Method; 46 import org.apache.bcel.Constants; 47 import org.apache.bcel.generic.ArrayType; 48 import org.apache.bcel.generic.ClassGen; 49 import org.apache.bcel.generic.ConstantPoolGen; 50 import org.apache.bcel.generic.FieldGen; 51 import org.apache.bcel.generic.InstructionConstants; 52 import org.apache.bcel.generic.InstructionFactory; 53 import org.apache.bcel.generic.InstructionHandle; 54 import org.apache.bcel.generic.InstructionList; 55 import org.apache.bcel.generic.MethodGen; 56 import org.apache.bcel.generic.ObjectType; 57 import org.apache.bcel.generic.PUSH; 58 import org.apache.bcel.generic.Type; 59 60 /*** 61 * Build the bytecode of a class deriving the subject class, with calls to 62 * a {@link InterceptionHandler} when 63 * {@link Override#getShouldIntercept override} 64 * indicate to do so. 65 * 66 * @author Laurent Caillette 67 * @version $Id$ 68 */ 69 public class CodeBuilder implements Constants { 70 71 // Ugly comments in the source code are supposed to be kept, 72 // they can be useful for debugging. Commented code is the one 73 // generated by the BCELIfier ran on a hard-coded interceptor class 74 // to get inspiration from. 75 76 private InstructionFactory _factory; 77 private ConstantPoolGen _cp; 78 private ClassGen _cg; 79 80 private final Class subjectClass ; 81 private final Override[] overrides ; 82 private final String interceptorClassName ; 83 private final String subjectClassName ; 84 85 public final static String createInterceptorClassName( Class subjectClass ) { 86 return subjectClass.getName() + "$Interceptor" ; 87 } 88 89 public CodeBuilder( 90 Class subjectClass, 91 Override[] overrides 92 ) { 93 94 this.subjectClass = subjectClass ; 95 subjectClassName = subjectClass.getName() ; 96 this.interceptorClassName = createInterceptorClassName( subjectClass ) ; 97 this.overrides = overrides ; 98 99 // _cg = new ClassGen( 100 // "tweed.system.interceptor.MyBeanInterceptor", 101 // "tweed.system.interceptor.MyBean", 102 // "MyBeanInterceptor.java", 103 // ACC_PUBLIC | ACC_SUPER, 104 // new String[] { } 105 // ) ; 106 _cg = new ClassGen( 107 interceptorClassName, 108 subjectClassName, 109 interceptorClassName + ".java", 110 ACC_PUBLIC | ACC_SUPER, 111 new String[] { } 112 ) ; 113 _cp = _cg.getConstantPool(); 114 _factory = new InstructionFactory(_cg, _cp); 115 } 116 117 public void create(OutputStream out) throws IOException { 118 119 createFields(); 120 createConstructor(); 121 122 for( int i = 0 ; i < overrides.length ; i++ ) { 123 Override override = overrides[ i ] ; 124 if( override.getShouldIntercept() ) { 125 createInterceptedMethod( override.getMethod(), i ) ; 126 } else { 127 createNonInterceptedMethod( override.getMethod() ) ; 128 } 129 } 130 131 _cg.getJavaClass().dump(out); 132 } 133 134 private void createFields() { 135 FieldGen field; 136 137 field = new FieldGen( 138 ACC_PRIVATE | ACC_FINAL, 139 // new ObjectType( "tweed.system.interceptor.MySimpleBean" ), 140 new ObjectType( subjectClassName ), 141 "subject", 142 _cp 143 ) ; 144 _cg.addField( field.getField() ) ; 145 146 field = new FieldGen( 147 ACC_PRIVATE | ACC_FINAL, 148 // new ObjectType( "tweed.system.interceptor.InterceptionHandler" ), 149 new ObjectType( InterceptionHandler.class.getName() ), 150 "interceptor", 151 _cp 152 ) ; 153 _cg.addField( field.getField() ) ; 154 155 field = new FieldGen( 156 ACC_PUBLIC | ACC_FINAL, 157 new ArrayType( 158 // new ObjectType( "tweed.system.interceptor.MethodDescriptor" ), 159 new ObjectType( MethodDescriptor.class.getName() ), 160 1 161 ), 162 "methodDescriptors", 163 _cp 164 ) ; 165 _cg.addField( field.getField() ) ; 166 } 167 168 169 private void createConstructor() { 170 171 InstructionList il = new InstructionList() ; 172 MethodGen method = new MethodGen( 173 ACC_PUBLIC, 174 Type.VOID, 175 new Type[] { 176 // new ObjectType( "tweed.system.interceptor.MySimpleBean" ), 177 new ObjectType( subjectClassName ), 178 // new ObjectType( "tweed.system.interceptor.InterceptionHandler" ) 179 new ObjectType( InterceptionHandler.class.getName() ) 180 }, 181 new String[] { "arg0", "arg1" }, 182 "<init>", 183 // "tweed.system.interceptor.MySimpleBean$Interceptor", 184 interceptorClassName, 185 il, 186 _cp 187 ) ; 188 189 InstructionHandle ih_0 = il.append( 190 _factory.createLoad( Type.OBJECT, 0 ) ) ; 191 il.append( 192 _factory.createInvoke( 193 // "tweed.system.interceptor.MySimpleBean", 194 subjectClassName, 195 "<init>", 196 Type.VOID, 197 Type.NO_ARGS, 198 Constants.INVOKESPECIAL 199 ) 200 ) ; 201 InstructionHandle ih_4 = 202 il.append( _factory.createLoad( Type.OBJECT, 0 ) ) ; 203 // il.append( new PUSH( _cp, 2 ) ) ; 204 il.append( new PUSH( _cp, overrides.length ) ) ; 205 il.append( _factory.createNewArray( 206 new ObjectType( 207 // "tweed.system.interceptor.MethodDescriptor" 208 MethodDescriptor.class.getName() 209 ), 210 ( short ) 1 211 ) ) ; 212 il.append( 213 _factory.createFieldAccess( 214 // "tweed.system.interceptor.MySimpleBean$Interceptor", 215 interceptorClassName, 216 "methodDescriptors", 217 new ArrayType( 218 // new ObjectType( "tweed.system.interceptor.MethodDescriptor" ), 219 new ObjectType( MethodDescriptor.class.getName() ), 220 1 221 ), 222 Constants.PUTFIELD 223 ) 224 ) ; 225 InstructionHandle ih_12 = il.append( 226 _factory.createLoad( Type.OBJECT, 0 ) ) ; 227 il.append( _factory.createLoad( Type.OBJECT, 1 ) ) ; 228 il.append( _factory.createFieldAccess( 229 // "tweed.system.interceptor.MySimpleBean$Interceptor", 230 interceptorClassName, 231 "subject", 232 // new ObjectType( "tweed.system.interceptor.MySimpleBean" ), 233 new ObjectType( subjectClassName ), 234 Constants.PUTFIELD 235 ) ) ; 236 InstructionHandle ih_17 = il.append( _factory.createLoad( 237 Type.OBJECT, 0 ) ) ; 238 il.append( _factory.createLoad( Type.OBJECT, 2 ) ) ; 239 il.append( 240 _factory.createFieldAccess( 241 // "tweed.system.interceptor.MySimpleBean$Interceptor", 242 interceptorClassName, 243 "interceptor", 244 // new ObjectType( "tweed.system.interceptor.InterceptionHandler" ), 245 new ObjectType( InterceptionHandler.class.getName() ), 246 Constants.PUTFIELD 247 ) 248 ) ; 249 InstructionHandle ih_22 = il.append( _factory.createReturn( Type.VOID ) ) ; 250 method.setMaxStack() ; 251 method.setMaxLocals() ; 252 _cg.addMethod( method.getMethod() ) ; 253 il.dispose() ; 254 } 255 256 private void createInterceptedMethod( Method template, int methodIndex ) { 257 258 InstructionList il = new InstructionList(); 259 260 Class[] parameterTypes = template.getParameterTypes() ; 261 int parameterCount = parameterTypes.length ; 262 Type[] argTypes = new Type[ parameterCount ] ; 263 String[] argNames = new String[ parameterCount ] ; 264 for( int i = 0 ; i < parameterCount ; i++ ) { 265 argTypes[ i ] = Type.getType( parameterTypes[ i ] ) ; 266 argNames[ i ] = "p" + i ; 267 } 268 269 MethodGen method = new MethodGen( 270 ACC_PUBLIC, 271 // Type.OBJECT, 272 Type.getType( template.getReturnType() ), 273 // Type.NO_ARGS, 274 argTypes, 275 // new String[] { }, 276 argNames, 277 // "getMyObject", 278 template.getName(), 279 // "tweed.system.interceptor.MySimpleBean$Interceptor", 280 interceptorClassName, 281 il, 282 _cp 283 ) ; 284 285 InstructionHandle ih_0 = il.append( 286 _factory.createLoad( Type.OBJECT, 0 ) ) ; 287 il.append( 288 _factory.createFieldAccess( 289 // "tweed.system.interceptor.MySimpleBean$Interceptor", 290 interceptorClassName, 291 "interceptor", 292 new ObjectType( 293 // "tweed.system.interceptor.InterceptionHandler" 294 InterceptionHandler.class.getName() 295 ), 296 Constants.GETFIELD 297 ) 298 ) ; 299 il.append( _factory.createLoad( Type.OBJECT, 0 ) ) ; 300 il.append( _factory.createFieldAccess( 301 // "tweed.system.interceptor.MySimpleBean$Interceptor", 302 interceptorClassName, 303 "subject", 304 // new ObjectType( "tweed.system.interceptor.MySimpleBean" ), 305 new ObjectType( subjectClassName ), 306 Constants.GETFIELD 307 ) ) ; 308 il.append( _factory.createLoad( Type.OBJECT, 0 ) ) ; 309 il.append( _factory.createFieldAccess( 310 // "tweed.system.interceptor.MySimpleBean$Interceptor", 311 interceptorClassName, 312 "methodDescriptors", 313 new ArrayType( 314 // new ObjectType( "tweed.system.interceptor.MethodDescriptor" ), 315 new ObjectType( MethodDescriptor.class.getName() ), 316 1 317 ), 318 Constants.GETFIELD 319 ) ) ; 320 // il.append( new PUSH( _cp, 0 ) ) ; 321 il.append( new PUSH( _cp, methodIndex ) ) ; 322 323 il.append( InstructionConstants.AALOAD ) ; 324 il.append( 325 _factory.createInvoke( 326 // "tweed.system.interceptor.InterceptionHandler", 327 InterceptionHandler.class.getName(), 328 "handleMethod", 329 Type.VOID, 330 new Type[] { 331 Type.OBJECT, 332 // new ObjectType( "tweed.system.interceptor.MethodDescriptor" ) 333 new ObjectType( MethodDescriptor.class.getName() ) 334 }, 335 Constants.INVOKEVIRTUAL 336 ) 337 ) ; 338 339 InstructionHandle ih_17 = il.append( 340 _factory.createLoad( Type.OBJECT, 0 ) ) ; 341 il.append( 342 _factory.createFieldAccess( 343 // "tweed.system.interceptor.MySimpleBean$Interceptor", 344 interceptorClassName, 345 "subject", 346 new ObjectType( subjectClassName ), 347 Constants.GETFIELD 348 ) 349 ) ; 350 il.append( 351 _factory.createInvoke( 352 // "tweed.system.interceptor.MySimpleBean", 353 subjectClassName, 354 // "getMyObject", 355 template.getName(), 356 // Type.OBJECT, 357 Type.getType( template.getReturnType() ), 358 // Type.NO_ARGS, 359 argTypes, 360 Constants.INVOKEVIRTUAL 361 // Oops, code below doesn't seem to work, what's wrong with it? 362 // template.getDeclaringClass().equals( subjectClass ) ? 363 // Constants.INVOKEVIRTUAL : 364 // Constants.INVOKESPECIAL 365 ) 366 ) ; 367 InstructionHandle ih_24 = il.append( 368 // _factory.createReturn( Type.OBJECT ) ) ; 369 _factory.createReturn( Type.getType( template.getReturnType() ) ) ) ; 370 method.setMaxStack(); 371 method.setMaxLocals(); 372 _cg.addMethod(method.getMethod()); 373 il.dispose(); 374 375 } 376 377 private void createNonInterceptedMethod( Method template ) { 378 379 InstructionList il = new InstructionList(); 380 381 Class[] parameterTypes = template.getParameterTypes() ; 382 int parameterCount = parameterTypes.length ; 383 Type[] argTypes = new Type[ parameterCount ] ; 384 String[] argNames = new String[ parameterCount ] ; 385 for( int i = 0 ; i < parameterCount ; i++ ) { 386 argTypes[ i ] = Type.getType( parameterTypes[ i ] ) ; 387 argNames[ i ] = "p" + i ; 388 } 389 Type returnType = Type.getType( template.getReturnType() ) ; 390 391 MethodGen method = new MethodGen( 392 ACC_PUBLIC, 393 // Type.VOID, 394 returnType, 395 // new Type[] { Type.OBJECT }, 396 argTypes, 397 // new String[] { "arg0" }, 398 argNames, 399 // "setMyObject", 400 template.getName(), 401 // "tweed.system.interceptor.MySimpleBean$Interceptor", 402 interceptorClassName, 403 il, 404 _cp 405 ) ; 406 407 createDelegateCall( il, template ) ; 408 409 method.setMaxStack(); 410 method.setMaxLocals(); 411 _cg.addMethod(method.getMethod()); 412 il.dispose(); 413 } 414 415 private void createDelegateCall( InstructionList il, Method template ) { 416 417 Type returnType = Type.getType( template.getReturnType() ) ; 418 Class[] parameterTypes = template.getParameterTypes() ; 419 int parameterCount = parameterTypes.length ; 420 Type[] argTypes = new Type[ parameterCount ] ; 421 String[] argNames = new String[ parameterCount ] ; 422 for( int i = 0 ; i < parameterCount ; i++ ) { 423 argTypes[ i ] = Type.getType( parameterTypes[ i ] ) ; 424 argNames[ i ] = "p" + i ; 425 } 426 427 InstructionHandle ih_0 = il.append( _factory.createLoad( 428 Type.OBJECT, 429 0 430 ) ) ; 431 il.append(_factory.createFieldAccess( 432 // "tweed.system.interceptor.MySimpleBean$Interceptor", 433 interceptorClassName, 434 "subject", 435 // new ObjectType("tweed.system.interceptor.MySimpleBean"), 436 new ObjectType( subjectClassName ), 437 Constants.GETFIELD 438 ) ) ; 439 440 for( int i = 0 ; i < argTypes.length ; i++ ) { 441 il.append( _factory.createLoad( argTypes[ i ], i + 1 ) ) ; 442 } 443 444 il.append( _factory.createInvoke( 445 // "tweed.system.interceptor.MySimpleBean", 446 subjectClassName, 447 // "setMyObject", 448 template.getName(), 449 // Type.VOID, 450 returnType, 451 // new Type[] { Type.OBJECT }, 452 argTypes, 453 Constants.INVOKEVIRTUAL 454 // template.getDeclaringClass().equals( subjectClass ) ? 455 // Constants.INVOKEVIRTUAL : 456 // Constants.INVOKESPECIAL 457 )); 458 // InstructionHandle ih_8 = il.append( _factory.createReturn( Type.VOID ) ) ; 459 InstructionHandle ih_8 = il.append( _factory.createReturn( returnType ) ) ; 460 461 462 } 463 464 }

This page was automatically generated by Maven