]> source.dussan.org Git - aspectj.git/commitdiff
124460: simple basic control of weaving via aop.xml
authoraclement <aclement>
Mon, 9 Feb 2009 20:13:01 +0000 (20:13 +0000)
committeraclement <aclement>
Mon, 9 Feb 2009 20:13:01 +0000 (20:13 +0000)
weaver/src/aspectj_1_5_0.dtd
weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java
weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java

index 1b776242af99db49a37a20f290477db7044859c8..872afd6c3bd36ef648754982d0beee484fa69dfd 100644 (file)
@@ -106,6 +106,7 @@ aspect
 <!ELEMENT aspect EMPTY>
 <!ATTLIST aspect
     name CDATA #REQUIRED
+    scope CDATA #IMPLIED
 >
 <!--*****************************************************************************************************************************
 exclude
index b2307d006c967d48d000da4267444e4208e54179..91125ff71bd772258002f0bc328f93231a0083c7 100644 (file)
@@ -18,8 +18,10 @@ import java.io.IOException;
 import java.lang.reflect.Modifier;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.StringTokenizer;
 
 import org.aspectj.apache.bcel.Constants;
@@ -45,6 +47,7 @@ import org.aspectj.bridge.IMessage;
 import org.aspectj.bridge.IMessageHandler;
 import org.aspectj.bridge.ISourceLocation;
 import org.aspectj.bridge.Message;
+import org.aspectj.bridge.MessageUtil;
 import org.aspectj.bridge.WeaveMessage;
 import org.aspectj.weaver.Advice;
 import org.aspectj.weaver.AdviceKind;
@@ -73,6 +76,8 @@ import org.aspectj.weaver.loadtime.definition.DocumentParser;
 import org.aspectj.weaver.model.AsmRelationshipProvider;
 import org.aspectj.weaver.patterns.DeclareAnnotation;
 import org.aspectj.weaver.patterns.DeclareParents;
+import org.aspectj.weaver.patterns.PatternParser;
+import org.aspectj.weaver.patterns.TypePattern;
 import org.aspectj.weaver.tools.Trace;
 import org.aspectj.weaver.tools.TraceFactory;
 
@@ -82,7 +87,8 @@ public class BcelWorld extends World implements Repository {
        protected Repository delegate;
        private BcelWeakClassLoaderReference loaderRef;
        private final BcelWeavingSupport bcelWeavingSupport = new BcelWeavingSupport();
-       private List/* File */xmlFiles;
+       private boolean isXmlConfiguredWorld = false;
+       private WeavingXmlConfig xmlConfiguration;
 
        private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWorld.class);
 
