Package org.jboss.aop.advice

Source Code of org.jboss.aop.advice.PrecedenceGraph$Node

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.aop.advice;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import org.jboss.aop.AspectManager;
import org.jboss.aop.pointcut.ast.ASTCFlowExpression;
import org.jboss.logging.Logger;

/**
*
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
* @version $Revision: 101146 $
*/
public class PrecedenceSorter
{
   private static final Logger logger = Logger.getLogger(PrecedenceSorter.class);
  
   static Comparator<InterceptorEntry> interceptorComparator = new Comparator<InterceptorEntry>()
   {
      public int compare(InterceptorEntry objA, InterceptorEntry objB)
      {
         InterceptorEntry entryA = objA;
         InterceptorEntry entryB = objB;

         return entryA.precedenceOrder - entryB.precedenceOrder;
      }
   };

   static class InterceptorEntry
   {
      Interceptor interceptor;
      ASTCFlowExpression cflow;
      GeneratedAdvisorInterceptor factoryWrapper;
      int originalOrder;
      int precedenceOrder = -1;
      String classname;
      String method;

      InterceptorEntry(GeneratedAdvisorInterceptor factoryWrapper)
      {
         this.factoryWrapper = factoryWrapper;
         classname = factoryWrapper.getName();

         InterceptorFactory ifac = factoryWrapper.getDelegate();

         if (ifac instanceof GenericInterceptorFactory)
         {
            //Dynamically added interceptors
            classname = ((GenericInterceptorFactory)ifac).getClassName();
         }
         else
         {
            AspectFactory af = factoryWrapper.getAspect().getFactory();
            classname = af.getName();
         }

         if (ifac instanceof AdviceFactory)
         {
            method = ((AdviceFactory)ifac).getAdvice();
         }
      }


      InterceptorEntry(Interceptor interceptor)
      {
         this.interceptor = interceptor;

         String interceptorName = null;
         if (interceptor instanceof PerInstanceInterceptor)
         {
            PerInstanceInterceptor icptr = (PerInstanceInterceptor)interceptor;
            interceptorName = icptr.getName();
         }
         else if (interceptor instanceof PerJoinpointInterceptor)
         {
            PerJoinpointInterceptor icptr = (PerJoinpointInterceptor)interceptor;
            interceptorName = icptr.getName();
         }
         else if (interceptor instanceof CFlowInterceptor)
         {
            CFlowInterceptor icptr = (CFlowInterceptor)interceptor;
            interceptorName = icptr.getName();
         }
         else
         {
            interceptorName = interceptor.getClass().getName();
         }

         try
         {
            boolean isAdvice = interceptorName.startsWith("org.jboss.aop.advice.");
            if (isAdvice)
            {
               String name = interceptor.getName();
               int index = name.lastIndexOf(".");
               classname = name.substring(0, index);
               method = name.substring(index + 1);
            }
            else
            {
               classname = interceptorName;
            }
         }
         catch (RuntimeException e)
         {
            logger.error(interceptor.getName());
            throw e;
         }
      }
     
      InterceptorEntry(Interceptor interceptor, ASTCFlowExpression cflow)
      {
         this(interceptor);
         this.cflow = cflow;
      }

      public String toString()
      {
         return "Entry: " + precedenceOrder + " (" + originalOrder + ")interceptorClass=" + classname + "; adviceMethod=" + method;
      }

   }

   private static boolean matches(InterceptorEntry ientry, PrecedenceDefEntry pentry)
   {
      if (ientry.classname != null && pentry.interceptorClass != null)
      {
         if (ientry.classname.equals(pentry.interceptorClass))
         {
            if (ientry.method == null)
            {
               if (pentry.adviceMethod == null)
               {
                  return true;
               }
            }
            else if (pentry.adviceMethod != null)
            {
               //This was:
               //return ientry.classname.equals(pentry.interceptorClass);
               return ientry.method.equals(pentry.adviceMethod);
            }
         }
      }
      return false;
   }


   public static PrecedenceDefEntry[] createOverallPrecedence(AspectManager manager)
   {
      PrecedenceGraph precedenceGraph = new PrecedenceGraph(manager.getPrecedenceDefs().values());
      return precedenceGraph.getSortedPrecedence();
   }

