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/03/19 02:05:57 UTC
svn commit: r158176 [3/79] - in incubator/jdo/trunk/ri11: ./ src/ src/conf/
src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/
src/java/org/apache/jdo/ejb/ 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/
src/java/org/apache/jdo/impl/fostore/ src/java/org/apache/jdo/impl/jdoql/
src/java/org/apache/jdo/impl/jdoql/jdoqlc/
src/java/org/apache/jdo/impl/jdoql/scope/
src/java/org/apache/jdo/impl/jdoql/tree/ src/java/org/apache/jdo/impl/model/
src/java/org/apache/jdo/impl/model/java/
src/java/org/apache/jdo/impl/model/java/runtime/
src/java/org/apache/jdo/impl/model/jdo/
src/java/org/apache/jdo/impl/model/jdo/caching/
src/java/org/apache/jdo/impl/model/jdo/util/
src/java/org/apache/jdo/impl/model/jdo/xml/
src/java/org/apache/jdo/impl/pm/ src/java/org/apache/jdo/impl/sco/
src/java/org/apache/jdo/impl/state/ src/java/org/apache/jdo/jdoql/
src/java/org/apache/jdo/jdoql/tree/ src/java/org/apache/jdo/model/
src/java/org/apache/jdo/model/java/ src/java/org/apache/jdo/model/jdo/
src/java/org/apache/jdo/pm/ src/java/org/apache/jdo/sco/
src/java/org/apache/jdo/state/ src/java/org/apache/jdo/store/
src/java/org/apache/jdo/util/ test/ test/conf/ test/enhancer/
test/enhancer/sempdept/ test/enhancer/sempdept/src/
test/enhancer/sempdept/src/empdept/ test/fsuid2/ test/fsuid2/org/
test/fsuid2/org/apache/ test/fsuid2/org/apache/jdo/
test/fsuid2/org/apache/jdo/pc/ test/java/ test/java/org/
test/java/org/apache/ test/java/org/apache/jdo/
test/java/org/apache/jdo/impl/ test/java/org/apache/jdo/impl/fostore/
test/java/org/apache/jdo/pc/ test/java/org/apache/jdo/pc/appid/
test/java/org/apache/jdo/pc/empdept/
test/java/org/apache/jdo/pc/serializable/
test/java/org/apache/jdo/pc/xempdept/ test/java/org/apache/jdo/test/
test/java/org/apache/jdo/test/query/ test/java/org/apache/jdo/test/util/
test/jdo/ test/jdo/org/ test/jdo/org/apache/ test/jdo/org/apache/jdo/
test/jdo/org/apache/jdo/pc/ test/jdo/org/apache/jdo/pc/appid/
test/jdo/org/apache/jdo/pc/empdept/ test/jdo/org/apache/jdo/pc/serializable/
test/jdo/org/apache/jdo/pc/xempdept/ xdocs/
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/Main.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/Main.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/Main.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/Main.java Fri Mar 18 17:02:29 2005
@@ -0,0 +1,957 @@
+/*
+ * 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.enhancer;
+
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.PrintWriter;
+import java.io.FileReader;
+import java.io.BufferedReader;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipException;
+
+import java.net.URL;
+
+import org.apache.jdo.impl.enhancer.ClassFileEnhancer;
+import org.apache.jdo.impl.enhancer.ClassFileEnhancerHelper;
+import org.apache.jdo.impl.enhancer.ClassFileEnhancerTimer;
+import org.apache.jdo.impl.enhancer.EnhancerFatalError;
+import org.apache.jdo.impl.enhancer.EnhancerUserException;
+import org.apache.jdo.impl.enhancer.OutputStreamWrapper;
+import org.apache.jdo.impl.enhancer.core.EnhancerFilter;
+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.EnhancerMetaDataBaseModel;
+import org.apache.jdo.impl.enhancer.meta.util.EnhancerMetaDataTimer;
+import org.apache.jdo.impl.enhancer.util.CombinedResourceLocator;
+import org.apache.jdo.impl.enhancer.util.ListResourceLocator;
+import org.apache.jdo.impl.enhancer.util.PathResourceLocator;
+import org.apache.jdo.impl.enhancer.util.ResourceLocator;
+import org.apache.jdo.impl.enhancer.util.ResourceLocatorTimer;
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+
+
+/**
+ * Main is the starting point for the persistent filter tool.
+ */
+public class Main
+ extends Support
+{
+ // return values of main()
+ static public final int OK = 0;
+ static public final int USAGE_ERROR = -1;
+ static public final int METADATA_ERROR = -2;
+ static public final int CLASS_LOCATOR_ERROR = -3;
+ static public final int INTERNAL_ERROR = -4;
+
+ /**
+ * The stream to write messages to.
+ */
+ private final PrintWriter out = new PrintWriter(System.out, true);
+
+ /**
+ * The stream to write error messages to.
+ */
+ private final PrintWriter err = new PrintWriter(System.err, true);
+
+ /**
+ * The command line options.
+ */
+ private final CmdLineOptions opts = new CmdLineOptions();
+
+ /**
+ * The byte code enhancer.
+ */
+ private ClassFileEnhancer enhancer;
+
+ /**
+ * The locator for classes.
+ */
+ protected ResourceLocator classLocator;
+
+ /**
+ * The metadata for the enhancer.
+ */
+ private EnhancerMetaData jdoMetaData;
+
+ /**
+ * Construct a filter tool instance
+ */
+ public Main()
+ {}
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * This is where it all starts.
+ */
+ public static void main(String[] argv)
+ {
+ int res;
+ final Main main = new Main();
+
+ //@olsen: added support for timing statistics
+ try {
+ res = main.process(argv);
+ } catch (RuntimeException ex) {
+ main.out.flush();
+ main.err.println("Internal error while postprocessing: "
+ + ex.getMessage());
+ ex.printStackTrace(main.err);
+ main.err.flush();
+ res = INTERNAL_ERROR;
+ } finally {
+ //@olsen: added support for timing statistics
+ if (main.opts.doTiming) {
+ Support.timer.print();
+ }
+ }
+ System.exit(res);
+ }
+
+ /**
+ * Process command line options and run enhancer.
+ */
+ public int process(String[] argv)
+ {
+ int res;
+
+ if ((res = opts.processArgs(argv)) != OK) {
+ printMessage("aborted with errors.");
+ return res;
+ }
+
+ //@olsen: added support for timing statistics
+ try {
+ if (opts.doTiming) {
+ timer.push("Main.process(String[])");
+ }
+
+ if ((res = createEnhancer()) != OK) {
+ printMessage("aborted with errors.");
+ return res;
+ }
+
+ if ((res = enhanceInputFiles(opts.classNames,
+ opts.classFileNames,
+ opts.zipFileNames,
+ opts.jdoFileNames)) != OK) {
+ printMessage("aborted with errors.");
+ return res;
+ }
+
+ printMessage("done.");
+ return 0;
+ } finally {
+ if (opts.doTiming) {
+ timer.pop();
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * A class for holding the command line options.
+ */
+ private class CmdLineOptions
+ {
+ final List classNames = new ArrayList();
+ final List classFileNames = new ArrayList();
+ final List zipFileNames = new ArrayList();
+ final List jdoFileNames = new ArrayList();
+ String sourcePath = null;
+ String destinationDirectory = null;
+ String propertiesFileName = null;
+ boolean doTiming = false;
+ boolean verbose = false;
+ boolean quiet = false;
+ boolean forceWrite = false;
+ boolean noWrite = false;
+ boolean dumpClass = false;
+ boolean noAugment = false;
+ boolean noAnnotate = false;
+
+ /**
+ * Print a usage message to System.err.
+ */
+ public void usage() {
+ err.println("Usage: main <options> <arguments>...");
+ err.println("Options:");
+ err.println(" -h, --help print usage message and exit gently");
+ err.println(" -v, --verbose print verbose messages");
+ err.println(" -q, --quiet supress warnings");
+ err.println(" -s, --sourcepath <path> source path for jdo and classfiles");
+ err.println(" -d, --destdir <dir> destination directory for output files");
+ err.println(" -f, --force overwrite output files");
+ err.println(" -n, --nowrite never write output files");
+ err.println(" -t, --timing do timing messures");
+ err.println();
+ err.println("Debugging Options:");
+ err.println(" --properties <file> use property file for meta data");
+ err.println(" --dumpclass print out disassembled code of classes");
+ err.println(" --noaugment do not enhance for persistence-capability");
+ err.println(" --noannotate do not enhance for persistence-awareness");
+ err.println();
+ err.println("Arguments:");
+ //err.println(" <class> the fully qualified name of a Java class");
+ err.println(" <jdofile> the name of a .jdo file");
+ err.println(" <classfile> the name of a .class file");
+ //err.println(" <zipfile> the name of a .zip or .jar file");
+ err.println();
+ err.println("Returns a non-zero value in case of errors.");
+ }
+
+ /**
+ * Process command line options.
+ */
+ protected int processArgs(String[] argv)
+ {
+ final Collection inputNames = new ArrayList();
+ for (int i = 0; i < argv.length; i++) {
+ final String arg = argv[i];
+ if (arg.equals("-h")
+ || arg.equals("--help")) {
+ usage();
+ return OK;
+ }
+ if (arg.equals("-v")
+ || arg.equals("--verbose")) {
+ verbose = true;
+ quiet = false;
+ continue;
+ }
+ if (arg.equals("-q")
+ || arg.equals("--quiet")) {
+ quiet = true;
+ verbose = false;
+ continue;
+ }
+ if (arg.equals("-t") ||
+ arg.equals("--timing")) {
+ doTiming = true;
+ continue;
+ }
+ if (arg.equals("-f")
+ || arg.equals("--force")) {
+ forceWrite = true;
+ noWrite = false;
+ continue;
+ }
+ if (arg.equals("-n")
+ || arg.equals("--nowrite")) {
+ noWrite = true;
+ forceWrite = false;
+ continue;
+ }
+ if (arg.equals("--dumpclass")) {
+ dumpClass = true;
+ continue;
+ }
+ if (arg.equals("--noaugment")) {
+ noAugment = true;
+ continue;
+ }
+ if (arg.equals("--noannotate")) {
+ noAnnotate = true;
+ continue;
+ }
+ if (arg.equals("-s")
+ || arg.equals("--sourcepath")) {
+ if (argv.length - i < 2) {
+ printError("Missing argument to the -s/--sourcepath option", null);
+ usage();
+ return USAGE_ERROR;
+ }
+ sourcePath = argv[++i];
+ continue;
+ }
+ if (arg.equals("-d")
+ || arg.equals("--destdir")) {
+ if (argv.length - i < 2) {
+ printError("Missing argument to the -d/-destdir option", null);
+ usage();
+ return USAGE_ERROR;
+ }
+ destinationDirectory = argv[++i];
+ continue;
+ }
+ if (arg.equals("--properties")) {
+ if (argv.length - i < 2) {
+ printError("Missing argument to the --properties option", null);
+ usage();
+ return USAGE_ERROR;
+ }
+ propertiesFileName = argv[++i];
+ continue;
+ }
+ if (arg.length() > 0 && arg.charAt(0) == '-') {
+ printError("Unrecognized option:" + arg, null);
+ usage();
+ return USAGE_ERROR;
+ }
+ if (arg.length() == 0) {
+ printMessage("Ignoring empty command line argument.");
+ continue;
+ }
+
+ inputNames.add(arg);
+ }
+
+ // group input file arguments
+ for (Iterator names = inputNames.iterator(); names.hasNext();) {
+ final String name = (String)names.next();
+ if (isJdoFileName(name)) {
+ jdoFileNames.add(name);
+ } else if (isClassFileName(name)) {
+ classFileNames.add(name);
+ } else if (isZipFileName(name)) {
+ zipFileNames.add(name);
+ } else {
+ classNames.add(name);
+ }
+ }
+
+ if (verbose) {
+ printArgs();
+ }
+ return checkArgs();
+ }
+
+ /**
+ * Check command line options.
+ */
+ protected int checkArgs()
+ {
+ // at least one class must be specified
+ if (classNames.isEmpty()
+ && classFileNames.isEmpty()
+ && zipFileNames.isEmpty()) {
+ final String msg
+ = "No classes specified";
+ printError(msg, null);
+ usage();
+ return USAGE_ERROR;
+ }
+
+ // at least one meta-data source must be specified for classfiles
+ if (classFileNames.size() > 0
+ && (jdoFileNames.isEmpty()
+ && propertiesFileName == null
+ && sourcePath == null)) {
+ final String msg
+ = "No JDO meta-data source specified for class files";
+ printError(msg, null);
+ usage();
+ return USAGE_ERROR;
+ }
+
+ // either jdo files or jdo properties specified
+ if (!jdoFileNames.isEmpty() && propertiesFileName != null) {
+ final String msg
+ = "Cannot have both jdo files and properties specified";
+ printError(msg, null);
+ usage();
+ return USAGE_ERROR;
+ }
+
+ return OK;
+ }
+
+ /**
+ * Print command line options.
+ */
+ protected void printArgs()
+ {
+ out.println("Enhancer: options:");
+ out.println(" verbose = " + verbose);
+ out.println(" quiet = " + quiet);
+ out.println(" forceWrite = " + forceWrite);
+ out.println(" noWrite = " + noWrite);
+ out.println(" sourcePath = " + sourcePath);
+ out.println(" destinationDirectory = " + destinationDirectory);
+ out.println(" propertiesFileName = " + propertiesFileName);
+ out.println(" doTiming = " + doTiming);
+ out.println(" classNames = {");
+ for (Iterator i = classNames.iterator(); i.hasNext();) {
+ out.println(" " + i.next());
+ }
+ out.println(" }");
+ out.println(" jdoFileNames = {");
+ for (Iterator i = jdoFileNames.iterator(); i.hasNext();) {
+ out.println(" " + i.next());
+ }
+ out.println(" }");
+ out.println(" classFileNames = {");
+ for (Iterator i = classFileNames.iterator(); i.hasNext();) {
+ out.println(" " + i.next());
+ }
+ out.println(" }");
+ out.println(" zipFileNames = {");
+ for (Iterator i = zipFileNames.iterator(); i.hasNext();) {
+ out.println(" " + i.next());
+ }
+ out.println(" }");
+ out.println(" dumpClass = " + dumpClass);
+ out.println(" noAugment = " + noAugment);
+ out.println(" noAnnotate = " + noAnnotate);
+ }
+ }
+
+ private int initClassLocator()
+ {
+ final boolean verbose = opts.verbose;
+ final List classFileNames = opts.classFileNames;
+ final List zipFileNames = opts.zipFileNames;
+ final String sourcePath = opts.sourcePath;
+ try {
+ final List locators = new ArrayList();
+
+ // create resource locator for specified class files
+ if (classFileNames != null && !classFileNames.isEmpty()) {
+ final ResourceLocator classes
+ = new ListResourceLocator(out, verbose, classFileNames);
+ if (verbose) {
+ out.println("Class Locator: using class files: {");
+ for (Iterator i = classFileNames.iterator(); i.hasNext();) {
+ out.println(" " + i.next());
+ }
+ out.println("}");
+ }
+ locators.add(classes);
+ }
+
+ // create resource locator for specified zip files
+ if (zipFileNames != null && !zipFileNames.isEmpty()) {
+ final StringBuffer s = new StringBuffer();
+ final Iterator i = zipFileNames.iterator();
+ s.append(i.next());
+ while (i.hasNext()) {
+ s.append(File.pathSeparator + i.next());
+ }
+ final ResourceLocator zips
+ = new PathResourceLocator(out, verbose, s.toString());
+ if (verbose)
+ out.println("Class Locator: using jar/zip files: "
+ + s.toString());
+ locators.add(zips);
+ }
+
+ // create resource locator for specified source path
+ if (sourcePath != null && sourcePath.length() > 0) {
+ final ResourceLocator path
+ = new PathResourceLocator(out, verbose, sourcePath);
+ if (verbose)
+ out.println("Class Locator: using source path: "
+ + sourcePath);
+ locators.add(path);
+ }
+
+ // print warning if no classes specified
+ affirm(!locators.isEmpty());
+ //if (locators.isEmpty()) {
+ // printWarning(getI18N("enhancer.using_no_classes"));
+ //}
+
+ // init class locators
+ classLocator
+ = new CombinedResourceLocator(out, verbose, locators);
+
+ // wrap with timing class locator
+ if (opts.doTiming) {
+ classLocator = new ResourceLocatorTimer(classLocator);
+ }
+ } catch (IOException ex) {
+ printError("Cannot initialize resource locator for classes", ex);
+ return CLASS_LOCATOR_ERROR;
+ }
+ return OK;
+ }
+
+ private int initEnhancerMetaData()
+ {
+ final boolean verbose = opts.verbose;
+ final String propertiesFileName = opts.propertiesFileName;
+ final List jdoFileNames = opts.jdoFileNames;
+ final List zipFileNames = opts.zipFileNames;
+ final String sourcePath = opts.sourcePath;
+ try {
+ if (propertiesFileName != null) {
+ jdoMetaData
+ = new EnhancerMetaDataPropertyImpl(out, verbose,
+ propertiesFileName);
+ } else {
+ jdoMetaData
+ = new EnhancerMetaDataJDOModelImpl(out, verbose,
+ jdoFileNames,
+ zipFileNames,
+ sourcePath);
+ }
+
+ // wrap with timing meta data object
+ if (opts.doTiming) {
+ jdoMetaData = new EnhancerMetaDataTimer(jdoMetaData);
+ }
+ } catch (EnhancerMetaDataFatalError ex) {
+ printError("Cannot initialize JDO meta-data source", ex);
+ return METADATA_ERROR;
+ }
+ return OK;
+ }
+
+ private int createEnhancer()
+ {
+ int res0 = initClassLocator();
+ if (res0 < 0) {
+ return res0;
+ }
+ affirm(classLocator != null);
+
+ int res = initEnhancerMetaData();
+ if (res < 0) {
+ return res;
+ }
+ affirm(jdoMetaData != null);
+
+ final Properties props = new Properties();
+ if (opts.verbose) {
+ props.put(EnhancerFilter.VERBOSE_LEVEL,
+ EnhancerFilter.VERBOSE_LEVEL_VERBOSE);
+ }
+
+ if (opts.doTiming) {
+ props.put(EnhancerFilter.DO_TIMING_STATISTICS,
+ Boolean.TRUE.toString());
+ }
+
+ if (opts.dumpClass) {
+ props.put(EnhancerFilter.DUMP_CLASS,
+ Boolean.TRUE.toString());
+ }
+
+ if (opts.noAugment) {
+ props.put(EnhancerFilter.NO_AUGMENT,
+ Boolean.TRUE.toString());
+ }
+
+ if (opts.noAnnotate) {
+ props.put(EnhancerFilter.NO_ANNOTATE,
+ Boolean.TRUE.toString());
+ }
+
+ try {
+ enhancer = new EnhancerFilter(jdoMetaData, props, out, err);
+ if (opts.doTiming) {
+ // wrap with timing byte-code enhancer
+ enhancer = new ClassFileEnhancerTimer(enhancer);
+ }
+ return 0;
+ } catch (EnhancerUserException ex) {
+ printError("Error while creating the enhancer", ex);
+ return -1;
+ } catch (EnhancerFatalError ex) {
+ // enhancer is not anymore guaranteed to be consistent
+ printError("Fatal error while creating the enhancer", ex);
+ enhancer = null;
+ return -1;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Enhances all files entered in the command line.
+ *
+ * @param classNames List of class names.
+ * @param classFileNames List of class file names.
+ * @param zipFileNames List of zip file names.
+ * @param jdoFileNames List of jdo file names.
+ */
+ private int enhanceInputFiles(List classNames,
+ List classFileNames,
+ List zipFileNames,
+ List jdoFileNames)
+ {
+ int res = 0;
+ try {
+ String name = null;
+ for (Iterator i = zipFileNames.iterator(); i.hasNext();) {
+ try {
+ name = (String)i.next();
+ enhanceZipFile(name);
+ } catch (EnhancerUserException ex) {
+ printError("Error while enhancing " + name, ex);
+ res++;
+ continue;
+ }
+ }
+ for (Iterator i = classFileNames.iterator(); i.hasNext();) {
+ try {
+ name = (String)i.next();
+ enhanceClassFile(openFileInputStream(name));
+ } catch (EnhancerUserException ex) {
+ printError("Error while enhancing " + name, ex);
+ res++;
+ continue;
+ }
+ }
+ for (Iterator i = classNames.iterator(); i.hasNext();) {
+ try {
+ name = (String)i.next();
+ enhanceClassFile(openClassInputStream(name));
+ } catch (EnhancerUserException ex) {
+ printError("Error while enhancing " + name, ex);
+ res++;
+ continue;
+ }
+ }
+ } catch (IOException ex) {
+ printError("IO Error while enhancing", ex);
+ return ++res;
+ } catch (EnhancerFatalError ex) {
+ // enhancer is not anymore guaranteed to be consistent
+ printError("Fatal error while enhancing", ex);
+ enhancer = null;
+ return ++res;
+ }
+ return res;
+ }
+
+ /**
+ * Enhances a classfile.
+ *
+ * @param in The input stream of the classfile.
+ */
+ private void enhanceClassFile(InputStream in)
+ throws IOException, EnhancerUserException, EnhancerFatalError
+ {
+ OutputStream out = null;
+ try {
+ final File temp = File.createTempFile("enhancer", ".class");
+ out = new BufferedOutputStream(new FileOutputStream(temp));
+
+ //enhance
+ final OutputStreamWrapper wrapper = new OutputStreamWrapper(out);
+ final boolean enhanced = enhancer.enhanceClassFile(in, wrapper);
+
+ closeOutputStream(out);
+ out = null;
+ createOutputFile(enhanced,
+ createClassFileName(wrapper.getClassName()),
+ temp);
+ } finally {
+ closeInputStream(in);
+ closeOutputStream(out);
+ }
+ }
+
+ /**
+ * Enhances a zipfile.
+ *
+ * @param filename The filename of the zipfile.
+ */
+ private void enhanceZipFile(String filename)
+ throws IOException, EnhancerUserException, EnhancerFatalError
+ {
+ ZipInputStream in = null;
+ ZipOutputStream out = null;
+ try {
+ final 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
+ final boolean enhanced
+ = ClassFileEnhancerHelper.enhanceZipFile(enhancer, in, out);
+
+ //create the output file
+ closeOutputStream(out);
+ out = null;
+ createOutputFile(enhanced, new File(filename).getName(), temp);
+ } finally {
+ closeOutputStream(out);
+ closeInputStream(in);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ static private InputStream openFileInputStream(String filename)
+ throws FileNotFoundException
+ {
+ return new BufferedInputStream(new FileInputStream(new File(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.
+ */
+ private InputStream openClassInputStream(String classname)
+ throws IOException
+ {
+ final String resourcename = createClassFileName(classname);
+ return classLocator.getInputStreamForResource(resourcename);
+ }
+
+ /**
+ * 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.
+ */
+ private File createZipOutputFile(String zipfilename)
+ {
+ return new File(opts.destinationDirectory,
+ new File(zipfilename).getName());
+ }
+
+ /**
+ * 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.
+ */
+ private void createOutputFile(boolean enhanced,
+ String filename,
+ File temp)
+ throws IOException
+ {
+ //noWrite or (not enhanced and not forceWrite)
+ if (opts.noWrite || (!enhanced && !opts.forceWrite)) {
+ temp.deleteOnExit();
+ return;
+ }
+
+ File file = new File(opts.destinationDirectory, filename);
+ createPathOfFile(file);
+ file.delete(); //delete old file if exists
+ 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".
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = new FileInputStream(temp);
+ out = new FileOutputStream(file);
+ int PAGESIZE = 4096; // Suggest a better size?
+ byte data[] = new byte[PAGESIZE];
+ while (in.available() > 0) {
+ int numRead = in.read(data, 0, PAGESIZE);
+ out.write(data, 0, numRead);
+ }
+ renamed = true;
+ } catch (IOException ex) {
+ throw new IOException("Could not rename temp file '" +
+ temp.getAbsolutePath() +
+ "' to '" + file.getAbsolutePath()
+ + "': " + ex);
+ } finally {
+ closeInputStream(in);
+ closeOutputStream(out);
+ }
+ if (renamed) {
+ temp.delete(); //delete temporary file
+ }
+ else {
+ throw new IOException("Could not rename temp file '" +
+ temp.getAbsolutePath() +
+ "' to '" + file.getAbsolutePath() + "'.");
+ }
+ }
+ }
+
+ /**
+ * Closes an input stream.
+ *
+ * @param in The input stream.
+ */
+ private void closeInputStream(InputStream in)
+ {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ex) {
+ printError(null, ex);
+ }
+ }
+ }
+
+ /**
+ * Closes an output stream.
+ *
+ * @param out The output stream.
+ */
+ private void closeOutputStream(OutputStream out)
+ {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException ex) {
+ printError(null, ex);
+ }
+ }
+ }
+
+ /**
+ * Tests if a filename is a classfile name (by testing if the filename
+ * ends with <code>".class"</code>).
+ *
+ * @param filename The name of the file.
+ * @return Do we have a potential classfile?
+ */
+ static private boolean isClassFileName(String filename)
+ {
+ return filename.toLowerCase().endsWith(".class");
+ }
+
+ /**
+ * Tests if a filename is a zipfile (by testing if the filename
+ * ends with <code>".zip"</code> or <code>".jar"</code>).
+ *
+ * @param filename The name of the file.
+ */
+ static private boolean isZipFileName(String filename)
+ {
+ final int n = filename.length();
+ if (n < 5) {
+ return false;
+ }
+ final String ext = filename.substring(n - 4);
+ return ext.equalsIgnoreCase(".zip") || ext.equalsIgnoreCase(".jar");
+ }
+
+ /**
+ * Tests if a filename is a jdo file name (by testing if the filename
+ * ends with <code>".jdo"</code>).
+ *
+ * @param filename The name of the file.
+ * @return Do we have a potential jdo file?
+ */
+ static private boolean isJdoFileName(String filename)
+ {
+ return filename.toLowerCase().endsWith(".jdo");
+ }
+
+ /**
+ * Creates a filename from a classname.
+ * This is done by replacing <code>'.'</code> by <code>'/'</code>.
+ *
+ * @param classname The classname.
+ * @return The filename.
+ */
+ static private String createClassFileName(String classname)
+ {
+ return classname.replace('.', '/') + ".class";
+ }
+
+ /**
+ * Creates only the path of the given file.
+ *
+ * @param file The file.
+ * @exception IOException If an error occured.
+ */
+ static private void createPathOfFile(File file)
+ throws IOException
+ {
+ File dir = file.getAbsoluteFile().getParentFile();
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new IOException("Error creating directory '"
+ + dir.getAbsolutePath() + "'.");
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Prints out an error.
+ *
+ * @param msg The error message (can be <code>null</code>).
+ * @param ex An optional exception (can be <code>null</code>).
+ */
+ private void printError(String msg,
+ Throwable ex)
+ {
+ out.flush();
+ if (msg != null) {
+ err.println(msg);
+ }
+ if (ex != null) {
+ if (opts.verbose) {
+ ex.printStackTrace(err);
+ }
+ else {
+ err.println(ex.toString());
+ }
+ }
+ }
+
+ /**
+ * Prints out a message.
+ *
+ * @param msg The message.
+ */
+ private void printMessage(String msg)
+ {
+ out.println(msg);
+ }
+}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/package.html
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/package.html?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/package.html (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/enhancer/package.html Fri Mar 18 17:02:29 2005
@@ -0,0 +1,26 @@
+<!--
+ 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.
+-->
+
+<html>
+<head>
+<title>Package org.apache.jdo.enhancer</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p>This package contains th eenhancer interface.</p>
+</body>
+</html>
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/Bundle.properties
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/Bundle.properties?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/Bundle.properties (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/Bundle.properties Fri Mar 18 17:02:29 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.
+
+
+# ResourceBundle properties file for model messages
+# key consists of: enhancer.<subpackage>.<description>
+# <subpackage> - is optional, package under model
+# <description> - short description (use _ to represent space)
+# all keys should be in lowercase
+
+#
+# Global Enhancer Metadata messages
+#
+
+# {0}=detail message
+enhancer.metadata.message=JDO ENHANCER: Metadata: {0}
+
+# {0}=error message
+enhancer.metadata.error=JDO ENHANCER: Metadata Error: {0}
+
+# {0}=warning message
+enhancer.metadata.warning=JDO ENHANCER: Metadata Warning: {0}
+
+# {0}=missing resource file
+enhancer.metadata.cannot_read_resource=Cannot read directory or jar file: {0}
+
+#
+# Detail Enhancer Metadata messages
+#
+
+# {0}=exception message
+enhancer.metadata.jdomodel_error=A JDO model exception has occurred: {0}
+
+# {0}=exception message
+enhancer.metadata.io_error=An I/O exception has occurred: {0}
+
+# {0}=filename
+enhancer.metadata.using_properties=using properties file: {0}
+
+# {0}=filenames
+enhancer.metadata.using_jdo_files=using jdo files: {0}
+
+# {0}=path
+enhancer.metadata.using_jar_files=using jar/zip files: {0}
+
+# {0}=path
+enhancer.metadata.using_source_path=using source path: {0}
+
+# {0}=
+enhancer.metadata.using_no_metadata=no JDO metadata source was specified
+
+
+#
+# Global enhancer messages
+#
+
+# {0}=detailed message
+enhancer.message=JDO ENHANCER: {0}
+
+# {0}=detailed message
+enhancer.error=JDO ENHANCER: At least one error occurred while enhancing input class for Transparent Persistence; detailed message(s): {0}
+
+# {0}=error number, {1}=detailed message
+enhancer.enumerated_error=JDO ENHANCER: Error ({0}): {1}
+
+# {0}=detailed message
+enhancer.internal_error=JDO ENHANCER: An internal error occurred while enhancing input class; detailed message: {0}
+
+# {0}=detailed message
+enhancer.warning=JDO ENHANCER: Warning: {0}
+
+#
+# Enhancer core messages
+#
+
+#
+enhancer.class_format_error=I/O error while reading input stream or input stream does not denote a valid Java class.
+
+#
+enhancer.io_error_while_writing_stream=I/O error while writing output stream.
+
+# {0}=dir name
+enhancer.unable_to_create_dir=Unable to create the directory named {0}.
+
+# {0}=class name
+enhancer.class_previously_annotated=The class {0} was previously annotated.
+
+# {0}=boolean
+enhancer.class_implements_jdo_pc=implements the JDO PersistenceCapable interface: {0}.
+
+#
+enhancer.class_has_default_constructor=has default constructor.
+enhancer.class_has_not_default_constructor=has not default constructor.
+
+#
+enhancer.class_has_static_initializer=has static initializer.
+enhancer.class_has_not_static_initializer=has not static initializer.
+
+#
+enhancer.class_has_clone_method=has clone method.
+enhancer.class_has_not_clone_method=has not clone method.
+
+#
+enhancer.class_has_writeObject_method=has writeObject method.
+enhancer.class_has_not_writeObject_method=has not writeObject method.
+
+#
+enhancer.class_has_writeReplace_method=has writeReplace method.
+enhancer.class_has_not_writeReplace_method=has not writeReplace method.
+
+#
+enhancer.class_has_readObject_method=has readObject method.
+enhancer.class_has_not_readObject_method=has not readObject method.
+
+# {0}=class name
+enhancer.class_missing_default_constructor=The persistence-capable class {0} does not provide a default (no-argument) constructor.
+
+# {0}=boolean
+enhancer.class_has_generic_jdo_fields=has the generic JDO fields: {0}.
+
+# {0}=boolean
+enhancer.class_has_generic_jdo_methods=has the generic JDO methods: {0}.
+
+# {0}=boolean
+enhancer.class_has_generic_jdo_members=has the generic JDO fields and methods: {0}.
+
+# {0}=boolean
+enhancer.class_has_specific_jdo_fields=has the specific JDO fields: {0}.
+
+# {0}=boolean
+enhancer.class_has_specific_jdo_methods=has the specific JDO methods: {0}.
+
+# {0}=boolean
+enhancer.class_has_specific_jdo_members=has the specific JDO fields and methods: {0}.
+
+# {0}=boolean
+enhancer.class_has_oid_handling_jdo_methods=has the ObjectId-handling JDO methods: {0}.
+
+# {0}=boolean
+enhancer.class_has_callback_jdo_methods=has the instance-callback JDO methods: {0}.
+
+# {0}=class name, {1}=method name
+enhancer.class_defines_jdo_method=The persistence-capable class {0} defines a JDO method called {1}.
+
+# {0}=class name, {1}=field name
+enhancer.class_defines_jdo_field=The persistence-capable class {0} defines a JDO field called {1}.
+
+# {0}=class name, {1}=member name
+enhancer.class_has_jdo_like_member=The persistence-capable class {0} defines a member {1} whose name starts with the reserved jdo prefix.
+
+# {0}=class name, {1}=method name,
+# {2}=expected signature, {3}=found signature
+# {4}=expected modifiers, {5}=found modifiers
+enhancer.class_has_illegally_declared_jdo_member=The persistence-capable class {0} has an illegally declared JDO member: {1}; expected signature: ''{2}''; found signature: ''{3}''; expected access modifier flags: {4}; found access modifier flags: {5}.
+
+# {0}=class name, {1}=found method names, {2}=missing method names
+enhancer.class_has_inconsistently_declared_jdo_members=The persistence-capable class {0} has an incosistent set of declared JDO members; found: {1}; missing: {2}.
+
+#
+# Other Enhancer messages
+#
+
+# {0}=filenames
+enhancer.using_jdo_files=using jdo files: {0}
+
+# {0}=path
+enhancer.using_archive_files=using jar/zip files: {0}
+
+# {0}=path
+enhancer.using_source_path=using source path: {0}
+
+# {0}=resource file name
+enhancer.using_file=using file: {0}
+
+# {0}=resource path element
+enhancer.using_path_element=using path element: {0}
+
+# {0}=class name, {1}=file name, {2}=file name
+enhancer.class_already_entered=The class {0} from {1} is already entered from {2}.
+
+# {0}=dir name, {1}=dir name
+enhancer.destination_directory_already_set=Attempt to set the destination directory to {0}, but it has already been set to {1}.
+
+# {0}=dir name
+enhancer.destination_directory_not_exist=The destination directory {0} does not exist.
+
+# {0}=resource name
+enhancer.found_resource=found resource: {0}
+enhancer.not_found_resource=not found resource: {0}
+
+# {0}=resource name
+enhancer.cannot_read_resource=resource does not exist or cannot be read: {0}
+
+# {0}=resource name {1}=exception message
+enhancer.io_error_while_reading_resource=An I/O exception has occurred while reading resource: {0}, exception: {1}
+
+# {0}=resource name
+enhancer.io_error_while_reading_resource=An I/O exception has occurred: {0}
+
+# {0}=resource name
+enhancer.illegal_path_element=illegal element source path: {0}
+
+#
+# Enhancer exception messages
+#
+
+MSG_CauseThrowable=CauseThrowable:
+MSG_CauseThrowableStackTrace=CauseThrowableStackTrace:
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgMain.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassArgOptions.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancer.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerHelper.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/ClassFileEnhancerTimer.java Fri Mar 18 17:02:29 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();
+ }
+ }
+}