1 /*
   2  * Copyright (c) 1999, 2013, 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             public Class<?> loadClass(String className) throws ClassNotFoundException {
 102                 if (Thread.currentThread().getContextClassLoader() != null) {
 103                     return Thread.currentThread().getContextClassLoader().
 104                         loadClass(className);
 105                 } else {
 106                     return ClassLoader.getSystemClassLoader().loadClass(className);
 107                 }
 108             }
 109         });
 110     }
 111 
 112     public static String getSignature(ValueMember member)
 113         throws ClassNotFoundException {
 114 
 115         // REVISIT.  Can the type be something that is
 116         // non-primitive yet not a value_box, value, or objref?
 117         // If so, should use ObjectStreamClass or throw
 118         // exception.
 119 
 120         if (member.type.kind().value() == TCKind._tk_value_box ||
 121             member.type.kind().value() == TCKind._tk_value ||
 122             member.type.kind().value() == TCKind._tk_objref) {
 123             Class c = RepositoryId.cache.getId(member.id).getClassFromType();
 124             return ObjectStreamClass.getSignature(c);
 125 
 126         } else {
 127 
 128             return primitiveConstants[member.type.kind().value()];
 129         }
 130 
 131     }
 132 
 133     public static FullValueDescription translate(ORB orb, ObjectStreamClass osc, ValueHandler vh){
 134 
 135         // Create FullValueDescription
 136         FullValueDescription result = new FullValueDescription();
 137         Class className = osc.forClass();
 138 
 139         ValueHandlerImpl vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
 140         String repId = vhandler.createForAnyType(className);
 141 
 142         // Set FVD name
 143         result.name = vhandler.getUnqualifiedName(repId);
 144         if (result.name == null)
 145             result.name = "";
 146 
 147         // Set FVD id _REVISIT_ : Manglings
 148         result.id = vhandler.getRMIRepositoryID(className);
 149         if (result.id == null)
 150             result.id = "";
 151 
 152         // Set FVD is_abstract
 153         result.is_abstract = ObjectStreamClassCorbaExt.isAbstractInterface(className);
 154 
 155         // Set FVD is_custom
 156         result.is_custom = osc.hasWriteObject() || osc.isExternalizable();
 157 
 158         // Set FVD defined_in _REVISIT_ : Manglings
 159         result.defined_in = vhandler.getDefinedInId(repId);
 160         if (result.defined_in == null)
 161             result.defined_in = "";
 162 
 163         // Set FVD version
 164         result.version = vhandler.getSerialVersionUID(repId);
 165         if (result.version == null)
 166             result.version = "";
 167 
 168         // Skip FVD operations - N/A
 169         result.operations = new OperationDescription[0];
 170 
 171         // Skip FVD attributed - N/A
 172         result.attributes = new AttributeDescription[0];
 173 
 174         // Set FVD members
 175         // Maps classes to repositoryIDs strings. This is used to detect recursive types.
 176         IdentityKeyValueStack createdIDs = new IdentityKeyValueStack();
 177         // Stores all types created for resolving indirect types at the end.
 178         result.members = translateMembers(orb, osc, vh, createdIDs);
 179 
 180         // Skip FVD initializers - N/A
 181         result.initializers = new Initializer[0];
 182 
 183         Class interfaces[] = osc.forClass().getInterfaces();
 184         int abstractCount = 0;
 185 
 186         // Skip FVD supported_interfaces
 187         result.supported_interfaces =  new String[interfaces.length];
 188         for (int interfaceIndex = 0; interfaceIndex < interfaces.length;
 189              interfaceIndex++) {
 190             result.supported_interfaces[interfaceIndex] =
 191                 vhandler.createForAnyType(interfaces[interfaceIndex]);
 192 
 193             if ((!(java.rmi.Remote.class.isAssignableFrom(interfaces[interfaceIndex]))) ||
 194                 (!Modifier.isPublic(interfaces[interfaceIndex].getModifiers())))
 195                 abstractCount++;
 196         }
 197 
 198         // Skip FVD abstract_base_values - N/A
 199         result.abstract_base_values = new String[abstractCount];
 200         for (int interfaceIndex = 0; interfaceIndex < interfaces.length;
 201              interfaceIndex++) {
 202             if ((!(java.rmi.Remote.class.isAssignableFrom(interfaces[interfaceIndex]))) ||
 203                 (!Modifier.isPublic(interfaces[interfaceIndex].getModifiers())))
 204                 result.abstract_base_values[interfaceIndex] =
 205                     vhandler.createForAnyType(interfaces[interfaceIndex]);
 206 
 207         }
 208 
 209         result.is_truncatable = false;
 210 
 211         // Set FVD base_value
 212         Class superClass = osc.forClass().getSuperclass();
 213         if (java.io.Serializable.class.isAssignableFrom(superClass))
 214             result.base_value = vhandler.getRMIRepositoryID(superClass);
 215         else
 216             result.base_value = "";
 217 
 218         // Set FVD type
 219         //result.type = createTypeCodeForClass(orb, osc.forClass());
 220         result.type = orb.get_primitive_tc(TCKind.tk_value); //11638
 221 
 222         return result;
 223 
 224     }
 225 
 226     private static ValueMember[] translateMembers (ORB orb,
 227                                                    ObjectStreamClass osc,
 228                                                    ValueHandler vh,
 229                                                    IdentityKeyValueStack createdIDs)
 230     {
 231         ValueHandlerImpl vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
 232         ObjectStreamField fields[] = osc.getFields();
 233         int fieldsLength = fields.length;
 234         ValueMember[] members = new ValueMember[fieldsLength];
 235         // Note : fields come out of ObjectStreamClass in correct order for
 236         // writing.  So, we will create the same order in the members array.
 237         for (int i = 0; i < fieldsLength; i++) {
 238             String valRepId = vhandler.getRMIRepositoryID(fields[i].getClazz());
 239             members[i] = new ValueMember();
 240             members[i].name = fields[i].getName();
 241             members[i].id = valRepId; // _REVISIT_ : Manglings
 242             members[i].defined_in = vhandler.getDefinedInId(valRepId);// _REVISIT_ : Manglings
 243             members[i].version = "1.0";
 244             members[i].type_def = new _IDLTypeStub(); // _REVISIT_ : IDLType implementation missing
 245 
 246             if (fields[i].getField() == null) {
 247                 // When using serialPersistentFields, the class may
 248                 // no longer have an actual Field that corresponds
 249                 // to one of the items.  The Java to IDL spec
 250                 // ptc-00-01-06 1.3.5.6 says that the IDL field
 251                 // should be private in this case.
 252                 members[i].access = PRIVATE_MEMBER;
 253             } else {
 254                 int m = fields[i].getField().getModifiers();
 255                 if (Modifier.isPublic(m))
 256                     members[i].access = PUBLIC_MEMBER;
 257                 else
 258                     members[i].access = PRIVATE_MEMBER;
 259             }
 260 
 261             switch (fields[i].getTypeCode()) {
 262             case 'B':
 263                 members[i].type = orb.get_primitive_tc(TCKind.tk_octet); //11638
 264                 break;
 265             case 'C':
 266                 members[i].type
 267                     = orb.get_primitive_tc(vhandler.getJavaCharTCKind()); // 11638
 268                 break;
 269             case 'F':
 270                 members[i].type = orb.get_primitive_tc(TCKind.tk_float); //11638
 271                 break;
 272             case 'D' :
 273                 members[i].type = orb.get_primitive_tc(TCKind.tk_double); //11638
 274                 break;
 275             case 'I':
 276                 members[i].type = orb.get_primitive_tc(TCKind.tk_long); //11638
 277                 break;
 278             case 'J':
 279                 members[i].type = orb.get_primitive_tc(TCKind.tk_longlong); //11638
 280                 break;
 281             case 'S':
 282                 members[i].type = orb.get_primitive_tc(TCKind.tk_short); //11638
 283                 break;
 284             case 'Z':
 285                 members[i].type = orb.get_primitive_tc(TCKind.tk_boolean); //11638
 286                 break;
 287         // case '[':
 288         //      members[i].type = orb.get_primitive_tc(TCKind.tk_value_box); //11638
 289         //      members[i].id = RepositoryId.createForAnyType(fields[i].getType());
 290         //      break;
 291             default:
 292                 members[i].type = createTypeCodeForClassInternal(orb, fields[i].getClazz(), vhandler,
 293                                   createdIDs);
 294                 members[i].id = vhandler.createForAnyType(fields[i].getType());
 295                 break;
 296             } // end switch
 297 
 298         } // end for loop
 299 
 300         return members;
 301     }
 302 
 303     private static boolean exists(String str, String strs[]){
 304         for (int i = 0; i < strs.length; i++)
 305             if (str.equals(strs[i]))
 306                 return true;
 307 
 308         return false;
 309     }
 310 
 311     public static boolean isAssignableFrom(String clzRepositoryId, FullValueDescription type,
 312                                            com.sun.org.omg.SendingContext.CodeBase sender){
 313 
 314         if (exists(clzRepositoryId, type.supported_interfaces))
 315             return true;
 316 
 317         if (clzRepositoryId.equals(type.id))
 318             return true;
 319 
 320         if ((type.base_value != null) &&
 321             (!type.base_value.equals(""))) {
 322             FullValueDescription parent = sender.meta(type.base_value);
 323 
 324             return isAssignableFrom(clzRepositoryId, parent, sender);
 325         }
 326 
 327         return false;
 328 
 329     }
 330 
 331     public static TypeCode createTypeCodeForClass (ORB orb, java.lang.Class c, ValueHandler vh) {
 332         // Maps classes to repositoryIDs strings. This is used to detect recursive types.
 333         IdentityKeyValueStack createdIDs = new IdentityKeyValueStack();
 334         // Stores all types created for resolving indirect types at the end.
 335         TypeCode tc = createTypeCodeForClassInternal(orb, c, vh, createdIDs);
 336         return tc;
 337     }
 338 
 339     private static TypeCode createTypeCodeForClassInternal (ORB orb,
 340                                                             java.lang.Class c,
 341                                                             ValueHandler vh,
 342                                                             IdentityKeyValueStack createdIDs)
 343     {
 344         // This wrapper method is the protection against infinite recursion.
 345         TypeCode tc = null;
 346         String id = (String)createdIDs.get(c);
 347         if (id != null) {
 348             return orb.create_recursive_tc(id);
 349         } else {
 350             id = vh.getRMIRepositoryID(c);
 351             if (id == null) id = "";
 352             // cache the rep id BEFORE creating a new typecode.
 353             // so that recursive tc can look up the rep id.
 354             createdIDs.push(c, id);
 355             tc = createTypeCodeInternal(orb, c, vh, id, createdIDs);
 356             createdIDs.pop();
 357             return tc;
 358         }
 359     }
 360 
 361     // Maintains a stack of key-value pairs. Compares elements using == operator.
 362     private static class IdentityKeyValueStack {
 363         private static class KeyValuePair {
 364             Object key;
 365             Object value;
 366             KeyValuePair(Object key, Object value) {
 367                 this.key = key;
 368                 this.value = value;
 369             }
 370             boolean equals(KeyValuePair pair) {
 371                 return pair.key == this.key;
 372             }
 373         }
 374 
 375         Stack pairs = null;
 376 
 377         Object get(Object key) {
 378             if (pairs == null) {
 379                 return null;
 380             }
 381             for (Iterator i = pairs.iterator(); i.hasNext();) {
 382                 KeyValuePair pair = (KeyValuePair)i.next();
 383                 if (pair.key == key) {
 384                     return pair.value;
 385                 }
 386             }
 387             return null;
 388         }
 389 
 390         void push(Object key, Object value) {
 391             if (pairs == null) {
 392                 pairs = new Stack();
 393             }
 394             pairs.push(new KeyValuePair(key, value));
 395         }
 396 
 397         void pop() {
 398             pairs.pop();
 399         }
 400     }
 401 
 402     private static TypeCode createTypeCodeInternal (ORB orb,
 403                                                     java.lang.Class c,
 404                                                     ValueHandler vh,
 405                                                     String id,
 406                                                     IdentityKeyValueStack createdIDs)
 407     {
 408         if ( c.isArray() ) {
 409             // Arrays - may recurse for multi-dimensional arrays
 410             Class componentClass = c.getComponentType();
 411             TypeCode embeddedType;
 412             if ( componentClass.isPrimitive() ){
 413                 embeddedType
 414                     = ValueUtility.getPrimitiveTypeCodeForClass(orb,
 415                                                                 componentClass,
 416                                                                 vh);
 417             } else {
 418                 embeddedType = createTypeCodeForClassInternal(orb, componentClass, vh,
 419                                                               createdIDs);
 420             }
 421             TypeCode t = orb.create_sequence_tc (0, embeddedType);
 422             return orb.create_value_box_tc (id, "Sequence", t);
 423         } else if ( c == java.lang.String.class ) {
 424             // Strings
 425             TypeCode t = orb.create_string_tc (0);
 426             return orb.create_value_box_tc (id, "StringValue", t);
 427         } else if (java.rmi.Remote.class.isAssignableFrom(c)) {
 428             return orb.get_primitive_tc(TCKind.tk_objref);
 429         } else if (org.omg.CORBA.Object.class.isAssignableFrom(c)) {
 430             return orb.get_primitive_tc(TCKind.tk_objref);
 431         }
 432 
 433         // Anything else
 434 
 435         ObjectStreamClass osc = ObjectStreamClass.lookup(c);
 436 
 437         if (osc == null) {
 438             return orb.create_value_box_tc (id, "Value", orb.get_primitive_tc (TCKind.tk_value));
 439         }
 440 
 441         // type modifier
 442         // REVISIT truncatable and abstract?
 443         short modifier = (osc.isCustomMarshaled() ? org.omg.CORBA.VM_CUSTOM.value : org.omg.CORBA.VM_NONE.value);
 444 
 445         // concrete base
 446         TypeCode base = null;
 447         Class superClass = c.getSuperclass();
 448         if (superClass != null && java.io.Serializable.class.isAssignableFrom(superClass)) {
 449             base = createTypeCodeForClassInternal(orb, superClass, vh, createdIDs);
 450         }
 451 
 452         // members
 453         ValueMember[] members = translateMembers (orb, osc, vh, createdIDs);
 454 
 455         return orb.create_value_tc(id, c.getName(), modifier, base, members);
 456     }
 457 
 458     public static TypeCode getPrimitiveTypeCodeForClass (ORB orb,
 459                                                          Class c,
 460                                                          ValueHandler vh) {
 461 
 462         if (c == Integer.TYPE) {
 463             return orb.get_primitive_tc (TCKind.tk_long);
 464         } else if (c == Byte.TYPE) {
 465             return orb.get_primitive_tc (TCKind.tk_octet);
 466         } else if (c == Long.TYPE) {
 467             return orb.get_primitive_tc (TCKind.tk_longlong);
 468         } else if (c == Float.TYPE) {
 469             return orb.get_primitive_tc (TCKind.tk_float);
 470         } else if (c == Double.TYPE) {
 471             return orb.get_primitive_tc (TCKind.tk_double);
 472         } else if (c == Short.TYPE) {
 473             return orb.get_primitive_tc (TCKind.tk_short);
 474         } else if (c == Character.TYPE) {
 475             return orb.get_primitive_tc (((ValueHandlerImpl)vh).getJavaCharTCKind());
 476         } else if (c == Boolean.TYPE) {
 477             return orb.get_primitive_tc (TCKind.tk_boolean);
 478         } else {
 479             // _REVISIT_ Not sure if this is right.
 480             return orb.get_primitive_tc (TCKind.tk_any);
 481         }
 482     }
 483 }