You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 19:55:54 UTC

svn commit: r171351 [2/16] - in /incubator/jdo/trunk/enhancer20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/enhancer/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/enhancer/ src/java/org/apache/jdo/impl/enhancer/classfile/ src/java/org/apache/jdo/impl/enhancer/core/ src/java/org/apache/jdo/impl/enhancer/generator/ src/java/org/apache/jdo/impl/enhancer/meta/ src/java/org/apache/jdo/impl/enhancer/meta/model/ src/java/org/apache/jdo/impl/enhancer/meta/prop/ src/java/org/apache/jdo/impl/enhancer/meta/util/ src/java/org/apache/jdo/impl/enhancer/util/ test/ test/sempdept/ test/sempdept/src/ test/sempdept/src/empdept/

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java Sun May 22 10:55:51 2005
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.File;
+
+import org.apache.jdo.impl.enhancer.util.PathResourceLocator;
+
+
+
+/**
+ * Base class for JDO command line enhancer and tests.
+ *
+ * @author Martin Zaun
+ */
+public class ClassArgMain
+    extends GenericMain
+{
+    /**
+     *  The options and arguments.
+     */
+    protected ClassArgOptions options;
+
+    /**
+     *  The locator for classes.
+     */
+    protected PathResourceLocator classes;
+
+    /**
+     * Creates an instance.
+     */
+    public ClassArgMain(PrintWriter out,
+                        PrintWriter err)
+    {
+        this(out, err, new ClassArgOptions(out, err));
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public ClassArgMain(PrintWriter out,
+                        PrintWriter err,
+                        ClassArgOptions options)
+    {
+        super(out, err, options);
+        this.options = options;
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Initializes the class locator.
+     */
+    protected void initClassLocator()
+        throws IOException
+    {
+        // create resource locator for specified source path
+        final String path = options.sourcePath.value;
+        if (path != null) {
+            affirm(path.length() > 0);
+            final boolean verbose = options.verbose.value;
+            classes = new PathResourceLocator(out, verbose, path);
+        }
+    }
+
+    /**
+     * Initializes all components.
+     */
+    protected void init()
+        throws EnhancerFatalError, EnhancerUserException
+    {
+        try {
+            initClassLocator();
+        } catch (Exception ex) {
+            throw new EnhancerFatalError(ex);
+        }
+    }
+    
+    // ----------------------------------------------------------------------
+
+    /**
+     *  Returns the file name for a class name.
+     *  This is done by replacing <code>'.'</code> by <code>'/'</code>.
+     *
+     *  @param  className  the classname
+     *  @return  the filename
+     */
+    static protected String getClassFileName(String className)
+    {
+        return className.replace('.', '/') + ".class";
+    }
+
+    /**
+     *  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
+     */
+    protected InputStream openFileInputStream(String fileName)
+        throws FileNotFoundException
+    {
+        affirm(fileName != null);
+        //^olsen: support for timing
+        //if (options.doTiming.value) {...}
+     	return new BufferedInputStream(new FileInputStream(fileName));
+    }
+
+    /**
+     * Opens an input stream for the given classname. The input stream is
+     * created via an URL that is obtained by the value of the sourcepath
+     * option and zip/jar file arguments.
+     * 
+     * @param  className  the name of the class (dot-notation)
+     * @return  the input stream
+     * @exception IOException if an I/O error occured
+     */
+    protected InputStream openClassInputStream(String className)
+        throws IOException
+    {
+        affirm(className != null);
+        final String resName = className.replace('.', '/') + ".class";
+        //^olsen: support for timing
+        //if (options.doTiming.value) {...}
+        final InputStream s = classes.getInputStreamForResource(resName);
+        affirm(s != null);
+        return new BufferedInputStream(s);
+    }
+
+    /**
+     *  Closes an input stream.
+     *
+     *  @param  in  the input stream
+     */
+    protected void closeInputStream(InputStream in)
+    {
+        if (in != null) {
+            try {
+                in.close();
+            } catch (IOException ex) {
+                printlnErr("", ex);
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Runs this class
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> ClassArgMain.main()");
+        final ClassArgMain main = new ClassArgMain(out, out);
+        int res = main.run(args);
+        out.println("<-- ClassArgMain.main(): exit = " + res);
+        System.exit(res);
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java Sun May 22 10:55:51 2005
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+
+/**
+ * Set of options used by the JDO enhancer and its test programs.
+ *
+ * @author Martin Zaun
+ */
+public class ClassArgOptions
+    extends GenericOptions
+{
+    /**
+     * Tests if a filename has suffix <code>".class"</code> (ignoring case).
+     *
+     * @param  filename  the name of the file
+     * @return true if filename has a class file suffix
+     */
+    static private boolean isClassFileName(String filename)
+    {
+        return filename.toLowerCase().endsWith(".class");
+    }
+
+    /**
+     * Tests if a filename has suffix <code>".jar"</code> or
+     * <code>".zip"</code> (ignoring case).
+     *
+     * @param  filename  the name of the file
+     * @return true if filename has an archive file suffix
+     */
+    static private boolean isArchiveFileName(String filename)
+    {
+        final String s = filename.toLowerCase();
+        return (s.endsWith(".jar") || s.endsWith(".zip"));
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * The source path option.
+     */
+    public final StringOption sourcePath
+        = createStringOption("sourcepath", "s",
+                             "<path>  : path for lookup of class files");
+
+    /**
+     * The list of class name arguments.
+     */
+    public final List classNames = new ArrayList();        
+
+    /**
+     * The list of class file name arguments.
+     */
+    public final List classFileNames = new ArrayList();        
+
+    /**
+     * The list of archive file name arguments.
+     */
+    public final List archiveFileNames = new ArrayList();        
+
+    /**
+     * Creates an instance.
+     */
+    public ClassArgOptions(PrintWriter out,
+                       PrintWriter err) 
+    {
+        super(out, err);
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Print a usage message to System.err.
+     */
+    public void printUsageHeader()
+    {
+        printlnErr("Usage: <options>.. <arguments>..");
+        printlnErr(indent
+                   + "-s <path>   <classname>..");
+        printlnErr(indent
+                   + "            <classfile>..");
+        //^olsen: re-enable support for archive files
+        //printlnErr(indent
+        //           + "            <archivefile>..");
+    }
+
+    /**
+     * Print a usage message to System.err.
+     */
+    public void printArgumentUsage()
+    {
+        printlnErr(indent
+                   + "<classname>       the fully qualified name of a Java class");
+        printlnErr(indent
+                   + "<classfile>       the name of a .class file");
+        printlnErr(indent
+                   + "<archivefile>     the name of a .zip or .jar file");
+    }
+
+    /**
+     * Print arguments.
+     */
+    public void printArguments()
+    {
+        println();
+        println(argumentsHeader);
+        printListArgument("classNames", classNames);
+        printListArgument("classFileNames", classFileNames);
+        printListArgument("archiveFileNames", archiveFileNames);
+    }
+    
+    /**
+     * Print argument of list type.
+     */
+    public void printListArgument(String name, List list)
+    {
+        print(indent);
+        final StringBuffer s = new StringBuffer();
+        for (Iterator i = list.iterator(); i.hasNext();) {
+            s.append(" " + i.next());
+        }
+        println(name + " = {" + s.toString() + " }");
+        println();
+    }
+
+    /**
+     * Check options and arguments.
+     */
+    public int check()
+    {
+        int res;
+        if ((res = super.check()) != OK) {
+            return res;
+        }
+
+        // group input file arguments
+        for (Iterator names = arguments.iterator(); names.hasNext();) {
+            final String name = (String)names.next();
+            if (isClassFileName(name)) {
+                classFileNames.add(name);
+            } else if (isArchiveFileName(name)) {
+                archiveFileNames.add(name);
+            } else {
+                classNames.add(name);
+            }
+        }
+
+        if (verbose.value) {
+            printAll();
+        }
+        
+        // check class arguments
+        final int argTypes = ((classNames.isEmpty() ? 0 : 1)
+                              + (classFileNames.isEmpty() ? 0 : 1)
+                              + (archiveFileNames.isEmpty() ? 0 : 1));
+        if (argTypes == 0) {
+            printUsageError("No class arguments: specify classes either by class name, class file, or archive file");
+            return USAGE_ERROR;
+        }
+        if (argTypes > 1) {
+            printUsageError("Mixed class arguments: specify classes by either class name, class file, or archive file");
+            return USAGE_ERROR;
+        }
+        
+        // check sourcepath option
+        if (sourcePath.value == null && !classNames.isEmpty()) {
+            printUsageError("No source-path specified for lookup of classes");
+            return USAGE_ERROR;
+        }
+        if (sourcePath.value != null && classNames.isEmpty()) {
+            printUsageError("No source-path can be specified with class or archive files");
+            return USAGE_ERROR;
+        }
+
+        //^olsen: re-enable support for archive files
+        if (!archiveFileNames.isEmpty()) {
+            printUsageError("Sorry, support for archive files currently disabled");
+            return USAGE_ERROR;
+        }
+
+        return OK;
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Tests the class.
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> ClassArgOptions.main()");
+        final ClassArgOptions options = new ClassArgOptions(out, out);
+        out.println("    options.process() ...");
+        int res = options.process(args);
+        out.println("    return value: " + res);
+        out.println("<-- ClassArgOptions.main()");
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java Sun May 22 10:55:51 2005
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A JDO enhancer, or byte-code enhancer, modifies the byte-codes of
+ * Java class files to enable transparent loading and storing of the
+ * fields of the persistent instances.
+ *
+ * @author Martin Zaun
+ */
+public interface ClassFileEnhancer
+{
+    /**
+     * Enhances a given class according to the JDO meta-data. If the
+     * input class has been enhanced or not - the output stream is
+     * always written, either with the enhanced class or with the
+     * non-enhanced class.
+     *
+     * @param in The byte-code of the class to be enhanced.
+     * @param out The byte-code of the enhanced class.
+     * @return  <code>true</code> if the class has been enhanced,
+     *          <code>false</code> otherwise.
+     */
+   boolean enhanceClassFile(InputStream in,
+                            OutputStream out)
+        throws EnhancerUserException, EnhancerFatalError;
+
+
+    /**
+     * Enhances a given class according to the JDO meta-data. If the
+     * input class has been enhanced or not - the output stream is
+     * always written, either with the enhanced class or with the
+     * non-enhanced class.
+     * <p>
+     * Furthermore, the enhancer has to set the classname of
+     * the enhanced class to the output stream wrapper object (it's
+     * possible to get the input stream without knowing the classname).
+     *
+     * @param in  The byte-code of the class to be enhanced.
+     * @param out The byte-code of the enhanced class.
+     * @return  <code>true</code> if the class has been enhanced,
+     *          <code>false</code> otherwise.
+     */
+    boolean enhanceClassFile(InputStream in,
+                             OutputStreamWrapper out)
+            throws EnhancerUserException, EnhancerFatalError;
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java Sun May 22 10:55:51 2005
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+
+/**
+ *  This is a helper-class to perform some useful operations outside a
+ *  byte code enhancer and delegate the real work to the enhancer.
+ */
+public class ClassFileEnhancerHelper
+{
+    /**
+     *  Enhances a classfile.
+     *
+     *  @param  enhancer  The enhancer to delegate the work to.
+     *  @param  in        The input stream with the Java class.
+     *  @param  out       The output stream to write the enhanced class to.
+     *
+     *  @return  Has the input stream been enhanced?
+     *
+     *  @exception  EnhancerUserException  If something went wrong.
+     *  @exception  EnhancerFatalError     If something went wrong.
+     *
+     *  @see  ClassFileEnhancer#enhanceClassFile
+     */
+    static public boolean enhanceClassFile(ClassFileEnhancer enhancer,
+                                           InputStream      in,
+                                           OutputStream     out)
+        throws EnhancerUserException,
+        EnhancerFatalError
+    {
+        return enhancer.enhanceClassFile(in, new OutputStreamWrapper(out));
+    }
+
+    /**
+     *  Enhances a zip file. The zip file is given as a uip input stream.
+     *  It's entries are read and - if necessary - individually enhanced.
+     *  The output stream has the same compressíon (if any) as the input
+     *  stream.
+     *
+     *  @param  enhancer  The enhancer.
+     *  @param  zip_in    The zip input stream.
+     *  @param  zip_out   The zip output stream.
+     *
+     *  @return  <code>true</code> if at least one entry of the zip file has
+     *           been enhanced, <code>false</code> otherwise.
+     *
+     *  @exception  EnhancerUserException  If something went wrong.
+     *  @exception  EnhancerFatalError     If something went wrong.
+     *
+     *  @see  ClassFileEnhancer#enhanceClassFile
+     */
+    static public boolean enhanceZipFile(ClassFileEnhancer enhancer,
+                                         ZipInputStream zip_in,
+                                         ZipOutputStream zip_out)
+        throws EnhancerUserException,
+        EnhancerFatalError
+    {
+        boolean enhanced = false;
+        try {
+            CRC32 crc32 = new CRC32();
+            ZipEntry entry;
+            while ((entry = zip_in.getNextEntry()) != null) {
+                InputStream in = zip_in;
+                final ZipEntry out_entry = new ZipEntry(entry);
+
+                // try to enhance
+                if (isClassFileEntry(entry)) {
+                    // enhance the classfile
+                    // we have to copy the classfile, because if it won't be
+                    // enhanced, the OutputStream is empty and we have to
+                    // re-read the InputStream, which is impossible with a
+                    // ZipInputStream (no mark/reset)
+                    in = openZipEntry(zip_in);
+                    in.mark(Integer.MAX_VALUE);
+                    final ByteArrayOutputStream tmp
+                        = new ByteArrayOutputStream();
+                    if (enhancer.enhanceClassFile(in, tmp)) {
+                        enhanced = true;
+                        final byte[] bytes = tmp.toByteArray();
+                        tmp.close();
+                        in.close();
+                        modifyZipEntry(out_entry, bytes, crc32);
+                        in = new ByteArrayInputStream(bytes);
+                    } else {
+                        // the classfile has not been enhanced
+                        in.reset();
+                    }
+                }
+
+                // copy the entry
+                zip_out.putNextEntry(out_entry);
+                copyZipEntry(in, zip_out);
+                zip_out.closeEntry();
+
+                if (in != zip_in) {
+                    in.close();
+                }
+            }
+        } catch (IOException ex) {
+            throw new EnhancerFatalError(ex);
+        }
+
+        return enhanced;
+    }
+
+    /**
+     *  Copies a zip entry from one stream to another.
+     *
+     *  @param  in   The inout stream.
+     *  @param  out  The output stream.
+     *
+     *  @exception  IOException  If the stream access failed.
+     */
+    static private void copyZipEntry(InputStream  in,
+                                     OutputStream out)
+        throws IOException
+    {
+        int b;
+        while ((in.available() > 0) && (b = in.read()) > -1) {
+            out.write(b);
+        }
+    }
+
+    /**
+     *  Opens the next zip entry of a zip input stream and copies it to
+     *  a <code>java.io.ByteArrayOutputStream</code>. It's byte array is made
+     *  available via an <code>java.io.ByteArrayInputStream</code> which is
+     *  returned.
+     *
+     *  @param  in  The zip input stream.
+     *
+     *  @return  The newly created input stream with the next zip entry.
+     *
+     *  @exception  IOException  If an I/O operation failed.
+     */
+    static private InputStream openZipEntry(ZipInputStream in)
+        throws IOException
+    {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        copyZipEntry(in, out);
+
+        return new ByteArrayInputStream(out.toByteArray());
+    }
+
+    /**
+     *  Modifies the given zip entry so that it can be added to zip file.
+     *  The given zip entry represents an enhanced class, so the zip entry
+     *  has to get the correct size and checksum (but only if the entry won't
+     *  be compressed).
+     *
+     *  @param  entry  The zip entry to modify.
+     *  @param  bytes  The uncompressed byte representation of the classfile.
+     *  @param  crc32  The checksum evaluator.
+     */
+    private static void modifyZipEntry(ZipEntry entry,
+                                       byte []  bytes,
+                                       CRC32    crc32)
+    {
+        entry.setSize(bytes.length);
+        if (entry.getMethod() == 0) {
+            //no compression (ZipInputStream.STORED - not accessible)
+            crc32.reset();
+            crc32.update(bytes);
+            entry.setCrc(crc32.getValue());
+            entry.setCompressedSize(bytes.length);
+        }
+    }
+
+    /**
+     *  Determines if a given entry represents a classfile.
+     *
+     *  @return  Does the given entry represent a classfile?
+     */
+    private static boolean isClassFileEntry(ZipEntry entry)
+    {
+        return entry.getName().endsWith(".class");
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java Sun May 22 10:55:51 2005
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+/**
+ * Timer-wrapper for ClassFileEnhancer instances.
+ *
+ * @author Martin Zaun
+ */
+public final class ClassFileEnhancerTimer
+    extends Support
+    implements ClassFileEnhancer
+{
+    // delegate
+    final protected ClassFileEnhancer delegate;
+
+    /**
+     * Creates an instance.
+     */
+    public ClassFileEnhancerTimer(ClassFileEnhancer delegate)
+    {
+        affirm(delegate);
+        this.delegate = delegate;
+    }
+
+    public boolean enhanceClassFile(InputStream inClassFile,
+                                    OutputStream outClassFile)
+        throws EnhancerUserException, EnhancerFatalError
+    {
+        try {
+            timer.push("ClassFileEnhancer.enhanceClassFile(InputStream,OutputStream)");
+            return delegate.enhanceClassFile(inClassFile, outClassFile);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean enhanceClassFile(InputStream inClassFile,
+                                    OutputStreamWrapper outClassFile)
+        throws EnhancerUserException, EnhancerFatalError
+    {
+        try {
+            timer.push("ClassFileEnhancer.enhanceClassFile(InputStream,OutputStreamWrapper)");
+            return delegate.enhanceClassFile(inClassFile, outClassFile);
+        } finally {
+            timer.pop();
+        }
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java Sun May 22 10:55:51 2005
@@ -0,0 +1,584 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.lang.ref.WeakReference;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import java.util.Properties;
+
+import java.net.URLClassLoader;
+import java.net.URL;
+
+//^olsen: eliminate these dependencies
+import sun.misc.Resource;
+import sun.misc.URLClassPath;
+
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.CodeSource;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+import java.security.cert.Certificate;
+
+import org.apache.jdo.impl.enhancer.core.EnhancerFilter;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.meta.model.EnhancerMetaDataJDOModelImpl;
+import org.apache.jdo.impl.enhancer.meta.prop.EnhancerMetaDataPropertyImpl;
+import org.apache.jdo.impl.enhancer.meta.util.EnhancerMetaDataTimer;
+import org.apache.jdo.impl.enhancer.util.Support;
+import org.apache.jdo.model.jdo.JDOModel;
+
+
+
+
+
+
+/**
+ * Implements a ClassLoader which automatically enchances the .class files
+ * according to the EnhancerMetaData information in the jar archive.
+ *
+ * @author Yury Kamen
+ * @author Martin Zaun
+ */
+public class EnhancerClassLoader extends URLClassLoader {
+
+    static public final String DO_TIMING_STATISTICS
+        = EnhancerFilter.DO_TIMING_STATISTICS;
+    static public final String VERBOSE_LEVEL
+        = EnhancerFilter.VERBOSE_LEVEL;
+    static public final String VERBOSE_LEVEL_QUIET
+        = EnhancerFilter.VERBOSE_LEVEL_QUIET;
+    static public final String VERBOSE_LEVEL_WARN
+        = EnhancerFilter.VERBOSE_LEVEL_WARN;
+    static public final String VERBOSE_LEVEL_VERBOSE
+        = EnhancerFilter.VERBOSE_LEVEL_VERBOSE;
+    static public final String VERBOSE_LEVEL_DEBUG
+        = EnhancerFilter.VERBOSE_LEVEL_DEBUG;
+
+    static public URL[] pathToURLs(String classpath)
+    {
+        return URLClassPath.pathToURLs(classpath);
+    }
+
+    static final void affirm(boolean cond)
+    {
+        if (!cond)
+            //^olsen: throw AssertionException ?
+            throw new RuntimeException("Assertion failed.");
+    }
+
+    // misc
+    private boolean debug = true;
+    private boolean doTiming = false;
+    private PrintWriter out = new PrintWriter(System.out, true);
+
+    private ClassFileEnhancer enhancer;
+    private EnhancerMetaData metaData;
+    private Properties settings;
+    private WeakReference outByteCodeRef;
+
+    // The search path for classes and resources
+    private final URLClassPath ucp;
+
+    // The context to be used when loading classes and resources
+    private final AccessControlContext acc;
+
+    private final void message()
+    {
+        if (debug) {
+            out.println();
+        }
+    }
+
+    private final void message(String s)
+    {
+        if (debug) {
+            out.println(s);
+        }
+    }
+
+    private final void message(Exception e)
+    {
+        if (debug) {
+            final String msg = ("Exception caught: " + e);
+            out.println(msg);
+            e.printStackTrace(out);
+        }
+    }
+
+    /**
+     * Creates a new EnhancerClassLoader for the specified url.
+     *
+     * @param urls the classpath to search
+     */
+    protected EnhancerClassLoader(URL[] urls)
+    {
+        super(urls);
+        acc = AccessController.getContext();
+        ucp = new URLClassPath(urls);
+        checkUCP(urls);
+    }
+
+    /**
+     * Creates a new EnhancerClassLoader for the specified url.
+     *
+     * @param urls the classpath to search
+     */
+    protected EnhancerClassLoader(URL[] urls,
+                                  ClassLoader loader)
+    {
+        super(urls, loader);
+        acc = AccessController.getContext();
+        ucp = new URLClassPath(urls);
+        checkUCP(urls);
+    }
+
+    /**
+     * Creates a new EnhancerClassLoader for the specified url.
+     *
+     * @param classpath the classpath to search
+     */
+    public EnhancerClassLoader(String classpath,
+                               Properties settings,
+                               PrintWriter out)
+    {
+        this(pathToURLs(classpath));
+        //^olsen: instantiate model
+        affirm(false);
+        EnhancerMetaData metaData
+            = new EnhancerMetaDataJDOModelImpl(out, true, null, null, null);
+        init(metaData, settings, out);
+    }
+
+    /**
+     * Creates a new EnhancerClassLoader for the specified url.
+     *
+     * @param urls the classpath to search
+     */
+    public EnhancerClassLoader(URL[] urls,
+                               Properties settings,
+                               PrintWriter out)
+    {
+        this(urls);
+        //^olsen: instantiate model
+        affirm(false);
+        EnhancerMetaData metaData
+            = new EnhancerMetaDataJDOModelImpl(out, true, null, null, null);
+        init(metaData, settings, out);
+    }
+
+    /**
+     * Creates a new EnhancerClassLoader for the specified url.
+     *
+     * @param classpath the classpath to search
+     */
+    public EnhancerClassLoader(String classpath,
+                               EnhancerMetaData metaData,
+                               Properties settings,
+                               PrintWriter out)
+    {
+        this(pathToURLs(classpath));
+        init(metaData, settings, out);
+    }
+
+    /**
+     * Creates a new EnhancerClassLoader for the specified url.
+     *
+     * @param urls the classpath to search
+     */
+    public EnhancerClassLoader(URL[] urls,
+                               EnhancerMetaData metaData,
+                               Properties settings,
+                               PrintWriter out)
+    {
+        this(urls);
+        init(metaData, settings, out);
+    }
+
+    /**
+     * Appends the specified URL to the list of URLs to search for
+     * classes and resources.
+     *
+     * @param url the URL to be added to the search path of URLs
+     */
+    protected void addURL(URL url)
+    {
+        throw new UnsupportedOperationException("Not implemented yet: EnhancerClassLoader.addURL(URL)");
+        //super.addURL(url);
+        //ucp.addURL(url);
+    }
+
+    private void checkUCP(URL[] urls)
+    {
+        // ensure classpath is not empty
+        if (null == urls) {
+            throw new IllegalArgumentException("urls == null");
+        }
+        if (urls.length == 0) {
+            throw new IllegalArgumentException("urls.length == 0");
+        }
+
+        for (int i = 0; i < urls.length; i++) {
+            super.addURL(urls[i]);
+        }
+    }
+
+    /**
+     * Initialize the EnhancingClassLoader
+     */
+    private void init(EnhancerMetaData metaData,
+                      Properties settings,
+                      PrintWriter out)
+    {
+        this.out = out;
+        final String verboseLevel
+            = (settings == null ? null
+               : settings.getProperty(EnhancerFilter.VERBOSE_LEVEL));
+        this.debug = EnhancerFilter.VERBOSE_LEVEL_DEBUG.equals(verboseLevel);
+        this.settings = settings;
+        this.metaData = metaData;
+        this.enhancer = null;
+
+        if (settings != null) {
+            final String timing
+                = settings.getProperty(EnhancerFilter.DO_TIMING_STATISTICS);
+            this.doTiming = Boolean.valueOf(timing).booleanValue();
+        }
+        if (this.doTiming) {
+            // wrap with timing meta data object
+            this.metaData = new EnhancerMetaDataTimer(metaData);
+        }
+
+        message("EnhancerClassLoader: UCP = {");
+        final URL[] urls = getURLs();
+        for (int i = 0; i < urls.length; i++) {
+            message("    " + urls[i]);
+        }
+        message("}");
+
+        message("EnhancerClassLoader: jdoMetaData = " + metaData);
+    }
+
+    public synchronized Class loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        message();
+        message("EnhancerClassLoader: loading class: " + name);
+
+        try {
+            Class c = null;
+
+            final String classPath = name.replace('.', '/');
+            // At least these packages must be delegated to parent class
+            // loader:
+            //    java/lang,	     (Object, ...)
+            //    java/util,         (Collection)
+            //    java/io,           (PrintWriter)
+            //    javax/sql,         (PMF->javax.sql.DataSource)
+            //    javax/transaction  (Tx->javax.transaction.Synchronization)
+            //
+            //@olsen: delegate loading of "safe" classes to parent
+            //if (metaData.isTransientClass(classPath)) {
+            //
+            //@olsen: only delegate loading of bootstrap classes to parent
+            //if (classPath.startsWith("java/lang/")) {
+            //
+            //@olsen: performance bug 4457471: delegate loading of F4J
+            // persistence classes to parent tp prevent passing these and
+            // other IDE classes plus database drivers etc. to the enhancer!
+            //if (classPath.startsWith("java/lang/")
+            //    || classPath.startsWith("com/sun/forte4j/persistence/")) {
+            //
+            //@olsen: bug 4480618: delegate loading of javax.{sql,transaction}
+            // classes to parent class loader to support user-defined
+            // DataSource and Synchronization objects to be passed to the
+            // TP runtime.  By the same argument, java.{util,io} classes need
+            // also be loaded by the parent class loader.  This has been
+            // the case since the EnhancerClassLoader will never find these
+            // bootstrap classes in the passed Classpath.  However, for
+            // efficiency and clarity, this delegation should be expressed
+            // by testing for entire "java/" package in the check here.
+            if (classPath.startsWith("java/")//NOI18N
+                || classPath.startsWith("javax/sql/")//NOI18N
+                || classPath.startsWith("javax/transaction/")//NOI18N
+                || classPath.startsWith("com/sun/forte4j/persistence/")) {//NOI18N
+                message("EnhancerClassLoader: bootstrap class, using parent loader for class: " + name);//NOI18N
+                return super.loadClass(name, resolve);
+
+//@olsen: dropped alternative approach
+/*
+                message("EnhancerClassLoader: transient class, skipping enhancing: " + name);
+
+                // get a byte array output stream to collect byte code
+                ByteArrayOutputStream outClassFile
+                    = ((null == outByteCodeRef)
+                       ? null : (ByteArrayOutputStream)outByteCodeRef.get());
+                if (null == outClassFile) {
+                    outClassFile = new ByteArrayOutputStream(10000);
+                    outByteCodeRef = new WeakReference(outClassFile);
+                }
+                outClassFile.reset();
+
+                // find byte code of class
+                final InputStream is = getSystemResourceAsStream(name);
+                //@olsen: (is == null) ?!
+
+                // copy byte code of class into byte array
+                final byte[] data;
+                try {
+                    int b;
+                    while ((b = is.read()) >= 0) {
+                        outClassFile.write(b);
+                    }
+                    data = outClassFile.toByteArray();
+                } catch (IOException e) {
+                    final String msg
+                        = ("Exception caught while loading class '"
+                           + name + "' : " + e);
+                    throw new ClassNotFoundException(msg, e);
+                }
+
+                // convert the byte code into class object
+                c = defineClass(name, data, 0, data.length);
+*/
+            }
+
+            //@olsen: check if class has been loaded already
+            if (c == null) {
+                c = findLoadedClass(name);
+                if (c != null) {                
+                    message("EnhancerClassLoader: class already loaded: " + name);//NOI18N
+                }
+            }
+
+            if (c == null) {
+                c = findAndEnhanceClass(name);
+            }
+
+            // as a last resort, if the class couldn't be found, try
+            // loading class by parent class loader
+            if (c == null) {
+                message("EnhancerClassLoader: class not found, using parent loader for class: " + name);//NOI18N
+                return super.loadClass(name, resolve);
+            }
+
+            message();
+            message("EnhancerClassLoader: loaded class: " + name);
+            if (resolve) {
+                resolveClass(c);
+            }
+
+            message();
+            message("EnhancerClassLoader: loaded+resolved class: " + name);
+            return c;
+        } catch (RuntimeException e) {
+            // log exception only
+            message();
+            message("EnhancerClassLoader: EXCEPTION SEEN: " + e);
+            //e.printStackTrace(out);
+            throw e;
+        } catch (ClassNotFoundException e) {
+            // log exception only
+            message();
+            message("EnhancerClassLoader: EXCEPTION SEEN: " + e);
+            //e.printStackTrace(out);
+            throw e;
+        }
+    }
+
+    /**
+     * Finds and loads the class with the specified name from the URL search
+     * path. Any URLs referring to JAR files are loaded and opened as needed
+     * until the class is found.
+     *
+     * @param name the name of the class
+     * @return the resulting class
+     * @exception ClassNotFoundException if the class could not be found
+     */
+    private Class findAndEnhanceClass(final String name)
+        throws ClassNotFoundException
+    {
+        try {
+            if (doTiming) {
+                Support.timer.push("EnhancerClassLoader.findAndEnhanceClass(String)",
+                                   "EnhancerClassLoader.findAndEnhanceClass(" + name + ")");
+            }
+            return (Class)
+            AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws ClassNotFoundException
+                {
+                    String path = name.replace('.', '/').concat(".class");
+                    //message("path=" + path);
+                    Resource res = ucp.getResource(path, false);
+                    if (res != null) {
+                        try {
+                            return defineClass(name, res);
+                        } catch (IOException e) {
+                            final String msg
+                                = ("Exception caught while loading class '"
+                                   + name + "' : " + e);
+                            throw new ClassNotFoundException(msg, e);
+                        }
+                    } else {
+                        // ok if class resource not found (e.g. java.*)
+                        //throw new ClassNotFoundException(name);
+                        return null;
+                    }
+                }
+            }, acc);
+        } catch (PrivilegedActionException pae) {
+            throw (ClassNotFoundException) pae.getException();
+        } finally {
+            if (doTiming) {
+                Support.timer.pop();
+            }
+        }
+    }
+
+    /**
+     * Defines a Class using the class bytes obtained from the specified
+     * Resource. The resulting Class must be resolved before it can be
+     * used.
+     */
+    private Class defineClass(String name, Resource res)
+        throws IOException, ClassNotFoundException
+    {
+        int i = name.lastIndexOf('.');
+        URL url = res.getCodeSourceURL();
+        if (i != -1) {
+            String pkgname = name.substring(0, i);
+            // Check if package already loaded.
+            Package pkg = getPackage(pkgname);
+            Manifest man = res.getManifest();
+            if (pkg != null) {
+                // Package found, so check package sealing.
+                boolean ok;
+                if (pkg.isSealed()) {
+                    // Verify that code source URL is the same.
+                    ok = pkg.isSealed(url);
+                } else {
+                    // Make sure we are not attempting to seal the package
+                    // at this code source URL.
+                    ok = (man == null) || !isSealed(pkgname, man);
+                }
+                if (!ok) {
+                    throw new SecurityException("sealing violation");
+                }
+            } else {
+                if (man != null) {
+                    definePackage(pkgname, man, url);
+                } else {
+                    definePackage(pkgname, null, null, null, null, null, null, null);
+                }
+            }
+        }
+        // Now read the class bytes and define the class
+        byte[] b = res.getBytes();
+        Certificate[] certs = res.getCertificates();
+        CodeSource cs = new CodeSource(url, certs);
+
+        //@olsen: performance bug 4457471: circumvent enhancer for
+        // non-enhancable classes
+        final String classPath = name.replace('.', '/');
+        if (!metaData.isKnownUnenhancableClass(classPath)) {
+            // Add enhancement here
+            b = enhance(name, b, 0, b.length);
+        }
+
+        return defineClass(name, b, 0, b.length, cs);
+    }
+
+    private byte[] enhance(String name, byte[] data, int off, int len)
+        throws ClassNotFoundException
+    {
+        //message("EnhancerClassLoader: enhance class: " + name);
+
+        final byte[] result;
+        try {
+            // create enhancer if not done yet
+            if (null == enhancer) {
+                enhancer = new EnhancerFilter(metaData, settings, out, null);
+                if (doTiming) {
+                    // wrap with timing filter enhancer object
+                    enhancer = new ClassFileEnhancerTimer(enhancer);
+                }
+            }
+
+            // create input and output byte streams
+            final ByteArrayInputStream inByteCode
+                = new ByteArrayInputStream(data, off, len);
+            ByteArrayOutputStream outByteCode
+                = ((null == outByteCodeRef)
+                   ? null : (ByteArrayOutputStream)outByteCodeRef.get());
+            if (null == outByteCode) {
+                outByteCode = new ByteArrayOutputStream(10000);
+                outByteCodeRef = new WeakReference(outByteCode);
+            }
+            outByteCode.reset();
+
+            // enhance class
+            final boolean changed
+                = enhancer.enhanceClassFile(inByteCode, outByteCode);
+
+            // check whether class has been enhanced
+            result = (changed ? outByteCode.toByteArray() : data);
+        } catch (EnhancerUserException e) {
+            message(e);
+            final String msg = ("Exception caught while loading class '"
+                                + name + "' : " + e);
+            throw new ClassNotFoundException(msg, e);
+        } catch(EnhancerFatalError e) {
+            message(e);
+            final String msg = ("Exception caught while loading class '"
+                                + name + "' : " + e);
+            // discard enhancer because it might have become inconsistent
+            enhancer = null;
+            throw new ClassNotFoundException(msg, e);
+        }
+        return result;
+    }
+
+    /**
+     * Returns true if the specified package name is sealed according to the
+     * given manifest.
+     */
+    private boolean isSealed(String name, Manifest man)
+    {
+        String path = name.replace('.', '/').concat("/");
+        Attributes attr = man.getAttributes(path);
+        String sealed = null;
+        if (attr != null) {
+            sealed = attr.getValue(Name.SEALED);
+        }
+        if (sealed == null) {
+            if ((attr = man.getMainAttributes()) != null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        return "true".equalsIgnoreCase(sealed);
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java Sun May 22 10:55:51 2005
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+
+/**
+ * Thrown to indicate that the class-file enhancer failed to perform an
+ * operation due to a serious error.  The enhancer is not guaranteed to
+ * be in a consistent state anymore.
+ */
+public class EnhancerFatalError
+    extends Exception
+{
+    /**
+     * An optional nested exception.
+     */
+    public final Throwable nested;
+
+    /**
+     * Constructs an <code>EnhancerFatalError</code> with no detail message.
+     */
+    public EnhancerFatalError()
+    {
+        this.nested = null;
+    }
+
+    /**
+     * Constructs an <code>EnhancerFatalError</code> with the specified
+     * detail message.
+     */
+    public EnhancerFatalError(String msg)
+    {
+        super(msg);
+        this.nested = null;
+    }
+
+    /**
+     * Constructs an <code>EnhancerFatalError</code> with an optional
+     * nested exception.
+     */
+    public EnhancerFatalError(Throwable nested)
+    {
+        super(nested.toString());
+        this.nested = nested;
+    }
+
+    /**
+     * Constructs an <code>EnhancerFatalError</code> with the specified
+     * detail message and an optional nested exception.
+     */
+    public EnhancerFatalError(String msg, Throwable nested)
+    {
+        super(msg);
+        this.nested = nested;
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java Sun May 22 10:55:51 2005
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+
+
+/**
+ * Set of options used by the JDO enhancer and its test programs.
+ *
+ * @author Martin Zaun
+ */
+public class EnhancerOptions
+    extends JdoMetaOptions
+{
+    /**
+     * The quiet option.
+     */
+    public final FlagOption quiet
+        = createFlagOption("quiet", "q",
+                             "           : suppress warnings");
+    /**
+     * The force write option.
+     */
+    public final FlagOption forceWrite
+        = createFlagOption("forcewrite", "f",
+                           "           : overwrite output files");
+
+    /**
+     * The no write option.
+     */
+    public final FlagOption noWrite
+        = createFlagOption("nowrite", "n",
+                           "           : never write output files");
+
+    /**
+     * The destination directory option.
+     */
+    public final StringOption destDir
+        = createStringOption("destdir", "d",
+                             "<path>     : directory for any output files");
+
+    /**
+     * The dump class option.
+     */
+    public final FlagOption dumpClass
+        = createFlagOption("dumpclass", null,
+                           "           : dump out disassembled byte-code");
+
+    /**
+     * The suppress augmentation option.
+     */
+    public final FlagOption noAugment
+        = createFlagOption("noaugment", null,
+                           "           : do not enhance for persistence-capability");
+
+    /**
+     * The suppress annotation option.
+     */
+    public final FlagOption noAnnotate
+        = createFlagOption("noannotate", null,
+                           "           : do not enhance for persistence-awareness");
+
+    /**
+     * Creates an instance.
+     */
+    public EnhancerOptions(PrintWriter out,
+                          PrintWriter err) 
+    {
+        super(out, err);
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Print a usage message to System.err.
+     */
+    public void printUsageHeader()
+    {
+        printlnErr("Usage: <options>.. <arguments>..");
+        printlnErr(indent
+                   + "-j <path> -s <path> -d <dir>   <classname>..");
+        printlnErr(indent
+                   + "-j <path> -d <dir>             <classfile>..");
+        //^olsen: consider allowing omission of destination directory for
+        // class file arguments
+        //printlnErr(indent
+        //           + "-j <path> [-d <dir>]           <classfile>..");
+        //^olsen: re-enable support for archive files
+        //printlnErr(indent
+        //           + "[-j <path>] [-d <dir>]         <archivefile>..");
+    }
+
+    /**
+     * Check options and arguments.
+     */
+    public int check()
+    {
+        int res;
+        if ((res = super.check()) != OK) {
+            return res;
+        }
+        
+        // check destination directory option
+        if (destDir.value == null && !classNames.isEmpty()) {
+            printUsageError("No destination directory specified for enhanced classes");
+            return USAGE_ERROR;
+        }
+
+        //^olsen: consider allowing omission of destination directory for
+        // class file arguments
+        if (destDir.value == null && !classFileNames.isEmpty()) {
+            printUsageError("No destination directory specified for enhanced classes");
+            return USAGE_ERROR;
+        }
+
+        return OK;
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Tests the class.
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> EnhancerOptions.main()");
+        final EnhancerOptions options = new EnhancerOptions(out, out);
+        out.println("    options.process() ...");
+        int res = options.process(args);
+        out.println("    return value: " + res);
+        out.println("<-- EnhancerOptions.main()");
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java Sun May 22 10:55:51 2005
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import org.apache.jdo.util.I18NHelper;
+
+/**
+ * Thrown to indicate that the class-file enhancer failed to perform an
+ * operation due to an error.  The enhancer is guaranteed to remain in a
+ * consistent state.
+ *
+ * @author Michael Bouschen
+ */
+public class EnhancerUserException
+    extends Exception
+{
+    /** The Throwable that caused this exception to be thrown. */
+    private Throwable cause;
+
+    /** Flag indicating whether printStackTrace is being executed. */
+    private boolean inPrintStackTrace = false;
+
+    /** I18N support */
+    private static I18NHelper msg = 
+        I18NHelper.getInstance("org.apache.jdo.impl.enhancer.Bundle");
+
+    /**
+     * Creates a new <code>EnhancerUserException</code> without detail
+     * message. 
+     */
+    public EnhancerUserException() 
+    {
+    }
+    
+    /**
+     * Creates a new <code>EnhancerUserException</code> with the specified
+     * detail message.
+     * @param message the detail message.
+     */
+    public EnhancerUserException(String message)
+    {
+        super(message);
+    }
+
+    /** 
+     * Creates a new <code>EnhancerUserException</code> with the specified 
+     * detail message and cause Throwable.
+     * @param message the detail message.
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause()} method). (A null value is permitted, and
+     * indicates that the cause is nonexistent or unknown.) 
+     */
+    public EnhancerUserException(String message, Throwable cause) 
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    /** 
+     * Returns the cause of this Exception or null if the cause is
+     * nonexistent or unknown. (The cause is the Throwable that caused this 
+     * Exception to get thrown.) 
+     * @return the cause of this Exception or null if the cause is
+     * nonexistent or unknown. 
+     */
+    public synchronized Throwable getCause() 
+    {
+        // super.printStackTrace calls getCause to handle the cause. 
+        // Returning null prevents the superclass from handling the cause;
+        // instead the local implementation of printStackTrace should
+        // handle the cause. Otherwise, the cause is printed twice.
+        return inPrintStackTrace ? null : cause;
+    }
+
+    /**
+     * Initializes the cause of this throwable to the specified value. (The
+     * cause is the Throwable that caused this Exception to get thrown.) 
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause()} method). (A null value is permitted, and
+     * indicates that the cause is nonexistent or unknown.)
+     * @return a reference to this <code>EnhancerUserException</code> 
+     * instance.
+     */
+    public Throwable initCause(Throwable cause)
+    {
+        this.cause = cause;
+        return this;
+    }
+    
+    /** 
+     * The <code>String</code> representation includes the name of the class,
+     * the descriptive comment (if any),
+     * and the <code>String</code> representation of the cause (if any). 
+     * @return the <code>String</code>.
+     */
+    public synchronized String toString() 
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(super.toString());
+        // Do not include cause information, if called by printStackTrace;
+        // the stacktrace will include the cause anyway.
+        if ((cause != null) && !inPrintStackTrace) {
+            sb.append("\n");  //NOI18N
+            sb.append(msg.msg("MSG_CauseThrowable")); //NOI18N
+            sb.append("\n");  //NOI18N
+            sb.append(cause.toString()); //NOI18N
+        }
+        return sb.toString();
+    }
+  
+    /**
+     * Prints this <code>EnhancerUserException</code> and its backtrace to the 
+     * standard error output.
+     * Print cause Throwable's stack trace as well.
+     */
+    public void printStackTrace()
+    {
+        printStackTrace(System.err);
+    }
+
+    /**
+     * Prints this <code>EnhancerUserException</code> and its backtrace to the 
+     * specified print stream.
+     * Print cause Throwable's stack trace as well.
+     * @param s <code>PrintStream</code> to use for output
+     */
+    public synchronized void printStackTrace(java.io.PrintStream s) 
+    { 
+        synchronized (s) {
+            inPrintStackTrace = true;
+            super.printStackTrace(s);
+            if (cause != null) {
+                s.println(msg.msg("MSG_CauseThrowableStackTrace")); //NOI18N
+                cause.printStackTrace(s);
+            }
+            inPrintStackTrace = false;
+        }
+    }
+    
+    /**
+     * Prints this <code>EnhancerUserException</code> and its backtrace to the specified
+     * print writer.
+     * Print cause Throwable' stack trace as well.
+     * @param s <code>PrintWriter</code> to use for output
+     */
+    public synchronized void printStackTrace(java.io.PrintWriter s) 
+    { 
+        synchronized (s) {
+            inPrintStackTrace = true;
+            super.printStackTrace(s);
+            if (cause != null) {
+                s.println(msg.msg("MSG_CauseThrowableStackTrace") + ' '); //NOI18N
+                cause.printStackTrace(s);
+            }
+            inPrintStackTrace = false;
+        }
+    }
+    
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericMain.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericMain.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericMain.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericMain.java Sun May 22 10:55:51 2005
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+
+
+/**
+ * Base class for JDO command line enhancer and tests.
+ *
+ * @author Martin Zaun
+ */
+public class GenericMain
+    extends LogSupport
+{
+    // return values for process() method
+    static public final int OK = 0;
+    static public final int USAGE_ERROR = -1;
+    static public final int USER_EXCEPTION = -2;
+    static public final int INTERNAL_ERROR = -3;
+
+    /**
+     *  The options and arguments.
+     */
+    protected GenericOptions options;
+
+    /**
+     * Creates an instance.
+     */
+    public GenericMain(PrintWriter out,
+                       PrintWriter err)
+    {
+        this(out, err, new GenericOptions(out, err));
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public GenericMain(PrintWriter out,
+                       PrintWriter err,
+                       GenericOptions options)
+    {
+        super(out, err);
+        this.options = options;
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Initializes all components.
+     */
+    protected void init()
+        throws EnhancerFatalError, EnhancerUserException
+    {}
+    
+    /**
+     * Do processing (to be overloaded by subclasses).
+     */
+    protected int process()
+    {
+        return OK;
+    }
+    
+    /**
+     * Process command line arguments, run initialization and do processing.
+     */
+    public int run(String[] args)
+    {
+        try {
+            // process passed command-line arguments
+            if (options.process(args) != options.OK) {
+                return USAGE_ERROR;
+            }
+
+            // run initialization and do processing
+            init();
+            return process();
+        } catch (RuntimeException ex) {
+            printlnErr("exception caught", ex);
+            return INTERNAL_ERROR;
+        } catch (Exception ex) {
+            printlnErr("exception caught", ex);
+            return USER_EXCEPTION;
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Runs this class
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> GenericMain.main()");
+        final GenericMain main = new GenericMain(out, out);
+        int res = main.run(args);
+        out.println("<-- GenericMain.main(): exit = " + res);
+        System.exit(res);
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java Sun May 22 10:55:51 2005
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+
+/**
+ * Set of options used by the JDO enhancer and its test programs.
+ *
+ * @author Martin Zaun
+ */
+public class GenericOptions
+    extends OptionSet
+{
+    /**
+     * The help option.
+     */
+    public final HelpOption help
+        = createHelpOption("help", "h",
+                           "              : print usage message and exit");
+
+    /**
+     * The verbose option.
+     */
+    public final FlagOption verbose
+        = createFlagOption("verbose", "v",
+                           "           : print verbose messages");
+
+    /**
+     * The timing option.
+     */
+    public final FlagOption doTiming
+        = createFlagOption("timing", "t",
+                           "            : do timing messures");
+
+    /**
+     * Creates an instance.
+     */
+    public GenericOptions(PrintWriter out,
+                       PrintWriter err) 
+    {
+        super(out, err);
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Tests the class.
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> GenericOptions.main()");
+        final GenericOptions options = new GenericOptions(out, out);
+        out.println("    options.process() ...");
+        int res = options.process(args);
+        out.println("    return value: " + res);
+        out.println("<-- GenericOptions.main()");
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java Sun May 22 10:55:51 2005
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+import java.io.IOException;
+
+import java.util.Properties;
+
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
+import org.apache.jdo.impl.enhancer.meta.model.EnhancerMetaDataJDOModelImpl;
+import org.apache.jdo.impl.enhancer.meta.prop.EnhancerMetaDataPropertyImpl;
+import org.apache.jdo.impl.enhancer.meta.util.EnhancerMetaDataTimer;
+
+/**
+ * Base class for JDO command line enhancer and tests.
+ *
+ * @author Martin Zaun
+ */
+public class JdoMetaMain
+    extends ClassArgMain
+{
+    /**
+     *  The options and arguments.
+     */
+    protected JdoMetaOptions options;
+
+    /**
+     *  The metadata.
+     */
+    protected EnhancerMetaData jdoMeta;
+
+    /**
+     * Creates an instance.
+     */
+    public JdoMetaMain(PrintWriter out,
+                       PrintWriter err)
+    {
+        this(out, err, new JdoMetaOptions(out, err));
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public JdoMetaMain(PrintWriter out,
+                       PrintWriter err,
+                       JdoMetaOptions options)
+    {
+        super(out, err, options);
+        this.options = options;
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Initializes the jdo metadata component.
+     */
+    protected void initJdoMetaData()
+        throws EnhancerMetaDataFatalError
+    {
+        final boolean verbose = options.verbose.value;
+        final String path = options.jdoPath.value;
+        final String jdoPropsFile = options.jdoPropertiesFile.value;
+
+        if (jdoPropsFile != null && jdoPropsFile.length() > 0) {
+            // read JDO metadata from properties file
+            if (path != null && path.length() > 0) {
+                // load the properties file using the path specified with
+                // -j (if available)
+                try {
+                    final Properties props = new Properties();
+                    props.load(classes.getInputStreamForResource(jdoPropsFile));
+                    jdoMeta = new EnhancerMetaDataPropertyImpl(out, 
+                                                               verbose, 
+                                                               props);
+                } catch (IOException ex) {
+                    throw new EnhancerMetaDataFatalError(ex);
+                }  
+            } else {
+                // no -j option => take the properties file name as it is
+                jdoMeta = new EnhancerMetaDataPropertyImpl(out, 
+                                                           verbose, 
+                                                           jdoPropsFile);
+            }
+        } else {
+            //^olsen: simplify interface; just append archives to jdo-path
+            jdoMeta = new EnhancerMetaDataJDOModelImpl(
+                out, verbose,
+                null,
+                options.archiveFileNames,
+                path);
+        }
+
+//^olsen: add archives to path locator...
+/*
+            // create resource locator for specified zip files
+            if (archiveFileNames != null && !archiveFileNames.isEmpty()) {
+                final StringBuffer s = new StringBuffer();
+                final Iterator i = archiveFileNames.iterator();
+                s.append(i.next());
+                while (i.hasNext()) {
+                    s.append(File.pathSeparator + i.next());
+                }
+                final ResourceLocator zips
+                    = new PathResourceLocator(out, verbose, s.toString());
+                printMessage(getI18N("enhancer.using_zip_files",
+                                     s.toString()));
+                locators.add(zips);
+            }
+*/
+
+        // wrap with timing meta data object
+        if (options.doTiming.value) {
+            jdoMeta = new EnhancerMetaDataTimer(jdoMeta);
+        }
+    }
+
+    /**
+     * Initializes all components.
+     */
+    protected void init()
+        throws EnhancerFatalError, EnhancerUserException
+    {
+        super.init();
+        try {
+            initJdoMetaData();
+        } catch (Exception ex) {
+            throw new EnhancerFatalError(ex);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Runs this class
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> JdoMetaMain.main()");
+        final JdoMetaMain main = new JdoMetaMain(out, out);
+        int res = main.run(args);
+        out.println("<-- JdoMetaMain.main(): exit = " + res);
+        System.exit(res);
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java Sun May 22 10:55:51 2005
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+
+
+/**
+ * Set of options used by the JDO enhancer and its test programs.
+ *
+ * @author Martin Zaun
+ */
+public class JdoMetaOptions
+    extends ClassArgOptions
+{
+    /**
+     * The jdo path option.
+     */
+    public final StringOption jdoPath
+        = createStringOption("jdopath", "j",
+                             "<path>     : path for lookup of jdo files");
+
+    /**
+     * The jdo properties option.
+     */
+    public final StringOption jdoPropertiesFile
+        = createStringOption("properties", null,
+                             "<file>  : use property file for JDO metadata");
+
+    /**
+     * Creates an instance.
+     */
+    public JdoMetaOptions(PrintWriter out,
+                          PrintWriter err) 
+    {
+        super(out, err);
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Print a usage message to System.err.
+     */
+    public void printUsageHeader()
+    {
+        printlnErr("Usage: <options>.. <arguments>..");
+        printlnErr(indent
+                   + "JDO metadata options:");
+        printlnErr(indent
+                   + "  --properties <file> [-j <path>] use property file for JDO metadata");
+        printlnErr(indent
+                   + "  -j <path>                       lookup .jdo files in the specified path");
+        printlnErr(indent
+                   + "Source option and arguments:");
+        printlnErr(indent
+                   + "  -s <path>   <classname>..");
+        printlnErr(indent
+                   + "              <classfile>..");
+        printlnErr(indent
+                   + "              <archivefile>..");
+    }
+
+    /**
+     * Check options and arguments.
+     */
+    public int check()
+    {
+        int res;
+        if ((res = super.check()) != OK) {
+            return res;
+        }
+        
+        // check jdopath option
+        if (jdoPropertiesFile.value == null && 
+            jdoPath.value == null && archiveFileNames.isEmpty()) {
+            printUsageError("No JDO metadata option: specify either properties file or jdo-path for lookup of jdo files");
+            return USAGE_ERROR;
+        }
+
+        return OK;
+    }
+
+    // ----------------------------------------------------------------------
+
+    /**
+     * Tests the class.
+     */
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> JdoMetaOptions.main()");
+        final JdoMetaOptions options = new JdoMetaOptions(out, out);
+        out.println("    options.process() ...");
+        int res = options.process(args);
+        out.println("    return value: " + res);
+        out.println("<-- JdoMetaOptions.main()");
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/LogSupport.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/LogSupport.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/LogSupport.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/LogSupport.java Sun May 22 10:55:51 2005
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer;
+
+import java.io.PrintWriter;
+
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+/**
+ * Provides some basic utilities for main classes.
+ *
+ * @author Martin Zaun
+ */
+class LogSupport
+    extends Support
+{
+    /**
+     * The stream to write messages to.
+     */
+    protected final PrintWriter out;
+
+    /**
+     * The stream to write error messages to.
+     */
+    protected final PrintWriter err;
+    
+    /**
+     * Creates an instance.
+     */
+    public LogSupport(PrintWriter out,
+                      PrintWriter err) 
+    {
+        affirm(out != null);
+        affirm(err != null);
+        this.out = out;
+        this.err = err;
+    }
+
+    /**
+     * Prints out an error message.
+     */
+    protected void printlnErr(String msg,
+                              Throwable ex,
+                              boolean verbose)
+    {
+        out.flush();
+        if (msg != null) {
+            err.println(msg);
+        }
+        if (ex != null) {
+            if (verbose) {
+                ex.printStackTrace(err);
+            }
+            else {
+                err.println(ex.toString());
+            }
+        }
+    }
+
+    /**
+     * Prints out an error message.
+     */
+    protected void printlnErr(String msg,
+                              Throwable ex)
+    {
+        out.flush();
+        err.println(msg + ": " + ex.getMessage());
+        ex.printStackTrace(err);
+    }
+
+    /**
+     * Prints out an error message.
+     */
+    protected void printlnErr(String msg)
+    {
+        out.flush();
+        err.println(msg);
+    }
+
+    /**
+     * Prints out an error message.
+     */
+    protected void printlnErr()
+    {
+        out.flush();
+        err.println();
+    }
+
+    /**
+     * Prints out a message.
+     */
+    protected void print(String msg)
+    {
+        out.print(msg);
+    }
+
+    /**
+     * Prints out a message.
+     */
+    protected void println(String msg)
+    {
+        out.println(msg);
+    }
+
+    /**
+     * Prints out a message.
+     */
+    protected void println()
+    {
+        out.println();
+    }
+
+    /**
+     * Flushes streams.
+     */
+    protected void flush()
+    {
+        out.flush();
+        err.flush();
+    }
+
+    // ----------------------------------------------------------------------
+
+//^olsen: support for I18N
+
+    /**
+     *  Prints out a warning message.
+     *
+     *  @param msg the message
+     */
+/*
+    public void printWarning(String msg)
+    {
+        out.println(getI18N("enhancer.warning", msg));
+    }
+*/
+    /**
+     *  Prints out a verbose message.
+     *
+     *  @param msg the message
+     */
+/*
+    public void printMessage(String msg)
+    {
+        if (options.verbose.value) {
+            out.println(getI18N("enhancer.message", msg));
+        }
+    }
+*/
+}