FileDocCategorySizeDatePackage
AugmentationTest.javaAPI DocGlassfish v2 API24773Fri May 04 22:34:58 BST 2007com.sun.jdo.api.persistence.support.util

AugmentationTest

public class AugmentationTest extends Object
Utility class for testing a class file for correct augmentation.

Fields Summary
static boolean
debug
static final PrintStream
out
public final int
AFFIRMATIVE
public final int
NEGATIVE
public final int
ERROR
boolean
verbose
boolean
requirePC
List
classes
String
className
Class
classClass
private static final String[]
transientPrefixes
Constructors Summary
public AugmentationTest()


     
    
Methods Summary
static final voidaffirm(boolean cond)


        
    
        if (debug && !cond)
            throw new RuntimeException("affirmion failed.");
    
static final voidaffirm(java.lang.Object obj)

        if (debug && obj == null)
            throw new RuntimeException("affirmion failed: obj = null");
    
inthasConstructor(int mods, java.lang.Class[] params)

        try {
            final Constructor ctor = classClass.getConstructor(params);

            if (ctor.getModifiers() != mods) {
                println("!!! ERROR: constructor declaration: ");
                println("    expected: " + toString(mods, className, params));
                println("    found:    " + ctor.toString());
                return ERROR;
            }

            verbose("+++ has constructor: " + ctor.toString());
            return AFFIRMATIVE;

        } catch (NoSuchMethodException ex) {
            verbose("--- no constructor: "
                    + toString(mods, className, params));
            return NEGATIVE;
        }
    
inthasField(int mods, java.lang.Class type, java.lang.String name)

        try {
            final Field field = classClass.getField(name);

            if (field.getModifiers() != mods
                || !field.getType().equals(type)) {
                println("!!! ERROR: field declaration: ");
                println("    expected: " + toString(mods, type, name));
                println("    found:    " + field.toString());
                return ERROR;
            }

            verbose("+++ has field: " + field.toString());
            return AFFIRMATIVE;

        } catch (NoSuchFieldException ex) {
            verbose("--- no field: " + toString(mods, type, name));
            return NEGATIVE;
        }
    
public inthasGenericAugmentation()

        affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);

        verbose();
        verbose("Check for \"generic\" augmentation ...");
        affirm(classClass);

        final int nofFeatures = 15;
        final int[] r = new int[nofFeatures];
        {
            int i = 0;
            r[i++] = implementsInterface(PersistenceCapable.class);

            r[i++] = hasField(Modifier.PUBLIC | Modifier.TRANSIENT,
                              StateManager.class,
                              "jdoStateManager");
            r[i++] = hasField(Modifier.PUBLIC | Modifier.TRANSIENT,
                              byte.class,
                              "jdoFlags");

            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               StateManager.class,
                               "jdoGetStateManager",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               void.class,
                               "jdoSetStateManager",
                               new Class[]{StateManager.class});

            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               byte.class,
                               "jdoGetFlags",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               void.class,
                               "jdoSetFlags",
                               new Class[]{byte.class});

            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               PersistenceManager.class,
                               "jdoGetPersistenceManager",
                               new Class[]{});

            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               Object.class,
                               "jdoGetObjectId",
                               new Class[]{});

            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               boolean.class,
                               "jdoIsDirty",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               boolean.class,
                               "jdoIsTransactional",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               boolean.class,
                               "jdoIsPersistent",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               boolean.class,
                               "jdoIsNew",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               boolean.class,
                               "jdoIsDeleted",
                               new Class[]{});

            r[i++] = hasMethod(Modifier.PUBLIC | Modifier.FINAL,
                               void.class,
                               "jdoMakeDirty",
                               new Class[]{String.class});
            affirm(i == nofFeatures);
        }

        int res = 0;
        for (int i = 0; i < nofFeatures; i ++) {
            final int j = r[i];
            affirm(ERROR <= j && j <= AFFIRMATIVE);

            if (j < res) {
                println("!!! ERROR: inconsistent \"generic\" augmentation of class: "
                      + className);
                return ERROR;
            }

            if (j > NEGATIVE)
                res = j;
        }

        if (res > NEGATIVE) {
            verbose("+++ has \"generic\" augmentation");
            return AFFIRMATIVE;
        }

        verbose("--- no \"generic\" augmentation");
        return NEGATIVE;
    
