Earlier this week I was discussing AOP tools with Guillaume in irc and I said that you couldn't do cflow with dynaop or nanning -- that you needed AspectJ or AspektWerks to do that. This didn't really seem true -- and I was right that i was wrong. It took all of fifteen minutes to do!
Cflow is basically a pointcut based on the state of the stack -- is this point in execution upstack from that point, etc. For the proof of concept to myself I didn't provide cflow as a pointcut (as it probably should be) but rather as a combination of an interceptor and mixin. It works as demonstrated by a simple unit test::
import dynaop.*;
import junit.framework.TestCase;
import java.util.Map;
import java.util.HashMap;
public class CFlowTest extends TestCase {
    public void testCFlow() throws Exception {
        Aspects aspects = new Aspects();
        aspects.interceptor(Pointcuts.instancesOf(Map.class),
                            Pointcuts.membersOf(Map.class),
                            new CFlowInterceptor());
        aspects.mixin(Pointcuts.ALL_CLASSES, CFlowMixin.class, null);
        final boolean[] called = { false };
        aspects.interceptor(Pointcuts.instancesOf(Map.class),
                            Pointcuts.membersOf(Map.class),
                            new Interceptor() {
            public Object intercept(final Invocation invocation) 
                    throws Throwable {
                called[0] = true;
                assertTrue(invocation.getProxy() instanceof CFlowAware);
                assertNotNull(((CFlowAware)invocation.getProxy()).getCFlow());
                return invocation.proceed();
            }
        });
        ProxyFactory fact = ProxyFactory.getInstance(aspects);
        Map proxy = (Map) fact.wrap(new HashMap());
        proxy.put("a", "b");
        assertTrue(called[0]);
    }
}
The silly part is how easy it was to do. This implementation won't be very fast, but it does work:
public interface CFlowAware
{
    void setCFlow(StackTraceElement[] stack);
    StackTraceElement[] getCFlow();
}
------------------------------------------------------
public class CFlowMixin implements CFlowAware {
    private StackTraceElement[] stack;
    public void setCFlow(StackTraceElement[] stack) {
        this.stack = stack;
    }
    public StackTraceElement[] getCFlow() {
        return this.stack;
    }
}
------------------------------------------------------
import dynaop.Interceptor;
import dynaop.Invocation;
import dynaop.Proxy;
public class CFlowInterceptor implements Interceptor {
 
    public Object intercept(Invocation invocation) 
            throws Throwable {
        Exception e = new Exception();
        StackTraceElement[] stack = e.getStackTrace();
        e = null;
        Proxy p = invocation.getProxy();
        ((CFlowAware)p).setCFlow(stack);
        return invocation.proceed();
    }
}
The CFlowInterceptor uses a hack to generate the stack trace -- it generates an exception and never throws it. There has to be a better way to do this, but I don't know it. It then passes the stack trace from the exception to the CFlowMixin which makes it availble downstream on the interception stack via the proxy =)