1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
133 scan();
134
135 if (env.errorCount() > 0)
136 return;
137
138
139 augment();
140
141 if (env.errorCount() > 0)
142 return;
143
144
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
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 }