001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.aop.deployment;
023:
024: import java.io.File;
025: import java.io.FileNotFoundException;
026: import java.net.URL;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.StringTokenizer;
031:
032: import javassist.ByteArrayClassPath;
033: import javassist.scopedpool.ScopedClassPoolFactory;
034:
035: import javax.management.Attribute;
036: import javax.management.AttributeNotFoundException;
037: import javax.management.InstanceNotFoundException;
038: import javax.management.InvalidAttributeValueException;
039: import javax.management.MBeanException;
040: import javax.management.Notification;
041: import javax.management.ObjectName;
042: import javax.management.ReflectionException;
043:
044: import org.jboss.aop.AspectManager;
045: import org.jboss.aop.AspectNotificationHandler;
046: import org.jboss.aop.AspectXmlLoader;
047: import org.jboss.aop.ClassLoaderValidation;
048: import org.jboss.aop.Deployment;
049: import org.jboss.aop.hook.JDK14Transformer;
050: import org.jboss.aop.hook.JDK14TransformerManager;
051: import org.jboss.aop.instrument.InstrumentorFactory;
052: import org.jboss.aop.instrument.TransformerCommon;
053: import org.jboss.mx.loading.HeirarchicalLoaderRepository3;
054: import org.jboss.mx.server.ServerConstants;
055: import org.jboss.mx.util.ObjectNameFactory;
056: import org.jboss.system.ServiceMBeanSupport;
057: import org.jboss.system.server.ServerConfig;
058:
059: /**
060: * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
061: * @version $Revision: 60554 $
062: * @jmx:mbean extends="org.jboss.system.ServiceMBean"
063: */
064: public class AspectManagerService extends ServiceMBeanSupport implements
065: AspectManagerServiceMBean, AspectNotificationHandler {
066: static {
067: //pre-load necessary classes so that we avoid NoClassDefFoundErrors on JRockit when using the RepositoryClassloader hook
068: //When AspectManager.translate() is called the first time, these classes have not been loaded yet, and this is what causes
069: //JRockit to get confused
070: Class clazz = TransformerCommon.class;
071: clazz = HeirarchicalLoaderRepository3.class;
072: clazz = ByteArrayClassPath.class;
073: }
074:
075: public static final ObjectName DEFAULT_LOADER_REPOSITORY = ObjectNameFactory
076: .create(ServerConstants.DEFAULT_LOADER_NAME);
077:
078: // Attributes ---------------------------------------------------
079:
080: boolean created = false;
081: protected File tmpClassesDir;
082: protected boolean enableTransformer = false;
083: protected boolean enableLoadtimeWeaving = false;
084: protected boolean suppressTransformationErrors = true;
085: protected boolean suppressReferenceErrors = true;
086: protected String exclude;
087: protected String include;
088: protected String ignore;
089:
090: // Static -------------------------------------------------------
091:
092: // Constructors -------------------------------------------------
093: public AspectManagerService() {
094: }
095:
096: // Public -------------------------------------------------------
097:
098: protected ScopedClassPoolFactory createFactory() throws Exception {
099: return new JBossClassPoolFactory(tmpClassesDir);
100: }
101:
102: protected ClassLoaderValidation createClassLoaderValidation() {
103: return new JBossClassLoaderValidator();
104: }
105:
106: protected void createService() throws Exception {
107: // Set a default tmp classes dir to the jboss tmp dir/aopclasses
108: if (tmpClassesDir == null) {
109: String jbossTmpDir = System
110: .getProperty(ServerConfig.SERVER_TEMP_DIR);
111: if (jbossTmpDir == null)
112: jbossTmpDir = System.getProperty("java.io.tmpdir");
113: tmpClassesDir = new File(jbossTmpDir, "aopdynclasses");
114: }
115: // Validate the the tmp dir exists
116: if (tmpClassesDir.exists() == false
117: && tmpClassesDir.mkdirs() == false)
118: throw new FileNotFoundException(
119: "Failed to create tmpClassesDir: "
120: + tmpClassesDir.getAbsolutePath());
121: AspectManager.setClassPoolFactory(createFactory());
122:
123: AspectManager.classLoaderValidator = createClassLoaderValidation();
124: // Add the tmp classes dir to our UCL classpath
125:
126: Deployment.searchClasspath = false; // turn off dynamic finding of DDs
127: AspectManager.suppressTransformationErrors = suppressTransformationErrors;
128: if (enableTransformer && enableLoadtimeWeaving)
129: throw new RuntimeException(
130: "Cannot set both EnableTransformer and EnableLoadtimeWeaving");
131: if (enableTransformer) {
132: attachDeprecatedTranslator();
133: }
134: if (enableLoadtimeWeaving) {
135: attachTranslator();
136: }
137: created = true;
138: AspectManager.notificationHandler = this ;
139:
140: AspectManager.scopedCLHelper = new JBossScopedClassLoaderHelper();
141:
142: baseAop();
143: }
144:
145: protected void baseAop() {
146: try {
147: ClassLoader cl = Thread.currentThread()
148: .getContextClassLoader();
149: URL base = cl.getResource("base-aop.xml");
150: AspectXmlLoader.deployXML(base);
151: } catch (Exception ex) {
152: ex.printStackTrace();
153: }
154: }
155:
156: protected void attachDeprecatedTranslator() {
157: log
158: .warn("EnableTransformer has been deprecated, please use EnableLoadtimeWeaving. See docs for more details");
159: AspectManager mgr = AspectManager.instance();
160: try {
161: server.setAttribute(DEFAULT_LOADER_REPOSITORY,
162: new Attribute("Translator", mgr));
163: } catch (InstanceNotFoundException e) {
164: throw new RuntimeException(e);
165: } catch (AttributeNotFoundException e) {
166: throw new RuntimeException(e);
167: } catch (InvalidAttributeValueException e) {
168: throw new RuntimeException(e);
169: } catch (MBeanException e) {
170: throw new RuntimeException(e);
171: } catch (ReflectionException e) {
172: throw new RuntimeException(e);
173: }
174: }
175:
176: protected void detachDeprecatedTranslator() {
177: try {
178: server.setAttribute(DEFAULT_LOADER_REPOSITORY,
179: new Attribute("Translator", null));
180: } catch (InstanceNotFoundException e) {
181: throw new RuntimeException(e);
182: } catch (AttributeNotFoundException e) {
183: throw new RuntimeException(e);
184: } catch (InvalidAttributeValueException e) {
185: throw new RuntimeException(e);
186: } catch (MBeanException e) {
187: throw new RuntimeException(e);
188: } catch (ReflectionException e) {
189: throw new RuntimeException(e);
190: }
191: }
192:
193: protected void attachTranslator() {
194: JDK14TransformerManager.transformer = new JDK14Transformer() {
195: public byte[] transform(ClassLoader loader,
196: String classname, byte[] classBytes) {
197: try {
198: //Make sure that we use the correct classloader, in order to get the correct domain if it is a scoped loader
199: return AspectManager.instance(loader).translate(
200: classname, loader, classBytes);
201: } catch (Exception e) {
202: throw new RuntimeException("Error converting "
203: + classname + " on " + loader, e);
204: }
205: }
206: };
207: }
208:
209: protected void detachTranslator() {
210: JDK14TransformerManager.transformer = null;
211: }
212:
213: public void attachClass(String classname) {
214: Notification msg = new Notification("AOP class attached", this ,
215: getNextNotificationSequenceNumber());
216: msg.setUserData(classname);
217: sendNotification(msg);
218: }
219:
220: protected void startService() throws Exception {
221: }
222:
223: protected void stopService() {
224: }
225:
226: public boolean getPrune() {
227: return AspectManager.getPrune();
228: }
229:
230: public void setPrune(boolean prune) {
231: AspectManager.setPrune(prune);
232: }
233:
234: public String getExclude() {
235: return exclude;
236: }
237:
238: public void setExclude(String exclude) {
239: this .exclude = exclude;
240: ArrayList list = new ArrayList();
241: if (exclude != null) {
242: StringTokenizer tokenizer = new StringTokenizer(exclude,
243: ",");
244: while (tokenizer.hasMoreTokens()) {
245: list.add(tokenizer.nextToken().trim());
246: }
247: }
248: AspectManager.instance().setExclude(list);
249: }
250:
251: public String getInclude() {
252: return include;
253: }
254:
255: public void setInclude(String include) {
256: this .include = include;
257: ArrayList list = new ArrayList();
258: if (include != null) {
259: StringTokenizer tokenizer = new StringTokenizer(include,
260: ",");
261: while (tokenizer.hasMoreTokens()) {
262: list.add(tokenizer.nextToken().trim());
263: }
264: }
265: AspectManager.instance().setInclude(list);
266: }
267:
268: public String getIgnore() {
269: return ignore;
270: }
271:
272: public void setIgnore(String ignore) {
273: this .ignore = ignore;
274: ArrayList list = new ArrayList();
275: if (ignore != null) {
276: StringTokenizer tokenizer = new StringTokenizer(ignore, ",");
277: while (tokenizer.hasMoreTokens()) {
278: list.add(tokenizer.nextToken().trim());
279: }
280: }
281: AspectManager.instance().setIgnore(list);
282: }
283:
284: /**
285: * The temporary directory to which dyn class files are written
286: *
287: * @jmx:managed-attribute
288: */
289: public File getTmpClassesDir() {
290: return tmpClassesDir;
291: }
292:
293: /**
294: * The temporary directory to which dyn class files are written
295: *
296: * @jmx:managed-attribute
297: */
298: public void setTmpClassesDir(File tmpClassesDir) {
299: this .tmpClassesDir = tmpClassesDir;
300: }
301:
302: /**
303: * Set the verbosity of aop logging. It doesn't use log4j
304: *
305: * @jmx:managed-attribute
306: */
307: public boolean getVerbose() {
308: return AspectManager.verbose;
309: }
310:
311: /**
312: * Set the verbosity of aop logging. It doesn't use log4j
313: *
314: * @jmx:managed-attribute
315: */
316: public void setVerbose(boolean verbose) {
317: AspectManager.verbose = verbose;
318: }
319:
320: /**
321: * Use aop optimizations. Optional just in case there is a bug
322: *
323: * @jmx:managed-attribute
324: */
325: public boolean getOptimized() {
326: return AspectManager.optimize;
327: }
328:
329: /**
330: * Use aop optimizations. Optional just in case there is a bug
331: *
332: * @jmx:managed-attribute
333: */
334: public void setOptimized(boolean verbose) {
335: AspectManager.optimize = verbose;
336: }
337:
338: /**
339: * @jmx:managed-attribute
340: */
341: public boolean getSuppressTransformationErrors() {
342: return suppressTransformationErrors;
343: }
344:
345: /**
346: * @jmx:managed-attribute
347: */
348: public void setSuppressTransformationErrors(
349: boolean suppressTransformationErrors) {
350: this .suppressTransformationErrors = suppressTransformationErrors;
351: AspectManager.suppressTransformationErrors = suppressTransformationErrors;
352: }
353:
354: /**
355: * @jmx:managed-attribute
356: */
357: public boolean getSuppressReferenceErrors() {
358: return suppressReferenceErrors;
359: }
360:
361: /**
362: * @jmx:managed-attribute
363: */
364: public void setSuppressReferenceErrors(
365: boolean suppressReferenceErrors) {
366: this .suppressReferenceErrors = suppressReferenceErrors;
367: AspectManager.suppressReferenceErrors = suppressReferenceErrors;
368: }
369:
370: /**
371: * The temporary directory to which dyn class files are written
372: *
373: * @jmx:managed-attribute
374: */
375: public boolean getEnableTransformer() {
376: return enableTransformer;
377: }
378:
379: /**
380: * The temporary directory to which dyn class files are written
381: *
382: * @jmx:managed-operation
383: */
384: public String interceptorFactories() {
385: Map factories = AspectManager.instance()
386: .getInterceptorFactories();
387: Iterator it = factories.keySet().iterator();
388: StringBuffer buffer = new StringBuffer("");
389: while (it.hasNext()) {
390: buffer.append(it.next() + "<br>");
391: }
392: return buffer.toString();
393: }
394:
395: /**
396: * The temporary directory to which dyn class files are written
397: *
398: * @jmx:managed-operation
399: */
400: public String aspectDefinitions() {
401: Map factories = AspectManager.instance().getAspectDefinitions();
402: Iterator it = factories.keySet().iterator();
403: StringBuffer buffer = new StringBuffer("");
404: while (it.hasNext()) {
405: buffer.append(it.next() + "<br>");
406: }
407: return buffer.toString();
408: }
409:
410: /**
411: * @jmx:managed-operation
412: */
413: public String introductions() {
414: Map factories = AspectManager.instance()
415: .getInterfaceIntroductions();
416: Iterator it = factories.keySet().iterator();
417: StringBuffer buffer = new StringBuffer("");
418: while (it.hasNext()) {
419: buffer.append(it.next() + "<br>");
420: }
421: return buffer.toString();
422: }
423:
424: /**
425: * The temporary directory to which dyn class files are written
426: *
427: * @jmx:managed-operation
428: */
429: public String stacks() {
430: Map factories = AspectManager.instance().getInterceptorStacks();
431: Iterator it = factories.keySet().iterator();
432: StringBuffer buffer = new StringBuffer("");
433: while (it.hasNext()) {
434: buffer.append(it.next() + "<br>");
435: }
436: return buffer.toString();
437: }
438:
439: /**
440: * The temporary directory to which dyn class files are written
441: *
442: * @jmx:managed-operation
443: */
444: public String bindings() {
445: Map factories = AspectManager.instance().getBindings();
446: Iterator it = factories.keySet().iterator();
447: StringBuffer buffer = new StringBuffer("");
448: while (it.hasNext()) {
449: buffer.append(it.next() + "<br>");
450: }
451: return buffer.toString();
452: }
453:
454: /**
455: * The temporary directory to which dyn class files are written
456: *
457: * @jmx:managed-operation
458: */
459: public String registeredClassLoaders() {
460: Map factories = AspectManager.instance().getRegisteredCLs();
461: Iterator it = factories.keySet().iterator();
462: StringBuffer buffer = new StringBuffer("");
463: while (it.hasNext()) {
464: buffer.append(it.next() + "<br>");
465: }
466: return buffer.toString();
467: }
468:
469: /**
470: * The temporary directory to which dyn class files are written
471: *
472: * @jmx:managed-attribute
473: */
474: public void setEnableTransformer(boolean enableTransformer) {
475: // Testsuite uses enableTransformer, we may be testing new loadtime features though.
476:
477: if (enableLoadtimeWeaving) {
478: log.warn("enabledLoadtimeWeaving alread set");
479: return;
480: }
481: if (this .enableTransformer == enableTransformer)
482: return;
483: if (this .getState() == STARTED) {
484: if (enableTransformer) {
485: attachDeprecatedTranslator();
486: } else {
487: detachDeprecatedTranslator();
488: }
489: }
490: this .enableTransformer = enableTransformer;
491: }
492:
493: public boolean getEnableLoadtimeWeaving() {
494: return enableLoadtimeWeaving;
495: }
496:
497: /**
498: * The temporary directory to which dyn class files are written
499: *
500: * @jmx:managed-attribute
501: */
502: public void setEnableLoadtimeWeaving(boolean enableTransformer) {
503: if (this .enableLoadtimeWeaving == enableTransformer)
504: return;
505: if (this .getState() == STARTED) {
506: if (enableTransformer) {
507: attachTranslator();
508: } else {
509: detachTranslator();
510: }
511: }
512: this .enableLoadtimeWeaving = enableTransformer;
513: }
514:
515: public String getInstrumentor() {
516: return InstrumentorFactory.getInstrumentorName();
517: }
518:
519: public void setInstrumentor(String instrumentor) {
520: InstrumentorFactory.initialise(instrumentor);
521: }
522:
523: }
|