/*
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 * Licensed Materials - Property of IBM
 * RMI-IIOP v1.0
 * Copyright IBM Corp. 1998 1999  All Rights Reserved
 *
 */

package com.sun.corba.se.impl.io;

import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
import com.sun.org.omg.CORBA.OperationDescription;
import com.sun.org.omg.CORBA.AttributeDescription;
import org.omg.CORBA.ValueMember;
import com.sun.org.omg.CORBA.Initializer;
import org.omg.CORBA.IDLType;
import com.sun.org.omg.CORBA._IDLTypeStub;
import org.omg.CORBA.ORB;
import org.omg.CORBA.TypeCodePackage.*;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TCKind;
import java.lang.reflect.*;
import com.sun.corba.se.impl.util.RepositoryId;
import java.util.*;
import javax.rmi.CORBA.Util;
import javax.rmi.CORBA.ValueHandler;

Holds utility methods for converting from ObjectStreamClass to FullValueDescription and generating typecodes from ObjectStreamClass.
/** * Holds utility methods for converting from ObjectStreamClass to * FullValueDescription and generating typecodes from ObjectStreamClass. **/
public class ValueUtility { public static final short PRIVATE_MEMBER = 0; public static final short PUBLIC_MEMBER = 1; private static final String primitiveConstants[] = { null, // tk_null 0 null, // tk_void 1 "S", // tk_short 2 "I", // tk_long 3 "S", // tk_ushort 4 "I", // tk_ulong 5 "F", // tk_float 6 "D", // tk_double 7 "Z", // tk_boolean 8 "C", // tk_char 9 "B", // tk_octet 10 null, // tk_any 11 null, // tk_typecode 12 null, // tk_principal 13 null, // tk_objref 14 null, // tk_struct 15 null, // tk_union 16 null, // tk_enum 17 null, // tk_string 18 null, // tk_sequence 19 null, // tk_array 20 null, // tk_alias 21 null, // tk_except 22 "J", // tk_longlong 23 "J", // tk_ulonglong 24 "D", // tk_longdouble 25 "C", // tk_wchar 26 null, // tk_wstring 27 null, // tk_fixed 28 null, // tk_value 29 null, // tk_value_box 30 null, // tk_native 31 null, // tk_abstract_interface 32 }; static { sun.corba.SharedSecrets.setJavaCorbaAccess(new sun.corba.JavaCorbaAccess() { public ValueHandlerImpl newValueHandlerImpl() { return ValueHandlerImpl.getInstance(); } public Class<?> loadClass(String className) throws ClassNotFoundException { if (Thread.currentThread().getContextClassLoader() != null) { return Thread.currentThread().getContextClassLoader(). loadClass(className); } else { return ClassLoader.getSystemClassLoader().loadClass(className); } } }); } public static String getSignature(ValueMember member) throws ClassNotFoundException { // REVISIT. Can the type be something that is // non-primitive yet not a value_box, value, or objref? // If so, should use ObjectStreamClass or throw // exception. if (member.type.kind().value() == TCKind._tk_value_box || member.type.kind().value() == TCKind._tk_value || member.type.kind().value() == TCKind._tk_objref) { Class c = RepositoryId.cache.getId(member.id).getClassFromType(); return ObjectStreamClass.getSignature(c); } else { return primitiveConstants[member.type.kind().value()]; } } public static FullValueDescription translate(ORB orb, ObjectStreamClass osc, ValueHandler vh){ // Create FullValueDescription FullValueDescription result = new FullValueDescription(); Class className = osc.forClass(); ValueHandlerImpl vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh; String repId = vhandler.createForAnyType(className); // Set FVD name result.name = vhandler.getUnqualifiedName(repId); if (result.name == null) result.name = ""; // Set FVD id _REVISIT_ : Manglings result.id = vhandler.getRMIRepositoryID(className); if (result.id == null) result.id = ""; // Set FVD is_abstract result.is_abstract = ObjectStreamClassCorbaExt.isAbstractInterface(className); // Set FVD is_custom result.is_custom = osc.hasWriteObject() || osc.isExternalizable(); // Set FVD defined_in _REVISIT_ : Manglings result.defined_in = vhandler.getDefinedInId(repId); if (result.defined_in == null) result.defined_in = ""; // Set FVD version result.version = vhandler.getSerialVersionUID(repId); if (result.version == null) result.version = ""; // Skip FVD operations - N/A result.operations = new OperationDescription[0]; // Skip FVD attributed - N/A result.attributes = new AttributeDescription[0]; // Set FVD members // Maps classes to repositoryIDs strings. This is used to detect recursive types. IdentityKeyValueStack createdIDs = new IdentityKeyValueStack(); // Stores all types created for resolving indirect types at the end. result.members = translateMembers(orb, osc, vh, createdIDs); // Skip FVD initializers - N/A result.initializers = new Initializer[0]; Class interfaces[] = osc.forClass().getInterfaces(); int abstractCount = 0; // Skip FVD supported_interfaces result.supported_interfaces = new String[interfaces.length]; for (int interfaceIndex = 0; interfaceIndex < interfaces.length; interfaceIndex++) { result.supported_interfaces[interfaceIndex] = vhandler.createForAnyType(interfaces[interfaceIndex]); if ((!(java.rmi.Remote.class.isAssignableFrom(interfaces[interfaceIndex]))) || (!Modifier.isPublic(interfaces[interfaceIndex].getModifiers()))) abstractCount++; } // Skip FVD abstract_base_values - N/A result.abstract_base_values = new String[abstractCount]; for (int interfaceIndex = 0; interfaceIndex < interfaces.length; interfaceIndex++) { if ((!(java.rmi.Remote.class.isAssignableFrom(interfaces[interfaceIndex]))) || (!Modifier.isPublic(interfaces[interfaceIndex].getModifiers()))) result.abstract_base_values[interfaceIndex] = vhandler.createForAnyType(interfaces[interfaceIndex]); } result.is_truncatable = false; // Set FVD base_value Class superClass = osc.forClass().getSuperclass(); if (java.io.Serializable.class.isAssignableFrom(superClass)) result.base_value = vhandler.getRMIRepositoryID(superClass); else result.base_value = ""; // Set FVD type //result.type = createTypeCodeForClass(orb, osc.forClass()); result.type = orb.get_primitive_tc(TCKind.tk_value); //11638 return result; } private static ValueMember[] translateMembers (ORB orb, ObjectStreamClass osc, ValueHandler vh, IdentityKeyValueStack createdIDs) { ValueHandlerImpl vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh; ObjectStreamField fields[] = osc.getFields(); int fieldsLength = fields.length; ValueMember[] members = new ValueMember[fieldsLength]; // Note : fields come out of ObjectStreamClass in correct order for // writing. So, we will create the same order in the members array. for (int i = 0; i < fieldsLength; i++) { String valRepId = vhandler.getRMIRepositoryID(fields[i].getClazz()); members[i] = new ValueMember(); members[i].name = fields[i].getName(); members[i].id = valRepId; // _REVISIT_ : Manglings members[i].defined_in = vhandler.getDefinedInId(valRepId);// _REVISIT_ : Manglings members[i].version = "1.0"; members[i].type_def = new _IDLTypeStub(); // _REVISIT_ : IDLType implementation missing if (fields[i].getField() == null) { // When using serialPersistentFields, the class may // no longer have an actual Field that corresponds // to one of the items. The Java to IDL spec // ptc-00-01-06 1.3.5.6 says that the IDL field // should be private in this case. members[i].access = PRIVATE_MEMBER; } else { int m = fields[i].getField().getModifiers(); if (Modifier.isPublic(m)) members[i].access = PUBLIC_MEMBER; else members[i].access = PRIVATE_MEMBER; } switch (fields[i].getTypeCode()) { case 'B': members[i].type = orb.get_primitive_tc(TCKind.tk_octet); //11638 break; case 'C': members[i].type = orb.get_primitive_tc(vhandler.getJavaCharTCKind()); // 11638 break; case 'F': members[i].type = orb.get_primitive_tc(TCKind.tk_float); //11638 break; case 'D' : members[i].type = orb.get_primitive_tc(TCKind.tk_double); //11638 break; case 'I': members[i].type = orb.get_primitive_tc(TCKind.tk_long); //11638 break; case 'J': members[i].type = orb.get_primitive_tc(TCKind.tk_longlong); //11638 break; case 'S': members[i].type = orb.get_primitive_tc(TCKind.tk_short); //11638 break; case 'Z': members[i].type = orb.get_primitive_tc(TCKind.tk_boolean); //11638 break; // case '[': // members[i].type = orb.get_primitive_tc(TCKind.tk_value_box); //11638 // members[i].id = RepositoryId.createForAnyType(fields[i].getType()); // break; default: members[i].type = createTypeCodeForClassInternal(orb, fields[i].getClazz(), vhandler, createdIDs); members[i].id = vhandler.createForAnyType(fields[i].getType()); break; } // end switch } // end for loop return members; } private static boolean exists(String str, String strs[]){ for (int i = 0; i < strs.length; i++) if (str.equals(strs[i])) return true; return false; } public static boolean isAssignableFrom(String clzRepositoryId, FullValueDescription type, com.sun.org.omg.SendingContext.CodeBase sender){ if (exists(clzRepositoryId, type.supported_interfaces)) return true; if (clzRepositoryId.equals(type.id)) return true; if ((type.base_value != null) && (!type.base_value.equals(""))) { FullValueDescription parent = sender.meta(type.base_value); return isAssignableFrom(clzRepositoryId, parent, sender); } return false; } public static TypeCode createTypeCodeForClass (ORB orb, java.lang.Class c, ValueHandler vh) { // Maps classes to repositoryIDs strings. This is used to detect recursive types. IdentityKeyValueStack createdIDs = new IdentityKeyValueStack(); // Stores all types created for resolving indirect types at the end. TypeCode tc = createTypeCodeForClassInternal(orb, c, vh, createdIDs); return tc; } private static TypeCode createTypeCodeForClassInternal (ORB orb, java.lang.Class c, ValueHandler vh, IdentityKeyValueStack createdIDs) { // This wrapper method is the protection against infinite recursion. TypeCode tc = null; String id = (String)createdIDs.get(c); if (id != null) { return orb.create_recursive_tc(id); } else { id = vh.getRMIRepositoryID(c); if (id == null) id = ""; // cache the rep id BEFORE creating a new typecode. // so that recursive tc can look up the rep id. createdIDs.push(c, id); tc = createTypeCodeInternal(orb, c, vh, id, createdIDs); createdIDs.pop(); return tc; } } // Maintains a stack of key-value pairs. Compares elements using == operator. private static class IdentityKeyValueStack { private static class KeyValuePair { Object key; Object value; KeyValuePair(Object key, Object value) { this.key = key; this.value = value; } boolean equals(KeyValuePair pair) { return pair.key == this.key; } } Stack pairs = null; Object get(Object key) { if (pairs == null) { return null; } for (Iterator i = pairs.iterator(); i.hasNext();) { KeyValuePair pair = (KeyValuePair)i.next(); if (pair.key == key) { return pair.value; } } return null; } void push(Object key, Object value) { if (pairs == null) { pairs = new Stack(); } pairs.push(new KeyValuePair(key, value)); } void pop() { pairs.pop(); } } private static TypeCode createTypeCodeInternal (ORB orb, java.lang.Class c, ValueHandler vh, String id, IdentityKeyValueStack createdIDs) { if ( c.isArray() ) { // Arrays - may recurse for multi-dimensional arrays Class componentClass = c.getComponentType(); TypeCode embeddedType; if ( componentClass.isPrimitive() ){ embeddedType = ValueUtility.getPrimitiveTypeCodeForClass(orb, componentClass, vh); } else { embeddedType = createTypeCodeForClassInternal(orb, componentClass, vh, createdIDs); } TypeCode t = orb.create_sequence_tc (0, embeddedType); return orb.create_value_box_tc (id, "Sequence", t); } else if ( c == java.lang.String.class ) { // Strings TypeCode t = orb.create_string_tc (0); return orb.create_value_box_tc (id, "StringValue", t); } else if (java.rmi.Remote.class.isAssignableFrom(c)) { return orb.get_primitive_tc(TCKind.tk_objref); } else if (org.omg.CORBA.Object.class.isAssignableFrom(c)) { return orb.get_primitive_tc(TCKind.tk_objref); } // Anything else ObjectStreamClass osc = ObjectStreamClass.lookup(c); if (osc == null) { return orb.create_value_box_tc (id, "Value", orb.get_primitive_tc (TCKind.tk_value)); } // type modifier // REVISIT truncatable and abstract? short modifier = (osc.isCustomMarshaled() ? org.omg.CORBA.VM_CUSTOM.value : org.omg.CORBA.VM_NONE.value); // concrete base TypeCode base = null; Class superClass = c.getSuperclass(); if (superClass != null && java.io.Serializable.class.isAssignableFrom(superClass)) { base = createTypeCodeForClassInternal(orb, superClass, vh, createdIDs); } // members ValueMember[] members = translateMembers (orb, osc, vh, createdIDs); return orb.create_value_tc(id, c.getName(), modifier, base, members); } public static TypeCode getPrimitiveTypeCodeForClass (ORB orb, Class c, ValueHandler vh) { if (c == Integer.TYPE) { return orb.get_primitive_tc (TCKind.tk_long); } else if (c == Byte.TYPE) { return orb.get_primitive_tc (TCKind.tk_octet); } else if (c == Long.TYPE) { return orb.get_primitive_tc (TCKind.tk_longlong); } else if (c == Float.TYPE) { return orb.get_primitive_tc (TCKind.tk_float); } else if (c == Double.TYPE) { return orb.get_primitive_tc (TCKind.tk_double); } else if (c == Short.TYPE) { return orb.get_primitive_tc (TCKind.tk_short); } else if (c == Character.TYPE) { return orb.get_primitive_tc (((ValueHandlerImpl)vh).getJavaCharTCKind()); } else if (c == Boolean.TYPE) { return orb.get_primitive_tc (TCKind.tk_boolean); } else { // _REVISIT_ Not sure if this is right. return orb.get_primitive_tc (TCKind.tk_any); } } }