Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerClassLoader.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerFatalError.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; + + +/** + * 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 EnhancerFatalError with no detail message. + */ + public EnhancerFatalError() + { + this.nested = null; + } + + /** + * Constructs an EnhancerFatalError with the specified + * detail message. + */ + public EnhancerFatalError(String msg) + { + super(msg); + this.nested = null; + } + + /** + * Constructs an EnhancerFatalError with an optional + * nested exception. + */ + public EnhancerFatalError(Throwable nested) + { + super(nested.toString()); + this.nested = nested; + } + + /** + * Constructs an EnhancerFatalError 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/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerOptions.java Fri Mar 18 17:02:29 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", + " : 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: .. .."); + printlnErr(indent + + "-j -s -d .."); + printlnErr(indent + + "-j -d .."); + //^olsen: consider allowing omission of destination directory for + // class file arguments + //printlnErr(indent + // + "-j [-d ] .."); + //^olsen: re-enable support for archive files + //printlnErr(indent + // + "[-j ] [-d ] .."); + } + + /** + * 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/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/EnhancerUserException.java Fri Mar 18 17:02:29 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 EnhancerUserException without detail + * message. + */ + public EnhancerUserException() + { + } + + /** + * Creates a new EnhancerUserException with the specified + * detail message. + * @param message the detail message. + */ + public EnhancerUserException(String message) + { + super(message); + } + + /** + * Creates a new EnhancerUserException 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 EnhancerUserException + * instance. + */ + public Throwable initCause(Throwable cause) + { + this.cause = cause; + return this; + } + + /** + * The String representation includes the name of the class, + * the descriptive comment (if any), + * and the String representation of the cause (if any). + * @return the String. + */ + 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 EnhancerUserException and its backtrace to the + * standard error output. + * Print cause Throwable's stack trace as well. + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Prints this EnhancerUserException and its backtrace to the + * specified print stream. + * Print cause Throwable's stack trace as well. + * @param s PrintStream 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 EnhancerUserException and its backtrace to the specified + * print writer. + * Print cause Throwable' stack trace as well. + * @param s PrintWriter 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/ri11/src/java/org/apache/jdo/impl/enhancer/GenericMain.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/GenericMain.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/GenericMain.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/GenericMain.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/GenericOptions.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaMain.java Fri Mar 18 17:02:29 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/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/JdoMetaOptions.java Fri Mar 18 17:02:29 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 for lookup of jdo files"); + + /** + * The jdo properties option. + */ + public final StringOption jdoPropertiesFile + = createStringOption("properties", null, + " : 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: .. .."); + printlnErr(indent + + "JDO metadata options:"); + printlnErr(indent + + " --properties [-j ] use property file for JDO metadata"); + printlnErr(indent + + " -j lookup .jdo files in the specified path"); + printlnErr(indent + + "Source option and arguments:"); + printlnErr(indent + + " -s .."); + printlnErr(indent + + " .."); + printlnErr(indent + + " .."); + } + + /** + * 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/ri11/src/java/org/apache/jdo/impl/enhancer/LogSupport.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/LogSupport.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/LogSupport.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/LogSupport.java Fri Mar 18 17:02:29 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)); + } + } +*/ +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OptionSet.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OptionSet.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OptionSet.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OptionSet.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,715 @@ +/* + * 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.Arrays; +import java.util.Map; +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Properties; + + +/** + * Represents a set of options a program may support. + * + * @author Martin Zaun + */ +public class OptionSet + extends LogSupport +{ + // return values of parse/check methods + static public final int OK = 0; + static public final int USAGE_ERROR = -1; + + // command-line option prefixes + static public final String prefix = "-"; + static public final String lprefix = "--"; + + // ---------------------------------------------------------------------- + + /** + * The base class of all option types. + */ + static public abstract class Option + { + /** + * The set the option is registered with. + */ + protected OptionSet set; + + /** + * The long form name of this option. + */ + public final String name; + + /** + * The short form name of this option. + */ + public final String abbrev; + + /** + * A description of this option. + */ + public final String descr; + + /** + * Creates an instance. + */ + public Option(String name, + String abbrev, + String descr) + { + affirm(name != null); + this.name = name; + this.abbrev = abbrev; + this.descr = descr; + } + + /** + * Parse this option for arguments it may require. + */ + abstract public int parse(Iterator i); + + /** + * Returns a String representation of this option's + * value for printing. + */ + abstract public String asNameValue(); + + /** + * Returns a usage description of this option. + */ + public String asUsageHelp() + { + String abbr = (abbrev == null ? " " : prefix + abbrev + "|"); + return (abbr + lprefix + name + " " + descr); + } + } + + /** + * An option that always causes a USAGE_ERROR when parsed (used for + * '-h|--help' kind of options). + */ + static public class HelpOption extends Option + { + /** + * Creates an instance. + */ + public HelpOption(String name, + String abbrev, + String descr) + { + super(name, abbrev, descr); + } + + public int parse(Iterator i) + { + return USAGE_ERROR; + } + + public String asNameValue() + { + return ("help = false"); + } + } + + /** + * An option representing a boolean flag. + */ + static public class FlagOption extends Option + { + /** + * The default value for this option. + */ + public final boolean deflt; + + /** + * The value of this option. + */ + public boolean value; + + /** + * Creates an instance. + */ + public FlagOption(String name, + String abbrev, + String descr) + { + this(name, abbrev, descr, false); + } + + /** + * Creates an instance. + */ + public FlagOption(String name, + String abbrev, + String descr, + boolean deflt) + { + super(name, abbrev, descr); + this.deflt = deflt; + this.value = deflt; + } + + public int parse(Iterator i) + { + if (value != deflt) { + set.printUsageError("Repeated option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + value = true; + return OK; + } + + public String asNameValue() + { + return (name + " = " + String.valueOf(value)); + } + } + + /** + * An option representing a int value. + */ + static public class IntOption extends Option + { + /** + * The default value for this option. + */ + public final int deflt; + + /** + * The value of this option. + */ + public int value; + + /** + * Creates an instance. + */ + public IntOption(String name, + String abbrev, + String descr) + { + this(name, abbrev, descr, 0); + } + + /** + * Creates an instance. + */ + public IntOption(String name, + String abbrev, + String descr, + int deflt) + { + super(name, abbrev, descr); + this.deflt = deflt; + this.value = deflt; + } + + public int parse(Iterator i) + { + if (value != deflt) { + set.printUsageError("Repeated option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + if (!i.hasNext()) { + set.printUsageError("Missing argument to option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + try { + value = Integer.valueOf((String)i.next()).intValue(); + } catch (NumberFormatException ex) { + set.printUsageError("Illegal argument to option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + return OK; + } + + public String asNameValue() + { + return (name + " = " + String.valueOf(value)); + } + } + + /** + * An option representing a String value. + */ + static public class StringOption extends Option + { + /** + * The default value for this option. + */ + public final String deflt; + + /** + * The value of this option. + */ + public String value; + + /** + * Creates an instance. + */ + public StringOption(String name, + String abbrev, + String descr) + { + this(name, abbrev, descr, null); + } + + /** + * Creates an instance. + */ + public StringOption(String name, + String abbrev, + String descr, + String deflt) + { + super(name, abbrev, descr); + this.deflt = deflt; + this.value = deflt; + } + + public int parse(Iterator i) + { + if (value != deflt) { + set.printUsageError("Repeated option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + if (!i.hasNext()) { + set.printUsageError("Missing argument to option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + value = (String)i.next(); + if (value.startsWith(prefix)) { + set.printUsageError("Missing argument to option: " + + prefix + abbrev + "/" + lprefix + name); + return USAGE_ERROR; + } + return OK; + } + + public String asNameValue() + { + return (name + " = " + String.valueOf(value)); + } + } + + // ---------------------------------------------------------------------- + + /** + * The list of registered options. + */ + protected final List options = new ArrayList(); + + /** + * Maps the option's long form against option instances. + */ + protected final Map names = new HashMap(); + + /** + * Maps the option's short form against option instances. + */ + protected final Map abbrevs = new HashMap(); + + /** + * The collected arguments. + */ + protected final List arguments = new ArrayList(); + + /** + * Usage printout. + */ + public String usageHeader + = "Usage: .. .."; + + /** + * Usage printout. + */ + public String optionsHeader + = "Options:"; + + /** + * Usage printout. + */ + public String argumentsHeader + = "Arguments:"; + + /** + * Usage printout. + */ + public String returnHeader + = "Returns: A non-zero value in case of errors."; + + /** + * Usage printout. + */ + public String indent + = " "; + + /** + * Creates an instance. + */ + public OptionSet(PrintWriter out, + PrintWriter err) + { + super(out, err); + } + + /** + * Creates an instance. + */ + public OptionSet(PrintWriter out, + PrintWriter err, + String usageHeader, + String optionsHeader, + String argumentsHeader, + String returnHeader, + String indent) + { + this(out, err); + this.usageHeader = usageHeader; + this.optionsHeader = optionsHeader; + this.argumentsHeader = argumentsHeader; + this.returnHeader = returnHeader; + this.indent = indent; + } + + // ---------------------------------------------------------------------- + + /** + * Registers an option with the set. + */ + public void register(Option option) + { + affirm(option != null); + option.set = this; + options.add(option); + + affirm(option.name != null); + Object obj = names.put(lprefix + option.name, option); + affirm(obj == null, "Option already registered: " + option.name); + + if (option.abbrev != null) { + obj = abbrevs.put(prefix + option.abbrev, option); + affirm(obj == null, "Option already registered: " + option.name); + } + } + + /** + * Creates and registers an option representing a usage-help request. + */ + public HelpOption createHelpOption(String name, + String abbrev, + String descr) + { + final HelpOption opt = new HelpOption(name, abbrev, descr); + register(opt); + return opt; + } + + /** + * Creates and registers an option representing a boolean flag. + */ + public FlagOption createFlagOption(String name, + String abbrev, + String descr) + { + final FlagOption opt = new FlagOption(name, abbrev, descr); + register(opt); + return opt; + } + + /** + * Creates and registers an option representing a boolean flag. + */ + public FlagOption createFlagOption(String name, + String abbrev, + String descr, + boolean deflt) + { + final FlagOption opt = new FlagOption(name, abbrev, descr, deflt); + register(opt); + return opt; + } + + /** + * Creates and registers an option representing a int + * value. + */ + public IntOption createIntOption(String name, + String abbrev, + String descr) + { + final IntOption opt = new IntOption(name, abbrev, descr); + register(opt); + return opt; + } + + /** + * Creates and registers an option representing a int + * value. + */ + public IntOption createIntOption(String name, + String abbrev, + String descr, + int deflt) + { + final IntOption opt = new IntOption(name, abbrev, descr, deflt); + register(opt); + return opt; + } + + /** + * Creates and registers an option representing a String + * value. + */ + public StringOption createStringOption(String name, + String abbrev, + String descr) + { + final StringOption opt = new StringOption(name, abbrev, descr); + register(opt); + return opt; + } + + /** + * Creates and registers an option representing a String + * value. + */ + public StringOption createStringOption(String name, + String abbrev, + String descr, + String deflt) + { + final StringOption opt + = new StringOption(name, abbrev, descr, deflt); + register(opt); + return opt; + } + + // ---------------------------------------------------------------------- + + /** + * Parses options and arguments. + */ + public int parse(String[] argv) + { + affirm(argv != null); + for (Iterator i = Arrays.asList(argv).iterator(); i.hasNext();) { + final String arg = (String)i.next(); + + // ignore empty arguments + if (arg == null || arg.length() == 0) { + //println("Ignoring empty command line argument."); + continue; + } + + // collect as argument if not option + if (!arg.startsWith(prefix)) { + arguments.add(arg); + continue; + } + + // lookup option by short and long form + Option option = (Option)abbrevs.get(arg); + if (option == null) { + option = (Option)names.get(arg); + } + + // return if option still not recognized + if (option == null) { + printlnErr("Unrecognized option: " + arg); + return USAGE_ERROR; + } + + // parse option for arguments + int res = option.parse(i); + if (res != OK) { + return res; + } + } + return OK; + } + + /** + * Checks options and arguments. + */ + public int check() + { + return OK; + } + + /** + * Parse and check options and arguments. + */ + public int process(String[] args) + { + int res = OK; + if ((res = parse(args)) != OK) { + printUsage(); + return res; + } + if ((res = check()) != OK) { + printUsage(); + return res; + } + return res; + } + + // ---------------------------------------------------------------------- + + /** + * Print a usage error message to System.err. + */ + public void printUsageError(String msg) + { + printlnErr("USAGE ERROR: " + msg); + } + + /** + * Print a usage message to System.err. + */ + public void printUsage() + { + println(); + printUsageHeader(); + printOptionHeader(); + printOptionUsage(); + printArgumentHeader(); + printArgumentUsage(); + printReturnHeader(); + printReturnUsage(); + } + + /** + * Print a usage message to System.err. + */ + public void printUsageHeader() + { + printlnErr(usageHeader); + } + + /** + * Print a usage message to System.err. + */ + public void printOptionHeader() + { + printlnErr(); + printlnErr(optionsHeader); + } + + /** + * Print a usage message to System.err. + */ + public void printOptionUsage() + { + for (Iterator i = options.iterator(); i.hasNext();) { + printlnErr(indent + ((Option)i.next()).asUsageHelp()); + } + } + + /** + * Print a usage message to System.err. + */ + public void printArgumentHeader() + { + printlnErr(); + printlnErr(argumentsHeader); + } + + /** + * Print a usage message to System.err. + */ + public void printArgumentUsage() + {} + + /** + * Print a usage message to System.err. + */ + public void printReturnHeader() + { + printlnErr(); + printlnErr(returnHeader); + } + + /** + * Print a usage message to System.err. + */ + public void printReturnUsage() + {} + + // ---------------------------------------------------------------------- + + /** + * Print options and arguments. + */ + public void printAll() + { + printOptions(); + printArguments(); + } + + /** + * Print options. + */ + public void printOptions() + { + println(); + println(optionsHeader); + for (Iterator i = options.iterator(); i.hasNext();) { + println(indent + ((Option)i.next()).asNameValue()); + } + } + + /** + * Print arguments. + */ + public void printArguments() + { + println(); + println(argumentsHeader); + print(indent); + for (Iterator i = arguments.iterator(); i.hasNext();) { + print(" " + i.next()); + } + } + + // ---------------------------------------------------------------------- + + /** + * Tests the class. + */ + static public void main(String[] args) + { + final PrintWriter out = new PrintWriter(System.out, true); + out.println("--> OptionSet.main()"); + final OptionSet options = new OptionSet(out, out); + out.println(" options.process() ..."); + int res = options.process(args); + out.println(" return value: " + res); + out.println("<-- OptionSet.main()"); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OutputStreamWrapper.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OutputStreamWrapper.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OutputStreamWrapper.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/OutputStreamWrapper.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,85 @@ +/* + * 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.OutputStream; + +/** + * This class serves as a wrapper for an output stream of a class file. The + * stream is passed as a parameter to the byte code enhancer, that can + * sets the classname of the written Java class to the wrapper. + *
+ * This wrapper is necessary to determine the classname outside the enhancer, + * after the class has been enhanced, since do do not always know the + * classname of an opened input stream. + * + */ +public class OutputStreamWrapper +{ + /** + * The wrapped output stream. + */ + private OutputStream out; + + /** + * The classname of the written Java class. This parameter + * is set by the enhancer. + */ + private String className = null; + + /** + * Constructs a new object. + * + * @param out The output stream to wrap. + */ + public OutputStreamWrapper(OutputStream out) + { + this.out = out; + } + + /** + * Gets the wrapped output stream. + * + * @return The wrapped output stream. + */ + public final OutputStream getStream() + { + return out; + } + + /** + * Gets the classname of the written Java class. This method should be + * called after the class has been enhanced. + * + * @return The name of the written Java class. + */ + public final String getClassName() + { + return className; + } + + /** + * Sets the name of the written Java class. This method should be called + * by the enhancer. + * + * @param classname The name of the Java class. + */ + public final void setClassName(String classname) + { + this.className = classname; + } +}