001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.aspect.management;
008:
009: import org.codehaus.aspectwerkz.aspect.DefaultMixinFactory;
010: import org.codehaus.aspectwerkz.aspect.MixinFactory;
011: import org.codehaus.aspectwerkz.util.ContextClassLoader;
012: import org.codehaus.aspectwerkz.DeploymentModel;
013: import org.codehaus.aspectwerkz.util.ContextClassLoader;
014: import org.codehaus.aspectwerkz.definition.SystemDefinition;
015: import org.codehaus.aspectwerkz.definition.SystemDefinitionContainer;
016: import org.codehaus.aspectwerkz.definition.MixinDefinition;
017: import org.codehaus.aspectwerkz.exception.DefinitionException;
018: import org.codehaus.aspectwerkz.DeploymentModel;
019:
020: import java.util.*;
021: import java.lang.reflect.Constructor;
022: import java.lang.reflect.InvocationTargetException;
023:
024: /**
025: * Manages the mixins, registry for the mixin factories (one factory per mixin type).
026: *
027: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
028: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
029: */
030: public class Mixins {
031:
032: /**
033: * The default mixin factory class.
034: */
035: public static final String DEFAULT_MIXIN_FACTORY = DefaultMixinFactory.class
036: .getName();
037:
038: /**
039: * Map with all the mixin factories mapped to the mixin class
040: */
041: private static final Map MIXIN_FACTORIES = new WeakHashMap();
042:
043: /**
044: * Returns the mixin factory for the mixin with the given name.
045: *
046: * @param mixinClass the class of the mixin
047: * @param mixinCalledFromLoader
048: * @return the factory, put in cache based on mixin class as a key
049: */
050: public static MixinFactory getFactory(final Class mixinClass,
051: final ClassLoader mixinCalledFromLoader) {
052: synchronized (MIXIN_FACTORIES) {
053: MixinFactory factory = (MixinFactory) MIXIN_FACTORIES
054: .get(mixinClass);
055: if (factory == null) {
056: factory = createMixinFactory(mixinClass,
057: mixinCalledFromLoader);
058: //FIXME by using a lookup by uuid/aspectNickName
059: // right now broken since we have 1 container per mixin CLASS while the definition
060: // does allow for some mix (several mixin, several container, same mixin class)
061: MIXIN_FACTORIES.put(mixinClass, factory);
062: }
063: return factory;
064: }
065: }
066:
067: /**
068: * Returns the per JVM mixin instance for the mixin with the given name
069: *
070: * @param name the name of the mixin
071: * @param loader target class classloader
072: * @return the per jvm mixin instance
073: */
074: public static Object mixinOf(final String name, ClassLoader loader) {
075: try {
076: Class mixinClass = Class.forName(name, false, loader);
077: return mixinOf(mixinClass);
078: } catch (ClassNotFoundException e) {
079: throw new RuntimeException("could not load mixin " + name
080: + " from " + loader);
081: }
082: }
083:
084: /**
085: * Returns the per jvm mixin instance for the mixin with the given implementation class
086: * deployed using the perJVM model.
087: *
088: * @param mixinClass the name of the mixin
089: * @return the per jvm mixin instance
090: */
091: public static Object mixinOf(final Class mixinClass) {
092: return getFactory(mixinClass, mixinClass.getClassLoader())
093: .mixinOf();
094: }
095:
096: /**
097: * Returns the per class mixin instance for the mixin with the given name for the perClass model
098: *
099: * @param name the name of the mixin
100: * @param targetClass the targetClass class
101: * @return the per class mixin instance
102: */
103: public static Object mixinOf(final String name,
104: final Class targetClass) {
105: try {
106: Class mixinClass = Class.forName(name, false, targetClass
107: .getClassLoader());
108: return mixinOf(mixinClass, targetClass);
109: } catch (ClassNotFoundException e) {
110: throw new RuntimeException("could not load mixin " + name
111: + " from " + targetClass.getClassLoader());
112: }
113: }
114:
115: /**
116: * Returns the per class mixin instance for the mixin with the given implemnentation class
117: * deployed using the perClass model.
118: *
119: * @param mixinClass the name of the mixin
120: * @param targetClass the targetClass class
121: * @return the per class mixin instance
122: */
123: public static Object mixinOf(final Class mixinClass,
124: final Class targetClass) {
125: return getFactory(mixinClass, targetClass.getClassLoader())
126: .mixinOf(targetClass);
127: }
128:
129: /**
130: * Returns the per targetClass instance mixin instance for the mixin with the given name for the perInstance model.
131: *
132: * @param name the name of the mixin
133: * @param targetInstance the targetClass instance, can be null (static method, ctor call)
134: * @return the per instance mixin instance, fallback on perClass if targetInstance is null
135: */
136: public static Object mixinOf(final String name,
137: final Object targetInstance) {
138: try {
139: Class mixinClass = Class.forName(name, false,
140: targetInstance.getClass().getClassLoader());
141: return mixinOf(mixinClass, targetInstance);
142: } catch (ClassNotFoundException e) {
143: throw new RuntimeException("could not load mixin " + name
144: + " from "
145: + targetInstance.getClass().getClassLoader());
146: }
147: }
148:
149: /**
150: * Returns the per class mixin instance for the mixin with the given implemnentation class
151: * deployed using the perClass model.
152: *
153: * @param mixinClass the name of the mixin
154: * @param targetInstance the targetClass instance, can be null
155: * @return the per targetClass instance mixin instance, fallback to perClass if targetInstance is null
156: */
157: public static Object mixinOf(final Class mixinClass,
158: final Object targetInstance) {
159: //TODO WHAT IF targetInstance is null ? f.e. ITD static methods
160: return getFactory(mixinClass,
161: targetInstance.getClass().getClassLoader()).mixinOf(
162: targetInstance);
163: }
164:
165: /**
166: * Creates a new mixin factory.
167: *
168: * @param mixinClass the mixin class
169: * @param mixinCalledFromLoader classloader of the target class advised by the mixin (app server packaging)
170: */
171: private static MixinFactory createMixinFactory(
172: final Class mixinClass,
173: final ClassLoader mixinCalledFromLoader) {
174: final MixinDefinition mixinDefinition = getMixinDefinition(
175: mixinClass, mixinCalledFromLoader);
176:
177: String factoryClassName = mixinDefinition.getFactoryClassName();
178: try {
179: Class containerClass;
180: if (factoryClassName == null) {
181: containerClass = ContextClassLoader.forName(mixinClass
182: .getClassLoader(), DEFAULT_MIXIN_FACTORY);
183: } else {
184: containerClass = ContextClassLoader.forName(mixinClass
185: .getClassLoader(), factoryClassName);
186: }
187: Constructor constructor = containerClass
188: .getConstructor(new Class[] { Class.class,
189: DeploymentModel.class });
190: final MixinFactory factory = (MixinFactory) constructor
191: .newInstance(new Object[] { mixinClass,
192: mixinDefinition.getDeploymentModel() });
193: return factory;
194: } catch (InvocationTargetException e) {
195: throw new DefinitionException(e.getTargetException()
196: .toString());
197: } catch (NoSuchMethodException e) {
198: throw new DefinitionException(
199: "mixin factory does not have a valid constructor ["
200: + factoryClassName
201: + "] need to have a signature like this [MyMixinFactory(Class mixin, DeploymentModel scope)]: "
202: + e.toString());
203: } catch (Throwable e) {
204: StringBuffer cause = new StringBuffer();
205: cause
206: .append("could not create mixin container using the implementation specified [");
207: cause.append(factoryClassName);
208: cause.append("] due to: ");
209: cause.append(e.toString());
210: throw new DefinitionException(cause.toString());
211: }
212: }
213:
214: /**
215: * Returns the parameter for a mixin based on the mixin implementation class and a classloader from
216: * where the mixin is visible (the classloader that owns the aop.xml with the "mixin" element, or a child of it).
217: * <p/>
218: * Note: the mixinClass classloader can be different, if you place the mixin in the system classpath, and reference
219: * it only from a deployed application.
220: * <p/>
221: * Note: you should not use a mixin more than once. Consider subclassing the mixin in this case. The returned parameters
222: * are the one from the first mixin found.
223: *
224: * @param mixinClass
225: * @return
226: */
227: public static Map getParameters(Class mixinClass, ClassLoader loader) {
228: MixinDefinition mixinDefinition = getMixinDefinition(
229: mixinClass, loader);
230: return mixinDefinition.getParameters();
231: }
232:
233: /**
234: * Lookups a mixin definition based on the mixin impl class and a classloader from where the mixin is
235: * visible. The given classloader can be different from the mixin class classloader.
236: *
237: * @param mixinClass
238: * @param visibleFrom
239: * @return
240: */
241: public static MixinDefinition getMixinDefinition(Class mixinClass,
242: ClassLoader visibleFrom) {
243: MixinDefinition mixinDefinition = null;
244:
245: Set definitions = SystemDefinitionContainer
246: .getDefinitionsFor(visibleFrom);
247: for (Iterator iterator = definitions.iterator(); iterator
248: .hasNext()
249: && mixinDefinition == null;) {
250: SystemDefinition systemDefinition = (SystemDefinition) iterator
251: .next();
252: for (Iterator iterator1 = systemDefinition
253: .getMixinDefinitions().iterator(); iterator1
254: .hasNext();) {
255: MixinDefinition mixinDef = (MixinDefinition) iterator1
256: .next();
257: if (mixinClass.getName().replace('/', '.').equals(
258: mixinDef.getMixinImpl().getName())) {
259: mixinDefinition = mixinDef;
260: break;
261: }
262: }
263: }
264: if (mixinDefinition == null) {
265: throw new DefinitionException(
266: "could not find definition for mixin: "
267: + mixinClass.getName() + " (loader "
268: + mixinClass.getClassLoader() + ")"
269: + " from loader " + visibleFrom);
270: }
271: return mixinDefinition;
272: }
273:
274: /**
275: * Class is non-instantiable.
276: */
277: private Mixins() {
278: }
279: }
|