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

Mon, 19 Aug 2013 15:22:59 +0100

author
msheppar
date
Mon, 19 Aug 2013 15:22:59 +0100
changeset 520
9c75c61d97f8
parent 158
91006f157c46
child 553
5ca1b4c282b8
permissions
-rw-r--r--

8022940: Enhance CORBA translations
Reviewed-by: coffeys, alanb, skoivu

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

mercurial