View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  package org.apache.jdo.impl.enhancer.core;
18  
19  import java.io.PrintStream;
20  import java.io.ByteArrayOutputStream;
21  
22  import org.apache.jdo.impl.enhancer.classfile.ClassAttribute;
23  import org.apache.jdo.impl.enhancer.classfile.ClassFile;
24  import org.apache.jdo.impl.enhancer.classfile.GenericAttribute;
25  import org.apache.jdo.impl.enhancer.util.Support;
26  
27  
28  
29  
30  /***
31   * Controls the enhancement of a class.
32   */
33  public final class Controller
34      extends Support
35      implements EnhancerConstants
36  {
37      /***
38       * Repository for enhancer options.
39       */
40      private final Environment env;
41  
42      /***
43       * The classfile to be enhanced.
44       */
45      private final ClassFile classFile;
46  
47      /***
48       * The class name in user ('.' delimited) form.
49       */
50      private final String userClassName;
51  
52      /***
53       * The analyzer for this class.
54       */
55      private final Analyzer analyzer;
56  
57      /***
58       * The augmentation controller for this class.
59       */
60      private final Augmenter augmenter;
61  
62      /***
63       * The method annotation controller for this class.
64       */
65      private final Annotater annotater;
66  
67      /***
68       * If true, this class is believed to have been modified in some way.
69       */
70      private boolean classUpdated = false;
71  
72      /***
73       * Constructor.
74       */
75      public Controller(ClassFile classFile,
76                        Environment env)
77      {
78          affirm(classFile != null);
79          affirm(env != null);
80  
81          this.classFile = classFile;
82          this.userClassName = classFile.userClassName();
83          this.env = env;
84          this.analyzer = new Analyzer(this, env);
85          this.augmenter = new Augmenter(this, analyzer, env);
86          this.annotater = new Annotater(this, analyzer, env);
87  
88          affirm(userClassName != null);
89          affirm(analyzer != null);
90          affirm(augmenter != null);
91          affirm(annotater != null);
92      }
93  
94      // ------------------------------------------------------------
95  
96      /***
97       * Returns the class file which we are operating on.
98       */
99      public ClassFile getClassFile()
100     {
101         return classFile;
102     }
103 
104     /***
105      * Returns true if the classfile has been updated.
106      */
107     public boolean updated()
108     {
109         return classUpdated;
110     }
111 
112     /***
113      * Records a modification of the class.
114      */
115     void noteUpdate()
116     {
117         classUpdated = true;
118     }
119 
120     // ------------------------------------------------------------
121 
122     /***
123      * Determines what modifications are needed and perform them.
124      */
125     public void enhanceClass()
126     {
127         try{
128             if (env.doTimingStatistics()) {
129                 Support.timer.push("Controller.enhanceClass()");
130             }
131 
132             // examine classes
133             scan();
134 
135             if (env.errorCount() > 0)
136                 return;
137 
138             // augment class
139             augment();
140 
141             if (env.errorCount() > 0)
142                 return;
143 
144             // annotate class
145             annotate();                
146 
147             if (env.errorCount() > 0)
148                 return;
149 
150             update();
151         } finally {
152             if (env.doTimingStatistics()) {
153                 Support.timer.pop();
154             }
155         }
156     }
157 
158     // ------------------------------------------------------------
159 
160     /***
161      * Notes the class characteristics.
162      */
163     private void scan()
164     {
165         if (analyzer.isAnalyzed()) {
166             return;
167         }
168 
169         try {
170             if (env.doTimingStatistics()) {
171                 Support.timer.push("Controller.scan()");
172             }
173 
174             if (env.dumpClass()) {
175                 dumpClass();
176             }
177 
178             analyzer.scan();
179         } finally {
180             if (env.doTimingStatistics()) {
181                 Support.timer.pop();
182             }
183         }
184     }
185 
186     /***
187      * Performs necessary augmentation actions on the class.
188      */
189     private void augment()
190     {
191         if (!analyzer.isAugmentable() || env.noAugment()) {
192             return;
193         }
194 
195         try{
196             if (env.doTimingStatistics()) {
197                 Support.timer.push("Controller.augment()");
198             }
199             augmenter.augment();
200 
201             if (env.dumpClass()) {
202                 dumpClass();
203             }
204         } finally {
205             if (env.doTimingStatistics()) {
206                 Support.timer.pop();
207             }
208         }
209     }
210 
211     /***
212      * Performs necessary annotation actions on the class.
213      */
214     private void annotate()
215     {
216         if (!analyzer.isAnnotateable() || env.noAnnotate()) {
217             return;
218         }
219 
220         try{
221             if (env.doTimingStatistics()) {
222                 Support.timer.push("Controller.annotate()");
223             }
224             annotater.annotate();
225 
226             if (env.dumpClass()) {
227                 dumpClass();
228             }
229         } finally {
230             if (env.doTimingStatistics()) {
231                 Support.timer.pop();
232             }
233         }
234     }
235 
236     /***
237      * Marks the class being enhanced.
238      */
239     private void update()
240     {
241         if (!classUpdated) {
242             return;
243         }
244     
245         affirm((analyzer.isAugmentable() && !env.noAugment())
246                || (analyzer.isAnnotateable() && !env.noAnnotate()));
247 
248         //^olsen: move non-modifying code to Analyzer
249         final byte[] data = new byte[2];
250         data[0] = (byte)(SUNJDO_PC_EnhancedVersion >>> 8);
251         data[1] = (byte)(SUNJDO_PC_EnhancedVersion & 0xff);
252         final ClassAttribute annotatedAttr
253             = new GenericAttribute(
254                 classFile.pool().addUtf8(SUNJDO_PC_EnhancedAttribute),
255                 data);
256         classFile.attributes().addElement(annotatedAttr);
257     }
258     
259     /***
260      * Dumps a class' signature and byte-code (for debugging).
261      */
262     private void dumpClass()
263     {
264         final ByteArrayOutputStream bs = new ByteArrayOutputStream();
265         final PrintStream ps = new PrintStream(bs);
266         env.messageNL("dumping class " + userClassName + " {");
267         classFile.print(ps);
268         env.getOutputWriter().println(bs.toString());
269         env.messageNL("} // end of class " + userClassName);
270     }
271 }