View Javadoc

1   package org.sourceforge.jemm.weaver.analysis;
2   
3   import java.util.ArrayList;
4   import java.util.LinkedHashSet;
5   import java.util.List;
6   import java.util.Set;
7   
8   import javassist.CtClass;
9   
10  import org.sourceforge.jemm.weaver.transformation.Transformation;
11  
12  /**
13   * Supports the dependencies between various transformations and determines 
14   * the correct execution order. 
15   * 
16   * @author <a href="mailto:csuml@yahoo.co.uk">Paul Keeble</a>
17   *
18   */
19  public class DependencyManager {
20      Set<Transformation> transforms;
21      LinkedHashSet<Transformation> allPlan;
22      
23      /**
24       * Creates a DependencyManager instance.
25       */
26      public DependencyManager() {
27          transforms = new LinkedHashSet<Transformation>();
28          
29          //using a LinkedHashSet to ensure only unique transformations and maintain execution order
30          //it can not be replaced by another Set implementation, its underlying implementation is necessary
31          //for the algorithm
32          allPlan = new LinkedHashSet<Transformation>();
33      }
34      
35      /**
36       * Adds a transformation to the set for which dependencies are determined.
37       * 
38       * Inserting the same transformation again will do nothing.
39       * 
40       * @param ct The transformation to add
41       */
42      public void addTransformation(Transformation ct) {
43          if(ct == null)
44              throw new IllegalArgumentException("ct may not be null");
45          transforms.add(ct);
46          allPlan.clear();
47      }
48      
49      /**
50       * Removes the instance from the transformation list.
51       * 
52       * @param ct The transformation to remove
53       */
54      public void removeTransformation(Transformation ct) {
55          transforms.remove(ct);
56          allPlan.clear();
57      }
58      
59      /**
60       * Retrieves all the transformations.
61       * 
62       * @return The list of transformations
63       */
64      public Set<Transformation> getTransformations() {
65          return new LinkedHashSet<Transformation>(transforms);
66      }
67      
68      /**
69       * Executes all the dependents of the ClassTransformation so that
70       * t can be executed.
71       * 
72       * @param t The Transformation to find the dependencies from
73       * @param c The class to transform
74       * @throws InvalidDependencyTreeException If the ordering can not be determined, 
75       * such as when a transformations dependencies have not been added.
76       */
77      public void executeDependents(Transformation t, CtClass c,CtClass proxy) {
78          List<Transformation> transforms = getDependencyTree(t);
79          for(Transformation ct : transforms) {
80              ct.transform(c);
81          }
82      }
83      
84      /**
85       * Gets the list of dependencies that need to be executed before t can be run.
86       * 
87       * @param t The transformation that dependencies are needed for.
88       * @return An in order list of the dependent transforms
89       */
90      public List<Transformation> getDependencyTree(Transformation t) {
91          if(t == null)
92              throw new IllegalArgumentException("Class transformation can not be null");
93          
94          List<Transformation> results = new ArrayList<Transformation>();
95          List<String> depClasses = getDependenciesAsStrings(t);
96          
97          for(String dependency : depClasses) {
98              Transformation toAdd = findTransform(dependency);
99              if(!results.contains(toAdd))
100                 results.add(toAdd);
101         }
102         return results;
103     }
104     
105     List<String> getDependenciesAsStrings(Transformation t) {
106         List<String> results = new ArrayList<String>();
107         if(t.dependentTransforms().length ==0) {
108             return results;
109         }
110         
111         for(String dependency : t.dependentTransforms()) {
112             results.addAll(getDependenciesAsStrings(findTransform(dependency)));
113             results.add(dependency);
114         }
115         return results;
116     }
117     
118     /**
119      * Finds the instance of the passed in class.
120      * Note this uses the exact class and not instanceof so subclasses will
121      * not be found.
122      * 
123      * @param clazz the class to search for
124      * @return The transformation
125      * @throws InvalidDependencyTreeException If no such transformation can be found
126      */
127     public Transformation findTransform(String clazz) {
128         for(Transformation t : transforms) {
129             if(t.getTransformationName().equals(clazz))
130                 return t;
131         }
132         
133         throw new InvalidDependencyTreeException("Unable to find transform of class " + clazz);
134     }
135     
136     public TransformationChain getCompleteChain() {
137     	if(allPlan.size()==0) {
138             for(Transformation ct : transforms) {
139                 List<Transformation> transforms = getDependencyTree(ct);
140                 allPlan.addAll(transforms);
141                 allPlan.add(ct);
142             }
143         }
144     	
145     	return new TransformationChain(allPlan.toArray(new Transformation[allPlan.size()]));
146     }
147 }