001: package org.objectweb.speedo.generation.start;
002:
003: import org.apache.tools.ant.BuildException;
004: import org.apache.tools.ant.DirectoryScanner;
005: import org.apache.tools.ant.Project;
006: import org.apache.tools.ant.taskdefs.MatchingTask;
007: import org.apache.tools.ant.types.Path;
008: import org.objectweb.jorm.api.PException;
009: import org.objectweb.speedo.api.SpeedoException;
010: import org.objectweb.speedo.api.SpeedoProperties;
011: import org.objectweb.speedo.generation.AbstractEnhancer;
012: import org.objectweb.speedo.generation.jdo.JDOEnhancer;
013: import org.objectweb.speedo.generation.api.SpeedoCompilerParameter;
014: import org.objectweb.util.monolog.Monolog;
015: import org.objectweb.util.monolog.api.BasicLevel;
016: import org.objectweb.util.monolog.api.Logger;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.io.PrintWriter;
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.Iterator;
024: import java.util.List;
025:
026: /**
027: * Main is the starting point for the persistent filter tool.
028: */
029: public class Main extends Support {
030: // return values of main()
031: static public final int OK = 0;
032: static public final int USAGE_ERROR = -1;
033: static public final int METADATA_ERROR = -2;
034: static public final int INTERNAL_ERROR = -3;
035:
036: protected Logger logger = null;
037: private SpeedoCompilerParameter scp = null;
038: private AbstractEnhancer sc = null;
039: private Description jdodesc = new Description();
040: private Description jormdesc = new Description();
041: private Description awareFiles = new Description();
042: private Project project = new Project();
043: /**
044: * The stream to write messages to.
045: */
046: private final PrintWriter out = new PrintWriter(System.out, true);
047:
048: /**
049: * The stream to write error messages to.
050: */
051: private final PrintWriter err = new PrintWriter(System.err, true);
052:
053: /**
054: * The command line options.
055: */
056: private final CmdLineOptions opts = new CmdLineOptions();
057:
058: /**
059: * Construct a filter tool instance
060: */
061: public Main() {
062: }
063:
064: // ----------------------------------------------------------------------
065:
066: /**
067: * This is where it all starts.
068: */
069: public static void main(String[] argv) {
070: int res;
071: final Main main = new Main();
072:
073: main.sc = new JDOEnhancer();
074: main.scp = main.sc.getSpeedoCompilerParameter();
075:
076: // added support for timing statistics
077: try {
078: res = main.process(argv);
079: } catch (RuntimeException ex) {
080: main.out.flush();
081: main.err.println("Internal error while postprocessing: "
082: + ex.getMessage());
083: ex.printStackTrace(main.err);
084: main.err.flush();
085: res = INTERNAL_ERROR;
086: } finally {
087: // added support for timing statistics
088: main.logger.log(BasicLevel.DEBUG, "Timing infos...");
089: if (main.opts.doTiming) {
090: Support.timer.print();
091: }
092: }
093: main.logger.log(BasicLevel.DEBUG,
094: "leaving org.objectweb.speedo.start.Main.main(), ret="
095: + res);
096: System.exit(res);
097: }
098:
099: /**
100: * Process command line options and perform filtering tasks
101: */
102: public int process(String[] argv) {
103: int res;
104: if ((res = opts.processArgs(argv)) != OK) {
105: printMessage("aborted with errors.");
106: return res;
107: }
108:
109: // added support for timing statistics
110: try {
111: if (opts.doTiming) {
112: timer.push("Main.process(String[])");
113: }
114:
115: if ((res = start()) != OK) {
116: printMessage("aborted with errors.");
117: return res;
118: }
119:
120: printMessage("done.");
121: return 0;
122: } finally {
123: if (opts.doTiming) {
124: timer.pop();
125: }
126: }
127: }
128:
129: // ----------------------------------------------------------------------
130:
131: /**
132: * A class for holding the command line options.
133: */
134: private class CmdLineOptions {
135: String speedoproperties = null;
136: final List classNames = new ArrayList();
137: final List classFileNames = new ArrayList();
138: final List zipFileNames = new ArrayList();
139: final List jdoFileNames = new ArrayList();
140: String sourcePath = null;
141: String destinationDirectory = null;
142: String propertiesFileName = null;
143: String logproperties = null;
144: String inputdir = null;
145: boolean doTiming = false;
146: boolean verbose = false;
147: boolean quiet = false;
148: boolean forceWrite = false;
149: boolean noWrite = false;
150: boolean dumpClass = false;
151: boolean noAugment = false;
152: boolean noAnnotate = false;
153:
154: /**
155: * Print a usage message to System.err.
156: */
157: public void usage() {
158: err.println("Usage: main <options> <arguments>...");
159: err.println("Options:");
160: err
161: .println(" -h, --help print usage message and exit gently");
162: err
163: .println(" -v, --verbose print verbose messages");
164: err
165: .println(" -q, --quiet supress warnings");
166: err.println(" -i, --input <dir> input dir");
167: err
168: .println(" -d, --destdir <dir> destination directory for output files");
169: err.println(" -s, --sourcepath <path> source path");
170: err
171: .println(" -sp, --speedoproperties <filepath> Absolute path of the Speedo properties file");
172: err
173: .println(" -log <filepath> Absolute path of the log properties file");
174: err
175: .println(" -f, --force overwrite output files");
176: err
177: .println(" -n, --nowrite never write output files");
178: err
179: .println(" -t, --timing do timing messures");
180: err.println();
181: err.println("Debugging Options:");
182: err
183: .println(" --properties <file> use property file for meta data");
184: err
185: .println(" --dumpclass print out disassembled code of classes");
186: err
187: .println(" --noaugment do not enhance for persistence-capability");
188: err
189: .println(" --noannotate do not enhance for persistence-awareness");
190: err.println();
191: err.println("Arguments:");
192: //err.println(" <class> the fully qualified name of a Java class");
193: err.println(" <jdofile> the name of a .jdo file");
194: err.println(" <classfile> the name of a .class file");
195: //err.println(" <zipfile> the name of a .zip or .jar file");
196: err.println();
197: err.println("Returns a non-zero value in case of errors.");
198: }
199:
200: /**
201: * Process command line options.
202: */
203: protected int processArgs(String[] argv) {
204: final Collection inputNames = new ArrayList();
205: for (int i = 0; i < argv.length; i++) {
206: final String arg = argv[i];
207: if (arg.equals("-h") || arg.equals("--help")) {
208: usage();
209: return OK;
210: }
211: if (arg.equals("-v") || arg.equals("--verbose")) {
212: verbose = true;
213: quiet = false;
214: continue;
215: }
216: if (arg.equals("-sp")
217: || arg.equals("--speedoproperties")) {
218: if (argv.length - i < 2) {
219: printError(
220: "Missing argument to the -sp/--speedoproperties option",
221: null);
222: usage();
223: return USAGE_ERROR;
224: }
225: speedoproperties = argv[++i];
226: continue;
227: }
228: if (arg.equals("-log")) {
229: if (argv.length - i < 2) {
230: printError(
231: "Missing argument to the -log option",
232: null);
233: usage();
234: return USAGE_ERROR;
235: }
236: logproperties = argv[++i];
237: continue;
238: }
239: if (arg.equals("-i") || arg.equals("--input")) {
240: if (argv.length - i < 2) {
241: printError("Missing argument to the -i option",
242: null);
243: usage();
244: return USAGE_ERROR;
245: }
246: inputdir = argv[++i];
247: continue;
248: }
249: if (arg.equals("-q") || arg.equals("--quiet")) {
250: quiet = true;
251: verbose = false;
252: continue;
253: }
254: if (arg.equals("-t") || arg.equals("--timing")) {
255: doTiming = true;
256: continue;
257: }
258: if (arg.equals("-f") || arg.equals("--force")) {
259: forceWrite = true;
260: noWrite = false;
261: continue;
262: }
263: if (arg.equals("-n") || arg.equals("--nowrite")) {
264: noWrite = true;
265: forceWrite = false;
266: continue;
267: }
268: if (arg.equals("--dumpclass")) {
269: dumpClass = true;
270: continue;
271: }
272: if (arg.equals("--noaugment")) {
273: noAugment = true;
274: continue;
275: }
276: if (arg.equals("--noannotate")) {
277: noAnnotate = true;
278: continue;
279: }
280: if (arg.equals("-s") || arg.equals("--sourcepath")) {
281: if (argv.length - i < 2) {
282: printError(
283: "Missing argument to the -s/--sourcepath option",
284: null);
285: usage();
286: return USAGE_ERROR;
287: }
288: sourcePath = argv[++i];
289: continue;
290: }
291: if (arg.equals("-d") || arg.equals("--destdir")) {
292: if (argv.length - i < 2) {
293: printError(
294: "Missing argument to the -d/-destdir option",
295: null);
296: usage();
297: return USAGE_ERROR;
298: }
299: destinationDirectory = argv[++i];
300: continue;
301: }
302: if (arg.equals("--properties")) {
303: if (argv.length - i < 2) {
304: printError(
305: "Missing argument to the --properties option",
306: null);
307: usage();
308: return USAGE_ERROR;
309: }
310: propertiesFileName = argv[++i];
311: continue;
312: }
313: if (arg.length() > 0 && arg.charAt(0) == '-') {
314: printError("Unrecognized option:" + arg, null);
315: usage();
316: return USAGE_ERROR;
317: }
318: if (arg.length() == 0) {
319: printMessage("Ignoring empty command line argument.");
320: continue;
321: }
322:
323: inputNames.add(arg);
324: }
325:
326: // group input file arguments
327: for (Iterator names = inputNames.iterator(); names
328: .hasNext();) {
329: final String name = (String) names.next();
330: if (isJdoFileName(name)) {
331: jdoFileNames.add(name);
332: } else if (isClassFileName(name)) {
333: classFileNames.add(name);
334: } else if (isZipFileName(name)) {
335: zipFileNames.add(name);
336: } else {
337: classNames.add(name);
338: }
339: }
340:
341: if (verbose) {
342: printArgs();
343: }
344: return checkArgs();
345: }
346:
347: /**
348: * Check command line options.
349: */
350: protected int checkArgs() {
351: // at least one meta-data source must be specified for classfiles
352: if (classFileNames.size() > 0
353: && (jdoFileNames.isEmpty()
354: && propertiesFileName == null && sourcePath == null)) {
355: final String msg = "No JDO meta-data source specified for class files";
356: printError(msg, null);
357: usage();
358: return USAGE_ERROR;
359: }
360:
361: // either jdo files or jdo properties specified
362: if (!jdoFileNames.isEmpty() && propertiesFileName != null) {
363: final String msg = "Cannot have both jdo files and properties specified";
364: printError(msg, null);
365: usage();
366: return USAGE_ERROR;
367: }
368:
369: return OK;
370: }
371:
372: /**
373: * return command line options.
374: */
375: protected String getArgs() {
376: String classnames = "";
377: for (Iterator i = classNames.iterator(); i.hasNext();) {
378: classnames.concat(" " + i.next());
379: }
380: String jdonames = "";
381: for (Iterator i = jdoFileNames.iterator(); i.hasNext();) {
382: jdonames.concat(" " + i.next());
383: }
384: String classfilenames = "";
385: for (Iterator i = classFileNames.iterator(); i.hasNext();) {
386: classfilenames.concat(" " + i.next());
387: }
388: String zipnames = "";
389: for (Iterator i = zipFileNames.iterator(); i.hasNext();) {
390: zipnames.concat(" " + i.next());
391: }
392: return "Enhancer: options:" + "\n" + " verbose = "
393: + verbose + "\n" + " quiet = " + quiet + "\n"
394: + " forceWrite = " + forceWrite + "\n"
395: + " noWrite = " + noWrite + "\n"
396: + " inputDirectory = " + inputdir + "\n"
397: + " destinationDirectory = "
398: + destinationDirectory + "\n"
399: + " SpeedopropertiesFileName = "
400: + speedoproperties + "\n" + " doTiming = "
401: + doTiming + "\n" + " classNames = {" + "\n"
402: + classnames + "\n" + " }" + "\n"
403: + " classfilenames = {" + "\n" + classfilenames
404: + "\n" + " }" + "\n" + " jdoFileNames = {"
405: + jdonames + "\n" + " }" + "\n"
406: + " zipnames = {" + "\n" + zipnames + "\n"
407: + " }" + "\n" + " dumpClass = " + dumpClass
408: + "\n" + " noAugment = " + noAugment + "\n"
409: + " noAnnotate = " + noAnnotate;
410: }
411:
412: /**
413: * Print command line options.
414: */
415: protected void printArgs() {
416: out.println("Enhancer: options:");
417: out.println(" verbose = " + verbose);
418: out.println(" quiet = " + quiet);
419: out.println(" forceWrite = " + forceWrite);
420: out.println(" noWrite = " + noWrite);
421: out.println(" inputDirectory = " + inputdir);
422: out.println(" destinationDirectory = "
423: + destinationDirectory);
424: out.println(" SpeedopropertiesFileName = "
425: + speedoproperties);
426: out.println(" doTiming = " + doTiming);
427: out.println(" classNames = {");
428: for (Iterator i = classNames.iterator(); i.hasNext();) {
429: out.println(" " + i.next());
430: }
431: out.println(" }");
432: out.println(" jdoFileNames = {");
433: for (Iterator i = jdoFileNames.iterator(); i.hasNext();) {
434: out.println(" " + i.next());
435: }
436: out.println(" classFileNames = {");
437: for (Iterator i = classFileNames.iterator(); i.hasNext();) {
438: out.println(" " + i.next());
439: }
440: out.println(" }");
441: out.println(" zipFileNames = {");
442: for (Iterator i = zipFileNames.iterator(); i.hasNext();) {
443: out.println(" " + i.next());
444: }
445: out.println(" }");
446: out.println(" dumpClass = " + dumpClass);
447: out.println(" noAugment = " + noAugment);
448: out.println(" noAnnotate = " + noAnnotate);
449: }
450: }
451:
452: private int initParameters() {
453: final String propertiesFileName = opts.propertiesFileName;
454: final List jdoFileNames = opts.jdoFileNames;
455: final List ClassFileNames = opts.classFileNames;
456: final String sourcePath = opts.sourcePath;
457:
458: try {
459: scp.logPropFile = opts.logproperties;
460:
461: // Initialize the logger factory if necessary
462: try {
463: if (scp.loggerFactory == null) {
464: if (scp.logPropFile == null) {
465: scp.loggerFactory = Monolog.initialize();
466: } else {
467: scp.loggerFactory = Monolog
468: .getMonologFactory(scp.logPropFile);
469: }
470: logger = scp.loggerFactory
471: .getLogger(SpeedoProperties.LOGGER_NAME
472: + ".start.Main");
473: } else if (logger == null) {
474: logger = scp.loggerFactory
475: .getLogger(SpeedoProperties.LOGGER_NAME
476: + ".start.Main");
477: }
478: } catch (Exception e) {
479: e.printStackTrace();
480: }
481: logger.log(BasicLevel.DEBUG, "Entering initParameters()");
482: scp.projectName = "";
483:
484: // Setting Classpath
485: scp.classpath = new Path(project, opts.sourcePath);
486: scp.classpath.append(new Path(project,
487: opts.destinationDirectory));
488: scp.jormclasspath = new MyArrayList(scp.classpath.list());
489:
490: // Setting directories (input, output,jdodir jormdir)
491: if (opts.inputdir != null)
492: scp.input = opts.inputdir;
493: else
494: scp.input = (new File(".")).getCanonicalPath();
495: if (opts.destinationDirectory != null)
496: scp.output = opts.destinationDirectory;
497: else
498: scp.output = scp.input;
499:
500: scp.jormDir = scp.input;
501: scp.xmlDir = "file:/" + scp.input;
502: scp.awareFilesDir = scp.input;
503:
504: // Verifying the accessibility of jorm.properties
505: if (this .getClass().getClassLoader().getResourceAsStream(
506: "jorm.properties") == null) {
507: throw new BuildException(
508: "ERROR: Impossible to "
509: + "find the 'jorm.properties' file in the classpath, classloader="
510: + getClass().getClassLoader());
511: }
512:
513: // Build the .pd list.
514: jormdesc.setDir(new File(scp.input));
515: jormdesc.setProject(project);
516: jormdesc.setIncludes("**/*.pd");
517: ListResourceLocator lrl = new ListResourceLocator(out,
518: true, new MyArrayList(jormdesc.getDirectoryScanner(
519: new File(scp.jormDir)).getIncludedFiles()),
520: scp.output, scp);
521: scp.jorm = lrl.getCollectionOfFiles();
522:
523: // search for the .jdo files in output folder if not specified
524: if (opts.jdoFileNames.size() == 0) {
525: jdodesc.setDir(new File(scp.input));
526: jdodesc.setProject(new Project());
527: jdodesc.setIncludes("**/*.jdo");
528: lrl = new ListResourceLocator(out, true,
529: new MyArrayList(jdodesc.getDirectoryScanner(
530: jdodesc.dir).getIncludedFiles()),
531: scp.input, scp);
532: scp.xml = lrl.getCollectionOfFiles();
533: } else {
534: scp.xml = opts.jdoFileNames;
535: }
536: } catch (Exception e1) {
537: e1.printStackTrace();
538: }
539:
540: Collection awarefiles = new ArrayList();
541: try {
542: // classes to enhance must have be specified in the command line.
543: ListResourceLocator lrl = new ListResourceLocator(out,
544: true, ClassFileNames, scp.output, scp);
545: awarefiles = lrl.getCollectionOfFiles();
546: } catch (IOException e) {
547: e.printStackTrace();
548: }
549: scp.awareFiles = awarefiles;
550:
551: logger.log(BasicLevel.DEBUG, "leaving initParameters(), ret="
552: + OK);
553: return OK;
554: }
555:
556: private int start() {
557: int res = initParameters();
558: if (res < 0) {
559: return res;
560: }
561: try {
562: logger.log(BasicLevel.DEBUG, "SpeedoCompiler init");
563: printMessage("SpeedoCompiler init");
564: sc.init();
565: logger.log(BasicLevel.DEBUG, "SpeedoCompiler process");
566: printMessage("SpeedoCompiler process");
567: sc.process();
568: logger.log(BasicLevel.DEBUG, "SpeedoCompiler end");
569: printMessage("SpeedoCompiler end");
570: } catch (SpeedoException e) {
571: e.printStackTrace();
572: throw new BuildException(getNestedException(e));
573: }
574: return res;
575: }
576:
577: private Exception getNestedException(Exception e) {
578: if (e instanceof SpeedoException
579: && ((SpeedoException) e).getNestedException() != null) {
580: return getNestedException(((SpeedoException) e)
581: .getNestedException());
582: } else if (e instanceof PException
583: && ((PException) e).getNestedException() != null) {
584: return getNestedException(((PException) e)
585: .getNestedException());
586: } else
587: return e;
588: }
589:
590: public class Description extends MatchingTask {
591:
592: public File dir = null;
593:
594: public void setDir(File dir) {
595: this .dir = dir;
596: }
597:
598: public DirectoryScanner getDirectoryScanner(File p) {
599: return super .getDirectoryScanner(p);
600: }
601: }
602:
603: class MyArrayList extends ArrayList {
604: public MyArrayList(Object[] os) {
605: super (os.length);
606: for (int i = 0; i < os.length; i++)
607: add(os[i]);
608: }
609: }
610:
611: /**
612: * Tests if a filename is a classfile name.
613: *
614: * @param filename The name of the file.
615: * @return Do we have a potential classfile?
616: */
617: static private boolean isClassFileName(String filename) {
618: return filename.endsWith(".class");
619: }
620:
621: /**
622: * Tests if a filename is a zipfile (only by testing if the extension -
623: * ignoring the case - is <code>".zip"</code> or <code>".jar"</code>).
624: *
625: * @param filename The name of the file.
626: * @param Do we have a potential zipfile?
627: */
628: static private boolean isZipFileName(String filename) {
629: final int n = filename.length();
630: if (n < 5) {
631: return false;
632: }
633: final String ext = filename.substring(n - 4);
634: return ext.equalsIgnoreCase(".zip")
635: || ext.equalsIgnoreCase(".jar");
636: }
637:
638: /**
639: * Tests if a filename is a zipfile (only by testing if the extension -
640: * ignoring the case - is <code>".jar"</code>).
641: *
642: * @param filename The name of the file.
643: * @param Do we have a potential jarfile?
644: */
645: static private boolean isJarFileName(String filename) {
646: final int n = filename.length();
647: if (n < 5) {
648: return false;
649: }
650: final String ext = filename.substring(n - 4);
651: return ext.equalsIgnoreCase(".jar");
652: }
653:
654: /**
655: * Tests if a filename is a jdo file name.
656: *
657: * @param filename The name of the file.
658: * @return Do we have a potential jdo file?
659: */
660: static private boolean isJdoFileName(String filename) {
661: // currently not case-tolerant
662: return filename.endsWith(".jdo");
663: }
664:
665: /**
666: * Prints out an error.
667: *
668: * @param msg The error message (can be <code>null</code>).
669: * @param ex An optional exception (can be <code>null</code>).
670: */
671: private void printError(String msg, Throwable ex) {
672: out.flush();
673: if (msg != null) {
674: err.println(msg
675: + (ex != null ? ": " + ex.getMessage() : ""));
676: }
677: if (ex != null) {
678: ex.printStackTrace(err);
679: }
680: }
681:
682: /**
683: * Prints out a message.
684: *
685: * @param msg The message.
686: */
687: private void printMessage(String msg) {
688: out.println(msg);
689: }
690: }
|