You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 19:55:54 UTC
svn commit: r171351 [15/16] - in /incubator/jdo/trunk/enhancer20: ./ src/
src/conf/ src/java/ src/java/org/ src/java/org/apache/
src/java/org/apache/jdo/ src/java/org/apache/jdo/enhancer/
src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/enhancer/
src/java/org/apache/jdo/impl/enhancer/classfile/
src/java/org/apache/jdo/impl/enhancer/core/
src/java/org/apache/jdo/impl/enhancer/generator/
src/java/org/apache/jdo/impl/enhancer/meta/
src/java/org/apache/jdo/impl/enhancer/meta/model/
src/java/org/apache/jdo/impl/enhancer/meta/prop/
src/java/org/apache/jdo/impl/enhancer/meta/util/
src/java/org/apache/jdo/impl/enhancer/util/ test/ test/sempdept/
test/sempdept/src/ test/sempdept/src/empdept/
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationDiffTest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationDiffTest.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationDiffTest.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationDiffTest.java Sun May 22 10:55:51 2005
@@ -0,0 +1,428 @@
+/*
+ * 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.util;
+
+import java.util.Iterator;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Stack;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileNotFoundException;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.apache.jdo.impl.enhancer.classfile.ClassFile;
+import org.apache.jdo.impl.enhancer.classfile.ClassMethod;
+import org.apache.jdo.impl.enhancer.classfile.Descriptor;
+
+
+
+/**
+ * Utility class for testing two class files for equal augmentation.
+ *
+ * @author Martin Zaun
+ */
+public class AugmentationDiffTest
+{
+ // return values of main()
+ static public final int OK = 0;
+ static public final int USAGE_ERROR = -1;
+ static public final int INTERNAL_ERROR = -3;
+
+ // return values of internal test methods
+ static public final int AFFIRMATIVE = 1;
+ static public final int NEGATIVE = 0;
+ static public final int ERROR = -1;
+
+ // output streams
+ static private boolean debug = false;
+ static private final PrintWriter out = new PrintWriter(System.out, true);
+ static private final PrintWriter err = new PrintWriter(System.err, true);
+
+ static final void affirm(boolean cond)
+ {
+ if (debug && !cond)
+ //^olsen: throw AssertionException ?
+ throw new RuntimeException("Assertion failed.");
+ }
+
+ static final void affirm(Object obj)
+ {
+ if (debug && obj == null)
+ //^olsen: throw AssertionException ?
+ throw new RuntimeException("Assertion failed: obj = null");
+ }
+
+ static private InputStream openFileInputStream(String fileName)
+ throws FileNotFoundException
+ {
+ return new BufferedInputStream(new FileInputStream(fileName));
+ }
+
+ static private void closeInputStream(InputStream in)
+ {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ex) {
+ err.println("Exception caught: " + ex);
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ private boolean verbose;
+ private String[] classFileNames;
+ private String[] classNames;
+ private String[] userClassNames;
+ private ClassFile[] classFiles;
+
+ public AugmentationDiffTest()
+ {}
+
+ private int diffAugmentation(PrintWriter out)
+ {
+ affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+ affirm(classFiles.length == 2);
+ affirm(classNames.length == 2);
+
+ int res = NEGATIVE;
+
+ final Map[] classMethods = { new HashMap(), new HashMap() };
+ for (int i = 0; i < 2; i++) {
+ for (Enumeration e = classFiles[i].methods().elements();
+ e.hasMoreElements();) {
+ final ClassMethod method = (ClassMethod)e.nextElement();
+ final String methodSig = method.signature().asString();
+ final String methodArgs = Descriptor.userMethodArgs(methodSig);
+ final String methodName = method.name().asString();
+
+ if (methodName.startsWith("jdo")) {
+ //if (methodName.equals("jdoReplaceField")) {
+ final Object obj
+ = classMethods[i].put(methodName + methodArgs, method);
+ affirm(obj == null);
+ }
+ }
+ }
+
+ final Set keySet = new HashSet();
+ keySet.addAll(classMethods[0].keySet());
+ keySet.addAll(classMethods[1].keySet());
+ for (Iterator i = keySet.iterator(); i.hasNext();) {
+ final Object key = i.next();
+
+ final ClassMethod method0
+ = (ClassMethod)classMethods[0].remove(key);
+ final ClassMethod method1
+ = (ClassMethod)classMethods[1].remove(key);
+ affirm(method0 != method1);
+ affirm(method0 != null || method1 != null);
+
+ if (method0 == null || method1 == null) {
+ out.println(" !!! ERROR: missing method: " + key);
+ out.println(" <<< method: " + method0);
+ out.println(" >>> method: " + method1);
+ res = ERROR;
+ continue;
+ }
+
+ final Stack msg = new Stack();
+ if (method0.isEqual(msg, method1)) {
+ if (verbose) {
+ out.println(" +++ equal augmentation: " + key);
+ }
+ } else {
+ out.println(" !!! not equal augmentation: " + key);
+ msg.push("method = " + method1);
+ msg.push("method = " + method0);
+ final StringWriter s0 = new StringWriter();
+ final StringWriter s1 = new StringWriter();
+ final PrintWriter p0 = new PrintWriter(s0);
+ final PrintWriter p1 = new PrintWriter(s1);
+ int j = 0;
+ while (!msg.empty()) {
+ p0.println(" <<< " + pad(j) + msg.pop());
+ p1.println(" >>> " + pad(j) + msg.pop());
+ j += 4;
+ }
+ out.println(s0.toString());
+ out.println(s1.toString());
+
+ if (verbose) {
+ ByteArrayOutputStream b0 = new ByteArrayOutputStream();
+ ByteArrayOutputStream b1 = new ByteArrayOutputStream();
+ method0.print(new PrintStream(b0), 4);
+ method1.print(new PrintStream(b1), 4);
+ out.println(b0.toString());
+ out.println(b1.toString());
+ if (res == NEGATIVE) {
+ res = AFFIRMATIVE;
+ }
+ }
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ static private String pad(int n)
+ {
+ final StringBuffer s = new StringBuffer();
+ for (int i = 0; i < n; i++) {
+ s.append(' ');
+ }
+ return s.toString();
+ }
+
+ private int parseClass(PrintWriter out,
+ int i)
+ {
+ affirm(0 <= i && i <= 1);
+ affirm(classFileNames.length == 2);
+ affirm(classFiles.length == 2);
+ affirm(classNames.length == 2);
+ affirm(userClassNames.length == 2);
+ final String fileName = classFileNames[i];
+
+ DataInputStream dis = null;
+ try {
+ // create class file
+ dis = new DataInputStream(openFileInputStream(fileName));
+ final boolean allowJDK12ClassFiles = true;
+ classFiles[i] = new ClassFile(dis, allowJDK12ClassFiles);
+
+ // get real class name
+ classNames[i] = classFiles[i].className().asString();
+ userClassNames[i] = classNames[i].replace('/', '.');
+ out.println(" +++ parsed classfile");
+ } catch (ClassFormatError ex) {
+ out.println(" !!! ERROR: format error when parsing classfile: "
+ + fileName);
+ out.println(" error: " + err);
+ return ERROR;
+ } catch (IOException ex) {
+ out.println(" !!! ERROR: exception while reading classfile: "
+ + fileName);
+ out.println(" exception: " + ex);
+ return ERROR;
+ } finally {
+ closeInputStream(dis);
+ }
+
+ return AFFIRMATIVE;
+ }
+
+ private int test(PrintWriter out,
+ String[] classFileNames)
+ {
+ affirm(classFileNames.length == 2);
+ this.classFileNames = classFileNames;
+
+ if (verbose) {
+ out.println("-------------------------------------------------------------------------------");
+ out.println();
+ out.println("Test classfiles for equal augmentation: ...");
+ }
+
+ // check parsing class
+ classFiles = new ClassFile[2];
+ classNames = new String[2];
+ userClassNames = new String[2];
+ for (int i = 0; i < 2; i++) {
+ final StringWriter s = new StringWriter();
+ if (parseClass(new PrintWriter(s), i) <= NEGATIVE) {
+ out.println();
+ out.println("!!! ERROR: failed parsing classfile: "
+ + classFileNames[i]);
+ out.println(s.toString());
+ return ERROR;
+ }
+
+ if (verbose) {
+ out.println();
+ out.println("+++ parsed classfile: " + classFileNames[i]);
+ out.println(s.toString());
+ }
+ }
+
+ // check class names
+ {
+ final StringWriter s = new StringWriter();
+ if (!classNames[0].equals(classNames[1])) {
+ out.println();
+ out.println("!!! ERROR: different class names:");
+ out.println("<<< class name = " + userClassNames[0]);
+ out.println(">>> class name = " + userClassNames[1]);
+ out.println(s.toString());
+ return ERROR;
+ }
+ }
+
+ // check for augmentation differences
+ final StringWriter s = new StringWriter();
+ final int r = diffAugmentation(new PrintWriter(s));
+ if (r < NEGATIVE) {
+ out.println();
+ out.println("!!! ERROR: incorrect augmentation: "
+ + userClassNames[0]);
+ out.println(s.toString());
+ return ERROR;
+ }
+
+ if (r == NEGATIVE) {
+ out.println();
+ out.println("+++ equal augmentation:"
+ + userClassNames[0]);
+ } else {
+ out.println();
+ out.println("!!! not equal augmentation:"
+ + userClassNames[0]);
+ }
+ if (verbose) {
+ out.println(s.toString());
+ }
+
+ return r;
+ }
+
+ public int test(PrintWriter out,
+ boolean verbose,
+ List classFileNames)
+ {
+ affirm(classFileNames.size() % 2 == 0);
+ this.verbose = verbose;
+
+ out.println();
+ out.println("AugmentationDiffTest: Testing Classes for JDO Persistence-Capability Enhancement");
+
+ final int all = classFileNames.size() / 2;
+ int nofFailed = 0;
+ for (int i = 0; i < all; i++) {
+ String name0 = (String)classFileNames.get(i);
+ String name1 = (String)classFileNames.get(all + i);
+ String[] pair = { name0, name1 };
+ if (test(out, pair) != NEGATIVE) {
+ nofFailed++;
+ }
+ }
+ final int nofPassed = all - nofFailed;
+
+ out.println();
+ out.println("AugmentationDiffTest: Summary: TESTED: " + all
+ + " PASSED: " + nofPassed
+ + " FAILED: " + nofFailed);
+ return nofFailed;
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Prints usage message.
+ */
+ static private void usage()
+ {
+ err.println();
+ err.println("Usage: AugmentationDiffTest <options> <classfile1> ... <classfile2> ...");
+ err.println();
+ err.println("This class pairwise tests if two classes have structurally the same code");
+ err.println("enhancement for persistence-capability (\"augmentation\").");
+ err.println();
+ err.println("Options include:");
+ err.println(" -h, --help print usage");
+ err.println(" -v, --verbose enable verbose output");
+ err.println();
+ err.println("Return value:");
+ err.println("= 0 equally augmented classfiles");
+ err.println("> 0 not equally augmented classfiles");
+ err.println("< 0 severe errors preventing the test to complete");
+ err.println();
+ }
+
+ static public void main(String[] argv)
+ {
+ // parse args
+ boolean verbose = false;
+ List classFileNames = new ArrayList();
+ for (int i = 0; i < argv.length; i++) {
+ String arg = argv[i];
+ if (arg.equals("-h") || arg.equals("--help")) {
+ usage();
+ System.exit(OK);
+ }
+ if (arg.equals("-v") || arg.equals("--verbose")) {
+ verbose = true;
+ continue;
+ }
+ if (arg.equals("-d") ||
+ arg.equals("--debug")) {
+ debug = true;
+ continue;
+ }
+ if (arg.startsWith("-")) {
+ err.println();
+ err.println("Unrecognized option: " + arg);
+ usage();
+ System.exit(USAGE_ERROR);
+ }
+ classFileNames.add(arg);
+ }
+
+ // check arguments
+ if (classFileNames.size() % 2 != 0) {
+ err.println();
+ err.println("Odd number of classfiles arguments.");
+ usage();
+ System.exit(USAGE_ERROR);
+ return;
+ }
+
+ if (debug) {
+ out.println("AugmentationDiffTest: options:");
+ out.println(" verbose = " + verbose);
+ out.print(" classFileNames =");
+ for (int i = 0; i < classFileNames.size(); i++)
+ out.print(" " + classFileNames.get(i));
+ out.println();
+ }
+
+ try {
+ final AugmentationDiffTest test = new AugmentationDiffTest();
+ final int res = test.test(out, verbose, classFileNames);
+ System.exit(res);
+ } catch (RuntimeException ex) {
+ err.println("Internal error;");
+ err.println("Exception caught:" + ex);
+ ex.printStackTrace(err);
+ System.exit(INTERNAL_ERROR);
+ }
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationTest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationTest.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationTest.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AugmentationTest.java Sun May 22 10:55:51 2005
@@ -0,0 +1,1380 @@
+/*
+ * 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.util;
+
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.IOException;
+
+import org.apache.jdo.impl.enhancer.EnhancerFatalError;
+import org.apache.jdo.impl.enhancer.EnhancerUserException;
+import org.apache.jdo.impl.enhancer.JdoMetaMain;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
+
+
+
+
+/**
+ * Utility class for testing a class file for correct augmentation.
+ *
+ * @author Martin Zaun
+ */
+public class AugmentationTest
+ extends JdoMetaMain
+{
+ // return values of internal test methods
+ static public final int AFFIRMATIVE = 1;
+ static public final int NEGATIVE = 0;
+ static public final int ERROR = -1;
+
+ static private final String[] transientPrefixes
+ = {"java.",
+ "javax." };
+
+ static String toString(int mods,
+ Class type,
+ String name)
+ {
+ final StringBuffer s = new StringBuffer();
+ s.append(Modifier.toString(mods));
+ s.append(" ");
+ s.append(type.getName());
+ s.append(" ");
+ s.append(name);
+ return s.toString();
+ }
+
+ static String toString(int mods,
+ String name,
+ Class[] params)
+ {
+ final StringBuffer s = new StringBuffer();
+ s.append(Modifier.toString(mods));
+ s.append(" ");
+ s.append(name);
+ s.append("(");
+ final int j = params.length - 1;
+ for (int i = 0; i <= j; i++) {
+ s.append(params[i].getName());
+ if (i < j)
+ s.append(",");
+ }
+ s.append(")");
+ return s.toString();
+ }
+
+ static String toString(int mods,
+ Class result,
+ String name,
+ Class[] params)
+ {
+ final StringBuffer s = new StringBuffer();
+ s.append(Modifier.toString(mods));
+ s.append(" ");
+ s.append(result.getName());
+ s.append(" ");
+ s.append(name);
+ s.append("(");
+ final int j = params.length - 1;
+ for (int i = 0; i <= j; i++) {
+ s.append(params[i].getName());
+ if (i < j)
+ s.append(",");
+ }
+ s.append(")");
+ return s.toString();
+ }
+
+ static String toString(int mods,
+ Class result,
+ String name,
+ Class[] params,
+ Class[] ex)
+ {
+ final StringBuffer s = new StringBuffer();
+ s.append(toString(mods, result, name, params));
+ s.append(" throws ");
+ final int j = ex.length - 1;
+ for (int i = 0; i <= j; i++) {
+ s.append(ex[i].getName());
+ if (i < j)
+ s.append(",");
+ }
+ return s.toString();
+ }
+
+ // ----------------------------------------------------------------------
+
+ // information on currently processed class
+ private boolean verbose;
+ private String className;
+ private String classPath;
+ private Class classObject;
+ private HashSet fields;
+ private HashSet methods;
+
+ // jdo class objects used by reflective tests
+ private ClassLoader classLoader;
+ private Class persistenceManagerClass;
+ private Class instanceCallbacksClass;
+ private Class persistenceCapableClass;
+ private Class objectIdFieldSupplierClass;
+ private Class objectIdFieldConsumerClass;
+ private Class stateManagerClass;
+
+ public AugmentationTest(PrintWriter out,
+ PrintWriter err)
+ {
+ super(out, err);
+ }
+
+ private int implementsInterface(PrintWriter out,
+ Class intf)
+ {
+ final Class[] interfaces = classObject.getInterfaces();
+ for (int i = interfaces.length - 1; i >= 0; i--) {
+ if (interfaces[i].equals(intf)) {
+ out.println(" +++ implements interface: "
+ + intf.getName());
+ return AFFIRMATIVE;
+ }
+ }
+ out.println(" --- not implementing interface: "
+ + intf.getName());
+ return NEGATIVE;
+ }
+
+ private int hasField(PrintWriter out,
+ int mods,
+ Class type,
+ String name)
+ {
+ try {
+ final Field field = classObject.getDeclaredField(name);
+ fields.remove(field);
+
+ if ((field.getModifiers() & mods) != mods) {
+ out.println(" !!! ERROR: field declaration: unmatched modifiers");
+ out.println(" expected: "
+ + toString(mods, type, name));
+ out.println(" found: "
+ + field.toString());
+ return ERROR;
+ }
+
+ if (!field.getType().equals(type)) {
+ out.println(" !!! ERROR: field declaration: unexpected type");
+ out.println(" expected: "
+ + toString(mods, type, name));
+ out.println(" found: "
+ + field.toString());
+ return ERROR;
+ }
+
+ out.println(" +++ has field: "
+ + field.toString());
+ return AFFIRMATIVE;
+ } catch (NoSuchFieldException ex) {
+ out.println(" --- no field: "
+ + toString(mods, type, name));
+ return NEGATIVE;
+ }
+ }
+
+ private int hasConstructor(PrintWriter out,
+ int mods,
+ Class[] params)
+ {
+ try {
+ final Constructor ctor = classObject.getDeclaredConstructor(params);
+
+ if ((ctor.getModifiers() & mods) != mods) {
+ out.println(" !!! ERROR: constructor declaration: unmatched modifiers");
+ out.println(" expected: "
+ + toString(mods, className, params));
+ out.println(" found: "
+ + ctor.toString());
+ return ERROR;
+ }
+
+ out.println(" +++ has constructor: "
+ + ctor.toString());
+ return AFFIRMATIVE;
+ } catch (NoSuchMethodException ex) {
+ out.println(" --- no constructor: "
+ + toString(mods, className, params));
+ return NEGATIVE;
+ }
+ }
+
+ private int hasMethod(PrintWriter out,
+ int mods,
+ Class result,
+ String name,
+ Class[] params,
+ Class[] exepts)
+ {
+ try {
+ final Method method = classObject.getDeclaredMethod(name, params);
+ methods.remove(method);
+
+ if ((method.getModifiers() & mods) != mods) {
+ out.println(" !!! ERROR: method declaration: unmatched modifiers");
+ out.println(" expected: "
+ + toString(mods, result, name, params));
+ out.println(" found: "
+ + method.toString());
+ return ERROR;
+ }
+
+ if (!method.getReturnType().equals(result)) {
+ out.println(" !!! ERROR: method declaration: unexpected result type");
+ out.println(" expected: "
+ + toString(mods, result, name, params));
+ out.println(" found: "
+ + method.toString());
+ return ERROR;
+ }
+
+ final Collection c0 = Arrays.asList(exepts);
+ final Collection c1 = Arrays.asList(method.getExceptionTypes());
+ if (!c0.containsAll(c1)) {
+ out.println(" !!! ERROR: method declaration: unexpected exceptions");
+ out.println(" expected: "
+ + toString(mods, result, name, params, exepts));
+ out.println(" found: "
+ + method.toString());
+ return ERROR;
+ }
+ if (!c1.containsAll(c0)) {
+ out.println(" !!! ERROR: method declaration: unmatched exceptions");
+ out.println(" expected: "
+ + toString(mods, result, name, params, exepts));
+ out.println(" found: "
+ + method.toString());
+ return ERROR;
+ }
+
+ out.println(" +++ has method: "
+ + method.toString());
+ return AFFIRMATIVE;
+ } catch (NoSuchMethodException ex) {
+ out.println(" --- no method: "
+ + toString(mods, result, name, params));
+ return NEGATIVE;
+ }
+ }
+
+ private int hasMethod(PrintWriter out,
+ int mods,
+ Class result,
+ String name,
+ Class[] params)
+ {
+ return hasMethod(out, mods, result, name, params, new Class[]{});
+ }
+
+ private int evaluate(int nofFeatures,
+ int[] r)
+ {
+ affirm(nofFeatures <= r.length);
+
+ int res = 0;
+ for (int i = 0; i < nofFeatures; i++) {
+ final int j = r[i];
+ affirm(ERROR <= j && j <= AFFIRMATIVE);
+
+ if (j < ERROR) {
+ return ERROR;
+ }
+
+ if (j > NEGATIVE) {
+ res++;
+ }
+ }
+ affirm(res >= 0);
+
+ if (res >= nofFeatures) {
+ return AFFIRMATIVE;
+ }
+ return NEGATIVE;
+ }
+
+ private int hasGenericAugmentation(PrintWriter out)
+ {
+ affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+ affirm(classObject);
+
+ final int nofFeatures = 16;
+ final int[] r = new int[nofFeatures];
+ {
+ int i = 0;
+
+ r[i++] = hasField(
+ out,
+ Modifier.PROTECTED | Modifier.TRANSIENT,
+ stateManagerClass,
+ "jdoStateManager");
+
+ r[i++] = hasField(
+ out,
+ Modifier.PROTECTED | Modifier.TRANSIENT,
+ byte.class,
+ "jdoFlags");
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC
+ | Modifier.FINAL
+ | Modifier.SYNCHRONIZED,
+ void.class,
+ "jdoReplaceStateManager",
+ new Class[]{stateManagerClass});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ void.class,
+ "jdoReplaceFlags",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ persistenceManagerClass,
+ "jdoGetPersistenceManager",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ Object.class,
+ "jdoGetObjectId",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ Object.class,
+ "jdoGetTransactionalObjectId",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ boolean.class,
+ "jdoIsPersistent",
+ new Class[]{});
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ boolean.class,
+ "jdoIsTransactional",
+ new Class[]{});
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ boolean.class,
+ "jdoIsNew",
+ new Class[]{});
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ boolean.class,
+ "jdoIsDeleted",
+ new Class[]{});
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ boolean.class,
+ "jdoIsDirty",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ void.class,
+ "jdoMakeDirty",
+ new Class[]{String.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ void.class,
+ "jdoReplaceFields",
+ new Class[]{int[].class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC | Modifier.FINAL,
+ void.class,
+ "jdoProvideFields",
+ new Class[]{int[].class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PROTECTED | Modifier.FINAL,
+ void.class,
+ "jdoPreSerialize",
+ new Class[]{});
+
+ affirm(i == nofFeatures);
+ }
+
+ return evaluate(nofFeatures, r);
+ }
+
+ private int hasSpecificAugmentation(PrintWriter out)
+ {
+ affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+ affirm(classObject);
+
+ final int nofFeatures = 15;
+ final int[] r = new int[nofFeatures];
+ {
+ int i = 0;
+
+ r[i++] = implementsInterface(
+ out,
+ persistenceCapableClass);
+
+ r[i++] = hasField(
+ out,
+ Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
+ int.class,
+ "jdoInheritedFieldCount");
+
+ r[i++] = hasField(
+ out,
+ Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
+ String[].class,
+ "jdoFieldNames");
+
+ r[i++] = hasField(
+ out,
+ Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
+ Class[].class,
+ "jdoFieldTypes");
+
+ r[i++] = hasField(
+ out,
+ Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
+ byte[].class,
+ "jdoFieldFlags");
+
+ r[i++] = hasField(
+ out,
+ Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
+ Class.class,
+ "jdoPersistenceCapableSuperclass");
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PROTECTED | Modifier.STATIC,
+ int.class,
+ "jdoGetManagedFieldCount",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ persistenceCapableClass,
+ "jdoNewInstance",
+ new Class[]{stateManagerClass});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ persistenceCapableClass,
+ "jdoNewInstance",
+ new Class[]{stateManagerClass, Object.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoReplaceField",
+ new Class[]{int.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoProvideField",
+ new Class[]{int.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoCopyFields",
+ new Class[]{Object.class, int[].class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PROTECTED | Modifier.FINAL,
+ void.class,
+ "jdoCopyField",
+ new Class[]{classObject, int.class});
+
+//^olsen: hack for debugging
+/*
+ r[i++] = hasField(
+ out,
+ Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
+ longClass,
+ "serialVersionUID");
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PRIVATE,
+ void.class,
+ "writeObject",
+ new Class[]{java.io.ObjectOutputStream.class},
+ new Class[]{java.io.IOException.class});
+
+ //^olsen: need to check for clone()?
+*/
+
+ //^olsen: hack for debugging
+ affirm(i == nofFeatures-2);
+ //affirm(i == nofFeatures);
+ }
+
+ //^olsen: hack for debugging
+ return evaluate(nofFeatures - 2, r);
+ }
+
+ private int hasKeyHandlingAugmentation(PrintWriter out)
+ {
+ affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+ affirm(classObject);
+
+ final int nofFeatures = 6;
+ final int[] r = new int[nofFeatures];
+ {
+ int i = 0;
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ Object.class,
+ "jdoNewObjectIdInstance",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ Object.class,
+ "jdoNewObjectIdInstance",
+ new Class[]{String.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoCopyKeyFieldsToObjectId",
+ new Class[]{Object.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoCopyKeyFieldsToObjectId",
+ new Class[]{objectIdFieldSupplierClass, Object.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PROTECTED,
+ void.class,
+ "jdoCopyKeyFieldsFromObjectId",
+ new Class[]{Object.class});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoCopyKeyFieldsFromObjectId",
+ new Class[]{objectIdFieldConsumerClass, Object.class});
+
+ affirm(i == nofFeatures);
+ }
+
+ return evaluate(nofFeatures, r);
+ }
+
+ private int hasAccessorMutators(PrintWriter out)
+ throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+ {
+ affirm(classObject);
+ int res = NEGATIVE;
+
+ // find managed field candidates by scanning for jdo[GS]et methods
+ final HashSet managedFields = new HashSet();
+ for (Iterator i = new HashSet(methods).iterator(); i.hasNext();) {
+ final Method method = (Method)i.next();
+ final String name = method.getName();
+
+ if (!name.startsWith("jdoGet") && !name.startsWith("jdoSet")) {
+ continue;
+ }
+ final String fieldName = name.substring(6);
+
+ // find declared field
+ final Field field;
+ try {
+ field = classObject.getDeclaredField(fieldName);
+ } catch (NoSuchFieldException ex) {
+ out.println(" !!! ERROR: potential jdo accessor/mutator method doesn't match declared field");
+ out.println(" found method: " + method);
+ methods.remove(method);
+ res = ERROR;
+ continue;
+ }
+
+ // field must not be static
+ final int fieldMods = field.getModifiers();
+ if ((fieldMods & Modifier.STATIC) != 0) {
+ out.println(" !!! ERROR: potential jdo accessor/mutator method matches a static field");
+ out.println(" found method: " + method);
+ out.println(" found field: " + field);
+ methods.remove(method);
+ res = ERROR;
+ continue;
+ }
+
+ // field must be managed by jdo metadata
+ if (jdoMeta != null && !jdoMeta.isManagedField(classPath, fieldName)) {
+ out.println(" !!! ERROR: potential jdo accessor/mutator method matches a non-managed field");
+ out.println(" found method: " + method);
+ out.println(" found field: " + field);
+ methods.remove(method);
+ res = ERROR;
+ continue;
+ }
+
+ managedFields.add(field);
+ }
+
+ // find managed field candidates by jdo meta-data
+ final String[] metaFieldNames = (jdoMeta != null
+ ? jdoMeta.getManagedFields(classPath)
+ : new String[]{});
+ for (int i = 0; i < metaFieldNames.length; i++) {
+ final String fieldName = metaFieldNames[i];
+
+ // find declared field
+ final Field field;
+ try {
+ field = classObject.getDeclaredField(fieldName);
+ fields.remove(field);
+ } catch (NoSuchFieldException ex) {
+ out.println(" !!! ERROR: field defined by jdo meta-data not declared in class");
+ out.println(" no declared field: " + fieldName);
+ res = ERROR;
+ continue;
+ }
+
+ // field must not be static
+ final int fieldMods = field.getModifiers();
+ if ((fieldMods & Modifier.STATIC) != 0) {
+
+ out.println(" !!! ERROR: field defined by jdo meta-data is declared static in class");
+ out.println(" static field: " + field);
+ res = ERROR;
+ continue;
+ }
+
+ managedFields.add(field);
+ }
+
+ // check accessor/mutator methods for managed field candidates
+ final HashSet methodSet = new HashSet(methods);
+ for (Iterator i = managedFields.iterator(); i.hasNext();) {
+ final Field field = (Field)i.next();
+ final String fieldName = field.getName();
+ final Class fieldType = field.getType();
+ final int fieldMods = field.getModifiers();
+
+ // accessor's and mutator's signature
+ final int mods = (Modifier.STATIC
+ | (fieldMods
+ & (Modifier.PUBLIC
+ | Modifier.PROTECTED
+ | Modifier.PRIVATE)));
+ final String accessorName = "jdoGet" + fieldName;
+ final Class[] accessorParams = new Class[]{classObject};
+ final Class accessorReturnType = fieldType;
+ final String mutatorName = "jdoSet" + fieldName;
+ final Class[] mutatorParams = new Class[]{classObject, fieldType};
+ final Class mutatorReturnType = void.class;
+ final Class[] exeptions = new Class[]{};
+
+ // find accessor
+ final int r0 = hasMethod(out,
+ mods,
+ accessorReturnType,
+ accessorName,
+ accessorParams,
+ exeptions);
+ if (r0 < NEGATIVE) {
+ res = ERROR;
+ } else if (r0 == NEGATIVE) {
+ out.println(" !!! ERROR: missing or incorrect jdo accessor for declared field");
+ out.println(" field: " + field);
+ out.println(" expected: "
+ + toString(mods,
+ accessorReturnType,
+ accessorName,
+ accessorParams,
+ exeptions));
+ for (Iterator j = methodSet.iterator(); j.hasNext();) {
+ final Method method = (Method)j.next();
+ if (method.getName().equals(accessorName)) {
+ out.println(" found: " + method);
+ methods.remove(method);
+ }
+ }
+ res = ERROR;
+ }
+
+ // find mutator
+ final int r1 = hasMethod(out,
+ mods,
+ mutatorReturnType,
+ mutatorName,
+ mutatorParams,
+ exeptions);
+ if (r1 < NEGATIVE) {
+ res = ERROR;
+ } else if (r1 == NEGATIVE) {
+ out.println(" !!! ERROR: missing or incorrect jdo mutator for declared field");
+ out.println(" field: " + field);
+ out.println(" expected: "
+ + toString(mods,
+ mutatorReturnType,
+ mutatorName,
+ mutatorParams,
+ exeptions));
+ for (Iterator j = methodSet.iterator(); j.hasNext();) {
+ final Method method = (Method)j.next();
+ if (method.getName().equals(accessorName)) {
+ out.println(" found: " + method);
+ methods.remove(method);
+ }
+ }
+ res = ERROR;
+ }
+
+ // have found legal accessor/mutator pair
+ if (res == NEGATIVE) {
+ res = AFFIRMATIVE;
+ }
+ }
+
+ return res;
+ }
+
+ private int hasInstanceCallbacks(PrintWriter out)
+ {
+ affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+ affirm(classObject);
+
+ final int nofFeatures = 5;
+ final int[] r = new int[nofFeatures];
+ {
+ int i = 0;
+
+ r[i++] = implementsInterface(
+ out,
+ instanceCallbacksClass);
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoPostLoad",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoPreStore",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoPreClear",
+ new Class[]{});
+
+ r[i++] = hasMethod(
+ out,
+ Modifier.PUBLIC,
+ void.class,
+ "jdoPreDelete",
+ new Class[]{});
+
+ affirm(i == nofFeatures);
+ }
+
+ return evaluate(1, r);
+ }
+
+ private int testPCFeasibility(PrintWriter out)
+ {
+ affirm(classObject);
+
+ int status = AFFIRMATIVE;
+
+ final int mods = classObject.getModifiers();
+
+ // PC class must provide default constructor
+ StringWriter s = new StringWriter();
+ final int hasCtor = hasConstructor(new PrintWriter(s),
+ 0,
+ new Class[]{});
+ if (hasCtor <= NEGATIVE) {
+ status = ERROR;
+ } else {
+ if (verbose) {
+ out.print(s.toString());
+ }
+ }
+
+ // PC class must not be an interface type
+ if (classObject.isInterface()) {
+ out.println(" !!! ERROR: class is interface");
+ status = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ is not an interface");
+ }
+ }
+
+ // PC class may be abstract if not instantiated at class
+ // registration with JDOImplHelper
+ //if (Modifier.isAbstract(mods)) {
+ // out.println(" !!! ERROR: class is abstract");
+ // status = ERROR;
+ //} else {
+ // if (verbose) {
+ // out.println(" +++ is not abstract");
+ // }
+ //}
+
+ // PC class cannot be an inner classes because of instantiation
+ // from static context (registration with JDOImplHelper)
+ if (classObject.getDeclaringClass() != null
+ && !Modifier.isStatic(mods)) {
+ out.println(" !!! ERROR: class is inner class");
+ status = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ is not an inner class");
+ }
+ }
+
+ // PC class must not have transient package prefix
+ for (int i = 0; i < transientPrefixes.length; i++) {
+ final String typePrefix = transientPrefixes[i];
+ if (className.startsWith(typePrefix)) {
+ out.println(" !!! ERROR: class is in package: "
+ + typePrefix + "..");
+ status = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ is not in package: "
+ + typePrefix + "..");
+ }
+ }
+ }
+
+ //^olsen: PC class must not be SCO type?
+
+ // PC class is better not a Throwable
+ //if (Throwable.class.isAssignableFrom(classObject)) {
+ // out.println(" !!! ERROR: class extends Throwable");
+ // status = ERROR;
+ //} else {
+ // if (verbose) {
+ // out.println(" +++ does not extend Throwable");
+ // }
+ //}
+
+ // PC class can have any access modifier; JDO runtime accesses it
+ // through PersistenceCapable interface only
+ //if (!Modifier.isPublic(mods)) {
+ // out.println(" !!! ERROR: class is not public");
+ // status = ERROR;
+ //} else {
+ // if (verbose) {
+ // out.println(" +++ is public");
+ // }
+ //}
+
+ // pathological: PC class must not be a primitive type
+ if (classObject.isPrimitive()) {
+ out.println(" !!! ERROR: class is of primitive type");
+ status = ERROR;
+ }
+
+ // pathological: PC class must not be an array type
+ if (classObject.isArray()) {
+ out.println(" !!! ERROR: class is of array type");
+ status = ERROR;
+ }
+
+ // pathological: PC class must have superclass
+ if (classObject.getSuperclass() == null) {
+ out.println(" !!! ERROR: class doesn't have super class");
+ status = ERROR;
+ }
+
+ return status;
+ }
+
+ private int hasNoIllegalJdoMembers(PrintWriter out)
+ {
+ affirm(classObject);
+ int res = AFFIRMATIVE;
+
+ for (Iterator i = new HashSet(methods).iterator(); i.hasNext();) {
+ final Method method = (Method)i.next();
+ final String name = method.getName();
+ if (name.startsWith("jdo")) {
+ out.println(" !!! ERROR: illegal jdo method");
+ out.println(" found method: " + method);
+ methods.remove(method);
+ res = ERROR;
+ }
+ }
+
+ for (Iterator i = new HashSet(fields).iterator(); i.hasNext();) {
+ final Field field = (Field)i.next();
+ final String name = field.getName();
+ if (name.startsWith("jdo")) {
+ out.println(" !!! ERROR: illegal jdo field");
+ out.println(" found field: " + field);
+ fields.remove(field);
+ res = ERROR;
+ }
+ }
+
+ return res;
+ }
+
+ private int testAugmentation(PrintWriter out)
+ throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+ {
+ affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+ affirm(classObject);
+ affirm(className);
+
+ // check class-specific enhancement
+ StringWriter s = new StringWriter();
+ int r0 = hasSpecificAugmentation(new PrintWriter(s));
+ //System.out.println("hasSpecificAugmentation = " + r0);
+ if (r0 < NEGATIVE) {
+ out.println(" !!! ERROR: inconsistent \"class-specific\" augmentation");
+ out.println(s.toString());
+ r0 = ERROR;
+ } else if (r0 == NEGATIVE) {
+ if (jdoMeta != null && jdoMeta.isPersistenceCapableClass(classPath)) {
+ out.println(" !!! ERROR: missing \"class-specific\" augmentation");
+ out.println(s.toString());
+ r0 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" --- no \"class-specific\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ } else {
+ affirm(r0 > NEGATIVE);
+ if (jdoMeta != null && !jdoMeta.isPersistenceCapableClass(classPath)) {
+ out.println(" !!! ERROR: unexpected \"class-specific\" augmentation");
+ out.println(s.toString());
+ r0 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ has correct \"class-specific\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ }
+
+ // check key-handling enhancement
+ s = new StringWriter();
+ int r1 = hasKeyHandlingAugmentation(new PrintWriter(s));
+ //System.out.println("hasKeyHandlingAugmentation = " + r1);
+ if (r1 < NEGATIVE) {
+ out.println(" !!! ERROR: inconsistent \"key-handling\" augmentation");
+ out.println(s.toString());
+ r1 = ERROR;
+ } else if (r1 == NEGATIVE) {
+ if (jdoMeta != null
+ && (jdoMeta.isPersistenceCapableClass(classPath)
+ && jdoMeta.getKeyClass(classPath) != null)) {
+ out.println(" !!! ERROR: missing \"key-handling\" augmentation");
+ out.println(s.toString());
+ r1 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" --- no \"key-handling\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ } else {
+ affirm(r1 > NEGATIVE);
+ if (r0 == NEGATIVE
+ || (jdoMeta != null
+ && (!jdoMeta.isPersistenceCapableRootClass(classPath)
+ && jdoMeta.getKeyClass(classPath) == null))) {
+ out.println(" !!! ERROR: unexpected \"key-handling\" augmentation");
+ out.println(s.toString());
+ r1 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ has correct \"key-handling\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ }
+ affirm(r0 != NEGATIVE || r1 <= NEGATIVE);
+
+ // check generic enhancement
+ s = new StringWriter();
+ int r2 = hasGenericAugmentation(new PrintWriter(s));
+ //System.out.println("hasGenericAugmentation = " + r2);
+ if (r2 < NEGATIVE) {
+ out.println(" !!! ERROR: inconsistent \"generic\" augmentation");
+ out.println(s.toString());
+ r2 = ERROR;
+ } else if (r2 == NEGATIVE) {
+ if (jdoMeta != null
+ && jdoMeta.isPersistenceCapableRootClass(classPath)) {
+ out.println(" !!! ERROR: missing \"generic\" augmentation");
+ out.println(s.toString());
+ r2 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" --- no \"generic\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ } else {
+ affirm(r2 > NEGATIVE);
+ if (r0 == NEGATIVE
+ || (jdoMeta != null
+ && !jdoMeta.isPersistenceCapableRootClass(classPath))) {
+ out.println(" !!! ERROR: unexpected \"generic\" augmentation");
+ out.println(s.toString());
+ r2 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ has correct \"generic\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ }
+ affirm(r0 != NEGATIVE || r2 <= NEGATIVE);
+
+ // check accessor/mutator enhancement
+ s = new StringWriter();
+ int r3 = hasAccessorMutators(new PrintWriter(s));
+ //System.out.println("hasAccessorMutators = " + r3);
+ if (r3 < NEGATIVE) {
+ out.println(" !!! ERROR: inconsistent \"accessor/mutator\" augmentation");
+ out.println(s.toString());
+ } else if (r3 == NEGATIVE) {
+ if (verbose) {
+ out.println(" --- no \"accessor/mutator\" augmentation");
+ out.println(s.toString());
+ }
+ } else {
+ affirm(r3 > NEGATIVE);
+ if (r0 == NEGATIVE) {
+ out.println(" !!! ERROR: unexpected \"accessor/mutator\" augmentation");
+ out.println(s.toString());
+ r3 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ has correct \"accessor/mutator\" augmentation");
+ out.println(s.toString());
+ }
+ }
+ }
+ affirm(r0 != NEGATIVE || r3 <= NEGATIVE);
+
+ // check user-defined instance callback features
+ s = new StringWriter();
+ int r4 = hasInstanceCallbacks(new PrintWriter(s));
+ //System.out.println("hasInstanceCallbacks = " + r4);
+ if (r4 < NEGATIVE) {
+ out.println(" !!! ERROR: inconsistent instance callback features");
+ out.println(s.toString());
+ } else if (r4 == NEGATIVE) {
+ if (verbose) {
+ out.println(" --- no instance callback features");
+ out.println(s.toString());
+ }
+ } else {
+ affirm(r4 > NEGATIVE);
+ if (verbose) {
+ out.println(" +++ has instance callback features");
+ out.println(s.toString());
+ }
+ }
+
+ // check for illegal jdo* member enhancement
+ s = new StringWriter();
+ int r5 = hasNoIllegalJdoMembers(new PrintWriter(s));
+ if (r5 <= NEGATIVE) {
+ out.println(" !!! ERROR: illegal jdo member");
+ out.println(s.toString());
+ } else {
+ if (verbose) {
+ out.println(" +++ no illegal jdo member");
+ out.println(s.toString());
+ }
+ }
+
+ // return if error so far
+ if (r0 < NEGATIVE || r1 < NEGATIVE || r2 < NEGATIVE || r3 < NEGATIVE
+ || r4 < NEGATIVE || r5 < NEGATIVE) {
+ return ERROR;
+ }
+
+ // return if class not PC and no error
+ if (r0 == NEGATIVE) {
+ affirm(r1 == NEGATIVE);
+ affirm(r2 == NEGATIVE);
+ affirm(r3 == NEGATIVE);
+ affirm(r4 >= NEGATIVE);
+ affirm(r5 > NEGATIVE);
+ return NEGATIVE;
+ }
+
+ // check feasibility if class PC
+ s = new StringWriter();
+ int r6 = testPCFeasibility(new PrintWriter(s));
+ if (r6 <= NEGATIVE) {
+ out.println(" !!! not feasible for persistence-capability");
+ out.println(s.toString());
+ r6 = ERROR;
+ } else {
+ if (verbose) {
+ out.println(" +++ is feasible for persistence-capability");
+ out.println(s.toString());
+ }
+ }
+
+ // return with error if class not PC feasible
+ if (r6 < NEGATIVE) {
+ return ERROR;
+ }
+
+ // class PC and no errors with augmentation
+ return AFFIRMATIVE;
+ }
+
+ private int testLoadingClass(PrintWriter out)
+ {
+ try {
+ classObject = classLoader.loadClass(className);
+ out.println(" +++ loaded class");
+ } catch (LinkageError err) {
+ out.println(" !!! ERROR: linkage error when loading class: "
+ + className);
+ out.println(" error: " + err);
+ return ERROR;
+ } catch (ClassNotFoundException ex) {
+ out.println(" !!! ERROR: class not found: " + className);
+ out.println(" exception: " + ex);
+ return ERROR;
+ }
+
+ try {
+ fields = new HashSet();
+ fields.addAll(Arrays.asList(classObject.getDeclaredFields()));
+ methods = new HashSet();
+ methods.addAll(Arrays.asList(classObject.getDeclaredMethods()));
+ } catch (SecurityException ex) {
+ affirm(false);
+ return ERROR;
+ }
+ return AFFIRMATIVE;
+ }
+
+ private int test(PrintWriter out,
+ String className)
+ throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+ {
+ affirm(className);
+ this.className = className;
+ this.classPath = className.replace('.', '/');
+
+
+ if (verbose) {
+ out.println("-------------------------------------------------------------------------------");
+ out.println();
+ out.println("Test class for augmentation: "
+ + className + " ...");
+ }
+
+ // check loading class
+ StringWriter s = new StringWriter();
+ if (testLoadingClass(new PrintWriter(s)) <= NEGATIVE) {
+ out.println();
+ out.println("!!! ERROR: failed loading class: " + className);
+ out.println(s.toString());
+ return ERROR;
+ }
+
+ if (verbose) {
+ out.println();
+ out.println("+++ loaded class: " + className);
+ out.println(s.toString());
+ }
+
+ // check augmentation
+ s = new StringWriter();
+ final int r = testAugmentation(new PrintWriter(s));
+ if (r < NEGATIVE) {
+ out.println();
+ out.println("!!! ERROR: incorrect augmentation: " + className);
+ out.println(s.toString());
+ return ERROR;
+ }
+
+ if (r == NEGATIVE) {
+ out.println();
+ out.println("--- class not augmented: " + className);
+ } else {
+ out.println();
+ out.println("+++ class augmented: " + className);
+ }
+ if (verbose) {
+ out.println(s.toString());
+ }
+
+ return r;
+ }
+
+ protected int test(PrintWriter out,
+ boolean verbose,
+ List classNames)
+ {
+ affirm(classNames);
+ this.verbose = verbose;
+ final int all = classNames.size();
+
+ out.println();
+ out.println("AugmentationTest: Testing Classes for JDO Persistence-Capability Enhancement");
+
+ int nofFailed = 0;
+ for (int i = 0; i < all; i++) {
+ if (test(out, (String)classNames.get(i)) < NEGATIVE) {
+ nofFailed++;
+ }
+ }
+ final int nofPassed = all - nofFailed;
+
+ out.println();
+ out.println("AugmentationTest: Summary: TESTED: " + all
+ + " PASSED: " + nofPassed
+ + " FAILED: " + nofFailed);
+ return nofFailed;
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Initializes all components.
+ */
+ protected void init()
+ throws EnhancerFatalError, EnhancerUserException
+ {
+ super.init();
+ if (!options.classFileNames.isEmpty()
+ || !options.archiveFileNames.isEmpty()) {
+ throw new EnhancerFatalError("Sorry, this test right now only support class name arguments, not class or archive files.");
+ }
+ affirm(classes != null);
+ try {
+ classLoader = classes.getClassLoader();
+ persistenceManagerClass
+ = classLoader.loadClass("javax.jdo.PersistenceManager");
+ instanceCallbacksClass
+ = classLoader.loadClass("javax.jdo.InstanceCallbacks");
+ persistenceCapableClass
+ = classLoader.loadClass("javax.jdo.spi.PersistenceCapable");
+ objectIdFieldSupplierClass
+ = classLoader.loadClass("javax.jdo.spi.PersistenceCapable$ObjectIdFieldSupplier");
+ objectIdFieldConsumerClass
+ = classLoader.loadClass("javax.jdo.spi.PersistenceCapable$ObjectIdFieldConsumer");
+ stateManagerClass
+ = classLoader.loadClass("javax.jdo.spi.StateManager");
+ } catch (Exception ex) {
+ throw new EnhancerFatalError(ex);
+ }
+ }
+
+ /**
+ * Run the augmentation test.
+ */
+ protected int process()
+ {
+ //^olsen: Unfortunately, this test cannot reasonably deal with
+ // java classfiles passed as command line arguments but only with
+ // archive files (.zip/.jar) or a source-path argument.
+ // For this restriction, the inherited parsing/checking of options
+ // and the usage-help needs to be overriden/corrected.
+ // --> BaseOptions.check(), printUsageHeader() ...
+
+ //^olsen: to be extended for zip/jar arguments
+ return test(out, options.verbose.value, options.classNames);
+ }
+
+ /**
+ * Runs this class
+ */
+ static public void main(String[] args)
+ {
+ final PrintWriter out = new PrintWriter(System.out, true);
+ out.println("--> AugmentationTest.main()");
+ final AugmentationTest main = new AugmentationTest(out, out);
+ int res = main.run(args);
+ out.println("<-- AugmentationTest.main(): exit = " + res);
+ System.exit(res);
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/CombinedResourceLocator.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/CombinedResourceLocator.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/CombinedResourceLocator.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/CombinedResourceLocator.java Sun May 22 10:55:51 2005
@@ -0,0 +1,69 @@
+/*
+ * 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.util;
+
+import java.util.List;
+import java.util.Iterator;
+
+import java.io.PrintWriter;
+import java.io.InputStream;
+
+
+
+/**
+ * Searches resources among a set of files.
+ */
+public class CombinedResourceLocator
+ extends ResourceLocatorBase
+ implements ResourceLocator
+{
+ /**
+ * List of resource locators.
+ */
+ final List locators;
+
+ /**
+ * Creates an intsance.
+ */
+ public CombinedResourceLocator(PrintWriter out,
+ boolean verbose,
+ List locators)
+ {
+ super(out, verbose);
+ affirm(locators != null);
+ this.locators = locators;
+ }
+
+ /**
+ * Finds a resource with a given name.
+ */
+ public InputStream getInputStreamForResource(String resourceName)
+ {
+ affirm(resourceName != null);
+
+ for (Iterator i = locators.iterator(); i.hasNext();) {
+ final ResourceLocator locator = (ResourceLocator)i.next();
+ affirm(locator != null);
+ final InputStream stream
+ = locator.getInputStreamForResource(resourceName);
+ if (stream != null) {
+ return stream;
+ }
+ }
+ return null;
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Disassembler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Disassembler.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Disassembler.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Disassembler.java Sun May 22 10:55:51 2005
@@ -0,0 +1,196 @@
+/*
+ * 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.util;
+
+import java.util.Iterator;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Stack;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileNotFoundException;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.apache.jdo.impl.enhancer.ClassArgMain;
+import org.apache.jdo.impl.enhancer.EnhancerFatalError;
+import org.apache.jdo.impl.enhancer.classfile.ClassFile;
+
+
+
+
+/**
+ * Utility class for testing two class files for equal augmentation.
+ *
+ * @author Martin Zaun
+ */
+public class Disassembler
+ extends ClassArgMain
+{
+ // return values of internal test methods
+ static public final int AFFIRMATIVE = 1;
+ static public final int NEGATIVE = 0;
+ static public final int ERROR = -1;
+
+ // ----------------------------------------------------------------------
+
+ private boolean verbose;
+
+ public Disassembler(PrintWriter out,
+ PrintWriter err)
+ {
+ super(out, err);
+ }
+
+ private int disassemble(PrintWriter out,
+ String className,
+ String classFileName)
+ {
+ affirm(className == null ^ classFileName == null);
+ final String name = (className != null ? className : classFileName);
+
+ DataInputStream dis = null;
+ try {
+ if (className != null) {
+ dis = new DataInputStream(openClassInputStream(className));
+ } else {
+ dis = new DataInputStream(openFileInputStream(classFileName));
+ }
+ final boolean allowJDK12ClassFiles = true;
+ final ClassFile classFile
+ = new ClassFile(dis, allowJDK12ClassFiles);
+ out.println(" +++ parsed class");
+
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ if (verbose) {
+ classFile.print(new PrintStream(b), 0);
+ out.println(b.toString());
+ }
+ out.println("Statistics:");
+ classFile.summarize(new PrintStream(b), 4);
+ out.println(b.toString());
+ } catch (ClassFormatError ex) {
+ out.println(" !!! ERROR: format error when parsing class: "
+ + name);
+ out.println(" error: " + err);
+ return ERROR;
+ } catch (IOException ex) {
+ out.println(" !!! ERROR: exception while reading class: "
+ + name);
+ out.println(" exception: " + ex);
+ return ERROR;
+ } finally {
+ closeInputStream(dis);
+ }
+
+ return AFFIRMATIVE;
+ }
+
+ protected int disassemble(PrintWriter out,
+ boolean verbose,
+ List classNames,
+ List classFileNames)
+ {
+ affirm(classNames);
+ affirm(classFileNames);
+ this.verbose = verbose;
+
+ out.println();
+ out.println("Disassembler: Dumps out the java byte-code for classes.");
+
+ int nofFailed = 0;
+ final int all = classNames.size() + classFileNames.size();
+ for (int i = 0; i < classNames.size(); i++) {
+ out.println("-------------------------------------------------------------------------------");
+ out.println();
+
+ // parse class
+ final String className = (String)classNames.get(i);
+ final StringWriter s = new StringWriter();
+ if (disassemble(new PrintWriter(s), className, null) < NEGATIVE) {
+ out.println();
+ out.println("!!! ERROR: failed disassembling class: "
+ + className);
+ out.println(s.toString());
+ nofFailed++;
+ }
+
+ out.println("+++ disassembled class: " + className);
+ out.println();
+ out.println(s.toString());
+ }
+ for (int i = 0; i < classFileNames.size(); i++) {
+ out.println("-------------------------------------------------------------------------------");
+ out.println();
+
+ // parse class
+ final String classFileName = (String)classFileNames.get(i);
+ final StringWriter s = new StringWriter();
+ if (disassemble(new PrintWriter(s), null, classFileName) < NEGATIVE) {
+ out.println();
+ out.println("!!! ERROR: failed disassembling class: "
+ + classFileName);
+ out.println(s.toString());
+ nofFailed++;
+ }
+
+ out.println("+++ disassembled class: " + classFileName);
+ out.println();
+ out.println(s.toString());
+ }
+ final int nofPassed = all - nofFailed;
+
+ out.println();
+ out.println("Disassembler: Summary: PROCESSED: " + all
+ + " PASSED: " + nofPassed
+ + " FAILED: " + nofFailed);
+ return nofFailed;
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Run the disassembler.
+ */
+ protected int process()
+ {
+ //^olsen: to be extended for zip/jar arguments
+ return disassemble(out, options.verbose.value,
+ options.classNames, options.classFileNames);
+ }
+
+ static public void main(String[] args)
+ {
+ final PrintWriter out = new PrintWriter(System.out, true);
+ out.println("--> Disassembler.main()");
+ final Disassembler main = new Disassembler(out, out);
+ int res = main.run(args);
+ out.println("<-- Disassembler.main(): exit = " + res);
+ System.exit(res);
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/InternalError.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/InternalError.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/InternalError.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/InternalError.java Sun May 22 10:55:51 2005
@@ -0,0 +1,31 @@
+/*
+ * 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.util;
+
+/**
+ * Support for signalling internal implementation errors.
+ */
+public class InternalError
+ extends RuntimeException {
+ public InternalError() {
+ }
+
+ public InternalError(String message) {
+ super(message);
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ListResourceLocator.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ListResourceLocator.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ListResourceLocator.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ListResourceLocator.java Sun May 22 10:55:51 2005
@@ -0,0 +1,119 @@
+/*
+ * 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.util;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Iterator;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.io.InputStream;
+import java.io.FileInputStream;
+
+import java.net.URL;
+
+
+/**
+ * Searches resources among a set of files.
+ */
+public class ListResourceLocator
+ extends ResourceLocatorBase
+ implements ResourceLocator
+{
+ /**
+ * The map of jdo files.
+ */
+ final Map files = new HashMap();
+
+ /**
+ * Creates an intsance.
+ */
+ public ListResourceLocator(PrintWriter out,
+ boolean verbose,
+ List fileNames)
+ throws IOException
+ {
+ super(out, verbose);
+ affirm(fileNames != null);
+
+ // hash the file objects by their canonical name
+ for (Iterator i = fileNames.iterator(); i.hasNext();) {
+ final String s = (String)i.next();
+
+ // canonicalize file name
+ final File file = new File(s).getCanonicalFile();
+ final URL url = file.toURL();
+ final String canonicalName = url.toString();
+ affirm(canonicalName != null);
+
+ // ensure file is readable
+ if (!file.canRead()) {
+ final String msg
+ = getI18N("enhancer.cannot_read_resource",
+ file.toString());
+ throw new IOException(msg);
+ }
+
+ // hash file by its canonicalized resource name
+ files.put(canonicalName, file);
+ printMessage(getI18N("enhancer.using_file",
+ canonicalName));
+ }
+ }
+
+ /**
+ * Finds a resource with a given name.
+ */
+ public InputStream getInputStreamForResource(String resourceName)
+ {
+ //printMessage("ListResourceLocator.getInputStreamForResource() : resourceName = " + resourceName);
+
+ affirm(resourceName != null);
+
+ final Set entries = files.entrySet();
+ for (Iterator i = entries.iterator(); i.hasNext();) {
+ final Map.Entry entry = (Map.Entry)i.next();
+ final String fileName = (String)entry.getKey();
+ if (!fileName.endsWith(resourceName)) {
+ continue;
+ }
+ final File file = (File)entry.getValue();
+
+ final InputStream stream;
+ try {
+ stream = new FileInputStream(file);
+ } catch (FileNotFoundException ex) {
+ // would be better to throw an IOException but currently
+ // not supported by the JDOModel's JavaModel interface
+ final String msg
+ = getI18N("enhancer.io_error_while_reading_resource",
+ file.toString(), ex.getMessage());
+ throw new RuntimeException(msg);
+ }
+ affirm(stream != null);
+ printMessage(getI18N("enhancer.found_resource", resourceName));
+ return stream;
+ }
+ printMessage(getI18N("enhancer.not_found_resource", resourceName));
+ return null;
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/PathResourceLocator.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/PathResourceLocator.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/PathResourceLocator.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/PathResourceLocator.java Sun May 22 10:55:51 2005
@@ -0,0 +1,137 @@
+/*
+ * 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.util;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.io.File;
+import java.io.InputStream;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * Searches resources within a path.
+ */
+public class PathResourceLocator
+ extends ResourceLocatorBase
+ implements ResourceLocator
+{
+ /**
+ * The class loader for loading jdo resources.
+ */
+ final private URLClassLoader classLoader;
+
+ /**
+ * Returns a classloader initialized on the path provided to constructor.
+ */
+ public URLClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ /**
+ * Creates an instance.
+ */
+ public PathResourceLocator(PrintWriter out,
+ boolean verbose,
+ String path)
+ throws IOException
+ {
+ super(out, verbose);
+ affirm(path != null);
+
+ // convert path into list of URLs
+ final List urls = new ArrayList();
+ for (Enumeration e = new StringTokenizer(path, File.pathSeparator);
+ e.hasMoreElements();) {
+ final String s = (String)e.nextElement();
+
+ // canonicalize file name
+ final File file = new File(s).getCanonicalFile();
+ final URL url = file.toURL();
+ final String canonicalName = url.toString();
+ affirm(canonicalName != null);
+
+ // ensure path element is readable
+ if (!file.canRead()) {
+ final String msg
+ = getI18N("enhancer.cannot_read_resource",
+ file.toString());
+ throw new IOException(msg);
+ }
+
+ // ensure path element is either directory or a jar/zip file
+ final String l = s.toLowerCase();
+ if (!(file.isDirectory()
+ || (file.isFile()
+ && (l.endsWith(".jar") || l.endsWith(".zip"))))) {
+ final String msg
+ = getI18N("enhancer.illegal_path_element",
+ file.toString());
+ throw new IOException(msg);
+ }
+
+ urls.add(url);
+ printMessage(getI18N("enhancer.using_path_element",
+ canonicalName));
+ }
+
+ // create class loader
+ final URL[] urlArray = (URL[])urls.toArray(new URL[urls.size()]);
+ classLoader = new URLClassLoader(urlArray, null);
+ affirm(classLoader != null);
+ }
+
+ /**
+ * Finds a resource with a given name.
+ */
+ public InputStream getInputStreamForResource(String resourceName)
+ {
+ //printMessage("PathResourceLocator.getInputStreamForResource() : resourceName = " + resourceName);
+
+ affirm(resourceName != null);
+
+ // not using getResourceAsStream() to catch IOExceptions
+ final URL url = classLoader.findResource(resourceName);
+ if (url == null) {
+ printMessage(getI18N("enhancer.not_found_resource", resourceName));
+ return null;
+ }
+
+ // return input stream
+ final InputStream stream;
+ try {
+ stream = url.openStream();
+ } catch (IOException ex) {
+ // would be better to throw an IOException but currently
+ // not supported by the JDOModel's JavaModel interface
+ final String msg
+ = getI18N("enhancer.io_error_while_reading_resource",
+ url.toString(), ex.getMessage());
+ throw new RuntimeException(msg);
+ }
+ affirm(stream != null);
+ printMessage(getI18N("enhancer.found_resource", resourceName));
+ return stream;
+ }
+}
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ResourceLocator.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ResourceLocator.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ResourceLocator.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/ResourceLocator.java Sun May 22 10:55:51 2005
@@ -0,0 +1,36 @@
+/*
+ * 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.util;
+
+import java.io.InputStream;
+
+
+/**
+ * Provides a method for searching resources.
+ */
+public interface ResourceLocator
+{
+ /**
+ * Finds a resource with a given name. This method returns
+ * <code>null</code> if no resource with this name is found.
+ * The name of a resource is a "/"-separated path name.
+ */
+ //^olsen: would be better to throw an IOException instead of a
+ // RuntimeException but currently not supported by the JDOModel's
+ // JavaModel interface
+ InputStream getInputStreamForResource(String resourceName);
+}