//
// CIMDataType.java
//
// The contents of this file are subject to the SNIA Public License Version 1.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.snia.org/resources/openSource.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CIMDataType.java
//
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s): Peter Rivera,
//                 Angela Lee,
//                 Andrei Viktorov ProdEx Technologies
//
//
// This source uses the Solaris WBEM APIs version 2.2.
// Synchronization will be maintained with the Solaris WBEM APIS,
// which are being standardized through the Java Community Process.
//
//
// $Id: CIMDataType.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
package org.snia.wbem.cim;

import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.io.Serializable;
import java.net.MalformedURLException;

/**
    Encapsulates the CIM data types (as defined in the CIM Specification).
    This class includes methods that perform operations on CIM data types, 
    such as returning the CIM data type of a CIM object, returning an 
    array of CIM data types for an array of CIM objects, and creating an 
    object or array of objects of the specified CIM data type.  All CIM 
    properties must have a valid CIM data type.

 */

public class CIMDataType
        extends Object
        implements Serializable
{

    ///////////////////////////////////////////////////////////////////////////
    // Public/Private Static Data
    ///////////////////////////////////////////////////////////////////////////

    /*
     * Type of size (single element, array with unlimited size etc.)
     */
    public static final int SIZE_SINGLE    = 0; // non-array types
    public static final int SIZE_UNLIMITED = 1; // indicates array type unlimited
    private static final int SIZE_LIMITED  = 2; // array but limited size (NOTSUN)

    /* Data Type Enum bases
     * [NOTE]: These are used to determine valid range of data type enums,
     * and should be updated if they change.
     */
    private final static int ENUM_DT_SINGLE_BASE  = 0;
    private final static int ENUM_DT_ARRAY_BASE   = 20;
    private final static int ENUM_DT_SPECIAL_BASE = 40;

    /* Data Type Enum - Invalid
     */
    public static final int INVALID=0;          // Invalid type

    /* Data Type Enums - single types
     */
    public static final int UINT8    = 1;       // Unsigned 8-bit integer
    public static final int SINT8    = 2;       // Signed 8-bit integer
    public static final int UINT16   = 3;       // Unsigned 16-bit integer
    public static final int SINT16   = 4;       // Signed 16-bit integer
    public static final int UINT32   = 5;       // Unsigned 32-bit integer
    public static final int SINT32   = 6;       // Signed 32-bit integer
    public static final int UINT64   = 7;       // Unsigned 64-bit integer
    public static final int SINT64   = 8;       // Signed 64-bit integer
    public static final int STRING   = 9;       // UCS-2 string
    public static final int BOOLEAN  = 10;      // boolean
    public static final int REAL32   = 11;      // IEEE 4-byte floating-point
    public static final int REAL64   = 12;      // IEEE 8-byte floating-point
    public static final int DATETIME = 13;      // date-time as a string
    public static final int CHAR16   = 14;      // 16-bit UCS-2 character

   /**
    * Data Type Enums - special types
    */
    public static final int REFERENCE = ENUM_DT_SPECIAL_BASE+1; // Reference type (eg: CIMObjectPath)
    public static final int OBJECT    = ENUM_DT_SPECIAL_BASE+2; // Object    type (eg: CIMInstance)
    public static final int NULL      = ENUM_DT_SPECIAL_BASE+3; // Null      type
    public static final int CLASS     = ENUM_DT_SPECIAL_BASE+4; // Class     type (eg: CIMClass)


   /* Data Type Enums - array types
    */
    public static final int UINT8_ARRAY = ENUM_DT_ARRAY_BASE + UINT8;       // Unsigned 8-bit integer array
    public static final int SINT8_ARRAY = ENUM_DT_ARRAY_BASE + SINT8;       // Signed 8-bit integer array
    public static final int UINT16_ARRAY = ENUM_DT_ARRAY_BASE + UINT16;     // Unsigned 16-bit integer array
    public static final int SINT16_ARRAY = ENUM_DT_ARRAY_BASE + SINT16;     // Signed 16-bit integer array
    public static final int UINT32_ARRAY = ENUM_DT_ARRAY_BASE + UINT32;     // Unsigned 32-bit integer array
    public static final int SINT32_ARRAY = ENUM_DT_ARRAY_BASE + SINT32;     // Signed 32-bit integer array
    public static final int UINT64_ARRAY = ENUM_DT_ARRAY_BASE + UINT64;     // Unsigned 64-bit integer array
    public static final int SINT64_ARRAY = ENUM_DT_ARRAY_BASE + SINT64;     // Signed 64-bit integer array
    public static final int STRING_ARRAY = ENUM_DT_ARRAY_BASE + STRING;     // UCS-2 string array
    public static final int BOOLEAN_ARRAY = ENUM_DT_ARRAY_BASE + BOOLEAN;   // boolean array
    public static final int REAL32_ARRAY = ENUM_DT_ARRAY_BASE + REAL32;     // IEEE 4-byte floating-point
    public static final int REAL64_ARRAY = ENUM_DT_ARRAY_BASE + REAL64;     // IEEE 8-byte floating-point
    public static final int DATETIME_ARRAY = ENUM_DT_ARRAY_BASE + DATETIME; // A string containing the date-time
    public static final int CHAR16_ARRAY = ENUM_DT_ARRAY_BASE + CHAR16;     // 16-bit UCS-2 character
    public static final int REFERENCE_ARRAY = ENUM_DT_ARRAY_BASE + REFERENCE;  // Reference type (eg: CIMObjectPath)

   /**
    *  Data Type Enum delimiters
    * [NOTE]: These are used to determine valid range of data type integers,
    * and should be updated if any definition changes are made.
    */
    private final static int ENUM_DT_SINGLE_FIRST   = CIMDataType.UINT8;
    private final static int ENUM_DT_SINGLE_LAST    = CIMDataType.CHAR16;
    private final static int ENUM_DT_ARRAY_FIRST    = CIMDataType.UINT8_ARRAY;
    private final static int ENUM_DT_ARRAY_LAST     = CIMDataType.CHAR16_ARRAY;
    private final static int ENUM_DT_SPECIAL_FIRST  = CIMDataType.REFERENCE;
    private final static int ENUM_DT_SPECIAL_LAST   = CIMDataType.CLASS;
    private final static int ENUM_DT_LAST           = ENUM_DT_SPECIAL_LAST;


   /**
     Data type mapper - string to CIMDataType object.
                Maps CIM Data Type strings (e.g., "uint8") and Java primitive
                strings (e.g., "int") to the predefined CIMDataType object
                corresponding to the data type.
     <p>
                Note: This and other Maps in this class are constantly accessed, and
                                efficiency is important.
     <ul>
     <li>       With the default load factor of .75, this initial capacity of 89
                will make sure no rehash is necessary up to about 60 entires.
                (i.e., no rehash if (initial capacity > (max entries/load factor))).
     <li>       After that (over 66 entries to be exact), this prime number
                is an excellent choice for the default growth factor
                formula of 2n + 1.
     </ul>
    **/
    private static Map s_mapDTStringToCDT = new HashMap(89);

    /**
     *  Data type mapper - Java Object class name to CIMDataType object.
     * Maps Java Object class name (full name including the package name)
     * string (e.g., "java.lang.Integer") to the predefined CIMDataType
     * object corresponding to the data type.
     * <p>
     * This (29) will ensure no rehash up to 21 entries, and then
     * the first expansion will still be a prime number.
     **/

    private static Map s_mapJavaClassNameToCDT = new HashMap(29);

    /** Data type information arrays
      <ul>
      <li>      # of entries = ENUM_DT_LAST + 1
      <li>      Indexed by the data type integer
      </ul>
    **/
    private static String[]      s_arrayDTString             = new String[CIMDataType.ENUM_DT_LAST + 1];
    private static CIMDataType[] s_arrayDTPredefinedObject   = new CIMDataType[CIMDataType.ENUM_DT_LAST + 1];
    private static int[]         s_arrayDTEquivalentTypeEnum = new int[CIMDataType.ENUM_DT_LAST + 1];

    private static int maxDefined = 0;    // number of prefined types

    /** Flag to indicate if the class data (static data) initialization is
        completed or not.
    **/
    private static boolean isClassDataInitialized = false;

    ///////////////////////////////////////////////////////////////////////////
    // Private Member Data
    ///////////////////////////////////////////////////////////////////////////

    private int dataType         = CIMDataType.INVALID;
    private int sizeRange        = CIMDataType.SIZE_SINGLE;
    private int numberOfElements = 1;       // -1 if SIZE_UNLIMITED
    private String reference     = null;    // only if type is REFERENCE
    private boolean isArray      = false;
    private boolean isReference  = false;


    ///////////////////////////////////////////////////////////////////////////
    // Static Initialization Block
    ///////////////////////////////////////////////////////////////////////////

    /**
        Initializes static data to be used by the class.
    **/
    static {
        initialize();
        isClassDataInitialized = true;
    }

    /**
        Initialization of static data used by the class.
<p>
                Called by the Static Initialization Block.
<p>
                [NOTE]:

<ul>
        <li>    Initialization ordering is important since previously initialized
                        array data is used for the subsequent array or map initialization.
        <li>    If the data type information is changed in any way, make sure this
                        method is updated to set up arrays and maps correctly.
</ul>                                                                                                                                                                                   **/
    private static void initialize() {
        int i;

        //////////
        // init array (equivalent, Single vs. Array, data type enum)
        //////////
        for (i = ENUM_DT_SINGLE_FIRST; i <= ENUM_DT_SINGLE_LAST; i++)
            s_arrayDTEquivalentTypeEnum[i] = i + ENUM_DT_ARRAY_BASE;
        for (i = ENUM_DT_ARRAY_FIRST; i <= ENUM_DT_ARRAY_LAST; i++)
            s_arrayDTEquivalentTypeEnum[i] = i - ENUM_DT_ARRAY_BASE;

        //////////
        // init array (data type string)
        // [NOTE]: This array is assumed to be initialized
        // before the ctor is invoked.
        //////////
        s_arrayDTString[CIMDataType.UINT8]      = "uint8";
        s_arrayDTString[CIMDataType.SINT8]      = "sint8";
        s_arrayDTString[CIMDataType.UINT16]     = "uint16";
        s_arrayDTString[CIMDataType.SINT16]     = "sint16";
        s_arrayDTString[CIMDataType.UINT32]     = "uint32";
        s_arrayDTString[CIMDataType.SINT32]     = "sint32";
        s_arrayDTString[CIMDataType.UINT64]     = "uint64";
        s_arrayDTString[CIMDataType.SINT64]     = "sint64";
        s_arrayDTString[CIMDataType.STRING]     = "string";
        s_arrayDTString[CIMDataType.BOOLEAN]    = "boolean";
        s_arrayDTString[CIMDataType.REAL32]     = "real32";
        s_arrayDTString[CIMDataType.REAL64]     = "real64";
        s_arrayDTString[CIMDataType.DATETIME]   = "datetime";
        s_arrayDTString[CIMDataType.CHAR16]     = "char16";

        // use the simple name for Arrays
        for (i = ENUM_DT_ARRAY_FIRST; i <= ENUM_DT_ARRAY_LAST; i++)
            s_arrayDTString[i] = new String(s_arrayDTString[s_arrayDTEquivalentTypeEnum[i]]);

        s_arrayDTString[CIMDataType.REFERENCE]  = "reference";
        s_arrayDTString[CIMDataType.OBJECT]     = "object";
        s_arrayDTString[CIMDataType.NULL]       = "null";
        s_arrayDTString[CIMDataType.CLASS]      = "class";

        //////////
        // init array (pre-defined CIMDataType Object)
        //////////
        for (i = ENUM_DT_SINGLE_FIRST; i <= ENUM_DT_SINGLE_LAST; i++)
            s_arrayDTPredefinedObject[i] = new CIMDataType(i);
        for (i = ENUM_DT_ARRAY_FIRST; i <= ENUM_DT_ARRAY_LAST; i++)
            s_arrayDTPredefinedObject[i] = new CIMDataType(i);
        for (i = ENUM_DT_SPECIAL_FIRST; i <= ENUM_DT_SPECIAL_LAST; i++)
            s_arrayDTPredefinedObject[i] = new CIMDataType(i);

        //////////
        // init map (data type string to CIMDataType object)
        //////////
        for (i = ENUM_DT_SINGLE_FIRST; i <= ENUM_DT_SINGLE_LAST; i++) {
            s_mapDTStringToCDT.put (s_arrayDTString[i],
                                    s_arrayDTPredefinedObject[i]);
            s_mapDTStringToCDT.put (s_arrayDTString[i].toUpperCase(),
                                    s_arrayDTPredefinedObject[i]);
        }

        for (i = ENUM_DT_SPECIAL_FIRST; i <= ENUM_DT_SPECIAL_LAST; i++) {
            s_mapDTStringToCDT.put (s_arrayDTString[i],
                                    s_arrayDTPredefinedObject[i]);
            s_mapDTStringToCDT.put (s_arrayDTString[i].toUpperCase(),
                                    s_arrayDTPredefinedObject[i]);
        }

        // Java primitives
        s_mapDTStringToCDT.put ("int",    s_arrayDTPredefinedObject[CIMDataType.SINT32]);
        s_mapDTStringToCDT.put ("short",  s_arrayDTPredefinedObject[CIMDataType.SINT16]);
        s_mapDTStringToCDT.put ("long",   s_arrayDTPredefinedObject[CIMDataType.SINT64]);
        s_mapDTStringToCDT.put ("byte",   s_arrayDTPredefinedObject[CIMDataType.SINT8]);
        s_mapDTStringToCDT.put ("double", s_arrayDTPredefinedObject[CIMDataType.REAL64]);
        s_mapDTStringToCDT.put ("float",  s_arrayDTPredefinedObject[CIMDataType.REAL32]);
        s_mapDTStringToCDT.put ("char",   s_arrayDTPredefinedObject[CIMDataType.CHAR16]);


        // same as CIM boolean string, should not add to the map which
        // can not have duplicate keys
        //      s_mapDTStringToCDT.put ("boolean",
        //                      s_arrayDTPredefinedObject[CIMDataType.BOOLEAN]);

        //////////
        // init map (Java Object class name string to CIMDataType object)
        //////////
        s_mapJavaClassNameToCDT.put ("java.lang.String",
                                     s_arrayDTPredefinedObject[CIMDataType.STRING]);
        s_mapJavaClassNameToCDT.put ("java.lang.Integer",
                                     s_arrayDTPredefinedObject[CIMDataType.SINT32]);
        s_mapJavaClassNameToCDT.put ("java.lang.Short",
                                     s_arrayDTPredefinedObject[CIMDataType.SINT16]);
        s_mapJavaClassNameToCDT.put ("java.lang.Long",
                                     s_arrayDTPredefinedObject[CIMDataType.SINT64]);
        s_mapJavaClassNameToCDT.put ("java.lang.Byte",
                                     s_arrayDTPredefinedObject[CIMDataType.SINT8]);
        s_mapJavaClassNameToCDT.put ("java.lang.Double",
                                     s_arrayDTPredefinedObject[CIMDataType.REAL64]);
        s_mapJavaClassNameToCDT.put ("java.lang.Float",
                                     s_arrayDTPredefinedObject[CIMDataType.REAL32]);
        s_mapJavaClassNameToCDT.put ("java.lang.Character",
                                     s_arrayDTPredefinedObject[CIMDataType.CHAR16]);
        s_mapJavaClassNameToCDT.put ("java.lang.Boolean",
                                     s_arrayDTPredefinedObject[CIMDataType.BOOLEAN]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.CIMObjectPath",
                                     s_arrayDTPredefinedObject[CIMDataType.REFERENCE]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.CIMInstance",
                                     s_arrayDTPredefinedObject[CIMDataType.OBJECT]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.CIMClass",
                                     s_arrayDTPredefinedObject[CIMDataType.CLASS]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.CIMDateTime",
                                     s_arrayDTPredefinedObject[CIMDataType.DATETIME]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.UnsignedInt8",
                                     s_arrayDTPredefinedObject[CIMDataType.UINT8]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.UnsignedInt16",
                                     s_arrayDTPredefinedObject[CIMDataType.UINT16]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.UnsignedInt32",
                                     s_arrayDTPredefinedObject[CIMDataType.UINT32]);
        s_mapJavaClassNameToCDT.put ("org.snia.wbem.cim.UnsignedInt64",
                                     s_arrayDTPredefinedObject[CIMDataType.UINT64]);

    }


    ///////////////////////////////////////////////////////////////////////////
    // Public Static Methods
    ///////////////////////////////////////////////////////////////////////////

    /**
        findType finds a datatype for an arbitrary object
        @param Object object to be checked
        @return int type of the object or INVALID if the object is  invalid.
     **/
    public static final int findType(Object o) {
        String className = o.getClass().getName();
        CIMDataType CDTObject =
                (CIMDataType)s_mapJavaClassNameToCDT.get(className);
        if (CDTObject != null)
            return CDTObject.getType();
        else
            return CIMDataType.INVALID;
        }

    //
    // findType
    //
    // Finds a datatype for an arbitrary set of objects
    //
    // SUNDIFF: Not supported
    //
    //public static final int findType(Vector v) {
    //   return(INVALID);
    //}

    /**
        Maps strings given by name
        @param String name 
        @return CIMDataType data of the string specified
     **/
    public static CIMDataType getDataType(String name)
                throws CIMException {
        if (name == null)
            return null;

        if (name.startsWith("java.lang."))
            name = name.substring(10);

        CIMDataType CDTObject = (CIMDataType)s_mapDTStringToCDT.get(name);
        if (CDTObject != null)
            return CDTObject;
        else
            // null if not in the map (i.e., unknown CIM data type or
            // Java primitive name). params[0] is the generating method
            // name, params[1] is detail message.
            throw new CIMException(CIMException.CIM_ERR_FAILED,
                                   "CIMDataType." + "getDataType()",
                                   "Unknown data type name \"" + name +
                                   "\" specified.");
    }

    /**
        findArrayType Takes a regular data type and returns the equivalent
        array type. Returns INVALID if there is no equiv array type.
        @param int simple type 
        @return int an integer for CIM array type else INVALID.
     **/
    public static final int findArrayType(int simpleType) {
        if (validSingleType(simpleType))
            return s_arrayDTEquivalentTypeEnum[simpleType];
        else
            return CIMDataType.INVALID;
    }

    /**
        findSimpleType Takes an array type and returns the equivalent non array
        data type. Returns INVALID if there is no equiv.
        @param int simple type 
        @return int an integer for CIM array type else INVALID.
     **/
    public static final int findSimpleType(int arrayType) {
        if (validArrayType(arrayType))
            return s_arrayDTEquivalentTypeEnum[arrayType];
        else
            return CIMDataType.INVALID;
    }


    /**
        Returns a shared datatype object with the specified type
        @param int type specified
        @return CIMDataType data of the string specified
     **/
    public static CIMDataType getPredefinedType(int type) {
        // if invalid type, it will find null in the array
        if (type < s_arrayDTPredefinedObject.length)
            return s_arrayDTPredefinedObject[type];
        else
            // out of bounds, return null
            return null;
    }

    //Modified by Prakash on 11-04-2002; converted from type private to type public
    /**
        convert specified enumtype to String
        @param int enum type specified
        @return String converted string 
     **/
    public static String convertTypeEnumToString(int typeEnum) {
        if (CIMDataType.validType(typeEnum))
            return s_arrayDTString[typeEnum];
        else
            return "invalid";
    }

    ///////////////////////////////////////////////////////////////////////////
    // Private Static Methods
    ///////////////////////////////////////////////////////////////////////////

    /**
     **/
    private static boolean validType(int inType) {
        if (CIMDataType.isClassDataInitialized)
            return (s_arrayDTString[inType] != null);
        else {
            boolean result = false;
            if ( ((inType >= ENUM_DT_SINGLE_FIRST)
                    && (inType <= ENUM_DT_SINGLE_LAST)) ||
                 ((inType >= ENUM_DT_ARRAY_FIRST)
                    && (inType <= ENUM_DT_ARRAY_LAST)) ||
                 ((inType >= ENUM_DT_SPECIAL_FIRST)
                    && (inType <= ENUM_DT_SPECIAL_LAST)) )
                result = true;
            return result;
        }
    }

    /**
     **/
    private static boolean validArrayType(int type) {
        return ((type >= ENUM_DT_ARRAY_FIRST) && (type <= ENUM_DT_ARRAY_LAST));
    }

    /**
     **/
    private static boolean validSingleType(int type) {
        return ((type >= ENUM_DT_SINGLE_FIRST) &&(type <= ENUM_DT_SINGLE_LAST));
    }


    ///////////////////////////////////////////////////////////////////////////
    // Public Constructors
    ///////////////////////////////////////////////////////////////////////////

    /**
     *
     * Constructor creates a new data type
     *
     * NOTE: Not for reference or NULL types
     * For arrays, the size is initialized to SIZE_UNLIMITED
     *
     **/
    public CIMDataType(int type) {
        if (validType(type)) {
            dataType = type;
            if ((type >= ENUM_DT_SINGLE_FIRST)
                 && (type <= ENUM_DT_SINGLE_LAST)) {
                //sizeRange = CIMDataType.SIZE_SINGLE;
                //numberOfElements = 1;
                //reference = null;
                //isArray = false;
                //isReference = false;
            } else if ((type >= ENUM_DT_ARRAY_FIRST)
                  && (type <= ENUM_DT_ARRAY_LAST)) {
                sizeRange = CIMDataType.SIZE_UNLIMITED;
                numberOfElements = -1;
                //reference = null;
                isArray = true;
                //isReference = false;
            } // ???? spec does not allow these, but we invoke it to instantiate pre-defined objects ????
              else if (type > ENUM_DT_SPECIAL_BASE) {
                //sizeRange = CIMDataType.SIZE_SINGLE;
                //numberOfElements = 1;
                //reference = null;
                //isArray = false;
                //isReference = false;
                // ??? no reference class, but reference type ???
                if (type == CIMDataType.REFERENCE) {
                    isReference = true;
                    reference = "String";
                }
            }
        }
        // default is an INVALID object
        // else
        //  invalidate();
    }

   /**
    *
    * Constructor for arrays.
    *
    * Note: type needs to be an array data type
    *
    **/
    public CIMDataType(int type, int size) {
        if (validArrayType(type)) {
            dataType=type;
            sizeRange = CIMDataType.SIZE_LIMITED;
            numberOfElements=size;
            //reference = null;
            isArray = true;
            //isReference = false;
        }
        // default is an INVALID object
        // else
        //   invalidate();
    }

    /**
     *
     * Creates a REFERENCE data type
     *
     **/
    public CIMDataType(String refClassName) {
        dataType = CIMDataType.REFERENCE;
        //sizeRange = CIMDataType.SIZE_SINGLE;
        //numberOfElements = 1;
        reference = refClassName;
        //isArray = false;
        isReference = true;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Public Member Methods
    ///////////////////////////////////////////////////////////////////////////


   /**
    * isArrayType
    *
    * Returns TRUE if the type is an array type.
    *
    **/
    public boolean isArrayType() {
        return isArray;
    }

    /**
     * isReferenceType
     *
     * Returns TRUE if the type is a reference.
     **/
    public boolean isReferenceType() {
        return isReference;
    }

    /**
     * getType
     *
     * Returns the data type
     *
     **/
    public int getType() {
        return dataType;
    }

    /**
     * getSize
     *
     * Returns the size of the type
     *
     **/
     public int getSize() {
        // 1 if SIZE_SINGLE, -1 if SIZE_UNLIMITED, <size> if SIZE_LIMITED
        return numberOfElements;
     }


    /**
     * getRefClassName
     *
     * Returns the classname for references
     *
     **/
    public String getRefClassName() {
        // null if not REFERENCE type
        return reference;
    }

    /**
     * equals
     *
     * Returns True if the specified object is a data type
     *
     **/
    public boolean equals(Object obj) {
        boolean result = false;

        //same objects
        if (this == obj)
            result = true;
        else if ((obj != null) && (obj instanceof CIMDataType)) {
            // make sure we have an equivalent object to compare
            //now we can safely cast the object
            CIMDataType other = (CIMDataType)obj;
            if ((dataType == other.dataType)
                 && (numberOfElements == other.numberOfElements))
                result = true;
        }
        return result;
    }


   /**
       toMOF returns a String representation of the CIM DataType.
       @return String String representation of this datatype.
    */
    public String toString() {
        // use MOF syntax string
        return toMOF();
    }

   /**
       toMOF returns a MOF representation of the CIM DataType.
       @return String MOF representation of this datatype.
    */
    public String toMOF() {
        String ret;

        if (dataType == CIMDataType.INVALID)
            ret = "**invalid**";
        // ???? NULL is no good ????
        else if (dataType == CIMDataType.NULL)
            ret = "BAD";
        else if (isReferenceType())
            ret = reference +" REF";
        else if (! isArrayType())
            ret = s_arrayDTString[dataType];
        else {
            // array type
            if (sizeRange == CIMDataType.SIZE_LIMITED)
                ret = s_arrayDTString[dataType] + "[" + numberOfElements + "]";
            else
                ret = s_arrayDTString[dataType] + "[ ]";
        }
        return ret;
    }

    /**
       Returns a string representation of the data type - in the
       XML case array identifiers are not included
       @return String XML representation of this datatype.
     **/
    public String toXml() throws MalformedURLException {
        String ret;

        if ((dataType == CIMDataType.INVALID) || (dataType == CIMDataType.NULL))
             throw new MalformedURLException("not a valid datatype");
        else {
            if (isReferenceType())
                ret = reference +" REF";
            else
                ret = s_arrayDTString[dataType];
        }
        return ret;
    }

    /**
     * main()
     * This is a test driver for class CIMDataType.
     * Instantiation and a few methods are tested.
     * @param args
     **/
    public static void main(String[] args) {
        try {
            // instantiate CIMDataType instances

            // invalid
            CIMDataType cdtInvalid      = new CIMDataType(CIMDataType.INVALID);

            // types at enum borders
            CIMDataType cdtSingleFirst  = new CIMDataType(CIMDataType.UINT8);
            CIMDataType cdtSingleLast   = new CIMDataType(CIMDataType.CHAR16);
            CIMDataType cdtArrayFirst   = new CIMDataType(CIMDataType.UINT8_ARRAY);
            CIMDataType cdtArrayLast    = new CIMDataType(CIMDataType.CHAR16_ARRAY);

            CIMDataType cdtRef          = new CIMDataType(CIMDataType.REFERENCE);
            CIMDataType cdtObj          = new CIMDataType(CIMDataType.OBJECT);
            CIMDataType cdtNull         = new CIMDataType(CIMDataType.NULL);
            CIMDataType cdtClass        = new CIMDataType(CIMDataType.CLASS);

            // invalid types at enum between borders
            CIMDataType cdtBad20        = new CIMDataType(CIMDataType.ENUM_DT_ARRAY_BASE);
            CIMDataType cdtBad40        = new CIMDataType(CIMDataType.ENUM_DT_SPECIAL_BASE);


            // valid single types
            CIMDataType cdtUint32       = new CIMDataType(CIMDataType.UINT32);
            CIMDataType cdtSint8        = new CIMDataType(CIMDataType.SINT8);
            CIMDataType cdtString       = new CIMDataType(CIMDataType.STRING);
            CIMDataType cdtBoolean      = new CIMDataType(CIMDataType.BOOLEAN);
            CIMDataType cdtReal64       = new CIMDataType(CIMDataType.REAL64);
            CIMDataType cdtDatetime     = new CIMDataType(CIMDataType.DATETIME);

            // valid array types
            CIMDataType cdtUint8Array       = new CIMDataType(CIMDataType.UINT8_ARRAY);
            CIMDataType cdtSint32Array      = new CIMDataType(CIMDataType.SINT32_ARRAY);
            CIMDataType cdtStringArray      = new CIMDataType(CIMDataType.STRING_ARRAY);
            CIMDataType cdtBooleanArray     = new CIMDataType(CIMDataType.BOOLEAN_ARRAY);
            CIMDataType cdtReal32Array      = new CIMDataType(CIMDataType.REAL32_ARRAY);
            CIMDataType cdtDatetimeArray    = new CIMDataType(CIMDataType.DATETIME_ARRAY);
            CIMDataType cdtReferenceArray   = new CIMDataType(CIMDataType.REFERENCE_ARRAY);


            // array types w/ size (valid and invalid parameters)
            CIMDataType cdtStringArraySized = new CIMDataType(CIMDataType.STRING_ARRAY, 5);
            CIMDataType cdtBadStringArray   = new CIMDataType(CIMDataType.STRING, 5);


            // reference type
            CIMDataType cdtRefCIMObjectPath = new CIMDataType("CIMObjectPath");
            CIMDataType cdtObjCIMInstance   = new CIMDataType("CIMInstance");
            CIMDataType cdtClassCIMClass    = new CIMDataType("CIMClass");

            // toMof() operation
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtInvalid.getType()) + ": " + cdtInvalid.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtSingleFirst.getType()) + ": " + cdtSingleFirst.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtSingleLast.getType()) + ": " + cdtSingleLast.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtArrayFirst.getType()) + ", array: " + cdtArrayFirst.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtArrayLast.getType()) + ", array: " + cdtArrayLast.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtRef.getType()) + ": " + cdtRef.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtObj.getType()) + ": " + cdtObj.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtNull.getType()) + ": " + cdtNull.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtClass.getType()) + ": " + cdtClass.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtBad20.getType()) + ": " + cdtBad20.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtBad40.getType()) + ": " + cdtBad40.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtUint32.getType()) + ": " + cdtUint32.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtSint8.getType()) + ": " + cdtSint8.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtString.getType()) + ": " + cdtString.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtBoolean.getType()) + ": " + cdtBoolean.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtReal64.getType()) + ": " + cdtReal64.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtUint8Array.getType()) + ", array: " + cdtUint8Array.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtSint32Array.getType()) + ", array: " + cdtSint32Array.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtStringArray.getType()) + ", array: " + cdtStringArray.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtBooleanArray.getType()) + ", array: " + cdtBooleanArray.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtReal32Array.getType()) + ", array: " + cdtReal32Array.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtDatetimeArray.getType()) + ", array: " + cdtDatetimeArray.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtStringArraySized.getType()) + ", array, sized: " + cdtStringArraySized.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtBadStringArray.getType()) + ", invalid array: " + cdtBadStringArray.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtRefCIMObjectPath.getType()) + ": " + cdtRefCIMObjectPath.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtObjCIMInstance.getType()) + ": " + cdtObjCIMInstance.toMOF());
            System.out.println ("toMof(), type=" + CIMDataType.convertTypeEnumToString(cdtClassCIMClass.getType()) + ": " + cdtClassCIMClass.toMOF());

            // findType() operation
            int result;

            result = CIMDataType.findType(new String("test"));
            if (result != CIMDataType.STRING)
                System.out.println ("findType(String) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Integer(1));
            if (result != CIMDataType.SINT32)
                System.out.println ("findType(Integer) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Short((short)1));
            if (result != CIMDataType.SINT16)
                System.out.println ("findType(Short) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Long(1));
            if (result != CIMDataType.SINT64)
                System.out.println ("findType(Long) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Byte((byte)1));
            if (result != CIMDataType.SINT8)
                System.out.println ("findType(Byte) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Double(1));
            if (result != CIMDataType.REAL64)
                System.out.println ("findType(Double) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Float(1));
            if (result != CIMDataType.REAL32)
                System.out.println ("findType(Float) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Character('A'));
            if (result != CIMDataType.CHAR16)
                System.out.println ("findType(Character) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new Boolean(true));
            if (result != CIMDataType.BOOLEAN)
                System.out.println ("findType(Boolean) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new CIMObjectPath("Win32_Share"));
            if (result != CIMDataType.REFERENCE)
                System.out.println ("findType(CIMObjectPath) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new CIMInstance("BoobaInstance"));
            if (result != CIMDataType.OBJECT)
                System.out.println ("findType(CIMInstance) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new CIMClass("BoobaClass"));
            if (result != CIMDataType.CLASS)
                System.out.println ("findType(CIMClass) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new CIMDateTime());
            if (result != CIMDataType.DATETIME)
                System.out.println ("findType(CIMDateTime) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new UnsignedInt8((short)1));
            if (result != CIMDataType.UINT8)
                System.out.println ("findType(UnsignedInt8) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new UnsignedInt16(1));
            if (result != CIMDataType.UINT16)
                System.out.println ("findType(UnsignedInt16) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new UnsignedInt32(1));
            if (result != CIMDataType.UINT32)
                System.out.println ("findType(UnsignedInt32) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

            result = CIMDataType.findType(new UnsignedInt64("1"));
            if (result != CIMDataType.UINT64)
                System.out.println ("findType(UnsignedInt64) returned " + result + " (= " + CIMDataType.convertTypeEnumToString(result) + ").");

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

}       // class CIMDataType

