Package com.sun.jdo.spi.persistence.support.sqlstore.utility

Source Code of com.sun.jdo.spi.persistence.support.sqlstore.utility.AugmentationTest

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* AugmentationTest.java
*
* Create on April 19, 2001
*/

package com.sun.jdo.spi.persistence.support.sqlstore.utility;


import java.lang.reflect.*;
import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;

// note the use of the public vs. the internal interfaces by this class
import com.sun.jdo.api.persistence.support.PersistenceManager;
import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceCapable;
import com.sun.jdo.spi.persistence.support.sqlstore.StateManager;

/**
* Utility class for testing a class file for correct augmentation.
*/
public class AugmentationTest
{
    static boolean debug = false;
    static final PrintStream out = System.out;

    static final void affirm(boolean cond)
    {
        if (debug && !cond)
            throw new RuntimeException("affirmion failed.");
    }

    static final void affirm(Object obj)
    {
        if (debug && obj == null)
            throw new RuntimeException("affirmion failed: obj = null");
    }

    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();
    }

    public final int AFFIRMATIVE = 1;
    public final int NEGATIVE = 0;
    public final int ERROR = -1;

    boolean verbose;
    boolean requirePC;
    List classes;
    String className;
    Class classClass;

    public AugmentationTest()
    {}

    final void println()
    {
        out.println();
    }

    final void println(String msg)
    {
        out.println(msg);
    }

    final void verbose()
    {
        if (verbose)
            out.println();
    }

    final void verbose(String msg)
    {
        if (verbose)
            out.println(msg);
    }

    public int testLoadingClass()
    {
        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;
        }
    }

    int implementsInterface(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;
    }

    int hasField(int mods,
                 Class type,
                 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;
        }
    }

    int hasConstructor(int mods,
                       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;
        }
    }

    int hasMethod(int mods,
                  Class result,
                  String name,
                  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 int hasGenericAugmentation()
    {
        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;
    }

    public int hasSpecificAugmentation()
    {
        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;
    }

    static private final String[] transientPrefixes
        = {"java.",
           "javax.",
           "com.sun.jdo."};

    public int testPCFeasibility()
    {
        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;
    }

    public int testJdoConstructor()
    {
        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 int test(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 int test(boolean verbose,
                    boolean requirePC,
                    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;
    }


    /**
     * Prints usage message.
     */
    static void usage()
    {
        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();
    }

    static public void main(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);
    }
}
TOP

Related Classes of com.sun.jdo.spi.persistence.support.sqlstore.utility.AugmentationTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.