diff options
author | aclement <aclement> | 2008-08-28 02:47:05 +0000 |
---|---|---|
committer | aclement <aclement> | 2008-08-28 02:47:05 +0000 |
commit | 4e4299ef560badce91ed62acff384f21311bb417 (patch) | |
tree | 051bc08e23642fcb59394fd25f0fe5563d4d63a8 /loadtime/src/org/aspectj/weaver | |
parent | 65f73464a4eff01b32a7789ca0a798e6a9898b6f (diff) | |
download | aspectj-4e4299ef560badce91ed62acff384f21311bb417.tar.gz aspectj-4e4299ef560badce91ed62acff384f21311bb417.zip |
fixed eclipse warnings
Diffstat (limited to 'loadtime/src/org/aspectj/weaver')
5 files changed, 1598 insertions, 1630 deletions
diff --git a/loadtime/src/org/aspectj/weaver/loadtime/Aj.java b/loadtime/src/org/aspectj/weaver/loadtime/Aj.java index 5d74f0623..668622589 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/Aj.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/Aj.java @@ -26,269 +26,277 @@ import org.aspectj.weaver.tools.TraceFactory; import org.aspectj.weaver.tools.WeavingAdaptor; /** - * Adapter between the generic class pre processor interface and the AspectJ weaver - * Load time weaving consistency relies on Bcel.setRepository - * + * Adapter between the generic class pre processor interface and the AspectJ weaver Load time weaving consistency relies on + * Bcel.setRepository + * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ public class Aj implements ClassPreProcessor { private IWeavingContext weavingContext; - /** - * References are added to this queue when their associated classloader is removed, and once on here that indicates - * that we should tidy up the adaptor map and remove the adaptor (weaver) from the map we are maintaining from - * adaptorkey > adaptor (weaver) - */ - private static ReferenceQueue adaptorQueue = new ReferenceQueue(); + /** + * References are added to this queue when their associated classloader is removed, and once on here that indicates that we + * should tidy up the adaptor map and remove the adaptor (weaver) from the map we are maintaining from adaptorkey > adaptor + * (weaver) + */ + private static ReferenceQueue adaptorQueue = new ReferenceQueue(); private static Trace trace = TraceFactory.getTraceFactory().getTrace(Aj.class); - - public Aj(){ + + public Aj() { this(null); } - - - public Aj(IWeavingContext context){ - if (trace.isTraceEnabled()) trace.enter("<init>",this,new Object[] {context, getClass().getClassLoader()}); + + public Aj(IWeavingContext context) { + if (trace.isTraceEnabled()) + trace.enter("<init>", this, new Object[] { context, getClass().getClassLoader() }); this.weavingContext = context; - if (trace.isTraceEnabled()) trace.exit("<init>"); + if (trace.isTraceEnabled()) + trace.exit("<init>"); + } + + /** + * Initialization + */ + public void initialize() { + + } + + /** + * Weave + * + * @param className + * @param bytes + * @param loader + * @return weaved bytes + */ + public byte[] preProcess(String className, byte[] bytes, ClassLoader loader) { + + // TODO AV needs to doc that + if (loader == null || className == null) { + // skip boot loader or null classes (hibernate) + return bytes; + } + + if (trace.isTraceEnabled()) + trace.enter("preProcess", this, new Object[] { className, bytes, loader }); + if (trace.isTraceEnabled()) + trace.event("preProcess", this, new Object[] { loader.getParent(), Thread.currentThread().getContextClassLoader() }); + + try { + synchronized (loader) { + WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext); + if (weavingAdaptor == null) { + if (trace.isTraceEnabled()) + trace.exit("preProcess"); + return bytes; + } + byte[] newBytes = weavingAdaptor.weaveClass(className, bytes, false); + Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true); + if (trace.isTraceEnabled()) + trace.exit("preProcess", newBytes); + return newBytes; + } + + /* Don't like to do this but JVMTI swallows all exceptions */ + } catch (Throwable th) { + trace.error(className, th); + Dump.dumpWithException(th); + // FIXME AV wondering if we should have the option to fail (throw runtime exception) here + // would make sense at least in test f.e. see TestHelper.handleMessage() + if (trace.isTraceEnabled()) + trace.exit("preProcess", th); + return bytes; + } finally { + CompilationAndWeavingContext.resetForThread(); + } + } + + /** + * An AdaptorKey is a WeakReference wrapping a classloader reference that will enqueue to a specified queue when the classloader + * is GC'd. Since the AdaptorKey is used as a key into a hashmap we need to give it a non-varying hashcode/equals + * implementation, and we need that hashcode not to vary even when the internal referent has been GC'd. The hashcode is + * calculated on creation of the AdaptorKey based on the loader instance that it is wrapping. This means even when the referent + * is gone we can still use the AdaptorKey and it will 'point' to the same place as it always did. + */ + private static class AdaptorKey extends WeakReference { + + private int hashcode = -1; + + public AdaptorKey(ClassLoader loader) { + super(loader, adaptorQueue); + hashcode = loader.hashCode() * 37; + } + + public ClassLoader getClassLoader() { + ClassLoader instance = (ClassLoader) get(); + // Assert instance!=null - shouldn't be asked for after a GC of the referent has occurred ! + return instance; + } + + public boolean equals(Object obj) { + if (!(obj instanceof AdaptorKey)) + return false; + AdaptorKey other = (AdaptorKey) obj; + return other.hashcode == hashcode; + } + + public int hashCode() { + return hashcode; + } + + } + + /** + * The reference queue is only processed when a request is made for a weaver adaptor. This means there can be one or two stale + * weavers left around. If the user knows they have finished all their weaving, they might wish to call removeStaleAdaptors + * which will process anything left on the reference queue containing adaptorKeys for garbage collected classloaders. + * + * @param displayProgress produce System.err info on the tidying up process + * @return number of stale weavers removed + */ + public static int removeStaleAdaptors(boolean displayProgress) { + int removed = 0; + synchronized (WeaverContainer.weavingAdaptors) { + if (displayProgress) { + System.err.println("Weaver adaptors before queue processing:"); + Map m = WeaverContainer.weavingAdaptors; + Set keys = m.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + Object object = iterator.next(); + System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); + } + } + Object o = adaptorQueue.poll(); + while (o != null) { + if (displayProgress) + System.err.println("Processing referencequeue entry " + o); + AdaptorKey wo = (AdaptorKey) o; + boolean didit = WeaverContainer.weavingAdaptors.remove(wo) != null; + if (didit) { + removed++; + } else { + throw new RuntimeException("Eh?? key=" + wo); + } + if (displayProgress) + System.err.println("Removed? " + didit); + o = adaptorQueue.poll(); + } + if (displayProgress) { + System.err.println("Weaver adaptors after queue processing:"); + Map m = WeaverContainer.weavingAdaptors; + Set keys = m.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + Object object = iterator.next(); + System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); + } + } + } + return removed; + } + + /** + * @return the number of entries still in the weavingAdaptors map + */ + public static int getActiveAdaptorCount() { + return WeaverContainer.weavingAdaptors.size(); + } + + /** + * Process the reference queue that contains stale AdaptorKeys - the keys are put on the queue when their classloader referent + * is garbage collected and so the associated adaptor (weaver) should be removed from the map + */ + public static void checkQ() { + synchronized (adaptorQueue) { + Object o = adaptorQueue.poll(); + while (o != null) { + AdaptorKey wo = (AdaptorKey) o; + // boolean removed = + WeaverContainer.weavingAdaptors.remove(wo); + // DBG System.err.println("Evicting key " + wo + " = " + didit); + o = adaptorQueue.poll(); + } + } + } + + /** + * Cache of weaver There is one weaver per classloader + */ + static class WeaverContainer { + + final static Map weavingAdaptors = Collections.synchronizedMap(new HashMap()); + + static WeavingAdaptor getWeaver(ClassLoader loader, IWeavingContext weavingContext) { + ExplicitlyInitializedClassLoaderWeavingAdaptor adaptor = null; + AdaptorKey adaptorKey = new AdaptorKey(loader); + + synchronized (weavingAdaptors) { + checkQ(); + adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey); + if (adaptor == null) { + String loaderClassName = loader.getClass().getName(); + if (loaderClassName.equals("sun.reflect.DelegatingClassLoader")) { + // we don't weave reflection generated types at all! + return null; + } else { + // create it and put it back in the weavingAdaptors map but avoid any kind of instantiation + // within the synchronized block + ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor(); + adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor); + weavingAdaptors.put(adaptorKey, adaptor); + } + } + } + // perform the initialization + return adaptor.getWeavingAdaptor(loader, weavingContext); + + } } - /** - * Initialization - */ - public void initialize() { - ; - } - - /** - * Weave - * - * @param className - * @param bytes - * @param loader - * @return weaved bytes - */ - public byte[] preProcess(String className, byte[] bytes, ClassLoader loader) { - - //TODO AV needs to doc that - if (loader == null || className == null) { - // skip boot loader or null classes (hibernate) - return bytes; - } - - if (trace.isTraceEnabled()) trace.enter("preProcess",this,new Object[] {className, bytes, loader}); - if (trace.isTraceEnabled()) trace.event("preProcess",this,new Object[] {loader.getParent(), Thread.currentThread().getContextClassLoader()}); - - try { - synchronized (loader) { - WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext); - if (weavingAdaptor == null) { - if (trace.isTraceEnabled()) trace.exit("preProcess"); - return bytes; - } - byte[] newBytes = weavingAdaptor.weaveClass(className, bytes,false); - Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true); - if (trace.isTraceEnabled()) trace.exit("preProcess",newBytes); - return newBytes; + static class ExplicitlyInitializedClassLoaderWeavingAdaptor { + private final ClassLoaderWeavingAdaptor weavingAdaptor; + private boolean isInitialized; + + public ExplicitlyInitializedClassLoaderWeavingAdaptor(ClassLoaderWeavingAdaptor weavingAdaptor) { + this.weavingAdaptor = weavingAdaptor; + this.isInitialized = false; + } + + private void initialize(ClassLoader loader, IWeavingContext weavingContext) { + if (!isInitialized) { + isInitialized = true; + weavingAdaptor.initialize(loader, weavingContext); } - - /* Don't like to do this but JVMTI swallows all exceptions */ - } catch (Throwable th) { - trace.error(className,th); - Dump.dumpWithException(th); - //FIXME AV wondering if we should have the option to fail (throw runtime exception) here - // would make sense at least in test f.e. see TestHelper.handleMessage() - if (trace.isTraceEnabled()) trace.exit("preProcess",th); - return bytes; - } finally { - CompilationAndWeavingContext.resetForThread(); - } - } - - /** - * An AdaptorKey is a WeakReference wrapping a classloader reference that will enqueue to a specified queue when the - * classloader is GC'd. Since the AdaptorKey is used as a key into a hashmap we need to give it a non-varying - * hashcode/equals implementation, and we need that hashcode not to vary even when the internal referent has been - * GC'd. The hashcode is calculated on creation of the AdaptorKey based on the loader instance that it is wrapping. - * This means even when the referent is gone we can still use the AdaptorKey and it will 'point' to the same place - * as it always did. - */ - private static class AdaptorKey extends WeakReference { - - private int hashcode = -1; - - public AdaptorKey(ClassLoader loader) { - super(loader, adaptorQueue); - hashcode = loader.hashCode() * 37; - } - - public ClassLoader getClassLoader() { - ClassLoader instance = (ClassLoader) get(); - // Assert instance!=null - shouldn't be asked for after a GC of the referent has occurred ! - return instance; - } - - public boolean equals(Object obj) { - if (!(obj instanceof AdaptorKey)) return false; - AdaptorKey other = (AdaptorKey) obj; - return other.hashcode == hashcode; - } - - public int hashCode() { - return hashcode; - } - - } - - /** - * The reference queue is only processed when a request is made for a weaver adaptor. This means there can be one or - * two stale weavers left around. If the user knows they have finished all their weaving, they might wish to call - * removeStaleAdaptors which will process anything left on the reference queue containing adaptorKeys for garbage - * collected classloaders. - * - * @param displayProgress produce System.err info on the tidying up process - * @return number of stale weavers removed - */ - public static int removeStaleAdaptors(boolean displayProgress) { - int removed = 0; - synchronized (WeaverContainer.weavingAdaptors) { - if (displayProgress) { - System.err.println("Weaver adaptors before queue processing:"); - Map m = WeaverContainer.weavingAdaptors; - Set keys = m.keySet(); - for (Iterator iterator = keys.iterator(); iterator.hasNext();) { - Object object = iterator.next(); - System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); - } - } - Object o = adaptorQueue.poll(); - while (o != null) { - if (displayProgress) System.err.println("Processing referencequeue entry " + o); - AdaptorKey wo = (AdaptorKey) o; - boolean didit = WeaverContainer.weavingAdaptors.remove(wo) != null; - if (didit) { - removed++; - } else { - throw new RuntimeException("Eh?? key="+wo); - } - if (displayProgress) System.err.println("Removed? "+didit); - o = adaptorQueue.poll(); - } - if (displayProgress) { - System.err.println("Weaver adaptors after queue processing:"); - Map m = WeaverContainer.weavingAdaptors; - Set keys = m.keySet(); - for (Iterator iterator = keys.iterator(); iterator.hasNext();) { - Object object = iterator.next(); - System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object)); - } - } - } - return removed; - } - - /** - * @return the number of entries still in the weavingAdaptors map - */ - public static int getActiveAdaptorCount() { - return WeaverContainer.weavingAdaptors.size(); - } - - /** - * Process the reference queue that contains stale AdaptorKeys - the keys are put on the queue when their - * classloader referent is garbage collected and so the associated adaptor (weaver) should be removed from the map - */ - public static void checkQ() { - synchronized (adaptorQueue) { - Object o = adaptorQueue.poll(); - while (o != null) { - AdaptorKey wo = (AdaptorKey) o; - boolean removed = WeaverContainer.weavingAdaptors.remove(wo) != null; - // DBG System.err.println("Evicting key " + wo + " = " + didit); - o = adaptorQueue.poll(); - } - } - } - - /** - * Cache of weaver - * There is one weaver per classloader - */ - static class WeaverContainer { - - final static Map weavingAdaptors = Collections.synchronizedMap(new HashMap()); - - static WeavingAdaptor getWeaver(ClassLoader loader, IWeavingContext weavingContext) { - ExplicitlyInitializedClassLoaderWeavingAdaptor adaptor = null; - AdaptorKey adaptorKey = new AdaptorKey(loader); - - synchronized (weavingAdaptors) { - checkQ(); - adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey); - if (adaptor == null) { - String loaderClassName = loader.getClass().getName(); - if (loaderClassName.equals("sun.reflect.DelegatingClassLoader")) { - // we don't weave reflection generated types at all! - return null; - } else { - // create it and put it back in the weavingAdaptors map but avoid any kind of instantiation - // within the synchronized block - ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor(); - adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor); - weavingAdaptors.put(adaptorKey, adaptor); - } - } - } - // perform the initialization - return adaptor.getWeavingAdaptor(loader, weavingContext); - - } - } - - static class ExplicitlyInitializedClassLoaderWeavingAdaptor { - private final ClassLoaderWeavingAdaptor weavingAdaptor; - private boolean isInitialized; - - public ExplicitlyInitializedClassLoaderWeavingAdaptor(ClassLoaderWeavingAdaptor weavingAdaptor) { - this.weavingAdaptor = weavingAdaptor; - this.isInitialized = false; - } - - private void initialize(ClassLoader loader, IWeavingContext weavingContext) { - if (!isInitialized) { - isInitialized = true; - weavingAdaptor.initialize(loader, weavingContext); - } - } - - public ClassLoaderWeavingAdaptor getWeavingAdaptor(ClassLoader loader, IWeavingContext weavingContext) { - initialize(loader, weavingContext); - return weavingAdaptor; - } - } - - /** - * Returns a namespace based on the contest of the aspects available - */ - public String getNamespace (ClassLoader loader) { - ClassLoaderWeavingAdaptor weavingAdaptor = (ClassLoaderWeavingAdaptor)WeaverContainer.getWeaver(loader, weavingContext); - return weavingAdaptor.getNamespace(); - } - - /** - * Check to see if any classes have been generated for a particular classes loader. - * Calls ClassLoaderWeavingAdaptor.generatedClassesExist() - * @param loader the class cloder - * @return true if classes have been generated. - */ - public boolean generatedClassesExist(ClassLoader loader){ - return ((ClassLoaderWeavingAdaptor)WeaverContainer.getWeaver(loader, weavingContext)).generatedClassesExistFor(null); - } - - public void flushGeneratedClasses(ClassLoader loader){ - ((ClassLoaderWeavingAdaptor)WeaverContainer.getWeaver(loader, weavingContext)).flushGeneratedClasses(); - } + } + + public ClassLoaderWeavingAdaptor getWeavingAdaptor(ClassLoader loader, IWeavingContext weavingContext) { + initialize(loader, weavingContext); + return weavingAdaptor; + } + } + + /** + * Returns a namespace based on the contest of the aspects available + */ + public String getNamespace(ClassLoader loader) { + ClassLoaderWeavingAdaptor weavingAdaptor = (ClassLoaderWeavingAdaptor) WeaverContainer.getWeaver(loader, weavingContext); + return weavingAdaptor.getNamespace(); + } + + /** + * Check to see if any classes have been generated for a particular classes loader. Calls + * ClassLoaderWeavingAdaptor.generatedClassesExist() + * + * @param loader the class cloder + * @return true if classes have been generated. + */ + public boolean generatedClassesExist(ClassLoader loader) { + return ((ClassLoaderWeavingAdaptor) WeaverContainer.getWeaver(loader, weavingContext)).generatedClassesExistFor(null); + } + + public void flushGeneratedClasses(ClassLoader loader) { + ((ClassLoaderWeavingAdaptor) WeaverContainer.getWeaver(loader, weavingContext)).flushGeneratedClasses(); + } }
\ No newline at end of file diff --git a/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java b/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java index cf73de3ca..95016f655 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java @@ -56,722 +56,742 @@ import org.aspectj.weaver.tools.WeavingAdaptor; */ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor { - private final static String AOP_XML = Constants.AOP_USER_XML + ";" + Constants.AOP_AJC_XML + ";" + Constants.AOP_OSGI_XML; - - private boolean initialized; - - private List m_dumpTypePattern = new ArrayList(); - private boolean m_dumpBefore = false; - private List m_includeTypePattern = new ArrayList(); - private List m_excludeTypePattern = new ArrayList(); - private List m_includeStartsWith = new ArrayList(); - private List m_excludeStartsWith = new ArrayList(); - private List m_aspectExcludeTypePattern = new ArrayList(); - private List m_aspectExcludeStartsWith = new ArrayList(); - private List m_aspectIncludeTypePattern = new ArrayList(); - private List m_aspectIncludeStartsWith = new ArrayList(); - - private StringBuffer namespace; - private IWeavingContext weavingContext; - - private List concreteAspects = new ArrayList(); + private final static String AOP_XML = Constants.AOP_USER_XML + ";" + Constants.AOP_AJC_XML + ";" + Constants.AOP_OSGI_XML; + + private boolean initialized; + + private List m_dumpTypePattern = new ArrayList(); + private boolean m_dumpBefore = false; + private List m_includeTypePattern = new ArrayList(); + private List m_excludeTypePattern = new ArrayList(); + private List m_includeStartsWith = new ArrayList(); + private List m_excludeStartsWith = new ArrayList(); + private List m_aspectExcludeTypePattern = new ArrayList(); + private List m_aspectExcludeStartsWith = new ArrayList(); + private List m_aspectIncludeTypePattern = new ArrayList(); + private List m_aspectIncludeStartsWith = new ArrayList(); + + private StringBuffer namespace; + private IWeavingContext weavingContext; + + private List concreteAspects = new ArrayList(); private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassLoaderWeavingAdaptor.class); - - public ClassLoaderWeavingAdaptor() { - super(); - if (trace.isTraceEnabled()) trace.enter("<init>",this); - if (trace.isTraceEnabled()) trace.exit("<init>"); - } - - /** - * We don't need a reference to the class loader and using it during - * construction can cause problems with recursion. It also makes sense - * to supply the weaving context during initialization to. - * @deprecated - */ - public ClassLoaderWeavingAdaptor(final ClassLoader deprecatedLoader, final IWeavingContext deprecatedContext) { - super(); - if (trace.isTraceEnabled()) trace.enter("<init>",this,new Object[] { deprecatedLoader, deprecatedContext }); - if (trace.isTraceEnabled()) trace.exit("<init>"); - } - - class SimpleGeneratedClassHandler implements GeneratedClassHandler { - private WeakClassLoaderReference loaderRef; - SimpleGeneratedClassHandler(ClassLoader loader) { - loaderRef = new WeakClassLoaderReference(loader); - } - - /** - * Callback when we need to define a Closure in the JVM - * - */ - public void acceptClass(String name, byte[] bytes) { - try { - if (shouldDump(name.replace('/', '.'), false)) { - dump(name, bytes, false); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - - defineClass(loaderRef.getClassLoader(), name, bytes); // could be done lazily using the hook - } - }; - - protected void initialize (final ClassLoader classLoader, IWeavingContext context) { - if (initialized) return; - - boolean success = true; - // if (trace.isTraceEnabled()) trace.enter("initialize",this,new Object[] { classLoader, context }); - - this.weavingContext = context; - if (weavingContext == null) { - weavingContext = new DefaultWeavingContext(classLoader); - } - - createMessageHandler(); - - this.generatedClassHandler = - new SimpleGeneratedClassHandler(classLoader); - - List definitions = weavingContext.getDefinitions(classLoader,this); - if (definitions.isEmpty()) { - disable(); // TODO maw Needed to ensure messages are flushed - if (trace.isTraceEnabled()) trace.exit("initialize",definitions); - return; - } - - bcelWorld = new LTWWorld( - classLoader, weavingContext, // TODO when the world works in terms of the context, we can remove the loader... - getMessageHandler(), null); - - weaver = new BcelWeaver(bcelWorld); - - // register the definitions - success = registerDefinitions(weaver, classLoader, definitions); - if (success) { - - // after adding aspects - weaver.prepareForWeave(); - - enable(); // TODO maw Needed to ensure messages are flushed - success = weaveAndDefineConceteAspects(); - } - - if (success) { - enable(); - } - else { - disable(); - bcelWorld = null; - weaver = null; - } - - initialized = true; - if (trace.isTraceEnabled()) trace.exit("initialize",isEnabled()); - } - - /** - * Load and cache the aop.xml/properties according to the classloader visibility rules - * - * @param weaver - * @param loader - */ - List parseDefinitions(final ClassLoader loader) { - if (trace.isTraceEnabled()) trace.enter("parseDefinitions", this); - - List definitions = new ArrayList(); - try { - info("register classloader " + getClassLoaderName(loader)); - //TODO av underoptimized: we will parse each XML once per CL that see it - - //TODO av dev mode needed ? TBD -Daj5.def=... - if (loader.equals(ClassLoader.getSystemClassLoader())) { - String file = System.getProperty("aj5.def", null); - if (file != null) { - info("using (-Daj5.def) " + file); - definitions.add(DocumentParser.parse((new File(file)).toURL())); - } - } - - String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration",AOP_XML); - if (trace.isTraceEnabled()) trace.event("parseDefinitions",this,resourcePath); - - StringTokenizer st = new StringTokenizer(resourcePath,";"); - - while(st.hasMoreTokens()){ - String nextDefinition = st.nextToken(); - if (nextDefinition.startsWith("file:")) { - try { - String fpath = new URL(nextDefinition).getFile(); - File configFile = new File(fpath); - if (!configFile.exists()) { - warn("configuration does not exist: "+nextDefinition); - } else { - definitions.add(DocumentParser.parse(configFile.toURL())); - } - } catch (MalformedURLException mue) { - error("malformed definition url: "+nextDefinition); - } - } else { - Enumeration xmls = weavingContext.getResources(nextDefinition); - // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader); - - Set seenBefore = new HashSet(); - while (xmls.hasMoreElements()) { - URL xml = (URL) xmls.nextElement(); - if (trace.isTraceEnabled()) trace.event("parseDefinitions",this,xml); - if (!seenBefore.contains(xml)) { - info("using configuration " + weavingContext.getFile(xml)); - definitions.add(DocumentParser.parse(xml)); - seenBefore.add(xml); - } - else { - warn("ignoring duplicate definition: " + xml); - } - } - } - } - if (definitions.isEmpty()) { - info("no configuration found. Disabling weaver for class loader " + getClassLoaderName(loader)); - } - } catch (Exception e) { - definitions.clear(); - warn("parse definitions failed",e); - } - - if (trace.isTraceEnabled()) trace.exit("parseDefinitions",definitions); + + public ClassLoaderWeavingAdaptor() { + super(); + if (trace.isTraceEnabled()) + trace.enter("<init>", this); + if (trace.isTraceEnabled()) + trace.exit("<init>"); + } + + /** + * We don't need a reference to the class loader and using it during construction can cause problems with recursion. It also + * makes sense to supply the weaving context during initialization to. + * + * @deprecated + */ + public ClassLoaderWeavingAdaptor(final ClassLoader deprecatedLoader, final IWeavingContext deprecatedContext) { + super(); + if (trace.isTraceEnabled()) + trace.enter("<init>", this, new Object[] { deprecatedLoader, deprecatedContext }); + if (trace.isTraceEnabled()) + trace.exit("<init>"); + } + + class SimpleGeneratedClassHandler implements GeneratedClassHandler { + private WeakClassLoaderReference loaderRef; + + SimpleGeneratedClassHandler(ClassLoader loader) { + loaderRef = new WeakClassLoaderReference(loader); + } + + /** + * Callback when we need to define a Closure in the JVM + * + */ + public void acceptClass(String name, byte[] bytes) { + try { + if (shouldDump(name.replace('/', '.'), false)) { + dump(name, bytes, false); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + + defineClass(loaderRef.getClassLoader(), name, bytes); // could be done lazily using the hook + } + } + + protected void initialize(final ClassLoader classLoader, IWeavingContext context) { + if (initialized) + return; + + boolean success = true; + // if (trace.isTraceEnabled()) trace.enter("initialize",this,new Object[] { classLoader, context }); + + this.weavingContext = context; + if (weavingContext == null) { + weavingContext = new DefaultWeavingContext(classLoader); + } + + createMessageHandler(); + + this.generatedClassHandler = new SimpleGeneratedClassHandler(classLoader); + + List definitions = weavingContext.getDefinitions(classLoader, this); + if (definitions.isEmpty()) { + disable(); // TODO maw Needed to ensure messages are flushed + if (trace.isTraceEnabled()) + trace.exit("initialize", definitions); + return; + } + + bcelWorld = new LTWWorld(classLoader, weavingContext, // TODO when the world works in terms of the context, we can remove + // the loader... + getMessageHandler(), null); + + weaver = new BcelWeaver(bcelWorld); + + // register the definitions + success = registerDefinitions(weaver, classLoader, definitions); + if (success) { + + // after adding aspects + weaver.prepareForWeave(); + + enable(); // TODO maw Needed to ensure messages are flushed + success = weaveAndDefineConceteAspects(); + } + + if (success) { + enable(); + } else { + disable(); + bcelWorld = null; + weaver = null; + } + + initialized = true; + if (trace.isTraceEnabled()) + trace.exit("initialize", isEnabled()); + } + + /** + * Load and cache the aop.xml/properties according to the classloader visibility rules + * + * @param weaver + * @param loader + */ + List parseDefinitions(final ClassLoader loader) { + if (trace.isTraceEnabled()) + trace.enter("parseDefinitions", this); + + List definitions = new ArrayList(); + try { + info("register classloader " + getClassLoaderName(loader)); + // TODO av underoptimized: we will parse each XML once per CL that see it + + // TODO av dev mode needed ? TBD -Daj5.def=... + if (loader.equals(ClassLoader.getSystemClassLoader())) { + String file = System.getProperty("aj5.def", null); + if (file != null) { + info("using (-Daj5.def) " + file); + definitions.add(DocumentParser.parse((new File(file)).toURL())); + } + } + + String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration", AOP_XML); + if (trace.isTraceEnabled()) + trace.event("parseDefinitions", this, resourcePath); + + StringTokenizer st = new StringTokenizer(resourcePath, ";"); + + while (st.hasMoreTokens()) { + String nextDefinition = st.nextToken(); + if (nextDefinition.startsWith("file:")) { + try { + String fpath = new URL(nextDefinition).getFile(); + File configFile = new File(fpath); + if (!configFile.exists()) { + warn("configuration does not exist: " + nextDefinition); + } else { + definitions.add(DocumentParser.parse(configFile.toURL())); + } + } catch (MalformedURLException mue) { + error("malformed definition url: " + nextDefinition); + } + } else { + Enumeration xmls = weavingContext.getResources(nextDefinition); + // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader); + + Set seenBefore = new HashSet(); + while (xmls.hasMoreElements()) { + URL xml = (URL) xmls.nextElement(); + if (trace.isTraceEnabled()) + trace.event("parseDefinitions", this, xml); + if (!seenBefore.contains(xml)) { + info("using configuration " + weavingContext.getFile(xml)); + definitions.add(DocumentParser.parse(xml)); + seenBefore.add(xml); + } else { + warn("ignoring duplicate definition: " + xml); + } + } + } + } + if (definitions.isEmpty()) { + info("no configuration found. Disabling weaver for class loader " + getClassLoaderName(loader)); + } + } catch (Exception e) { + definitions.clear(); + warn("parse definitions failed", e); + } + + if (trace.isTraceEnabled()) + trace.exit("parseDefinitions", definitions); return definitions; - } - - private boolean registerDefinitions(final BcelWeaver weaver, final ClassLoader loader, List definitions) { - if (trace.isTraceEnabled()) trace.enter("registerDefinitions",this,definitions); - boolean success = true; - - try { - registerOptions(weaver, loader, definitions); - registerAspectExclude(weaver, loader, definitions); - registerAspectInclude(weaver, loader, definitions); - success = registerAspects(weaver, loader, definitions); - registerIncludeExclude(weaver, loader, definitions); - registerDump(weaver, loader, definitions); - } catch (Exception ex) { - trace.error("register definition failed",ex); - success = false; - warn("register definition failed",(ex instanceof AbortException)?null:ex); - } - - if (trace.isTraceEnabled()) trace.exit("registerDefinitions",success); - return success; - } - - private String getClassLoaderName (ClassLoader loader) { - return weavingContext.getClassLoaderName(); - } - - /** - * Configure the weaver according to the option directives - * TODO av - don't know if it is that good to reuse, since we only allow a small subset of options in LTW - * - * @param weaver - * @param loader - * @param definitions - */ - private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { - StringBuffer allOptions = new StringBuffer(); - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - allOptions.append(definition.getWeaverOptions()).append(' '); - } - - Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader, getMessageHandler()); - - // configure the weaver and world - // AV - code duplicates AspectJBuilder.initWorldAndWeaver() - World world = weaver.getWorld(); - setMessageHandler(weaverOption.messageHandler); - world.setXlazyTjp(weaverOption.lazyTjp); - world.setXHasMemberSupportEnabled(weaverOption.hasMember); - world.setOptionalJoinpoints(weaverOption.optionalJoinpoints); - world.setPinpointMode(weaverOption.pinpoint); - weaver.setReweavableMode(weaverOption.notReWeavable); - world.performExtraConfiguration(weaverOption.xSet); - world.setXnoInline(weaverOption.noInline); - // AMC - autodetect as per line below, needed for AtAjLTWTests.testLTWUnweavable - world.setBehaveInJava5Way(LangUtil.is15VMOrGreater()); - world.setAddSerialVerUID(weaverOption.addSerialVersionUID); - - /* First load defaults */ + } + + private boolean registerDefinitions(final BcelWeaver weaver, final ClassLoader loader, List definitions) { + if (trace.isTraceEnabled()) + trace.enter("registerDefinitions", this, definitions); + boolean success = true; + + try { + registerOptions(weaver, loader, definitions); + registerAspectExclude(weaver, loader, definitions); + registerAspectInclude(weaver, loader, definitions); + success = registerAspects(weaver, loader, definitions); + registerIncludeExclude(weaver, loader, definitions); + registerDump(weaver, loader, definitions); + } catch (Exception ex) { + trace.error("register definition failed", ex); + success = false; + warn("register definition failed", (ex instanceof AbortException) ? null : ex); + } + + if (trace.isTraceEnabled()) + trace.exit("registerDefinitions", success); + return success; + } + + private String getClassLoaderName(ClassLoader loader) { + return weavingContext.getClassLoaderName(); + } + + /** + * Configure the weaver according to the option directives TODO av - don't know if it is that good to reuse, since we only allow + * a small subset of options in LTW + * + * @param weaver + * @param loader + * @param definitions + */ + private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + StringBuffer allOptions = new StringBuffer(); + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + allOptions.append(definition.getWeaverOptions()).append(' '); + } + + Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader, getMessageHandler()); + + // configure the weaver and world + // AV - code duplicates AspectJBuilder.initWorldAndWeaver() + World world = weaver.getWorld(); + setMessageHandler(weaverOption.messageHandler); + world.setXlazyTjp(weaverOption.lazyTjp); + world.setXHasMemberSupportEnabled(weaverOption.hasMember); + world.setOptionalJoinpoints(weaverOption.optionalJoinpoints); + world.setPinpointMode(weaverOption.pinpoint); + weaver.setReweavableMode(weaverOption.notReWeavable); + world.performExtraConfiguration(weaverOption.xSet); + world.setXnoInline(weaverOption.noInline); + // AMC - autodetect as per line below, needed for AtAjLTWTests.testLTWUnweavable + world.setBehaveInJava5Way(LangUtil.is15VMOrGreater()); + world.setAddSerialVerUID(weaverOption.addSerialVersionUID); + + /* First load defaults */ bcelWorld.getLint().loadDefaultProperties(); - + /* Second overlay LTW defaults */ bcelWorld.getLint().adviceDidNotMatch.setKind(null); - - /* Third load user file using -Xlintfile so that -Xlint wins */ - if (weaverOption.lintFile != null) { - InputStream resource = null; - try { - resource = loader.getResourceAsStream(weaverOption.lintFile); - Exception failure = null; - if (resource != null) { - try { - Properties properties = new Properties(); - properties.load(resource); - world.getLint().setFromProperties(properties); - } catch (IOException e) { - failure = e; - } - } - if (failure != null || resource == null) { - warn("Cannot access resource for -Xlintfile:"+weaverOption.lintFile,failure); -// world.getMessageHandler().handleMessage(new Message( -// "Cannot access resource for -Xlintfile:"+weaverOption.lintFile, -// IMessage.WARNING, -// failure, -// null)); - } - } finally { - try { resource.close(); } catch (Throwable t) {;} - } - } - - /* Fourth override with -Xlint */ - if (weaverOption.lint != null) { - if (weaverOption.lint.equals("default")) {//FIXME should be AjBuildConfig.AJLINT_DEFAULT but yetanother deps.. - bcelWorld.getLint().loadDefaultProperties(); - } else { - bcelWorld.getLint().setAll(weaverOption.lint); - } - } - //TODO proceedOnError option - } - - private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { - String fastMatchInfo = null; - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - for (Iterator iterator1 = definition.getAspectExcludePatterns().iterator(); iterator1.hasNext();) { - String exclude = (String) iterator1.next(); - TypePattern excludePattern = new PatternParser(exclude).parseTypePattern(); - m_aspectExcludeTypePattern.add(excludePattern); - fastMatchInfo = looksLikeStartsWith(exclude); - if (fastMatchInfo != null) { - m_aspectExcludeStartsWith.add(fastMatchInfo); - } - } - } - } - - private void registerAspectInclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { - String fastMatchInfo = null; - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - for (Iterator iterator1 = definition.getAspectIncludePatterns().iterator(); iterator1.hasNext();) { - String include = (String) iterator1.next(); - TypePattern includePattern = new PatternParser(include).parseTypePattern(); - m_aspectIncludeTypePattern.add(includePattern); - fastMatchInfo = looksLikeStartsWith(include); - if (fastMatchInfo != null) { - m_aspectIncludeStartsWith.add(fastMatchInfo); - } - } - } - } - - protected void lint (String name, String[] infos) { - Lint lint = bcelWorld.getLint(); - Kind kind = lint.getLintKind(name); - kind.signal(infos,null,null); - } - - public String getContextId () { + + /* Third load user file using -Xlintfile so that -Xlint wins */ + if (weaverOption.lintFile != null) { + InputStream resource = null; + try { + resource = loader.getResourceAsStream(weaverOption.lintFile); + Exception failure = null; + if (resource != null) { + try { + Properties properties = new Properties(); + properties.load(resource); + world.getLint().setFromProperties(properties); + } catch (IOException e) { + failure = e; + } + } + if (failure != null || resource == null) { + warn("Cannot access resource for -Xlintfile:" + weaverOption.lintFile, failure); + // world.getMessageHandler().handleMessage(new Message( + // "Cannot access resource for -Xlintfile:"+weaverOption.lintFile, + // IMessage.WARNING, + // failure, + // null)); + } + } finally { + try { + resource.close(); + } catch (Throwable t) { + } + } + } + + /* Fourth override with -Xlint */ + if (weaverOption.lint != null) { + if (weaverOption.lint.equals("default")) {// FIXME should be AjBuildConfig.AJLINT_DEFAULT but yetanother deps.. + bcelWorld.getLint().loadDefaultProperties(); + } else { + bcelWorld.getLint().setAll(weaverOption.lint); + } + } + // TODO proceedOnError option + } + + private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + String fastMatchInfo = null; + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + for (Iterator iterator1 = definition.getAspectExcludePatterns().iterator(); iterator1.hasNext();) { + String exclude = (String) iterator1.next(); + TypePattern excludePattern = new PatternParser(exclude).parseTypePattern(); + m_aspectExcludeTypePattern.add(excludePattern); + fastMatchInfo = looksLikeStartsWith(exclude); + if (fastMatchInfo != null) { + m_aspectExcludeStartsWith.add(fastMatchInfo); + } + } + } + } + + private void registerAspectInclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + String fastMatchInfo = null; + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + for (Iterator iterator1 = definition.getAspectIncludePatterns().iterator(); iterator1.hasNext();) { + String include = (String) iterator1.next(); + TypePattern includePattern = new PatternParser(include).parseTypePattern(); + m_aspectIncludeTypePattern.add(includePattern); + fastMatchInfo = looksLikeStartsWith(include); + if (fastMatchInfo != null) { + m_aspectIncludeStartsWith.add(fastMatchInfo); + } + } + } + } + + protected void lint(String name, String[] infos) { + Lint lint = bcelWorld.getLint(); + Kind kind = lint.getLintKind(name); + kind.signal(infos, null, null); + } + + public String getContextId() { return weavingContext.getId(); } - - /** - * Register the aspect, following include / exclude rules - * - * @param weaver - * @param loader - * @param definitions - */ - private boolean registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { - if (trace.isTraceEnabled()) trace.enter("registerAspects",this, new Object[] { weaver, loader, definitions} ); - boolean success = true; - - //TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ?? - // if not, review the getResource so that we track which resource is defined by which CL - - //iterate aspectClassNames - //exclude if in any of the exclude list - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - for (Iterator aspects = definition.getAspectClassNames().iterator(); aspects.hasNext();) { - String aspectClassName = (String) aspects.next(); - if (acceptAspect(aspectClassName)) { - info("register aspect " + aspectClassName); -// System.err.println("? ClassLoaderWeavingAdaptor.registerAspects() aspectName=" + aspectClassName + ", loader=" + loader + ", bundle=" + weavingContext.getClassLoaderName()); - /*ResolvedType aspect = */weaver.addLibraryAspect(aspectClassName); - - //generate key for SC - if(namespace==null){ - namespace=new StringBuffer(aspectClassName); - }else{ - namespace = namespace.append(";"+aspectClassName); - } - } - else { -// warn("aspect excluded: " + aspectClassName); - lint("aspectExcludedByConfiguration", new String[] { aspectClassName, getClassLoaderName(loader) }); - } - } - } - - //iterate concreteAspects - //exclude if in any of the exclude list - note that the user defined name matters for that to happen - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - for (Iterator aspects = definition.getConcreteAspects().iterator(); aspects.hasNext();) { - Definition.ConcreteAspect concreteAspect = (Definition.ConcreteAspect) aspects.next(); - if (acceptAspect(concreteAspect.name)) { - info("define aspect " + concreteAspect.name); - ConcreteAspectCodeGen gen = new ConcreteAspectCodeGen(concreteAspect, weaver.getWorld()); - if (!gen.validate()) { - error("Concrete-aspect '"+concreteAspect.name+"' could not be registered"); - success = false; - break; - } - - ((BcelWorld)weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes())); - - concreteAspects.add(gen); - - weaver.addLibraryAspect(concreteAspect.name); - - //generate key for SC - if(namespace==null){ - namespace=new StringBuffer(concreteAspect.name); - }else{ - namespace = namespace.append(";"+concreteAspect.name); - } - } - } - } - - /* We couldn't register one or more aspects so disable the adaptor */ - if (!success) { - warn("failure(s) registering aspects. Disabling weaver for class loader " + getClassLoaderName(loader)); - } - - /* We didn't register any aspects so disable the adaptor */ - else if (namespace == null) { - success = false; - info("no aspects registered. Disabling weaver for class loader " + getClassLoaderName(loader)); - } - - if (trace.isTraceEnabled()) trace.exit("registerAspects",success); - return success; - } - - private boolean weaveAndDefineConceteAspects () { - if (trace.isTraceEnabled()) trace.enter("weaveAndDefineConceteAspects",this,concreteAspects); - boolean success = true; - - for (Iterator iterator = concreteAspects.iterator(); iterator.hasNext();) { - ConcreteAspectCodeGen gen = (ConcreteAspectCodeGen)iterator.next(); - String name = gen.getClassName(); - byte[] bytes = gen.getBytes(); - - try { - byte[] newBytes = weaveClass(name, bytes,true); - this.generatedClassHandler.acceptClass(name,newBytes); - } - catch (IOException ex) { - trace.error("weaveAndDefineConceteAspects",ex); - error("exception weaving aspect '" + name + "'",ex); - } - } - - if (trace.isTraceEnabled()) trace.exit("weaveAndDefineConceteAspects",success); - return success; - } - - /** - * Register the include / exclude filters - * We duplicate simple patterns in startWith filters that will allow faster matching without ResolvedType - * - * @param weaver - * @param loader - * @param definitions - */ - private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { - String fastMatchInfo = null; - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) { - String include = (String) iterator1.next(); - TypePattern includePattern = new PatternParser(include).parseTypePattern(); - m_includeTypePattern.add(includePattern); - fastMatchInfo = looksLikeStartsWith(include); - if (fastMatchInfo != null) { - m_includeStartsWith.add(fastMatchInfo); - } - } - for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) { - String exclude = (String) iterator1.next(); - TypePattern excludePattern = new PatternParser(exclude).parseTypePattern(); - m_excludeTypePattern.add(excludePattern); - fastMatchInfo = looksLikeStartsWith(exclude); - if (fastMatchInfo != null) { - m_excludeStartsWith.add(fastMatchInfo); - } - } - } - } - - /** - * Checks if the type pattern can be handled as a startswith check - * - * TODO AV - enhance to support "char.sss" ie FQN direclty (match iff equals) - * we could also add support for "*..*charss" endsWith style? - * - * @param typePattern - * @return null if not possible, or the startWith sequence to test against - */ - private String looksLikeStartsWith(String typePattern) { - if (typePattern.indexOf('@') >= 0 - || typePattern.indexOf('+') >= 0 - || typePattern.indexOf(' ') >= 0 - || typePattern.charAt(typePattern.length()-1) != '*') { - return null; - } - // now must looks like with "charsss..*" or "cha.rss..*" etc - // note that "*" and "*..*" won't be fast matched - // and that "charsss.*" will not neither - int length = typePattern.length(); - if (typePattern.endsWith("..*") && length > 3) { - if (typePattern.indexOf("..") == length-3 // no ".." before last sequence - && typePattern.indexOf('*') == length-1) { // no "*" before last sequence - return typePattern.substring(0, length-2).replace('$', '.'); - // ie "charsss." or "char.rss." etc - } - } - return null; - } - - /** - * Register the dump filter - * - * @param weaver - * @param loader - * @param definitions - */ - private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { - for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { - Definition definition = (Definition) iterator.next(); - for (Iterator iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) { - String dump = (String) iterator1.next(); - TypePattern pattern = new PatternParser(dump).parseTypePattern(); - m_dumpTypePattern.add(pattern); - } - if (definition.shouldDumpBefore()) { - m_dumpBefore = true; - } - } - } - - protected boolean accept(String className, byte[] bytes) { - // avoid ResolvedType if not needed - if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) { - return true; - } - - // still try to avoid ResolvedType if we have simple patterns - String fastClassName = className.replace('/', '.').replace('$', '.'); - for (int i = 0; i < m_excludeStartsWith.size(); i++) { - if (fastClassName.startsWith((String)m_excludeStartsWith.get(i))) { - return false; - } - } - - /* - * Bug 120363 - * If we have an exclude pattern that cannot be matched using "starts with" - * then we cannot fast accept - */ - if (m_excludeTypePattern.isEmpty()) { - boolean fastAccept = false;//defaults to false if no fast include - for (int i = 0; i < m_includeStartsWith.size(); i++) { - fastAccept = fastClassName.startsWith((String)m_includeStartsWith.get(i)); - if (fastAccept) { - break; - } - } - } - - // needs further analysis - // TODO AV - needs refactoring - // during LTW this calling resolve at that stage is BAD as we do have the bytecode from the classloader hook - // but still go thru resolve that will do a getResourcesAsStream on disk - // this is also problematic for jit stub which are not on disk - as often underlying infra - // does returns null or some other info for getResourceAsStream (f.e. WLS 9 CR248491) - // Instead I parse the given bytecode. But this also means it will be parsed again in - // new WeavingClassFileProvider() from WeavingAdaptor.getWovenBytes()... - - ensureDelegateInitialized(className,bytes); - ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();//BAD: weaver.getWorld().resolve(UnresolvedType.forName(className), true); - - //exclude are "AND"ed - for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) { - TypePattern typePattern = (TypePattern) iterator.next(); - if (typePattern.matchesStatically(classInfo)) { - // exclude match - skip - return false; - } - } - //include are "OR"ed - boolean accept = true;//defaults to true if no include - for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) { - TypePattern typePattern = (TypePattern) iterator.next(); - accept = typePattern.matchesStatically(classInfo); - if (accept) { - break; - } - // goes on if this include did not match ("OR"ed) - } - return accept; - } - - - //FIXME we don't use include/exclude of others aop.xml - //this can be nice but very dangerous as well to change that - private boolean acceptAspect(String aspectClassName) { - // avoid ResolvedType if not needed - if (m_aspectExcludeTypePattern.isEmpty() && m_aspectIncludeTypePattern.isEmpty()) { - return true; - } - - // still try to avoid ResolvedType if we have simple patterns - // EXCLUDE: if one match then reject - String fastClassName = aspectClassName.replace('/', '.').replace('.', '$'); - for (int i = 0; i < m_aspectExcludeStartsWith.size(); i++) { - if (fastClassName.startsWith((String)m_aspectExcludeStartsWith.get(i))) { - return false; - } - } - //INCLUDE: if one match then accept - for (int i = 0; i < m_aspectIncludeStartsWith.size(); i++) { - if (fastClassName.startsWith((String)m_aspectIncludeStartsWith.get(i))) { - return true; - } - } - - // needs further analysis - ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true); - //exclude are "AND"ed - for (Iterator iterator = m_aspectExcludeTypePattern.iterator(); iterator.hasNext();) { - TypePattern typePattern = (TypePattern) iterator.next(); - if (typePattern.matchesStatically(classInfo)) { - // exclude match - skip - return false; - } - } - //include are "OR"ed - boolean accept = true;//defaults to true if no include - for (Iterator iterator = m_aspectIncludeTypePattern.iterator(); iterator.hasNext();) { - TypePattern typePattern = (TypePattern) iterator.next(); - accept = typePattern.matchesStatically(classInfo); - if (accept) { - break; - } - // goes on if this include did not match ("OR"ed) - } - return accept; - } - - protected boolean shouldDump(String className, boolean before) { - // Don't dump before weaving unless asked to - if (before && !m_dumpBefore) { - return false; - } - - // avoid ResolvedType if not needed - if (m_dumpTypePattern.isEmpty()) { - return false; - } - - //TODO AV - optimize for className.startWith only - ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true); - //dump - for (Iterator iterator = m_dumpTypePattern.iterator(); iterator.hasNext();) { - TypePattern typePattern = (TypePattern) iterator.next(); - if (typePattern.matchesStatically(classInfo)) { - // dump match - return true; - } - } - return false; - } - - /* - * shared classes methods - */ - - /** + + /** + * Register the aspect, following include / exclude rules + * + * @param weaver + * @param loader + * @param definitions + */ + private boolean registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + if (trace.isTraceEnabled()) + trace.enter("registerAspects", this, new Object[] { weaver, loader, definitions }); + boolean success = true; + + // TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ?? + // if not, review the getResource so that we track which resource is defined by which CL + + // iterate aspectClassNames + // exclude if in any of the exclude list + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + for (Iterator aspects = definition.getAspectClassNames().iterator(); aspects.hasNext();) { + String aspectClassName = (String) aspects.next(); + if (acceptAspect(aspectClassName)) { + info("register aspect " + aspectClassName); + // System.err.println("? ClassLoaderWeavingAdaptor.registerAspects() aspectName=" + aspectClassName + + // ", loader=" + loader + ", bundle=" + weavingContext.getClassLoaderName()); + /* ResolvedType aspect = */weaver.addLibraryAspect(aspectClassName); + + // generate key for SC + if (namespace == null) { + namespace = new StringBuffer(aspectClassName); + } else { + namespace = namespace.append(";" + aspectClassName); + } + } else { + // warn("aspect excluded: " + aspectClassName); + lint("aspectExcludedByConfiguration", new String[] { aspectClassName, getClassLoaderName(loader) }); + } + } + } + + // iterate concreteAspects + // exclude if in any of the exclude list - note that the user defined name matters for that to happen + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + for (Iterator aspects = definition.getConcreteAspects().iterator(); aspects.hasNext();) { + Definition.ConcreteAspect concreteAspect = (Definition.ConcreteAspect) aspects.next(); + if (acceptAspect(concreteAspect.name)) { + info("define aspect " + concreteAspect.name); + ConcreteAspectCodeGen gen = new ConcreteAspectCodeGen(concreteAspect, weaver.getWorld()); + if (!gen.validate()) { + error("Concrete-aspect '" + concreteAspect.name + "' could not be registered"); + success = false; + break; + } + + ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes())); + + concreteAspects.add(gen); + + weaver.addLibraryAspect(concreteAspect.name); + + // generate key for SC + if (namespace == null) { + namespace = new StringBuffer(concreteAspect.name); + } else { + namespace = namespace.append(";" + concreteAspect.name); + } + } + } + } + + /* We couldn't register one or more aspects so disable the adaptor */ + if (!success) { + warn("failure(s) registering aspects. Disabling weaver for class loader " + getClassLoaderName(loader)); + } + + /* We didn't register any aspects so disable the adaptor */ + else if (namespace == null) { + success = false; + info("no aspects registered. Disabling weaver for class loader " + getClassLoaderName(loader)); + } + + if (trace.isTraceEnabled()) + trace.exit("registerAspects", success); + return success; + } + + private boolean weaveAndDefineConceteAspects() { + if (trace.isTraceEnabled()) + trace.enter("weaveAndDefineConceteAspects", this, concreteAspects); + boolean success = true; + + for (Iterator iterator = concreteAspects.iterator(); iterator.hasNext();) { + ConcreteAspectCodeGen gen = (ConcreteAspectCodeGen) iterator.next(); + String name = gen.getClassName(); + byte[] bytes = gen.getBytes(); + + try { + byte[] newBytes = weaveClass(name, bytes, true); + this.generatedClassHandler.acceptClass(name, newBytes); + } catch (IOException ex) { + trace.error("weaveAndDefineConceteAspects", ex); + error("exception weaving aspect '" + name + "'", ex); + } + } + + if (trace.isTraceEnabled()) + trace.exit("weaveAndDefineConceteAspects", success); + return success; + } + + /** + * Register the include / exclude filters We duplicate simple patterns in startWith filters that will allow faster matching + * without ResolvedType + * + * @param weaver + * @param loader + * @param definitions + */ + private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + String fastMatchInfo = null; + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) { + String include = (String) iterator1.next(); + TypePattern includePattern = new PatternParser(include).parseTypePattern(); + m_includeTypePattern.add(includePattern); + fastMatchInfo = looksLikeStartsWith(include); + if (fastMatchInfo != null) { + m_includeStartsWith.add(fastMatchInfo); + } + } + for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) { + String exclude = (String) iterator1.next(); + TypePattern excludePattern = new PatternParser(exclude).parseTypePattern(); + m_excludeTypePattern.add(excludePattern); + fastMatchInfo = looksLikeStartsWith(exclude); + if (fastMatchInfo != null) { + m_excludeStartsWith.add(fastMatchInfo); + } + } + } + } + + /** + * Checks if the type pattern can be handled as a startswith check + * + * TODO AV - enhance to support "char.sss" ie FQN direclty (match iff equals) we could also add support for "*..*charss" + * endsWith style? + * + * @param typePattern + * @return null if not possible, or the startWith sequence to test against + */ + private String looksLikeStartsWith(String typePattern) { + if (typePattern.indexOf('@') >= 0 || typePattern.indexOf('+') >= 0 || typePattern.indexOf(' ') >= 0 + || typePattern.charAt(typePattern.length() - 1) != '*') { + return null; + } + // now must looks like with "charsss..*" or "cha.rss..*" etc + // note that "*" and "*..*" won't be fast matched + // and that "charsss.*" will not neither + int length = typePattern.length(); + if (typePattern.endsWith("..*") && length > 3) { + if (typePattern.indexOf("..") == length - 3 // no ".." before last sequence + && typePattern.indexOf('*') == length - 1) { // no "*" before last sequence + return typePattern.substring(0, length - 2).replace('$', '.'); + // ie "charsss." or "char.rss." etc + } + } + return null; + } + + /** + * Register the dump filter + * + * @param weaver + * @param loader + * @param definitions + */ + private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { + Definition definition = (Definition) iterator.next(); + for (Iterator iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) { + String dump = (String) iterator1.next(); + TypePattern pattern = new PatternParser(dump).parseTypePattern(); + m_dumpTypePattern.add(pattern); + } + if (definition.shouldDumpBefore()) { + m_dumpBefore = true; + } + } + } + + protected boolean accept(String className, byte[] bytes) { + // avoid ResolvedType if not needed + if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) { + return true; + } + + // still try to avoid ResolvedType if we have simple patterns + String fastClassName = className.replace('/', '.').replace('$', '.'); + for (int i = 0; i < m_excludeStartsWith.size(); i++) { + if (fastClassName.startsWith((String) m_excludeStartsWith.get(i))) { + return false; + } + } + + /* + * Bug 120363 If we have an exclude pattern that cannot be matched using "starts with" then we cannot fast accept + */ + if (m_excludeTypePattern.isEmpty()) { + boolean fastAccept = false;// defaults to false if no fast include + for (int i = 0; i < m_includeStartsWith.size(); i++) { + fastAccept = fastClassName.startsWith((String) m_includeStartsWith.get(i)); + if (fastAccept) { + break; + } + } + } + + // needs further analysis + // TODO AV - needs refactoring + // during LTW this calling resolve at that stage is BAD as we do have the bytecode from the classloader hook + // but still go thru resolve that will do a getResourcesAsStream on disk + // this is also problematic for jit stub which are not on disk - as often underlying infra + // does returns null or some other info for getResourceAsStream (f.e. WLS 9 CR248491) + // Instead I parse the given bytecode. But this also means it will be parsed again in + // new WeavingClassFileProvider() from WeavingAdaptor.getWovenBytes()... + + ensureDelegateInitialized(className, bytes); + ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();// BAD: + // weaver.getWorld().resolve(UnresolvedType.forName( + // className), true); + + // exclude are "AND"ed + for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) { + TypePattern typePattern = (TypePattern) iterator.next(); + if (typePattern.matchesStatically(classInfo)) { + // exclude match - skip + return false; + } + } + // include are "OR"ed + boolean accept = true;// defaults to true if no include + for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) { + TypePattern typePattern = (TypePattern) iterator.next(); + accept = typePattern.matchesStatically(classInfo); + if (accept) { + break; + } + // goes on if this include did not match ("OR"ed) + } + return accept; + } + + // FIXME we don't use include/exclude of others aop.xml + // this can be nice but very dangerous as well to change that + private boolean acceptAspect(String aspectClassName) { + // avoid ResolvedType if not needed + if (m_aspectExcludeTypePattern.isEmpty() && m_aspectIncludeTypePattern.isEmpty()) { + return true; + } + + // still try to avoid ResolvedType if we have simple patterns + // EXCLUDE: if one match then reject + String fastClassName = aspectClassName.replace('/', '.').replace('.', '$'); + for (int i = 0; i < m_aspectExcludeStartsWith.size(); i++) { + if (fastClassName.startsWith((String) m_aspectExcludeStartsWith.get(i))) { + return false; + } + } + // INCLUDE: if one match then accept + for (int i = 0; i < m_aspectIncludeStartsWith.size(); i++) { + if (fastClassName.startsWith((String) m_aspectIncludeStartsWith.get(i))) { + return true; + } + } + + // needs further analysis + ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true); + // exclude are "AND"ed + for (Iterator iterator = m_aspectExcludeTypePattern.iterator(); iterator.hasNext();) { + TypePattern typePattern = (TypePattern) iterator.next(); + if (typePattern.matchesStatically(classInfo)) { + // exclude match - skip + return false; + } + } + // include are "OR"ed + boolean accept = true;// defaults to true if no include + for (Iterator iterator = m_aspectIncludeTypePattern.iterator(); iterator.hasNext();) { + TypePattern typePattern = (TypePattern) iterator.next(); + accept = typePattern.matchesStatically(classInfo); + if (accept) { + break; + } + // goes on if this include did not match ("OR"ed) + } + return accept; + } + + protected boolean shouldDump(String className, boolean before) { + // Don't dump before weaving unless asked to + if (before && !m_dumpBefore) { + return false; + } + + // avoid ResolvedType if not needed + if (m_dumpTypePattern.isEmpty()) { + return false; + } + + // TODO AV - optimize for className.startWith only + ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true); + // dump + for (Iterator iterator = m_dumpTypePattern.iterator(); iterator.hasNext();) { + TypePattern typePattern = (TypePattern) iterator.next(); + if (typePattern.matchesStatically(classInfo)) { + // dump match + return true; + } + } + return false; + } + + /* + * shared classes methods + */ + + /** * @return Returns the key. */ public String getNamespace() { -// System.out.println("ClassLoaderWeavingAdaptor.getNamespace() classloader=" + weavingContext.getClassLoaderName() + ", namespace=" + namespace); - if(namespace==null) return ""; - else return new String(namespace); + // System.out.println("ClassLoaderWeavingAdaptor.getNamespace() classloader=" + weavingContext.getClassLoaderName() + + // ", namespace=" + namespace); + if (namespace == null) + return ""; + else + return new String(namespace); } - /** - * Check to see if any classes are stored in the generated classes cache. - * Then flush the cache if it is not empty - * @param className TODO - * @return true if a class has been generated and is stored in the cache - */ - public boolean generatedClassesExistFor (String className) { -// System.err.println("? ClassLoaderWeavingAdaptor.generatedClassesExist() classname=" + className + ", size=" + generatedClasses); - if (className == null) return !generatedClasses.isEmpty(); - else return generatedClasses.containsKey(className); - } - - /** - * Flush the generated classes cache - */ - public void flushGeneratedClasses() { -// System.err.println("? ClassLoaderWeavingAdaptor.flushGeneratedClasses() generatedClasses=" + generatedClasses); - generatedClasses = new HashMap(); - } + /** + * Check to see if any classes are stored in the generated classes cache. Then flush the cache if it is not empty + * + * @param className TODO + * @return true if a class has been generated and is stored in the cache + */ + public boolean generatedClassesExistFor(String className) { + // System.err.println("? ClassLoaderWeavingAdaptor.generatedClassesExist() classname=" + className + ", size=" + + // generatedClasses); + if (className == null) + return !generatedClasses.isEmpty(); + else + return generatedClasses.containsKey(className); + } + + /** + * Flush the generated classes cache + */ + public void flushGeneratedClasses() { + // System.err.println("? ClassLoaderWeavingAdaptor.flushGeneratedClasses() generatedClasses=" + generatedClasses); + generatedClasses = new HashMap(); + } private void defineClass(ClassLoader loader, String name, byte[] bytes) { - if (trace.isTraceEnabled()) trace.enter("defineClass",this,new Object[] {loader,name,bytes}); - Object clazz = null; + if (trace.isTraceEnabled()) + trace.enter("defineClass", this, new Object[] { loader, name, bytes }); + Object clazz = null; debug("generating class '" + name + "'"); - + try { - //TODO av protection domain, and optimize - Method defineClass = ClassLoader.class.getDeclaredMethod( - "defineClass", new Class[] { String.class, - bytes.getClass(), int.class, int.class }); + // TODO av protection domain, and optimize + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, bytes.getClass(), + int.class, int.class }); defineClass.setAccessible(true); - clazz = defineClass.invoke(loader, new Object[] { name, bytes, - new Integer(0), new Integer(bytes.length) }); + clazz = defineClass.invoke(loader, new Object[] { name, bytes, new Integer(0), new Integer(bytes.length) }); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof LinkageError) { - warn("define generated class failed",e.getTargetException()); - //is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved) + warn("define generated class failed", e.getTargetException()); + // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved) // TODO maw I don't think this is OK and } else { - warn("define generated class failed",e.getTargetException()); + warn("define generated class failed", e.getTargetException()); } } catch (Exception e) { - warn("define generated class failed",e); + warn("define generated class failed", e); } - if (trace.isTraceEnabled()) trace.exit("defineClass",clazz); + if (trace.isTraceEnabled()) + trace.exit("defineClass", clazz); } }
\ No newline at end of file diff --git a/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java b/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java index 08f52664d..703403ba2 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java @@ -11,6 +11,15 @@ *******************************************************************************/ package org.aspectj.weaver.loadtime; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; @@ -37,365 +46,320 @@ import org.aspectj.weaver.loadtime.definition.Definition; import org.aspectj.weaver.patterns.PerClause; import org.aspectj.weaver.patterns.PerSingleton; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - /** - * Generates bytecode for concrete-aspect - * <p/> - * The concrete aspect is @AspectJ code generated. As it is build during aop.xml definitions registration - * we perform the type munging for perclause ie aspectOf artifact directly, instead of waiting for it - * to go thru the weaver (that we are in the middle of configuring). - * + * Generates bytecode for concrete-aspect <p/> The concrete aspect is @AspectJ code generated. As it is build during aop.xml + * definitions registration we perform the type munging for perclause ie aspectOf artifact directly, instead of waiting for it to go + * thru the weaver (that we are in the middle of configuring). + * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ public class ConcreteAspectCodeGen { - private final static String[] EMPTY_STRINGS = new String[0]; - private final static Type[] EMPTY_TYPES = new Type[0]; - - /** - * Concrete aspect definition we build for - */ - private final Definition.ConcreteAspect m_concreteAspect; - - /** - * World for which we build for - */ - private final World m_world; - - /** - * Set to true when all is checks are verified - */ - private boolean m_isValid = false; - - /** - * The parent aspect, not concretized - */ - private ResolvedType m_parent; - - /** - * Aspect perClause, used for direct munging of aspectOf artifacts - */ - private PerClause m_perClause; - - /** - * Create a new compiler for a concrete aspect - * - * @param concreteAspect - * @param world - */ - ConcreteAspectCodeGen(Definition.ConcreteAspect concreteAspect, World world) { - m_concreteAspect = concreteAspect; - m_world = world; - } - - /** - * Checks that concrete aspect is valid - * - * @return true if ok, false otherwise - */ - public boolean validate() { - if (!(m_world instanceof BcelWorld)) { - reportError("Internal error: world must be of type BcelWorld"); - return false; - } - - // name must be undefined so far - // TODO only convert the name to signature once, probably earlier than this - ResolvedType current = m_world.lookupBySignature(UnresolvedType.forName(m_concreteAspect.name).getSignature()); - - if (current!=null && !current.isMissing()) { - reportError("Attempt to concretize but chosen aspect name already defined: " + stringify()); - return false; - } - - // it can happen that extends is null, for precedence only declaration - if (m_concreteAspect.extend == null && m_concreteAspect.precedence != null) { - if (m_concreteAspect.pointcuts.isEmpty()) { - m_isValid = true; - m_perClause = new PerSingleton(); - m_parent = null; - return true;// no need to checks more in that special case - } else { - reportError("Attempt to use nested pointcuts without extends clause: "+stringify()); - return false; - } - } - - m_parent = m_world.resolve(m_concreteAspect.extend, true); - // handle inner classes - if (m_parent.isMissing()) { - // fallback on inner class lookup mechanism - String fixedName = m_concreteAspect.extend; - int hasDot = fixedName.lastIndexOf('.'); - while (hasDot > 0) { - char[] fixedNameChars = fixedName.toCharArray(); - fixedNameChars[hasDot] = '$'; - fixedName = new String(fixedNameChars); - hasDot = fixedName.lastIndexOf('.'); - m_parent = m_world.resolve(UnresolvedType.forName(fixedName), true); - if (!m_parent.isMissing()) { - break; - } - } - } - if (m_parent.isMissing()) { - reportError("Cannot find m_parent aspect for: " + stringify()); - return false; - } - - // extends must be abstract - if (!m_parent.isAbstract()) { - reportError("Attempt to concretize a non-abstract aspect: " + stringify()); - return false; - } - - // m_parent must be aspect - if (!m_parent.isAspect()) { - reportError("Attempt to concretize a non aspect: " + stringify()); - return false; - } - - // must have all abstractions defined - List elligibleAbstractions = new ArrayList(); - - Collection abstractMethods = getOutstandingAbstractMethods(m_parent); - for (Iterator iter = abstractMethods.iterator(); iter.hasNext();) { + private final static String[] EMPTY_STRINGS = new String[0]; + private final static Type[] EMPTY_TYPES = new Type[0]; + + /** + * Concrete aspect definition we build for + */ + private final Definition.ConcreteAspect m_concreteAspect; + + /** + * World for which we build for + */ + private final World m_world; + + /** + * Set to true when all is checks are verified + */ + private boolean m_isValid = false; + + /** + * The parent aspect, not concretized + */ + private ResolvedType m_parent; + + /** + * Aspect perClause, used for direct munging of aspectOf artifacts + */ + private PerClause m_perClause; + + /** + * Create a new compiler for a concrete aspect + * + * @param concreteAspect + * @param world + */ + ConcreteAspectCodeGen(Definition.ConcreteAspect concreteAspect, World world) { + m_concreteAspect = concreteAspect; + m_world = world; + } + + /** + * Checks that concrete aspect is valid + * + * @return true if ok, false otherwise + */ + public boolean validate() { + if (!(m_world instanceof BcelWorld)) { + reportError("Internal error: world must be of type BcelWorld"); + return false; + } + + // name must be undefined so far + // TODO only convert the name to signature once, probably earlier than this + ResolvedType current = m_world.lookupBySignature(UnresolvedType.forName(m_concreteAspect.name).getSignature()); + + if (current != null && !current.isMissing()) { + reportError("Attempt to concretize but chosen aspect name already defined: " + stringify()); + return false; + } + + // it can happen that extends is null, for precedence only declaration + if (m_concreteAspect.extend == null && m_concreteAspect.precedence != null) { + if (m_concreteAspect.pointcuts.isEmpty()) { + m_isValid = true; + m_perClause = new PerSingleton(); + m_parent = null; + return true;// no need to checks more in that special case + } else { + reportError("Attempt to use nested pointcuts without extends clause: " + stringify()); + return false; + } + } + + m_parent = m_world.resolve(m_concreteAspect.extend, true); + // handle inner classes + if (m_parent.isMissing()) { + // fallback on inner class lookup mechanism + String fixedName = m_concreteAspect.extend; + int hasDot = fixedName.lastIndexOf('.'); + while (hasDot > 0) { + char[] fixedNameChars = fixedName.toCharArray(); + fixedNameChars[hasDot] = '$'; + fixedName = new String(fixedNameChars); + hasDot = fixedName.lastIndexOf('.'); + m_parent = m_world.resolve(UnresolvedType.forName(fixedName), true); + if (!m_parent.isMissing()) { + break; + } + } + } + if (m_parent.isMissing()) { + reportError("Cannot find m_parent aspect for: " + stringify()); + return false; + } + + // extends must be abstract + if (!m_parent.isAbstract()) { + reportError("Attempt to concretize a non-abstract aspect: " + stringify()); + return false; + } + + // m_parent must be aspect + if (!m_parent.isAspect()) { + reportError("Attempt to concretize a non aspect: " + stringify()); + return false; + } + + // must have all abstractions defined + List elligibleAbstractions = new ArrayList(); + + Collection abstractMethods = getOutstandingAbstractMethods(m_parent); + for (Iterator iter = abstractMethods.iterator(); iter.hasNext();) { ResolvedMember method = (ResolvedMember) iter.next(); if ("()V".equals(method.getSignature())) { - String n = method.getName(); - if (n.startsWith("ajc$pointcut")) { // Allow for the abstract pointcut being from a code style aspect compiled with -1.5 (see test for 128744) - n = n.substring(14); - n = n.substring(0,n.indexOf("$")); - elligibleAbstractions.add(n); - } else if (hasPointcutAnnotation(method)) { - elligibleAbstractions.add(method.getName()); - } else { - // error, an outstanding abstract method that can't be concretized in XML - reportError("Abstract method '" + method.toString() + "' cannot be concretized in XML: " + stringify()); - return false; - } - } else { - if (method.getName().startsWith("ajc$pointcut") || hasPointcutAnnotation(method)) { - // it may be a pointcut but it doesn't meet the requirements for XML concretization - reportError("Abstract method '" + method.toString() + "' cannot be concretized as a pointcut (illegal signature, must have no arguments, must return void): " + stringify()); - return false; - } else { - // error, an outstanding abstract method that can't be concretized in XML - reportError("Abstract method '" + method.toString() + "' cannot be concretized in XML: " + stringify()); - return false; - } - } + String n = method.getName(); + if (n.startsWith("ajc$pointcut")) { // Allow for the abstract pointcut being from a code style aspect compiled with + // -1.5 (see test for 128744) + n = n.substring(14); + n = n.substring(0, n.indexOf("$")); + elligibleAbstractions.add(n); + } else if (hasPointcutAnnotation(method)) { + elligibleAbstractions.add(method.getName()); + } else { + // error, an outstanding abstract method that can't be concretized in XML + reportError("Abstract method '" + method.toString() + "' cannot be concretized in XML: " + stringify()); + return false; + } + } else { + if (method.getName().startsWith("ajc$pointcut") || hasPointcutAnnotation(method)) { + // it may be a pointcut but it doesn't meet the requirements for XML concretization + reportError("Abstract method '" + + method.toString() + + "' cannot be concretized as a pointcut (illegal signature, must have no arguments, must return void): " + + stringify()); + return false; + } else { + // error, an outstanding abstract method that can't be concretized in XML + reportError("Abstract method '" + method.toString() + "' cannot be concretized in XML: " + stringify()); + return false; + } + } + } + List pointcutNames = new ArrayList(); + for (Iterator it = m_concreteAspect.pointcuts.iterator(); it.hasNext();) { + Definition.Pointcut abstractPc = (Definition.Pointcut) it.next(); + pointcutNames.add(abstractPc.name); } - List pointcutNames = new ArrayList(); - for (Iterator it = m_concreteAspect.pointcuts.iterator(); it.hasNext();) { - Definition.Pointcut abstractPc = (Definition.Pointcut) it.next(); - pointcutNames.add(abstractPc.name); - } - for (Iterator it = elligibleAbstractions.iterator(); it.hasNext();) { - String elligiblePc = (String) it.next(); - if (!pointcutNames.contains(elligiblePc)) { - reportError("Abstract pointcut '" + elligiblePc + "' not configured: " + stringify()); - return false; - } - } - - m_perClause = m_parent.getPerClause(); - m_isValid = true; - return m_isValid; - } - - private Collection getOutstandingAbstractMethods(ResolvedType type) { - Map collector = new HashMap(); - // let's get to the top of the hierarchy and then walk down ... recording abstract methods then removing - // them if they get defined further down the hierarchy - getOutstandingAbstractMethodsHelper(type,collector); + for (Iterator it = elligibleAbstractions.iterator(); it.hasNext();) { + String elligiblePc = (String) it.next(); + if (!pointcutNames.contains(elligiblePc)) { + reportError("Abstract pointcut '" + elligiblePc + "' not configured: " + stringify()); + return false; + } + } + + m_perClause = m_parent.getPerClause(); + m_isValid = true; + return m_isValid; + } + + private Collection getOutstandingAbstractMethods(ResolvedType type) { + Map collector = new HashMap(); + // let's get to the top of the hierarchy and then walk down ... recording abstract methods then removing + // them if they get defined further down the hierarchy + getOutstandingAbstractMethodsHelper(type, collector); return collector.values(); } - - // We are trying to determine abstract methods left over at the bottom of a hierarchy that have not been - // concretized. - private void getOutstandingAbstractMethodsHelper(ResolvedType type,Map collector) { - if (type==null) return; - // Get to the top - if (type!=null && !type.equals(ResolvedType.OBJECT)) { - if (type.getSuperclass()!=null) - getOutstandingAbstractMethodsHelper(type.getSuperclass(),collector); - } - ResolvedMember[] rms = type.getDeclaredMethods(); - if (rms!=null) { - for (int i = 0; i < rms.length; i++) { + + // We are trying to determine abstract methods left over at the bottom of a hierarchy that have not been + // concretized. + private void getOutstandingAbstractMethodsHelper(ResolvedType type, Map collector) { + if (type == null) + return; + // Get to the top + if (!type.equals(ResolvedType.OBJECT)) { + if (type.getSuperclass() != null) + getOutstandingAbstractMethodsHelper(type.getSuperclass(), collector); + } + ResolvedMember[] rms = type.getDeclaredMethods(); + if (rms != null) { + for (int i = 0; i < rms.length; i++) { ResolvedMember member = rms[i]; - String key = member.getName()+member.getSignature(); + String key = member.getName() + member.getSignature(); if (member.isAbstract()) { - collector.put(key,member); + collector.put(key, member); } else { collector.remove(key); } - } - } - } + } + } + } /** - * Rebuild the XML snip that defines this concrete aspect, for log error purpose - * - * @return string repr. - */ - private String stringify() { - StringBuffer sb = new StringBuffer("<concrete-aspect name='"); - sb.append(m_concreteAspect.name); - sb.append("' extends='"); - sb.append(m_concreteAspect.extend); - sb.append("'/> in aop.xml"); - return sb.toString(); - } - - private boolean hasPointcutAnnotation(ResolvedMember member) { - AnnotationX[] as = member.getAnnotations(); - if (as==null || as.length==0) return false; - for (int i = 0; i < as.length; i++) { + * Rebuild the XML snip that defines this concrete aspect, for log error purpose + * + * @return string repr. + */ + private String stringify() { + StringBuffer sb = new StringBuffer("<concrete-aspect name='"); + sb.append(m_concreteAspect.name); + sb.append("' extends='"); + sb.append(m_concreteAspect.extend); + sb.append("'/> in aop.xml"); + return sb.toString(); + } + + private boolean hasPointcutAnnotation(ResolvedMember member) { + AnnotationX[] as = member.getAnnotations(); + if (as == null || as.length == 0) + return false; + for (int i = 0; i < as.length; i++) { if (as[i].getTypeSignature().equals("Lorg/aspectj/lang/annotation/Pointcut;")) { return true; } } - return false; - } - - public String getClassName () { - return m_concreteAspect.name; - } - - /** - * Build the bytecode for the concrete aspect - * - * @return concrete aspect bytecode - */ - public byte[] getBytes() { - if (!m_isValid) { - throw new RuntimeException("Must validate first"); - } - - //TODO AV - abstract away from BCEL... - // @Aspect //inherit clause from m_parent - // @DeclarePrecedence("....") // if any - // public class xxxName [extends xxxExtends] { - // [@Pointcut(xxxExpression-n) - // public void xxxName-n() {}] - // } - - // @Aspect public class ... - LazyClassGen cg = new LazyClassGen( - m_concreteAspect.name.replace('.', '/'), - (m_parent==null)?"java/lang/Object":m_parent.getName().replace('.', '/'), - null,//TODO AV - we could point to the aop.xml that defines it and use JSR-45 - Modifier.PUBLIC + Constants.ACC_SUPER, - EMPTY_STRINGS, - m_world - ); - AnnotationGen ag = new AnnotationGen( - new ObjectType("org/aspectj/lang/annotation/Aspect"), - Collections.EMPTY_LIST, - true, - cg.getConstantPool() - ); - cg.addAnnotation(ag); - if (m_concreteAspect.precedence != null) { - SimpleElementValueGen svg = new SimpleElementValueGen( - ElementValueGen.STRING, - cg.getConstantPool(), - m_concreteAspect.precedence - ); - List elems = new ArrayList(); - elems.add(new ElementNameValuePairGen("value", svg, cg.getConstantPool())); - AnnotationGen agprec = new AnnotationGen( - new ObjectType("org/aspectj/lang/annotation/DeclarePrecedence"), - elems, - true, - cg.getConstantPool() - ); - cg.addAnnotation(agprec); - } - - // default constructor - LazyMethodGen init = new LazyMethodGen( - Modifier.PUBLIC, - Type.VOID, - "<init>", - EMPTY_TYPES, - EMPTY_STRINGS, - cg - ); - InstructionList cbody = init.getBody(); - cbody.append(InstructionConstants.ALOAD_0); - cbody.append(cg.getFactory().createInvoke( - (m_parent==null)?"java/lang/Object":m_parent.getName().replace('.', '/'), - "<init>", - Type.VOID, - EMPTY_TYPES, - Constants.INVOKESPECIAL - )); - cbody.append(InstructionConstants.RETURN); - cg.addMethodGen(init); - - for (Iterator it = m_concreteAspect.pointcuts.iterator(); it.hasNext();) { - Definition.Pointcut abstractPc = (Definition.Pointcut) it.next(); - - LazyMethodGen mg = new LazyMethodGen( - Modifier.PUBLIC,//TODO AV - respect visibility instead of opening up? - Type.VOID, - abstractPc.name, - EMPTY_TYPES, - EMPTY_STRINGS, - cg - ); - SimpleElementValueGen svg = new SimpleElementValueGen( - ElementValueGen.STRING, - cg.getConstantPool(), - abstractPc.expression - ); - List elems = new ArrayList(); - elems.add(new ElementNameValuePairGen("value", svg, cg.getConstantPool())); - AnnotationGen mag = new AnnotationGen( - new ObjectType("org/aspectj/lang/annotation/Pointcut"), - elems, - true, - cg.getConstantPool() - ); - AnnotationX max = new AnnotationX(mag, m_world); - mg.addAnnotation(max); - - InstructionList body = mg.getBody(); - body.append(InstructionConstants.RETURN); - - cg.addMethodGen(mg); - } - - // handle the perClause - ReferenceType rt = new ReferenceType(ResolvedType.forName(m_concreteAspect.name).getSignature(),m_world); - BcelPerClauseAspectAdder perClauseMunger = new BcelPerClauseAspectAdder(rt,m_perClause.getKind()); - perClauseMunger.forceMunge(cg, false); - - //TODO AV - unsafe cast - // register the fresh new class into the world repository as it does not exist on the classpath anywhere - JavaClass jc = cg.getJavaClass((BcelWorld) m_world); - ((BcelWorld) m_world).addSourceObjectType(jc); - - return jc.getBytes(); - } - - /** - * Error reporting - * - * @param message - */ - private void reportError(String message) { - m_world.getMessageHandler().handleMessage(new Message(message, IMessage.ERROR, null, null)); - } + return false; + } + + public String getClassName() { + return m_concreteAspect.name; + } + + /** + * Build the bytecode for the concrete aspect + * + * @return concrete aspect bytecode + */ + public byte[] getBytes() { + if (!m_isValid) { + throw new RuntimeException("Must validate first"); + } + + // TODO AV - abstract away from BCEL... + // @Aspect //inherit clause from m_parent + // @DeclarePrecedence("....") // if any + // public class xxxName [extends xxxExtends] { + // [@Pointcut(xxxExpression-n) + // public void xxxName-n() {}] + // } + + // @Aspect public class ... + LazyClassGen cg = new LazyClassGen(m_concreteAspect.name.replace('.', '/'), (m_parent == null) ? "java/lang/Object" + : m_parent.getName().replace('.', '/'), null,// TODO AV - we could point to the aop.xml that defines it and use + // JSR-45 + Modifier.PUBLIC + Constants.ACC_SUPER, EMPTY_STRINGS, m_world); + AnnotationGen ag = new AnnotationGen(new ObjectType("org/aspectj/lang/annotation/Aspect"), Collections.EMPTY_LIST, true, cg + .getConstantPool()); + cg.addAnnotation(ag); + if (m_concreteAspect.precedence != null) { + SimpleElementValueGen svg = new SimpleElementValueGen(ElementValueGen.STRING, cg.getConstantPool(), + m_concreteAspect.precedence); + List elems = new ArrayList(); + elems.add(new ElementNameValuePairGen("value", svg, cg.getConstantPool())); + AnnotationGen agprec = new AnnotationGen(new ObjectType("org/aspectj/lang/annotation/DeclarePrecedence"), elems, true, + cg.getConstantPool()); + cg.addAnnotation(agprec); + } + + // default constructor + LazyMethodGen init = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, "<init>", EMPTY_TYPES, EMPTY_STRINGS, cg); + InstructionList cbody = init.getBody(); + cbody.append(InstructionConstants.ALOAD_0); + cbody.append(cg.getFactory().createInvoke((m_parent == null) ? "java/lang/Object" : m_parent.getName().replace('.', '/'), + "<init>", Type.VOID, EMPTY_TYPES, Constants.INVOKESPECIAL)); + cbody.append(InstructionConstants.RETURN); + cg.addMethodGen(init); + + for (Iterator it = m_concreteAspect.pointcuts.iterator(); it.hasNext();) { + Definition.Pointcut abstractPc = (Definition.Pointcut) it.next(); + + LazyMethodGen mg = new LazyMethodGen(Modifier.PUBLIC,// TODO AV - respect visibility instead of opening up? + Type.VOID, abstractPc.name, EMPTY_TYPES, EMPTY_STRINGS, cg); + SimpleElementValueGen svg = new SimpleElementValueGen(ElementValueGen.STRING, cg.getConstantPool(), + abstractPc.expression); + List elems = new ArrayList(); + elems.add(new ElementNameValuePairGen("value", svg, cg.getConstantPool())); + AnnotationGen mag = new AnnotationGen(new ObjectType("org/aspectj/lang/annotation/Pointcut"), elems, true, cg + .getConstantPool()); + AnnotationX max = new AnnotationX(mag, m_world); + mg.addAnnotation(max); + + InstructionList body = mg.getBody(); + body.append(InstructionConstants.RETURN); + + cg.addMethodGen(mg); + } + + // handle the perClause + ReferenceType rt = new ReferenceType(ResolvedType.forName(m_concreteAspect.name).getSignature(), m_world); + BcelPerClauseAspectAdder perClauseMunger = new BcelPerClauseAspectAdder(rt, m_perClause.getKind()); + perClauseMunger.forceMunge(cg, false); + + // TODO AV - unsafe cast + // register the fresh new class into the world repository as it does not exist on the classpath anywhere + JavaClass jc = cg.getJavaClass((BcelWorld) m_world); + ((BcelWorld) m_world).addSourceObjectType(jc); + + return jc.getBytes(); + } + + /** + * Error reporting + * + * @param message + */ + private void reportError(String message) { + m_world.getMessageHandler().handleMessage(new Message(message, IMessage.ERROR, null, null)); + } } diff --git a/loadtime/src/org/aspectj/weaver/loadtime/Options.java b/loadtime/src/org/aspectj/weaver/loadtime/Options.java index 89e172bc1..b9276170e 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/Options.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/Options.java @@ -11,171 +11,158 @@ *******************************************************************************/ package org.aspectj.weaver.loadtime; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + import org.aspectj.bridge.IMessage; import org.aspectj.bridge.IMessageHandler; import org.aspectj.bridge.Message; import org.aspectj.util.LangUtil; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - /** - * A class that hanldes LTW options. - * Note: AV - I choosed to not reuse AjCompilerOptions and alike since those implies too many dependancies on - * jdt and ajdt modules. - * + * A class that hanldes LTW options. Note: AV - I choosed to not reuse AjCompilerOptions and alike since those implies too many + * dependancies on jdt and ajdt modules. + * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ public class Options { - private final static String OPTION_15 = "-1.5"; - private final static String OPTION_lazyTjp = "-XlazyTjp"; - private final static String OPTION_noWarn = "-nowarn"; - private final static String OPTION_noWarnNone = "-warn:none"; - private final static String OPTION_proceedOnError = "-proceedOnError"; - private final static String OPTION_verbose = "-verbose"; - private final static String OPTION_debug = "-debug"; - private final static String OPTION_reweavable = "-Xreweavable";//notReweavable is default for LTW - private final static String OPTION_noinline = "-Xnoinline"; - private final static String OPTION_addSerialVersionUID = "-XaddSerialVersionUID"; - private final static String OPTION_hasMember = "-XhasMember"; - private final static String OPTION_pinpoint = "-Xdev:pinpoint"; - private final static String OPTION_showWeaveInfo = "-showWeaveInfo"; - private final static String OPTIONVALUED_messageHandler = "-XmessageHandlerClass:"; - private static final String OPTIONVALUED_Xlintfile = "-Xlintfile:"; - private static final String OPTIONVALUED_Xlint = "-Xlint:"; - private static final String OPTIONVALUED_joinpoints = "-Xjoinpoints:"; - private static final String OPTIONVALUED_Xset = "-Xset:"; + private final static String OPTION_15 = "-1.5"; + private final static String OPTION_lazyTjp = "-XlazyTjp"; + private final static String OPTION_noWarn = "-nowarn"; + private final static String OPTION_noWarnNone = "-warn:none"; + private final static String OPTION_proceedOnError = "-proceedOnError"; + private final static String OPTION_verbose = "-verbose"; + private final static String OPTION_debug = "-debug"; + private final static String OPTION_reweavable = "-Xreweavable";// notReweavable is default for LTW + private final static String OPTION_noinline = "-Xnoinline"; + private final static String OPTION_addSerialVersionUID = "-XaddSerialVersionUID"; + private final static String OPTION_hasMember = "-XhasMember"; + private final static String OPTION_pinpoint = "-Xdev:pinpoint"; + private final static String OPTION_showWeaveInfo = "-showWeaveInfo"; + private final static String OPTIONVALUED_messageHandler = "-XmessageHandlerClass:"; + private static final String OPTIONVALUED_Xlintfile = "-Xlintfile:"; + private static final String OPTIONVALUED_Xlint = "-Xlint:"; + private static final String OPTIONVALUED_joinpoints = "-Xjoinpoints:"; + private static final String OPTIONVALUED_Xset = "-Xset:"; - public static WeaverOption parse(String options, ClassLoader laoder, IMessageHandler imh) { - WeaverOption weaverOption = new WeaverOption(imh); + public static WeaverOption parse(String options, ClassLoader laoder, IMessageHandler imh) { + WeaverOption weaverOption = new WeaverOption(imh); - if (LangUtil.isEmpty(options)) { - return weaverOption; - } - // the first option wins - List flags = LangUtil.anySplit(options, " "); - Collections.reverse(flags); + if (LangUtil.isEmpty(options)) { + return weaverOption; + } + // the first option wins + List flags = LangUtil.anySplit(options, " "); + Collections.reverse(flags); - // do a first round on the message handler since it will report the options themselves - for (Iterator iterator = flags.iterator(); iterator.hasNext();) { - String arg = (String) iterator.next(); - if (arg.startsWith(OPTIONVALUED_messageHandler)) { - if (arg.length() > OPTIONVALUED_messageHandler.length()) { - String handlerClass = arg.substring(OPTIONVALUED_messageHandler.length()).trim(); - try { - Class handler = Class.forName(handlerClass, false, laoder); - weaverOption.messageHandler = ((IMessageHandler) handler.newInstance()); - } catch (Throwable t) { - weaverOption.messageHandler.handleMessage( - new Message( - "Cannot instantiate message handler " + handlerClass, - IMessage.ERROR, - t, - null - ) - ); - } - } - } - } + // do a first round on the message handler since it will report the options themselves + for (Iterator iterator = flags.iterator(); iterator.hasNext();) { + String arg = (String) iterator.next(); + if (arg.startsWith(OPTIONVALUED_messageHandler)) { + if (arg.length() > OPTIONVALUED_messageHandler.length()) { + String handlerClass = arg.substring(OPTIONVALUED_messageHandler.length()).trim(); + try { + Class handler = Class.forName(handlerClass, false, laoder); + weaverOption.messageHandler = ((IMessageHandler) handler.newInstance()); + } catch (Throwable t) { + weaverOption.messageHandler.handleMessage(new Message("Cannot instantiate message handler " + handlerClass, + IMessage.ERROR, t, null)); + } + } + } + } - // configure the other options - for (Iterator iterator = flags.iterator(); iterator.hasNext();) { - String arg = (String) iterator.next(); - if (arg.equals(OPTION_15)) { - weaverOption.java5 = true; - } else if (arg.equalsIgnoreCase(OPTION_lazyTjp)) { - weaverOption.lazyTjp = true; - } else if (arg.equalsIgnoreCase(OPTION_noinline)) { - weaverOption.noInline = true; - } else if (arg.equalsIgnoreCase(OPTION_addSerialVersionUID)) { - weaverOption.addSerialVersionUID=true; - } else if (arg.equalsIgnoreCase(OPTION_noWarn) || arg.equalsIgnoreCase(OPTION_noWarnNone)) { - weaverOption.noWarn = true; - } else if (arg.equalsIgnoreCase(OPTION_proceedOnError)) { - weaverOption.proceedOnError = true; - } else if (arg.equalsIgnoreCase(OPTION_reweavable)) { - weaverOption.notReWeavable = false; - } else if (arg.equalsIgnoreCase(OPTION_showWeaveInfo)) { - weaverOption.showWeaveInfo = true; - } else if (arg.equalsIgnoreCase(OPTION_hasMember)) { - weaverOption.hasMember = true; - } else if (arg.startsWith(OPTIONVALUED_joinpoints)) { - if (arg.length()>OPTIONVALUED_joinpoints.length()) - weaverOption.optionalJoinpoints = arg.substring(OPTIONVALUED_joinpoints.length()).trim(); - } else if (arg.equalsIgnoreCase(OPTION_verbose)) { - weaverOption.verbose = true; - } else if (arg.equalsIgnoreCase(OPTION_debug)) { - weaverOption.debug = true; - } else if (arg.equalsIgnoreCase(OPTION_pinpoint)) { - weaverOption.pinpoint = true; - } else if (arg.startsWith(OPTIONVALUED_messageHandler)) { - ;// handled in first round - } else if (arg.startsWith(OPTIONVALUED_Xlintfile)) { - if (arg.length() > OPTIONVALUED_Xlintfile.length()) { - weaverOption.lintFile = arg.substring(OPTIONVALUED_Xlintfile.length()).trim(); - } - } else if (arg.startsWith(OPTIONVALUED_Xlint)) { - if (arg.length() > OPTIONVALUED_Xlint.length()) { - weaverOption.lint = arg.substring(OPTIONVALUED_Xlint.length()).trim(); - } - } else if (arg.startsWith(OPTIONVALUED_Xset)) { - if (arg.length() > OPTIONVALUED_Xlint.length()) { - weaverOption.xSet = arg.substring(OPTIONVALUED_Xset.length()).trim(); - } - } else { - weaverOption.messageHandler.handleMessage( - new Message( - "Cannot configure weaver with option '" + arg + "': unknown option", - IMessage.WARNING, - null, - null - ) - ); - } - } + // configure the other options + for (Iterator iterator = flags.iterator(); iterator.hasNext();) { + String arg = (String) iterator.next(); + if (arg.equals(OPTION_15)) { + weaverOption.java5 = true; + } else if (arg.equalsIgnoreCase(OPTION_lazyTjp)) { + weaverOption.lazyTjp = true; + } else if (arg.equalsIgnoreCase(OPTION_noinline)) { + weaverOption.noInline = true; + } else if (arg.equalsIgnoreCase(OPTION_addSerialVersionUID)) { + weaverOption.addSerialVersionUID = true; + } else if (arg.equalsIgnoreCase(OPTION_noWarn) || arg.equalsIgnoreCase(OPTION_noWarnNone)) { + weaverOption.noWarn = true; + } else if (arg.equalsIgnoreCase(OPTION_proceedOnError)) { + weaverOption.proceedOnError = true; + } else if (arg.equalsIgnoreCase(OPTION_reweavable)) { + weaverOption.notReWeavable = false; + } else if (arg.equalsIgnoreCase(OPTION_showWeaveInfo)) { + weaverOption.showWeaveInfo = true; + } else if (arg.equalsIgnoreCase(OPTION_hasMember)) { + weaverOption.hasMember = true; + } else if (arg.startsWith(OPTIONVALUED_joinpoints)) { + if (arg.length() > OPTIONVALUED_joinpoints.length()) + weaverOption.optionalJoinpoints = arg.substring(OPTIONVALUED_joinpoints.length()).trim(); + } else if (arg.equalsIgnoreCase(OPTION_verbose)) { + weaverOption.verbose = true; + } else if (arg.equalsIgnoreCase(OPTION_debug)) { + weaverOption.debug = true; + } else if (arg.equalsIgnoreCase(OPTION_pinpoint)) { + weaverOption.pinpoint = true; + } else if (arg.startsWith(OPTIONVALUED_messageHandler)) { + // handled in first round + } else if (arg.startsWith(OPTIONVALUED_Xlintfile)) { + if (arg.length() > OPTIONVALUED_Xlintfile.length()) { + weaverOption.lintFile = arg.substring(OPTIONVALUED_Xlintfile.length()).trim(); + } + } else if (arg.startsWith(OPTIONVALUED_Xlint)) { + if (arg.length() > OPTIONVALUED_Xlint.length()) { + weaverOption.lint = arg.substring(OPTIONVALUED_Xlint.length()).trim(); + } + } else if (arg.startsWith(OPTIONVALUED_Xset)) { + if (arg.length() > OPTIONVALUED_Xlint.length()) { + weaverOption.xSet = arg.substring(OPTIONVALUED_Xset.length()).trim(); + } + } else { + weaverOption.messageHandler.handleMessage(new Message("Cannot configure weaver with option '" + arg + + "': unknown option", IMessage.WARNING, null, null)); + } + } - // refine message handler configuration - if (weaverOption.noWarn) { - weaverOption.messageHandler.ignore(IMessage.WARNING); - } - if (weaverOption.verbose) { - weaverOption.messageHandler.dontIgnore(IMessage.INFO); - } - if (weaverOption.debug) { - weaverOption.messageHandler.dontIgnore(IMessage.DEBUG); - } - if (weaverOption.showWeaveInfo) { - weaverOption.messageHandler.dontIgnore(IMessage.WEAVEINFO); - } + // refine message handler configuration + if (weaverOption.noWarn) { + weaverOption.messageHandler.ignore(IMessage.WARNING); + } + if (weaverOption.verbose) { + weaverOption.messageHandler.dontIgnore(IMessage.INFO); + } + if (weaverOption.debug) { + weaverOption.messageHandler.dontIgnore(IMessage.DEBUG); + } + if (weaverOption.showWeaveInfo) { + weaverOption.messageHandler.dontIgnore(IMessage.WEAVEINFO); + } - return weaverOption; - } + return weaverOption; + } - public static class WeaverOption { + public static class WeaverOption { boolean java5; - boolean lazyTjp; - boolean hasMember; - String optionalJoinpoints; - boolean noWarn; - boolean proceedOnError; - boolean verbose; - boolean debug; - boolean notReWeavable = true;//default to notReweavable for LTW (faster) - boolean noInline; - boolean addSerialVersionUID; - boolean showWeaveInfo; - boolean pinpoint; - IMessageHandler messageHandler; - String lint; - String lintFile; - String xSet; + boolean lazyTjp; + boolean hasMember; + String optionalJoinpoints; + boolean noWarn; + boolean proceedOnError; + boolean verbose; + boolean debug; + boolean notReWeavable = true;// default to notReweavable for LTW (faster) + boolean noInline; + boolean addSerialVersionUID; + boolean showWeaveInfo; + boolean pinpoint; + IMessageHandler messageHandler; + String lint; + String lintFile; + String xSet; - public WeaverOption(IMessageHandler imh) { -// messageHandler = new DefaultMessageHandler();//default - this.messageHandler = imh; - } - } + public WeaverOption(IMessageHandler imh) { + // messageHandler = new DefaultMessageHandler();//default + this.messageHandler = imh; + } + } } diff --git a/loadtime/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java b/loadtime/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java index 2e109527a..727d93501 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java @@ -28,93 +28,92 @@ import org.xml.sax.helpers.XMLReaderFactory; /** * FIXME AV - doc, concrete aspect - * + * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ public class DocumentParser extends DefaultHandler { - /** - * The current DTD public id. The matching dtd will be searched as a resource. - */ - private final static String DTD_PUBLIC_ID = "-//AspectJ//DTD 1.5.0//EN"; + /** + * The current DTD public id. The matching dtd will be searched as a resource. + */ + private final static String DTD_PUBLIC_ID = "-//AspectJ//DTD 1.5.0//EN"; + + /** + * The DTD alias, for better user experience. + */ + private final static String DTD_PUBLIC_ID_ALIAS = "-//AspectJ//DTD//EN"; - /** - * The DTD alias, for better user experience. - */ - private final static String DTD_PUBLIC_ID_ALIAS = "-//AspectJ//DTD//EN"; + /** + * A handler to the DTD stream so that we are only using one file descriptor + */ + private final static InputStream DTD_STREAM = DocumentParser.class.getResourceAsStream("/aspectj_1_5_0.dtd"); - /** - * A handler to the DTD stream so that we are only using one file descriptor - */ - private final static InputStream DTD_STREAM = DocumentParser.class.getResourceAsStream("/aspectj_1_5_0.dtd"); + private final static String ASPECTJ_ELEMENT = "aspectj"; + private final static String WEAVER_ELEMENT = "weaver"; + private final static String DUMP_ELEMENT = "dump"; + private final static String DUMP_BEFOREANDAFTER_ATTRIBUTE = "beforeandafter"; + private final static String INCLUDE_ELEMENT = "include"; + private final static String EXCLUDE_ELEMENT = "exclude"; + private final static String OPTIONS_ATTRIBUTE = "options"; + private final static String ASPECTS_ELEMENT = "aspects"; + private final static String ASPECT_ELEMENT = "aspect"; + private final static String CONCRETE_ASPECT_ELEMENT = "concrete-aspect"; + private final static String NAME_ATTRIBUTE = "name"; + private final static String EXTEND_ATTRIBUTE = "extends"; + private final static String PRECEDENCE_ATTRIBUTE = "precedence"; + private final static String POINTCUT_ELEMENT = "pointcut"; + private final static String WITHIN_ATTRIBUTE = "within"; + private final static String EXPRESSION_ATTRIBUTE = "expression"; - private final static String ASPECTJ_ELEMENT = "aspectj"; - private final static String WEAVER_ELEMENT = "weaver"; - private final static String DUMP_ELEMENT = "dump"; - private final static String DUMP_BEFOREANDAFTER_ATTRIBUTE = "beforeandafter"; - private final static String INCLUDE_ELEMENT = "include"; - private final static String EXCLUDE_ELEMENT = "exclude"; - private final static String OPTIONS_ATTRIBUTE = "options"; - private final static String ASPECTS_ELEMENT = "aspects"; - private final static String ASPECT_ELEMENT = "aspect"; - private final static String CONCRETE_ASPECT_ELEMENT = "concrete-aspect"; - private final static String NAME_ATTRIBUTE = "name"; - private final static String EXTEND_ATTRIBUTE = "extends"; - private final static String PRECEDENCE_ATTRIBUTE = "precedence"; - private final static String POINTCUT_ELEMENT = "pointcut"; - private final static String WITHIN_ATTRIBUTE = "within"; - private final static String EXPRESSION_ATTRIBUTE = "expression"; + private final Definition m_definition; - private final Definition m_definition; + private boolean m_inAspectJ; + private boolean m_inWeaver; + private boolean m_inAspects; - private boolean m_inAspectJ; - private boolean m_inWeaver; - private boolean m_inAspects; + private Definition.ConcreteAspect m_lastConcreteAspect; - private Definition.ConcreteAspect m_lastConcreteAspect; + private DocumentParser() { + m_definition = new Definition(); + } - private DocumentParser() { - m_definition = new Definition(); - } - - public static Definition parse(final URL url) throws Exception { - InputStream in = null; - try { - DocumentParser parser = new DocumentParser(); + public static Definition parse(final URL url) throws Exception { + InputStream in = null; + try { + DocumentParser parser = new DocumentParser(); - XMLReader xmlReader = getXMLReader(); - xmlReader.setContentHandler(parser); - xmlReader.setErrorHandler(parser); + XMLReader xmlReader = getXMLReader(); + xmlReader.setContentHandler(parser); + xmlReader.setErrorHandler(parser); - try { - xmlReader.setFeature("http://xml.org/sax/features/validation", false); - } catch (SAXException e) { - ;//fine, the parser don't do validation - } - try { - xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); - } catch (SAXException e) { - ;//fine, the parser don't do validation - } - try { - xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - } catch (SAXException e) { - ;//fine, the parser don't do validation - } + try { + xmlReader.setFeature("http://xml.org/sax/features/validation", false); + } catch (SAXException e) { + // fine, the parser don't do validation + } + try { + xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); + } catch (SAXException e) { + // fine, the parser don't do validation + } + try { + xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (SAXException e) { + // fine, the parser don't do validation + } + xmlReader.setEntityResolver(parser); + in = url.openStream(); + xmlReader.parse(new InputSource(in)); + return parser.m_definition; + } finally { + try { + in.close(); + } catch (Throwable t) { - xmlReader.setEntityResolver(parser); - in = url.openStream(); - xmlReader.parse(new InputSource(in)); - return parser.m_definition; - } finally { - try { - in.close(); - } catch (Throwable t) { - ; - } - } - } + } + } + } private static XMLReader getXMLReader() throws SAXException, ParserConfigurationException { XMLReader xmlReader = null; @@ -123,7 +122,7 @@ public class DocumentParser extends DefaultHandler { try { xmlReader = XMLReaderFactory.createXMLReader(); } - + /* .. and ignore "System property ... not set" and then try this instead */ catch (SAXException ex) { xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); @@ -131,145 +130,135 @@ public class DocumentParser extends DefaultHandler { return xmlReader; } - public InputSource resolveEntity(String publicId, String systemId) throws SAXException { - if (publicId.equals(DTD_PUBLIC_ID) || publicId.equals(DTD_PUBLIC_ID_ALIAS)) { - InputStream in = DTD_STREAM; - if (in == null) { - System.err.println( - "AspectJ - WARN - could not read DTD " - + publicId - ); - return null; - } else { - return new InputSource(in); - } - } else { - System.err.println( - "AspectJ - WARN - unknown DTD " - + publicId - + " - consider using " - + DTD_PUBLIC_ID - ); - return null; - } - } + public InputSource resolveEntity(String publicId, String systemId) throws SAXException { + if (publicId.equals(DTD_PUBLIC_ID) || publicId.equals(DTD_PUBLIC_ID_ALIAS)) { + InputStream in = DTD_STREAM; + if (in == null) { + System.err.println("AspectJ - WARN - could not read DTD " + publicId); + return null; + } else { + return new InputSource(in); + } + } else { + System.err.println("AspectJ - WARN - unknown DTD " + publicId + " - consider using " + DTD_PUBLIC_ID); + return null; + } + } - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - if (ASPECT_ELEMENT.equals(qName)) { - String name = attributes.getValue(NAME_ATTRIBUTE); - if (!isNull(name)) { - m_definition.getAspectClassNames().add(name); - } - } else if (WEAVER_ELEMENT.equals(qName)) { - String options = attributes.getValue(OPTIONS_ATTRIBUTE); - if (!isNull(options)) { - m_definition.appendWeaverOptions(options); - } - m_inWeaver = true; - } else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { - String name = attributes.getValue(NAME_ATTRIBUTE); - String extend = attributes.getValue(EXTEND_ATTRIBUTE); - String precedence = attributes.getValue(PRECEDENCE_ATTRIBUTE); - if (!isNull(name)) { - if (isNull(precedence) && !isNull(extend)) {//if no precedence, then extends must be there - m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend); - } else if (!isNull(precedence)) { - // wether a pure precedence def, or an extendsANDprecedence def. - m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend, precedence); - } - m_definition.getConcreteAspects().add(m_lastConcreteAspect); - } - } else if (POINTCUT_ELEMENT.equals(qName) && m_lastConcreteAspect != null) { - String name = attributes.getValue(NAME_ATTRIBUTE); - String expression = attributes.getValue(EXPRESSION_ATTRIBUTE); - if (!isNull(name) && !isNull(expression)) { - m_lastConcreteAspect.pointcuts.add(new Definition.Pointcut(name, replaceXmlAnd(expression))); - } - } else if (ASPECTJ_ELEMENT.equals(qName)) { - if (m_inAspectJ) { - throw new SAXException("Found nested <aspectj> element"); - } - m_inAspectJ = true; - } else if (ASPECTS_ELEMENT.equals(qName)) { - m_inAspects = true; - } else if (INCLUDE_ELEMENT.equals(qName) && m_inWeaver) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - m_definition.getIncludePatterns().add(typePattern); - } - } else if (EXCLUDE_ELEMENT.equals(qName) && m_inWeaver) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - m_definition.getExcludePatterns().add(typePattern); - } - } else if (DUMP_ELEMENT.equals(qName) && m_inWeaver) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - m_definition.getDumpPatterns().add(typePattern); - } - String beforeAndAfter = attributes.getValue(DUMP_BEFOREANDAFTER_ATTRIBUTE); - if (isTrue(beforeAndAfter)) { - m_definition.setDumpBefore(true); - } - } else if (EXCLUDE_ELEMENT.equals(qName) && m_inAspects) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - m_definition.getAspectExcludePatterns().add(typePattern); - } - } else if (INCLUDE_ELEMENT.equals(qName) && m_inAspects) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - m_definition.getAspectIncludePatterns().add(typePattern); - } - } else { - throw new SAXException("Unknown element while parsing <aspectj> element: " + qName); - } - super.startElement(uri, localName, qName, attributes); - } + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if (ASPECT_ELEMENT.equals(qName)) { + String name = attributes.getValue(NAME_ATTRIBUTE); + if (!isNull(name)) { + m_definition.getAspectClassNames().add(name); + } + } else if (WEAVER_ELEMENT.equals(qName)) { + String options = attributes.getValue(OPTIONS_ATTRIBUTE); + if (!isNull(options)) { + m_definition.appendWeaverOptions(options); + } + m_inWeaver = true; + } else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { + String name = attributes.getValue(NAME_ATTRIBUTE); + String extend = attributes.getValue(EXTEND_ATTRIBUTE); + String precedence = attributes.getValue(PRECEDENCE_ATTRIBUTE); + if (!isNull(name)) { + if (isNull(precedence) && !isNull(extend)) {// if no precedence, then extends must be there + m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend); + } else if (!isNull(precedence)) { + // wether a pure precedence def, or an extendsANDprecedence def. + m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend, precedence); + } + m_definition.getConcreteAspects().add(m_lastConcreteAspect); + } + } else if (POINTCUT_ELEMENT.equals(qName) && m_lastConcreteAspect != null) { + String name = attributes.getValue(NAME_ATTRIBUTE); + String expression = attributes.getValue(EXPRESSION_ATTRIBUTE); + if (!isNull(name) && !isNull(expression)) { + m_lastConcreteAspect.pointcuts.add(new Definition.Pointcut(name, replaceXmlAnd(expression))); + } + } else if (ASPECTJ_ELEMENT.equals(qName)) { + if (m_inAspectJ) { + throw new SAXException("Found nested <aspectj> element"); + } + m_inAspectJ = true; + } else if (ASPECTS_ELEMENT.equals(qName)) { + m_inAspects = true; + } else if (INCLUDE_ELEMENT.equals(qName) && m_inWeaver) { + String typePattern = getWithinAttribute(attributes); + if (!isNull(typePattern)) { + m_definition.getIncludePatterns().add(typePattern); + } + } else if (EXCLUDE_ELEMENT.equals(qName) && m_inWeaver) { + String typePattern = getWithinAttribute(attributes); + if (!isNull(typePattern)) { + m_definition.getExcludePatterns().add(typePattern); + } + } else if (DUMP_ELEMENT.equals(qName) && m_inWeaver) { + String typePattern = getWithinAttribute(attributes); + if (!isNull(typePattern)) { + m_definition.getDumpPatterns().add(typePattern); + } + String beforeAndAfter = attributes.getValue(DUMP_BEFOREANDAFTER_ATTRIBUTE); + if (isTrue(beforeAndAfter)) { + m_definition.setDumpBefore(true); + } + } else if (EXCLUDE_ELEMENT.equals(qName) && m_inAspects) { + String typePattern = getWithinAttribute(attributes); + if (!isNull(typePattern)) { + m_definition.getAspectExcludePatterns().add(typePattern); + } + } else if (INCLUDE_ELEMENT.equals(qName) && m_inAspects) { + String typePattern = getWithinAttribute(attributes); + if (!isNull(typePattern)) { + m_definition.getAspectIncludePatterns().add(typePattern); + } + } else { + throw new SAXException("Unknown element while parsing <aspectj> element: " + qName); + } + super.startElement(uri, localName, qName, attributes); + } private String getWithinAttribute(Attributes attributes) { return replaceXmlAnd(attributes.getValue(WITHIN_ATTRIBUTE)); } - public void endElement(String uri, String localName, String qName) throws SAXException { - if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { - m_lastConcreteAspect = null; - } else if (ASPECTJ_ELEMENT.equals(qName)) { - m_inAspectJ = false; - } else if (WEAVER_ELEMENT.equals(qName)) { - m_inWeaver = false; - } else if (ASPECTS_ELEMENT.equals(qName)) { - m_inAspects = false; - } - super.endElement(uri, localName, qName); - } - - //TODO AV - define what we want for XML parser error - for now stderr - public void warning(SAXParseException e) throws SAXException { - super.warning(e); - } - - public void error(SAXParseException e) throws SAXException { - super.error(e); - } + public void endElement(String uri, String localName, String qName) throws SAXException { + if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { + m_lastConcreteAspect = null; + } else if (ASPECTJ_ELEMENT.equals(qName)) { + m_inAspectJ = false; + } else if (WEAVER_ELEMENT.equals(qName)) { + m_inWeaver = false; + } else if (ASPECTS_ELEMENT.equals(qName)) { + m_inAspects = false; + } + super.endElement(uri, localName, qName); + } - public void fatalError(SAXParseException e) throws SAXException { - super.fatalError(e); - } + // TODO AV - define what we want for XML parser error - for now stderr + public void warning(SAXParseException e) throws SAXException { + super.warning(e); + } + public void error(SAXParseException e) throws SAXException { + super.error(e); + } - private static String replaceXmlAnd(String expression) { - //TODO AV do we need to handle "..)AND" or "AND(.." ? - return LangUtil.replace(expression, " AND ", " && "); - } + public void fatalError(SAXParseException e) throws SAXException { + super.fatalError(e); + } - private boolean isNull(String s) { - return (s == null || s.length() <= 0); - } + private static String replaceXmlAnd(String expression) { + // TODO AV do we need to handle "..)AND" or "AND(.." ? + return LangUtil.replace(expression, " AND ", " && "); + } - private boolean isTrue(String s) { - return (s != null && s.equals("true")); - } + private boolean isNull(String s) { + return (s == null || s.length() <= 0); + } + private boolean isTrue(String s) { + return (s != null && s.equals("true")); + } } |