All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.weaver.tools.WeavingAdaptor Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * 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 v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * 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. * */ public class WeavingAdaptor implements IMessageContext { /** * 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 generatedClasses = new HashMap<>(); 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. * * @param loader instance of ClassLoader */ public WeavingAdaptor(WeavingClassLoader loader) { // System.err.println("? WeavingAdaptor.(" + 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. * * @param handler GeneratedClassHandler * @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.()"); generatedClassHandler = handler; init(null, FileUtil.makeClasspath(classURLs), FileUtil.makeClasspath(aspectURLs)); } protected List getFullClassPath(ClassLoader loader) { List list = new LinkedList<>(); 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.isVMGreaterOrEqual(9)) { list.add(0, LangUtil.getJrtFsFilePath()); List 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 getFullAspectPath(ClassLoader loader) { List list = new LinkedList<>(); 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 * @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 classPath, List aspectPath) { abortOnError = true; createMessageHandler(); info("using classpath: " + classPath); info("using aspectpath: " + aspectPath); bcelWorld = new BcelWorld(classPath, messageHandler, null); bcelWorld.setXnoInline(false); bcelWorld.getLint().loadDefaultProperties(); 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 - * * @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 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 * * @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. * * @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 weaverRunning = new ThreadLocal() { @Override protected Boolean initialValue() { return Boolean.FALSE; } }; /** * Weave a class using aspects previously supplied to the adaptor. * * @param name the name of the class in the internal form of fully qualified class and interface names as defined * in The Java Virtual Machine Specification. For example, "java/util/List". * @param bytes the input byte buffer in class file format - must not be modified * @param mustWeave if true then this class must get woven (used for concrete aspects generated from XML) * * @return a well-formed class file buffer (the weaving result), or {@code null} if no weaving was performed * * @throws IOException weave failed * * @see java.lang.instrument.ClassFileTransformer#transform(ClassLoader, String, Class, ProtectionDomain, byte[]) */ public byte[] weaveClass(String name, final 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 null; } if (weaverRunning.get()) { // System.out.println("AJC: avoiding re-entrant call to transform " + name); return null; } try { byte[] newBytes = null; weaverRunning.set(true); if (trace.isTraceEnabled()) { trace.enter("weaveClass", this, new Object[] { name, bytes }); } if (!enabled) { if (trace.isTraceEnabled()) { trace.exit("weaveClass", false); } return null; } boolean debugOn = !messageHandler.isIgnoring(Message.DEBUG); name = name.replace('/', '.'); byte[] wovenBytes = wovenWithGeneratedClass(name); if (wovenBytes != null) { if (debugOn) { debug("returning woven bytes for '" + name + "' that were generated by a previous weaving process"); } return wovenBytes; } try { delegateForCurrentClass = null; if (shouldWeaveName(name)) { if (accept(name, bytes)) { // Determine if we have the weaved class cached CachedClassReference cacheKey = null; if (cache != null && !mustWeave) { cacheKey = cache.createCacheKey(name, bytes); CachedClassEntry entry = cache.get(cacheKey, bytes); if (entry != null) { // If the entry has been explicitly ignored // return the original bytes if (entry.isIgnored()) { return null; } 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 + "'"); } newBytes = getWovenBytes(name, bytes); // TODO: Is this OK performance-wise? if (Arrays.equals(bytes, newBytes)) { // null means unchanged in java.lang.instrument.ClassFileTransformer::transform newBytes = null; } // 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 (newBytes == null) { cache.ignore(cacheKey, bytes); } else { cache.put(cacheKey, bytes, newBytes); } } } else if (debugOn) { debug("not weaving '" + name + "'"); } } else if (debugOn) { debug("cannot weave '" + name + "'"); } } finally { delegateForCurrentClass = null; } if (trace.isTraceEnabled()) { trace.exit("weaveClass", newBytes); } return newBytes; } finally { weaverRunning.remove(); } } /** * Return the bytes from a (parallel?) weaving process that generated an inner class, e.g. to support Around closures. * This is done instead of weaving again, as weaving would generate another inner class. * @param name * @return the cached bytes of a previously woven class, or null if not found */ private byte[] wovenWithGeneratedClass(String name) { IUnwovenClassFile woven = generatedClasses.get(name); if (woven == null) { return null; } return woven.getBytes(); } // 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) * * @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. * * @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 * * @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 (String libName : aspectPath) { 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 findClass() 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 makeClasspath(String cp) { List ret = new ArrayList<>(); 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) * * @param name * @param b * @param before whether we are dumping before weaving */ 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); } } /** * @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. */ protected class WeavingAdaptorMessageHolder extends MessageHandler { private IMessageHandler delegate; private List 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<>(); 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 getUnmodifiableListView() { // System.err.println("? WeavingAdaptorMessageHolder.getUnmodifiableListView() savedMessages=" + savedMessages); List allMessages = new ArrayList<>(); allMessages.addAll(savedMessages); allMessages.addAll(super.getUnmodifiableListView()); return allMessages; } } protected class WeavingAdaptorMessageWriter extends MessageWriter { private final Set ignoring = new HashSet<>(); 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 */ @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. */ @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 unwovenClasses = new ArrayList<>(); 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 getClassFileIterator() { return unwovenClasses.iterator(); } public IWeaveRequestor getRequestor() { return new WeaveRequestor(); } private class WeaveRequestor implements IWeaveRequestor { @Override 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(wovenClass.getClassName(), wovenClass); 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy