123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /* *******************************************************************
- * 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,
- * 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.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.Message;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.bridge.MessageWriter;
- import org.aspectj.bridge.Version;
- 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.ResolvedType;
- import org.aspectj.weaver.bcel.BcelObjectType;
- 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;
- protected BcelWeaver weaver;
- private IMessageHandler messageHandler;
- private WeavingAdaptorMessageHandler messageHolder;
- protected GeneratedClassHandler generatedClassHandler;
- protected Map generatedClasses = new HashMap(); /* String -> UnwovenClassFile */
-
- 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 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);
- }
-
- protected void createMessageHandler() {
- messageHolder = new WeavingAdaptorMessageHandler(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.text + " built on " + Version.time_text); //$NON-NLS-1$
- }
-
- protected IMessageHandler getMessageHandler () {
- return messageHandler;
- }
-
- protected void setMessageHandler (IMessageHandler mh) {
- if (messageHolder != null) {
- messageHolder.flushMessages();
- messageHolder = null;
- }
- messageHandler = mh;
- bcelWorld.setMessageHandler(mh);
- }
-
- /**
- * 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 (enabled) {
- if (trace.isTraceEnabled()) trace.enter("weaveClass",this,new Object[] {name,bytes});
-
- if (shouldWeave(name, bytes)) {
- 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);
- }
- else {
- info("not weaving '" + name + "'");
- }
-
- if (trace.isTraceEnabled()) trace.exit("weaveClass",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 = !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;
- }
-
- protected boolean shouldDump(String name, boolean before) {
- return false;
- }
-
- private boolean shouldWeaveName (String name) {
- boolean should =
- !((/*(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
- return should;
- }
-
- /**
- * 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()
- || (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 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 String getContextId () {
- return "WeavingAdaptor";
- }
-
- /**
- * 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 = "_ajdump";
- 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);
- }
- }
-
- /**
- * 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;
- private boolean accumulating = true;
- private List messages = new ArrayList();
-
- public WeavingAdaptorMessageHandler (PrintWriter writer) {
- super(writer,true);
-
- ignore(IMessage.WEAVEINFO);
- ignore(IMessage.INFO);
- this.failKind = IMessage.ERROR;
- }
-
- public boolean handleMessage(IMessage message) throws AbortException {
- addMessage(message);
- 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);
- if (kind.equals(IMessage.INFO)) accumulating = false;
- }
- }
-
- private void addMessage (IMessage message) {
- if (accumulating && isIgnoring(message.getKind())) {
- messages.add(message);
- }
- }
-
- public void flushMessages () {
- for (Iterator iter = messages.iterator(); iter.hasNext();) {
- IMessage message = (IMessage)iter.next();
- super.handleMessage(message);
- }
- accumulating = false;
- messages.clear();
- }
-
- protected String render(IMessage message) {
- return "[" + getContextId() + "] " + super.render(message);
- }
- }
-
- private class WeavingClassFileProvider implements IClassFileProvider {
-
- private UnwovenClassFile unwovenClass;
- private List unwovenClasses = new ArrayList(); /* List<UnovenClassFile> */
- private UnwovenClassFile wovenClass;
- private boolean isApplyAtAspectJMungersOnly = false;
- private BcelObjectType delegate;
-
- public WeavingClassFileProvider (String name, byte[] bytes) {
- this.unwovenClass = new UnwovenClassFile(name,bytes);
- this.unwovenClasses.add(unwovenClass);
-
- if (shouldDump(name.replace('/', '.'),true)) {
- dump(name, bytes, true);
- }
-
- delegate = bcelWorld.addSourceObjectType(unwovenClass.getJavaClass());
- }
-
- 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 IWeaveRequestor() {
-
- public void acceptResult(UnwovenClassFile result) {
- if (wovenClass == null) {
- wovenClass = result;
-
- String name = result.getClassName();
- if (shouldDump(name.replace('/', '.'), false)) {
- dump(name, result.getBytes(), false);
- }
- }
-
- /* Classes generated by weaver e.g. around closure advice */
- else {
- String className = result.getClassName();
- generatedClasses.put(className,result);
- generatedClasses.put(wovenClass.getClassName(),result);
- generatedClassHandler.acceptClass(className,result.getBytes());
- }
- }
-
- public void processingReweavableState() { }
-
- public void addingTypeMungers() {}
-
- public void weavingAspects() {}
-
- public void weavingClasses() {}
-
- public void weaveCompleted() {
- if (delegate!=null) delegate.weavingCompleted();
- ResolvedType.resetPrimitives();
- }
- };
- }
- }
- }
|