001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.aspect.management;
005:
006: import com.tc.aspectwerkz.DeploymentModel;
007: import com.tc.aspectwerkz.aspect.container.AspectFactoryManager;
008: import com.tc.aspectwerkz.definition.AspectDefinition;
009: import com.tc.aspectwerkz.definition.SystemDefinition;
010: import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
011: import com.tc.aspectwerkz.util.ContextClassLoader;
012:
013: import java.util.*;
014: import java.lang.reflect.Method;
015:
016: /**
017: * Manages the aspects.
018: * <p/>
019: * Each Aspect qName has a generated factory (one factory per aspect qName) on which we invoke reflectively
020: * the aspectOf and alike. Those are user exposed method. The weaved code does not use those.
021: *
022: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
023: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
024: */
025: public class Aspects {
026:
027: /**
028: * Returns the aspect container class for the given aspect class qName.
029: * The qName is returned since we may have only the aspect class name upon lookup
030: *
031: * @param visibleFrom class loader to look from
032: * @param qName
033: * @return array of qName and aspect class name (dot formatted as in the aspect definition)
034: */
035: private static String[] getAspectQNameAndAspectClassName(
036: final ClassLoader visibleFrom, final String qName) {
037: AspectDefinition aspectDefinition = lookupAspectDefinition(
038: visibleFrom, qName);
039: return new String[] { aspectDefinition.getQualifiedName(),
040: aspectDefinition.getClassName() };
041: }
042:
043: /**
044: * Returns the singleton aspect instance for the aspect with the given qualified name.
045: * The aspect is looked up from the thread context classloader.
046: *
047: * @param qName the qualified name of the aspect
048: * @return the singleton aspect instance
049: */
050: public static Object aspectOf(final String qName) {
051: return aspectOf(Thread.currentThread().getContextClassLoader(),
052: qName);
053: }
054:
055: /**
056: * Returns the singleton aspect instance for the given aspect class.
057: * Consider using aspectOf(visibleFrom, qName) if the aspect is used more than once
058: * or if it is used in a class loader which is child of its own classloader.
059: *
060: * @param aspectClass the class of the aspect
061: * @return the singleton aspect instance
062: */
063: public static Object aspectOf(final Class aspectClass) {
064: String aspectClassName = aspectClass.getName()
065: .replace('/', '.');
066: return aspectOf(aspectClass.getClassLoader(), aspectClassName);
067: }
068:
069: /**
070: * Returns the singleton aspect instance for given aspect qName, with visibility from the given class loader
071: *
072: * @param visibleFrom the class loader from where aspect is visible, likely to be the class loader of the
073: * advised classes, or the one where the system hosting the aspect is deployed.
074: * @return the singleton aspect instance
075: */
076: public static Object aspectOf(final ClassLoader visibleFrom,
077: final String qName) {
078: String[] qNameAndAspectClassName = getAspectQNameAndAspectClassName(
079: visibleFrom, qName);
080: return aspect$Of(qNameAndAspectClassName[0],
081: qNameAndAspectClassName[1], visibleFrom);
082: }
083:
084: /**
085: * Returns the per class aspect attached to targetClass
086: * Consider using aspectOf(qName, targetClass) if the aspect is used more than once
087: *
088: * @param aspectClass the name of the aspect
089: * @param targetClass the target class
090: * @return the per class aspect instance
091: */
092: public static Object aspectOf(final Class aspectClass,
093: final Class targetClass) {
094: String aspectClassName = aspectClass.getName()
095: .replace('/', '.');
096: return aspectOf(aspectClassName, targetClass);
097: }
098:
099: /**
100: * Returns the per class aspect instance for the aspect with the given qualified name for targetClass
101: *
102: * @param qName the qualified name of the aspect
103: * @param targetClass the target class
104: * @return the per class aspect instance
105: */
106: public static Object aspectOf(final String qName,
107: final Class targetClass) {
108: // look up from the targetClass loader is enough in that case
109: String[] qNameAndAspectClassName = getAspectQNameAndAspectClassName(
110: targetClass.getClassLoader(), qName);
111: return aspect$Of(qNameAndAspectClassName[0],
112: qNameAndAspectClassName[1], targetClass);
113: }
114:
115: /**
116: * Returns the per instance aspect attached to targetInstance
117: * Consider using aspectOf(qName, targetInstance) if the aspect is used more than once
118: *
119: * @param aspectClass the name of the aspect
120: * @param targetInstance the target instance
121: * @return the per class aspect instance
122: */
123: public static Object aspectOf(final Class aspectClass,
124: final Object targetInstance) {
125: String aspectClassName = aspectClass.getName()
126: .replace('/', '.');
127: return aspectOf(aspectClassName, targetInstance);
128: }
129:
130: /**
131: * Returns the per instance aspect attached to targetInstance
132: *
133: * @param qName the qualified name of the aspect
134: * @param targetInstance the target instance
135: * @return the per class aspect instance
136: */
137: public static Object aspectOf(final String qName,
138: final Object targetInstance) {
139: // look up from the targetInstance loader is enough in that case
140: AspectDefinition aspectDef = lookupAspectDefinition(
141: targetInstance.getClass().getClassLoader(), qName);
142: DeploymentModel deployModel = aspectDef.getDeploymentModel();
143: String[] qNameAndAspectClassName = getAspectQNameAndAspectClassName(
144: targetInstance.getClass().getClassLoader(), qName);
145:
146: if (DeploymentModel.PER_INSTANCE.equals(deployModel)
147: || DeploymentModel.PER_THIS.equals(deployModel)
148: || DeploymentModel.PER_TARGET.equals(deployModel)) {
149: return aspect$Of(qNameAndAspectClassName[0],
150: qNameAndAspectClassName[1], targetInstance);
151: } else {
152: throw new NoAspectBoundException(
153: "Cannot retrieve instance level aspect with "
154: + "deployment-scope "
155: + deployModel.toString() + " named ", qName);
156: }
157: }
158:
159: /**
160: * Test if there is a per instance aspect (per instance, perthis/target) attached to targetInstance
161: *
162: * @param qName
163: * @param targetInstance
164: * @return
165: */
166: public static boolean hasAspect(final String qName,
167: final Object targetInstance) {
168: String[] qNameAndAspectClassName = getAspectQNameAndAspectClassName(
169: targetInstance.getClass().getClassLoader(), qName);
170: try {
171: Class factory = ContextClassLoader.forName(targetInstance
172: .getClass().getClassLoader(), AspectFactoryManager
173: .getAspectFactoryClassName(
174: qNameAndAspectClassName[1], qName).replace(
175: '/', '.'));
176: Method m = factory.getMethod("hasAspect",
177: new Class[] { Object.class });
178: Boolean b = (Boolean) m.invoke(null,
179: new Object[] { targetInstance });
180: return b.booleanValue();
181: } catch (Throwable t) {
182: return false;
183: }
184: }
185:
186: //---------- weaver exposed
187: // TODO can we cache all those ? what would be the key ?
188:
189: public static Object aspect$Of(String qName,
190: String aspectClassName, ClassLoader loader) {
191: try {
192: Class factory = ContextClassLoader.forName(loader,
193: AspectFactoryManager.getAspectFactoryClassName(
194: aspectClassName, qName).replace('/', '.'));
195: Method m = factory.getMethod("aspectOf", new Class[0]);
196: return m.invoke(null, new Object[0]);
197: } catch (NoAspectBoundException nabe) {
198: throw nabe;
199: } catch (Throwable t) {
200: throw new NoAspectBoundException(t, qName);
201: }
202: }
203:
204: public static Object aspect$Of(String qName,
205: String aspectClassName, final Class perClass) {
206: try {
207: Class factory = ContextClassLoader.forName(perClass
208: .getClassLoader(), AspectFactoryManager
209: .getAspectFactoryClassName(aspectClassName, qName)
210: .replace('/', '.'));
211: Method m = factory.getMethod("aspectOf",
212: new Class[] { Class.class });
213: return m.invoke(null, new Object[] { perClass });
214: } catch (NoAspectBoundException nabe) {
215: throw nabe;
216: } catch (Throwable t) {
217: throw new NoAspectBoundException(t, qName);
218: }
219: }
220:
221: public static Object aspect$Of(String qName,
222: String aspectClassName, final Object perInstance) {
223: try {
224: ClassLoader loader = perInstance.getClass()
225: .getClassLoader();
226: Class containerClass = ContextClassLoader.forName(loader,
227: AspectFactoryManager.getAspectFactoryClassName(
228: aspectClassName, qName).replace('/', '.'));
229: Method m = containerClass.getMethod("aspectOf",
230: new Class[] { Object.class });
231: return m.invoke(null, new Object[] { perInstance });
232: } catch (NoAspectBoundException nabe) {
233: throw nabe;
234: } catch (Throwable t) {
235: throw new NoAspectBoundException(t, qName);
236: }
237: }
238:
239: //---------- helpers
240:
241: /**
242: * Lookup the aspect definition with the given qName, visible from the given loader.
243: * If qName is a class name only, the fallback will ensure only one aspect use is found.
244: *
245: * @param visibleFrom
246: * @param qName
247: * @return
248: */
249: private static AspectDefinition lookupAspectDefinition(
250: final ClassLoader visibleFrom, final String qName) {
251: AspectDefinition aspectDefinition = null;
252:
253: Set definitions = SystemDefinitionContainer
254: .getDefinitionsFor(visibleFrom);
255: if (qName.indexOf('/') > 0) {
256: // has system uuid ie real qName
257: for (Iterator iterator = definitions.iterator(); iterator
258: .hasNext();) {
259: SystemDefinition systemDefinition = (SystemDefinition) iterator
260: .next();
261: if (!qName.startsWith(systemDefinition.getUuid())) {
262: continue;
263: }
264: for (Iterator iterator1 = systemDefinition
265: .getAspectDefinitions().iterator(); iterator1
266: .hasNext();) {
267: AspectDefinition aspectDef = (AspectDefinition) iterator1
268: .next();
269: if (qName.equals(aspectDef.getQualifiedName())) {
270: aspectDefinition = aspectDef;
271: break;
272: }
273: }
274: }
275: } else {
276: // fallback on class name lookup
277: // must find at most one
278: int found = 0;
279: for (Iterator iterator = definitions.iterator(); iterator
280: .hasNext();) {
281: SystemDefinition systemDefinition = (SystemDefinition) iterator
282: .next();
283: for (Iterator iterator1 = systemDefinition
284: .getAspectDefinitions().iterator(); iterator1
285: .hasNext();) {
286: AspectDefinition aspectDef = (AspectDefinition) iterator1
287: .next();
288: if (qName.equals(aspectDef.getClassName())) {
289: aspectDefinition = aspectDef;
290: found++;
291: }
292: }
293: }
294: if (found > 1) {
295: throw new NoAspectBoundException(
296: "More than one AspectDefinition found, consider using other API methods",
297: qName);
298: }
299:
300: }
301:
302: if (aspectDefinition == null) {
303: throw new NoAspectBoundException(
304: "Could not find AspectDefinition", qName);
305: }
306:
307: return aspectDefinition;
308: }
309:
310: /**
311: * Class is non-instantiable.
312: */
313: private Aspects() {
314: }
315:
316: }
|