diff options
author | aclement <aclement> | 2005-04-19 11:52:17 +0000 |
---|---|---|
committer | aclement <aclement> | 2005-04-19 11:52:17 +0000 |
commit | 2fcbc5bda7a0e1a6103eba2913e769fe891e4da2 (patch) | |
tree | 48186a483c3c220fab4e147f3cb953e5cee9cfc2 /runtime | |
parent | 11ddbca0fd1d44048332e3649967d82d03a78014 (diff) | |
download | aspectj-2fcbc5bda7a0e1a6103eba2913e769fe891e4da2.tar.gz aspectj-2fcbc5bda7a0e1a6103eba2913e769fe891e4da2.zip |
From branch: Changes to runtime for @AJ
Diffstat (limited to 'runtime')
5 files changed, 229 insertions, 10 deletions
diff --git a/runtime/src/org/aspectj/lang/Aspects.java b/runtime/src/org/aspectj/lang/Aspects.java new file mode 100644 index 000000000..d907fce59 --- /dev/null +++ b/runtime/src/org/aspectj/lang/Aspects.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2005 Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * initial implementation Jonas Bonér, Alexandre Vasseur + *******************************************************************************/ +package org.aspectj.lang; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Handles generic aspectOf method when those are not available in the aspects but added later on + * thru load time weaving. + * <p/> + * Aspects.aspectOf(..) is doing reflective calls to the aspect aspectOf, so for better performance + * consider using preparation of the aspects. + * + * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> + */ +public class Aspects { + + private final static Class[] EMPTY_CLASS_ARRAY = new Class[0]; + private final static Class[] PEROBJECT_CLASS_ARRAY = new Class[]{Object.class}; + private final static Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + private final static String ASPECTOF = "aspectOf"; + + /** + * Returns the singleton aspect + * + * @param aspectClass + * @return + * @throws NoAspectBoundException if no such aspect + */ + public static Object aspectOf(Class aspectClass) throws NoAspectBoundException { + try { + return getSingletonAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); + } catch (Exception e) { + throw new NoAspectBoundException(aspectClass.getName(), e); + } + } + + /** + * Returns the perthis / pertarget aspect + * @param aspectClass + * @param perObject + * @return + * @throws NoAspectBoundException if no such aspect, or no aspect bound + */ + public static Object aspectOf(Class aspectClass, Object perObject) throws NoAspectBoundException { + try { + return getPerObjectAspectOf(aspectClass).invoke(null, new Object[]{perObject}); + } catch (Exception e) { + throw new NoAspectBoundException(aspectClass.getName(), e); + } + } + + public static Object aspectOf(Class aspectClass, Thread perThread) throws NoAspectBoundException { + //TODO - how to know it s a real per Thread ? + // if it is actually a singleton one, we will have it as well... + try { + return getSingletonAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); + } catch (Exception e) { + throw new NoAspectBoundException(aspectClass.getName(), e); + } + } + + private static Method getSingletonAspectOf(Class aspectClass) throws NoSuchMethodException { + Method method = aspectClass.getDeclaredMethod(ASPECTOF, EMPTY_CLASS_ARRAY); + method.setAccessible(true); + if (!method.isAccessible() + || !Modifier.isPublic(method.getModifiers()) + || !Modifier.isStatic(method.getModifiers())) { + throw new RuntimeException(aspectClass.getName(), new Exception("aspectOf is not public static")); + } + return method; + } + + private static Method getPerObjectAspectOf(Class aspectClass) throws NoSuchMethodException { + Method method = aspectClass.getDeclaredMethod(ASPECTOF, PEROBJECT_CLASS_ARRAY); + method.setAccessible(true); + if (!method.isAccessible() + || !Modifier.isPublic(method.getModifiers()) + || !Modifier.isStatic(method.getModifiers())) { + throw new RuntimeException(aspectClass.getName(), new Exception("aspectOf is not public static")); + } + return method; + } +} diff --git a/runtime/src/org/aspectj/lang/ProceedingJoinPoint.java b/runtime/src/org/aspectj/lang/ProceedingJoinPoint.java new file mode 100644 index 000000000..2a54d407b --- /dev/null +++ b/runtime/src/org/aspectj/lang/ProceedingJoinPoint.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2005 Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * initial implementation Jonas Bonér, Alexandre Vasseur + *******************************************************************************/ +package org.aspectj.lang; + +import org.aspectj.runtime.internal.AroundClosure; + +/** + * ProceedingJoinPoint exposes the proceed(..) method in order to support around advice in @AJ aspects + * + * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> + */ +public interface ProceedingJoinPoint extends JoinPoint { + + /** + * The joinpoint needs to know about its closure so that proceed can delegate to closure.run() + * <p/> + * This internal method should not be called directly, and won't be visible to the end-user when + * packed in a jar (synthetic method) + * + * @param arc + */ + void set$AroundClosure(AroundClosure arc); + + /** + * Proceed with the next advice or target method invocation + * + * @return + * @throws Throwable + */ + public Object proceed() throws Throwable; + + /** + * Proceed with the next advice or target method invocation + * <p/> + * The given args Object[] must be in the same order and size as the advice signature but + * without the actual joinpoint instance + * + * @param args + * @return + * @throws Throwable + */ + public Object proceed(Object[] args) throws Throwable; + +} + + diff --git a/runtime/src/org/aspectj/runtime/internal/AroundClosure.java b/runtime/src/org/aspectj/runtime/internal/AroundClosure.java index 1d5ad810a..f47921688 100644 --- a/runtime/src/org/aspectj/runtime/internal/AroundClosure.java +++ b/runtime/src/org/aspectj/runtime/internal/AroundClosure.java @@ -9,24 +9,31 @@ * * Contributors: * Xerox/PARC initial implementation + * Alex Vasseur wired up for @AJ proceeding * ******************************************************************/ package org.aspectj.runtime.internal; +import org.aspectj.lang.ProceedingJoinPoint; + public abstract class AroundClosure { - //private Object[] state; + private Object[] state; + protected Object[] preInitializationState; - public AroundClosure(/* Object[] state */) { - // this.state = state; + public AroundClosure() { } - protected Object[] state; - protected Object[] preInitializationState; public AroundClosure(Object[] state) { this.state = state; } + + + public Object[] getState() { + return state; + } + public Object[] getPreInitializationState() { return preInitializationState; } @@ -36,4 +43,15 @@ public abstract class AroundClosure { * call in the around advice (with primitives coerced to Object types) */ public abstract Object run(Object[] args) throws Throwable; + + /** + * This method is called to implicitly associate the closure with the joinpoint + * as required for @AJ aspect proceed() + */ + public ProceedingJoinPoint linkClosureAndJoinPoint() { + //TODO is this cast safe ? + ProceedingJoinPoint jp = (ProceedingJoinPoint)state[state.length-1]; + jp.set$AroundClosure(this); + return jp; + } } diff --git a/runtime/src/org/aspectj/runtime/reflect/Factory.java b/runtime/src/org/aspectj/runtime/reflect/Factory.java index 3ee924f99..c3e662874 100644 --- a/runtime/src/org/aspectj/runtime/reflect/Factory.java +++ b/runtime/src/org/aspectj/runtime/reflect/Factory.java @@ -9,6 +9,7 @@ * * Contributors: * Xerox/PARC initial implementation + * Alex Vasseur new factory methods for variants of JP * ******************************************************************/ @@ -43,7 +44,19 @@ public final class Factory { public JoinPoint.StaticPart makeSJP(String kind, Signature sig, int l) { return new JoinPointImpl.StaticPartImpl(kind, sig, makeSourceLoc(l, -1)); } - + + public JoinPoint.EnclosingStaticPart makeESJP(String kind, Signature sig, SourceLocation loc) { + return new JoinPointImpl.EnclosingStaticPartImpl(kind, sig, loc); + } + + public JoinPoint.EnclosingStaticPart makeESJP(String kind, Signature sig, int l, int c) { + return new JoinPointImpl.EnclosingStaticPartImpl(kind, sig, makeSourceLoc(l, c)); + } + + public JoinPoint.EnclosingStaticPart makeESJP(String kind, Signature sig, int l) { + return new JoinPointImpl.EnclosingStaticPartImpl(kind, sig, makeSourceLoc(l, -1)); + } + public static JoinPoint.StaticPart makeEncSJP(Member member) { Signature sig = null; String kind = null; @@ -64,7 +77,7 @@ public final class Factory { } else { throw new IllegalArgumentException("member must be either a method or constructor"); } - return new JoinPointImpl.StaticPartImpl(kind,sig,null); + return new JoinPointImpl.EnclosingStaticPartImpl(kind,sig,null); } private static Object[] NO_ARGS = new Object[0]; diff --git a/runtime/src/org/aspectj/runtime/reflect/JoinPointImpl.java b/runtime/src/org/aspectj/runtime/reflect/JoinPointImpl.java index 430f36a42..34d5b469c 100644 --- a/runtime/src/org/aspectj/runtime/reflect/JoinPointImpl.java +++ b/runtime/src/org/aspectj/runtime/reflect/JoinPointImpl.java @@ -14,11 +14,13 @@ package org.aspectj.runtime.reflect; -import org.aspectj.lang.*; - +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; import org.aspectj.lang.reflect.SourceLocation; +import org.aspectj.runtime.internal.AroundClosure; -class JoinPointImpl implements JoinPoint { +class JoinPointImpl implements ProceedingJoinPoint { static class StaticPartImpl implements JoinPoint.StaticPart { String kind; Signature signature; @@ -48,6 +50,12 @@ class JoinPointImpl implements JoinPoint { public final String toLongString() { return toString(StringMaker.longStringMaker); } } + static class EnclosingStaticPartImpl extends StaticPartImpl implements EnclosingStaticPart { + public EnclosingStaticPartImpl(String kind, Signature signature, SourceLocation sourceLocation) { + super(kind, signature, sourceLocation); + } + } + Object _this; Object target; Object[] args; @@ -78,4 +86,37 @@ class JoinPointImpl implements JoinPoint { public final String toString() { return staticPart.toString(); } public final String toShortString() { return staticPart.toShortString(); } public final String toLongString() { return staticPart.toLongString(); } + + // To proceed we need a closure to proceed on + private AroundClosure arc; + public void set$AroundClosure(AroundClosure arc) { + this.arc = arc; + } + + public Object proceed() throws Throwable { + // when called from a before advice, but be a no-op + if (arc == null) + return null; + else + return arc.run(arc.getState()); + } + + public Object proceed(Object[] adviceBindings) throws Throwable { + // when called from a before advice, but be a no-op + if (arc == null) + return null; + else { + // state is always consistent with caller?,callee?,formals...,jp + Object[] state = arc.getState(); + for (int i = state.length-2; i >= 0; i--) { + int formalIndex = (adviceBindings.length - 1) - (state.length-2) + i; + if (formalIndex >= 0 && formalIndex < adviceBindings.length) { + state[i] = adviceBindings[formalIndex]; + } + } + return arc.run(state); + } + } + + } |