View Javadoc

1   /** 2007, Digitalis Informatica. All rights reserved.
2    *
3    * Distribuicao e Gestao de Informatica, Lda.
4    * Estrada de Paco de Arcos num.9 - Piso -1
5    * 2780-666 Paco de Arcos
6    * Telefone: (351) 21 4408990
7    * Fax: (351) 21 4408999
8    * http://www.digitalis.pt
9    */
10  package pt.digitalis.dif.codegen.util;
11  
12  import java.util.ArrayList;
13  import java.util.HashMap;
14  import java.util.List;
15  import java.util.Map;
16  
17  import pt.digitalis.dif.startup.DIFStartupConfiguration;
18  import pt.digitalis.dif.utils.ObjectFormatter;
19  import pt.digitalis.log.LogLevel;
20  import pt.digitalis.utils.bytecode.exceptions.CodeGenerationException;
21  import pt.digitalis.utils.bytecode.holders.ClassHolder;
22  import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
23  
24  /**
25   * Defines a class enhancement object.
26   *
27   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
28   * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a><br/>
29   * @created Dec 10, 2007
30   */
31  public class ClassEnhancements {
32  
33      /** The class name for all entries. */
34      private String className;
35  
36      /** List of incremental methods. */
37      private List<String> incrementalMethods = new ArrayList<String>();
38  
39      /** The entries for all methods to enhance. */
40      private Map<String, ClassMethodEnhancement> methodEnhancements = new HashMap<String, ClassMethodEnhancement>();
41  
42      /** The class holder for the enhanced object. */
43      private ClassHolder theClassObject;
44  
45      /**
46       * Builds a class enhancements object from the class name.
47       *
48       * @param clazz
49       *            the class to be enhanced
50       */
51      public ClassEnhancements(ClassHolder clazz) {
52          this.className = clazz.getFQName();
53          this.theClassObject = clazz;
54      }
55  
56      /**
57       * Adds a processed enhancement to the class.
58       *
59       * @param enhancement
60       *            the enhancement to add
61       */
62      public void addEnhancement(ClassMethodEnhancement enhancement) {
63          methodEnhancements.put(enhancement.getMethodName(), enhancement);
64      }
65  
66      /**
67       * Adds a source to a given method. Takes care of the incremental logic according to the registered methods.
68       *
69       * @param methodName
70       *            the method name
71       * @param methodSource
72       *            the method source
73       */
74      public void addSource(String methodName, String methodSource) {
75          ClassMethodEnhancement methodEnhancement = methodEnhancements.get(methodName);
76  
77          if (methodEnhancement == null)
78              methodEnhancement = new ClassMethodEnhancement(methodName, incrementalMethods.contains(methodName));
79          else
80              methodSource = "\n" + methodSource;
81  
82          methodEnhancement.addSource(methodSource);
83          methodEnhancements.put(methodName, methodEnhancement);
84      }
85  
86      /**
87       * Commits all the enhancements to a class file.
88       *
89       * @throws ResourceNotFoundException
90       *             if the class can't be found
91       * @throws CodeGenerationException
92       *             if the code can't be compiled
93       */
94      public void commitEnhancements() throws ResourceNotFoundException, CodeGenerationException {
95  
96          // Implement all enhancements
97          for (String methodName : methodEnhancements.keySet()) {
98              String source = methodEnhancements.get(methodName).getSource();
99  
100             // In trace mode we see every CG line before it is executed.
101             if (DIFStartupConfiguration.getLogLevel() == LogLevel.DEBUG
102                     || DIFStartupConfiguration.getLogLevel() == LogLevel.TRACE)
103                 source = getSourceWithTraceInfo(methodName, source);
104 
105             if (!source.startsWith("{"))
106                 source = "{" + source + "}";
107 
108             this.theClassObject.updateMethodSource(methodName, source);
109         }
110 
111         // Write class to disk
112         this.theClassObject.writeClass();
113     }
114 
115     /**
116      * Returns the class name.
117      *
118      * @return the class name
119      */
120     public String getClassName() {
121         return className;
122     }
123 
124     /**
125      * Returns the class object.
126      *
127      * @return the class object
128      */
129     public ClassHolder getClassObject() {
130         return this.theClassObject;
131     }
132 
133     /**
134      * Returns the method enhancements map.
135      *
136      * @return the method enhancements map
137      */
138     public Map<String, ClassMethodEnhancement> getMethodEnhancements() {
139         return methodEnhancements;
140     }
141 
142     /**
143      * Add trace info to system out for each line in the source code
144      *
145      * @param methodName
146      *            the method name
147      * @param source
148      *            the original source code without trace
149      * @return the source with trace added
150      * @throws ResourceNotFoundException
151      *             if the class can't be found
152      */
153     private String getSourceWithTraceInfo(String methodName, String source) throws ResourceNotFoundException {
154         String[] lines = source.split("\n");
155         StringBuffer temp = new StringBuffer();
156 
157         for (String line : lines) {
158             temp.append("System.out.println(\"" + this.theClassObject.getName() + " [" + methodName + "]: Executing - "
159                     + line.replaceAll("\\\"", "\\\\\"").replaceAll("\\\\", "\\\\") + "\");\n");
160             temp.append(line);
161             temp.append("\n");
162         }
163 
164         return temp.toString();
165 
166     }
167 
168     /**
169      * Adds a method name to the list of incremental methods.
170      *
171      * @param methodName
172      *            the name of the method to register
173      */
174     public void registerMethodAsIncremental(String methodName) {
175         incrementalMethods.add(methodName);
176     }
177 
178     /**
179      * Adds a source to a given method. Takes care of the incremental logic according to the registered methods.
180      *
181      * @param methodName
182      *            the method name
183      * @param terminator
184      *            the finalize code for the method
185      */
186     public void setTerminator(String methodName, String terminator) {
187         ClassMethodEnhancement methodEnhancement = methodEnhancements.get(methodName);
188 
189         methodEnhancement.setTerminator(terminator);
190         methodEnhancements.put(methodName, methodEnhancement);
191     }
192 
193     /**
194      * @see java.lang.Object#toString()
195      */
196     @Override
197     public String toString() {
198         ObjectFormatter formatter = new ObjectFormatter();
199 
200         formatter.addItem("Class Name", this.className);
201         formatter.addItem("Incremental Methods", this.incrementalMethods);
202         formatter.addItem("Method Enhancements", this.methodEnhancements);
203 
204         return formatter.getFormatedObject();
205     }
206 }