1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.enhancer;
19
20 import java.io.IOException;
21 import java.io.File;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.BufferedInputStream;
27 import java.io.BufferedOutputStream;
28 import java.io.PrintWriter;
29
30 import java.util.List;
31 import java.util.Iterator;
32 import java.util.Properties;
33
34 import java.util.zip.ZipInputStream;
35 import java.util.zip.ZipOutputStream;
36
37 import org.apache.jdo.impl.enhancer.ClassFileEnhancer;
38 import org.apache.jdo.impl.enhancer.ClassFileEnhancerHelper;
39 import org.apache.jdo.impl.enhancer.ClassFileEnhancerTimer;
40 import org.apache.jdo.impl.enhancer.EnhancerFatalError;
41 import org.apache.jdo.impl.enhancer.EnhancerOptions;
42 import org.apache.jdo.impl.enhancer.EnhancerUserException;
43 import org.apache.jdo.impl.enhancer.JdoMetaMain;
44 import org.apache.jdo.impl.enhancer.OutputStreamWrapper;
45 import org.apache.jdo.impl.enhancer.core.EnhancerFilter;
46
47
48
49 /***
50 * JDO command line enhancer.
51 *
52 * @author Martin Zaun
53 */
54 public class EnhancerMain
55 extends JdoMetaMain
56 {
57 /***
58 * The options and arguments.
59 */
60 protected EnhancerOptions options;
61
62 /***
63 * The byte code enhancer.
64 */
65 protected ClassFileEnhancer enhancer;
66
67 /***
68 * Creates an instance.
69 */
70 public EnhancerMain(PrintWriter out,
71 PrintWriter err)
72 {
73 this(out, err, new EnhancerOptions(out, err));
74 }
75
76 /***
77 * Creates an instance.
78 */
79 public EnhancerMain(PrintWriter out,
80 PrintWriter err,
81 EnhancerOptions options)
82 {
83 super(out, err, options);
84 this.options = options;
85 }
86
87
88
89 /***
90 * Enhances all files entered in the command line.
91 *
92 * @param classNames List of class names.
93 * @param classFileNames List of class file names.
94 * @param archiveFileNames List of archive file names.
95 */
96 private int enhanceInputFiles(List classNames,
97 List classFileNames,
98 List archiveFileNames)
99 {
100 int res = 0;
101 try {
102 String name = null;
103 for (Iterator i = archiveFileNames.iterator(); i.hasNext();) {
104 try {
105 name = (String)i.next();
106 enhanceArchiveFile(name);
107 } catch (EnhancerUserException ex) {
108 printlnErr("Error while enhancing " + name, ex,
109 options.verbose.value);
110 res++;
111 continue;
112 }
113 }
114 for (Iterator i = classFileNames.iterator(); i.hasNext();) {
115 try {
116 name = (String)i.next();
117 enhanceClassFile(openFileInputStream(name));
118 } catch (EnhancerUserException ex) {
119 printlnErr("Error while enhancing " + name, ex,
120 options.verbose.value);
121 res++;
122 continue;
123 }
124 }
125 for (Iterator i = classNames.iterator(); i.hasNext();) {
126 try {
127 name = (String)i.next();
128 enhanceClassFile(openClassInputStream(name));
129 } catch (EnhancerUserException ex) {
130 printlnErr("Error while enhancing " + name, ex,
131 options.verbose.value);
132 res++;
133 continue;
134 }
135 }
136 } catch (IOException ex) {
137 printlnErr("IO Error while enhancing", ex, options.verbose.value);
138 return ++res;
139 } catch (EnhancerFatalError ex) {
140
141 printlnErr("Fatal error while enhancing", ex, options.verbose.value);
142 enhancer = null;
143 return ++res;
144 }
145 return res;
146 }
147
148 /***
149 * Enhances a classfile.
150 *
151 * @param in The input stream of the classfile.
152 */
153 private void enhanceClassFile(InputStream in)
154 throws IOException, EnhancerUserException, EnhancerFatalError
155 {
156 OutputStream out = null;
157 try {
158 final File temp = File.createTempFile("enhancer", ".class");
159 out = new BufferedOutputStream(new FileOutputStream(temp));
160
161
162 final OutputStreamWrapper wrapper = new OutputStreamWrapper(out);
163 final boolean enhanced = enhancer.enhanceClassFile(in, wrapper);
164
165 closeOutputStream(out);
166 out = null;
167 createOutputFile(enhanced,
168 getClassFileName(wrapper.getClassName()), temp);
169 } finally {
170 closeInputStream(in);
171 closeOutputStream(out);
172 }
173 }
174
175 /***
176 * Enhances a archive file.
177 *
178 * @param fileName The filename of the archive file.
179 */
180 private void enhanceArchiveFile(String fileName)
181 throws IOException, EnhancerUserException, EnhancerFatalError
182 {
183 ZipInputStream in = null;
184 ZipOutputStream out = null;
185 try {
186 final File temp = File.createTempFile("enhancer", ".zip");
187 in = new ZipInputStream(new BufferedInputStream(
188 new FileInputStream(new File(fileName))));
189 out = new ZipOutputStream(new BufferedOutputStream(
190 new FileOutputStream(temp)));
191
192
193 final boolean enhanced
194 = ClassFileEnhancerHelper.enhanceZipFile(enhancer, in, out);
195
196
197 closeOutputStream(out);
198 out = null;
199 createOutputFile(enhanced, new File(fileName).getName(), temp);
200 } finally {
201 closeOutputStream(out);
202 closeInputStream(in);
203 }
204 }
205
206 /***
207 * Creates a file object that represents the output archive file for
208 * a given archive file to enhance.
209 *
210 * @param archiveFileName the input archive file name
211 * @return the output archive file
212 */
213 private File createArchiveOutputFile(String archiveFileName)
214 {
215 return new File(options.destDir.value,
216 new File(archiveFileName).getName());
217 }
218
219 /***
220 * Creates the output file for an enhanced class- or archive file. If the
221 * enhanced file is written back depends on the command line options.
222 *
223 * @param enhanced Has the input file been enhanced?
224 * @param fileName The name of the output file.
225 * @param temp The temp file, the output is written to.
226 * @exception IOException If the file could not be created.
227 */
228 private void createOutputFile(boolean enhanced,
229 String fileName,
230 File temp)
231 throws IOException
232 {
233
234 if (options.noWrite.value
235 || (!enhanced && !options.forceWrite.value)) {
236 temp.deleteOnExit();
237 return;
238 }
239
240
241 final File file = new File(options.destDir.value, fileName);
242 final File dir = file.getAbsoluteFile().getParentFile();
243 if (!dir.exists() && !dir.mkdirs()) {
244 throw new IOException("Error creating directory '"
245 + dir.getAbsolutePath() + "'.");
246 }
247
248 file.delete();
249 boolean renamed = temp.renameTo(file);
250 if (!renamed) {
251
252
253 InputStream in = null;
254 OutputStream out = null;
255 try {
256 in = new FileInputStream(temp);
257 out = new FileOutputStream(file);
258 int PAGESIZE = 4096;
259 byte data[] = new byte[PAGESIZE];
260 while (in.available() > 0) {
261 int numRead = in.read(data, 0, PAGESIZE);
262 out.write(data, 0, numRead);
263 }
264 renamed = true;
265 } catch (IOException ex) {
266 throw new IOException("Could not rename temp file '" +
267 temp.getAbsolutePath() +
268 "' to '" + file.getAbsolutePath()
269 + "': " + ex);
270 } finally {
271 closeInputStream(in);
272 closeOutputStream(out);
273 }
274 if (renamed) {
275 temp.delete();
276 }
277 else {
278 throw new IOException("Could not rename temp file '" +
279 temp.getAbsolutePath() +
280 "' to '" + file.getAbsolutePath() + "'.");
281 }
282 }
283 }
284
285 /***
286 * Closes an output stream.
287 *
288 * @param out the output stream
289 */
290 private void closeOutputStream(OutputStream out)
291 {
292 if (out != null) {
293 try {
294 out.close();
295 } catch (IOException ex) {
296 printlnErr("", ex, options.verbose.value);
297 }
298 }
299 }
300
301
302
303 /***
304 * Initializes all components.
305 */
306 protected void init()
307 throws EnhancerFatalError, EnhancerUserException
308 {
309 super.init();
310
311 final Properties props = new Properties();
312 if (options.verbose.value) {
313 props.put(EnhancerFilter.VERBOSE_LEVEL,
314 EnhancerFilter.VERBOSE_LEVEL_VERBOSE);
315 }
316
317 if (options.doTiming.value) {
318 props.put(EnhancerFilter.DO_TIMING_STATISTICS,
319 Boolean.TRUE.toString());
320 }
321
322 if (options.dumpClass.value) {
323 props.put(EnhancerFilter.DUMP_CLASS,
324 Boolean.TRUE.toString());
325 }
326
327 if (options.noAugment.value) {
328 props.put(EnhancerFilter.NO_AUGMENT,
329 Boolean.TRUE.toString());
330 }
331
332 if (options.noAnnotate.value) {
333 props.put(EnhancerFilter.NO_ANNOTATE,
334 Boolean.TRUE.toString());
335 }
336
337 try {
338 enhancer = new EnhancerFilter(jdoMeta, props, out, err);
339 if (options.doTiming.value) {
340
341 enhancer = new ClassFileEnhancerTimer(enhancer);
342 }
343 } catch (EnhancerUserException ex) {
344 printlnErr("Error while creating the enhancer", ex,
345 options.verbose.value);
346 throw ex;
347 } catch (EnhancerFatalError ex) {
348
349 printlnErr("Fatal error while creating the enhancer", ex,
350 options.verbose.value);
351 enhancer = null;
352 throw ex;
353 } catch (RuntimeException ex) {
354
355 printlnErr("Internal error while creating the enhancer", ex,
356 options.verbose.value);
357 enhancer = null;
358 throw new EnhancerFatalError(ex);
359 }
360 }
361
362 /***
363 * Run the enhancer.
364 */
365 protected int process()
366 {
367 return enhanceInputFiles(options.classNames,
368 options.classFileNames,
369 options.archiveFileNames);
370 }
371
372
373
374 /***
375 * Runs this class
376 */
377 static public void main(String[] args)
378 {
379 final PrintWriter out = new PrintWriter(System.out, true);
380 out.println("--> EnhancerMain.main()");
381
382 final EnhancerMain main = new EnhancerMain(out, out);
383 int res = main.run(args);
384
385 out.println("<-- EnhancerMain.main(): exit = " + res);
386 System.exit(res);
387 }
388 }