ValueUtility.java revision 608:7e06bf1dcb09
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
32package com.sun.corba.se.impl.io;
33
34import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
35import com.sun.org.omg.CORBA.OperationDescription;
36import com.sun.org.omg.CORBA.AttributeDescription;
37import org.omg.CORBA.ValueMember;
38import com.sun.org.omg.CORBA.Initializer;
39import org.omg.CORBA.IDLType;
40import com.sun.org.omg.CORBA._IDLTypeStub;
41import org.omg.CORBA.ORB;
42import org.omg.CORBA.TypeCodePackage.*;
43import org.omg.CORBA.TypeCode;
44import org.omg.CORBA.TCKind;
45import java.lang.reflect.*;
46import com.sun.corba.se.impl.util.RepositoryId;
47import java.util.*;
48import javax.rmi.CORBA.Util;
49import javax.rmi.CORBA.ValueHandler;
50
51/**
52 * Holds utility methods for converting from ObjectStreamClass to
53 * FullValueDescription and generating typecodes from ObjectStreamClass.
54 **/
55public 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}
484