IDLNameTranslatorImpl.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 2003, 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
26package com.sun.corba.se.impl.presentation.rmi ;
27
28import java.security.AccessController;
29import java.security.PrivilegedAction;
30
31import java.lang.reflect.Method;
32
33import java.math.BigInteger;
34
35import java.util.Map;
36import java.util.Set;
37import java.util.HashSet;
38import java.util.Iterator;
39import java.util.HashMap;
40import java.util.StringTokenizer;
41
42import com.sun.corba.se.spi.presentation.rmi.IDLNameTranslator ;
43
44import com.sun.corba.se.impl.presentation.rmi.IDLType ;
45import com.sun.corba.se.impl.presentation.rmi.IDLTypeException ;
46import com.sun.corba.se.impl.presentation.rmi.IDLTypesUtil ;
47import com.sun.corba.se.impl.orbutil.ObjectUtility ;
48
49/**
50 * Bidirectional translator between RMI-IIOP interface methods and
51 * and IDL Names.
52 */
53public class IDLNameTranslatorImpl implements IDLNameTranslator {
54
55    // From CORBA Spec, Table 6 Keywords.
56    // Note that since all IDL identifiers are case
57    // insensitive, java identifier comparisons to these
58    // will be case insensitive also.
59    private static String[] IDL_KEYWORDS = {
60
61        "abstract", "any", "attribute", "boolean", "case", "char",
62        "const", "context", "custom", "default", "double", "enum",
63        "exception", "factory", "FALSE", "fixed", "float", "in", "inout",
64        "interface", "long", "module", "native", "Object", "octet",
65        "oneway", "out", "private", "public", "raises", "readonly", "sequence",
66        "short", "string", "struct", "supports", "switch", "TRUE", "truncatable",
67        "typedef", "unsigned", "union", "ValueBase", "valuetype", "void",
68        "wchar", "wstring"
69
70    };
71
72    private static char[] HEX_DIGITS = {
73        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
74        'A', 'B', 'C', 'D', 'E', 'F'
75    };
76
77    private static final String UNDERSCORE = "_";
78
79    // used to mangle java inner class names
80    private static final String INNER_CLASS_SEPARATOR =
81        UNDERSCORE + UNDERSCORE;
82
83    // used to form IDL array type names
84    private static final String[] BASE_IDL_ARRAY_MODULE_TYPE=
85        new String[] { "org", "omg", "boxedRMI" } ;
86
87    private static final String BASE_IDL_ARRAY_ELEMENT_TYPE = "seq";
88
89    // used to mangling java identifiers that have a leading underscore
90    private static final String LEADING_UNDERSCORE_CHAR = "J";
91    private static final String ID_CONTAINER_CLASH_CHAR = UNDERSCORE;
92
93    // separator used between types in a mangled overloaded method name
94    private static final String OVERLOADED_TYPE_SEPARATOR =
95        UNDERSCORE + UNDERSCORE;
96
97    // string appended to attribute if it clashes with a method name
98    private static final String ATTRIBUTE_METHOD_CLASH_MANGLE_CHARS =
99        UNDERSCORE + UNDERSCORE;
100
101    // strings prepended to the attribute names in order to form their
102    // IDL names.
103    private static final String GET_ATTRIBUTE_PREFIX = "_get_";
104    private static final String SET_ATTRIBUTE_PREFIX = "_set_";
105    private static final String IS_ATTRIBUTE_PREFIX  = "_get_";
106
107    private static Set idlKeywords_;
108
109    static {
110
111        idlKeywords_ = new HashSet();
112        for(int i = 0; i < IDL_KEYWORDS.length; i++) {
113            String next = (String) IDL_KEYWORDS[i];
114            // Convert keyword to all caps to ease equality
115            // check.
116            String keywordAllCaps = next.toUpperCase();
117            idlKeywords_.add(keywordAllCaps);
118        }
119
120    }
121
122    //
123    // Instance state
124    //
125
126    // Remote interface for name translation.
127    private Class[] interf_;
128
129    // Maps used to hold name translations.  These do not need to be
130    // synchronized since the translation is never modified after
131    // initialization.
132    private Map methodToIDLNameMap_;
133    private Map IDLNameToMethodMap_;
134    private Method[] methods_;
135
136    /**
137     * Return an IDLNameTranslator for the given interface.
138     *
139     * @throws IllegalStateException if given class is not a valid
140     *         RMI/IIOP Remote Interface
141     */
142    public static IDLNameTranslator get( Class interf )
143    {
144
145        return new IDLNameTranslatorImpl(new Class[] { interf } );
146
147    }
148
149    /**
150     * Return an IDLNameTranslator for the given interfacex.
151     *
152     * @throws IllegalStateException if given classes are not  valid
153     *         RMI/IIOP Remote Interfaces
154     */
155    public static IDLNameTranslator get( Class[] interfaces )
156    {
157
158        return new IDLNameTranslatorImpl(interfaces );
159
160    }
161
162    public static String getExceptionId( Class cls )
163    {
164        // Requirements for this method:
165        // 1. cls must be an exception but not a RemoteException.
166        // 2. If cls has an IDL keyword name, an underscore is prepended (1.3.2.2).
167        // 3. If cls jas a leading underscore, J is prepended (1.3.2.3).
168        // 4. If cls has an illegal IDL ident char, it is mapped to UXXXX where
169        //    XXXX is the unicode value in hex of the char (1.3.2.4).
170        // 5. double underscore for inner class (1.3.2.5).
171        // 6. The ID is "IDL:" + name with / separators + ":1.0".
172        IDLType itype = classToIDLType( cls ) ;
173        return itype.getExceptionName() ;
174    }
175
176    public Class[] getInterfaces()
177    {
178        return interf_;
179    }
180
181    public Method[] getMethods()
182    {
183        return methods_ ;
184    }
185
186    public Method getMethod( String idlName )
187    {
188        return (Method) IDLNameToMethodMap_.get(idlName);
189    }
190
191    public String getIDLName( Method method )
192    {
193        return (String) methodToIDLNameMap_.get(method);
194    }
195
196    /**
197     * Initialize an IDLNameTranslator for the given interface.
198     *
199     * @throws IllegalStateException if given class is not a valid
200     *         RMI/IIOP Remote Interface
201     */
202    private IDLNameTranslatorImpl(Class[] interfaces)
203    {
204
205        SecurityManager s = System.getSecurityManager();
206        if (s != null) {
207            s.checkPermission(new DynamicAccessPermission("access"));
208        }
209        try {
210            IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
211            for (int ctr=0; ctr<interfaces.length; ctr++)
212                idlTypesUtil.validateRemoteInterface(interfaces[ctr]);
213            interf_ = interfaces;
214            buildNameTranslation();
215        } catch( IDLTypeException ite) {
216            String msg = ite.getMessage();
217            IllegalStateException ise = new IllegalStateException(msg);
218            ise.initCause(ite);
219            throw ise;
220        }
221    }
222
223    private void buildNameTranslation()
224    {
225        // holds method info, keyed by method
226        Map allMethodInfo = new HashMap() ;
227
228        for (int ctr=0; ctr<interf_.length; ctr++) {
229            Class interf = interf_[ctr] ;
230
231            IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
232            final Method[] methods = interf.getMethods();
233            // Handle the case of a non-public interface!
234            AccessController.doPrivileged(new PrivilegedAction() {
235                public Object run() {
236                    Method.setAccessible( methods, true ) ;
237                    return null ;
238                }
239            } ) ;
240
241            // Take an initial pass through all the methods and create some
242            // information that will be used to track the IDL name
243            // transformation.
244            for(int i = 0; i < methods.length; i++) {
245
246                Method nextMethod = methods[i];
247
248                IDLMethodInfo methodInfo = new IDLMethodInfo();
249
250                methodInfo.method = nextMethod;
251
252                if (idlTypesUtil.isPropertyAccessorMethod(nextMethod, interf)) {
253                    methodInfo.isProperty = true;
254                    String attributeName = idlTypesUtil.
255                        getAttributeNameForProperty(nextMethod.getName());
256                    methodInfo.originalName = attributeName;
257                    methodInfo.mangledName  = attributeName;
258                } else {
259                    methodInfo.isProperty = false;
260                    methodInfo.originalName = nextMethod.getName();
261                    methodInfo.mangledName  = nextMethod.getName();
262                }
263
264                allMethodInfo.put(nextMethod, methodInfo);
265            }
266        }
267
268        //
269        // Perform case sensitivity test first.  This applies to all
270        // method names AND attributes.  Compare each method name and
271        // attribute to all other method names and attributes.  If names
272        // differ only in case, apply mangling as defined in section 1.3.2.7
273        // of Java2IDL spec.  Note that we compare using the original names.
274        //
275        for(Iterator outerIter=allMethodInfo.values().iterator();
276            outerIter.hasNext();) {
277            IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
278            for(Iterator innerIter = allMethodInfo.values().iterator();
279                innerIter.hasNext();) {
280                IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
281
282                if( (outer != inner) &&
283                    (!outer.originalName.equals(inner.originalName)) &&
284                    outer.originalName.equalsIgnoreCase(inner.originalName) ) {
285                    outer.mangledName =
286                        mangleCaseSensitiveCollision(outer.originalName);
287                    break;
288                }
289
290            }
291        }
292
293        for(Iterator iter = allMethodInfo.values().iterator();
294            iter.hasNext();) {
295            IDLMethodInfo next = (IDLMethodInfo) iter.next();
296            next.mangledName =
297                mangleIdentifier(next.mangledName, next.isProperty);
298        }
299
300        //
301        // Now check for overloaded method names and apply 1.3.2.6.
302        //
303        for(Iterator outerIter=allMethodInfo.values().iterator();
304            outerIter.hasNext();) {
305            IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
306            if( outer.isProperty ) {
307                continue;
308            }
309            for(Iterator innerIter = allMethodInfo.values().iterator();
310                innerIter.hasNext();) {
311                IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
312
313                if( (outer != inner) &&
314                    !inner.isProperty &&
315                    outer.originalName.equals(inner.originalName) ) {
316                    outer.mangledName = mangleOverloadedMethod
317                        (outer.mangledName, outer.method);
318                    break;
319                }
320            }
321        }
322
323        //
324        // Now mangle any properties that clash with method names.
325        //
326        for(Iterator outerIter=allMethodInfo.values().iterator();
327            outerIter.hasNext();) {
328            IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
329            if( !outer.isProperty ) {
330                continue;
331            }
332            for(Iterator innerIter = allMethodInfo.values().iterator();
333                innerIter.hasNext();) {
334                IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
335                if( (outer != inner) &&
336                    !inner.isProperty &&
337                    outer.mangledName.equals(inner.mangledName) ) {
338                    outer.mangledName = outer.mangledName +
339                        ATTRIBUTE_METHOD_CLASH_MANGLE_CHARS;
340                    break;
341                }
342            }
343        }
344
345        //
346        // Ensure that no mapped method names clash with mapped name
347        // of container(1.3.2.9).  This is a case insensitive comparison.
348        //
349        for (int ctr=0; ctr<interf_.length; ctr++ ) {
350            Class interf = interf_[ctr] ;
351            String mappedContainerName = getMappedContainerName(interf);
352            for(Iterator iter = allMethodInfo.values().iterator();
353                iter.hasNext();) {
354                IDLMethodInfo next = (IDLMethodInfo) iter.next();
355                if( !next.isProperty &&
356                    identifierClashesWithContainer(mappedContainerName,
357                                                   next.mangledName)) {
358                    next.mangledName = mangleContainerClash(next.mangledName);
359                }
360            }
361        }
362
363        //
364        // Populate name translation maps.
365        //
366        methodToIDLNameMap_ = new HashMap();
367        IDLNameToMethodMap_ = new HashMap();
368        methods_ = (Method[])allMethodInfo.keySet().toArray(
369            new Method[0] ) ;
370
371        for(Iterator iter = allMethodInfo.values().iterator();
372            iter.hasNext();) {
373            IDLMethodInfo next = (IDLMethodInfo) iter.next();
374            String idlName = next.mangledName;
375            if( next.isProperty ) {
376                String origMethodName = next.method.getName();
377                String prefix = "";
378
379                if( origMethodName.startsWith("get") ) {
380                    prefix = GET_ATTRIBUTE_PREFIX;
381                } else if( origMethodName.startsWith("set") ) {
382                    prefix = SET_ATTRIBUTE_PREFIX;
383                } else {
384                    prefix = IS_ATTRIBUTE_PREFIX;
385                }
386
387                idlName = prefix + next.mangledName;
388            }
389
390            methodToIDLNameMap_.put(next.method, idlName);
391
392            // Final check to see if there are any clashes after all the
393            // manglings have been applied.  If so, this is treated as an
394            // invalid interface.  Currently, we do a CASE-SENSITIVE
395            // comparison since that matches the rmic behavior.
396            // @@@ Shouldn't this be a case-insensitive check?
397            if( IDLNameToMethodMap_.containsKey(idlName) ) {
398                // @@@ I18N
399                Method clash = (Method) IDLNameToMethodMap_.get(idlName);
400                throw new IllegalStateException("Error : methods " +
401                    clash + " and " + next.method +
402                    " both result in IDL name '" + idlName + "'");
403            } else {
404                IDLNameToMethodMap_.put(idlName, next.method);
405            }
406        }
407
408        return;
409
410    }
411
412
413    /**
414     * Perform all necessary stand-alone identifier mangling operations
415     * on a java identifier that is being transformed into an IDL name.
416     * That is, mangling operations that don't require looking at anything
417     * else but the identifier itself.  This covers sections 1.3.2.2, 1.3.2.3,
418     * and 1.3.2.4 of the Java2IDL spec.  Method overloading and
419     * case-sensitivity checks are handled elsewhere.
420     */
421
422    private static String mangleIdentifier(String identifier) {
423        return mangleIdentifier(identifier, false);
424    }
425
426    private static String mangleIdentifier(String identifier, boolean attribute) {
427
428        String mangledName = identifier;
429
430        //
431        // Apply leading underscore test (1.3.2.3)
432        // This should be done before IDL Keyword clash test, since clashing
433        // IDL keywords are mangled by adding a leading underscore.
434        //
435        if( hasLeadingUnderscore(mangledName) ) {
436            mangledName = mangleLeadingUnderscore(mangledName);
437        }
438
439        //
440        // Apply IDL keyword clash test (1.3.2.2).
441        // This is not needed for attributes since when the full property
442        // name is composed it cannot clash with an IDL keyword.
443        // (Also, rmic doesn't do it.)
444        //
445
446        if( !attribute && isIDLKeyword(mangledName) ) {
447            mangledName = mangleIDLKeywordClash(mangledName);
448        }
449
450        //
451        // Replace illegal IDL identifier characters (1.3.2.4)
452        // for all method names and attributes.
453        //
454        if( !isIDLIdentifier(mangledName) ) {
455            mangledName = mangleUnicodeChars(mangledName);
456        }
457
458        return mangledName;
459    }
460
461    // isIDLKeyword and mangleIDLKeywordClash are exposed here so that
462    // IDLType can use them.
463    //
464    // XXX refactoring needed:
465    // 1. Split off isIDLKeywork and mangleIDLKeywordClash (and possibly
466    //    other methods) into a utility class.
467    // 2. Move all of classToIDLType to a constructor inside IDLType.
468    //
469    // The problem appears to be that we need all of the code that
470    // performs various checks for name problems and the corresponding
471    // fixes into a utility class.  Then we need to see what other
472    // refactorings present themselves.
473
474    /**
475     * Checks whether a java identifier clashes with an
476     * IDL keyword.  Note that this is a case-insensitive
477     * comparison.
478     *
479     * Used to implement section 1.3.2.2 of Java2IDL spec.
480     */
481    static boolean isIDLKeyword(String identifier) {
482
483        String identifierAllCaps = identifier.toUpperCase();
484
485        return idlKeywords_.contains(identifierAllCaps);
486    }
487
488    static String mangleIDLKeywordClash(String identifier) {
489        return UNDERSCORE + identifier;
490    }
491
492    private static String mangleLeadingUnderscore(String identifier) {
493        return LEADING_UNDERSCORE_CHAR + identifier;
494    }
495
496    /**
497     * Checks whether a java identifier starts with an underscore.
498     * Used to implement section 1.3.2.3 of Java2IDL spec.
499     */
500    private static boolean hasLeadingUnderscore(String identifier) {
501        return identifier.startsWith(UNDERSCORE);
502    }
503
504    /**
505     * Implements Section 1.3.2.4 of Java2IDL Mapping.
506     * All non-IDL identifier characters must be replaced
507     * with their Unicode representation.
508     */
509    static String mangleUnicodeChars(String identifier) {
510        StringBuffer mangledIdentifier = new StringBuffer();
511
512        for(int i = 0; i < identifier.length(); i++) {
513            char nextChar = identifier.charAt(i);
514            if( isIDLIdentifierChar(nextChar) ) {
515                mangledIdentifier.append(nextChar);
516            } else {
517                String unicode = charToUnicodeRepresentation(nextChar);
518                mangledIdentifier.append(unicode);
519            }
520        }
521
522        return mangledIdentifier.toString();
523    }
524
525    /**
526     * Implements mangling portion of Section 1.3.2.7 of Java2IDL spec.
527     * This method only deals with the actual mangling.  Decision about
528     * whether case-sensitive collision mangling is required is made
529     * elsewhere.
530     *
531     *
532     * "...a mangled name is generated consisting of the original name
533     * followed by an underscore separated list of decimal indices
534     * into the string, where the indices identify all the upper case
535     * characters in the original string. Indices are zero based."
536     *
537     */
538    String mangleCaseSensitiveCollision(String identifier) {
539
540        StringBuffer mangledIdentifier = new StringBuffer(identifier);
541
542        // There is always at least one trailing underscore, whether or
543        // not the identifier has uppercase letters.
544        mangledIdentifier.append(UNDERSCORE);
545
546        boolean needUnderscore = false;
547        for(int i = 0; i < identifier.length(); i++) {
548            char next = identifier.charAt(i);
549            if( Character.isUpperCase(next) ) {
550                // This bit of logic is needed to ensure that we have
551                // an underscore separated list of indices but no
552                // trailing underscores.  Basically, after we have at least
553                // one uppercase letter, we always put an undercore before
554                // printing the next one.
555                if( needUnderscore ) {
556                    mangledIdentifier.append(UNDERSCORE);
557                }
558                mangledIdentifier.append(i);
559                needUnderscore = true;
560            }
561        }
562
563        return mangledIdentifier.toString();
564    }
565
566    private static String mangleContainerClash(String identifier) {
567        return identifier + ID_CONTAINER_CLASH_CHAR;
568    }
569
570    /**
571     * Implements Section 1.3.2.9 of Java2IDL Mapping. Container in this
572     * context means the name of the java Class(excluding package) in which
573     * the identifier is defined.  Comparison is case-insensitive.
574     */
575    private static boolean identifierClashesWithContainer
576        (String mappedContainerName, String identifier) {
577
578        return identifier.equalsIgnoreCase(mappedContainerName);
579    }
580
581    /**
582     * Returns Unicode mangling as defined in Section 1.3.2.4 of
583     * Java2IDL spec.
584     *
585     * "For Java identifiers that contain illegal OMG IDL identifier
586     * characters such as '$' or Unicode characters outside of ISO Latin 1,
587     * any such illegal characters are replaced by "U" followed by the
588     * 4 hexadecimal characters(in upper case) representing the Unicode
589     * value.  So, the Java name a$b is mapped to aU0024b and
590     * x\u03bCy is mapped to xU03BCy."
591     */
592    public static String charToUnicodeRepresentation(char c) {
593
594        int orig = (int) c;
595        StringBuffer hexString = new StringBuffer();
596
597        int value = orig;
598
599        while( value > 0 ) {
600            int div = value / 16;
601            int mod = value % 16;
602            hexString.insert(0, HEX_DIGITS[mod]);
603            value = div;
604        }
605
606        int numZerosToAdd = 4 - hexString.length();
607        for(int i = 0; i < numZerosToAdd; i++) {
608            hexString.insert(0, "0");
609        }
610
611        hexString.insert(0, "U");
612        return hexString.toString();
613    }
614
615    private static boolean isIDLIdentifier(String identifier) {
616
617        boolean isIdentifier = true;
618
619        for(int i = 0; i < identifier.length(); i++) {
620            char nextChar = identifier.charAt(i);
621            // 1st char must be alphbetic.
622            isIdentifier  = (i == 0) ?
623                isIDLAlphabeticChar(nextChar) :
624                isIDLIdentifierChar(nextChar);
625            if( !isIdentifier ) {
626                break;
627            }
628        }
629
630        return isIdentifier;
631
632    }
633
634    private static boolean isIDLIdentifierChar(char c) {
635        return (isIDLAlphabeticChar(c) ||
636                isIDLDecimalDigit(c)   ||
637                isUnderscore(c));
638    }
639
640    /**
641     * True if character is one of 114 Alphabetic characters as
642     * specified in Table 2 of Chapter 3 in CORBA spec.
643     */
644    private static boolean isIDLAlphabeticChar(char c) {
645
646        // NOTE that we can't use the java.lang.Character
647        // isUpperCase, isLowerCase, etc. methods since they
648        // include many characters other than the Alphabetic list in
649        // the CORBA spec.  Instead, we test for inclusion in the
650        // Unicode value ranges for the corresponding legal characters.
651
652        boolean alphaChar =
653            (
654             // A - Z
655             ((c >= 0x0041) && (c <= 0x005A))
656
657             ||
658
659             // a - z
660             ((c >= 0x0061) && (c <= 0x007A))
661
662             ||
663
664             // other letter uppercase, other letter lowercase, which is
665             // the entire upper half of C1 Controls except X and /
666             ((c >= 0x00C0) && (c <= 0x00FF)
667              && (c != 0x00D7) && (c != 0x00F7)));
668
669        return alphaChar;
670    }
671
672    /**
673     * True if character is one of 10 Decimal Digits
674     * specified in Table 3 of Chapter 3 in CORBA spec.
675     */
676    private static boolean isIDLDecimalDigit(char c) {
677        return ( (c >= 0x0030) && (c <= 0x0039) );
678    }
679
680    private static boolean isUnderscore(char c) {
681        return ( c == 0x005F );
682    }
683
684    /**
685     * Mangle an overloaded method name as defined in Section 1.3.2.6 of
686     * Java2IDL spec.  Current value of method name is passed in as argument.
687     * We can't start from original method name since the name might have
688     * been partially mangled as a result of the other rules.
689     */
690    private static String mangleOverloadedMethod(String mangledName, Method m) {
691
692        IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
693
694        // Start by appending the separator string
695        String newMangledName = mangledName + OVERLOADED_TYPE_SEPARATOR;
696
697        Class[] parameterTypes = m.getParameterTypes();
698
699        for(int i = 0; i < parameterTypes.length; i++) {
700            Class nextParamType = parameterTypes[i];
701
702            if( i > 0 ) {
703                newMangledName = newMangledName + OVERLOADED_TYPE_SEPARATOR;
704            }
705            IDLType idlType = classToIDLType(nextParamType);
706
707            String moduleName = idlType.getModuleName();
708            String memberName = idlType.getMemberName();
709
710            String typeName = (moduleName.length() > 0) ?
711                moduleName + UNDERSCORE + memberName : memberName;
712
713            if( !idlTypesUtil.isPrimitive(nextParamType) &&
714                (idlTypesUtil.getSpecialCaseIDLTypeMapping(nextParamType)
715                 == null) &&
716                isIDLKeyword(typeName) ) {
717                typeName = mangleIDLKeywordClash(typeName);
718            }
719
720            typeName = mangleUnicodeChars(typeName);
721
722            newMangledName = newMangledName + typeName;
723        }
724
725        return newMangledName;
726    }
727
728
729    private static IDLType classToIDLType(Class c) {
730
731        IDLType idlType = null;
732        IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
733
734        if( idlTypesUtil.isPrimitive(c) ) {
735
736            idlType = idlTypesUtil.getPrimitiveIDLTypeMapping(c);
737
738        } else if( c.isArray() ) {
739
740            // Calculate array depth, as well as base element type.
741            Class componentType = c.getComponentType();
742            int numArrayDimensions = 1;
743            while(componentType.isArray()) {
744                componentType = componentType.getComponentType();
745                numArrayDimensions++;
746            }
747            IDLType componentIdlType = classToIDLType(componentType);
748
749            String[] modules = BASE_IDL_ARRAY_MODULE_TYPE;
750            if( componentIdlType.hasModule() ) {
751                modules = (String[])ObjectUtility.concatenateArrays( modules,
752                    componentIdlType.getModules() ) ;
753            }
754
755            String memberName = BASE_IDL_ARRAY_ELEMENT_TYPE +
756                numArrayDimensions + UNDERSCORE +
757                componentIdlType.getMemberName();
758
759            idlType = new IDLType(c, modules, memberName);
760
761        } else {
762            idlType = idlTypesUtil.getSpecialCaseIDLTypeMapping(c);
763
764            if (idlType == null) {
765                // Section 1.3.2.5 of Java2IDL spec defines mangling rules for
766                // inner classes.
767                String memberName = getUnmappedContainerName(c);
768
769                // replace inner class separator with double underscore
770                memberName = memberName.replaceAll("\\$",
771                                                   INNER_CLASS_SEPARATOR);
772
773                if( hasLeadingUnderscore(memberName) ) {
774                    memberName = mangleLeadingUnderscore(memberName);
775                }
776
777                // Get raw package name.  If there is a package, it
778                // will still have the "." separators and none of the
779                // mangling rules will have been applied.
780                String packageName = getPackageName(c);
781
782                if (packageName == null) {
783                    idlType = new IDLType( c, memberName ) ;
784                } else {
785                    // If this is a generated IDL Entity Type we need to
786                    // prepend org_omg_boxedIDL per sections 1.3.5 and 1.3.9
787                    if (idlTypesUtil.isEntity(c)) {
788                        packageName = "org.omg.boxedIDL." + packageName ;
789                    }
790
791                    // Section 1.3.2.1 and 1.3.2.6 of Java2IDL spec defines
792                    // rules for mapping java packages to IDL modules and for
793                    // mangling module name portion of type name.  NOTE that
794                    // of the individual identifier mangling rules,
795                    // only the leading underscore test is done here.
796                    // The other two(IDL Keyword, Illegal Unicode chars) are
797                    // done in mangleOverloadedMethodName.
798                    StringTokenizer tokenizer =
799                        new StringTokenizer(packageName, ".");
800
801                    String[] modules = new String[ tokenizer.countTokens() ] ;
802                    int index = 0 ;
803                    while (tokenizer.hasMoreElements()) {
804                        String next = tokenizer.nextToken();
805                        String moreMangled = hasLeadingUnderscore( next ) ?
806                            mangleLeadingUnderscore( next ) : next;
807
808                        modules[index++] = moreMangled ;
809                    }
810
811                    idlType = new IDLType(c, modules, memberName);
812                }
813            }
814        }
815
816        return idlType;
817    }
818
819    /**
820     * Return Class' package name or null if there is no package.
821     */
822    private static String getPackageName(Class c) {
823        Package thePackage = c.getPackage();
824        String packageName = null;
825
826        // Try to get package name by introspection.  Some classloaders might
827        // not provide this information, so check for null.
828        if( thePackage != null ) {
829            packageName = thePackage.getName();
830        } else {
831            // brute force method
832            String fullyQualifiedClassName = c.getName();
833            int lastDot = fullyQualifiedClassName.indexOf('.');
834            packageName = (lastDot == -1) ? null :
835                fullyQualifiedClassName.substring(0, lastDot);
836        }
837        return packageName;
838    }
839
840    private static String getMappedContainerName(Class c) {
841        String unmappedName = getUnmappedContainerName(c);
842
843        return mangleIdentifier(unmappedName);
844    }
845
846    /**
847     * Return portion of class name excluding package name.
848     */
849    private static String getUnmappedContainerName(Class c) {
850
851        String memberName  = null;
852        String packageName = getPackageName(c);
853
854        String fullyQualifiedClassName = c.getName();
855
856        if( packageName != null ) {
857            int packageLength = packageName.length();
858            memberName = fullyQualifiedClassName.substring(packageLength + 1);
859        } else {
860            memberName = fullyQualifiedClassName;
861
862        }
863
864        return memberName;
865    }
866
867    /**
868     * Internal helper class for tracking information related to each
869     * interface method while we're building the name translation table.
870     */
871    private static class IDLMethodInfo
872    {
873        public Method method;
874        public boolean isProperty;
875
876        // If this is a property, originalName holds the original
877        // attribute name. Otherwise, it holds the original method name.
878        public String originalName;
879
880        // If this is a property, mangledName holds the mangled attribute
881        // name. Otherwise, it holds the mangled method name.
882        public String mangledName;
883
884    }
885
886    public String toString() {
887
888        StringBuffer contents = new StringBuffer();
889        contents.append("IDLNameTranslator[" );
890        for( int ctr=0; ctr<interf_.length; ctr++) {
891            if (ctr != 0)
892                contents.append( " " ) ;
893            contents.append( interf_[ctr].getName() ) ;
894        }
895        contents.append("]\n");
896        for(Iterator iter = methodToIDLNameMap_.keySet().iterator();
897            iter.hasNext();) {
898
899            Method method  = (Method) iter.next();
900            String idlName = (String) methodToIDLNameMap_.get(method);
901
902            contents.append(idlName + ":" + method + "\n");
903
904        }
905
906        return contents.toString();
907    }
908}
909