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 } |
|