diff options
author | acolyer <acolyer> | 2004-04-02 12:03:40 +0000 |
---|---|---|
committer | acolyer <acolyer> | 2004-04-02 12:03:40 +0000 |
commit | 33d8ee9eededcd1219a6cbd1d063af005d40a3f7 (patch) | |
tree | d30f882cbab26f54b62dc1cddfab666d97d6bd3d /weaver/src | |
parent | fc1c15110e8a9cfafabad0dcc4c10445725c9fb2 (diff) | |
download | aspectj-33d8ee9eededcd1219a6cbd1d063af005d40a3f7.tar.gz aspectj-33d8ee9eededcd1219a6cbd1d063af005d40a3f7.zip |
fix for Bugzilla Bug 31460
Weaving class loader
Diffstat (limited to 'weaver/src')
6 files changed, 609 insertions, 0 deletions
diff --git a/weaver/src/org/aspectj/weaver/ExtensibleURLClassLoader.java b/weaver/src/org/aspectj/weaver/ExtensibleURLClassLoader.java new file mode 100644 index 000000000..1117c6b96 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ExtensibleURLClassLoader.java @@ -0,0 +1,87 @@ +/* ******************************************************************* + * 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; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.CodeSource; + +import org.aspectj.util.FileUtil; +import org.aspectj.weaver.bcel.ClassPathManager; +import org.aspectj.weaver.tools.*; + +public abstract class ExtensibleURLClassLoader extends URLClassLoader { + + private ClassPathManager classPath; + + public ExtensibleURLClassLoader (URL[] urls, ClassLoader parent) { + super(urls,parent); + +// System.err.println("? ExtensibleURLClassLoader.<init>() path=" + WeavingAdaptor.makeClasspath(urls)); + classPath = new ClassPathManager(FileUtil.makeClasspath(urls),null); + } + + protected void addURL(URL url) { + classPath.addPath(url.getPath(),null); + } + + protected Class findClass(String name) throws ClassNotFoundException { +// System.err.println("? ExtensibleURLClassLoader.findClass(" + name + ")"); + try { + byte[] bytes = getBytes(name); + if (bytes != null) { + return defineClass(name,bytes); + } + else { + throw new ClassNotFoundException(name); + } + } + catch (IOException ex) { + throw new ClassNotFoundException(name); + } + } + + protected Class defineClass(String name, byte[] b, CodeSource cs) throws IOException { +// System.err.println("? ExtensibleURLClassLoader.defineClass(" + name + ",[" + b.length + "])"); + return defineClass(name, b, 0, b.length, cs); + } + + protected byte[] getBytes (String name) throws IOException { + byte[] b = null; + ClassPathManager.ClassFile classFile = classPath.find(TypeX.forName(name)); + if (classFile != null) { + b = FileUtil.readAsByteArray(classFile.getInputStream()); + } + return b; + } + + private Class defineClass(String name, byte[] bytes /*ClassPathManager.ClassFile classFile*/) throws IOException { + String packageName = getPackageName(name); + if (packageName != null) { + Package pakkage = getPackage(packageName); + if (pakkage == null) { + definePackage(packageName,null,null,null,null,null,null,null); + } + } + + return defineClass(name, bytes, null); + } + + private String getPackageName (String className) { + int offset = className.lastIndexOf('.'); + return (offset == -1)? null : className.substring(0,offset); + } + +} diff --git a/weaver/src/org/aspectj/weaver/WeavingURLClassLoader.java b/weaver/src/org/aspectj/weaver/WeavingURLClassLoader.java new file mode 100644 index 000000000..c01f18812 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/WeavingURLClassLoader.java @@ -0,0 +1,123 @@ +/* ******************************************************************* + * 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; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.aspectj.util.UtilClassLoader; +import org.aspectj.weaver.tools.*; + +public class WeavingURLClassLoader extends ExtensibleURLClassLoader implements WeavingClassLoader { + + public static final String WEAVING_CLASS_PATH = "aj.class.path"; + public static final String WEAVING_ASPECT_PATH = "aj.aspect.path"; + + private URL[] aspectURLs; + private WeavingAdaptor adaptor; + private Map generatedClasses = new HashMap(); /* String -> byte[] */ + + /* + * This constructor is needed when using "-Djava.system.class.loader". + */ + public WeavingURLClassLoader (ClassLoader parent) { + this(getURLs(getClassPath()),getURLs(getAspectPath()),parent); +// System.err.println("? WeavingURLClassLoader.<init>(" + parent + ")"); + } + + public WeavingURLClassLoader (URL[] classURLs, URL[] aspectURLs, ClassLoader parent) { + super(classURLs,parent); +// System.err.println("? WeavingURLClassLoader.<init>()"); + this.aspectURLs = aspectURLs; + adaptor = new WeavingAdaptor(this); + } + + private static String getAspectPath () { + return System.getProperty(WEAVING_ASPECT_PATH,""); + } + + private static String getClassPath () { + return System.getProperty(WEAVING_CLASS_PATH,""); + } + + private static URL[] getURLs (String path) { + List urlList = new ArrayList(); + for (StringTokenizer t = new StringTokenizer(path,File.pathSeparator); + t.hasMoreTokens();) { + File f = new File(t.nextToken().trim()); + try { + if (f.exists()) { + URL url = f.toURL(); + if (url != null) urlList.add(url); + } + } catch (MalformedURLException e) {} + } + + URL[] urls = new URL[urlList.size()]; + urlList.toArray(urls); + return urls; + } + + protected void addURL(URL url) { + adaptor.addURL(url); + super.addURL(url); + } + + /** + * Override to weave class using WeavingAdaptor + */ + protected Class defineClass(String name, byte[] b, CodeSource cs) throws IOException { +// System.err.println("? WeavingURLClassLoader.defineClass(" + name + ", [" + b.length + "])"); + b = adaptor.weaveClass(name,b); + return super.defineClass(name, b, cs); + } + + /** + * Override to find classes generated by WeavingAdaptor + */ + protected byte[] getBytes (String name) throws IOException { + byte[] bytes = super.getBytes(name); + + if (bytes == null) { +// return adaptor.findClass(name); + return (byte[])generatedClasses.remove(name); + } + + return bytes; + } + + /** + * Implement method from WeavingClassLoader + */ + public URL[] getAspectURLs() { + return aspectURLs; + } + + public void acceptClass (String name, byte[] bytes) { + generatedClasses.put(name,bytes); + } + +} diff --git a/weaver/src/org/aspectj/weaver/tools/GeneratedClassHandler.java b/weaver/src/org/aspectj/weaver/tools/GeneratedClassHandler.java new file mode 100644 index 000000000..0a782452c --- /dev/null +++ b/weaver/src/org/aspectj/weaver/tools/GeneratedClassHandler.java @@ -0,0 +1,29 @@ +/* ******************************************************************* + * 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; + +/** + * Interface implemented by weaving class loaders to allow classes generated by + * the weaving process to be defined. + */ +public interface GeneratedClassHandler { + + /** + * Accept class generated by WeavingAdaptor. The class loader should store + * the class definition in its local cache until called upon to load it. + * @param name class name + * @param bytes class definition + */ + public void acceptClass (String name, byte[] bytes); + +} diff --git a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java new file mode 100644 index 000000000..a7cd1ed74 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java @@ -0,0 +1,332 @@ +/* ******************************************************************* + * 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.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +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 java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.aspectj.bridge.AbortException; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.bridge.MessageHandler; +import org.aspectj.bridge.IMessage.Kind; +import org.aspectj.util.FileUtil; +import org.aspectj.weaver.IClassFileProvider; +import org.aspectj.weaver.IWeaveRequestor; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.bcel.BcelObjectType; +import org.aspectj.weaver.bcel.BcelWeaver; +import org.aspectj.weaver.bcel.BcelWorld; +import org.aspectj.weaver.bcel.LazyClassGen; +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"; + + private boolean enabled = true; + private boolean verbose = getVerbose(); + private BcelWorld bcelWorld = null; + private BcelWeaver weaver = null; + private IMessageHandler messageHandler = null; + private GeneratedClassHandler generatedClassHandler; + private Map generatedClasses = new HashMap(); /* String -> UnwovenClassFile */ + + /** + * 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 { + if (verbose) System.err.println("WeavingAdaptor: Warning - could not determine classpath for " + loader); + } + } + + 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) { + if (verbose) System.out.println("WeavingAdaptor: classPath='" + classPath + "'"); + + // make sure the weaver can find all types... + messageHandler = new MessageHandler(); + bcelWorld = new BcelWorld(classPath,messageHandler,null); + bcelWorld.setXnoInline(false); + bcelWorld.getLint().loadDefaultProperties(); + + weaver = new BcelWeaver(bcelWorld); + registerAspectLibraries(aspectPath); + } + + /** + * Appends URL to path used by the WeavingAdptor to resolve classes + * @param url to be appended to search path + */ + public void addURL(URL url) { + try { + weaver.addLibraryJarFile(new File(url.getPath())); + } + catch (IOException ex) { + } + } + + /** + * 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 = getWovenBytes(name, bytes); + } + return bytes; + } + + private boolean shouldWeave (String name) { + name = name.replace('/','.'); + boolean b = (enabled && !generatedClasses.containsKey(name) && shouldWeaveName(name) && shouldWeaveAspect(name)); + if (verbose) System.out.println("WeavingAdaptor: shouldWeave('" + name + "') " + b); + return b; + } + + private boolean shouldWeaveName (String name) { + return !((name.startsWith("org.apache.bcel.") || name.startsWith("org.aspectj.") || name.startsWith("java.") || name.startsWith("javax."))); + } + + private boolean shouldWeaveAspect (String name) { + ResolvedTypeX type = bcelWorld.resolve(name); + return (type == null || !type.isAspect()); + } + + /** + * 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 + * @throws FileNotFoundException + */ + private byte[] getWovenBytes(String name, byte[] bytes) throws IOException { + WeavingClassFileProvider wcp = new WeavingClassFileProvider(name,bytes); + weaver.weave(wcp); + return wcp.getBytes(); + +// UnwovenClassFile unwoven = new UnwovenClassFile(name,bytes); +// +// // weave +// BcelObjectType bcelType = bcelWorld.addSourceObjectType(unwoven.getJavaClass()); +// LazyClassGen woven = weaver.weaveWithoutDump(unwoven,bcelType); +// +// byte[] wovenBytes = woven != null ? woven.getJavaClass(bcelWorld).getBytes() : bytes; +// return wovenBytes; + } + + private void registerAspectLibraries(List aspectPath) { +// System.err.println("? WeavingAdaptor.registerAspectLibraries(" + aspectPath + ")"); + for (Iterator i = aspectPath.iterator(); i.hasNext();) { + String lib = (String)i.next(); + File libFile = new File(lib); + if (libFile.isFile() && lib.endsWith(".jar")) { + try { + if (verbose) System.out.println("WeavingAdaptor: adding aspect '" + lib + "' to weaver"); + addAspectLibrary(new File(lib)); + } catch (IOException ioEx) { + if (verbose) System.err.println( + "WeavingAdaptor: Warning - could not load aspect path entry " + + lib + " : " + ioEx); + } + } else { + if (verbose) System.err.println( + "WeavingAdaptor: Warning - ignoring aspect path entry: " + lib); + } + } + + 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(File aspectLibraryJarFile) throws IOException { + weaver.addLibraryJarFile(aspectLibraryJarFile); +// weaver.prepareForWeave(); + } + + 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; + } + + /** + * Processes messages arising from weaver operations. + * Tell weaver to abort on any non-informational error. + */ + private class MessageHandler implements IMessageHandler { + + public boolean handleMessage(IMessage message) throws AbortException { + if (!isIgnoring(message.getKind())) { + if (verbose) System.err.println(message.getMessage()); + throw new AbortException(message); + } + return true; + } + + public boolean isIgnoring(Kind kind) { + return ((kind == IMessage.INFO) || (kind == IMessage.DEBUG)); + } + } + + private class WeavingClassFileProvider implements IClassFileProvider { + + private List unwovenClasses = new ArrayList(); /* List<UnovenClassFile> */ + private UnwovenClassFile wovenClass; + + public WeavingClassFileProvider (String name, byte[] bytes) { + UnwovenClassFile unwoven = new UnwovenClassFile(name,bytes); + unwovenClasses.add(unwoven); + bcelWorld.addSourceObjectType(unwoven.getJavaClass()); + } + + 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() {} + }; + } + } +} diff --git a/weaver/src/org/aspectj/weaver/tools/WeavingClassLoader.java b/weaver/src/org/aspectj/weaver/tools/WeavingClassLoader.java new file mode 100644 index 000000000..045cd6c8b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/tools/WeavingClassLoader.java @@ -0,0 +1,31 @@ +/* ******************************************************************* + * 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.net.URL; + +/** + * An interface for weaving class loaders to provide callbacks for a + * WeavingAdaptor. + */ +public interface WeavingClassLoader extends GeneratedClassHandler { + + /** + * Returns the aspects to be used by a WeavingAdaptor to weave classes + * defined by the class loader. + * @return the aspects used for weaving classes. + */ + public URL[] getAspectURLs (); + +} diff --git a/weaver/src/org/aspectj/weaver/tools/package.html b/weaver/src/org/aspectj/weaver/tools/package.html new file mode 100644 index 000000000..b996ebb69 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/tools/package.html @@ -0,0 +1,7 @@ +<html> +<body> +Provides a set of interfaces to allow a class loader to perform +load-time weaving. + +</body> +</html> |