FileDocCategorySizeDatePackage
Main.javaAPI DocGlassfish v2 API38491Fri May 04 22:34:26 BST 2007com.sun.jdo.api.persistence.enhancer

Main

public class Main extends Object
Main is the starting point for the persistent filter tool.

Fields Summary
private ByteCodeEnhancer
enhancer
The byte code enhancer.
private final PrintWriter
outMessages
The stream to write messages to.
private final PrintWriter
outErrors
The stream to write error messages to.
private final CmdLineOptions
cmdLineOpts
The command line options.
Constructors Summary
public Main()
Construct a filter tool instance



              
      
    
Methods Summary
private voidappendFileContents(java.lang.String filename, java.util.ArrayList argVec)
Given an input file name, open the file and append each "word" within the file to argVec. This currently has only a very primitive notion of words (separated by white space).

        try {
            FileReader inputFile = new FileReader(filename);
            try {
                BufferedReader input = new BufferedReader(inputFile);
                String s = null;
                while ((s = input.readLine()) != null) {
                    StringTokenizer parser = new StringTokenizer(s, " \t", false);//NOI18N
                    while (parser.hasMoreElements()) {
                        String token = parser.nextToken();
                        if (token.length() > 0 && token.charAt(0) == '@")
                            printError("The included file \"" +//NOI18N
                                      filename +
                                      "\" contains a recursive include.  " +//NOI18N
                                      "Recursive includes are not supported.", null);//NOI18N
                        if (token.charAt(0) == '#") break;
                        argVec.add(token);
                    }
                }
            }
            catch (IOException ex) {
                printError("IO exception reading file " + filename + ".", ex);//NOI18N
            }
        }
        catch (FileNotFoundException ex) {
            printError("file " + filename + " not found.", ex);//NOI18N
        }
    
private final voidcloseInputStream(java.io.InputStream in)
Closes an input stream.

param
in The input stream.


        if  (in != null)
        {
            try
            {
                in.close ();
            }
            catch (IOException ex)
            {
                printError (null, ex);
            }
        }

    
private final voidcloseOutputStream(java.io.OutputStream out)
Closes an output stream.

param
in The output stream.


        if  (out != null)
        {
            try
            {
                out.close ();
            }
            catch (IOException ex)
            {
                printError (null, ex);
            }
        }

    
private static final java.lang.StringcreateClassFileName(java.lang.String classname)
Creates a filename from a classname (by replacing '.' by '/'.

param
classname The classname.
return
The filename.


        return classname.replace ('.", '/") + ".class";

    
private final ByteCodeEnhancercreateEnhancer(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData jdometadata)


        Properties props = new Properties ();
        if  (this.cmdLineOpts.verbose)
        {
            props.put (FilterEnhancer.VERBOSE_LEVEL, FilterEnhancer.VERBOSE_LEVEL_VERBOSE);
        }

        return new FilterEnhancer (jdometadata, props, this.outMessages, this.outErrors);

    
private final voidcreateOutputFile(boolean enhanced, java.lang.String filename, java.io.File temp)
Creates the output file for an enhaced class- or zipfile. If the enhanced file is written back depends on the command line options.

param
enhanced Has the input file been enhanced?
param
filename The name of the output file.
param
temp The temp file, the output is written to.
exception
IOException If the file could not be created.


        //noWrite or (not enhanced and not forceWrite)
        if  (this.cmdLineOpts.noWrite  ||  ( ! enhanced  &&  ! this.cmdLineOpts.forceWrite))
        {
            temp.deleteOnExit ();
            return;
        }

        File file = new File (this.cmdLineOpts.destinationDirectory, filename);
        createPathOfFile (file);
        file.delete ();  //delete old file if exists
        //@olsen: added workaround to JDK bug with file.renameTo()
        boolean renamed = temp.renameTo(file);
        if (!renamed) {
            //@dave: empirical evidence shows that renameTo does not allow for
            // crossing filesystem boundaries.  If it fails, try "by hand".
            try {
                DataInputStream dis =
                    new DataInputStream(new FileInputStream(temp));
                DataOutputStream dos =
                    new DataOutputStream(new FileOutputStream(file));
                int PAGESIZE = 4096; // Suggest a better size?
                byte data[] = new byte[PAGESIZE];
                while (dis.available() > 0) {
                    int numRead = dis.read(data, 0, PAGESIZE);
                    dos.write(data, 0, numRead);
                }
                renamed = true;
                temp.delete ();  // delete temp file
            } catch (IOException ex) {
                // empty
            }
            if (!renamed) {
                throw new IOException("Could not rename temp file '" +
                                      temp.getAbsolutePath() +
                                      "' to '" + file.getAbsolutePath() + "'.");
            }
        }
    
private static final voidcreatePathOfFile(java.io.File file)
Creates only the path of the given file.

param
file The file.
exception
IOException If an error occured.


        //Verzeichnis erzeugen
        File dir = file.getAbsoluteFile ().getParentFile ();
        if  ( ! dir.exists ()  &&  ! dir.mkdirs ())
        {
            throw new IOException ("Error creating directory '" + dir.getAbsolutePath () + "'.");
        }

    
private final java.io.FilecreateZipOutputFile(java.lang.String zipfilename)
Creates a file object that represents the output zipfile for a given zipfile to enhance.

param
zipfilename The input zipfile name.
return
The output zipfile name.


        return new File (this.cmdLineOpts.destinationDirectory, new File (zipfilename).getName ());

    
private final voidenhanceClassFile(java.io.InputStream in)
Enhances a classfile.

param
in The input stream of the classfile.


        OutputStream out = null;
        try
        {
            File temp = File.createTempFile ("enhancer", ".class");
            out = new BufferedOutputStream (new FileOutputStream (temp));

            //enhance
            OutputStreamWrapper wrapper = new OutputStreamWrapper (out);
            boolean enhanced = this.enhancer.enhanceClassFile (in, wrapper);
            closeOutputStream (out);
            createOutputFile (enhanced, createClassFileName (wrapper.getClassName ()), temp);
        }
        catch (Throwable ex)
        {
            printError (null, ex);
        }
        finally
        {
            closeInputStream (in);
            closeOutputStream (out);
        }

    
private final voidenhanceInputFiles(java.util.Collection filenames)
Enhances all files entered in the command line.

param
filenames The filenames.


        for (Iterator names = filenames.iterator(); names.hasNext ();)
        {
            try
            {
                String name = (String) names.next ();
                int n = name.length ();

                //if we have a class-files
                InputStream in = null;
                if (isClassFileName (name))
                {
                    enhanceClassFile (openFileInputStream (name));
                }
                else
                {
                    //if we have an archive
                    if (isZipFileName (name))
                    {
                        enhanceZipFile (name); //getZipFile (name));
                    }
                    //assume that it is a class name
                    else
                    {
                        enhanceClassFile (openClassInputStream (name));
                    }
                }
            }
            catch (Throwable ex)
            {
                printError (null, ex);
            }
        }

    
private final voidenhanceZipFile(java.lang.String filename)
Enhances a zipfile.

param
name The filename of the zipfile.


        ZipInputStream  in = null;
        ZipOutputStream out = null;
        try
        {
            File temp = File.createTempFile ("enhancer", ".zip");
            in = new ZipInputStream (new BufferedInputStream (new FileInputStream (new File (filename))));
            out = new ZipOutputStream (new BufferedOutputStream (new FileOutputStream (temp)));

            //enhance the zipfile
            boolean enhanced = ByteCodeEnhancerHelper.enhanceZipFile (this.enhancer, in, out);
            closeOutputStream (out);
            out = null;

            //create the output file
            createOutputFile (enhanced, new File (filename).getName (), temp);
        }
        catch (Throwable ex)
        {
            printError (null, ex);
        }
        finally
        {
            closeOutputStream (out);
            closeInputStream (in);
        }

    
private static final booleanisClassFileName(java.lang.String filename)
Tests if a filename is a classfile name.

param
filename The name of the file.
return
Do we have a potential classfile?


        return filename.endsWith (".class");

    
private static final booleanisZipFileName(java.lang.String filename)
Tests if a filename is a zipfile (only by testing if the extension - ignoring the case - is ".zip" or ".jar").

param
filename The name of the file.
param
Do we have a potential zipfile?


        final int n = filename.length ();
        if  (n < 5)
        {
            return false;
        }
        String ext = filename.substring (n - 4);

        return ext.equalsIgnoreCase (".zip")  ||  ext.equalsIgnoreCase (".jar");

    
public static voidmain(java.lang.String[] argv)
This is where it all starts.

        //@olsen: added support for timing statistics
        final Main main = new Main();
        try {
            //@olsen: split: method filter() -> process(), processArgs()
            //System.exit(new Main().process(argv));
            main.process(argv);
        } catch (RuntimeException tt) {
            //} catch (Throwable tt) {
            //@olsen: changed to print to error stream
            System.err.println("Exception occurred while postprocessing:");
            tt.printStackTrace(System.err);
            //System.exit(1);
            throw tt;
        } finally {
            //@olsen: added support for timing statistics
            if (main.cmdLineOpts.doTiming) {
                Support.timer.print();
            }
        }
    
private final java.io.InputStreamopenClassInputStream(java.lang.String classname)
Opens an input stream for the given classname. The input stream is created via an URL that is obtained by the current ClassLoader.

param
classname The name of the class (dot-notation).
return
The iput stream.
exception
IOException If an I/O error occured.
exception
ClassNotFoundException If the class could not be found.


        URL url = Main.class.getClassLoader ().getSystemResource (createClassFileName (classname));
        if  (url == null)
        {
            throw new ClassNotFoundException (classname);
        }
        return url.openStream ();

    
private static final java.io.InputStreamopenFileInputStream(java.lang.String filename)
Opens an input stream for the given filename

param
filename The name of the file.
return
The input stream.
exception
FileNotFoundException If the file could not be found.


     	return new BufferedInputStream (new FileInputStream (new File (filename)));

    
private java.lang.String[]preprocess(java.lang.String[] args)
Preprocess @files, returning a new argv incorporating the contents of the @files, if any

        ArrayList argVec = new ArrayList();
        for (int i=0; i<args.length; i++) {
            if (args[i].length() > 0 && args[i].charAt(0) == '@") {
                String filename = null;
                if (args[i].length() == 1) {
                    if (i+1 < args.length)
                        filename = args[++i];
                } else {
                    filename = args[i].substring(1);
                }

                if (filename == null) {
                    printError("missing file name argument to @.", null);//NOI18N
                } else {
                    appendFileContents(filename, argVec);
                }
            } else {
                argVec.add(args[i]);
            }
        }
        //@olsen: subst: Vector -> ArrayList
        //String[] newArgs = new String[argVec.size()];
        //argVec.copyInto(newArgs);
        final String[] newArgs = (String[])argVec.toArray(new String[0]);
        return newArgs;
    
private final voidprintError(java.lang.String msg, java.lang.Throwable ex)
Prints out an error.

param
msg The error message (can be null).
param
ex An optional exception (can be null).


        if  (msg != null)
        {
            this.outErrors.println (msg + (ex != null  ?  ": " + ex  :  ""));
        }
        if (ex != null)
        {
            ex.printStackTrace (this.outErrors);
        }

    
private final voidprintMessage(java.lang.String msg)
Prints out a message.

param
msg The message.


        this.outMessages.println (msg);

    
public intprocess(java.lang.String[] argv)
Process command line options and perform filtering tasks

        //@olsen: added inplace of disabled feature
        ArrayList cNames = new ArrayList();
        //@olsen: split: method filter() -> process(), processArgs()
        int res = processArgs(argv, cNames);
        if (res != 0) {
            //@olsen: added println()
            printMessage ("aborted with errors.");//NOI18N
            return res;
        }

        //@olsen: added support for timing statistics
        try {
            if (this.cmdLineOpts.doTiming) {
                Support.timer.push("Main.process(String[])");//NOI18N
            }

            // Find all of the classes on which we want to operate
//@olsen: disabled feature
            enhanceInputFiles (cNames);
/*
            computeClasses(pcNames, paNames, ccNames);
*/

            printMessage ("done.");//NOI18N
            return 0;
        } finally {
            if (this.cmdLineOpts.doTiming) {
                Support.timer.pop();
            }
        }
    
protected intprocessArgs(java.lang.String[] argv, java.util.Collection cNames)
Process command line options

        argv = preprocess(argv);

//@olsen: disabled feature
/*
        ArrayList ccNames = new ArrayList();
        ArrayList pcNames = new ArrayList();
        ArrayList paNames = new ArrayList();
        int classMode = ClassControl.PersistCapable;
*/

//@olsen: disabled feature
/*
        String classpath = System.getProperty("java.class.path");
        String sysClasspath = System.getProperty("sun.boot.class.path", "");
*/

        //@olsen: added
        Properties jdoMetaDataProperties = null;

        for (int i=0; i<argv.length; i++) {
            //@olsen: improved control flow, subst: else -> continue

            String arg = argv[i];
//@olsen: disabled feature
/*
            if (arg.equals("-cc") ||
                arg.equals("-copyclass")) {
                classMode = ClassControl.PersistUnknown;
                continue;
            }
            if (arg.equals("-pa") ||
                arg.equals("-persistaware")) {
                classMode = ClassControl.PersistAware;
                continue;
            }
            if (arg.equals("-pc") ||
                arg.equals("-persistcapable")) {
                classMode = ClassControl.PersistCapable;
                continue;
            }
*/
            if (arg.equals("-v") ||//NOI18N
                arg.equals("-verbose")) {//NOI18N
                this.cmdLineOpts.verbose = true;
                this.cmdLineOpts.quiet = false;
                continue;
            }
            if (arg.equals("-q") ||//NOI18N
                arg.equals("-quiet")) {//NOI18N
                this.cmdLineOpts.quiet = true;
                this.cmdLineOpts.verbose = false;
                continue;
            }
            if (arg.equals("-f") ||//NOI18N
                arg.equals("-force")) {//NOI18N
                this.cmdLineOpts.forceWrite = true;
                continue;
            }
//@olsen: disabled feature
/*
            if (arg.equals("-inplace")) {
                env.setUpdateInPlace(true);
                continue;
            }
*/
//@lars: disabled feature
/*
            if (arg.equals("-qf") ||//NOI18N
                arg.equals("-quietfield")) {//NOI18N
                if (argv.length-i < 2) {
                    usage();
                    printError ("Missing argument to the -quietfield option", null);//NOI18N
                } else {
                    String fullFieldName = argv[++i];
                    if (fullFieldName.indexOf('.') == -1) {
                        printError ("Field name specifications must include " +//NOI18N
                                  "a fully qualified class name.  " +//NOI18N
                                  fullFieldName + " does not include one.", null);//NOI18N
                    } else {
                        env.suppressFieldWarnings(fullFieldName);
                    }
                }
                continue;
            }
            if (arg.equals("-qc") ||//NOI18N
                arg.equals("-quietclass")) {//NOI18N
                if (argv.length-i < 2) {
                    usage();
                    env.error("Missing argument to the -quietclass option");//NOI18N
                } else {
                    env.suppressClassWarnings(argv[++i]);
                }
                continue;
            }
*/
            if (arg.equals("-nowrite")) {//NOI18N
                this.cmdLineOpts.noWrite = true;
                continue;
            }
//@olsen: disabled feature
/*
            if (arg.equals("-modifyjava")) {
                env.setModifyJavaClasses(true);
                continue;
            }
*/
//@olsen: disabled feature
/*
            if (arg.equals("-modifyfinals")) {
                env.setAllowFinalModifications(true);
                continue;
            }
*/
//@olsen: disabled feature
/*
            if (arg.equals("-noarrayopt")) {
                env.setNoArrayOptimization(true);
                continue;
            }
*/
//@lars: disabled feature
/*
            if (arg.equals("-nothisopt")) {//NOI18N
                env.setNoThisOptimization(true);
                continue;
            }
            if (arg.equals("-noinitializeropt")) {//NOI18N
                env.setNoInitializerOptimization(true);
                continue;
            }
            if (arg.equals("-noopt")) {//NOI18N
                env.setNoOptimization(true);
                continue;
            }
*/
            if (arg.equals("-d") ||//NOI18N
                arg.equals("-dest")) {//NOI18N
                if (argv.length-i < 2) {
                    printError ("Missing argument to the -dest option", null);//NOI18N
                    usage();
                }
                this.cmdLineOpts.destinationDirectory = argv[++i];
                continue;
            }
//@olsen: disabled feature
/*
            if (arg.equals("-classpath") ||
                arg.equals("-cpath")) {
                if (argv.length-i < 2) {
                    usage();
                    env.error("Missing argument to the -classpath option");
                }
                classpath = argv[++i];
                continue;
            }
            if (arg.equals("-sysclasspath") ||
                arg.equals("-syscpath")) {
                if (argv.length-i < 2) {
                    usage();
                    env.error("Missing argument to the -sysclasspath option");
                }
                sysClasspath = argv[++i];
                continue;
            }
*/
//@olsen: disabled feature
/*
            if (arg.equals("-tp") ||
                arg.equals("-translatepackage")) {
                if (argv.length-i < 3) {
                    usage();
                    env.error("Missing arguments to the -translatepackage option");
                }
                env.setPackageTranslation(argv[i+1], argv[i+2]);
                i += 2;
                continue;
            }
*/
            //@olsen: new command line option for timing statistics
            if (arg.equals("-t") ||//NOI18N
                arg.equals("--doTiming")) {//NOI18N
                this.cmdLineOpts.doTiming = true;
//                env.setDoTimingStatistics(true);
                continue;
            }
            //@olsen: new command line option for JDO meta data properties
            if (arg.equals("-jp") ||//NOI18N
                arg.equals("--jdoProperties")) {//NOI18N
                if (argv.length-i < 2) {
                    printError("Missing argument to the -jp/--jdoProperties option", null);//NOI18N
                    usage();
                }
                try {
                    jdoMetaDataProperties = new Properties();
                    jdoMetaDataProperties.load(new FileInputStream(argv[++i]));
                } catch (IOException ex) {
                    printError("Cannot read JDO meta data properties from file", ex);//NOI18N
                    usage();
                }
                continue;
            }
            if (arg.length() > 0 && arg.charAt(0) == '-") {
                printError("Unrecognized option:" + arg, null);//NOI18N
                usage();
            }
            if (arg.length() == 0) {
                printMessage ("Empty file name encountered on the command line.");//NOI18N
            }

            //@olsen: added inplace of disabled feature
            cNames.add(arg);
//@olsen: disabled feature
/*
            {
                if (arg.equals("java.lang.Object"))
                    env.error("java.lang.Object may not be postprocessed");
                else if (classMode == ClassControl.PersistCapable)
                    pcNames.add(arg);
                else if (classMode == ClassControl.PersistAware)
                    paNames.add(arg);
                else if (classMode == ClassControl.PersistUnknown)
                    ccNames.add(arg);
                else
                    affirm(false, "Invalid class mode");
            }
*/
        }

        //@olsen: forced settings
        //env.setVerbose(true);
        this.cmdLineOpts.quiet = false;
//        env.setNoOptimization(true);
//        env.message("forced settings: -noopt");//NOI18N

/*
        if (env.errorCount() > 0)
            return 1;
*/

//@olsen: disabled feature
/*
        env.setClassPath(classpath +
                         java.io.File.pathSeparator +
                         sysClasspath);
*/

        // The user must specify a destination directory
        if (this.cmdLineOpts.destinationDirectory == null) {
            if (argv.length > 0)
                printError("No -dest output directory was specified", null);//NOI18N
            usage();
        }

        //@olsen: added: initialize JDO meta data
        JDOMetaData jdoMetaData;
        if (jdoMetaDataProperties != null) {
            printMessage("using JDO meta-data from properties");//NOI18N
            jdoMetaData = new JDOMetaDataPropertyImpl(jdoMetaDataProperties, this.outMessages);
        } else {
            printMessage("using JDO meta-data from Model.Enhancer");//NOI18N
            jdoMetaData = new JDOMetaDataModelImpl(Model.ENHANCER, this.outMessages);
        }
        //@olsen: added support for timing statistics
        if (this.cmdLineOpts.doTiming) {
            // wrap with timing meta data object
            jdoMetaData = new JDOMetaDataTimer(jdoMetaData);
        }

        try
        {
            this.enhancer = createEnhancer (jdoMetaData);
        }
        catch (Exception ex)
        {
            printError ("Error creating the enhancer", ex);
        }


//@olsen: disabled feature
/*
        // -translatepackage is incompatible with in-place update.
        if (env.updateInPlace() && env.translations().size() > 0) {
            env.error("The -translatepackage option cannot be used " +
                      "in conjunction with the -inplace option.");
            return 1;
        }
*/

        // make sure we don't lookup classes from the destination directory
        // unless we are doing in-place annotation, and in that case it should
        // be as a last resort.
//@lars: removed
/*
        if (env.updateInPlace())
            env.moveDestinationDirectoryToEnd();
        else
            env.excludeDestinationDirectory();
*/

        //@olsen: split: method filter() -> process(), processArgs()
        return 0;
    
public static voidusage()
Print a usage message to System.err

        //@olsen: document that main() takes a file name argument
        System.err.println("Usage: main <options> <file name>");
//@olsen: disabled feature
/*
        System.err.println("  { -copyclass | -cc }");
        System.err.println("  { -persistaware | -pa }");
        System.err.println("  { -persistcapable | -pc }");
*/
        System.err.println("  { -verbose | -v }");
        System.err.println("  { -force | -f }");
        System.err.println("  { -quiet | -q }");
//        System.err.println("  { -quietfield | -qf } <qualified field name>");
//        System.err.println("  { -quietclass | -qc } <qualified class name>");
//@olsen: disabled feature
/*
        System.err.println("  -inplace");
*/
//        System.err.println("  -noarrayopt");
//        System.err.println("  -nothisopt");
//        System.err.println("  -noinitializeropt");
//        System.err.println("  -noopt");
//@olsen: disabled feature
/*
        System.err.println("  -modifyjava");
*/
//@olsen: disabled feature
/*
        //@olsen: added missing  cmd line option
        System.err.println("  -modifyfinals");
*/
        System.err.println("  -nowrite");
        System.err.println(" -dest | -d <destination directory>");
//@olsen: disabled feature
/*
        System.err.println("  { -translatepackage | -tp } <orig pkg name> <new pkg name>");
*/
//@olsen: disabled feature
/*
        System.err.println("  { -arraydims | -a } <number of array dimensions>");
*/
//@olsen: disabled feature
/*
        System.err.println("  { -classpath | -cpath } <classpath for lookup>");
        System.err.println("  { -sysclasspath | -syscpath } <system classpath for lookup>");
*/
        //@olsen: new command line option for JDO meta data properties
        System.err.println("  --jdoProperties | -jp");
        System.err.println("  --timing | -t");

        System.err.println("  @<cmd-arg-file>");

        System.exit (1);