/* *******************************************************************
 * Copyright (c) 2004 IBM Corporation
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Matthew Webster, Adrian Colyer, John Kew + Lyor Goldstein (caching)
 *     Martin Lippert     initial implementation
 * ******************************************************************/

package org.aspectj.weaver.tools;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

import org.aspectj.bridge.AbortException;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessage.Kind;
import org.aspectj.bridge.IMessageContext;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.IMessageHolder;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageHandler;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.MessageWriter;
import org.aspectj.bridge.Version;
import org.aspectj.bridge.WeaveMessage;
import org.aspectj.util.FileUtil;
import org.aspectj.util.LangUtil;
import org.aspectj.weaver.IClassFileProvider;
import org.aspectj.weaver.IUnwovenClassFile;
import org.aspectj.weaver.IWeaveRequestor;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelObjectType;
import org.aspectj.weaver.bcel.BcelWeaver;
import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.bcel.UnwovenClassFile;
import org.aspectj.weaver.tools.cache.CachedClassEntry;
import org.aspectj.weaver.tools.cache.CachedClassReference;
import org.aspectj.weaver.tools.cache.SimpleCache;
import org.aspectj.weaver.tools.cache.SimpleCacheFactory;
import org.aspectj.weaver.tools.cache.WeavedClassCache;

// OPTIMIZE add guards for all the debug/info/etc
This adaptor allows the AspectJ compiler to be embedded in an existing system to facilitate load-time weaving. It provides an interface for a weaving class loader to provide a classpath to be woven by a set of aspects. A callback is supplied to allow a class loader to define classes generated by the compiler during the weaving process.

A weaving class loader should create a WeavingAdaptor before any classes are defined, typically during construction. The set of aspects passed to the adaptor is fixed for the lifetime of the adaptor although the classpath can be augmented. A system property can be set to allow verbose weaving messages to be written to the console.