   @Deprecated
   public static ArrayList<PrecedenceDefEntry> mergePrecedenceDef(ArrayList<PrecedenceDefEntry> overall, PrecedenceDef precedenceDef)
   {
      // This method does not follow the improved algorithm used on PrecedenceGraph.
      // If you have the precedences
      //    1) A, D
      //    2) C, E
      //    3) C, D
      //After adding 2) to 1) since there is no relationship defined you get:
      //    i) A, D, C, E
      //After adding 3) to i) you end up with an overall precedence of
      //    ii) A, C, D, C, E,
      //In practice this should be fine, since the applyPrecedence() looks for the
      //first matching entry, so the second (duplicate) occurrence of C is ignored.
      PrecedenceDefEntry[] entries = precedenceDef.getEntries();
      int start = 0, end = 0;
      int size = overall.size();
      for (int i = 0 ; i < size ; i++)
      {
         PrecedenceDefEntry global = overall.get(i);
         boolean found = false;

         //find current overall precedence entry in the new set of defs
         for (int j = start ; j < entries.length ; j++)
         {
            PrecedenceDefEntry cur = entries[j];

            if (cur.equals(global))
            {
               found = true;
               end = j;
               break;
            }
         }

         //We found it. Now insert everything until this into global and
         //reset the counters
         if (found)
         {
            int insert = i;
            for (int j = start ; j < end ; j++)
            {
               overall.add(insert++, entries[j]);
            }
            end++;
            start = end;
         }
      }

      for (int j = start ; j < entries.length ; j++)
      {
         overall.add(entries[j]);
      }

      return overall;
   }

   public static Interceptor[] applyPrecedence(Interceptor[] interceptors, AspectManager manager)
   {
      if (interceptors.length == 0)
         return interceptors;

      ArrayList<InterceptorEntry> all = new ArrayList<InterceptorEntry>(interceptors.length);
      ArrayList<InterceptorEntry> precedence = new ArrayList<InterceptorEntry>(interceptors.length);
      PrecedenceDefEntry[] precedenceEntries = manager.getSortedPrecedenceDefEntries();
      boolean cflowFound = false;
      //Figure out what interceptors have precedence
      for (int i = 0 ; i < interceptors.length ; i++)
      {
         InterceptorEntry[] interceptorEntries;
         ASTCFlowExpression cflow = null;
         // Break cflow interceptor into separate interceptor units
         if (interceptors[i] instanceof CFlowInterceptor)
         {
            cflowFound = true;
            CFlowInterceptor cflowInterceptor = (CFlowInterceptor) interceptors[i];
            cflow = cflowInterceptor.getExpr();
            interceptorEntries = new InterceptorEntry[cflowInterceptor.getChain().length];
            for (int j = 0; j < interceptorEntries.length; j++)
            {
               interceptorEntries[j] = new InterceptorEntry(cflowInterceptor.getChain()[j], cflow);
               all.add(interceptorEntries[j]);
            }
         }
         else
         {
            interceptorEntries = new InterceptorEntry[]{new InterceptorEntry(interceptors[i])};
            all.add(interceptorEntries[0]);
         }
         for (int k = 0; k < interceptorEntries.length; k++)
         {
            InterceptorEntry interceptorEntry = interceptorEntries[k];
            for (int j = 0 ; j < precedenceEntries.length ; j++)
            {
               if (matches(interceptorEntry, precedenceEntries[j]))
               {
                  //This interceptor is defined in the precedence
                  interceptorEntry.originalOrder = all.size() - interceptorEntries.length + k;
                  interceptorEntry.precedenceOrder = j;
                  precedence.add(interceptorEntry);
                  break;
               }
            }
         }
      }

      //Sort the interceptors having precedence
      Collections.sort(precedence, interceptorComparator);
      Interceptor[] sortedInterceptors = new Interceptor[all.size()];
      ASTCFlowExpression[] sortedCFlows = new ASTCFlowExpression[all.size()];

      //Build up new array of interceptors depending on their precedence
      int prec = 0;
      int allSize = all.size();
      int precedenceSize = precedence.size();

      for (int i = 0 ; i < allSize ; i++)
      {
         InterceptorEntry entry = all.get(i);

         if (entry.precedenceOrder >= 0 && prec < precedenceSize)
         {
            entry = precedence.get(prec++);
         }
         sortedInterceptors[i] = entry.interceptor;
         sortedCFlows[i] = entry.cflow;
      }
      if (cflowFound)
      {
         return new Interceptor[]{new SortedCFlowInterceptor(
               sortedInterceptors, sortedCFlows)};
      }
      return sortedInterceptors;
   }

