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