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.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.io.PrintWriter;
24 import java.io.DataInputStream;
25 import java.io.DataOutputStream;
26
27 import java.util.Properties;
28
29 import org.apache.jdo.impl.enhancer.ClassFileEnhancer;
30 import org.apache.jdo.impl.enhancer.EnhancerFatalError;
31 import org.apache.jdo.impl.enhancer.EnhancerUserException;
32 import org.apache.jdo.impl.enhancer.OutputStreamWrapper;
33 import org.apache.jdo.impl.enhancer.classfile.ClassFile;
34 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
35 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
36 import org.apache.jdo.impl.enhancer.util.Support;
37
38
39
40
41
42
43
44 /***
45 * Provides a JDO byte-code enhancer.
46 */
47 public class EnhancerFilter
48 extends Support
49 implements ClassFileEnhancer
50 {
51 static public final String DO_TIMING_STATISTICS
52 = "Enhancer.doTimingStatistics";
53 static public final String DUMP_CLASS
54 = "Enhancer.dumpClass";
55 static public final String NO_AUGMENT
56 = "Enhancer.noAugment";
57 static public final String NO_ANNOTATE
58 = "Enhancer.noAnnotate";
59 static public final String VERBOSE_LEVEL
60 = "Enhancer.verboseLevel";
61 static public final String VERBOSE_LEVEL_QUIET
62 = "quiet";
63 static public final String VERBOSE_LEVEL_WARN
64 = "warn";
65 static public final String VERBOSE_LEVEL_VERBOSE
66 = "verbose";
67 static public final String VERBOSE_LEVEL_DEBUG
68 = "debug";
69
70
71
72 private Environment env = new Environment();
73
74 /***
75 * Initializes an instance of a JDO enhancer.
76 * @param metaData the JDO meta-data object
77 * @param settings enhancement properties
78 * @param out standard ouput stream for the enhancer
79 */
80 protected void init(EnhancerMetaData metaData,
81 Properties settings,
82 PrintWriter out,
83 PrintWriter err)
84 throws EnhancerUserException, EnhancerFatalError
85 {
86 if (metaData == null) {
87 throw new EnhancerFatalError(
88 getI18N("enhancer.internal_error",
89 "Illegal argument: metaData == null"));
90 }
91
92 env.setEnhancerMetaData(metaData);
93
94 final String doTiming
95 = (settings == null
96 ? null
97 : settings.getProperty(DO_TIMING_STATISTICS));
98 env.setDoTimingStatistics(Boolean.valueOf(doTiming).booleanValue());
99
100 final String dumpClass
101 = (settings == null
102 ? null
103 : settings.getProperty(DUMP_CLASS));
104 env.setDumpClass(Boolean.valueOf(dumpClass).booleanValue());
105
106 final String noAugment
107 = (settings == null
108 ? null
109 : settings.getProperty(NO_AUGMENT));
110 env.setNoAugment(Boolean.valueOf(noAugment).booleanValue());
111
112 final String noAnnotate
113 = (settings == null
114 ? null
115 : settings.getProperty(NO_ANNOTATE));
116 env.setNoAnnotate(Boolean.valueOf(noAnnotate).booleanValue());
117
118
119 if (err != null) {
120 env.setErrorWriter(err);
121 }
122 if (out != null) {
123 env.setOutputWriter(out);
124 }
125 final String verboseLevel
126 = (settings == null ? null : settings.getProperty(VERBOSE_LEVEL));
127 if (VERBOSE_LEVEL_QUIET.equals(verboseLevel)) {
128 env.setVerbose(false);
129 env.setQuiet(true);
130 } else if (VERBOSE_LEVEL_WARN.equals(verboseLevel)) {
131 env.setVerbose(false);
132 env.setQuiet(false);
133 } else if (VERBOSE_LEVEL_VERBOSE.equals(verboseLevel)) {
134 env.setVerbose(true);
135 env.setQuiet(false);
136 } else if (VERBOSE_LEVEL_DEBUG.equals(verboseLevel)) {
137 env.setVerbose(true);
138 env.setQuiet(false);
139 } else {
140 env.setVerbose(false);
141 env.setQuiet(false);
142 }
143 }
144
145 /***
146 * Creates an instance of a JDO enhancer.
147 * @param metaData the JDO meta-data object
148 * @param settings enhancement properties
149 * @param out standard ouput stream for the enhancer
150 */
151 public EnhancerFilter(EnhancerMetaData metaData,
152 Properties settings,
153 PrintWriter out,
154 PrintWriter err)
155 throws EnhancerUserException, EnhancerFatalError
156 {
157 init(metaData, settings, out, err);
158 }
159
160 /***
161 * Enhances a given class according to the JDO meta-data.
162 */
163 private boolean enhanceClassFile1(InputStream inClassFile,
164 OutputStreamWrapper outClassFile)
165 throws EnhancerUserException
166 {
167
168 affirm(inClassFile, "Illegal argument: inClassFile == null.");
169 affirm(outClassFile, "Illegal argument: outClassFile == null.");
170
171
172 final ClassFile cf;
173 final Controller cc;
174 try {
175
176 final DataInputStream dis = new DataInputStream(inClassFile);
177 final boolean allowJDK12ClassFiles = true;
178 cf = new ClassFile(dis, allowJDK12ClassFiles);
179
180
181
182
183 cc = new Controller(cf, env);
184
185
186 final String className = cf.classNameString();
187 } catch (ClassFormatError ex) {
188 throw new EnhancerUserException(
189 getI18N("enhancer.class_format_error"),
190 ex);
191 }
192
193
194 cc.enhanceClass();
195 if (env.errorCount() > 0) {
196
197 env.getErrorWriter().flush();
198
199 throw new EnhancerUserException(env.getLastErrorMessage());
200 }
201 affirm(env.errorCount() == 0);
202
203
204 boolean changed = cc.updated();
205 try {
206 if (changed) {
207 env.message("writing enhanced class " + cf.userClassName()
208 + " to output stream");
209 } else {
210 env.message("no changes to class " + cf.userClassName());
211 }
212 outClassFile.setClassName(cf.userClassName());
213 final DataOutputStream dos
214 = new DataOutputStream(outClassFile.getStream());
215 cf.write(dos);
216 dos.flush();
217 } catch (IOException ex) {
218 throw new EnhancerUserException(
219 getI18N("enhancer.io_error_while_writing_stream"),
220 ex);
221 }
222 return changed;
223 }
224
225 /***
226 * Enhances a given class according to the JDO meta-data.
227 */
228 public boolean enhanceClassFile(InputStream inClassFile,
229 OutputStreamWrapper outClassFile)
230 throws EnhancerUserException, EnhancerFatalError
231 {
232 env.verbose("---------------------------------------------------------------------------");
233 env.messageNL("Enhancer: enhancing classfile ...");
234
235
236 env.reset();
237
238
239 final boolean changed;
240 try {
241 changed = enhanceClassFile1(inClassFile, outClassFile);
242 } catch (EnhancerUserException ex) {
243
244 env.reset();
245 throw ex;
246 } catch (EnhancerMetaDataUserException ex) {
247
248
249
250 env.reset();
251 throw new EnhancerUserException(
252 getI18N("enhancer.error", ex.getMessage()),
253 ex);
254 } catch (RuntimeException ex) {
255
256 env.reset();
257 ex.printStackTrace ();
258 throw new EnhancerFatalError(
259 getI18N("enhancer.internal_error", ex.getMessage()),
260 ex);
261 }
262
263 env.messageNL(changed
264 ? "Enhancer: classfile enhanced successfully."
265 : "Enhancer: classfile not changed.");
266 return changed;
267 }
268
269 public boolean enhanceClassFile(InputStream in,
270 OutputStream out)
271 throws EnhancerUserException,
272 EnhancerFatalError
273 {
274 return enhanceClassFile(in, new OutputStreamWrapper(out));
275 }
276 }