Logo Search packages:      
Sourcecode: aspectj version File versions  Download package

CrosscuttingMembersSet.java

/* *******************************************************************
 * Copyright (c) 2002-2009 Contributors
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver;

import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.weaver.patterns.Declare;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.DeclareParents;
import org.aspectj.weaver.patterns.DeclareSoft;
import org.aspectj.weaver.patterns.IVerificationRequired;
import org.aspectj.weaver.tools.Trace;
import org.aspectj.weaver.tools.TraceFactory;

/**
 * This holds on to all CrosscuttingMembers for a world. It handles management of change.
 * 
 * @author Jim Hugunin
 * @author Andy Clement
 */
00039 public class CrosscuttingMembersSet {

      private static Trace trace = TraceFactory.getTraceFactory().getTrace(CrosscuttingMembersSet.class);

      private transient World world;

      // FIXME AV - ? we may need a sequencedHashMap there to ensure source based precedence for @AJ advice
      private final Map /* ResolvedType (the aspect) > CrosscuttingMembers */<ResolvedType, CrosscuttingMembers> members = new HashMap<ResolvedType, CrosscuttingMembers>();

      // List of things to be verified once the type system is 'complete'
      private transient List /* IVerificationRequired */<IVerificationRequired> verificationList = null;

      private List<ShadowMunger> shadowMungers = null;
      private List<ConcreteTypeMunger> typeMungers = null;
      private List<ConcreteTypeMunger> lateTypeMungers = null;
      private List<DeclareSoft> declareSofts = null;
      private List<DeclareParents> declareParents = null;
      private List<DeclareAnnotation> declareAnnotationOnTypes = null;
      private List<DeclareAnnotation> declareAnnotationOnFields = null;
      private List<DeclareAnnotation> declareAnnotationOnMethods = null; // includes constructors
      private List<Declare> declareDominates = null;
      private boolean changedSinceLastReset = false;

      public CrosscuttingMembersSet(World world) {
            this.world = world;
      }

      public boolean addOrReplaceAspect(ResolvedType aspectType) {
            return addOrReplaceAspect(aspectType, true);
      }

      /**
       * @return whether or not that was a change to the global signature XXX for efficiency we will need a richer representation than
       *         this
       */
00074       public boolean addOrReplaceAspect(ResolvedType aspectType, boolean inWeavingPhase) {

            if (!world.isAspectIncluded(aspectType)) {
                  return false;
            }

            boolean change = false;
            CrosscuttingMembers xcut = members.get(aspectType);
            if (xcut == null) {
                  members.put(aspectType, aspectType.collectCrosscuttingMembers(inWeavingPhase));
                  clearCaches();
                  change = true;
            } else {
                  if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(inWeavingPhase), inWeavingPhase)) {
                        clearCaches();
                        change = true;
                  } else {
                        if (inWeavingPhase) {
                              // bug 134541 - even though we haven't changed we may have updated the
                              // sourcelocation for the shadowMunger which we need to pick up
                              shadowMungers = null;
                        }
                        change = false;
                  }
            }
            if (aspectType.isAbstract()) {
                  // we might have sub-aspects that need to re-collect their crosscutting members from us
                  boolean ancestorChange = addOrReplaceDescendantsOf(aspectType, inWeavingPhase);
                  change = change || ancestorChange;
            }
            changedSinceLastReset = changedSinceLastReset || change;

            return change;
      }

      private boolean addOrReplaceDescendantsOf(ResolvedType aspectType, boolean inWeavePhase) {
            // System.err.println("Looking at descendants of "+aspectType.getName());
            Set<ResolvedType> knownAspects = members.keySet();
            Set<ResolvedType> toBeReplaced = new HashSet<ResolvedType>();
            for (Iterator<ResolvedType> it = knownAspects.iterator(); it.hasNext();) {
                  ResolvedType candidateDescendant = it.next();
                  if ((candidateDescendant != aspectType) && (aspectType.isAssignableFrom(candidateDescendant))) {
                        toBeReplaced.add(candidateDescendant);
                  }
            }
            boolean change = false;
            for (Iterator<ResolvedType> it = toBeReplaced.iterator(); it.hasNext();) {
                  ResolvedType next = it.next();
                  boolean thisChange = addOrReplaceAspect(next, inWeavePhase);
                  change = change || thisChange;
            }
            return change;
      }

      public void addAdviceLikeDeclares(ResolvedType aspectType) {
            if (!members.containsKey(aspectType)) {
                  return;
            }
            CrosscuttingMembers xcut = members.get(aspectType);
            xcut.addDeclares(aspectType.collectDeclares(true));
      }

      public boolean deleteAspect(UnresolvedType aspectType) {
            boolean isAspect = members.remove(aspectType) != null;
            clearCaches();
            return isAspect;
      }

      public boolean containsAspect(UnresolvedType aspectType) {
            return members.containsKey(aspectType);
      }

      // XXX only for testing
      public void addFixedCrosscuttingMembers(ResolvedType aspectType) {
            members.put(aspectType, aspectType.crosscuttingMembers);
            clearCaches();
      }

      private void clearCaches() {
            shadowMungers = null;
            typeMungers = null;
            lateTypeMungers = null;
            declareSofts = null;
            declareParents = null;
            declareAnnotationOnFields = null;
            declareAnnotationOnMethods = null;
            declareAnnotationOnTypes = null;
            declareDominates = null;
      }

      public List<ShadowMunger> getShadowMungers() {
            if (shadowMungers == null) {
                  List<ShadowMunger> ret = new ArrayList<ShadowMunger>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getShadowMungers());
                  }
                  shadowMungers = ret;
            }
            return shadowMungers;
      }

      public List<ConcreteTypeMunger> getTypeMungers() {
            if (typeMungers == null) {
                  List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getTypeMungers());
                  }
                  typeMungers = ret;
            }
            return typeMungers;
      }

      public List<ConcreteTypeMunger> getLateTypeMungers() {
            if (lateTypeMungers == null) {
                  List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getLateTypeMungers());
                  }
                  lateTypeMungers = ret;
            }
            return lateTypeMungers;
      }

      public List<DeclareSoft> getDeclareSofts() {
            if (declareSofts == null) {
                  Set<DeclareSoft> ret = new HashSet<DeclareSoft>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getDeclareSofts());
                  }
                  declareSofts = new ArrayList<DeclareSoft>();
                  declareSofts.addAll(ret);
            }
            return declareSofts;
      }

      public List<DeclareParents> getDeclareParents() {
            if (declareParents == null) {
                  Set<DeclareParents> ret = new HashSet<DeclareParents>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getDeclareParents());
                  }
                  declareParents = new ArrayList<DeclareParents>();
                  declareParents.addAll(ret);
            }
            return declareParents;
      }

      // DECAT Merge multiple together
      public List<DeclareAnnotation> getDeclareAnnotationOnTypes() {
            if (declareAnnotationOnTypes == null) {
                  Set<DeclareAnnotation> ret = new HashSet<DeclareAnnotation>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getDeclareAnnotationOnTypes());
                  }
                  declareAnnotationOnTypes = new ArrayList<DeclareAnnotation>();
                  declareAnnotationOnTypes.addAll(ret);
            }
            return declareAnnotationOnTypes;
      }

      public List<DeclareAnnotation> getDeclareAnnotationOnFields() {
            if (declareAnnotationOnFields == null) {
                  Set<DeclareAnnotation> ret = new HashSet<DeclareAnnotation>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getDeclareAnnotationOnFields());
                  }
                  declareAnnotationOnFields = new ArrayList<DeclareAnnotation>();
                  declareAnnotationOnFields.addAll(ret);
            }
            return declareAnnotationOnFields;
      }

      /**
       * Return an amalgamation of the declare @method/@constructor statements.
       */
