123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /* *******************************************************************
- * Copyright (c) 2004 IBM Corporation
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Common Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * Matthew Webster, Adrian Colyer,
- * Martin Lippert initial implementation
- * ******************************************************************/
-
- package org.aspectj.weaver.tools;
-
- import java.io.File;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.ArrayList;
- 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.Set;
- import java.util.StringTokenizer;
-
- import org.aspectj.bridge.AbortException;
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHandler;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.bridge.MessageWriter;
- import org.aspectj.bridge.IMessage.Kind;
- import org.aspectj.util.FileUtil;
- import org.aspectj.util.LangUtil;
- import org.aspectj.weaver.IClassFileProvider;
- import org.aspectj.weaver.IWeaveRequestor;
- import org.aspectj.weaver.bcel.BcelWeaver;
- import org.aspectj.weaver.bcel.BcelWorld;
- import org.aspectj.weaver.bcel.UnwovenClassFile;
-
- /**
- * 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 {
-
- /**
- * 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";
-
- protected boolean enabled = true;
- protected boolean verbose = getVerbose();
- protected BcelWorld bcelWorld = null;
- protected BcelWeaver weaver = null;
- protected IMessageHandler/*WeavingAdaptorMessageHandler*/ messageHandler = null;
- protected GeneratedClassHandler generatedClassHandler;
- protected Map generatedClasses = new HashMap(); /* String -> UnwovenClassFile */
-
- protected WeavingAdaptor () {
- createMessageHandler();
- }
-
-
- /**
- * 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 ofr weaving.
- * @param loader instance of <code>ClassLoader</code>
- */
- public WeavingAdaptor (WeavingClassLoader loader) {
- // System.err.println("? WeavingAdaptor.<init>(" + loader +"," + aspectURLs.length + ")");
- generatedClassHandler = loader;
- init(getFullClassPath((ClassLoader)loader),getFullAspectPath((ClassLoader)loader/*,aspectURLs*/));
- }
-
- /**
- * Construct a WeavingAdator 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(FileUtil.makeClasspath(classURLs),FileUtil.makeClasspath(aspectURLs));
- }
-
- private 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");
- }
- }
-
- 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 () {
- return Boolean.getBoolean(WEAVING_ADAPTOR_VERBOSE);
- }
-
- private void init(List classPath, List aspectPath) {
- 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);
- }
-
-
- private void createMessageHandler() {
- messageHandler = new WeavingAdaptorMessageHandler(new PrintWriter(System.err));
- if (verbose) messageHandler.dontIgnore(IMessage.INFO);
- if (Boolean.getBoolean(SHOW_WEAVE_INFO_PROPERTY)) messageHandler.dontIgnore(IMessage.WEAVEINFO);
- }
-
- /**
- * 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 {
- if (shouldWeave(name, bytes)) {
- //System.out.println("WeavingAdaptor.weaveClass " + name);
- info("weaving '" + name + "'");
- bytes = getWovenBytes(name, bytes);
- } else if (shouldWeaveAnnotationStyleAspect(name, bytes)) {
- // an @AspectJ aspect needs to be at least munged by the aspectOf munger
- info("weaving '" + name + "'");
- bytes = getAtAspectJAspectBytes(name, bytes);
- }
-
- return bytes;
- }
-
- /**
- * @param name
- * @return true if should weave (but maybe we still need to munge it for @AspectJ aspectof support)
- */
- private boolean shouldWeave (String name, byte[] bytes) {
- name = name.replace('/','.');
- boolean b = enabled && !generatedClasses.containsKey(name) && shouldWeaveName(name);
- return b && accept(name, bytes);
- // && shouldWeaveAnnotationStyleAspect(name);
- // // we recall shouldWeaveAnnotationStyleAspect as we need to add aspectOf methods for @Aspect anyway
- // //FIXME AV - this is half ok as the aspect will be weaved by others. In theory if the aspect
- // // is excluded from include/exclude config we should only weave late type mungers for aspectof
- // return b && (accept(name) || shouldWeaveAnnotationStyleAspect(name));
- }
-
- //ATAJ
- protected boolean accept(String name, byte[] bytes) {
- return true;
- }
-
- public boolean shouldDump(String name) {
- return false;
- }
-
- private boolean shouldWeaveName (String name) {
- return !((/*(name.startsWith("org.apache.bcel.")//FIXME AV why ? bcel is wrapped in org.aspectj.
- ||*/ name.startsWith("org.aspectj.")
- || name.startsWith("java.")
- || name.startsWith("javax."))
- //|| name.startsWith("$Proxy")//JDK proxies//FIXME AV is that 1.3 proxy ? fe. ataspect.$Proxy0 is a java5 proxy...
- || name.startsWith("sun.reflect."));//JDK reflect
- }
-
- /**
- * 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) {
- // AV: instead of doing resolve that would lookup stuff on disk thru BCEL ClassLoaderRepository
- // we reuse bytes[] here to do a fast lookup for @Aspect annotation
- return bcelWorld.isAnnotationStyleAspect(name, bytes);
- }
-
- /**
- * 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 (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()
- || (aspectLibrary.isFile()
- && FileUtil.hasZipSuffix(aspectLibraryName))) {
- 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 info (String message) {
- return MessageUtil.info(messageHandler,message);
- }
-
- protected boolean warn (String message) {
- return MessageUtil.warn(messageHandler,message);
- }
-
- protected boolean error (String message) {
- return MessageUtil.error(messageHandler,message);
- }
-
- /**
- * Processes messages arising from weaver operations.
- * Tell weaver to abort on any message more severe than warning.
- */
- protected class WeavingAdaptorMessageHandler extends MessageWriter {
-
- private Set ignoring = new HashSet();
- private IMessage.Kind failKind;
-
- public WeavingAdaptorMessageHandler (PrintWriter writer) {
- super(writer,true);
-
- ignore(IMessage.WEAVEINFO);
- ignore(IMessage.INFO);
- this.failKind = IMessage.ERROR;
-
- }
-
- public boolean handleMessage(IMessage message) throws AbortException {
- boolean result = super.handleMessage(message);
- if (0 <= message.getKind().compareTo(failKind)) {
- throw new AbortException(message);
- }
- return true;
- }
-
- public boolean isIgnoring (Kind kind) {
- return ((null != kind) && (ignoring.contains(kind)));
- }
-
- /**
- * Set a message kind to be ignored from now on
- */
- 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.
- */
- public void dontIgnore (IMessage.Kind kind) {
- if (null != kind) {
- ignoring.remove(kind);
- }
- }
- }
-
- private class WeavingClassFileProvider implements IClassFileProvider {
-
- private List unwovenClasses = new ArrayList(); /* List<UnovenClassFile> */
- private UnwovenClassFile wovenClass;
- private boolean isApplyAtAspectJMungersOnly = false;
-
- public WeavingClassFileProvider (String name, byte[] bytes) {
- UnwovenClassFile unwoven = new UnwovenClassFile(name,bytes);
- unwovenClasses.add(unwoven);
- bcelWorld.addSourceObjectType(unwoven.getJavaClass());
- }
-
- public void setApplyAtAspectJMungersOnly() {
- isApplyAtAspectJMungersOnly = true;
- }
-
- public boolean isApplyAtAspectJMungersOnly() {
- return isApplyAtAspectJMungersOnly;
- }
-
- public byte[] getBytes () {
- return wovenClass.getBytes();
- }
-
- public Iterator getClassFileIterator() {
- return unwovenClasses.iterator();
- }
-
- public IWeaveRequestor getRequestor() {
- return new IWeaveRequestor() {
-
- public void acceptResult(UnwovenClassFile result) {
- if (wovenClass == null) {
- wovenClass = result;
- }
-
- /* Classes generated by weaver e.g. around closure advice */
- else {
- String className = result.getClassName();
- generatedClasses.put(className,result);
- generatedClassHandler.acceptClass(className,result.getBytes());
- }
- }
-
- public void processingReweavableState() { }
-
- public void addingTypeMungers() {}
-
- public void weavingAspects() {}
-
- public void weavingClasses() {}
-
- public void weaveCompleted() {}
- };
- }
- }
- }
|