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