inthasMethod(int mods, java.lang.Class result, java.lang.String name, java.lang.Class[] params)

        try {
            final Method method = classClass.getMethod(name, params);

            if (method.getModifiers() != mods
                || !method.getReturnType().equals(result)) {
                println("!!! ERROR: method declaration: ");
                println("    expected: " + toString(mods, result, name, params));
                println("    found:    " + method.toString());
                return ERROR;
            }

            verbose("+++ has method: " + method.toString());
            return AFFIRMATIVE;

        } catch (NoSuchMethodException ex) {
            verbose("--- no method: "
                    + toString(mods, result, name, params));
            return NEGATIVE;
        }
    
public inthasSpecificAugmentation()

        affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);

        verbose();
        verbose("Check for \"class-specific\" augmentation ...");
        affirm(classClass);

        final int nofFeatures = 5;
        final int[] r = new int[nofFeatures];
        {
            int i = 0;
            r[i++] = hasConstructor(Modifier.PUBLIC,
                                    new Class[]{StateManager.class});
            r[i++] = hasMethod(Modifier.PUBLIC,
                               Object.class,
                               "jdoGetField",
                               new Class[]{int.class});
            r[i++] = hasMethod(Modifier.PUBLIC,
                               void.class,
                               "jdoSetField",
                               new Class[]{int.class, Object.class});

            r[i++] = hasMethod(Modifier.PUBLIC,
                               void.class,
                               "jdoClear",
                               new Class[]{});
            r[i++] = hasMethod(Modifier.PUBLIC,
                               Object.class,
                               "jdoNewInstance",
                               new Class[]{StateManager.class});
            affirm(i == nofFeatures);
        }

        //@olsen: todo
        // + clone()

        int res = 0;
        for (int i = 0; i < nofFeatures; i++) {
            final int j = r[i];
            affirm(ERROR <= j && j <= AFFIRMATIVE);

            if (j < res) {
                println("!!! ERROR: inconsistent \"class-specific\" augmentation of class: "
                      + className);
                return ERROR;
            }

            if (j > NEGATIVE)
                res = j;
        }

        if (res > NEGATIVE) {
            verbose("+++ has \"class-specific\" augmentation");
            return AFFIRMATIVE;
        }

        verbose("--- no \"class-specific\" augmentation");
        return NEGATIVE;
    
intimplementsInterface(java.lang.Class intf)

        final Class[] interfaces = classClass.getInterfaces();
        for (int i = interfaces.length - 1; i >= 0; i--) {
            if (interfaces[i].equals(intf)) {
                verbose("+++ implements interface: " + intf.getName());
                return AFFIRMATIVE;
            }
        }
        verbose("--- not implementing interface: " + intf.getName());
        return NEGATIVE;
    
public static voidmain(java.lang.String[] argv)

        // parse args
        boolean verbose = false;
        boolean requirePC = false;
        List classes = new ArrayList();
        for (int i = 0; i < argv.length; i++) {
            String arg = argv[i];
            if (arg.equals("-h") || arg.equals("--help")) {
                usage();
                return;
            }
            if (arg.equals("-v") || arg.equals("--verbose")) {
                verbose = true;
                continue;
            }
            if (arg.equals("-pc") || arg.equals("--requirePC")) {
                requirePC = true;
                continue;
            }
            if (arg.equals("--debug")) {
                debug = true;
                continue;
            }
            if (arg.startsWith("-")) {
                out.println();
                out.println("Unrecognized option: " + arg);
                usage();
                return;
            }
            classes.add(arg);
        }

        // check arguments
        if (classes.isEmpty()) {
            out.println();
            out.println("Missing classes argument");
            usage();
            return;
        }

        if (debug) {
            out.println("options:");
            out.println("    verbose = " + verbose);
            out.println("    requirePC = " + requirePC);
            out.print("    classes =");
            for (int i = 0; i < classes.size(); i++)
                out.print(" " + classes.get(i));
            out.println();
        }

        final AugmentationTest test = new AugmentationTest();
        final int r = test.test(verbose, requirePC, classes);
        System.exit(r);
    
