/* * @(#)IDLNameTranslatorImpl.java 1.12 04/06/21 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.corba.se.impl.presentation.rmi ; import java.security.AccessController; import java.security.PrivilegedAction; import java.lang.reflect.Method; import java.math.BigInteger; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.util.Iterator; import java.util.HashMap; import java.util.StringTokenizer; import com.sun.corba.se.spi.presentation.rmi.IDLNameTranslator ; import com.sun.corba.se.impl.presentation.rmi.IDLType ; import com.sun.corba.se.impl.presentation.rmi.IDLTypeException ; import com.sun.corba.se.impl.presentation.rmi.IDLTypesUtil ; import com.sun.corba.se.impl.orbutil.ObjectUtility ; /** * Bidirectional translator between RMI-IIOP interface methods and * and IDL Names. */ public class IDLNameTranslatorImpl implements IDLNameTranslator { // From CORBA Spec, Table 6 Keywords. // Note that since all IDL identifiers are case // insensitive, java identifier comparisons to these // will be case insensitive also. private static String[] IDL_KEYWORDS = { "abstract", "any", "attribute", "boolean", "case", "char", "const", "context", "custom", "default", "double", "enum", "exception", "factory", "FALSE", "fixed", "float", "in", "inout", "interface", "long", "module", "native", "Object", "octet", "oneway", "out", "private", "public", "raises", "readonly", "sequence", "short", "string", "struct", "supports", "switch", "TRUE", "truncatable", "typedef", "unsigned", "union", "ValueBase", "valuetype", "void", "wchar", "wstring" }; private static char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; private static final String UNDERSCORE = "_"; // used to mangle java inner class names private static final String INNER_CLASS_SEPARATOR = UNDERSCORE + UNDERSCORE; // used to form IDL array type names private static final String[] BASE_IDL_ARRAY_MODULE_TYPE= new String[] { "org", "omg", "boxedRMI" } ; private static final String BASE_IDL_ARRAY_ELEMENT_TYPE = "seq"; // used to mangling java identifiers that have a leading underscore private static final String LEADING_UNDERSCORE_CHAR = "J"; private static final String ID_CONTAINER_CLASH_CHAR = UNDERSCORE; // separator used between types in a mangled overloaded method name private static final String OVERLOADED_TYPE_SEPARATOR = UNDERSCORE + UNDERSCORE; // string appended to attribute if it clashes with a method name private static final String ATTRIBUTE_METHOD_CLASH_MANGLE_CHARS = UNDERSCORE + UNDERSCORE; // strings prepended to the attribute names in order to form their // IDL names. private static final String GET_ATTRIBUTE_PREFIX = "_get_"; private static final String SET_ATTRIBUTE_PREFIX = "_set_"; private static final String IS_ATTRIBUTE_PREFIX = "_get_"; private static Set idlKeywords_; static { idlKeywords_ = new HashSet(); for(int i = 0; i < IDL_KEYWORDS.length; i++) { String next = (String) IDL_KEYWORDS[i]; // Convert keyword to all caps to ease equality // check. String keywordAllCaps = next.toUpperCase(); idlKeywords_.add(keywordAllCaps); } } // // Instance state // // Remote interface for name translation. private Class[] interf_; // Maps used to hold name translations. These do not need to be // synchronized since the translation is never modified after // initialization. private Map methodToIDLNameMap_; private Map IDLNameToMethodMap_; private Method[] methods_; /** * Return an IDLNameTranslator for the given interface. * * @throws IllegalStateException if given class is not a valid * RMI/IIOP Remote Interface */ public static IDLNameTranslator get( Class interf ) { return new IDLNameTranslatorImpl(new Class[] { interf } ); } /** * Return an IDLNameTranslator for the given interfacex. * * @throws IllegalStateException if given classes are not valid * RMI/IIOP Remote Interfaces */ public static IDLNameTranslator get( Class[] interfaces ) { return new IDLNameTranslatorImpl(interfaces ); } public static String getExceptionId( Class cls ) { // Requirements for this method: // 1. cls must be an exception but not a RemoteException. // 2. If cls has an IDL keyword name, an underscore is prepended (1.3.2.2). // 3. If cls jas a leading underscore, J is prepended (1.3.2.3). // 4. If cls has an illegal IDL ident char, it is mapped to UXXXX where // XXXX is the unicode value in hex of the char (1.3.2.4). // 5. double underscore for inner class (1.3.2.5). // 6. The ID is "IDL:" + name with / separators + ":1.0". IDLType itype = classToIDLType( cls ) ; return itype.getExceptionName() ; } public Class[] getInterfaces() { return interf_; } public Method[] getMethods() { return methods_ ; } public Method getMethod( String idlName ) { return (Method) IDLNameToMethodMap_.get(idlName); } public String getIDLName( Method method ) { return (String) methodToIDLNameMap_.get(method); } /** * Initialize an IDLNameTranslator for the given interface. * * @throws IllegalStateException if given class is not a valid * RMI/IIOP Remote Interface */ private IDLNameTranslatorImpl(Class[] interfaces) { try { IDLTypesUtil idlTypesUtil = new IDLTypesUtil(); for (int ctr=0; ctr 0 ) { int div = value / 16; int mod = value % 16; hexString.insert(0, HEX_DIGITS[mod]); value = div; } int numZerosToAdd = 4 - hexString.length(); for(int i = 0; i < numZerosToAdd; i++) { hexString.insert(0, "0"); } hexString.insert(0, "U"); return hexString.toString(); } private static boolean isIDLIdentifier(String identifier) { boolean isIdentifier = true; for(int i = 0; i < identifier.length(); i++) { char nextChar = identifier.charAt(i); // 1st char must be alphbetic. isIdentifier = (i == 0) ? isIDLAlphabeticChar(nextChar) : isIDLIdentifierChar(nextChar); if( !isIdentifier ) { break; } } return isIdentifier; } private static boolean isIDLIdentifierChar(char c) { return (isIDLAlphabeticChar(c) || isIDLDecimalDigit(c) || isUnderscore(c)); } /** * True if character is one of 114 Alphabetic characters as * specified in Table 2 of Chapter 3 in CORBA spec. */ private static boolean isIDLAlphabeticChar(char c) { // NOTE that we can't use the java.lang.Character // isUpperCase, isLowerCase, etc. methods since they // include many characters other than the Alphabetic list in // the CORBA spec. Instead, we test for inclusion in the // Unicode value ranges for the corresponding legal characters. boolean alphaChar = ( // A - Z ((c >= 0x0041) && (c <= 0x005A)) || // a - z ((c >= 0x0061) && (c <= 0x007A)) || // other letter uppercase, other letter lowercase, which is // the entire upper half of C1 Controls except X and / ((c >= 0x00C0) && (c <= 0x00FF) && (c != 0x00D7) && (c != 0x00F7))); return alphaChar; } /** * True if character is one of 10 Decimal Digits * specified in Table 3 of Chapter 3 in CORBA spec. */ private static boolean isIDLDecimalDigit(char c) { return ( (c >= 0x0030) && (c <= 0x0039) ); } private static boolean isUnderscore(char c) { return ( c == 0x005F ); } /** * Mangle an overloaded method name as defined in Section 1.3.2.6 of * Java2IDL spec. Current value of method name is passed in as argument. * We can't start from original method name since the name might have * been partially mangled as a result of the other rules. */ private static String mangleOverloadedMethod(String mangledName, Method m) { IDLTypesUtil idlTypesUtil = new IDLTypesUtil(); // Start by appending the separator string String newMangledName = mangledName + OVERLOADED_TYPE_SEPARATOR; Class[] parameterTypes = m.getParameterTypes(); for(int i = 0; i < parameterTypes.length; i++) { Class nextParamType = parameterTypes[i]; if( i > 0 ) { newMangledName = newMangledName + OVERLOADED_TYPE_SEPARATOR; } IDLType idlType = classToIDLType(nextParamType); String moduleName = idlType.getModuleName(); String memberName = idlType.getMemberName(); String typeName = (moduleName.length() > 0) ? moduleName + UNDERSCORE + memberName : memberName; if( !idlTypesUtil.isPrimitive(nextParamType) && (idlTypesUtil.getSpecialCaseIDLTypeMapping(nextParamType) == null) && isIDLKeyword(typeName) ) { typeName = mangleIDLKeywordClash(typeName); } typeName = mangleUnicodeChars(typeName); newMangledName = newMangledName + typeName; } return newMangledName; } private static IDLType classToIDLType(Class c) { IDLType idlType = null; IDLTypesUtil idlTypesUtil = new IDLTypesUtil(); if( idlTypesUtil.isPrimitive(c) ) { idlType = idlTypesUtil.getPrimitiveIDLTypeMapping(c); } else if( c.isArray() ) { // Calculate array depth, as well as base element type. Class componentType = c.getComponentType(); int numArrayDimensions = 1; while(componentType.isArray()) { componentType = componentType.getComponentType(); numArrayDimensions++; } IDLType componentIdlType = classToIDLType(componentType); String[] modules = BASE_IDL_ARRAY_MODULE_TYPE; if( componentIdlType.hasModule() ) { modules = (String[])ObjectUtility.concatenateArrays( modules, componentIdlType.getModules() ) ; } String memberName = BASE_IDL_ARRAY_ELEMENT_TYPE + numArrayDimensions + UNDERSCORE + componentIdlType.getMemberName(); idlType = new IDLType(c, modules, memberName); } else { idlType = idlTypesUtil.getSpecialCaseIDLTypeMapping(c); if (idlType == null) { // Section 1.3.2.5 of Java2IDL spec defines mangling rules for // inner classes. String memberName = getUnmappedContainerName(c); // replace inner class separator with double underscore memberName = memberName.replaceAll("\\$", INNER_CLASS_SEPARATOR); if( hasLeadingUnderscore(memberName) ) { memberName = mangleLeadingUnderscore(memberName); } // Get raw package name. If there is a package, it // will still have the "." separators and none of the // mangling rules will have been applied. String packageName = getPackageName(c); if (packageName == null) { idlType = new IDLType( c, memberName ) ; } else { // If this is a generated IDL Entity Type we need to // prepend org_omg_boxedIDL per sections 1.3.5 and 1.3.9 if (idlTypesUtil.isEntity(c)) { packageName = "org.omg.boxedIDL." + packageName ; } // Section 1.3.2.1 and 1.3.2.6 of Java2IDL spec defines // rules for mapping java packages to IDL modules and for // mangling module name portion of type name. NOTE that // of the individual identifier mangling rules, // only the leading underscore test is done here. // The other two(IDL Keyword, Illegal Unicode chars) are // done in mangleOverloadedMethodName. StringTokenizer tokenizer = new StringTokenizer(packageName, "."); String[] modules = new String[ tokenizer.countTokens() ] ; int index = 0 ; while (tokenizer.hasMoreElements()) { String next = tokenizer.nextToken(); String moreMangled = hasLeadingUnderscore( next ) ? mangleLeadingUnderscore( next ) : next; modules[index++] = moreMangled ; } idlType = new IDLType(c, modules, memberName); } } } return idlType; } /** * Return Class' package name or null if there is no package. */ private static String getPackageName(Class c) { Package thePackage = c.getPackage(); String packageName = null; // Try to get package name by introspection. Some classloaders might // not provide this information, so check for null. if( thePackage != null ) { packageName = thePackage.getName(); } else { // brute force method String fullyQualifiedClassName = c.getName(); int lastDot = fullyQualifiedClassName.indexOf('.'); packageName = (lastDot == -1) ? null : fullyQualifiedClassName.substring(0, lastDot); } return packageName; } private static String getMappedContainerName(Class c) { String unmappedName = getUnmappedContainerName(c); return mangleIdentifier(unmappedName); } /** * Return portion of class name excluding package name. */ private static String getUnmappedContainerName(Class c) { String memberName = null; String packageName = getPackageName(c); String fullyQualifiedClassName = c.getName(); if( packageName != null ) { int packageLength = packageName.length(); memberName = fullyQualifiedClassName.substring(packageLength + 1); } else { memberName = fullyQualifiedClassName; } return memberName; } /** * Internal helper class for tracking information related to each * interface method while we're building the name translation table. */ private static class IDLMethodInfo { public Method method; public boolean isProperty; // If this is a property, originalName holds the original // attribute name. Otherwise, it holds the original method name. public String originalName; // If this is a property, mangledName holds the mangled attribute // name. Otherwise, it holds the mangled method name. public String mangledName; } public String toString() { StringBuffer contents = new StringBuffer(); contents.append("IDLNameTranslator[" ); for( int ctr=0; ctr 0 ) { String className = args[0]; try { remoteInterface = Class.forName(className); } catch(Exception e) { e.printStackTrace(); System.exit(-1); } } System.out.println("Building name translation for " + remoteInterface); try { IDLNameTranslator nameTranslator = IDLNameTranslatorImpl.get(remoteInterface); System.out.println(nameTranslator); } catch(IllegalStateException ise) { ise.printStackTrace(); } } }