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