final voidprintln()

        out.println();
    
final voidprintln(java.lang.String msg)

        out.println(msg);
    
public inttest(java.lang.String className)

        affirm(className);
        this.className = className;

        verbose();
        verbose("-------------------------------------------------------------------------------");
        verbose();
        verbose("Test class for augmentation: "
                + className + " ...");

        if (testLoadingClass() < AFFIRMATIVE) {
            return ERROR;
        }

        final int r0 = hasGenericAugmentation();
        final int r1 = hasSpecificAugmentation();

        if (r1 < NEGATIVE || r0 < NEGATIVE) {
            return ERROR;
        }
        affirm(r1 >= NEGATIVE && r0 >= NEGATIVE);

        if (r1 == NEGATIVE && r0 == NEGATIVE) {
            if (requirePC) {
                println();
                println("!!! ERROR: class not augmented: " + className);
                return ERROR;
            }

            println();
            println("--- not augmented: " + className);
            return NEGATIVE;
        }

        if (r0 == NEGATIVE) {
            println();
            println("!!! ERROR: class lacking \"generic\" augmentation: "
                    + className);
            return ERROR;
        }

        if (r1 == NEGATIVE) {
            println();
            println("!!! ERROR: class lacking \"class-specific\" augmentation: "
                    + className);
            return ERROR;
        }
        affirm(r1 > NEGATIVE && r0 > NEGATIVE);

        final int r2 = testPCFeasibility();
        if (r2 < AFFIRMATIVE) {
            return ERROR;
        }

        final int r3 = testJdoConstructor();
        if (r3 < AFFIRMATIVE) {
            return ERROR;
        }

        println();
        println("+++ augmented: " + className);
        return AFFIRMATIVE;
    
public inttest(boolean verbose, boolean requirePC, java.util.List classes)

        affirm(classes);
        this.verbose = verbose;
        this.requirePC = requirePC;

        final int all = classes.size();

        println();
        println("AugmentationTest: Testing classes for being enhanced for persistence-capability");

        int failed = 0;
        for (int i = 0; i < all; i++) {
            if (test((String)classes.get(i)) < NEGATIVE) {
                failed++;
            }
        }
        final int passed = all - failed;

        println();
        println("AugmentationTest: Summary:  TESTED: " + all
                + "  PASSED: " + passed
                + "  FAILED: " + failed);
        return failed;
    
public inttestJdoConstructor()

        verbose();
        verbose("Test JDO constructor ...");
        affirm(classClass);

        try {
            //verbose("get jdo constructor ...");
            final Class[] params = new Class[]{StateManager.class};
            final Constructor ctor = classClass.getConstructor(params);

            //verbose("create new instance by jdo constructor ...");
            final Object[] args = new Object[]{null};
            final Object instance = ctor.newInstance(args);

            //verbose("cast instance to PersistenceCapable ...");
            PersistenceCapable pc = (PersistenceCapable)instance;

            //verbose("check jdoStateManager ...");
            if (pc.jdoGetStateManager() != null) {
                println("!!! ERROR: invokation of JDO constructor:");
                println("    pc.jdoStateManager != null");
                println("!!! failed testing JDO constructor");
                return ERROR;
            }

            //verbose("check jdoFlags ...");
            if (pc.jdoGetFlags() != 1) {
                println("!!! ERROR: invokation of JDO constructor:");
                println("    pc.jdoFlags != 0");
                println("!!! failed testing JDO constructor");
                return ERROR;
            }
        } catch (NoSuchMethodException ex) {
            println("!!! ERROR: no JDO constructor");
            println("!!! failed testing JDO constructor");
            return ERROR;
        } catch (InstantiationException ex) {
            println("!!! ERROR: invokation of JDO constructor:");
            println("    exception: " + ex);
            println("!!! failed testing JDO constructor");
            return ERROR;
        } catch (IllegalAccessException ex) {
            println("!!! ERROR: invokation of JDO constructor:");
            println("    exception: " + ex);
            println("!!! failed testing JDO constructor");
            return ERROR;
        } catch (InvocationTargetException ex) {
            println("!!! ERROR: invokation of JDO constructor:");
            println("    exception: " + ex);
            println("    nested:    " + ex.getTargetException());
            println("!!! failed testing JDO constructor");
            return ERROR;
        }

        verbose("+++ tested JDO constructor");
        return AFFIRMATIVE;
    
