@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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]; |
@@ -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); | |||
} | |||
} | |||
} |