   public static GeneratedAdvisorInterceptor[] applyPrecedence(GeneratedAdvisorInterceptor[] interceptors, AspectManager manager)
   {
      ArrayList<InterceptorEntry> all = new ArrayList<InterceptorEntry>(interceptors.length);
      ArrayList<InterceptorEntry> precedence = new ArrayList<InterceptorEntry>(interceptors.length);
      PrecedenceDefEntry[] precedenceEntries = manager.getSortedPrecedenceDefEntries();

      //Figure out what interceptors have precedence
      for (int i = 0 ; i < interceptors.length ; i++)
      {
         InterceptorEntry interceptorEntry = new InterceptorEntry(interceptors[i]);
         all.add(interceptorEntry);
         for (int j = 0 ; j < precedenceEntries.length ; j++)
         {
            if (matches(interceptorEntry, precedenceEntries[j]))
            {
               //This interceptor is defined in the precedence
               interceptorEntry.originalOrder = i;
               interceptorEntry.precedenceOrder = j;
               precedence.add(interceptorEntry);
               break;
            }
         }
      }

      //Sort the interceptors having precedence
      Collections.sort(precedence, interceptorComparator);
      GeneratedAdvisorInterceptor[] sortedInterceptors = new GeneratedAdvisorInterceptor[interceptors.length];

      //Build up new array of interceptors depending on their precedence
      int prec = 0;
      int allSize = all.size();
      int precedenceSize = precedence.size();

      for (int i = 0 ; i < allSize ; i++)
      {
         InterceptorEntry entry = all.get(i);

         if (entry.precedenceOrder >= 0 && prec < precedenceSize)
         {
            entry = precedence.get(prec++);
         }
         sortedInterceptors[i] = entry.factoryWrapper;
      }

      return sortedInterceptors;
   }

/* public static void main(String[] args)
   {
      System.out.println("Hello");
      AspectManager manager = new AspectManager();
      PrecedenceDef def = new PrecedenceDef("3",new PrecedenceDefEntry[]{
            new PrecedenceDefEntry("A", null),
           new PrecedenceDefEntry("D", null)});
      manager.addPrecedence(def);
      outputOverAll(manager);

      def = new PrecedenceDef("4",new PrecedenceDefEntry[]{
            new PrecedenceDefEntry("C", null),
            new PrecedenceDefEntry("E", null)});
      manager.addPrecedence(def);
      outputOverAll(manager);

      def = new PrecedenceDef("5",new PrecedenceDefEntry[]{
            new PrecedenceDefEntry("C", null),
            new PrecedenceDefEntry("D", null)});
      manager.addPrecedence(def);
      outputOverAll(manager);
     
      def = new PrecedenceDef("6",new PrecedenceDefEntry[]{
            new PrecedenceDefEntry("E", null),
            new PrecedenceDefEntry("C", null)});
      manager.addPrecedence(def);
      outputOverAll(manager);

   }

   private static void outputOverAll(AspectManager manager)
   {
      PrecedenceDefEntry[] entries = manager.getSortedPrecedenceDefEntries();
      for (int i = 0 ; i < entries.length ; i++)
      {
         System.out.println("\t" + entries[i]);
      }
      System.out.println("==================================");
   }
*/
}

class PrecedenceGraph
{
   private Map<PrecedenceDefEntry, Node> nodes;
  
