[jboss-svn-commits] JBL Code SVN: r6714 - in labs/jbossrules/trunk/drools-core/src: main/java/org/drools/base test/java/org/drools/base
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Mon Oct 9 17:22:55 EDT 2006
Author: tirelli
Date: 2006-10-09 17:22:37 -0400 (Mon, 09 Oct 2006)
New Revision: 6714
Modified:
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java
Log:
Adding eager proxy creating support
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java 2006-10-09 20:51:28 UTC (rev 6713)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java 2006-10-09 21:22:37 UTC (rev 6714)
@@ -34,6 +34,8 @@
* A factory for ShadowProxy classes
*/
public class ShadowProxyFactory {
+ private static final String UPDATE_PROXY = "updateProxy";
+
private static final String BASE_INTERFACE = Type.getInternalName( ShadowProxy.class );
private static final String FIELD_NAME_PREFIX = "__";
@@ -45,9 +47,8 @@
public static Class getProxy(final Class clazz) {
try {
String className = null;
- if( clazz.getPackage().getName().startsWith( "java." ) ||
- clazz.getPackage().getName().startsWith( "javax." )) {
- className = "org/drools/shadow/"+Type.getInternalName( clazz )+"ShadowProxy";
+ if ( clazz.getPackage().getName().startsWith( "java." ) || clazz.getPackage().getName().startsWith( "javax." ) ) {
+ className = "org/drools/shadow/" + Type.getInternalName( clazz ) + "ShadowProxy";
} else {
className = Type.getInternalName( clazz ) + "ShadowProxy";
}
@@ -65,6 +66,28 @@
}
}
+ public static Class getEagerProxy(final Class clazz) {
+ try {
+ String className = null;
+ if ( clazz.getPackage().getName().startsWith( "java." ) || clazz.getPackage().getName().startsWith( "javax." ) ) {
+ className = "org/drools/shadow/" + Type.getInternalName( clazz ) + "EagerShadowProxy";
+ } else {
+ className = Type.getInternalName( clazz ) + "EagerShadowProxy";
+ }
+ // generating byte array to create target class
+ final byte[] bytes = dumpEager( clazz,
+ className );
+ // use bytes to get a class
+ final ByteArrayClassLoader classLoader = new ByteArrayClassLoader( Thread.currentThread().getContextClassLoader() );
+ final Class newClass = classLoader.defineClass( className.replace( '/',
+ '.' ),
+ bytes );
+ return newClass;
+ } catch ( final Exception e ) {
+ throw new RuntimeDroolsException( e );
+ }
+ }
+
protected static byte[] dump(final Class clazz,
final String className) throws Exception {
@@ -79,11 +102,9 @@
cw );
Map fieldTypes = new HashMap();
-
Method[] methods = clazz.getMethods();
for ( int i = 0; i < methods.length; i++ ) {
- if ( (! Modifier.isFinal( methods[i].getModifiers() )) &&
- Modifier.isPublic( methods[i].getModifiers() )) {
+ if ( (!Modifier.isFinal( methods[i].getModifiers() )) && Modifier.isPublic( methods[i].getModifiers() ) ) {
if ( (!methods[i].getReturnType().equals( Void.TYPE )) && (methods[i].getParameterTypes().length == 0) ) {
String fieldName = methods[i].getName();
@@ -117,9 +138,69 @@
cw );
buildUpdateProxyMethod( fieldTypes,
+ className,
+ cw );
+
+ return cw.toByteArray();
+ }
+
+ protected static byte[] dumpEager(final Class clazz,
+ final String className) throws Exception {
+
+ final ClassWriter cw = new ClassWriter( true );
+
+ buildClassHeader( clazz,
+ className,
+ cw );
+
+ buildField( DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ),
+ cw );
+
+ Map fieldTypes = new HashMap();
+ Map fieldMethods = new HashMap();
+
+ Method[] methods = clazz.getMethods();
+ for ( int i = 0; i < methods.length; i++ ) {
+ if ( (!Modifier.isFinal( methods[i].getModifiers() )) && Modifier.isPublic( methods[i].getModifiers() ) ) {
+ if ( (!methods[i].getReturnType().equals( Void.TYPE )) && (methods[i].getParameterTypes().length == 0) &&
+ ((methods[i].getName().startsWith( "get" )) || (methods[i].getName().startsWith( "is" )))) {
+ String fieldName = methods[i].getName();
+
+ buildField( FIELD_NAME_PREFIX + fieldName,
+ Type.getDescriptor( methods[i].getReturnType() ),
+ cw );
+ fieldMethods.put( FIELD_NAME_PREFIX + fieldName,
+ methods[i] );
+ fieldTypes.put( FIELD_NAME_PREFIX + fieldName,
+ methods[i].getReturnType() );
+
+ buildSimpleGetMethod( FIELD_NAME_PREFIX + fieldName,
+ methods[i].getReturnType(),
+ FIELD_NAME_PREFIX + fieldName + FIELD_SET_FLAG,
+ methods[i],
+ className,
+ clazz,
+ cw );
+ } else {
+ buildDelegateMethod( methods[i],
+ clazz,
+ className,
+ cw );
+ }
+ }
+ }
+
+ buildEagerConstructor( clazz,
className,
cw );
+ buildEagerUpdateProxyMethod( clazz,
+ fieldTypes,
+ fieldMethods,
+ className,
+ cw );
+
return cw.toByteArray();
}
@@ -255,6 +336,97 @@
}
/**
+ * Creates a constructor for the shadow proxy receiving
+ * the actual delegate class as parameter
+ *
+ * @param originalClassName
+ * @param className
+ * @param cw
+ */
+ private static void buildEagerConstructor(final Class clazz,
+ final String className,
+ final ClassWriter cw) {
+ MethodVisitor mv;
+ {
+ mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+ "<init>",
+ Type.getMethodDescriptor( Type.VOID_TYPE,
+ new Type[]{Type.getType( clazz )} ),
+ null,
+ null );
+ mv.visitCode();
+
+ // super();
+ Label l0 = new Label();
+ mv.visitLabel( l0 );
+ mv.visitLineNumber( 41,
+ l0 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ if ( clazz.isInterface() ) {
+ mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
+ Type.getInternalName( Object.class ),
+ "<init>",
+ Type.getMethodDescriptor( Type.VOID_TYPE,
+ new Type[]{} ) );
+ } else {
+ mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
+ Type.getInternalName( clazz ),
+ "<init>",
+ Type.getMethodDescriptor( Type.VOID_TYPE,
+ new Type[]{} ) );
+ }
+
+ // this.delegate = delegate
+ Label l1 = new Label();
+ mv.visitLabel( l1 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 1 );
+ mv.visitFieldInsn( Opcodes.PUTFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ) );
+
+ // this.updateProxy();
+ Label l4 = new Label();
+ mv.visitLabel( l4 );
+ mv.visitVarInsn( Opcodes.ALOAD, 0 );
+ mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+ className,
+ UPDATE_PROXY,
+ Type.getMethodDescriptor( Type.VOID_TYPE,
+ new Type[]{} ) );
+
+ // return
+ Label l2 = new Label();
+ mv.visitLabel( l2 );
+ mv.visitLineNumber( 43,
+ l2 );
+ mv.visitInsn( Opcodes.RETURN );
+
+ Label l3 = new Label();
+ mv.visitLabel( l3 );
+ mv.visitLocalVariable( "this",
+ "L" + className + ";",
+ null,
+ l0,
+ l3,
+ 0 );
+ mv.visitLocalVariable( DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ),
+ null,
+ l0,
+ l3,
+ 1 );
+ mv.visitMaxs( 0,
+ 0 );
+ mv.visitEnd();
+ }
+ }
+
+ /**
* Creates the proxy reader method for the given method
*
* @param fieldName
@@ -355,11 +527,125 @@
mv.visitEnd();
}
+ /**
+ * Creates the proxy reader method for the given method
+ *
+ * @param fieldName
+ * @param fieldFlag
+ * @param method
+ * @param cw
+ */
+ protected static void buildSimpleGetMethod(String fieldName,
+ Class fieldType,
+ String fieldFlag,
+ Method method,
+ String className,
+ Class clazz,
+ ClassWriter cw) {
+ // method signature
+ Class[] exceptionTypes = method.getExceptionTypes();
+ String[] exceptions = getExceptionArrayAsString( exceptionTypes );
+ MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+ method.getName(),
+ Type.getMethodDescriptor( method ),
+ null,
+ exceptions );
+ mv.visitCode();
+
+ // return __field;
+ Label l0 = new Label();
+ mv.visitLabel( l0 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ fieldName,
+ Type.getDescriptor( fieldType ) );
+ mv.visitInsn( Type.getType( fieldType ).getOpcode( Opcodes.IRETURN ) );
+
+ // local variables table
+ Label l4 = new Label();
+ mv.visitLabel( l4 );
+ mv.visitLocalVariable( "this",
+ "L" + className + ";",
+ null,
+ l0,
+ l4,
+ 0 );
+ mv.visitMaxs( 0,
+ 0 );
+ mv.visitEnd();
+ }
+
+ protected static void buildEagerUpdateProxyMethod(Class delegate,
+ Map fieldTypes,
+ Map fieldMethods,
+ String className,
+ ClassWriter cw) {
+ MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+ UPDATE_PROXY,
+ Type.getMethodDescriptor( Type.VOID_TYPE,
+ new Type[]{} ),
+ null,
+ null );
+ mv.visitCode();
+ Label l0 = new Label();
+ mv.visitLabel( l0 );
+ for ( Iterator it = fieldTypes.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) it.next();
+ String fieldName = (String) entry.getKey();
+ Class fieldType = (Class) entry.getValue();
+ Method method = (Method) fieldMethods.get( fieldName );
+
+ // __field = this.delegate.getField()
+ Label l1 = new Label();
+ mv.visitLabel( l1 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( delegate ) );
+ if ( delegate.isInterface() ) {
+ mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+ Type.getInternalName( delegate ),
+ method.getName(),
+ Type.getMethodDescriptor( method ) );
+ } else {
+ mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName( delegate ),
+ method.getName(),
+ Type.getMethodDescriptor( method ) );
+ }
+ mv.visitFieldInsn( Opcodes.PUTFIELD,
+ className,
+ fieldName,
+ Type.getDescriptor( fieldType ) );
+
+ }
+ Label l4 = new Label();
+ mv.visitLabel( l4 );
+ mv.visitInsn( Opcodes.RETURN );
+ Label l5 = new Label();
+ mv.visitLabel( l5 );
+ mv.visitLocalVariable( "this",
+ "L" + className + ";",
+ null,
+ l0,
+ l5,
+ 0 );
+ mv.visitMaxs( 0,
+ 0 );
+ mv.visitEnd();
+ }
+
protected static void buildUpdateProxyMethod(Map fieldTypes,
- String className,
- ClassWriter cw) {
+ String className,
+ ClassWriter cw) {
MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
- "updateProxy",
+ UPDATE_PROXY,
Type.getMethodDescriptor( Type.VOID_TYPE,
new Type[]{} ),
null,
@@ -419,49 +705,6 @@
mv.visitEnd();
}
- // protected static void buildEqualsMethod(Class clazz,
- // String className,
- // ClassWriter cw) {
- // MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
- // "equals",
- // "(Ljava/lang/Object;)Z",
- // null,
- // null );
- // mv.visitCode();
- // Label l0 = new Label();
- // mv.visitLabel( l0 );
- // mv.visitVarInsn( Opcodes.ALOAD,
- // 0 );
- // mv.visitFieldInsn( Opcodes.GETFIELD,
- // className,
- // DELEGATE_FIELD_NAME,
- // Type.getDescriptor( clazz ) );
- // mv.visitVarInsn( Opcodes.ALOAD,
- // 1 );
- // mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
- // Type.getInternalName( clazz ),
- // "equals",
- // "(Ljava/lang/Object;)Z" );
- // mv.visitInsn( Opcodes.IRETURN );
- // Label l1 = new Label();
- // mv.visitLabel( l1 );
- // mv.visitLocalVariable( "this",
- // "L"+className+";",
- // null,
- // l0,
- // l1,
- // 0 );
- // mv.visitLocalVariable( "object",
- // Type.getDescriptor( Object.class ),
- // null,
- // l0,
- // l1,
- // 1 );
- // mv.visitMaxs( 0,
- // 0 );
- // mv.visitEnd();
- // }
-
protected static void buildDelegateMethod(Method method,
Class clazz,
String className,
Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java 2006-10-09 20:51:28 UTC (rev 6713)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java 2006-10-09 21:22:37 UTC (rev 6714)
@@ -126,4 +126,111 @@
}
}
+ public void testEagerProxyForClass() {
+ try {
+ // creating original object
+ String originalType = "stilton";
+ int originalPrice = 15;
+ Cheese cheese = new Cheese(originalType, originalPrice);
+
+ // creating proxy
+ Class proxy = ShadowProxyFactory.getEagerProxy( Cheese.class );
+ Cheese cheeseProxy = (Cheese) proxy.getConstructor( new Class[] { Cheese.class } ).newInstance( new Object[] { cheese } );
+
+ // proxy is proxying the values
+ Assert.assertEquals( originalType, cheeseProxy.getType() );
+ Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+
+ // changing original values
+ String actualType = "rotten stilton";
+ int actualPrice = 1;
+ cheese.setType( actualType );
+ cheese.setPrice( actualPrice );
+
+ // proxy does not see changes
+ Assert.assertEquals( actualType, cheese.getType() );
+ Assert.assertFalse( actualType.equals( cheeseProxy.getType() ) );
+ Assert.assertEquals( originalType, cheeseProxy.getType() );
+ Assert.assertEquals( actualPrice, cheese.getPrice() );
+ Assert.assertFalse( actualPrice == cheeseProxy.getPrice() );
+ Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+
+ // reseting proxy
+ ((ShadowProxy) cheeseProxy).updateProxy();
+
+ // now proxy see changes
+ Assert.assertEquals( actualType, cheese.getType() );
+ Assert.assertEquals( actualType, cheeseProxy.getType() );
+ Assert.assertFalse( originalType.equals( cheeseProxy.getType() ) );
+ Assert.assertEquals( actualPrice, cheese.getPrice() );
+ Assert.assertEquals( actualPrice, cheeseProxy.getPrice() );
+ Assert.assertFalse( originalPrice == cheeseProxy.getPrice() );
+
+ } catch ( Exception e ) {
+ fail("Error: "+e.getMessage());
+ }
+ }
+
+ public void testEagerProxyForInterface() {
+ try {
+ // creating original object
+ String originalType = "stilton";
+ int originalPrice = 15;
+ Cheese cheese = new Cheese(originalType, originalPrice);
+
+ // creating proxy
+ Class proxy = ShadowProxyFactory.getEagerProxy( CheeseInterface.class );
+ CheeseInterface cheeseProxy = (CheeseInterface) proxy.getConstructor( new Class[] { CheeseInterface.class } ).newInstance( new Object[] { cheese } );
+
+ // proxy is proxying the values
+ Assert.assertEquals( originalType, cheeseProxy.getType() );
+ Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+
+ // changing original values
+ String actualType = "rotten stilton";
+ int actualPrice = 1;
+ cheese.setType( actualType );
+ cheese.setPrice( actualPrice );
+
+ // proxy does not see changes
+ Assert.assertEquals( actualType, cheese.getType() );
+ Assert.assertFalse( actualType.equals( cheeseProxy.getType() ) );
+ Assert.assertEquals( originalType, cheeseProxy.getType() );
+ Assert.assertEquals( actualPrice, cheese.getPrice() );
+ Assert.assertFalse( actualPrice == cheeseProxy.getPrice() );
+ Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+
+ // reseting proxy
+ ((ShadowProxy) cheeseProxy).updateProxy();
+
+ // now proxy see changes
+ Assert.assertEquals( actualType, cheese.getType() );
+ Assert.assertEquals( actualType, cheeseProxy.getType() );
+ Assert.assertFalse( originalType.equals( cheeseProxy.getType() ) );
+ Assert.assertEquals( actualPrice, cheese.getPrice() );
+ Assert.assertEquals( actualPrice, cheeseProxy.getPrice() );
+ Assert.assertFalse( originalPrice == cheeseProxy.getPrice() );
+
+ } catch ( Exception e ) {
+ fail("Error: "+e.getMessage());
+ }
+ }
+
+ public void testEagerProxyForAPIClass() {
+ try {
+ // creating original object
+ List list = new ArrayList();
+
+ // creating proxy
+ Class proxy = ShadowProxyFactory.getEagerProxy( ArrayList.class );
+ List listProxy = (List) proxy.getConstructor( new Class[] { ArrayList.class } ).newInstance( new Object[] { list } );
+
+ // proxy is proxying the values
+ Assert.assertEquals( list, listProxy );
+
+ } catch ( Exception e ) {
+ fail("Error: "+e.getMessage());
+ }
+ }
+
}
More information about the jboss-svn-commits
mailing list