src/share/classes/com/sun/corba/se/impl/presentation/rmi/IDLNameTranslatorImpl.java

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
55540e827aef
child 72
e149090eb21a
permissions
-rw-r--r--

Initial load

     1 /*
     2  * Copyright 2003-2004 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.corba.se.impl.presentation.rmi ;
    28 import java.security.AccessController;
    29 import java.security.PrivilegedAction;
    31 import java.lang.reflect.Method;
    33 import java.math.BigInteger;
    35 import java.util.Map;
    36 import java.util.Set;
    37 import java.util.HashSet;
    38 import java.util.Iterator;
    39 import java.util.HashMap;
    40 import java.util.StringTokenizer;
    42 import com.sun.corba.se.spi.presentation.rmi.IDLNameTranslator ;
    44 import com.sun.corba.se.impl.presentation.rmi.IDLType ;
    45 import com.sun.corba.se.impl.presentation.rmi.IDLTypeException ;
    46 import com.sun.corba.se.impl.presentation.rmi.IDLTypesUtil ;
    47 import com.sun.corba.se.impl.orbutil.ObjectUtility ;
    49 /**
    50  * Bidirectional translator between RMI-IIOP interface methods and
    51  * and IDL Names.
    52  */
    53 public class IDLNameTranslatorImpl implements IDLNameTranslator {
    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 = {
    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"
    70     };
    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     };
    77     private static final String UNDERSCORE = "_";
    79     // used to mangle java inner class names
    80     private static final String INNER_CLASS_SEPARATOR =
    81         UNDERSCORE + UNDERSCORE;
    83     // used to form IDL array type names
    84     private static final String[] BASE_IDL_ARRAY_MODULE_TYPE=
    85         new String[] { "org", "omg", "boxedRMI" } ;
    87     private static final String BASE_IDL_ARRAY_ELEMENT_TYPE = "seq";
    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;
    93     // separator used between types in a mangled overloaded method name
    94     private static final String OVERLOADED_TYPE_SEPARATOR =
    95         UNDERSCORE + UNDERSCORE;
    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;
   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_";
   107     private static Set idlKeywords_;
   109     static {
   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         }
   120     }
   122     //
   123     // Instance state
   124     //
   126     // Remote interface for name translation.
   127     private Class[] interf_;
   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_;
   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     {
   145         return new IDLNameTranslatorImpl(new Class[] { interf } );
   147     }
   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     {
   158         return new IDLNameTranslatorImpl(interfaces );
   160     }
   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     }
   176     public Class[] getInterfaces()
   177     {
   178         return interf_;
   179     }
   181     public Method[] getMethods()
   182     {
   183         return methods_ ;
   184     }
   186     public Method getMethod( String idlName )
   187     {
   188         return (Method) IDLNameToMethodMap_.get(idlName);
   189     }
   191     public String getIDLName( Method method )
   192     {
   193         return (String) methodToIDLNameMap_.get(method);
   194     }
   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     {
   205         try {
   206             IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
   207             for (int ctr=0; ctr<interfaces.length; ctr++)
   208                 idlTypesUtil.validateRemoteInterface(interfaces[ctr]);
   209             interf_ = interfaces;
   210             buildNameTranslation();
   211         } catch( IDLTypeException ite) {
   212             String msg = ite.getMessage();
   213             IllegalStateException ise = new IllegalStateException(msg);
   214             ise.initCause(ite);
   215             throw ise;
   216         }
   217     }
   219     private void buildNameTranslation()
   220     {
   221         // holds method info, keyed by method
   222         Map allMethodInfo = new HashMap() ;
   224         for (int ctr=0; ctr<interf_.length; ctr++) {
   225             Class interf = interf_[ctr] ;
   227             IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
   228             final Method[] methods = interf.getMethods();
   229             // Handle the case of a non-public interface!
   230             AccessController.doPrivileged(new PrivilegedAction() {
   231                 public Object run() {
   232                     Method.setAccessible( methods, true ) ;
   233                     return null ;
   234                 }
   235             } ) ;
   237             // Take an initial pass through all the methods and create some
   238             // information that will be used to track the IDL name
   239             // transformation.
   240             for(int i = 0; i < methods.length; i++) {
   242                 Method nextMethod = methods[i];
   244                 IDLMethodInfo methodInfo = new IDLMethodInfo();
   246                 methodInfo.method = nextMethod;
   248                 if (idlTypesUtil.isPropertyAccessorMethod(nextMethod, interf)) {
   249                     methodInfo.isProperty = true;
   250                     String attributeName = idlTypesUtil.
   251                         getAttributeNameForProperty(nextMethod.getName());
   252                     methodInfo.originalName = attributeName;
   253                     methodInfo.mangledName  = attributeName;
   254                 } else {
   255                     methodInfo.isProperty = false;
   256                     methodInfo.originalName = nextMethod.getName();
   257                     methodInfo.mangledName  = nextMethod.getName();
   258                 }
   260                 allMethodInfo.put(nextMethod, methodInfo);
   261             }
   262         }
   264         //
   265         // Perform case sensitivity test first.  This applies to all
   266         // method names AND attributes.  Compare each method name and
   267         // attribute to all other method names and attributes.  If names
   268         // differ only in case, apply mangling as defined in section 1.3.2.7
   269         // of Java2IDL spec.  Note that we compare using the original names.
   270         //
   271         for(Iterator outerIter=allMethodInfo.values().iterator();
   272             outerIter.hasNext();) {
   273             IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
   274             for(Iterator innerIter = allMethodInfo.values().iterator();
   275                 innerIter.hasNext();) {
   276                 IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
   278                 if( (outer != inner) &&
   279                     (!outer.originalName.equals(inner.originalName)) &&
   280                     outer.originalName.equalsIgnoreCase(inner.originalName) ) {
   281                     outer.mangledName =
   282                         mangleCaseSensitiveCollision(outer.originalName);
   283                     break;
   284                 }
   286             }
   287         }
   289         for(Iterator iter = allMethodInfo.values().iterator();
   290             iter.hasNext();) {
   291             IDLMethodInfo next = (IDLMethodInfo) iter.next();
   292             next.mangledName =
   293                 mangleIdentifier(next.mangledName, next.isProperty);
   294         }
   296         //
   297         // Now check for overloaded method names and apply 1.3.2.6.
   298         //
   299         for(Iterator outerIter=allMethodInfo.values().iterator();
   300             outerIter.hasNext();) {
   301             IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
   302             if( outer.isProperty ) {
   303                 continue;
   304             }
   305             for(Iterator innerIter = allMethodInfo.values().iterator();
   306                 innerIter.hasNext();) {
   307                 IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
   309                 if( (outer != inner) &&
   310                     !inner.isProperty &&
   311                     outer.originalName.equals(inner.originalName) ) {
   312                     outer.mangledName = mangleOverloadedMethod
   313                         (outer.mangledName, outer.method);
   314                     break;
   315                 }
   316             }
   317         }
   319         //
   320         // Now mangle any properties that clash with method names.
   321         //
   322         for(Iterator outerIter=allMethodInfo.values().iterator();
   323             outerIter.hasNext();) {
   324             IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
   325             if( !outer.isProperty ) {
   326                 continue;
   327             }
   328             for(Iterator innerIter = allMethodInfo.values().iterator();
   329                 innerIter.hasNext();) {
   330                 IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
   331                 if( (outer != inner) &&
   332                     !inner.isProperty &&
   333                     outer.mangledName.equals(inner.mangledName) ) {
   334                     outer.mangledName = outer.mangledName +
   335                         ATTRIBUTE_METHOD_CLASH_MANGLE_CHARS;
   336                     break;
   337                 }
   338             }
   339         }
   341         //
   342         // Ensure that no mapped method names clash with mapped name
   343         // of container(1.3.2.9).  This is a case insensitive comparison.
   344         //
   345         for (int ctr=0; ctr<interf_.length; ctr++ ) {
   346             Class interf = interf_[ctr] ;
   347             String mappedContainerName = getMappedContainerName(interf);
   348             for(Iterator iter = allMethodInfo.values().iterator();
   349                 iter.hasNext();) {
   350                 IDLMethodInfo next = (IDLMethodInfo) iter.next();
   351                 if( !next.isProperty &&
   352                     identifierClashesWithContainer(mappedContainerName,
   353                                                    next.mangledName)) {
   354                     next.mangledName = mangleContainerClash(next.mangledName);
   355                 }
   356             }
   357         }
   359         //
   360         // Populate name translation maps.
   361         //
   362         methodToIDLNameMap_ = new HashMap();
   363         IDLNameToMethodMap_ = new HashMap();
   364         methods_ = (Method[])allMethodInfo.keySet().toArray(
   365             new Method[0] ) ;
   367         for(Iterator iter = allMethodInfo.values().iterator();
   368             iter.hasNext();) {
   369             IDLMethodInfo next = (IDLMethodInfo) iter.next();
   370             String idlName = next.mangledName;
   371             if( next.isProperty ) {
   372                 String origMethodName = next.method.getName();
   373                 String prefix = "";
   375                 if( origMethodName.startsWith("get") ) {
   376                     prefix = GET_ATTRIBUTE_PREFIX;
   377                 } else if( origMethodName.startsWith("set") ) {
   378                     prefix = SET_ATTRIBUTE_PREFIX;
   379                 } else {
   380                     prefix = IS_ATTRIBUTE_PREFIX;
   381                 }
   383                 idlName = prefix + next.mangledName;
   384             }
   386             methodToIDLNameMap_.put(next.method, idlName);
   388             // Final check to see if there are any clashes after all the
   389             // manglings have been applied.  If so, this is treated as an
   390             // invalid interface.  Currently, we do a CASE-SENSITIVE
   391             // comparison since that matches the rmic behavior.
   392             // @@@ Shouldn't this be a case-insensitive check?
   393             if( IDLNameToMethodMap_.containsKey(idlName) ) {
   394                 // @@@ I18N
   395                 Method clash = (Method) IDLNameToMethodMap_.get(idlName);
   396                 throw new IllegalStateException("Error : methods " +
   397                     clash + " and " + next.method +
   398                     " both result in IDL name '" + idlName + "'");
   399             } else {
   400                 IDLNameToMethodMap_.put(idlName, next.method);
   401             }
   402         }
   404         return;
   406     }
   409     /**
   410      * Perform all necessary stand-alone identifier mangling operations
   411      * on a java identifier that is being transformed into an IDL name.
   412      * That is, mangling operations that don't require looking at anything
   413      * else but the identifier itself.  This covers sections 1.3.2.2, 1.3.2.3,
   414      * and 1.3.2.4 of the Java2IDL spec.  Method overloading and
   415      * case-sensitivity checks are handled elsewhere.
   416      */
   418     private static String mangleIdentifier(String identifier) {
   419         return mangleIdentifier(identifier, false);
   420     }
   422     private static String mangleIdentifier(String identifier, boolean attribute) {
   424         String mangledName = identifier;
   426         //
   427         // Apply leading underscore test (1.3.2.3)
   428         // This should be done before IDL Keyword clash test, since clashing
   429         // IDL keywords are mangled by adding a leading underscore.
   430         //
   431         if( hasLeadingUnderscore(mangledName) ) {
   432             mangledName = mangleLeadingUnderscore(mangledName);
   433         }
   435         //
   436         // Apply IDL keyword clash test (1.3.2.2).
   437         // This is not needed for attributes since when the full property
   438         // name is composed it cannot clash with an IDL keyword.
   439         // (Also, rmic doesn't do it.)
   440         //
   442         if( !attribute && isIDLKeyword(mangledName) ) {
   443             mangledName = mangleIDLKeywordClash(mangledName);
   444         }
   446         //
   447         // Replace illegal IDL identifier characters (1.3.2.4)
   448         // for all method names and attributes.
   449         //
   450         if( !isIDLIdentifier(mangledName) ) {
   451             mangledName = mangleUnicodeChars(mangledName);
   452         }
   454         return mangledName;
   455     }
   457     // isIDLKeyword and mangleIDLKeywordClash are exposed here so that
   458     // IDLType can use them.
   459     //
   460     // XXX refactoring needed:
   461     // 1. Split off isIDLKeywork and mangleIDLKeywordClash (and possibly
   462     //    other methods) into a utility class.
   463     // 2. Move all of classToIDLType to a constructor inside IDLType.
   464     //
   465     // The problem appears to be that we need all of the code that
   466     // performs various checks for name problems and the corresponding
   467     // fixes into a utility class.  Then we need to see what other
   468     // refactorings present themselves.
   470     /**
   471      * Checks whether a java identifier clashes with an
   472      * IDL keyword.  Note that this is a case-insensitive
   473      * comparison.
   474      *
   475      * Used to implement section 1.3.2.2 of Java2IDL spec.
   476      */
   477     static boolean isIDLKeyword(String identifier) {
   479         String identifierAllCaps = identifier.toUpperCase();
   481         return idlKeywords_.contains(identifierAllCaps);
   482     }
   484     static String mangleIDLKeywordClash(String identifier) {
   485         return UNDERSCORE + identifier;
   486     }
   488     private static String mangleLeadingUnderscore(String identifier) {
   489         return LEADING_UNDERSCORE_CHAR + identifier;
   490     }
   492     /**
   493      * Checks whether a java identifier starts with an underscore.
   494      * Used to implement section 1.3.2.3 of Java2IDL spec.
   495      */
   496     private static boolean hasLeadingUnderscore(String identifier) {
   497         return identifier.startsWith(UNDERSCORE);
   498     }
   500     /**
   501      * Implements Section 1.3.2.4 of Java2IDL Mapping.
   502      * All non-IDL identifier characters must be replaced
   503      * with their Unicode representation.
   504      */
   505     static String mangleUnicodeChars(String identifier) {
   506         StringBuffer mangledIdentifier = new StringBuffer();
   508         for(int i = 0; i < identifier.length(); i++) {
   509             char nextChar = identifier.charAt(i);
   510             if( isIDLIdentifierChar(nextChar) ) {
   511                 mangledIdentifier.append(nextChar);
   512             } else {
   513                 String unicode = charToUnicodeRepresentation(nextChar);
   514                 mangledIdentifier.append(unicode);
   515             }
   516         }
   518         return mangledIdentifier.toString();
   519     }
   521     /**
   522      * Implements mangling portion of Section 1.3.2.7 of Java2IDL spec.
   523      * This method only deals with the actual mangling.  Decision about
   524      * whether case-sensitive collision mangling is required is made
   525      * elsewhere.
   526      *
   527      *
   528      * "...a mangled name is generated consisting of the original name
   529      * followed by an underscore separated list of decimal indices
   530      * into the string, where the indices identify all the upper case
   531      * characters in the original string. Indices are zero based."
   532      *
   533      */
   534     String mangleCaseSensitiveCollision(String identifier) {
   536         StringBuffer mangledIdentifier = new StringBuffer(identifier);
   538         // There is always at least one trailing underscore, whether or
   539         // not the identifier has uppercase letters.
   540         mangledIdentifier.append(UNDERSCORE);
   542         boolean needUnderscore = false;
   543         for(int i = 0; i < identifier.length(); i++) {
   544             char next = identifier.charAt(i);
   545             if( Character.isUpperCase(next) ) {
   546                 // This bit of logic is needed to ensure that we have
   547                 // an underscore separated list of indices but no
   548                 // trailing underscores.  Basically, after we have at least
   549                 // one uppercase letter, we always put an undercore before
   550                 // printing the next one.
   551                 if( needUnderscore ) {
   552                     mangledIdentifier.append(UNDERSCORE);
   553                 }
   554                 mangledIdentifier.append(i);
   555                 needUnderscore = true;
   556             }
   557         }
   559         return mangledIdentifier.toString();
   560     }
   562     private static String mangleContainerClash(String identifier) {
   563         return identifier + ID_CONTAINER_CLASH_CHAR;
   564     }
   566     /**
   567      * Implements Section 1.3.2.9 of Java2IDL Mapping. Container in this
   568      * context means the name of the java Class(excluding package) in which
   569      * the identifier is defined.  Comparison is case-insensitive.
   570      */
   571     private static boolean identifierClashesWithContainer
   572         (String mappedContainerName, String identifier) {
   574         return identifier.equalsIgnoreCase(mappedContainerName);
   575     }
   577     /**
   578      * Returns Unicode mangling as defined in Section 1.3.2.4 of
   579      * Java2IDL spec.
   580      *
   581      * "For Java identifiers that contain illegal OMG IDL identifier
   582      * characters such as '$' or Unicode characters outside of ISO Latin 1,
   583      * any such illegal characters are replaced by "U" followed by the
   584      * 4 hexadecimal characters(in upper case) representing the Unicode
   585      * value.  So, the Java name a$b is mapped to aU0024b and
   586      * x\u03bCy is mapped to xU03BCy."
   587      */
   588     public static String charToUnicodeRepresentation(char c) {
   590         int orig = (int) c;
   591         StringBuffer hexString = new StringBuffer();
   593         int value = orig;
   595         while( value > 0 ) {
   596             int div = value / 16;
   597             int mod = value % 16;
   598             hexString.insert(0, HEX_DIGITS[mod]);
   599             value = div;
   600         }
   602         int numZerosToAdd = 4 - hexString.length();
   603         for(int i = 0; i < numZerosToAdd; i++) {
   604             hexString.insert(0, "0");
   605         }
   607         hexString.insert(0, "U");
   608         return hexString.toString();
   609     }
   611     private static boolean isIDLIdentifier(String identifier) {
   613         boolean isIdentifier = true;
   615         for(int i = 0; i < identifier.length(); i++) {
   616             char nextChar = identifier.charAt(i);
   617             // 1st char must be alphbetic.
   618             isIdentifier  = (i == 0) ?
   619                 isIDLAlphabeticChar(nextChar) :
   620                 isIDLIdentifierChar(nextChar);
   621             if( !isIdentifier ) {
   622                 break;
   623             }
   624         }
   626         return isIdentifier;
   628     }
   630     private static boolean isIDLIdentifierChar(char c) {
   631         return (isIDLAlphabeticChar(c) ||
   632                 isIDLDecimalDigit(c)   ||
   633                 isUnderscore(c));
   634     }
   636     /**
   637      * True if character is one of 114 Alphabetic characters as
   638      * specified in Table 2 of Chapter 3 in CORBA spec.
   639      */
   640     private static boolean isIDLAlphabeticChar(char c) {
   642         // NOTE that we can't use the java.lang.Character
   643         // isUpperCase, isLowerCase, etc. methods since they
   644         // include many characters other than the Alphabetic list in
   645         // the CORBA spec.  Instead, we test for inclusion in the
   646         // Unicode value ranges for the corresponding legal characters.
   648         boolean alphaChar =
   649             (
   650              // A - Z
   651              ((c >= 0x0041) && (c <= 0x005A))
   653              ||
   655              // a - z
   656              ((c >= 0x0061) && (c <= 0x007A))
   658              ||
   660              // other letter uppercase, other letter lowercase, which is
   661              // the entire upper half of C1 Controls except X and /
   662              ((c >= 0x00C0) && (c <= 0x00FF)
   663               && (c != 0x00D7) && (c != 0x00F7)));
   665         return alphaChar;
   666     }
   668     /**
   669      * True if character is one of 10 Decimal Digits
   670      * specified in Table 3 of Chapter 3 in CORBA spec.
   671      */
   672     private static boolean isIDLDecimalDigit(char c) {
   673         return ( (c >= 0x0030) && (c <= 0x0039) );
   674     }
   676     private static boolean isUnderscore(char c) {
   677         return ( c == 0x005F );
   678     }
   680     /**
   681      * Mangle an overloaded method name as defined in Section 1.3.2.6 of
   682      * Java2IDL spec.  Current value of method name is passed in as argument.
   683      * We can't start from original method name since the name might have
   684      * been partially mangled as a result of the other rules.
   685      */
   686     private static String mangleOverloadedMethod(String mangledName, Method m) {
   688         IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
   690         // Start by appending the separator string
   691         String newMangledName = mangledName + OVERLOADED_TYPE_SEPARATOR;
   693         Class[] parameterTypes = m.getParameterTypes();
   695         for(int i = 0; i < parameterTypes.length; i++) {
   696             Class nextParamType = parameterTypes[i];
   698             if( i > 0 ) {
   699                 newMangledName = newMangledName + OVERLOADED_TYPE_SEPARATOR;
   700             }
   701             IDLType idlType = classToIDLType(nextParamType);
   703             String moduleName = idlType.getModuleName();
   704             String memberName = idlType.getMemberName();
   706             String typeName = (moduleName.length() > 0) ?
   707                 moduleName + UNDERSCORE + memberName : memberName;
   709             if( !idlTypesUtil.isPrimitive(nextParamType) &&
   710                 (idlTypesUtil.getSpecialCaseIDLTypeMapping(nextParamType)
   711                  == null) &&
   712                 isIDLKeyword(typeName) ) {
   713                 typeName = mangleIDLKeywordClash(typeName);
   714             }
   716             typeName = mangleUnicodeChars(typeName);
   718             newMangledName = newMangledName + typeName;
   719         }
   721         return newMangledName;
   722     }
   725     private static IDLType classToIDLType(Class c) {
   727         IDLType idlType = null;
   728         IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
   730         if( idlTypesUtil.isPrimitive(c) ) {
   732             idlType = idlTypesUtil.getPrimitiveIDLTypeMapping(c);
   734         } else if( c.isArray() ) {
   736             // Calculate array depth, as well as base element type.
   737             Class componentType = c.getComponentType();
   738             int numArrayDimensions = 1;
   739             while(componentType.isArray()) {
   740                 componentType = componentType.getComponentType();
   741                 numArrayDimensions++;
   742             }
   743             IDLType componentIdlType = classToIDLType(componentType);
   745             String[] modules = BASE_IDL_ARRAY_MODULE_TYPE;
   746             if( componentIdlType.hasModule() ) {
   747                 modules = (String[])ObjectUtility.concatenateArrays( modules,
   748                     componentIdlType.getModules() ) ;
   749             }
   751             String memberName = BASE_IDL_ARRAY_ELEMENT_TYPE +
   752                 numArrayDimensions + UNDERSCORE +
   753                 componentIdlType.getMemberName();
   755             idlType = new IDLType(c, modules, memberName);
   757         } else {
   758             idlType = idlTypesUtil.getSpecialCaseIDLTypeMapping(c);
   760             if (idlType == null) {
   761                 // Section 1.3.2.5 of Java2IDL spec defines mangling rules for
   762                 // inner classes.
   763                 String memberName = getUnmappedContainerName(c);
   765                 // replace inner class separator with double underscore
   766                 memberName = memberName.replaceAll("\\$",
   767                                                    INNER_CLASS_SEPARATOR);
   769                 if( hasLeadingUnderscore(memberName) ) {
   770                     memberName = mangleLeadingUnderscore(memberName);
   771                 }
   773                 // Get raw package name.  If there is a package, it
   774                 // will still have the "." separators and none of the
   775                 // mangling rules will have been applied.
   776                 String packageName = getPackageName(c);
   778                 if (packageName == null) {
   779                     idlType = new IDLType( c, memberName ) ;
   780                 } else {
   781                     // If this is a generated IDL Entity Type we need to
   782                     // prepend org_omg_boxedIDL per sections 1.3.5 and 1.3.9
   783                     if (idlTypesUtil.isEntity(c)) {
   784                         packageName = "org.omg.boxedIDL." + packageName ;
   785                     }
   787                     // Section 1.3.2.1 and 1.3.2.6 of Java2IDL spec defines
   788                     // rules for mapping java packages to IDL modules and for
   789                     // mangling module name portion of type name.  NOTE that
   790                     // of the individual identifier mangling rules,
   791                     // only the leading underscore test is done here.
   792                     // The other two(IDL Keyword, Illegal Unicode chars) are
   793                     // done in mangleOverloadedMethodName.
   794                     StringTokenizer tokenizer =
   795                         new StringTokenizer(packageName, ".");
   797                     String[] modules = new String[ tokenizer.countTokens() ] ;
   798                     int index = 0 ;
   799                     while (tokenizer.hasMoreElements()) {
   800                         String next = tokenizer.nextToken();
   801                         String moreMangled = hasLeadingUnderscore( next ) ?
   802                             mangleLeadingUnderscore( next ) : next;
   804                         modules[index++] = moreMangled ;
   805                     }
   807                     idlType = new IDLType(c, modules, memberName);
   808                 }
   809             }
   810         }
   812         return idlType;
   813     }
   815     /**
   816      * Return Class' package name or null if there is no package.
   817      */
   818     private static String getPackageName(Class c) {
   819         Package thePackage = c.getPackage();
   820         String packageName = null;
   822         // Try to get package name by introspection.  Some classloaders might
   823         // not provide this information, so check for null.
   824         if( thePackage != null ) {
   825             packageName = thePackage.getName();
   826         } else {
   827             // brute force method
   828             String fullyQualifiedClassName = c.getName();
   829             int lastDot = fullyQualifiedClassName.indexOf('.');
   830             packageName = (lastDot == -1) ? null :
   831                 fullyQualifiedClassName.substring(0, lastDot);
   832         }
   833         return packageName;
   834     }
   836     private static String getMappedContainerName(Class c) {
   837         String unmappedName = getUnmappedContainerName(c);
   839         return mangleIdentifier(unmappedName);
   840     }
   842     /**
   843      * Return portion of class name excluding package name.
   844      */
   845     private static String getUnmappedContainerName(Class c) {
   847         String memberName  = null;
   848         String packageName = getPackageName(c);
   850         String fullyQualifiedClassName = c.getName();
   852         if( packageName != null ) {
   853             int packageLength = packageName.length();
   854             memberName = fullyQualifiedClassName.substring(packageLength + 1);
   855         } else {
   856             memberName = fullyQualifiedClassName;
   858         }
   860         return memberName;
   861     }
   863     /**
   864      * Internal helper class for tracking information related to each
   865      * interface method while we're building the name translation table.
   866      */
   867     private static class IDLMethodInfo
   868     {
   869         public Method method;
   870         public boolean isProperty;
   872         // If this is a property, originalName holds the original
   873         // attribute name. Otherwise, it holds the original method name.
   874         public String originalName;
   876         // If this is a property, mangledName holds the mangled attribute
   877         // name. Otherwise, it holds the mangled method name.
   878         public String mangledName;
   880     }
   882     public String toString() {
   884         StringBuffer contents = new StringBuffer();
   885         contents.append("IDLNameTranslator[" );
   886         for( int ctr=0; ctr<interf_.length; ctr++) {
   887             if (ctr != 0)
   888                 contents.append( " " ) ;
   889             contents.append( interf_[ctr].getName() ) ;
   890         }
   891         contents.append("]\n");
   892         for(Iterator iter = methodToIDLNameMap_.keySet().iterator();
   893             iter.hasNext();) {
   895             Method method  = (Method) iter.next();
   896             String idlName = (String) methodToIDLNameMap_.get(method);
   898             contents.append(idlName + ":" + method + "\n");
   900         }
   902         return contents.toString();
   903     }
   905     public static void main(String[] args) {
   907         Class remoteInterface = java.rmi.Remote.class;
   909         if( args.length > 0 ) {
   910             String className = args[0];
   911             try {
   912                 remoteInterface = Class.forName(className);
   913             } catch(Exception e) {
   914                 e.printStackTrace();
   915                 System.exit(-1);
   916             }
   917         }
   919         System.out.println("Building name translation for " + remoteInterface);
   920         try {
   921             IDLNameTranslator nameTranslator =
   922                 IDLNameTranslatorImpl.get(remoteInterface);
   923             System.out.println(nameTranslator);
   924         } catch(IllegalStateException ise) {
   925             ise.printStackTrace();
   926         }
   927     }
   928 }

mercurial