View Javadoc

1   package org.neo.swarm.core.aop.silc.comp;
2   
3   import java.io.Serializable;
4   import java.lang.reflect.AccessibleObject;
5   import java.lang.reflect.Method;
6   import java.util.ArrayList;
7   import java.util.Arrays;
8   import java.util.HashMap;
9   import java.util.Iterator;
10  import java.util.LinkedList;
11  import java.util.List;
12  import java.util.Map;
13  
14  import org.neo.swarm.core.aop.AspectComponent;
15  
16  
17  /***
18   * This class manages the interceptor chain for an aspected component.
19   * 
20   * @author damiang
21   * @author navery
22   */
23  public class AspectComponentImpl extends AccessibleObject implements AspectComponent, Serializable {
24  	private Class[] interfaces;
25  	private Object key; // key used to reference this object; DG - would like to get rid of this
26  	private Object target; // TODO: make this transient to prevent massive serialization...considering mobility etc. - making it transient blows up serialization
27  	private Map perspectiveInterceptors; //[perspective, Map][method, interceptor]]]
28      private ProxyFactory proxyFactory;
29  
30      public AspectComponentImpl(Object key, Class[] interfaces, Object target, ProxyFactory proxyFactory) {
31          if (interfaces == null || interfaces.length == 0) {
32  			throw new IllegalArgumentException("interfaces must be supplied");
33  		}
34  		if (target == null) {
35  			throw new IllegalArgumentException("target must not be null");
36  		}
37          if (proxyFactory == null) {
38              throw new IllegalArgumentException("ProxyFactory must not be null");
39          }
40  		this.key = key;
41  		this.target = target;
42  		this.interfaces = interfaces;
43          this.proxyFactory = proxyFactory;
44  		perspectiveInterceptors = new HashMap();
45  		// add the default perspective
46  		addPerspective(Perspective.DEFAULT);
47  	}
48  	
49  	/***
50  	 * Apply an interceptor to all methods - and if needed classify it using the given perspective.
51  	 */
52  	public void addInterceptor(Perspective perspective, MethodInterceptor methodInterceptor) {
53  		for (Iterator iter = getPerspectiveInterceptorMap(perspective).values().iterator(); iter.hasNext();) {
54  			List interceptors = (List) iter.next();
55  			if (!interceptors.contains(methodInterceptor)) {
56  				interceptors.add(methodInterceptor);
57  			}
58  		}
59  	}
60  
61  	/***
62  	 * Apply interceptor to only one method.
63  	 * @param method
64  	 * @param interceptor
65  	 */
66  	public void addInterceptor(Perspective perspective, Method method, MethodInterceptor interceptor) {
67  		List interceptors = getInterceptorsForMethod(perspective, method);
68  		if (!interceptors.contains(interceptor)) {
69  			interceptors.add(interceptor);
70  		}
71  	}
72  	
73  	public Object getTarget() {
74  		return target;
75  	}
76  
77      public Object getProxy() {
78          return getProxy(Perspective.DEFAULT);
79  	}
80  	
81  	public Object getProxy(Perspective perspective) {
82          return proxyFactory.createProxy(perspective, key, interfaces, this);
83  	}
84  
85      // This is just for a perf test - will be removed
86      public Object getCGLibProxy() {
87          return proxyFactory.createProxy(key, interfaces, this, getPerspectiveInterceptorMap(Perspective.DEFAULT));
88      }
89  
90  	/***
91  	 * callback from the invocation handler - this is where we need to apply the associated perspective.
92  	 */
93  	public Object invokeMethod(Object key, Perspective perspective, Object proxy, Method method, Object[] args) throws Throwable {
94  		Invocation invocation = getInvocation(key, perspective, method, args);
95  		return invocation.proceed();
96  	}
97  	
98  	public Method[] getInterfaceMethods() {
99  		ArrayList list = new ArrayList();
100 		for (int i = 0; i < interfaces.length; i++) {
101 			Class anInterface = interfaces[i];
102 			list.addAll(Arrays.asList(anInterface.getMethods()));
103 		}
104 		return (Method[]) list.toArray(new Method[list.size()]);
105 	}
106 
107 	public Class[] getInterfaces() {
108 		return interfaces;
109 	}
110 
111 	private Map getPerspectiveInterceptorMap(Perspective perspective) {
112 		if (perspectiveInterceptors.get(perspective) == null) {
113 			addPerspective(perspective);
114 		}
115 		return (Map) perspectiveInterceptors.get(perspective);
116 	}
117 
118 	
119 	private Invocation getInvocation(Object key, Perspective perspective, Method method, Object[] args) {
120 		return new AspectInvocation(this, key, target, method, args, getInterceptorsAsArray(perspective, method));
121 	}
122 
123 	private MethodInterceptor[] getInterceptorsAsArray(Perspective perspective, Method method) {
124 		List interceptors = getInterceptorsForMethod(perspective, method);
125 		if (interceptors == null) {
126 			return new MethodInterceptor[0];
127 		}
128 		return (MethodInterceptor[]) interceptors.toArray(new MethodInterceptor[interceptors.size()]);
129 	}
130 
131 	private List getInterceptorsForMethod(Perspective perspective, Method method) {
132 			Map methodMap = getPerspectiveInterceptorMap(perspective);
133 			return (List) methodMap.get(getMethodKey(method));		
134 	}
135 
136 	private Map createMethodToInterceptorMap() {
137 		Map map = new HashMap();
138 		for (int i = 0; i < interfaces.length; i++) {
139 			initInterceptorChain(interfaces[i].getMethods(), map);
140 		}
141 		return map;
142 	}
143 
144 	private void initInterceptorChain(Method[] methods, Map map) {
145 		for (int i = 0; i < methods.length; i++) {
146 			map.put(getMethodKey(methods[i]), new LinkedList());
147 		}
148 	}
149 
150     // this will not work with overridden methods!
151 	private String getMethodKey(Method method) {
152 		return method.getDeclaringClass().getName() + "." + method.getName();
153 	}
154 
155 
156 	private void addPerspective(Perspective perspective) {
157 		perspectiveInterceptors.put(perspective, createMethodToInterceptorMap());
158 	}
159 
160 }