001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005:
006: package com.tc.aspectwerkz.definition.deployer;
007:
008: import com.tc.aspectwerkz.DeploymentModel;
009: import com.tc.aspectwerkz.definition.SystemDefinition;
010: import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
011: import com.tc.aspectwerkz.exception.WrappedRuntimeException;
012: import com.tc.aspectwerkz.transform.Properties;
013: import com.tc.aspectwerkz.util.Strings;
014: import com.tc.logging.CustomerLogging;
015: import com.tc.logging.TCLogger;
016:
017: import java.util.ArrayList;
018: import java.util.HashMap;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Map;
022:
023: /**
024: * TODO document class
025: *
026: * @author Jonas Bonér
027: */
028: public class StandardAspectModuleDeployer implements
029: AspectModuleDeployer {
030:
031: public static final String[] ASPECT_MODULES;
032: static {
033: ASPECT_MODULES = Strings.splitString(Properties.ASPECT_MODULES,
034: ",");
035: }
036:
037: private final static Map modules = new HashMap();
038: private final static TCLogger logger = CustomerLogging
039: .getDSOInstrumentationLogger();
040:
041: private final List m_builders = new ArrayList();
042: private final SystemDefinition m_systemDef;
043: private final ClassLoader m_loader;
044:
045: /**
046: * Loads all registered aspect modules, builds and deploy them in the class loader specified.
047: *
048: * @param loader
049: * @param moduleNames
050: */
051: public static void deploy(final ClassLoader loader,
052: String[] moduleNames) {
053: for (int i = 0; i < moduleNames.length; i++) {
054: deploy(loader, moduleNames[i]);
055: }
056: }
057:
058: public static void deploy(final ClassLoader loader,
059: String moduleName) {
060: final Map loaders;
061:
062: synchronized (modules) {
063: // TODO loaders collection should use weak refs to class loaders
064: Map tmp = (Map) modules.get(moduleName);
065: if (tmp == null) {
066: tmp = new HashMap();
067: modules.put(moduleName, tmp);
068: }
069: loaders = tmp;
070: }
071:
072: final DeployedLoader deployedLoader;
073:
074: synchronized (loaders) {
075: DeployedLoader d = (DeployedLoader) loaders.get(loader);
076: if (d == null) {
077: d = new DeployedLoader(loader, moduleName);
078: loaders.put(loader, d);
079: }
080: deployedLoader = d;
081: }
082:
083: try {
084: deployedLoader.doDeployIfNeeded();
085: } catch (InterruptedException e) {
086: throw new WrappedRuntimeException(e);
087: }
088: }
089:
090: private static String getLoaderName(final ClassLoader loader) {
091: // XXX: Dependency on DSO L1 code from AW. This isn't kosher at the moment
092: // if(loader instanceof NamedClassLoader) {
093: // return ((NamedClassLoader) loader).__tc_getClassLoaderName();
094: // }
095: return loader.getClass().getName() + "@"
096: + System.identityHashCode(loader);
097: }
098:
099: /**
100: * Creates, registers and returns an aspect definition builder. Use-case: Get an aspect builder and then use it to add
101: * advice and pointcut builders to build up a full aspect definintion programatically.
102: *
103: * @param aspectClass
104: * @param scope
105: * @param containerClassName
106: * @return a newly registered aspect builder
107: */
108: public synchronized AspectDefinitionBuilder newAspectBuilder(
109: final String aspectClass, final DeploymentModel scope,
110: final String containerClassName) {
111: AspectDefinitionBuilder aspectDefinitionBuilder = new AspectDefinitionBuilder(
112: aspectClass, scope, containerClassName, m_systemDef,
113: m_loader);
114: m_builders.add(aspectDefinitionBuilder);
115: return aspectDefinitionBuilder;
116: }
117:
118: /**
119: * Creates and adds a new mixin builder to the deployment set.
120: *
121: * @param aspectClass
122: * @param deploymentModel
123: * @param pointcut
124: */
125: public synchronized void addMixin(final String aspectClass,
126: final DeploymentModel deploymentModel,
127: final String pointcut, final boolean isTransient) {
128: m_builders.add(new MixinDefinitionBuilder(aspectClass,
129: deploymentModel, pointcut, isTransient, m_systemDef,
130: m_loader));
131: }
132:
133: public ClassLoader getClassLoader() {
134: return m_loader;
135: }
136:
137: /**
138: * Creates a new aspect module.
139: *
140: * @param loader
141: */
142: private StandardAspectModuleDeployer(final ClassLoader loader) {
143: m_systemDef = SystemDefinitionContainer
144: .getVirtualDefinitionFor(loader);
145: m_loader = loader;
146: }
147:
148: private synchronized void doDeploy(String moduleName) {
149: loadModule(moduleName);
150: buildModule();
151: SystemDefinitionContainer.printDeploymentInfoFor(m_loader);
152: }
153:
154: private void loadModule(String moduleName) {
155: try {
156: Class aspectModuleClass = getClass().getClassLoader()
157: .loadClass(moduleName);
158: AspectModule aspectModule = (AspectModule) aspectModuleClass
159: .newInstance();
160: aspectModule.deploy(this );
161: } catch (Throwable e) {
162: logger.error("Aspect module [" + moduleName
163: + "] could not be deployed in "
164: + getLoaderName(m_loader) + "; " + e.toString(), e);
165: }
166: }
167:
168: private void buildModule() {
169: for (Iterator it = m_builders.iterator(); it.hasNext();) {
170: ((DefinitionBuilder) it.next()).build();
171: }
172: }
173:
174: private static class DeployedLoader {
175: private static final int NOT_DEPLOYED = 1;
176: private static final int DEPLOYING = 2;
177: private static final int DEPLOYED = 3;
178:
179: private int state = NOT_DEPLOYED;
180:
181: private final ClassLoader loader;
182: private final String moduleName;
183:
184: DeployedLoader(ClassLoader loader, String moduleName) {
185: this .loader = loader;
186: this .moduleName = moduleName;
187: }
188:
189: void doDeployIfNeeded() throws InterruptedException {
190: boolean doDeploy = false;
191: boolean wait = false;
192:
193: synchronized (this ) {
194: switch (state) {
195: case NOT_DEPLOYED: {
196: state = DEPLOYING;
197: doDeploy = true;
198: break;
199: }
200: case DEPLOYING: {
201: wait = true;
202: break;
203: }
204: case DEPLOYED: {
205: // no action required
206: break;
207: }
208: default: {
209: throw new AssertionError("unknown state: " + state);
210: }
211: }
212: }
213:
214: if (doDeploy) {
215: logger.info("Loading aspect module [" + moduleName
216: + "] in loader " + getLoaderName(loader));
217: new StandardAspectModuleDeployer(loader)
218: .doDeploy(moduleName);
219: synchronized (this) {
220: state = DEPLOYED;
221: notifyAll();
222: }
223: } else if (wait) {
224: synchronized (this) {
225: while (state != DEPLOYED) {
226: wait();
227: }
228: }
229: }
230: }
231: }
232: }
|