/*
* Copyright (c) 1999, 2002, 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 org.jboss.com.sun.corba.se.impl.io;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Stack;
import javax.rmi.CORBA.ValueHandler;
import org.omg.CORBA.ORB;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.ValueMember;
import org.jboss.com.sun.corba.se.impl.util.RepositoryId;
import org.jboss.com.sun.org.omg.CORBA.AttributeDescription;
import org.jboss.com.sun.org.omg.CORBA.Initializer;
import org.jboss.com.sun.org.omg.CORBA.OperationDescription;
import org.jboss.com.sun.org.omg.CORBA._IDLTypeStub;
import org.jboss.com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
/**
* 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
};
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 = (org.jboss.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 = (org.jboss.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,
org.jboss.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, 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, 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;
}
@SuppressWarnings("unused")
boolean equals(KeyValuePair pair)
{
return pair.key == this.key;
}
}
Stack<KeyValuePair> pairs = null;
Object get(Object key)
{
if (pairs == null)
{
return null;
}
for (Iterator<KeyValuePair> i = pairs.iterator(); i.hasNext();)
{
KeyValuePair pair = i.next();
if (pair.key == key)
{
return pair.value;
}
}
return null;
}
void push(Object key, Object value)
{
if (pairs == null)
{
pairs = new Stack<KeyValuePair>();
}
pairs.push(new KeyValuePair(key, value));
}
void pop()
{
pairs.pop();
}
}
private static TypeCode createTypeCodeInternal(ORB orb, 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);
}
}
}