   public PrecedenceGraph(Collection<PrecedenceDef> precedenceDefs)
   {
      nodes = new HashMap<PrecedenceDefEntry, Node>();
      for(PrecedenceDef precedence: precedenceDefs)
      {
         PrecedenceDefEntry[] entries = precedence.getEntries();
         if (entries.length < 2)
         {
            continue;
         }
         Node node1 = createNode(entries[0]);
         for (int i = 1; i < entries.length; i++)
         {
            Node node2 = createNode(entries[i]);
            node1.addNextNode(node2);
            node1 = node2;
         }
      }
   }
  
   private Node createNode(PrecedenceDefEntry entry)
   {
      Node node = nodes.get(entry);
      if (node == null)
      {
         node = new Node(entry);
         nodes.put(entry, node);
      }
      return node;
   }
  
   public PrecedenceDefEntry[] getSortedPrecedence()
   {
      PrecedenceDefEntry[] overallPrecedence = new PrecedenceDefEntry[nodes.size()];
      int i = 0;
      for (Node node: nodes.values())
      {
         // work only with the first nodes of precedence chains
         if (node.hasPreviousNode() || node.isVisited())
         {
            continue;
         }
         i = node.addSortedPrecedence(overallPrecedence, i);
         if (i == overallPrecedence.length)
         {
            break;
         }
      }
      return overallPrecedence;
   }
  
   private static class Node
   {
      private enum SearchStatus {NOT_VISITED, VISITING, VISITED, CLEARED};
      private PrecedenceDefEntry precedenceEntry;
      private SearchStatus searchStatus;
     
      private Collection<Node> next;
      private Collection<Node> previous;
     
      public Node(PrecedenceDefEntry precedenceEntry)
      {
         this.precedenceEntry = precedenceEntry;
         this.searchStatus = SearchStatus.NOT_VISITED;
         this.next = new ArrayList<Node>();
         this.previous = new ArrayList<Node>();
      }
     

      public boolean hasPreviousNode()
      {
         return !this.previous.isEmpty();
      }
     
      public boolean isVisited()
      {
         return searchStatus != SearchStatus.NOT_VISITED;
      }
     
      public void addNextNode(Node node)
      {
         if (!next.contains(node))
         {
            for (Node previousNode: previous)
            {
               previousNode.removeEdge(node);
            }
            next.add(node);
            node.previous.add(this);
         }
      }
     
      public int addSortedPrecedence(PrecedenceDefEntry[] sortedPrecedence, int index)
      {
         switch (searchStatus)
         {
            case NOT_VISITED:
               this.searchStatus = SearchStatus.VISITING;
               if (!previous.isEmpty())
               {
                  for (Node node: previous)
                  {
                     if (!node.isVisited())
                     {
                        index = node.addSortedPrecedence(sortedPrecedence, index);
                     }
                  }
               }
               this.searchStatus = SearchStatus.VISITED;
               sortedPrecedence[index++] = precedenceEntry;
               boolean cleared = true;
               for (Node node: next)
               {
                  int newIndex = node.addSortedPrecedence(sortedPrecedence, index);
                  if (newIndex == -1)
                  {
                     cleared = false;
                  }
                  else
                  {
                     index = newIndex;
                  }
               }
               if (cleared)
               {
                  searchStatus = SearchStatus.CLEARED;
               }
               break;
            case VISITING:
               // warn that this method is returning without processing the branch
               index = -1;
               break;
            case VISITED:
               throw new RuntimeException("The specified advice precedence rules contain an invalid cyclic dependency");
            case CLEARED:
               // do nothing, this branch of the graph is already cleared
               break;
         }
         return index;
      }
     
      private void removeEdge(Node node)
      {
         next.remove(node);
         node.previous.remove(this);
         // create an auxiliary collection to avoid concurrent modification
         Collection<Node> toRemove = new ArrayList<Node>();
         for (Node previousNode: previous)
         {
            toRemove.add(previousNode);
         }
         for (Node previousNode:toRemove)
         {
            previousNode.removeEdge(node);
         }
      }
     
      public int hashCode()
      {
         return precedenceEntry.hashCode();
      }
     
      public boolean equals(Node other)
      {
         return precedenceEntry.equals(other);
      }
   }
}
TOP

Related Classes of org.jboss.aop.advice.PrecedenceGraph$Node

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.