/** * This adaptor allows the AspectJ compiler to be embedded in an existing system to facilitate load-time weaving. It provides an * interface for a weaving class loader to provide a classpath to be woven by a set of aspects. A callback is supplied to allow a * class loader to define classes generated by the compiler during the weaving process. * <p> * A weaving class loader should create a <code>WeavingAdaptor</code> before any classes are defined, typically during construction. * The set of aspects passed to the adaptor is fixed for the lifetime of the adaptor although the classpath can be augmented. A * system property can be set to allow verbose weaving messages to be written to the console. * */
public class WeavingAdaptor implements IMessageContext {
System property used to turn on verbose weaving messages
/** * System property used to turn on verbose weaving messages */
public static final String WEAVING_ADAPTOR_VERBOSE = "aj.weaving.verbose"; public static final String SHOW_WEAVE_INFO_PROPERTY = "org.aspectj.weaver.showWeaveInfo"; public static final String TRACE_MESSAGES_PROPERTY = "org.aspectj.tracing.messages"; private final static String ASPECTJ_BASE_PACKAGE = "org.aspectj."; private final static String PACKAGE_INITIAL_CHARS = ASPECTJ_BASE_PACKAGE.charAt(0) + "sj"; private boolean enabled = false; protected boolean verbose = getVerbose(); protected BcelWorld bcelWorld; protected BcelWeaver weaver; private IMessageHandler messageHandler; private WeavingAdaptorMessageHolder messageHolder; private boolean abortOnError = false; protected GeneratedClassHandler generatedClassHandler; protected Map<String, IUnwovenClassFile> generatedClasses = new HashMap<String, IUnwovenClassFile>(); public BcelObjectType delegateForCurrentClass; // lazily initialized, should be used to prevent parsing bytecode multiple // times protected ProtectionDomain activeProtectionDomain; private boolean haveWarnedOnJavax = false; protected WeavedClassCache cache; private int weavingSpecialTypes = 0; private static final int INITIALIZED = 0x1; private static final int WEAVE_JAVA_PACKAGE = 0x2; private static final int WEAVE_JAVAX_PACKAGE = 0x4; private static Trace trace = TraceFactory.getTraceFactory().getTrace(WeavingAdaptor.class); protected WeavingAdaptor() { }
Construct a WeavingAdaptor with a reference to a weaving class loader. The adaptor will automatically search the class loader hierarchy to resolve classes. The adaptor will also search the hierarchy for WeavingClassLoader instances to determine the set of aspects to be used for weaving.
Params:
  • loader – instance of ClassLoader
/** * Construct a WeavingAdaptor with a reference to a weaving class loader. The adaptor will automatically search the class loader * hierarchy to resolve classes. The adaptor will also search the hierarchy for WeavingClassLoader instances to determine the * set of aspects to be used for weaving. * * @param loader instance of <code>ClassLoader</code> */
public WeavingAdaptor(WeavingClassLoader loader) { // System.err.println("? WeavingAdaptor.<init>(" + loader +"," + aspectURLs.length + ")"); generatedClassHandler = loader; init((ClassLoader)loader, getFullClassPath((ClassLoader) loader), getFullAspectPath((ClassLoader) loader/* ,aspectURLs */)); }
Construct a WeavingAdaptor with a reference to a GeneratedClassHandler, a full search path for resolving classes and a complete set of aspects. The search path must include classes loaded by the class loader constructing the WeavingAdaptor and all its parents in the hierarchy.
Params:
  • handler – GeneratedClassHandler
  • classURLs – the URLs from which to resolve classes
  • aspectURLs – the aspects used to weave classes defined by this class loader
/** * Construct a WeavingAdaptor with a reference to a <code>GeneratedClassHandler</code>, a full search path for resolving classes * and a complete set of aspects. The search path must include classes loaded by the class loader constructing the * WeavingAdaptor and all its parents in the hierarchy. * * @param handler <code>GeneratedClassHandler</code> * @param classURLs the URLs from which to resolve classes * @param aspectURLs the aspects used to weave classes defined by this class loader */
public WeavingAdaptor(GeneratedClassHandler handler, URL[] classURLs, URL[] aspectURLs) { // System.err.println("? WeavingAdaptor.<init>()"); generatedClassHandler = handler; init(null, FileUtil.makeClasspath(classURLs), FileUtil.makeClasspath(aspectURLs)); } protected List<String> getFullClassPath(ClassLoader loader) { List<String> list = new LinkedList<String>(); for (; loader != null; loader = loader.getParent()) { if (loader instanceof URLClassLoader) { URL[] urls = ((URLClassLoader) loader).getURLs(); list.addAll(0, FileUtil.makeClasspath(urls)); } else { warn("cannot determine classpath"); } } // On Java9 it is possible to fail to find a URLClassLoader from which to derive a suitable classpath // For now we can determine it from the java.class.path: if (LangUtil.is19VMOrGreater()) { list.add(0, LangUtil.getJrtFsFilePath()); List<String> javaClassPathEntries = makeClasspath(System.getProperty("java.class.path")); for (int i=javaClassPathEntries.size()-1;i>=0;i--) { String javaClassPathEntry = javaClassPathEntries.get(i); if (!list.contains(javaClassPathEntry)) { list.add(0,javaClassPathEntry); } } } // On Java9 the sun.boot.class.path won't be set. System classes accessible through JRT filesystem list.addAll(0, makeClasspath(System.getProperty("sun.boot.class.path"))); return list; } private List<String> getFullAspectPath(ClassLoader loader) { List<String> list = new LinkedList<String>(); for (; loader != null; loader = loader.getParent()) { if (loader instanceof WeavingClassLoader) { URL[] urls = ((WeavingClassLoader) loader).getAspectURLs(); list.addAll(0, FileUtil.makeClasspath(urls)); } } return list; } private static boolean getVerbose() { try { return Boolean.getBoolean(WEAVING_ADAPTOR_VERBOSE); } catch (Throwable t) { // security exception return false; } }
Initialize the WeavingAdapter
Params:
  • loader – ClassLoader used by this adapter; which can be null
  • classPath – classpath of this adapter
  • aspectPath – list of aspect paths
/** * Initialize the WeavingAdapter * @param loader ClassLoader used by this adapter; which can be null * @param classPath classpath of this adapter * @param aspectPath list of aspect paths */
private void init(ClassLoader loader, List<String> classPath, List<String> aspectPath) { abortOnError = true; createMessageHandler(); info("using classpath: " + classPath); info("using aspectpath: " + aspectPath); bcelWorld = new BcelWorld(classPath, messageHandler, null); bcelWorld.setXnoInline(false); bcelWorld.getLint().loadDefaultProperties(); if (LangUtil.is15VMOrGreater()) { bcelWorld.setBehaveInJava5Way(true); } weaver = new BcelWeaver(bcelWorld); registerAspectLibraries(aspectPath); initializeCache(loader, aspectPath, null, getMessageHandler()); enabled = true; }
If the cache is enabled, initialize it and swap out the existing classhandler for the caching one -
Params:
  • loader – classloader for this adapter, may be null
  • aspects – List of strings representing aspects managed by the adapter; these could be urls or classnames
  • existingClassHandler – current class handler
  • myMessageHandler – current message handler
/** * If the cache is enabled, initialize it and swap out the existing classhandler * for the caching one - * * @param loader classloader for this adapter, may be null * @param aspects List of strings representing aspects managed by the adapter; these could be urls or classnames * @param existingClassHandler current class handler * @param myMessageHandler current message handler */
protected void initializeCache(ClassLoader loader, List<String> aspects, GeneratedClassHandler existingClassHandler, IMessageHandler myMessageHandler) { if (WeavedClassCache.isEnabled()) { cache = WeavedClassCache.createCache(loader, aspects, existingClassHandler, myMessageHandler); // Wrap the existing class handler so that any generated classes are also cached if (cache != null) { this.generatedClassHandler = cache.getCachingClassHandler(); } } } protected void createMessageHandler() { messageHolder = new WeavingAdaptorMessageHolder(new PrintWriter(System.err)); messageHandler = messageHolder; if (verbose) { messageHandler.dontIgnore(IMessage.INFO); } if (Boolean.getBoolean(SHOW_WEAVE_INFO_PROPERTY)) { messageHandler.dontIgnore(IMessage.WEAVEINFO); } info("AspectJ Weaver Version " + Version.getText() + " built on " + Version.getTimeText()); //$NON-NLS-1$ } protected IMessageHandler getMessageHandler() { return messageHandler; } public IMessageHolder getMessageHolder() { return messageHolder; } protected void setMessageHandler(IMessageHandler mh) { if (mh instanceof ISupportsMessageContext) { ISupportsMessageContext smc = (ISupportsMessageContext) mh; smc.setMessageContext(this); } if (mh != messageHolder) { messageHolder.setDelegate(mh); } messageHolder.flushMessages(); } protected void disable() { if (trace.isTraceEnabled()) { trace.enter("disable", this); } enabled = false; messageHolder.flushMessages(); if (trace.isTraceEnabled()) { trace.exit("disable"); } } protected void enable() { enabled = true; messageHolder.flushMessages(); } protected boolean isEnabled() { return enabled; }
Appends URL to path used by the WeavingAdptor to resolve classes
Params:
  • url – to be appended to search path
/** * Appends URL to path used by the WeavingAdptor to resolve classes * * @param url to be appended to search path */
public void addURL(URL url) { File libFile = new File(url.getPath()); try { weaver.addLibraryJarFile(libFile); } catch (IOException ex) { warn("bad library: '" + libFile + "'"); } }
Weave a class using aspects previously supplied to the adaptor.
Params:
  • name – the name of the class
  • bytes – the class bytes
Throws:
Returns:the woven bytes
/** * Weave a class using aspects previously supplied to the adaptor. * * @param name the name of the class * @param bytes the class bytes * @return the woven bytes * @exception IOException weave failed */
public byte[] weaveClass(String name, byte[] bytes) throws IOException { return weaveClass(name, bytes, false); } // Track if the weaver is already running on this thread - don't allow re-entrant calls private ThreadLocal<Boolean> weaverRunning = new ThreadLocal<Boolean>() { @Override protected Boolean initialValue() { return Boolean.FALSE; } };
Weave a class using aspects previously supplied to the adaptor.
Params:
  • name – the name of the class
  • bytes – the class bytes
  • mustWeave – if true then this class *must* get woven (used for concrete aspects generated from XML)
Throws:
Returns:the woven bytes
/** * Weave a class using aspects previously supplied to the adaptor. * * @param name the name of the class * @param bytes the class bytes * @param mustWeave if true then this class *must* get woven (used for concrete aspects generated from XML) * @return the woven bytes * @exception IOException weave failed */
public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IOException { if (trace == null) { // Pr231945: we are likely to be under tomcat and ENABLE_CLEAR_REFERENCES hasn't been set System.err .println("AspectJ Weaver cannot continue to weave, static state has been cleared. Are you under Tomcat? In order to weave '" + name + "' during shutdown, 'org.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false' must be set (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=231945)."); return bytes; } if (weaverRunning.get()) { // System.out.println("AJC: avoiding re-entrant call to transform " + name); return bytes; } try { weaverRunning.set(true); if (trace.isTraceEnabled()) { trace.enter("weaveClass", this, new Object[] { name, bytes }); } if (!enabled) { if (trace.isTraceEnabled()) { trace.exit("weaveClass", false); } return bytes; } boolean debugOn = !messageHandler.isIgnoring(Message.DEBUG); try { delegateForCurrentClass = null; name = name.replace('/', '.'); if (couldWeave(name, bytes)) { if (accept(name, bytes)) { // Determine if we have the weaved class cached CachedClassReference cacheKey = null; final byte[] original_bytes = bytes; if (cache != null && !mustWeave) { cacheKey = cache.createCacheKey(name, original_bytes); CachedClassEntry entry = cache.get(cacheKey, original_bytes); if (entry != null) { // If the entry has been explicitly ignored // return the original bytes if (entry.isIgnored()) { return bytes; } return entry.getBytes(); } } // TODO @AspectJ problem // Annotation style aspects need to be included regardless in order to get // a valid aspectOf()/hasAspect() generated in them. However - if they are excluded // (via include/exclude in aop.xml) they really should only get aspectOf()/hasAspect() // and not be included in the full set of aspects being applied by 'this' weaver if (debugOn) { debug("weaving '" + name + "'"); } bytes = getWovenBytes(name, bytes); // temporarily out - searching for @Aspect annotated types is a slow thing to do - we should // expect the user to name them if they want them woven - just like code style // } else if (shouldWeaveAnnotationStyleAspect(name, bytes)) { // if (mustWeave) { // if (bcelWorld.getLint().mustWeaveXmlDefinedAspects.isEnabled()) { // bcelWorld.getLint().mustWeaveXmlDefinedAspects.signal(name, null); // } // } // // an @AspectJ aspect needs to be at least munged by the aspectOf munger // if (debugOn) { // debug("weaving '" + name + "'"); // } // bytes = getAtAspectJAspectBytes(name, bytes); // Add the weaved class to the cache only if there // has been an actual change // JVK: Is there a better way to check if the class has // been transformed without carrying up some value // from the depths? if (cacheKey != null) { // If no transform has been applied, mark the class // as ignored. if (Arrays.equals(original_bytes, bytes)) { cache.ignore(cacheKey, original_bytes); } else { cache.put(cacheKey, original_bytes, bytes); } } } else if (debugOn) { debug("not weaving '" + name + "'"); } } else if (debugOn) { debug("cannot weave '" + name + "'"); } } finally { delegateForCurrentClass = null; } if (trace.isTraceEnabled()) { trace.exit("weaveClass", bytes); } return bytes; } finally { weaverRunning.remove(); } }
Params:
  • name –
Returns:true if even valid to weave: either with an accept check or to munge it for @AspectJ aspectof support
/** * @param name * @return true if even valid to weave: either with an accept check or to munge it for @AspectJ aspectof support */
private boolean couldWeave(String name, byte[] bytes) { return !generatedClasses.containsKey(name) && shouldWeaveName(name); } // ATAJ protected boolean accept(String name, byte[] bytes) { return true; } protected boolean shouldDump(String name, boolean before) { return false; } private boolean shouldWeaveName(String name) { if (PACKAGE_INITIAL_CHARS.indexOf(name.charAt(0)) != -1) { if ((weavingSpecialTypes & INITIALIZED) == 0) { weavingSpecialTypes |= INITIALIZED; // initialize it Properties p = weaver.getWorld().getExtraConfiguration(); if (p != null) { boolean b = p.getProperty(World.xsetWEAVE_JAVA_PACKAGES, "false").equalsIgnoreCase("true"); if (b) { weavingSpecialTypes |= WEAVE_JAVA_PACKAGE; } b = p.getProperty(World.xsetWEAVE_JAVAX_PACKAGES, "false").equalsIgnoreCase("true"); if (b) { weavingSpecialTypes |= WEAVE_JAVAX_PACKAGE; } } } if (name.startsWith(ASPECTJ_BASE_PACKAGE)) { return false; } if (name.startsWith("sun.reflect.")) {// JDK reflect return false; } if (name.startsWith("javax.")) { if ((weavingSpecialTypes & WEAVE_JAVAX_PACKAGE) != 0) { return true; } else { if (!haveWarnedOnJavax) { haveWarnedOnJavax = true; warn("javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified"); } return false; } } if (name.startsWith("java.")) { if ((weavingSpecialTypes & WEAVE_JAVA_PACKAGE) != 0) { return true; } else { return false; } } } // boolean should = !(name.startsWith("org.aspectj.") // || (name.startsWith("java.") && (weavingSpecialTypes & WEAVE_JAVA_PACKAGE) == 0) // || (name.startsWith("javax.") && (weavingSpecialTypes & WEAVE_JAVAX_PACKAGE) == 0) // // || name.startsWith("$Proxy")//JDK proxies//FIXME AV is that 1.3 proxy ? fe. ataspect.$Proxy0 is a java5 proxy... // || name.startsWith("sun.reflect.")); return true; }
We allow @AJ aspect weaving so that we can add aspectOf() as part of the weaving (and not part of the source compilation)
Params:
  • name –
  • bytes – bytecode (from classloader), allow to NOT lookup stuff on disk again during resolve
Returns:true if @Aspect
/** * We allow @AJ aspect weaving so that we can add aspectOf() as part of the weaving (and not part of the source compilation) * * @param name * @param bytes bytecode (from classloader), allow to NOT lookup stuff on disk again during resolve * @return true if @Aspect */
private boolean shouldWeaveAnnotationStyleAspect(String name, byte[] bytes) { if (delegateForCurrentClass == null) { // if (weaver.getWorld().isASMAround()) return asmCheckAnnotationStyleAspect(bytes); // else ensureDelegateInitialized(name, bytes); } return (delegateForCurrentClass.isAnnotationStyleAspect()); } // private boolean asmCheckAnnotationStyleAspect(byte[] bytes) { // IsAtAspectAnnotationVisitor detector = new IsAtAspectAnnotationVisitor(); // // ClassReader cr = new ClassReader(bytes); // try { // cr.accept(detector, true);//, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); // } catch (Exception spe) { // // if anything goes wrong, e.g., an NPE, then assume it's NOT an @AspectJ aspect... // System.err.println("Unexpected problem parsing bytes to discover @Aspect annotation"); // spe.printStackTrace(); // return false; // } // // return detector.isAspect(); // } protected void ensureDelegateInitialized(String name, byte[] bytes) { if (delegateForCurrentClass == null) { BcelWorld world = (BcelWorld) weaver.getWorld(); delegateForCurrentClass = world.addSourceObjectType(name, bytes, false); } }
Weave a set of bytes defining a class.
Params:
  • name – the name of the class being woven
  • bytes – the bytes that define the class
Throws:
Returns:byte[] the woven bytes for the class
/** * Weave a set of bytes defining a class. * * @param name the name of the class being woven * @param bytes the bytes that define the class * @return byte[] the woven bytes for the class * @throws IOException */
private byte[] getWovenBytes(String name, byte[] bytes) throws IOException { WeavingClassFileProvider wcp = new WeavingClassFileProvider(name, bytes); weaver.weave(wcp); return wcp.getBytes(); }
Weave a set of bytes defining a class for only what is needed to turn @AspectJ aspect in a usefull form ie with aspectOf method - see #113587
Params:
  • name – the name of the class being woven
  • bytes – the bytes that define the class
Throws:
Returns:byte[] the woven bytes for the class
/** * Weave a set of bytes defining a class for only what is needed to turn @AspectJ aspect in a usefull form ie with aspectOf * method - see #113587 * * @param name the name of the class being woven * @param bytes the bytes that define the class * @return byte[] the woven bytes for the class * @throws IOException */
private byte[] getAtAspectJAspectBytes(String name, byte[] bytes) throws IOException { WeavingClassFileProvider wcp = new WeavingClassFileProvider(name, bytes); wcp.setApplyAtAspectJMungersOnly(); weaver.weave(wcp); return wcp.getBytes(); } private void registerAspectLibraries(List aspectPath) { // System.err.println("? WeavingAdaptor.registerAspectLibraries(" + aspectPath + ")"); for (Iterator i = aspectPath.iterator(); i.hasNext();) { String libName = (String) i.next(); addAspectLibrary(libName); } weaver.prepareForWeave(); } /* * Register an aspect library with this classloader for use during weaving. This class loader will also return (unmodified) any * of the classes in the library in response to a <code>findClass()</code> request. The library is not required to be on the * weavingClasspath given when this classloader was constructed. * * @param aspectLibraryJarFile a jar file representing an aspect library * * @throws IOException */ private void addAspectLibrary(String aspectLibraryName) { File aspectLibrary = new File(aspectLibraryName); if (aspectLibrary.isDirectory() || (FileUtil.isZipFile(aspectLibrary))) { try { info("adding aspect library: '" + aspectLibrary + "'"); weaver.addLibraryJarFile(aspectLibrary); } catch (IOException ex) { error("exception adding aspect library: '" + ex + "'"); } } else { error("bad aspect library: '" + aspectLibrary + "'"); } } private static List<String> makeClasspath(String cp) { List<String> ret = new ArrayList<String>(); if (cp != null) { StringTokenizer tok = new StringTokenizer(cp, File.pathSeparator); while (tok.hasMoreTokens()) { ret.add(tok.nextToken()); } } return ret; } protected boolean debug(String message) { return MessageUtil.debug(messageHandler, message); } protected boolean info(String message) { return MessageUtil.info(messageHandler, message); } protected boolean warn(String message) { return MessageUtil.warn(messageHandler, message); } protected boolean warn(String message, Throwable th) { return messageHandler.handleMessage(new Message(message, IMessage.WARNING, th, null)); } protected boolean error(String message) { return MessageUtil.error(messageHandler, message); } protected boolean error(String message, Throwable th) { return messageHandler.handleMessage(new Message(message, IMessage.ERROR, th, null)); } public String getContextId() { return "WeavingAdaptor"; }
Dump the given bytcode in _dump/... (dev mode)
Params:
  • name –
  • b –
  • before – whether we are dumping before weaving
Throws:
/** * Dump the given bytcode in _dump/... (dev mode) * * @param name * @param b * @param before whether we are dumping before weaving * @throws Throwable */
protected void dump(String name, byte[] b, boolean before) { String dirName = getDumpDir(); if (before) { dirName = dirName + File.separator + "_before"; } String className = name.replace('.', '/'); final File dir; if (className.indexOf('/') > 0) { dir = new File(dirName + File.separator + className.substring(0, className.lastIndexOf('/'))); } else { dir = new File(dirName); } dir.mkdirs(); String fileName = dirName + File.separator + className + ".class"; try { // System.out.println("WeavingAdaptor.dump() fileName=" + new File(fileName).getAbsolutePath()); FileOutputStream os = new FileOutputStream(fileName); os.write(b); os.close(); } catch (IOException ex) { warn("unable to dump class " + name + " in directory " + dirName, ex); } }
Returns:the directory in which to dump - default is _ajdump but it
/** * @return the directory in which to dump - default is _ajdump but it */
protected String getDumpDir() { return "_ajdump"; }
Processes messages arising from weaver operations. Tell weaver to abort on any message more severe than warning.
/** * Processes messages arising from weaver operations. Tell weaver to abort on any message more severe than warning. */
protected class WeavingAdaptorMessageHolder extends MessageHandler { private IMessageHandler delegate; private List<IMessage> savedMessages; protected boolean traceMessages = Boolean.getBoolean(TRACE_MESSAGES_PROPERTY); public WeavingAdaptorMessageHolder(PrintWriter writer) { this.delegate = new WeavingAdaptorMessageWriter(writer); super.dontIgnore(IMessage.WEAVEINFO); } private void traceMessage(IMessage message) { if (message instanceof WeaveMessage) { trace.debug(render(message)); } else if (message.isDebug()) { trace.debug(render(message)); } else if (message.isInfo()) { trace.info(render(message)); } else if (message.isWarning()) { trace.warn(render(message), message.getThrown()); } else if (message.isError()) { trace.error(render(message), message.getThrown()); } else if (message.isFailed()) { trace.fatal(render(message), message.getThrown()); } else if (message.isAbort()) { trace.fatal(render(message), message.getThrown()); } else { trace.error(render(message), message.getThrown()); } } protected String render(IMessage message) { return "[" + getContextId() + "] " + message.toString(); } public void flushMessages() { if (savedMessages == null) { savedMessages = new ArrayList<IMessage>(); savedMessages.addAll(super.getUnmodifiableListView()); clearMessages(); for (IMessage message : savedMessages) { delegate.handleMessage(message); } } // accumulating = false; // messages.clear(); } public void setDelegate(IMessageHandler messageHandler) { delegate = messageHandler; } /* * IMessageHandler */ @Override public boolean handleMessage(IMessage message) throws AbortException { if (traceMessages) { traceMessage(message); } super.handleMessage(message); if (abortOnError && 0 <= message.getKind().compareTo(IMessage.ERROR)) { throw new AbortException(message); } // if (accumulating) { // boolean result = addMessage(message); // if (abortOnError && 0 <= message.getKind().compareTo(IMessage.ERROR)) { // throw new AbortException(message); // } // return result; // } // else return delegate.handleMessage(message); if (savedMessages != null) { delegate.handleMessage(message); } return true; } @Override public boolean isIgnoring(Kind kind) { return delegate.isIgnoring(kind); } @Override public void dontIgnore(IMessage.Kind kind) { if (null != kind && delegate != null) { delegate.dontIgnore(kind); } } @Override public void ignore(Kind kind) { if (null != kind && delegate != null) { delegate.ignore(kind); } } /* * IMessageHolder */ @Override public List<IMessage> getUnmodifiableListView() { // System.err.println("? WeavingAdaptorMessageHolder.getUnmodifiableListView() savedMessages=" + savedMessages); List<IMessage> allMessages = new ArrayList<IMessage>(); allMessages.addAll(savedMessages); allMessages.addAll(super.getUnmodifiableListView()); return allMessages; } } protected class WeavingAdaptorMessageWriter extends MessageWriter { private final Set<IMessage.Kind> ignoring = new HashSet<IMessage.Kind>(); private final IMessage.Kind failKind; public WeavingAdaptorMessageWriter(PrintWriter writer) { super(writer, true); ignore(IMessage.WEAVEINFO); ignore(IMessage.DEBUG); ignore(IMessage.INFO); this.failKind = IMessage.ERROR; } @Override public boolean handleMessage(IMessage message) throws AbortException { // boolean result = super.handleMessage(message); if (abortOnError && 0 <= message.getKind().compareTo(failKind)) { throw new AbortException(message); } return true; } @Override public boolean isIgnoring(Kind kind) { return ((null != kind) && (ignoring.contains(kind))); }
Set a message kind to be ignored from now on
/** * Set a message kind to be ignored from now on */
@Override public void ignore(IMessage.Kind kind) { if ((null != kind) && (!ignoring.contains(kind))) { ignoring.add(kind); } }
Remove a message kind from the list of those ignored from now on.
/** * Remove a message kind from the list of those ignored from now on. */
@Override public void dontIgnore(IMessage.Kind kind) { if (null != kind) { ignoring.remove(kind); } } @Override protected String render(IMessage message) { return "[" + getContextId() + "] " + super.render(message); } } private class WeavingClassFileProvider implements IClassFileProvider { private final UnwovenClassFile unwovenClass; private final List<UnwovenClassFile> unwovenClasses = new ArrayList<UnwovenClassFile>(); private IUnwovenClassFile wovenClass; private boolean isApplyAtAspectJMungersOnly = false; public WeavingClassFileProvider(String name, byte[] bytes) { ensureDelegateInitialized(name, bytes); this.unwovenClass = new UnwovenClassFile(name, delegateForCurrentClass.getResolvedTypeX().getName(), bytes); this.unwovenClasses.add(unwovenClass); if (shouldDump(name.replace('/', '.'), true)) { dump(name, bytes, true); } } public void setApplyAtAspectJMungersOnly() { isApplyAtAspectJMungersOnly = true; } public boolean isApplyAtAspectJMungersOnly() { return isApplyAtAspectJMungersOnly; } public byte[] getBytes() { if (wovenClass != null) { return wovenClass.getBytes(); } else { return unwovenClass.getBytes(); } } public Iterator<UnwovenClassFile> getClassFileIterator() { return unwovenClasses.iterator(); } public IWeaveRequestor getRequestor() { return new IWeaveRequestor() { public void acceptResult(IUnwovenClassFile result) { if (wovenClass == null) { wovenClass = result; String name = result.getClassName(); if (shouldDump(name.replace('/', '.'), false)) { dump(name, result.getBytes(), false); } } else { // Classes generated by weaver e.g. around closure advice String className = result.getClassName(); byte[] resultBytes = result.getBytes(); if (SimpleCacheFactory.isEnabled()) { SimpleCache lacache=SimpleCacheFactory.createSimpleCache(); lacache.put(result.getClassName(), wovenClass.getBytes(), result.getBytes()); lacache.addGeneratedClassesNames(wovenClass.getClassName(), wovenClass.getBytes(), result.getClassName()); } generatedClasses.put(className, result); generatedClasses.put(wovenClass.getClassName(), result); generatedClassHandler.acceptClass(className, null, resultBytes); } } public void processingReweavableState() { } public void addingTypeMungers() { } public void weavingAspects() { } public void weavingClasses() { } public void weaveCompleted() { // ResolvedType.resetPrimitives(); if (delegateForCurrentClass != null) { delegateForCurrentClass.weavingCompleted(); } // ResolvedType.resetPrimitives(); // bcelWorld.discardType(typeBeingProcessed.getResolvedTypeX()); // work in progress } }; } } public void setActiveProtectionDomain(ProtectionDomain protectionDomain) { activeProtectionDomain = protectionDomain; } }