1 /*
   2  * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 /*
  26  * Licensed Materials - Property of IBM
  27  * RMI-IIOP v1.0
  28  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  29  *
  30  */
  31 
  32 package com.sun.corba.se.impl.io;
  33 
  34 import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
  35 import com.sun.org.omg.CORBA.OperationDescription;
  36 import com.sun.org.omg.CORBA.AttributeDescription;
  37 import org.omg.CORBA.ValueMember;
  38 import com.sun.org.omg.CORBA.Initializer;
  39 import org.omg.CORBA.IDLType;
  40 import com.sun.org.omg.CORBA._IDLTypeStub;
  41 import org.omg.CORBA.ORB;
  42 import org.omg.CORBA.TypeCodePackage.*;
  43 import org.omg.CORBA.TypeCode;
  44 import org.omg.CORBA.TCKind;
  45 import java.lang.reflect.*;
  46 import com.sun.corba.se.impl.util.RepositoryId;
  47 import java.util.*;
  48 import javax.rmi.CORBA.Util;
  49 import javax.rmi.CORBA.ValueHandler;
  50 
  51 /**
  52  * Holds utility methods for converting from ObjectStreamClass to
  53  * FullValueDescription and generating typecodes from ObjectStreamClass.
  54  **/
  55 public class ValueUtility {
  56 
  57     public static final short PRIVATE_MEMBER = 0;
  58     public static final short PUBLIC_MEMBER = 1;
  59 
  60     private static final String primitiveConstants[] = {
  61         null,       // tk_null         0
  62         null,           // tk_void         1
  63         "S",            // tk_short        2
  64         "I",            // tk_long         3
  65         "S",            // tk_ushort       4
  66         "I",            // tk_ulong        5
  67         "F",            // tk_float        6
  68         "D",            // tk_double       7
  69         "Z",            // tk_boolean      8
  70         "C",            // tk_char         9
  71         "B",            // tk_octet        10
  72         null,           // tk_any          11
  73         null,           // tk_typecode     12
  74         null,           // tk_principal    13
  75         null,           // tk_objref       14
  76         null,           // tk_struct       15
  77         null,           // tk_union        16
  78         null,           // tk_enum         17
  79         null,           // tk_string       18
  80         null,           // tk_sequence     19
  81         null,           // tk_array        20
  82         null,           // tk_alias        21
  83         null,           // tk_except       22
  84         "J",            // tk_longlong     23
  85         "J",            // tk_ulonglong    24
  86         "D",            // tk_longdouble   25
  87         "C",            // tk_wchar        26
  88         null,           // tk_wstring      27
  89         null,       // tk_fixed        28
  90         null,       // tk_value        29
  91         null,       // tk_value_box    30
  92         null,       // tk_native       31
  93         null,       // tk_abstract_interface 32
  94     };
  95 
  96     static {
  97         sun.corba.SharedSecrets.setJavaCorbaAccess(new sun.corba.JavaCorbaAccess() {
  98             public ValueHandlerImpl newValueHandlerImpl() {
  99                 return ValueHandlerImpl.getInstance();
 100             }
 101         });
 102     }
 103 
 104     public static String getSignature(ValueMember member)
 105         throws ClassNotFoundException {
 106 
 107         // REVISIT.  Can the type be something that is
 108         // non-primitive yet not a value_box, value, or objref?
 109         // If so, should use ObjectStreamClass or throw
 110         // exception.
 111 
 112         if (member.type.kind().value() == TCKind._tk_value_box ||
 113             member.type.kind().value() == TCKind._tk_value ||
 114             member.type.kind().value() == TCKind._tk_objref) {
 115             Class c = RepositoryId.cache.getId(member.id).getClassFromType();
 116             return ObjectStreamClass.getSignature(c);
 117 
 118         } else {
 119 
 120             return primitiveConstants[member.type.kind().value()];
 121         }
 122 
 123     }
 124 
 125     public static FullValueDescription translate(ORB orb, ObjectStreamClass osc, ValueHandler vh){
 126 
 127         // Create FullValueDescription
 128         FullValueDescription result = new FullValueDescription();
 129         Class className = osc.forClass();
 130 
 131         ValueHandlerImpl vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
 132         String repId = vhandler.createForAnyType(className);
 133 
 134         // Set FVD name
 135         result.name = vhandler.getUnqualifiedName(repId);
 136         if (result.name == null)
 137             result.name = "";
 138 
 139         // Set FVD id _REVISIT_ : Manglings
 140         result.id = vhandler.getRMIRepositoryID(className);
 141         if (result.id == null)
 142             result.id = "";
 143 
 144         // Set FVD is_abstract
 145         result.is_abstract = ObjectStreamClassCorbaExt.isAbstractInterface(className);
 146 
 147         // Set FVD is_custom
 148         result.is_custom = osc.hasWriteObject() || osc.isExternalizable();
 149 
 150         // Set FVD defined_in _REVISIT_ : Manglings
 151         result.defined_in = vhandler.getDefinedInId(repId);
 152         if (result.defined_in == null)
 153             result.defined_in = "";
 154 
 155         // Set FVD version
 156         result.version = vhandler.getSerialVersionUID(repId);
 157         if (result.version == null)
 158             result.version = "";
 159 
 160         // Skip FVD operations - N/A
 161         result.operations = new OperationDescription[0];
 162 
 163         // Skip FVD attributed - N/A
 164         result.attributes = new AttributeDescription[0];
 165 
 166         // Set FVD members
 167         // Maps classes to repositoryIDs strings. This is used to detect recursive types.
 168         IdentityKeyValueStack createdIDs = new IdentityKeyValueStack();
 169         // Stores all types created for resolving indirect types at the end.
 170         result.members = translateMembers(orb, osc, vh, createdIDs);
 171 
 172         // Skip FVD initializers - N/A
 173         result.initializers = new Initializer[0];
 174 
 175         Class interfaces[] = osc.forClass().getInterfaces();
 176         int abstractCount = 0;
 177 
 178         // Skip FVD supported_interfaces
 179         result.supported_interfaces =  new String[interfaces.length];
 180         for (int interfaceIndex = 0; interfaceIndex < interfaces.length;
 181              interfaceIndex++) {
 182             result.supported_interfaces[interfaceIndex] =
 183                 vhandler.createForAnyType(interfaces[interfaceIndex]);
 184 
 185             if ((!(java.rmi.Remote.class.isAssignableFrom(interfaces[interfaceIndex]))) ||
 186                 (!Modifier.isPublic(interfaces[interfaceIndex].getModifiers())))
 187                 abstractCount++;
 188         }
 189 
 190         // Skip FVD abstract_base_values - N/A
 191         result.abstract_base_values = new String[abstractCount];
 192         for (int interfaceIndex = 0; interfaceIndex < interfaces.length;
 193              interfaceIndex++) {
 194             if ((!(java.rmi.Remote.class.isAssignableFrom(interfaces[interfaceIndex]))) ||
 195                 (!Modifier.isPublic(interfaces[interfaceIndex].getModifiers())))
 196                 result.abstract_base_values[interfaceIndex] =
 197                     vhandler.createForAnyType(interfaces[interfaceIndex]);
 198 
 199         }
 200 
 201         result.is_truncatable = false;
 202 
 203         // Set FVD base_value
 204         Class superClass = osc.forClass().getSuperclass();
 205         if (java.io.Serializable.class.isAssignableFrom(superClass))
 206             result.base_value = vhandler.getRMIRepositoryID(superClass);
 207         else
 208             result.base_value = "";
 209 
 210         // Set FVD type
 211         //result.type = createTypeCodeForClass(orb, osc.forClass());
 212         result.type = orb.get_primitive_tc(TCKind.tk_value); //11638
 213 
 214         return result;
 215 
 216     }
 217 
 218     private static ValueMember[] translateMembers (ORB orb,
 219                                                    ObjectStreamClass osc,
 220                                                    ValueHandler vh,
 221                                                    IdentityKeyValueStack createdIDs)
 222     {
 223         ValueHandlerImpl vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
 224         ObjectStreamField fields[] = osc.getFields();
 225         int fieldsLength = fields.length;
 226         ValueMember[] members = new ValueMember[fieldsLength];
 227         // Note : fields come out of ObjectStreamClass in correct order for
 228         // writing.  So, we will create the same order in the members array.
 229         for (int i = 0; i < fieldsLength; i++) {
 230             String valRepId = vhandler.getRMIRepositoryID(fields[i].getClazz());
 231             members[i] = new ValueMember();
 232             members[i].name = fields[i].getName();
 233             members[i].id = valRepId; // _REVISIT_ : Manglings
 234             members[i].defined_in = vhandler.getDefinedInId(valRepId);// _REVISIT_ : Manglings
 235             members[i].version = "1.0";
 236             members[i].type_def = new _IDLTypeStub(); // _REVISIT_ : IDLType implementation missing
 237 
 238             if (fields[i].getField() == null) {
 239                 // When using serialPersistentFields, the class may
 240                 // no longer have an actual Field that corresponds
 241                 // to one of the items.  The Java to IDL spec
 242                 // ptc-00-01-06 1.3.5.6 says that the IDL field
 243                 // should be private in this case.
 244                 members[i].access = PRIVATE_MEMBER;
 245             } else {
 246                 int m = fields[i].getField().getModifiers();
 247                 if (Modifier.isPublic(m))
 248                     members[i].access = PUBLIC_MEMBER;
 249                 else
 250                     members[i].access = PRIVATE_MEMBER;
 251             }
 252 
 253             switch (fields[i].getTypeCode()) {
 254             case 'B':
 255                 members[i].type = orb.get_primitive_tc(TCKind.tk_octet); //11638
 256                 break;
 257             case 'C':
 258                 members[i].type
 259                     = orb.get_primitive_tc(vhandler.getJavaCharTCKind()); // 11638
 260                 break;
 261             case 'F':
 262                 members[i].type = orb.get_primitive_tc(TCKind.tk_float); //11638
 263                 break;
 264             case 'D' :
 265                 members[i].type = orb.get_primitive_tc(TCKind.tk_double); //11638
 266                 break;
 267             case 'I':
 268                 members[i].type = orb.get_primitive_tc(TCKind.tk_long); //11638
 269                 break;
 270             case 'J':
 271                 members[i].type = orb.get_primitive_tc(TCKind.tk_longlong); //11638
 272                 break;
 273             case 'S':
 274                 members[i].type = orb.get_primitive_tc(TCKind.tk_short); //11638
 275                 break;
 276             case 'Z':
 277                 members[i].type = orb.get_primitive_tc(TCKind.tk_boolean); //11638
 278                 break;
 279         // case '[':
 280         //      members[i].type = orb.get_primitive_tc(TCKind.tk_value_box); //11638
 281         //      members[i].id = RepositoryId.createForAnyType(fields[i].getType());
 282         //      break;
 283             default:
 284                 members[i].type = createTypeCodeForClassInternal(orb, fields[i].getClazz(), vhandler,
 285                                   createdIDs);
 286                 members[i].id = vhandler.createForAnyType(fields[i].getType());
 287                 break;
 288             } // end switch
 289 
 290         } // end for loop
 291 
 292         return members;
 293     }
 294 
 295     private static boolean exists(String str, String strs[]){
 296         for (int i = 0; i < strs.length; i++)
 297             if (str.equals(strs[i]))
 298                 return true;
 299 
 300         return false;
 301     }
 302 
 303     public static boolean isAssignableFrom(String clzRepositoryId, FullValueDescription type,
 304                                            com.sun.org.omg.SendingContext.CodeBase sender){
 305 
 306         if (exists(clzRepositoryId, type.supported_interfaces))
 307             return true;
 308 
 309         if (clzRepositoryId.equals(type.id))
 310             return true;
 311 
 312         if ((type.base_value != null) &&
 313             (!type.base_value.equals(""))) {
 314             FullValueDescription parent = sender.meta(type.base_value);
 315 
 316             return isAssignableFrom(clzRepositoryId, parent, sender);
 317         }
 318 
 319         return false;
 320 
 321     }
 322 
 323     public static TypeCode createTypeCodeForClass (ORB orb, java.lang.Class c, ValueHandler vh) {
 324         // Maps classes to repositoryIDs strings. This is used to detect recursive types.
 325         IdentityKeyValueStack createdIDs = new IdentityKeyValueStack();
 326         // Stores all types created for resolving indirect types at the end.
 327         TypeCode tc = createTypeCodeForClassInternal(orb, c, vh, createdIDs);
 328         return tc;
 329     }
 330 
 331     private static TypeCode createTypeCodeForClassInternal (ORB orb,
 332                                                             java.lang.Class c,
 333                                                             ValueHandler vh,
 334                                                             IdentityKeyValueStack createdIDs)
 335     {
 336         // This wrapper method is the protection against infinite recursion.
 337         TypeCode tc = null;
 338         String id = (String)createdIDs.get(c);
 339         if (id != null) {
 340             return orb.create_recursive_tc(id);
 341         } else {
 342             id = vh.getRMIRepositoryID(c);
 343             if (id == null) id = "";
 344             // cache the rep id BEFORE creating a new typecode.
 345             // so that recursive tc can look up the rep id.
 346             createdIDs.push(c, id);
 347             tc = createTypeCodeInternal(orb, c, vh, id, createdIDs);
 348             createdIDs.pop();
 349             return tc;
 350         }
 351     }
 352 
 353     // Maintains a stack of key-value pairs. Compares elements using == operator.
 354     private static class IdentityKeyValueStack {
 355         private static class KeyValuePair {
 356             Object key;
 357             Object value;
 358             KeyValuePair(Object key, Object value) {
 359                 this.key = key;
 360                 this.value = value;
 361             }
 362             boolean equals(KeyValuePair pair) {
 363                 return pair.key == this.key;
 364             }
 365         }
 366 
 367         Stack pairs = null;
 368 
 369         Object get(Object key) {
 370             if (pairs == null) {
 371                 return null;
 372             }
 373             for (Iterator i = pairs.iterator(); i.hasNext();) {
 374                 KeyValuePair pair = (KeyValuePair)i.next();
 375                 if (pair.key == key) {
 376                     return pair.value;
 377                 }
 378             }
 379             return null;
 380         }
 381 
 382         void push(Object key, Object value) {
 383             if (pairs == null) {
 384                 pairs = new Stack();
 385             }
 386             pairs.push(new KeyValuePair(key, value));
 387         }
 388 
 389         void pop() {
 390             pairs.pop();
 391         }
 392     }
 393 
 394     private static TypeCode createTypeCodeInternal (ORB orb,
 395                                                     java.lang.Class c,
 396                                                     ValueHandler vh,
 397                                                     String id,
 398                                                     IdentityKeyValueStack createdIDs)
 399     {
 400         if ( c.isArray() ) {
 401             // Arrays - may recurse for multi-dimensional arrays
 402             Class componentClass = c.getComponentType();
 403             TypeCode embeddedType;
 404             if ( componentClass.isPrimitive() ){
 405                 embeddedType
 406                     = ValueUtility.getPrimitiveTypeCodeForClass(orb,
 407                                                                 componentClass,
 408                                                                 vh);
 409             } else {
 410                 embeddedType = createTypeCodeForClassInternal(orb, componentClass, vh,
 411                                                               createdIDs);
 412             }
 413             TypeCode t = orb.create_sequence_tc (0, embeddedType);
 414             return orb.create_value_box_tc (id, "Sequence", t);
 415         } else if ( c == java.lang.String.class ) {
 416             // Strings
 417             TypeCode t = orb.create_string_tc (0);
 418             return orb.create_value_box_tc (id, "StringValue", t);
 419         } else if (java.rmi.Remote.class.isAssignableFrom(c)) {
 420             return orb.get_primitive_tc(TCKind.tk_objref);
 421         } else if (org.omg.CORBA.Object.class.isAssignableFrom(c)) {
 422             return orb.get_primitive_tc(TCKind.tk_objref);
 423         }
 424 
 425         // Anything else
 426 
 427         ObjectStreamClass osc = ObjectStreamClass.lookup(c);
 428 
 429         if (osc == null) {
 430             return orb.create_value_box_tc (id, "Value", orb.get_primitive_tc (TCKind.tk_value));
 431         }
 432 
 433         // type modifier
 434         // REVISIT truncatable and abstract?
 435         short modifier = (osc.isCustomMarshaled() ? org.omg.CORBA.VM_CUSTOM.value : org.omg.CORBA.VM_NONE.value);
 436 
 437         // concrete base
 438         TypeCode base = null;
 439         Class superClass = c.getSuperclass();
 440         if (superClass != null && java.io.Serializable.class.isAssignableFrom(superClass)) {
 441             base = createTypeCodeForClassInternal(orb, superClass, vh, createdIDs);
 442         }
 443 
 444         // members
 445         ValueMember[] members = translateMembers (orb, osc, vh, createdIDs);
 446 
 447         return orb.create_value_tc(id, c.getName(), modifier, base, members);
 448     }
 449 
 450     public static TypeCode getPrimitiveTypeCodeForClass (ORB orb,
 451                                                          Class c,
 452                                                          ValueHandler vh) {
 453 
 454         if (c == Integer.TYPE) {
 455             return orb.get_primitive_tc (TCKind.tk_long);
 456         } else if (c == Byte.TYPE) {
 457             return orb.get_primitive_tc (TCKind.tk_octet);
 458         } else if (c == Long.TYPE) {
 459             return orb.get_primitive_tc (TCKind.tk_longlong);
 460         } else if (c == Float.TYPE) {
 461             return orb.get_primitive_tc (TCKind.tk_float);
 462         } else if (c == Double.TYPE) {
 463             return orb.get_primitive_tc (TCKind.tk_double);
 464         } else if (c == Short.TYPE) {
 465             return orb.get_primitive_tc (TCKind.tk_short);
 466         } else if (c == Character.TYPE) {
 467             return orb.get_primitive_tc (((ValueHandlerImpl)vh).getJavaCharTCKind());
 468         } else if (c == Boolean.TYPE) {
 469             return orb.get_primitive_tc (TCKind.tk_boolean);
 470         } else {
 471             // _REVISIT_ Not sure if this is right.
 472             return orb.get_primitive_tc (TCKind.tk_any);
 473         }
 474     }
 475 }