00249       public List<DeclareAnnotation> getDeclareAnnotationOnMethods() {
            if (declareAnnotationOnMethods == null) {
                  Set<DeclareAnnotation> ret = new HashSet<DeclareAnnotation>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getDeclareAnnotationOnMethods());
                  }
                  declareAnnotationOnMethods = new ArrayList<DeclareAnnotation>();
                  declareAnnotationOnMethods.addAll(ret);
            }
            return declareAnnotationOnMethods;
      }

      public List<Declare> getDeclareDominates() {
            if (declareDominates == null) {
                  List<Declare> ret = new ArrayList<Declare>();
                  for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
                        ret.addAll(i.next().getDeclareDominates());
                  }
                  declareDominates = ret;
            }
            return declareDominates;
      }

      public ResolvedType findAspectDeclaringParents(DeclareParents p) {
            Set<ResolvedType> keys = this.members.keySet();
            for (Iterator<ResolvedType> iter = keys.iterator(); iter.hasNext();) {
                  ResolvedType element = iter.next();
                  for (Iterator i = members.get(element).getDeclareParents().iterator(); i.hasNext();) {
                        DeclareParents dp = (DeclareParents) i.next();
                        if (dp.equals(p)) {
                              return element;
                        }
                  }
            }
            return null;
      }

      public void reset() {
            verificationList = null;
            changedSinceLastReset = false;
      }

      public boolean hasChangedSinceLastReset() {
            return changedSinceLastReset;
      }

      /**
       * Record something that needs verifying when we believe the type system is complete. Used for things that can't be verified as
       * we go along - for example some recursive type variable references (pr133307)
       */
00299       public void recordNecessaryCheck(IVerificationRequired verification) {
            if (verificationList == null) {
                  verificationList = new ArrayList<IVerificationRequired>();
            }
            verificationList.add(verification);
      }

      /**
       * Called when type bindings are complete - calls all registered verification objects in turn.
       */
00309       public void verify() {
            if (verificationList == null) {
                  return;
            }
            for (Iterator<IVerificationRequired> iter = verificationList.iterator(); iter.hasNext();) {
                  IVerificationRequired element = iter.next();
                  element.verify();
            }
            verificationList = null;
      }

      public int serializationVersion = 1;

      public void write(DataOutputStream stream) throws IOException {
            // stream.writeInt(serializationVersion);
            stream.writeInt(shadowMungers.size());
            for (Iterator iterator = shadowMungers.iterator(); iterator.hasNext();) {
                  ShadowMunger shadowMunger = (ShadowMunger) iterator.next();
                  shadowMunger.write(stream);
            }
            // // private List /* ShadowMunger */shadowMungers = null;
            // // private List typeMungers = null;
            // // private List lateTypeMungers = null;
            // // private List declareSofts = null;
            // // private List declareParents = null;
            // // private List declareAnnotationOnTypes = null;
            // // private List declareAnnotationOnFields = null;
            // // private List declareAnnotationOnMethods = null; // includes constructors
            // // private List declareDominates = null;
            // // private boolean changedSinceLastReset = false;
            //
      }
}

Generated by  Doxygen 1.6.0   Back to index