public inttestLoadingClass()

        verbose();
        verbose("Test loading class: " + className + " ...");

        try {
            classClass = Class.forName(className);
            verbose("+++ loaded class");
            return AFFIRMATIVE;
        } catch (LinkageError err) {
            println("!!! ERROR: linkage error when loading class: "
                    + className);
            println("    error: " + err);
            println("!!! failed loading class");
            return ERROR;
        } catch (ClassNotFoundException ex) {
            println("!!! ERROR: class not found: " + className);
            println("    exception: " + ex);
            println("!!! failed loading class");
            return ERROR;
        }
    
public inttestPCFeasibility()


      
    
        verbose();
        verbose("Test feasibility of class: " + className + " ...");

        int status = AFFIRMATIVE;

        final int mods = classClass.getModifiers();

        if (classClass.isPrimitive()) {
            println("!!! ERROR: specified class is primitive type");
            status = ERROR;
        }

        if (classClass.isArray()) {
            println("!!! ERROR: specified class is array");
            status = ERROR;
        }

        if (classClass.isInterface()) {
            println("!!! ERROR: specified class is interface");
            status = ERROR;
        }

        if (Modifier.isAbstract(mods)) {
            println("!!! ERROR: specified class is abstract");
            status = ERROR;
        }

        if (!Modifier.isPublic(mods)) {
            println("!!! ERROR: specified class is not public");
            status = ERROR;
        }

        //if (classClass.getDeclaringClass() != null
        //    && !isStatic(classClass.getModifiers())) {
        if (classClass.getDeclaringClass() != null) {
            println("!!! ERROR: specified class is inner class");
            status = ERROR;
        }

        if (Throwable.class.isAssignableFrom(classClass)) {
            println("!!! ERROR: specified class extends Throwable");
            status = ERROR;
        }

        // check for transient package prefixes
        // precludes SCO types from lang.*, math.*, util.*, sql.*
        for (int i = 0; i < transientPrefixes.length; i++) {
            final String typePrefix = transientPrefixes[i];
            if (className.startsWith(typePrefix)) {
                println("!!! ERROR: specified class starts with package prefix: "
                      + typePrefix);
                status = ERROR;
            }
        }

        //verbose("get superclass ...");
        final Class superClass = classClass.getSuperclass();
        if (superClass == null) {
            println("!!! ERROR: specified class doesn't have super class");
            status = ERROR;
        } else {
            try {
                //verbose("get superclass' default constructor ...");
                final Class[] params = new Class[]{};
                Constructor sctor = superClass.getConstructor(params);
            } catch (NoSuchMethodException ex) {
                println("!!! ERROR: super class '" + superClass.getName()
                      + "' doesn't provide default constructor");
                status = ERROR;
            }
        }

        verbose(status == AFFIRMATIVE
                ? "+++ is feasible for persistence-capability"
                : "!!! not feasible for persistence-capability");
        return status;
    
static java.lang.StringtoString(int mods, java.lang.Class type, java.lang.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 java.lang.StringtoString(int mods, java.lang.String name, java.lang.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 java.lang.StringtoString(int mods, java.lang.Class result, java.lang.String name, java.lang.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 voidusage()
Prints usage message.

        out.println();
        out.println("Usage: AugmentationTest <options> <classes>...");
        out.println();
        out.println("This class tests if classes have been correctly enhanced");
        out.println("for persistence-capability (\"augmented\").");
        out.println();
        out.println("Options include:");
        out.println("    -h, --help        print usage");
        out.println("    -v, --verbose     enable verbose output");
        out.println("    -pc, --requirePC  require all classes to be augmented");
        out.println();
        out.println("A non-zero value is returned in case of any errors.");
        out.println();
    
final voidverbose(java.lang.String msg)

        if (verbose)
            out.println(msg);
    
final voidverbose()

        if (verbose)
            out.println();