@@ -563,6 +569,12 @@ public class BcelWorld extends World implements Repository {
         * BcelObjectType - this happens quite often when incrementally compiling.
         */
        public static BcelObjectType getBcelObjectType(ResolvedType concreteAspect) {
+               if (concreteAspect == null) {
+                       return null;
+               }
+               if (!(concreteAspect instanceof ReferenceType)) { // Might be Missing
+                       return null;
+               }
                ReferenceTypeDelegate rtDelegate = ((ReferenceType) concreteAspect).getDelegate();
                if (rtDelegate instanceof BcelObjectType) {
                        return (BcelObjectType) rtDelegate;
@@ -799,17 +811,23 @@ public class BcelWorld extends World implements Repository {
         * @param xmlFiles list of File objects representing any aop.xml files passed in to configure the build process
         */
        public void setXmlFiles(List xmlFiles) {
-               this.xmlFiles = xmlFiles;
+               if (!xmlFiles.isEmpty()) {
+                       isXmlConfiguredWorld = true;
+                       xmlConfiguration = new WeavingXmlConfig(this);
+               }
                for (Iterator iterator = xmlFiles.iterator(); iterator.hasNext();) {
                        File xmlfile = (File) iterator.next();
                        try {
                                Definition d = DocumentParser.parse(xmlfile.toURI().toURL());
-                               xmlAspectNames.addAll(d.getAspectClassNames());
-                               isXmlConfiguredWorld = true;
+                               xmlConfiguration.add(d);
                        } catch (MalformedURLException e) {
-                               e.printStackTrace();
+                               getMessageHandler().handleMessage(
+                                               MessageUtil.error("Unexpected problem processing XML config file '" + xmlfile.getName() + "' :"
+                                                               + e.getMessage()));
                        } catch (Exception e) {
-                               e.printStackTrace();
+                               getMessageHandler().handleMessage(
+                                               MessageUtil.error("Unexpected problem processing XML config file '" + xmlfile.getName() + "' :"
+                                                               + e.getMessage()));
                        }
                }
        }
@@ -818,11 +836,96 @@ public class BcelWorld extends World implements Repository {
                return isXmlConfiguredWorld;
        }
 
-       // public boolean specifiesInclusionOfAspect(String name) {
-       // return xmlAspectNames.contains(name);
-       // }
+       public boolean isAspectIncluded(ResolvedType aspectType) {
+               if (!isXmlConfigured()) {
+                       return true;
+               }
+               return xmlConfiguration.specifiesInclusionOfAspect(aspectType.getName());
+       }
 
-       private boolean isXmlConfiguredWorld = false;
-       private List/* String */xmlAspectNames = new ArrayList();
+       public TypePattern getAspectScope(ResolvedType declaringType) {
+               return xmlConfiguration.getScopeFor(declaringType.getName());
+       }
+
+       /**
+        * A WeavingXmlConfig is initially a collection of definitions from XML files - once the world is ready and weaving is running
+        * it will initialize and transform those definitions into an optimized set of values (eg. resolve type patterns and string
+        * names to real entities). It can then answer questions quickly: (1) is this aspect included in the weaving? (2) Is there a
+        * scope specified for this aspect and does it include type X?
+        * 
+        */
+       static class WeavingXmlConfig {
+
+               private boolean initialized = false; // Lazily done
+               private List/* Definition */definitions = new ArrayList();
+
+               private List/* <String> */resolvedIncludedAspects = new ArrayList();
+               private Map/* <String,TypePattern> */scopes = new HashMap();
+
+               private BcelWorld world;
+
+               public WeavingXmlConfig(BcelWorld bcelWorld) {
+                       this.world = bcelWorld;
+               }
+
+               public void add(Definition d) {
+                       definitions.add(d);
+               }
+
+               public void ensureInitialized() {
+                       if (!initialized) {
+                               try {
+                                       resolvedIncludedAspects = new ArrayList();
+                                       // Process the definitions into something more optimal
+                                       for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
+                                               Definition definition = (Definition) iterator.next();
+                                               List/* String */aspectNames = definition.getAspectClassNames();
+                                               for (Iterator iterator2 = aspectNames.iterator(); iterator2.hasNext();) {
+                                                       String name = (String) iterator2.next();
+                                                       resolvedIncludedAspects.add(name);
+                                                       // TODO check for existence?
+                                                       // ResolvedType resolvedAspect = resolve(UnresolvedType.forName(name));
+                                                       // if (resolvedAspect.isMissing()) {
+                                                       // // ERROR
+                                                       // } else {
+                                                       // resolvedIncludedAspects.add(resolvedAspect);
+                                                       // }
+                                                       String scope = definition.getScopeForAspect(name);
+                                                       if (scope != null) {
+                                                               // Resolve the type pattern
+                                                               try {
+                                                                       TypePattern scopePattern = new PatternParser(scope).parseTypePattern();
+                                                                       scopePattern.resolve(world);
+                                                                       scopes.put(name, scopePattern);
+                                                                       if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
+                                                                               world.getMessageHandler().handleMessage(
+                                                                                               MessageUtil.info("Aspect '" + name
+                                                                                                               + "' is scoped to apply against types matching pattern '"
+                                                                                                               + scopePattern.toString() + "'"));
+                                                                       }
+                                                               } catch (Exception e) {
+                                                                       // TODO definitions should remember which file they came from, for inclusion in this message
+                                                                       world.getMessageHandler().handleMessage(
+                                                                                       MessageUtil.error("Unable to parse scope as type pattern.  Scope was '" + scope + "': "
+                                                                                                       + e.getMessage()));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               } finally {
+                                       initialized = true;
+                               }
+                       }
+               }
+
+               public boolean specifiesInclusionOfAspect(String name) {
+                       ensureInitialized();
+                       return resolvedIncludedAspects.contains(name);
+               }
+
+               public TypePattern getScopeFor(String name) {
+                       return (TypePattern) scopes.get(name);
+               }
+       }
 
-}
\ No newline at end of file
+}
index 7b6da954e5d8a03f96f86b959b6dfed27e4a892a..6328aefd829c041b394586c70a1e1ccfd803e61b 100644 (file)
@@ -12,7 +12,9 @@
 package org.aspectj.weaver.loadtime.definition;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A POJO that contains raw strings from the XML (sort of XMLBean for our simple LTW DTD)
@@ -41,6 +43,11 @@ public class Definition {
 
        private final List m_concreteAspects;
 
+       /**
+        * When aspects are defined, they can specify a scope type pattern and then will only apply to types matching that pattern.
+        */
+       private final Map scopedAspects;
+
        public Definition() {
                m_weaverOptions = new StringBuffer();
                m_dumpBefore = false;
@@ -52,6 +59,7 @@ public class Definition {
                m_aspectExcludePatterns = new ArrayList(0);
                m_aspectIncludePatterns = new ArrayList(0);
                m_concreteAspects = new ArrayList(0);
+               scopedAspects = new HashMap();
        }
 
        public String getWeaverOptions() {
@@ -144,4 +152,12 @@ public class Definition {
                m_weaverOptions.append(option.trim()).append(' ');
        }
 
+       public void addScopedAspect(String name, String scopePattern) {
+               scopedAspects.put(name, scopePattern);
+       }
+
+       public String getScopeForAspect(String name) {
+               return (String) scopedAspects.get(name);
+       }
+
 }
index 101fcbaa721d36f6984da53a191a82ad0aa0b6c8..b05f92685f1b950f191b4fe5ebd0b00656746902 100644 (file)
@@ -60,6 +60,7 @@ public class DocumentParser extends DefaultHandler {
        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 SCOPE_ATTRIBUTE = "scope";
        private final static String EXTEND_ATTRIBUTE = "extends";
        private final static String PRECEDENCE_ATTRIBUTE = "precedence";
        private final static String PERCLAUSE_ATTRIBUTE = "perclause";
@@ -150,8 +151,12 @@ public class DocumentParser extends DefaultHandler {
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                if (ASPECT_ELEMENT.equals(qName)) {
                        String name = attributes.getValue(NAME_ATTRIBUTE);
+                       String scopePattern = replaceXmlAnd(attributes.getValue(SCOPE_ATTRIBUTE));
                        if (!isNull(name)) {
                                m_definition.getAspectClassNames().add(name);
+                               if (scopePattern != null) {
+                                       m_definition.addScopedAspect(name, scopePattern);
+                               }
                        }
                } else if (WEAVER_ELEMENT.equals(qName)) {
                        String options = attributes.getValue(OPTIONS_ATTRIBUTE);