/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. 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.html
 * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [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.
 */
package com.sun.enterprise.tools.verifier.tests.ejb;

import com.sun.enterprise.tools.verifier.tests.ejb.EjbTest;
import java.lang.reflect.*;
import java.util.*;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.MethodDescriptor;
import com.sun.enterprise.tools.verifier.*;
import java.lang.ClassLoader;
import com.sun.enterprise.tools.verifier.tests.ejb.EjbCheck;

/** 
 * Interface, parameters, return type, and exceptions checked for RMI-IIOP 
 *  compliance test.
 * 
 */
public class RmiIIOPUtils { 



    /** 
     * Interface checked for RMI-IIOP compliance test.
     * Verify the following:
     *
     *   The remote interface is allowed to have superinterfaces. Use of interface
     *   inheritance is subject to the RMI-IIOP rules for the definition of remote
     *   interfaces.
     * 
     *  Verify the following:
     *
     *  An RMI remote interface defines a Java interface that can be invoked 
     *  remotely. A Java interface is a conforming RMI/IDL remote interface if: 
     *
     *  1. The interface is or inherits from java.rmi.Remote either directly or 
     *     indirectly. 
     * 
     *  2. All methods in the interface are defined to throw 
     *     java.rmi.RemoteException or a superclass of java.rmi.RemoteException. 
     *     Throughout this section, references to methods in the interface include 
     *     methods in any inherited interfaces. 
     *
     *  3. Method arguments and results may be of any types. However at run-time, 
     *     the actual values passed as arguments or returned as results must be 
     *     conforming RMI/IDL types (see "Overview of Conforming RMI/IDL Types" on 
     *     page 28-2). In addition, for each RMI/IDL remote interface reference, 
     *     the actual value passed or returned must be either a stub object or a 
     *     remote interface implementation object (see "Stubs and remote 
     *     implementation classes" on page 28-4). 
     *
     *  4. All checked exception classes used in method declarations (other than 
     *     java.rmi.RemoteException and its subclasses) are conforming RMI/IDL 
     *     exception types (see "RMI/IDL Exception Types" on page 28-5)1 
     *
     *  5. Method names may be overloaded. However, when an interface directly 
     *     inherits from several base interfaces, it is forbidden for there to be 
     *     method name conflicts between the inherited interfaces. This outlaws the
     *     case where an interface A defines a method "foo," an interface B also 
     *     defines a method "foo," and an interface C tries to inherit from both A 
     *     and B. 
     *
     *  6. Constant definitions in the form of interface variables are permitted. 
     *     The constant value must be a compile-time constant of one of the RMI/IDL
     *     primitive types or String. 
     *
     *  7. Method and constant names must not cause name collisions when mapped to 
     *     IDL (see "Names that would cause OMG IDL name collisions" on page 28-9). 
     *
     *     The following is an example of a conforming RMI/IDL interface definition:
     *        // Java 
     *        public interface Wombat extends java.rmi.Remote { 
     *          String BLEAT_CONSTANT = "bleat"; 
     *          boolean bleat(Wombat other) throws java.rmi.RemoteException; 
     *        }
     *
     *     While the following is an example of a non-conforming RMI/IDL interface:
     *        // Java 
     *        // IllegalInterface fails to extend Remote!! 
     *        public interface IllegalInterface { 
     *          // illegalExceptions fails to throw RemoteException. 
     *          void illegalExceptions(); 
     *        }
     *
     * @param RMIIIOPinterface the Interface to be checked for Rmi-IIOP compliance
     *
     * @return <code>boolean</code> true if RMIIIOPinterface is valid RMIIIOP interface, false otherwise
     */
    public static boolean isValidRmiIIOPInterface(Class RMIIIOPinterface) {

	// 1. The interface is or inherits from java.rmi.Remote either directly or
	//     indirectly.
	boolean validInterface = false;                     
	Class c = RMIIIOPinterface;
	// walk up the class tree
	do {
	    if (RMIIIOPinterface.getName().equals("java.rmi.Remote")) {
		validInterface = true;
		break;
	    } else {
		// walk up the class tree of the interface and see if it
		// inherits from java.rmi.Remote either directly or indirectly.
		Class[] interfaces = RMIIIOPinterface.getInterfaces();
		//Class interfaces = RMIIIOPinterface.getSuperclass();
		for (int i = 0; i < interfaces.length; i++) {

		    //if (interfaces[i].getName().equals("java.rmi.Remote")) {
		    if ((interfaces[i].getName().equals("java.rmi.Remote")) ||
			//hack until i can ask hans why loop doesn't continue up past
			// javax.ejb.EJBHome
			(interfaces[i].getName().equals("javax.ejb.EJBObject")) ||
			(interfaces[i].getName().equals("javax.ejb.EJBHome"))) {
			validInterface = true;
			break;
		    }
		    else if (isValidRmiIIOPInterface(interfaces[i])) {
			return true;
		    }
		}
	    }
	} while ((((RMIIIOPinterface=RMIIIOPinterface.getSuperclass()) != null) && (!validInterface)));
     
        if (validInterface) {
            return true;
        } else {
            return false;
        }
    }





    /**
     * Interface checked for RMI-IIOP compliance test.
     *
     * @param RMIIIOPinterface the Interface to be checked for Rmi-IIOP compliance
     *
     * @return <code>boolean</code> true if RMIIIOPinterface is valid RMIIIOP interface, false otherwise
     */
    public static boolean isValidRmiIIOPInterfaceMethods(Class RMIIIOPinterface) {

        Class c = RMIIIOPinterface;
	    // continue on and check next condition

	    // All methods in the interface are defined to throw
	    // java.rmi.RemoteException or a superclass of java.rmi.RemoteException.
	    // Throughout this section, references to methods in the interface include
	    // methods in any inherited interfaces.
            try {
	        Method methods[] = c.getDeclaredMethods();
	        Class [] methodExceptionTypes;
	        for (int i=0; i< methods.length; i++) {
		    // The methods exceptions types must be legal types for
		    // RMI-IIOP.  This means that their exception values must
		    // throw java.rmi.RemoteException
		    methodExceptionTypes = methods[i].getExceptionTypes();
		    if (!EjbUtils.isValidRemoteException(methodExceptionTypes)) {
       		        return false;
		    } else { 
		        continue; 
		    }
		}
 
	    // made it throw all methods thowing java.rmi.RemoteException check,
	    // without returning false, continue on...

	    // Method arguments and results may be of any types. However at run-time,
	    // the actual values passed as arguments or returned as results must be
	    // conforming RMI/IDL types (see "Overview of Conforming RMI/IDL Types" on
	    // page 28-2). 
	    // can't check anything here, since this is a run-time check

	    // All checked exception classes used in method declarations (other than
	    // java.rmi.RemoteException and its subclasses) are conforming RMI/IDL
	    // exception types (see "RMI/IDL Exception Types" on page 28-5)1
	    for (int i=0; i < methods.length; i++) {
		    methodExceptionTypes = methods[i].getExceptionTypes();
		    if (!isValidRmiIIOPException(methodExceptionTypes)) {
			return false;
		    } else { 
			continue; 
		    }
		}
      
	    // Method names may be overloaded. However, when an interface directly
	    //inherits from several base interfaces, it is forbidden for there to be
	    //method name conflicts between the inherited interfaces. This outlaws the
	    //case where an interface A defines a method "foo," an interface B also
	    //defines a method "foo," and an interface C tries to inherit from both A
	    //and B.
	    // can't check anything here, since this is check cannot be determined
	    // thru reflection api checking

	    // Constant definitions in the form of interface variables are permitted.
	    //The constant value must be a compile-time constant of one of the RMI/IDL
	    // primitive types or String.
    
	    Field fields[] = c.getFields();
	    for (int i=0; i< fields.length; i++) {
		    // The fields types must be a compile-time constant of one of the 
		    // RMI/IDL primitive types or String
		    if (!(isValidRmiIIOPField(fields[i]))) {
			return false;
		    } else { 
			continue; 
		    }
		}
 
	    // Method and constant names must not cause name collisions when mapped to
	    // IDL (see "Names that would cause OMG IDL name collisions" on page 28-9)
	    // can't check anything here, since this is an non-exhaustive search and
	    // compare, don't know all the various combinations that would cause
	    // name collisions, 
            } catch (Throwable t) {
                Verifier.debug(t);
                return false;
            }
     return true;
    } 

    /**
     * Method parameters checked for RMI-IIOP compliance test.
     * Verify the following:
     *
     *   The home/remote interface methods arguments types must be legal types for
     *   RMI-IIOP.  This includes primitives, value types, and interfaces.  This 
     *   means that their arguments must be of valid types for RMI-IIOP.
     *
     *   28.2.4 RMI/IDL Value Types 
     *    An RMI/IDL value type represents a class whose values can be moved 
     *    between systems. So rather than transmitting a reference between systems,
     *    the actual state of the object is transmitted between systems. This 
     *    requires that the receiving system have an analogous class that can be 
     *    used to hold the received value. Value types may be passed as arguments 
     *    or results of remote methods, or as fields within other objects that are 
     *    passed remotely. A Java class is a conforming RMI/IDL value type if the 
     *    following applies: 
     *  
     *      1. The class must implement the java.io.Serializable interface, either 
     *         directly or indirectly, and must be serializable at run-time. It may
     *         serialize references to other RMI/IDL types, including value types 
     *         and remote interfaces. 
     *      2. The class may implement java.io.Externalizable. (This indicates it 
     *         overrides some of the standard serialization machinery.) 
     *      3. If the class is a non-static inner class, then its containing class 
     *         must also be a conforming RMI/IDL value type. 
     *      4. A value type must not either directly or indirectly implement the 
     *         java.rmi.Remote interface. (If this were allowed, then there would 
     *         be potential confusion between value types and remote interface 
     *         references.) 
     *      5. A value type may implement any interface except for java.rmi.Remote.
     *      6. There are no restrictions on the method signatures for a value type.
     *      7. There are no restrictions on static fields for a value type. 
     *      8. There are no restrictions on transient fields for a value type. 
     *      9. Method, constant and field names must not cause name collisions when
     *         mapped to IDL (see "Names that would cause OMG IDL name collisions" 
     *         on page 28-9). 
     *         
     *         Here is an example of a conforming RMI/IDL value type: 
     *           // Java 
     *           public class Point implements java.io.Serializable { 
     *             public final static int CONSTANT_FOO = 3+3; 
     *             private int x; 
     *             private int y; 
     *             public Point(int x, y) { ... } 
     *             public int getX() { ... } 
     *             public int getY() { ... } 
     *           } 
     *  
     *     28.2.4.1 The Java String Type 
     *     The java.lang.String class is a conforming RMI/IDL value type following 
     *     these rules. Note, however, that String is handled specially when mapping
     *     Java to OMG IDL (see "Mapping for java.lang.String" on page 28-18).
     *
     * @param RMIIIOPparams the params to be checked for Rmi-IIOP compliance
     *
     * @return <code>boolean</code> true if RMIIIOPParams are valid RMIIIOP parameters, false otherwise
     */
    public static boolean isValidRmiIIOPParameters(Class [] RMIIIOPparams) {
	if (RMIIIOPparams.length > 0) {
	    for (int ii = 0; ii < RMIIIOPparams.length; ii++) {
		Class c = RMIIIOPparams[ii];

		// if it's not a primitve, or
		// if it's not a valid rmi-idl type, or
		// if it's not java.lang.String, return false
		if (!(isValidRmiIDLPrimitiveType(c)) &&
		    !(isValidRmiIIOPValueType(c)) &&
		    !(isValidRmiIIOPInterfaceType(c)) &&
		    !(isJavaLangStringType(c)) &&
		    !(isValidRmiIIOPException(RMIIIOPparams)) &&
		    !(c.getName().equals("java.lang.Object")) &&
		    !(isValidRmiIIOPCORBAObjectType(c)) &&
		    !(isValidRmiIIOPIDLEntityType(c))) {
		    //exception,corba object,array,idl entity type
		    return false;
		}
	    }
	    // if you made it thru loop without returning false, then you 
	    // passed the tests, return true
	    return true;
	} else {
	    return true;
	}
    }


    /** 
     * Class checked for RMI-IIOP value type compliance test.
     * Verify the following:
     *
     *   This class is proper CORBA Object type.
     *
     * @param RMIIIOPvaluetype the class to be checked 
     *
     * @return <code>boolean</code> true if RMIIIOPvaluetype is valid Rmi-IIOP value type, false otherwise
     */
    public static boolean isValidRmiIIOPCORBAObjectType(Class RMIIIOPvaluetype) {

	Class c = RMIIIOPvaluetype;
	boolean validInterface = false;

	do {
	    Class[] interfaces = c.getInterfaces();
	    for (int i = 0; i < interfaces.length; i++) {
		if (interfaces[i].getName().equals("org.omg.CORBA.Object")) {
		    validInterface = true;
		    break;
		} else {
		    // walk up the class tree of the interface and see if it
		    // implements org.omg.CORBA.Object
		    Class superClass = interfaces[i];
		    do {
			if (superClass.getName().equals("org.omg.CORBA.Object")) {
			    validInterface = true;
			    break;
			}
		    } while ((((superClass=superClass.getSuperclass()) != null) && (!validInterface)));
		}
	    }
	} while ((((c=c.getSuperclass()) != null) && (!validInterface)));
	if (!validInterface) {
	    return false;
	} else {
	    return true;
	}
    }

  /** 
     * Class checked for RMI-IIOP value type compliance test.
     * Verify the following:
     *
     *   This class is proper Java IDL Entity type.
     *
     * @param RMIIIOPvaluetype the class to be checked 
     *
     * @return <code>boolean</code> true if RMIIIOPvaluetype is valid Rmi-IIOP value type, false otherwise
     */
    public static boolean isValidRmiIIOPIDLEntityType(Class RMIIIOPvaluetype) {

	Class c = RMIIIOPvaluetype;
	boolean validInterface = false;

	do {
	    Class[] interfaces = c.getInterfaces();
	    for (int i = 0; i < interfaces.length; i++) {
		if (interfaces[i].getName().equals("org.omg.CORBA.portable.IDLEntity")) {
		    validInterface = true;
		    break;
		} else {
		    // walk up the class tree of the interface and see if it
		    // implements java.io.Serializable
		    Class superClass = interfaces[i];
		    do {
			if (superClass.getName().equals("org.omg.CORBA.portable.IDLEntity")) {
			    validInterface = true;
			    break;
			}
		    } while ((((superClass=superClass.getSuperclass()) != null) && (!validInterface)));
		}
	    }
	} while ((((c=c.getSuperclass()) != null) && (!validInterface)));
	if (!validInterface) {
	    return false;
	} else {
	    return true;
	}
    }

    /** 
     * Class checked for RMI-IIOP value type compliance test.
     * Verify the following:
     *
     *   This class s proper value types.
     *
     * @param RMIIIOPvaluetype the class to be checked for Rmi-IIOP value type
     *        compliance
     *
     * @return <code>boolean</code> true if RMIIIOPvaluetype is valid Rmi-IIOP value type, false otherwise
     */
    public static boolean isValidRmiIIOPValueType(Class RMIIIOPvaluetype) {

	Class c = RMIIIOPvaluetype;
	boolean validInterface = false;
	boolean badOne = false;
	// The class must implement the java.io.Serializable interface, either
	// directly or indirectly, and must be serializable at run-time. It may
	// serialize references to other RMI/IDL types, including value types
	// and remote interfaces.
	// walk up the class tree
	if (c.getName().equals("java.lang.Object")) {
	    //validInterface = true;
            return true;
	}
        /* Buggy Code
	do {
	    Class[] interfaces = c.getInterfaces();
	    for (int i = 0; i < interfaces.length; i++) {
		if (interfaces[i].getName().equals("java.io.Serializable")) {
		    validInterface = true;
		    break;
		} else {
		    // walk up the class tree of the interface and see if it
		    // implements java.io.Serializable
		    Class superClass = interfaces[i];
		    do {
			if (superClass.getName().equals("java.io.Serializable")) {
			    validInterface = true;
			    break;
			}
		    } while ((((superClass=superClass.getSuperclass()) != null) && (validInterface == false)));
		}
	    }
	} while ((((c=c.getSuperclass()) != null) && (validInterface == false)));
        */
        validInterface = java.io.Serializable.class.isAssignableFrom(c);

	if (validInterface == false) {
	    return false;
	} else {
	    // 2. The class may implement java.io.Externalizable. (This indicates it
	    // overrides some of the standard serialization machinery.)
	    // nothing to check for here, since the keyword is "may implement"
 

	    //  3. If the class is a non-static inner class, then its containing class
	    //         must also be a conforming RMI/IDL value type.
	    // don't know if this can be checked statically

	    // reset class c since it may have gotten moved in the above do/while loop
            /* Buggy Code
	    c = RMIIIOPvaluetype;

	    do {
		Class[] interfaces = c.getInterfaces();
		for (int i = 0; i < interfaces.length; i++) {
		    if (interfaces[i].getName().equals("java.rmi.Remote")) {
			badOne = true;
			break;
		    }
		}
	    } while ((((c=c.getSuperclass()) != null) && (!badOne)));
            */

            badOne = java.rmi.Remote.class.isAssignableFrom(c);

	    if (badOne) {
		return false;
	    }
  
	    // 5. A value type may implement any interface except for java.rmi.Remote.
	    // already checked this in step #4 above

	    // 6. There are no restrictions on the method signatures for a value type.
	    // 7. There are no restrictions on static fields for a value type.
	    // 8. There are no restrictions on transient fields for a value type.
	    // no checking need be done for these 6, 7, & 8

	    // 9. Method, constant and field names must not cause name collisions when
	    // mapped to IDL (see "Names that would cause OMG IDL name collisions"
	    // on page 28-9).
	    // can't check anything here, since this is an non-exhaustive search and
	    // compare, don't know all the various combinations that would cause
	    // name collisions, ask hans to be sure

	}
	if (validInterface) {
	    return true;
	} else {
	    return false;
	}
    }


    /** 
     * Constant definitions in the form of interface variables are permitted test.
     * The constant value must be a compile-time constant of one of the RMI/IDL 
     * primitive types or String.
     *
     * Verify the following:
     *
     *   The home/remote interface field types must be legal types for
     *   RMI-IIOP.  
     *   This means that the constant value must be a compile-time constant 
     *   of one of the RMI/IDL primitive types or String.
     *
     * @param RMIIIOPField the field to be checked for Rmi-IIOP compile-time 
     *        constant of one of the RMI/IDL primitive types or String
     *
     * @return <code>boolean</code> true if RMIIIOPField is valid Rmi-IIOP type, false otherwise
     */
    public static boolean isValidRmiIIOPField(Field RMIIIOPField) {
	boolean validPrimitiveType = false;
	if ((isValidRmiIDLPrimitiveType(RMIIIOPField)) ||
	    (RMIIIOPField.getType().equals(java.lang.String.class))) {
	    validPrimitiveType = true;
	}
	return validPrimitiveType;
    }



    /** 
     * Constant definitions in the form of interface variables are permitted test.
     * The constant value must be a compile-time constant of one of the RMI/IDL 
     * primitive types .
     *
     * Verify the following:
     *
     *   The home/remote interface field types must be legal types for
     *   RMI-IIOP.  
     *   This means that the constant value must be a compile-time constant 
     *   of one of the RMI/IDL primitive types .
     *
     * @param RMIIIOPField the field to be checked for Rmi-IIOP compile-time 
     *        constant of one of the RMI/IDL primitive types or String
     *
     * @return <code>boolean</code> true if RMIIIOPField is valid  compile-time constant of
     *                              one of the RMI/IDL primitive types, false otherwise
     */
    public static boolean isValidRmiIDLPrimitiveType(Field RMIIIOPField) {
	boolean validPrimitiveType = false;
	if ((RMIIIOPField.getType().getName().equals("void")) ||
	    (RMIIIOPField.getType().getName().equals("boolean")) ||
	    (RMIIIOPField.getType().getName().equals("byte")) ||
	    (RMIIIOPField.getType().getName().equals("char")) ||
	    (RMIIIOPField.getType().getName().equals("short")) ||
	    (RMIIIOPField.getType().getName().equals("int")) ||
	    (RMIIIOPField.getType().getName().equals("long")) ||
	    (RMIIIOPField.getType().getName().equals("float")) ||
	    (RMIIIOPField.getType().getName().equals("double")))  {
	    validPrimitiveType = true;
	}
	return validPrimitiveType;
    }


    /** Class is interface test.
     *  The class value must be a java interface type .
     *
     * Verify the following:
     *
     *   The home/remote interface method params types must be legal types for
     *   RMI-IIOP.  
     *  The class value must be a java interface type .
     *
     * @param interfaceClass the class to be checked for java interface class
     *
     * @return <code>boolean</code> true if interfaceClass is legal types for
     *                              RMI-IIOP.  false otherwise
     */
    private static boolean isValidRmiIIOPInterfaceType(Class interfaceClass) {
	if (interfaceClass.isInterface()) {
	    return true;
	} else {
	    return false;
	}
    }


    /** Class is primitve test.
     *  The class value must be a java primitive type .
     *
     * Verify the following:
     *
     *   The home/remote interface method params types must be legal types for
     *   RMI-IIOP.  
     *  The class value must be a java primitive type .
     *
     * @param primitiveClass the class to be checked for java primitive class
     *
     * @return <code>boolean</code> true if primitiveClass is legal Java primitive type, false otherwise
     */
    public static boolean isValidRmiIDLPrimitiveType(Class primitiveClass) {
	boolean validPrimitiveType = false;
	if ((primitiveClass.getName().equals("void")) ||
	    (primitiveClass.getName().equals("boolean")) ||
	    (primitiveClass.getName().equals("byte")) ||
	    (primitiveClass.getName().equals("char")) ||
	    (primitiveClass.getName().equals("short")) ||
	    (primitiveClass.getName().equals("int")) ||
	    (primitiveClass.getName().equals("long")) ||
	    (primitiveClass.getName().equals("float")) ||
	    (primitiveClass.getName().equals("double")))  {
	    validPrimitiveType = true;
	}
	return validPrimitiveType;
    }


    /** 
     * Class is java.lang.String test.
     * The class value may be java.lang.String type .
     *
     * Verify the following:
     *
     *   The home/remote interface method params types must be legal types for
     *   RMI-IIOP.  
     *   The class value may be java.lang.String type .
     *
     * @param jlsClass the class to be checked for java primitive class
     *
     * @return <code>boolean</code> true if jlsClass is java.lang.String type, false otherwise
     */
    public static boolean isJavaLangStringType(Class jlsClass) { 
	boolean validJlsType = false;
	if (jlsClass.getName().equals("java.lang.String")) {
	    validJlsType = true;
	}
	return validJlsType;
    }

    /** 
     * Method exception checked for RMI-IIOP compliance test.
     * Verify the following:
     *
     *   The home/remote interface methods exception types must be legal types for
     *   RMI-IIOP.  This includes primitives, value types, and interfaces.
     *   This means that their exception must throw java.rmi.RemoteException.
     *
     *   28.2.6 RMI/IDL Exception Types An RMI/IDL exception type is a checked 
     *   exception class (as defined by the Java Language Specification). Since 
     *   checked exception classes extend java.lang.Throwable which implements 
     *   java.io.Serializable, it is unnecessary for an RMI/IDL exception class to 
     *   directly implement java.io.Serializable. A type is a conforming RMI/IDL 
     *   exception if the class:
     *     - is a checked exception class. 
     *     - meets the requirements for RMI/IDL value types defined in 
     *       "RMI/IDL Value Types" on page 28-4.
     *
     * @param RMIIIOPexceptions the exceptions to be checked for Rmi-IIOP throws
     *        java.rmi.RemoteException 
     *
     * @return <code>boolean</code> true if RMIIIOPexceptions are legal type for RMI-IIOP, false otherwise
     */
    public static boolean isValidRmiIIOPException(Class [] RMIIIOPexceptions) {
	// methods must throw java.rmi.RemoteException
	boolean throwsRemoteException = false;
	for (int kk = 0; kk < RMIIIOPexceptions.length; ++kk) {
	    if ((RMIIIOPexceptions[kk].getName().equals("java.rmi.RemoteException")) ||
		(RMIIIOPexceptions[kk].getName().equals("RemoteException"))) {
		throwsRemoteException = true;
		break;
	    }
	}
	return throwsRemoteException;
    }

    /**
     * Method return type checked for RMI-IIOP compliance test.
     * Verify the following:
     *
     *   The home/remote interface methods return type must be legal types for
     *   RMI-IIOP.  This includes primitives, value types, and interfaces.
     *   This means that their return type must be of valid types for RMI-IIOP.
     *
     * @param RMIIIOPparams the return type to be checked for Rmi-IIOP compliance
     *
     * @return <code>boolean</code> true if RMIIIOPReturnType is legal type for RMI-IIOP, false otherwise
     */
    public static boolean isValidRmiIIOPReturnType(Class RMIIIOPReturnType) {
	// if it's not a primitve, or
	// if it's not a valid rmi-idl type, or
	// if it's not java.lang.String, return false
	if (!((isValidRmiIDLPrimitiveType(RMIIIOPReturnType)) ||
	      (isValidRmiIIOPValueType(RMIIIOPReturnType)) ||
	      (isValidRmiIIOPInterfaceType(RMIIIOPReturnType)) ||
	      (isJavaLangStringType(RMIIIOPReturnType)) ||
	      //(isValidRmiIIOPException(RMIIIOPparams)) ||
	      (isValidRmiIIOPCORBAObjectType(RMIIIOPReturnType)) ||
	      (RMIIIOPReturnType.getName().equals("java.lang.Object")) ||
	      (isValidRmiIIOPIDLEntityType(RMIIIOPReturnType)))) {
	    return false;
	} else {
	    return true;
	}
    }


    /** 
     * Class checked for Serializable value type compliance test.
     * Verify the following:
     *
     *   This class is a serializable class.
     *
     * @param serializableClass the class to be checked for serializable
     *        compliance
     *
     * @return <code>boolean</code> true if c is a serializable class, false otherwise
     */
    public static boolean isValidSerializableType(Class c) {

       return java.io.Serializable.class.isAssignableFrom(c);

       /* Buggy Code
	boolean validInterface = false;

	if (c.getName().equals("java.io.Serializable")) {
	    validInterface = true;
	    return validInterface;	    
	}
	do {
	    Class[] interfaces = c.getInterfaces();
	    for (int i = 0; i < interfaces.length; i++) {
		if (interfaces[i].getName().equals("java.io.Serializable")) {
		    validInterface = true;
		    break;
		} else {
		    // walk up the class tree of the interface and see if it
		    // implements java.io.Serializable
		    Class superClass = interfaces[i];
		    do {
			if (superClass.getName().equals("java.io.Serializable")) {
			    validInterface = true;
			    break;
			}
		    } while ((((superClass=superClass.getSuperclass()) != null) && (!validInterface)));
		}
	    }
	} while ((((c=c.getSuperclass()) != null) && (!validInterface)));

	// The class must implement the java.io.Serializable interface, either
	// directly or indirectly, and must be serializable at run-time. 
	// walk up the class tree

	if (!validInterface) {
	    return false;
	} else {
	    return true;
	}
        */
    }


    /**
     * Container managed fields checked for one of the following: 
     * Java primitive types, Java serializable types, or references to 
     * enterprise beans' remote or home interfaces.
     *
     * Verify the following:
     *
     * Container managed fields checked for one of the following: 
     * Java primitive types, Java serializable types, or references to 
     * enterprise beans' remote or home interfaces.
     *
     * All the standard Java primitive types are supported as part of RMI/IDL. 
     *  These are:  void, boolean, byte, char, short, int, long, float, double
     *
     * @param CmpField params to be checked for CmpField valid type compliance
     * @param HomeClass home class
     * @param RemoteClass remote class
     *
     * @return <code>boolean</code> true if CmpField is Java primitive type,
     *                              Java serializable types, or references to
     *                              enterprise beans' remote or home interfaces.,
     *                              false otherwise
     */
    public static boolean isPersistentFieldTypeValid(Class CmpField, String HomeClass, String RemoteClass) {
	// if Java primitive types, Java serializable types, or references to 
	// enterprise beans' remote or home interfaces.
	if (!((isValidRmiIDLPrimitiveType(CmpField)) ||
	      (isValidSerializableType(CmpField)) ||
	      (CmpField.getName().equals(HomeClass)) ||
	      (CmpField.getName().equals(RemoteClass)))) {
	    return false;
	} else {
	    return true;
	}

    }


    /**
     * The ejbFind<METHOD> exceptions of Bean clas smust be a subset of the names
     * of the exceptions defined in the throws clause of the matching find method
     * of the home interface.  
     *
     * Verify the following:
     *
     * All the exceptions defined in the throws clause of the
     * matching ejbFind method of the
     * enterprise Bean class must be included in the throws
     * clause of the matching find method of the home interface
     * this home interface find method must define a superset of all the
     * exceptions thrown in the ejbFind method of the bean class                    
     * so there may not be a 1-1 mapping of exceptions
     * also, for all ejbFind/find combo's any unchecked
     * exceptions thrown by the ejbFind<METHOD> in the bean
     * class doesn't need to be thrown in the corresponding
     * find<METHOD> of the home interface , these unchecked
     * exceptions "subclass of RuntimeException" i.e
     * out of memory exception are handled by the container,
     * who throws a Runtime exception to the appropriate
     * instance/object
     *
     * @param ejbFindExceptions the ejbFind<METHOD> exceptions to be checked for 
     *        containment within the names of the exceptions defined in the throws 
     *        clause of the matching find method of the home interface (i.e subset)
     * @param findExceptions the find<METHOD> exceptions to be checked for 
     *        containing the names of the exceptions defined in the throws 
     *        clause of the matching ejbFind<METHOD> method of the bean class
     *        (i.e. superset)
     *
     * @return <code>boolean</code> true if ejbFindExceptions is subset of findExceptions,
     *                              false otherwise
     */
    public static boolean isEjbFindMethodExceptionsSubsetOfFindMethodExceptions
	(Class [] ejbFindExceptions, Class [] findExceptions) {
	boolean oneFailed = false;
	if (Arrays.equals(ejbFindExceptions,findExceptions)) {
	    return true;
	} else {
	    // manipulate as list, and use list.contains() method
	    List ejbFindList = Arrays.asList(ejbFindExceptions);
	    List findList = Arrays.asList(findExceptions);
	    if (!ejbFindList.isEmpty()) {
		for (Iterator itr = ejbFindList.iterator(); itr.hasNext();) {
		    Class nextEjbFindMethodException = (Class) itr.next();
		    if (findList.contains(nextEjbFindMethodException)) {
			continue;
		    } else {
			// also, for all ejbFind/find combo's any unchecked
			// exceptions thrown by the ejbFind<METHOD> in the bean
			// class doesn't need to be thrown in the corresponding
			// find<METHOD> of the home interface , these unchecked
			// exceptions "subclass of RuntimeException" i.e
			// out of memory exception are handled by the container,
			// who throws a Runtime exception to the appropriate
			// instance/object
			if (isSuperClassofClass("java.lang.RuntimeException",
						nextEjbFindMethodException)) {
			    // ignore this particular unchecked exception, since it stems
			    // from RuntimeException, we can ignore it
			    continue;
			} else {
			    // okay, that's it, now we know ejbFind<METHOD> exception
			    // is not defined in the find<METHOD> in the home interface
			    // test must fail
			    oneFailed = true;
			    // break out after first failure, however, no precise feedback
			    // to caller as to exactly which exception is causing problem
			    // which we happen to know at this point in time
			    break;
			}
		    }
		}
		
		// if we get thru all of 'em, and oneFailed is set, then we flunked test
		if (oneFailed) {
		    return false;
		} else {
		    // we know we never set oneFailed in the above loop, so either all
		    // ejbFind<METHOD> exceptions are defined in the superset find<METHOD>
		    // exceptions, or they are unchecked exceptions, which we can ignore
		    // so set test to passed
		    return true;
		}
	    } else {
		// ejbFind<METHOD> exceptions list is empty, pass test
		return true;
	    }
	}
    }


    /**
     * Find superClass of specified class.
     *
     * @param superClass the specifed super Class to be checked against  
     *                   for containment of
     * @param fromClass the class which you are trying to find the parent super 
     *                  class of
     *
     * @return <code>boolean</code> true if superClass is parent class of fromClass, false otherwise
     */
    private static boolean isSuperClassofClass(String superClass, Class fromClass) {
	boolean validSuperClass = false;
	Class c = fromClass;
	// walk up the class tree
	do {
	    if (c.getName().equals(superClass)) {
		validSuperClass = true;
		break;
	    }
	} while ((((c=c.getSuperclass()) != null) && (!validSuperClass)));

	if (!validSuperClass){
	    return false;
	} else {
	    return true;
	}



    }


} 
