Commit 41dff8ed authored by Lionel Seinturier's avatar Lionel Seinturier

Dynamically invoke the base method when intent handlers are woven instead of...

Dynamically invoke the base method when intent handlers are woven instead of generating subclasses (suggested by Philippe.)
parent dca714e1
......@@ -119,17 +119,17 @@ public class HelloWorldTestCase extends TestCase {
final static private String[] expecteds =
new String[]{
"Server3: begin printing...",
"== hello world",
"== hello world",
"== hello world",
"Server3: print done.",
"Server: begin printing...",
"-> hello world",
"Server: print done.",
"Server2: begin printing...",
"=> hello world",
"=> hello world",
"Server2: print done.",
"Server3: begin printing...",
"== hello world",
"== hello world",
"== hello world",
"Server3: print done."
"Server2: print done."
};
}
......@@ -146,91 +146,108 @@ extends AbstractInterceptorSourceCodeGenerator {
cv.visitField( modifiers, type, name, null );
/*
* Generate a subclass of IntentJoinPointImpl per method defined in
* proxycl. Instances of the generated class reifies invocations on the
* associated method.
* The following piece of code corresponds to a feature which has been
* removed in version 1.3.
*
* Generating a subclass of IntentJoinPointImpl per method defined in
* proxycl enables invoking statically the base method which corresponds
* to the intercepted join point. Following a discussion with Philippe,
* it has been decided that we wouldn't loose much by performing a
* dynamic method invocation instead. The advantage is that we don't
* need these subclasses anymore. I keep this piece of code commented
* for the record just in case we would need to re-install it in the
* future.
*
* Two other pieces of code related to this feature have been commented:
* see IntentJoinPointImpl#proceed() and
* see #generateProxyMethodBodyBeforeCode().
*/
UnifiedMethod[] proxymethods = proxycl.getMethods();
String proxyclname = proxycl.getName();
for (int i = 0; i <proxymethods.length; i++) {
UnifiedMethod proxym = proxymethods[i];
String proxymname = proxym.getName();
String proxymrettypename = proxym.getReturnType().getName();
UnifiedClass[] paramtypes = proxym.getParameterTypes();
// Inner class header
ClassSourceCodeVisitor innercv = cv.visitInnerClass();
int innermodifiers = Modifier.PRIVATE + Modifier.STATIC;
String innername = "IntentJoinPointImplForMethod"+i;
innercv.visit(
innermodifiers, innername, null,
IntentJoinPointImpl.class.getName()+'<'+proxyclname+'>', null );
// proceed() method
MethodSourceCodeVisitor mv =
innercv.visitMethod(
Modifier.PUBLIC, null, "Object", "proceed", null,
new String[]{"Throwable"});
mv.visitBegin();
mv.visitln(" if( index == handlers.size() ) {");
mv.visit (" ");
if( ! proxymrettypename.equals("void") ) {
mv.visit("return ");
}
mv.visit("intentTarget.");
mv.visit(proxymname);
mv.visit("(");
for (int j = 0; j < paramtypes.length; j++) {
UnifiedClass paramtype = paramtypes[j];
if( paramtypes[j].isPrimitive() ) {
paramtype = paramtype.box();
}
String paramtypename = paramtype.getName();
if(j!=0) mv.visit(",");
if( ! paramtypename.equals("java.lang.Object") ) {
mv.visit("(");
mv.visit(paramtypename);
mv.visit(")");
}
mv.visit("intentMethodArguments[");
mv.visit(Integer.toString(j));
mv.visit("]");
}
mv.visitln(");");
if( proxymrettypename.equals("void") ) {
mv.visitln(" return null;");
}
mv.visitln(" }");
mv.visitln(" else {");
mv.visitln(" return super.proceed();");
mv.visitln(" }");
// End of the proceed() method
mv.visitEnd();
/*
* Up to r1958 I was generating a base() method for the reason
* explained in the next paragraph. See
* http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/frascati/trunk/tinfi/opt/oo/src/main/java/org/ow2/frascati/tinfi/opt/oo/SCAIntentInterceptorSourceCodeGenerator.java?rev=1958&view=auto
* The issue of the two cast(Object) was indirectly resolved by
* Stphane Drapeau when I mentioned it: he noticed that this was an
* error and removed the inadequate one. It is not clear to me
* whether I should expect the issue to reappear with another
* interface. I guess not and decide to include the code from the
* base method into proceed.
*
* In theory, the base() method is not strictly needed. One should
* be able to invoke the base method from the proceed method
* generated just before. It happens that the JDT compiler can not
* decide which method to invoke in the case of the ComponentContext
* interface with the two cast(Object) methods. The fact of
* introducing the base() method solves the issue.
*/
// End of the inner class
innercv.visitEnd();
}
// /*
// * Generate a subclass of IntentJoinPointImpl per method defined in
// * proxycl. Instances of the generated class reifies invocations on the
// * associated method.
// */
// UnifiedMethod[] proxymethods = proxycl.getMethods();
// String proxyclname = proxycl.getName();
// for (int i = 0; i <proxymethods.length; i++) {
//
// UnifiedMethod proxym = proxymethods[i];
// String proxymname = proxym.getName();
// String proxymrettypename = proxym.getReturnType().getName();
// UnifiedClass[] paramtypes = proxym.getParameterTypes();
//
// // Inner class header
// ClassSourceCodeVisitor innercv = cv.visitInnerClass();
// int innermodifiers = Modifier.PRIVATE + Modifier.STATIC;
// String innername = "IntentJoinPointImplForMethod"+i;
// innercv.visit(
// innermodifiers, innername, null,
// IntentJoinPointImpl.class.getName()+'<'+proxyclname+'>', null );
//
// // proceed() method
// MethodSourceCodeVisitor mv =
// innercv.visitMethod(
// Modifier.PUBLIC, null, "Object", "proceed", null,
// new String[]{"Throwable"});
// mv.visitBegin();
// mv.visitln(" if( index == handlers.size() ) {");
// mv.visit (" ");
// if( ! proxymrettypename.equals("void") ) {
// mv.visit("return ");
// }
// mv.visit("intentTarget.");
// mv.visit(proxymname);
// mv.visit("(");
// for (int j = 0; j < paramtypes.length; j++) {
// UnifiedClass paramtype = paramtypes[j];
// if( paramtypes[j].isPrimitive() ) {
// paramtype = paramtype.box();
// }
// String paramtypename = paramtype.getName();
// if(j!=0) mv.visit(",");
// if( ! paramtypename.equals("java.lang.Object") ) {
// mv.visit("(");
// mv.visit(paramtypename);
// mv.visit(")");
// }
// mv.visit("intentMethodArguments[");
// mv.visit(Integer.toString(j));
// mv.visit("]");
// }
// mv.visitln(");");
// if( proxymrettypename.equals("void") ) {
// mv.visitln(" return null;");
// }
// mv.visitln(" }");
// mv.visitln(" else {");
// mv.visitln(" return super.proceed();");
// mv.visitln(" }");
//
// // End of the proceed() method
// mv.visitEnd();
//
// /*
// * Up to r1958 I was generating a base() method for the reason
// * explained in the next paragraph. See
// * http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/frascati/trunk/tinfi/opt/oo/src/main/java/org/ow2/frascati/tinfi/opt/oo/SCAIntentInterceptorSourceCodeGenerator.java?rev=1958&view=auto
// * The issue of the two cast(Object) was indirectly resolved by
// * Stphane Drapeau when I mentioned it: he noticed that this was an
// * error and removed the inadequate one. It is not clear to me
// * whether I should expect the issue to reappear with another
// * interface. I guess not and decide to include the code from the
// * base method into proceed.
// *
// * In theory, the base() method is not strictly needed. One should
// * be able to invoke the base method from the proceed method
// * generated just before. It happens that the JDT compiler can not
// * decide which method to invoke in the case of the ComponentContext
// * interface with the two cast(Object) methods. The fact of
// * introducing the base() method solves the issue.
// */
//
// // End of the inner class
// innercv.visitEnd();
// }
}
@Override
......@@ -329,8 +346,19 @@ extends AbstractInterceptorSourceCodeGenerator {
mv.visit (IntentJoinPointImpl.class.getName());
mv.visit ("<");
mv.visit (it.getFcItfSignature());
mv.visit ("> ijp = new IntentJoinPointImplForMethod");
mv.visit (Integer.toString(idx));
mv.visit ("> ijp = new ");
mv.visit (IntentJoinPointImpl.class.getName());
/*
* The following commented lines of code correspond to a feature
* which has been removed in version 1.3.
*
* See #generateFields() for further information.
*/
// mv.visit ("IntentJoinPointImplForMethod");
// mv.visit (Integer.toString(idx));
mv.visitln("();");
mv.visit (" ijp.init(handlers,compctx,itf,impl,METHODS[");
mv.visit (Integer.toString(idx));
......
......@@ -25,11 +25,11 @@
package org.ow2.frascati.tinfi.control.intent;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import org.objectweb.fractal.api.Interface;
import org.ow2.frascati.tinfi.TinfiRuntimeException;
import org.ow2.frascati.tinfi.control.component.ReconfigurableComponentContext;
/**
......@@ -123,10 +123,31 @@ public class IntentJoinPointImpl<T> implements IntentJoinPoint {
* Proceed to the next intent handler.
*/
public Object proceed() throws Throwable {
if( index == handlers.size() ) {
String msg = "Unexpected case: index==handlers.length should have been checked by the subclass";
throw new TinfiRuntimeException(msg);
if( index == handlers.size() ) {
try {
Object ret =
intentMethod.invoke(intentTarget,intentMethodArguments);
return ret;
}
catch( InvocationTargetException ite ) {
// Throw the exception thrown by the invoked method
Throwable t = ite.getTargetException();
throw t;
}
/*
* The following commented lines of code correspond to a feature
* which has been removed in version 1.3.
*
* See SCAIntentInterceptorSourceCodeGenerator#generateFields() for
* further information.
*/
// String msg = "Unexpected case: index==handlers.length should have been checked by the subclass";
// throw new TinfiRuntimeException(msg);
}
IntentHandler handler = handlers.get(index);
index++;
Object ret = handler.invoke(this);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment