Package org.apache.geronimo.interop.rmi.iiop

Source Code of org.apache.geronimo.interop.rmi.iiop.ValueType

/**
*
*  Copyright 2004-2005 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.geronimo.interop.rmi.iiop;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import org.apache.geronimo.interop.SystemException;
import org.apache.geronimo.interop.util.ArrayUtil;
import org.apache.geronimo.interop.util.ExceptionUtil;
import org.apache.geronimo.interop.util.JavaClass;
import org.apache.geronimo.interop.util.JavaType;
import org.apache.geronimo.interop.util.SystemUtil;
import org.apache.geronimo.interop.util.ThreadContext;
import org.omg.CORBA.TCKind;

/**
** A wrapper over java.lang.Class to help improve performance of using
** the Java reflection API for valuetype marshalling. We keep as much
** derived information as possible for optimal performance.
**/
public class ValueType
{
    public static ValueType getInstance(Class forClass)
    {
        ValueType vt = (ValueType)_valueTypeMap.get(forClass);
        if (vt == null)
        {
            synchronized (_valueTypeMap)
            {
                vt = (ValueType)_valueTypeMap.get(forClass);
                if (vt == null)
                {
                    vt = new ValueType();
                    _valueTypeMap.put(forClass, vt);
                    vt.init(forClass);
                }
            }
        }
        return vt;
    }

    public static ValueType getInstanceByID(String id)
    {
        // TODO: handle multiple class loaders???
        ValueType vt = (ValueType)_idTypeMap.get(id);
        if (vt == null)
        {
            synchronized (_idTypeMap)
            {
                vt = (ValueType)_idTypeMap.get(id);
                if (vt == null)
                {
                    Class theClass = getClass(id);
                    vt = getInstance(theClass);
                    _idTypeMap.put(id, vt);
                }
            }
        }
        return vt;
    }

    // -----------------------------------------------------------------------
    // public data
    // -----------------------------------------------------------------------

    public Class _class;

    public org.apache.geronimo.interop.rmi.iiop.ObjectHelper helper;

    // -----------------------------------------------------------------------
    // private data
    // -----------------------------------------------------------------------

    private static HashMap _valueTypeMap = new HashMap();

    private static HashMap _initMap = new HashMap();

    private static HashMap _idTypeMap = new HashMap();

    private static final boolean JDK14 = SystemUtil.isJDK14();

    private static Method _allocateNewObject;

    private static Object[] _allocateNewObjectArgs;

    private static Method _newInstance;

    private ObjectStreamClass _objectStreamClass;

    private Method _readExternal;
    private Method _readObject;
    private Method _readResolve;
    private Method _writeExternal;
    private Method _writeObject;
    private Method _writeReplace;

    // -----------------------------------------------------------------------
    // package-private data
    // -----------------------------------------------------------------------

    static final int NULL_VALUE_TAG                    = 0;
    static final int NO_TYPE_VALUE_TAG                 = 0x7fffff00;
    static final int SINGLE_TYPE_VALUE_TAG             = 0x7fffff02;
    static final int TRUNCATABLE_NO_TYPE_VALUE_TAG     = 0x7fffff08;
    static final int TRUNCATABLE_SINGLE_TYPE_VALUE_TAG = 0x7fffff0a;
    static final int TYPE_LIST_VALUE_TAG               = 0x7fffff06;
    static final int INDIRECTION_TAG                   = 0xffffffff;

    static final int CASE_ARRAY = 1;
    static final int CASE_CLASS = 2;
    static final int CASE_IDL_ENTITY = 3;
    static final int CASE_IDL_OBJECT = 4;
    static final int CASE_STRING = 5;

    static final ValueType OBJECT_VALUE_TYPE = getInstance(Object.class);

    static final ValueType STRING_VALUE_TYPE = getInstance(String.class);

    static final org.omg.CORBA.TypeCode TC_NULL = new TypeCode(TCKind.tk_null);

    static TypeCode TC_ABSTRACT_BASE;

    String id; // CORBA Repository ID

    TypeCode tc;

    ValueType parent;

    ValueTypeField[] fields; // just the serializable fields.

    ValueType element; // if array, this is ValueType for elements.

    boolean hasParentState;
    boolean hasReadObject;
    boolean hasReadOrWriteObject;
    boolean hasWriteObject;
    boolean hasReadResolve;
    boolean hasWriteReplace;

    boolean isAbstractInterface;
    boolean isAny;
    boolean isAnyOrObjectRefOrAbstractInterface;
    boolean isArray;
    boolean isExternalizable;
    boolean isIDLEntity;
    boolean isObjectRef;

    int primitiveArray;

    int readWriteCase;

    boolean requiresCustomSerialization;

    boolean skipCustomFlags; // TODO: init this

    // -----------------------------------------------------------------------
    // static initializer
    // -----------------------------------------------------------------------

    static
    {
        TC_ABSTRACT_BASE = new TypeCode(TCKind.tk_abstract_interface);
        TC_ABSTRACT_BASE.id("IDL:omg.org/CORBA/AbstractBase:1.0");
        TC_ABSTRACT_BASE.name("");

        try
        {
            if (JDK14)
            {
                _newInstance = java.io.ObjectStreamClass.class.getDeclaredMethod("newInstance", new Class[] {});
                _newInstance.setAccessible(true);
            }
            else
            {
                _allocateNewObject = java.io.ObjectInputStream.class.getDeclaredMethod("allocateNewObject", new Class[] { Class.class, Class.class });
                _allocateNewObject.setAccessible(true);
            }
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    // -----------------------------------------------------------------------
    // public methods
    // -----------------------------------------------------------------------

    public Object newInstance()
    {
        try
        {
            if (JDK14)
            {
                if (_class == Object.class)
                {
                    return new Object();
                }
                else
                {
                    return _newInstance.invoke(_objectStreamClass, ArrayUtil.EMPTY_OBJECT_ARRAY);
                }
            }
            else
            {
                return _allocateNewObject.invoke(null, _allocateNewObjectArgs);
            }
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    public String toString()
    {
        return "ValueType:" + JavaType.getName(_class);
    }

    public void readObject(Object _this, org.apache.geronimo.interop.rmi.iiop.ObjectInputStream input)
    {
        try
        {
            _readObject.invoke(_this, input.thisAsObjectArray);
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    public void writeObject(Object _this, org.apache.geronimo.interop.rmi.iiop.ObjectOutputStream output)
    {
        try
        {
            _writeObject.invoke(_this, output.thisAsObjectArray);
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    public Object readResolve(Object _this)
    {
        try
        {
            return _readResolve.invoke(_this, ArrayUtil.EMPTY_OBJECT_ARRAY);
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    public Object writeReplace(Object _this)
    {
        try
        {
            return _writeReplace.invoke(_this, ArrayUtil.EMPTY_OBJECT_ARRAY);
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    public void readExternal(Object _this, org.apache.geronimo.interop.rmi.iiop.ObjectInputStream input)
    {
        try
        {
            _readExternal.invoke(_this, input.thisAsObjectArray);
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    public void writeExternal(Object _this, org.apache.geronimo.interop.rmi.iiop.ObjectOutputStream output)
    {
        try
        {
            _writeExternal.invoke(_this, output.thisAsObjectArray);
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
    }

    // -----------------------------------------------------------------------
    // protected methods
    // -----------------------------------------------------------------------

    protected void init(Class theClass)
    {
        boolean recursive = false;
        if (_initMap.get(theClass) != null)
        {
//              recursive = true;
            return; // Already initializing (recursive 'init' call).
        }
        _initMap.put(theClass, Boolean.TRUE);
        try
        {
            _class = theClass;
            _objectStreamClass = ObjectStreamClass.lookup(_class);
            if (org.omg.CORBA.Object.class.isAssignableFrom(theClass)
                || javax.ejb.EJBHome.class.isAssignableFrom(theClass)
                || javax.ejb.EJBObject.class.isAssignableFrom(theClass)
                || java.rmi.Remote.class.isAssignableFrom(theClass))
            {
                helper = ObjectRefHelper.getInstance(theClass);
                isObjectRef = true;
                readWriteCase = CASE_IDL_OBJECT;
            }
            else if (org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(theClass))
            {
                helper = IDLEntityHelper.getInstance(theClass);
                isIDLEntity = true;
                readWriteCase = CASE_IDL_ENTITY;
            }
            else if (theClass == String.class)
            {
                helper = StringHelper.SINGLETON;
                readWriteCase = CASE_STRING;
            }
            else if (theClass.isArray())
            {
                Class elementClass = theClass.getComponentType();
                element = getInstance(elementClass);
                isArray = true;
                if (elementClass.isPrimitive())
                {
                    primitiveArray = PrimitiveType.get(elementClass);
                    helper = PrimitiveType.getArrayHelper(elementClass);
                }
                else
                {
                    helper = new ArrayHelper(elementClass);
                }
                readWriteCase = CASE_ARRAY;
            }
            else if (theClass == Class.class)
            {
                readWriteCase = CASE_CLASS;
            }
            if (_allocateNewObject != null)
            {
                Class bc = _class;
                while (Serializable.class.isAssignableFrom(bc) && (bc.getSuperclass() != null))
                {
                    bc = bc.getSuperclass();
                }
                _allocateNewObjectArgs = new Object[] { _class, bc };
            }

            isAny = _class == java.lang.Object.class
                    || _class == java.io.Externalizable.class
                    || _class == java.io.Serializable.class;

            isExternalizable = java.io.Externalizable.class.isAssignableFrom(_class);
            if (isExternalizable)
            {
                _readExternal = _class.getDeclaredMethod("readExternal", new Class[] { ObjectInput.class } );
                _writeExternal = _class.getDeclaredMethod("writeExternal", new Class[] { ObjectOutput.class } );
            }

            // SG: Hopefully we got all the info that is needed
            if(recursive)
            {
                return;
            }


            java.lang.Class tmpClass = _class;
            ArrayList fieldList = new ArrayList();
            Field[] javaFields = tmpClass.getDeclaredFields();

            // TODO: suppress sort for IDL-generated valuetypes
            Arrays.sort(javaFields, FieldComparator.SINGLETON);

            // Create vector of non-static, non-transient fields.
            // Ensure that all fields are readable/writable using reflection.
            int nf = javaFields.length;
            for (int f = 0; f < nf; f++)
            {
                Field javaField = javaFields[f];
                int modifiers = javaField.getModifiers();
                if ((modifiers & (Modifier.STATIC | Modifier.TRANSIENT)) != 0)
                {
                    continue;
                }
                if (! javaField.isAccessible())
                {
                    javaField.setAccessible(true);
                }
                ValueTypeField field = new ValueTypeField(javaField);
                fieldList.add(field);
            }

            fields = (ValueTypeField[])fieldList.toArray(new ValueTypeField[fieldList.size()]);

            // Check methods for readObject/writeObject. Also check for
            // abstract interfaces.
            Method[] methods = _class.getDeclaredMethods();
            int countThrowsRemoteException = 0;
            int nm = methods.length;
            for (int m = 0; m < nm; m++)
            {
                Method method = methods[m];
                Class[] types = method.getParameterTypes();
                if (types.length == 1
                    && types[0] == java.io.ObjectInputStream.class
                    && (method.getModifiers() & Modifier.PRIVATE) != 0
                    && method.getName().equals("readObject"))
                {
                    _readObject = method;
                    if (! _readObject.isAccessible())
                    {
                        _readObject.setAccessible(true);
                    }
                }
                if (types.length == 1
                    && types[0] == java.io.ObjectOutputStream.class
                    && (method.getModifiers() & Modifier.PRIVATE) != 0
                    && method.getName().equals("writeObject"))
                {
                    _writeObject = method;
                    if (! _writeObject.isAccessible())
                    {
                        _writeObject.setAccessible(true);
                    }
                }

                if (types.length == 0
                    && method.getReturnType() == java.lang.Object.class
                    && method.getName().equals("writeReplace"))
                {
                    _writeReplace = method;
                    if (! _writeReplace.isAccessible())
                    {
                        _writeReplace.setAccessible(true);
                    }
                }
                if (types.length == 0
                && method.getReturnType() == java.lang.Object.class
                    && method.getName().equals("readResolve"))
                {
                    _readResolve = method;
                    if (! _readResolve.isAccessible())
                    {
                        _readResolve.setAccessible(true);
                    }
                }
                Class[] exceptions = method.getExceptionTypes();
                for (int i = 0; i < exceptions.length; i++)
                {
                    Class exception = exceptions[i];
                    if (exception.isAssignableFrom(java.rmi.RemoteException.class))
                    {
                        // TODO: check Java to IDL wording for this
                        countThrowsRemoteException++;
                        break;
                    }
                }
            }

            hasReadOrWriteObject = _readObject != null || _writeObject != null;
            hasReadObject = _readObject != null;
            hasWriteObject = _writeObject != null;
            hasWriteReplace = _writeReplace != null;
            hasReadResolve = _readResolve != null;

            isAbstractInterface = ! isObjectRef
                && _class.isInterface()
                && countThrowsRemoteException == methods.length;

            Class superclass = _class.getSuperclass();
            if((superclass != null) && (superclass != java.lang.Object.class) && (!isIDLEntity ))
            {
                parent = getInstance(superclass);
            }

            hasParentState = parent != null
                && (parent.fields.length > 0
                    || parent.isExternalizable
                    || parent.hasReadOrWriteObject
                    || parent.hasParentState);

            requiresCustomSerialization = hasWriteObject || isExternalizable;

            initRepositoryID();
            initTypeCode();

            isAnyOrObjectRefOrAbstractInterface = isAny || isObjectRef || isAbstractInterface;
        }
        catch (Exception ex)
        {
            throw ExceptionUtil.getRuntimeException(ex);
        }
        finally
        {
            if(!recursive)
            {
            _initMap.remove(theClass);
        }
    }
    }

    protected void initRepositoryID()
    {
        final String sixteenZeros = "0000000000000000";
        final int requiredLength = 16;
       /* if (isAny)
        {
            id = "#ANY-TODO#";
            return;
        }*/
        if (isArray && primitiveArray != 0)
        {
            id = "RMI:" + _class.getName() + ":" + sixteenZeros;
            return;
        }
        if (_class == String.class)
        {
            id = "IDL:omg.org/CORBA/WStringValue:1.0";
            return;
        }
        if (isObjectRef)
        {
            id = "RMI:" + _class.getName() + ":" + sixteenZeros;
            return;
        }
        if (_class == java.lang.Class.class)
        {
            id = "RMI:javax.rmi.CORBA.ClassDesc:2BABDA04587ADCCC:CFBF02CF5294176B";
            return;
        }
        if (_class == java.math.BigInteger.class)
        {
            id = "RMI:java.math.BigInteger:E2F79B6E7A470003:8CFC9F1FA93BFB1D";
            return;
        }
        if (_objectStreamClass == null)
        {
            id = "???";
            return;
        }
        long structuralUID = computeStructuralUID(this);
        long serialVersionUID = _objectStreamClass.getSerialVersionUID();
        String structuralUIDString = Long.toHexString(structuralUID).toUpperCase();
        String serialVersionUIDString = Long.toHexString(serialVersionUID).toUpperCase();
        int currentLength;
        int lengthNeeded;
        currentLength = structuralUIDString.length();
        if (currentLength < requiredLength)
        {
            lengthNeeded = requiredLength - currentLength;
            structuralUIDString = sixteenZeros.substring(0, lengthNeeded) + structuralUIDString;
        }
        currentLength = serialVersionUIDString.length();
        if (currentLength < requiredLength)
        {
            lengthNeeded = requiredLength - currentLength;
            serialVersionUIDString = sixteenZeros.substring(0, lengthNeeded) + serialVersionUIDString;
        }
        id = "RMI:" + _class.getName() + ":" + structuralUIDString + ":" + serialVersionUIDString;
    }

    protected void initTypeCode()
    {
        if (isObjectRef)
        {
            tc = new TypeCode(TCKind.tk_objref);
            tc.id(id);
            tc.name("");
        }
        else if (isArray || isIDLEntity || _class == String.class)
        {
            tc = new TypeCode(TCKind.tk_value_box);
            tc.id(id);
            tc.name("");
            if (_class == String.class)
            {
                tc.content_type(new TypeCode(TCKind.tk_wstring));
            }
            else if (isArray)
            {
                TypeCode seqTC = new TypeCode(TCKind.tk_sequence);
                if (primitiveArray != 0)
                {
                    seqTC.content_type(PrimitiveType.getTypeCode(primitiveArray));
                }
                else
                {
                    seqTC.content_type(element.tc);
                }
                tc.content_type(seqTC);
            }
            else if (isIDLEntity)
            {
                // TODO tc.content_type(helper.type());
            }
        }
        else
        {
            tc = new TypeCode(TCKind.tk_value);
            tc.id(id);
            tc.name("");

            // TODO: value modifier
            if (requiresCustomSerialization)
            {
                tc.type_modifier((short)1);
            }
            else if (isAbstractInterface)
            {
                tc.type_modifier((short)2);
            }
            else
            {
                tc.type_modifier((short)0);
            }
            if (parent == null)
            {
                tc.concrete_base_type(TC_NULL);
            }
            else
            {
                // TODO: check validity of this
                tc.concrete_base_type(TC_NULL);
                // tc.concrete_base_type(getTypeCode(parent));
            }
            // TODO: member fields
            tc.member_count(0);
        }
    }

    static long computeStructuralUID(ValueType vt)
    {
        Class c = vt._class;
        ObjectStreamClass osc = vt._objectStreamClass;
        ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
        long h = 0;
        try
        {
            if (! java.io.Serializable.class.isAssignableFrom(c)
                || c.isInterface())
            {
                return 0;
            }
            if (java.io.Externalizable.class.isAssignableFrom(c))
            {
                return 1;
            }
            MessageDigest md = MessageDigest.getInstance("SHA");
            DigestOutputStream mdo = new DigestOutputStream(devnull, md);
            DataOutputStream data = new DataOutputStream(mdo);
            if (vt.parent != null)
            {
                data.writeLong(computeStructuralUID(vt.parent));
            }
            if (vt.hasWriteObject)
            {
                data.writeInt(2);
            }
            else
            {
                data.writeInt(1);
            }
            List fieldList = new ArrayList(vt.fields.length);
            for (int i = 0; i < vt.fields.length; i++)
            {
                fieldList.add(vt.fields[i].javaField);
            }
            Field[] fields = (Field[])fieldList.toArray(new Field[fieldList.size()]);
            Arrays.sort(fields, FieldByNameComparator.SINGLETON);
            for (int i = 0; i < vt.fields.length; i++)
            {
                Field f = fields[i];
                data.writeUTF(f.getName());
                data.writeUTF(JavaClass.getSignature(f.getType()));
            }
            data.flush();
            byte[] hasharray = md.digest();
            for (int i = 0; i < Math.min(8, hasharray.length); i++)
            {
                h += (long)(hasharray[i] & 255) << (i * 8);
            }
            return h;
        }
        catch (Exception ex)
        {
            throw new SystemException(ex);
        }
    }

    /**
     ** Map an RMI/IDL Repository ID to a java.lang.Class.
     **/
    static Class getClass(String id)
    {
        if (id.startsWith("RMI:"))
        {
            int endClass = id.indexOf(':', 4);
            if (endClass == -1)
            {
                throw new org.omg.CORBA.INV_IDENT(id);
            }
            String className = id.substring(4, endClass);
            if (className.equals("javax.rmi.CORBA.ClassDesc"))
            {
                return Class.class;
            }
            else
            {
                return loadClass(className);
            }
        }
        else if (id.equals("IDL:omg.org/CORBA/WStringValue:1.0"))
        {
            return java.lang.String.class;
        }
        else if (id.startsWith("IDL:omg.org/"))
        {
            int endClass = id.indexOf(':', 12);
            if (endClass == -1)
            {
                throw new org.omg.CORBA.INV_IDENT(id);
            }
            String className = "org.omg" + id.substring( "IDL:omg.org".length(), endClass).replace('/', '.');
            return loadClass(className);
        }
        else if (id.startsWith("IDL:"))
        {
            int endClass = id.indexOf(':', 4);
            if (endClass == -1)
            {
                throw new org.omg.CORBA.INV_IDENT(id);
            }
            String className = id.substring(4, endClass).replace('/', '.');
            return loadClass(className);
        }
        else
        {
            throw new org.omg.CORBA.INV_IDENT(id);
        }
    }

    public Class getTheClass()
    {
        return _class;
    }

    static Class loadClass(String className)
    {
        return ThreadContext.loadClass(className);
    }
}
TOP

Related Classes of org.apache.geronimo.interop.rmi.iiop.ValueType

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.