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