001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.iiop.rmi;
023:
024: import java.io.Externalizable;
025: import java.io.ObjectStreamClass;
026: import java.io.Serializable;
027: import java.lang.reflect.Field;
028: import java.lang.reflect.Method;
029: import java.lang.reflect.Modifier;
030: import java.util.ArrayList;
031:
032: /**
033: * Common base class of ValueAnalysis and InterfaceAnalysis.
034: *
035: * Routines here are conforming to the "Java(TM) Language to IDL Mapping
036: * Specification", version 1.1 (01-06-07).
037: *
038: * @author <a href="mailto:osh@sparre.dk">Ole Husgaard</a>
039: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
040: * @version $Revision: 63377 $
041: */
042: public abstract class ContainerAnalysis extends ClassAnalysis {
043: // Constants -----------------------------------------------------
044:
045: /** Flags a method as overloaded. */
046: protected final byte M_OVERLOADED = 1;
047:
048: /** Flags a method as the accessor of a read-write property. */
049: protected final byte M_READ = 2;
050:
051: /** Flags a method as the mutator of a read-write property. */
052: protected final byte M_WRITE = 4;
053:
054: /** Flags a method as the accessor of a read-only property. */
055: protected final byte M_READONLY = 8;
056:
057: /** Flags a method as being inherited. */
058: protected final byte M_INHERITED = 16;
059:
060: /**
061: * Flags a method as being the writeObject() method
062: * used for serialization.
063: */
064: protected final byte M_WRITEOBJECT = 32;
065:
066: /** Flags a field as being a constant (public final static). */
067: protected final byte F_CONSTANT = 1;
068:
069: /**
070: * Flags a field as being the special <code> public final static
071: * java.io.ObjectStreamField[] serialPersistentFields</code> field.
072: */
073: protected final byte F_SPFFIELD = 2;
074:
075: // Attributes ----------------------------------------------------
076:
077: /**
078: * Array of all java methods.
079: */
080: protected Method[] methods;
081:
082: /**
083: * Array with flags for all java methods.
084: */
085: protected byte[] m_flags;
086:
087: /**
088: * Index of the mutator for read-write attributes.
089: * Only entries <code>i</code> where <code>(m_flags[i]&M_READ) != 0</code>
090: * are used. These entries contain the index of the mutator method
091: * corresponding to the accessor method.
092: */
093: protected int[] mutators;
094:
095: /**
096: * Array of all java fields.
097: */
098: protected Field[] fields;
099:
100: /**
101: * Array with flags for all java fields.
102: */
103: protected byte[] f_flags;
104:
105: /**
106: * The class hash code, as specified in "The Common Object Request
107: * Broker: Architecture and Specification" (01-02-33), section 10.6.2.
108: */
109: protected long classHashCode = 0;
110:
111: /**
112: * The repository ID.
113: * This is in the RMI hashed format, like
114: * "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8".
115: */
116: protected String repositoryId;
117:
118: /**
119: * The prefix and postfix of members repository ID.
120: * These are used to calculate member repository IDs and are like
121: * "RMI:java.util.Hashtable." and ":C03324C0EA357270:13BB0F25214AE4B8".
122: */
123: protected String memberPrefix, memberPostfix;
124:
125: /**
126: * Array of analysis of the interfaces implemented/extended here.
127: */
128: protected InterfaceAnalysis[] interfaces;
129:
130: /**
131: * Array of analysis of the abstract base valuetypes implemented/extended here.
132: */
133: protected ValueAnalysis[] abstractBaseValuetypes;
134:
135: /**
136: * Array of attributes.
137: */
138: protected AttributeAnalysis[] attributes;
139:
140: /**
141: * Array of Constants.
142: */
143: protected ConstantAnalysis[] constants;
144:
145: /**
146: * Array of operations.
147: */
148: protected OperationAnalysis[] operations;
149:
150: // Static --------------------------------------------------------
151:
152: private static final org.jboss.logging.Logger logger = org.jboss.logging.Logger
153: .getLogger(ContainerAnalysis.class);
154:
155: // Constructors -------------------------------------------------
156:
157: protected ContainerAnalysis(Class cls) {
158: super (cls);
159:
160: if (cls == java.lang.Object.class
161: || cls == java.io.Serializable.class
162: || cls == java.io.Externalizable.class)
163: throw new IllegalArgumentException(
164: "Cannot analyze special class: " + cls.getName());
165:
166: this .cls = cls;
167: }
168:
169: protected void doAnalyze() throws RMIIIOPViolationException {
170: analyzeInterfaces();
171: analyzeMethods();
172: analyzeFields();
173: calculateClassHashCode();
174: calculateRepositoryId();
175: analyzeAttributes();
176: analyzeConstants();
177: analyzeOperations();
178: fixupOverloadedOperationNames();
179: }
180:
181: // Public --------------------------------------------------------
182:
183: /**
184: * Return the interfaces.
185: */
186: public InterfaceAnalysis[] getInterfaces() {
187: logger.debug(cls + " Interface count: " + interfaces.length);
188: return (InterfaceAnalysis[]) interfaces.clone();
189: }
190:
191: /**
192: * Return the abstract base valuetypes.
193: */
194: public ValueAnalysis[] getAbstractBaseValuetypes() {
195: logger.debug(cls + " Abstract base valuetype count: "
196: + abstractBaseValuetypes.length);
197: return (ValueAnalysis[]) abstractBaseValuetypes.clone();
198: }
199:
200: /**
201: * Return the attributes.
202: */
203: public AttributeAnalysis[] getAttributes() {
204: logger.debug(cls + " Attribute count: " + attributes.length);
205: return (AttributeAnalysis[]) attributes.clone();
206: }
207:
208: /**
209: * Return the constants.
210: */
211: public ConstantAnalysis[] getConstants() {
212: logger.debug(cls + " Constants count: " + constants.length);
213: return (ConstantAnalysis[]) constants.clone();
214: }
215:
216: /**
217: * Return the operations.
218: */
219: public OperationAnalysis[] getOperations() {
220: logger.debug(cls + " Operations count: " + operations.length);
221: return (OperationAnalysis[]) operations.clone();
222: }
223:
224: /**
225: * Return the repository ID.
226: */
227: public String getRepositoryId() {
228: return repositoryId;
229: }
230:
231: /**
232: * Return a repository ID for a member.
233: *
234: * @param memberName The Java name of the member.
235: */
236: public String getMemberRepositoryId(String memberName) {
237: return memberPrefix + escapeIRName(memberName) + memberPostfix;
238: }
239:
240: /**
241: * Return the fully qualified IDL module name that this
242: * analysis should be placed in.
243: */
244: public String getIDLModuleName() {
245: if (idlModuleName == null) {
246: String pkgName = cls.getPackage().getName();
247: StringBuffer b = new StringBuffer();
248:
249: while (!"".equals(pkgName)) {
250: int idx = pkgName.indexOf('.');
251: String n = (idx == -1) ? pkgName : pkgName.substring(0,
252: idx);
253:
254: b.append("::").append(Util.javaToIDLName(n));
255:
256: pkgName = (idx == -1) ? "" : pkgName.substring(idx + 1);
257: }
258: idlModuleName = b.toString();
259: }
260: return idlModuleName;
261: }
262:
263: // Protected -----------------------------------------------------
264:
265: /**
266: * Convert an integer to a 16-digit hex string.
267: */
268: protected String toHexString(int i) {
269: String s = Integer.toHexString(i).toUpperCase();
270:
271: if (s.length() < 8)
272: return "00000000".substring(0, 8 - s.length()) + s;
273: else
274: return s;
275: }
276:
277: /**
278: * Convert a long to a 16-digit hex string.
279: */
280: protected String toHexString(long l) {
281: String s = Long.toHexString(l).toUpperCase();
282:
283: if (s.length() < 16)
284: return "0000000000000000".substring(0, 16 - s.length()) + s;
285: else
286: return s;
287: }
288:
289: /**
290: * Check if a method is an accessor.
291: */
292: protected boolean isAccessor(Method m) {
293: Class returnType = m.getReturnType();
294: // JBAS-4473, look for get<name>()
295: String name = m.getName();
296: if (!(name.startsWith("get") && name.length() > "get".length()))
297: if (!(name.startsWith("is") && name.length() > "is"
298: .length())
299: || !(returnType == Boolean.TYPE))
300: return false;
301: if (returnType == Void.TYPE)
302: return false;
303: if (m.getParameterTypes().length != 0)
304: return false;
305:
306: return hasNonAppExceptions(m);
307: }
308:
309: /**
310: * Check if a method is a mutator.
311: */
312: protected boolean isMutator(Method m) {
313: // JBAS-4473, look for set<name>()
314: String name = m.getName();
315: if (!(name.startsWith("set") && name.length() > "set".length()))
316: return false;
317: if (m.getReturnType() != Void.TYPE)
318: return false;
319: if (m.getParameterTypes().length != 1)
320: return false;
321: return hasNonAppExceptions(m);
322: }
323:
324: /**
325: * Check if a method throws anything checked other than
326: * java.rmi.RemoteException and its subclasses.
327: */
328: protected boolean hasNonAppExceptions(Method m) {
329: Class[] ex = m.getExceptionTypes();
330:
331: for (int i = 0; i < ex.length; ++i)
332: if (!java.rmi.RemoteException.class.isAssignableFrom(ex[i]))
333: return false;
334: return true;
335: }
336:
337: /**
338: * Analyze the fields of the class.
339: * This will fill in the <code>fields</code> and <code>f_flags</code>
340: * arrays.
341: */
342: protected void analyzeFields() {
343: logger.debug(cls + " analyzeFields");
344:
345: //fields = cls.getFields();
346: fields = cls.getDeclaredFields();
347: f_flags = new byte[fields.length];
348:
349: for (int i = 0; i < fields.length; ++i) {
350: int mods = fields[i].getModifiers();
351:
352: if (Modifier.isFinal(mods) && Modifier.isStatic(mods)
353: && Modifier.isPublic(mods))
354: f_flags[i] |= F_CONSTANT;
355: }
356:
357: logger.debug(cls + " analyzeFields fields=" + fields.length);
358: }
359:
360: /**
361: * Analyze the interfaces of the class.
362: * This will fill in the <code>interfaces</code> array.
363: */
364: protected void analyzeInterfaces() throws RMIIIOPViolationException {
365: logger.debug(cls + " analyzeInterfaces");
366:
367: Class[] intfs = cls.getInterfaces();
368: ArrayList a = new ArrayList();
369: ArrayList b = new ArrayList();
370:
371: for (int i = 0; i < intfs.length; ++i) {
372: // Ignore java.rmi.Remote
373: if (intfs[i] == java.rmi.Remote.class)
374: continue;
375: // Ignore java.io.Serializable
376: if (intfs[i] == java.io.Serializable.class)
377: continue;
378: // Ignore java.io.Externalizable
379: if (intfs[i] == java.io.Externalizable.class)
380: continue;
381: if (!RmiIdlUtil.isAbstractValueType(intfs[i])) {
382: a.add(InterfaceAnalysis.getInterfaceAnalysis(intfs[i]));
383: } else {
384: b.add(ValueAnalysis.getValueAnalysis(intfs[i]));
385: }
386: }
387:
388: interfaces = new InterfaceAnalysis[a.size()];
389: interfaces = (InterfaceAnalysis[]) a.toArray(interfaces);
390:
391: abstractBaseValuetypes = new ValueAnalysis[b.size()];
392: abstractBaseValuetypes = (ValueAnalysis[]) b
393: .toArray(abstractBaseValuetypes);
394:
395: logger.debug(cls + " analyzeInterfaces interfaces="
396: + interfaces.length + " abstractBaseValueTypes="
397: + abstractBaseValuetypes.length);
398: }
399:
400: /**
401: * Analyze the methods of the class.
402: * This will fill in the <code>methods</code> and <code>m_flags</code>
403: * arrays.
404: */
405: protected void analyzeMethods() {
406: logger.debug(cls + " analyzeMethods");
407:
408: // The dynamic stub and skeleton strategy generation mechanism
409: // requires the inclusion of inherited methods in the analysis of
410: // remote interfaces. To speed things up, inherited methods are
411: // not considered in the analysis of a class or non-remote interface.
412: if (cls.isInterface()
413: && java.rmi.Remote.class.isAssignableFrom(cls))
414: methods = cls.getMethods();
415: else
416: methods = cls.getDeclaredMethods();
417: m_flags = new byte[methods.length];
418: mutators = new int[methods.length];
419:
420: // Find read-write properties
421: for (int i = 0; i < methods.length; ++i)
422: mutators[i] = -1; // no mutator here
423: for (int i = 0; i < methods.length; ++i) {
424: logger.debug("analyzeMethods(): method[" + i
425: + "].getName()=\"" + methods[i].getName() + "\".");
426:
427: if (isAccessor(methods[i]) && (m_flags[i] & M_READ) == 0) {
428: String attrName = attributeReadName(methods[i]
429: .getName());
430: Class iReturn = methods[i].getReturnType();
431: for (int j = i + 1; j < methods.length; ++j) {
432: if (isMutator(methods[j])
433: && (m_flags[j] & M_WRITE) == 0
434: && attrName
435: .equals(attributeWriteName(methods[j]
436: .getName()))) {
437: Class[] jParams = methods[j]
438: .getParameterTypes();
439: if (jParams.length == 1
440: && jParams[0] == iReturn) {
441: m_flags[i] |= M_READ;
442: m_flags[j] |= M_WRITE;
443: mutators[i] = j;
444: break;
445: }
446: }
447: }
448: } else if (isMutator(methods[i])
449: && (m_flags[i] & M_WRITE) == 0) {
450: String attrName = attributeWriteName(methods[i]
451: .getName());
452: Class[] iParams = methods[i].getParameterTypes();
453: for (int j = i + 1; j < methods.length; ++j) {
454: if (isAccessor(methods[j])
455: && (m_flags[j] & M_READ) == 0
456: && attrName
457: .equals(attributeReadName(methods[j]
458: .getName()))) {
459: Class jReturn = methods[j].getReturnType();
460: if (iParams.length == 1
461: && iParams[0] == jReturn) {
462: m_flags[i] |= M_WRITE;
463: m_flags[j] |= M_READ;
464: mutators[j] = i;
465: break;
466: }
467: }
468: }
469: }
470: }
471:
472: // Find read-only properties
473: for (int i = 0; i < methods.length; ++i)
474: if ((m_flags[i] & (M_READ | M_WRITE)) == 0
475: && isAccessor(methods[i]))
476: m_flags[i] |= M_READONLY;
477:
478: // Check for overloaded and inherited methods
479: for (int i = 0; i < methods.length; ++i) {
480: if ((m_flags[i] & (M_READ | M_WRITE | M_READONLY)) == 0) {
481: String iName = methods[i].getName();
482:
483: for (int j = i + 1; j < methods.length; ++j) {
484: if (iName.equals(methods[j].getName())) {
485: m_flags[i] |= M_OVERLOADED;
486: m_flags[j] |= M_OVERLOADED;
487: }
488: }
489: }
490:
491: if (methods[i].getDeclaringClass() != cls)
492: m_flags[i] |= M_INHERITED;
493: }
494:
495: logger.debug(cls + " analyzeMethods methods=" + methods.length);
496: }
497:
498: /**
499: * Convert an attribute read method name in Java format to
500: * an attribute name in Java format.
501: */
502: protected String attributeReadName(String name) {
503: if (name.startsWith("get"))
504: name = name.substring(3);
505: else if (name.startsWith("is"))
506: name = name.substring(2);
507: else
508: throw new IllegalArgumentException("Not an accessor: "
509: + name);
510:
511: return name;
512: }
513:
514: /**
515: * Convert an attribute write method name in Java format to
516: * an attribute name in Java format.
517: */
518: protected String attributeWriteName(String name) {
519: if (name.startsWith("set"))
520: name = name.substring(3);
521: else
522: throw new IllegalArgumentException("Not an accessor: "
523: + name);
524:
525: return name;
526: }
527:
528: /**
529: * Analyse constants.
530: * This will fill in the <code>constants</code> array.
531: */
532: protected void analyzeConstants() throws RMIIIOPViolationException {
533: logger.debug(cls + " analyzeConstants");
534:
535: ArrayList a = new ArrayList();
536:
537: for (int i = 0; i < fields.length; ++i) {
538: logger.debug("f_flags[" + i + "]=" + f_flags[i]);
539: if ((f_flags[i] & F_CONSTANT) == 0)
540: continue;
541:
542: Class type = fields[i].getType();
543:
544: // Only map primitives and java.lang.String
545: if (!type.isPrimitive() && type != java.lang.String.class) {
546: // It is an RMI/IIOP violation for interfaces.
547: if (cls.isInterface())
548: throw new RMIIIOPViolationException("Field \""
549: + fields[i].getName()
550: + "\" of interface \"" + cls.getName()
551: + "\" is a constant, but not of one "
552: + "of the primitive types, or String.",
553: "1.2.3");
554:
555: continue;
556: }
557:
558: String name = fields[i].getName();
559:
560: Object value;
561: try {
562: value = fields[i].get(null);
563: } catch (Exception ex) {
564: throw new RuntimeException(ex.toString());
565: }
566:
567: logger.debug("Constant[" + i + "] name= " + name);
568: logger.debug("Constant[" + i + "] type= " + type.getName());
569: logger.debug("Constant[" + i + "] value= " + value);
570: a.add(new ConstantAnalysis(name, type, value));
571: }
572:
573: constants = new ConstantAnalysis[a.size()];
574: constants = (ConstantAnalysis[]) a.toArray(constants);
575: logger.debug(cls + " analyzeConstants constant=" + a.size());
576: }
577:
578: /**
579: * Analyse attributes.
580: * This will fill in the <code>attributes</code> array.
581: */
582: protected void analyzeAttributes() throws RMIIIOPViolationException {
583: logger.debug(cls + " analyzeAttributes");
584:
585: ArrayList a = new ArrayList();
586:
587: for (int i = 0; i < methods.length; ++i) {
588: logger.debug("m_flags[" + i + "]=" + m_flags[i]);
589: //if ((m_flags[i]&M_INHERITED) != 0)
590: // continue;
591:
592: if ((m_flags[i] & (M_READ | M_READONLY)) != 0) {
593: // Read method of an attribute.
594: String name = attributeReadName(methods[i].getName());
595:
596: logger.debug("Attribute[" + i + "] name= " + name);
597: if ((m_flags[i] & M_READONLY) != 0)
598: a.add(new AttributeAnalysis(name, methods[i]));
599: else
600: a.add(new AttributeAnalysis(name, methods[i],
601: methods[mutators[i]]));
602: }
603: }
604:
605: attributes = new AttributeAnalysis[a.size()];
606: attributes = (AttributeAnalysis[]) a.toArray(attributes);
607:
608: logger.debug(cls + " analyzeAttributes attributes=" + a.size());
609: }
610:
611: /**
612: * Analyse operations.
613: * This will fill in the <code>operations</code> array.
614: * This implementation just creates an empty array; override
615: * in subclasses for a real analysis.
616: */
617: protected void analyzeOperations() throws RMIIIOPViolationException {
618: logger.debug(cls + " analyzeOperations");
619: operations = new OperationAnalysis[0];
620: logger.debug(cls + " analyzeOperations operations="
621: + operations.length);
622: }
623:
624: /**
625: * Fixup overloaded operation names.
626: * As specified in section 1.3.2.6.
627: */
628: protected void fixupOverloadedOperationNames()
629: throws RMIIIOPViolationException {
630: for (int i = 0; i < methods.length; ++i) {
631: if ((m_flags[i] & M_OVERLOADED) == 0)
632: continue;
633:
634: // Find the operation
635: OperationAnalysis oa = null;
636: String javaName = methods[i].getName();
637: for (int opIdx = 0; oa == null && opIdx < operations.length; ++opIdx)
638: if (operations[opIdx].getMethod().equals(methods[i]))
639: oa = operations[opIdx];
640:
641: if (oa == null)
642: continue; // This method is not mapped.
643:
644: // Calculate new IDL name
645: ParameterAnalysis[] parms = oa.getParameters();
646: StringBuffer b = new StringBuffer(oa.getIDLName());
647: if (parms.length == 0)
648: b.append("__");
649: for (int j = 0; j < parms.length; ++j) {
650: String s = parms[j].getTypeIDLName();
651:
652: if (s.startsWith("::"))
653: s = s.substring(2);
654:
655: if (s.startsWith("_")) {
656: // remove leading underscore in IDL escaped identifier
657: s = s.substring(1);
658: }
659:
660: b.append('_');
661:
662: while (!"".equals(s)) {
663: int idx = s.indexOf("::");
664:
665: b.append('_');
666:
667: if (idx == -1) {
668: b.append(s);
669: s = "";
670: } else {
671: b.append(s.substring(0, idx));
672: if (s.length() > idx + 2
673: && s.charAt(idx + 2) == '_') {
674: // remove leading underscore in IDL escaped identifier
675: s = s.substring(idx + 3);
676: } else {
677: s = s.substring(idx + 2);
678: }
679: }
680: }
681: }
682:
683: // Set new IDL name
684: oa.setIDLName(b.toString());
685: }
686: }
687:
688: /**
689: * Fixup names differing only in case.
690: * As specified in section 1.3.2.7.
691: */
692: protected void fixupCaseNames() throws RMIIIOPViolationException {
693: ArrayList entries = getContainedEntries();
694: boolean[] clash = new boolean[entries.size()];
695: String[] upperNames = new String[entries.size()];
696:
697: for (int i = 0; i < entries.size(); ++i) {
698: AbstractAnalysis aa = (AbstractAnalysis) entries.get(i);
699:
700: clash[i] = false;
701: upperNames[i] = aa.getIDLName().toUpperCase();
702:
703: for (int j = 0; j < i; ++j) {
704: if (upperNames[i].equals(upperNames[j])) {
705: clash[i] = true;
706: clash[j] = true;
707: }
708: }
709: }
710:
711: for (int i = 0; i < entries.size(); ++i) {
712: if (!clash[i])
713: continue;
714:
715: AbstractAnalysis aa = (AbstractAnalysis) entries.get(i);
716: boolean noUpper = true;
717: String name = aa.getIDLName();
718: StringBuffer b = new StringBuffer(name);
719: b.append('_');
720: for (int j = 0; j < name.length(); ++j) {
721: if (!Character.isUpperCase(name.charAt(j)))
722: continue;
723: if (noUpper)
724: noUpper = false;
725: else
726: b.append('_');
727: b.append(j);
728: }
729:
730: aa.setIDLName(b.toString());
731: }
732: }
733:
734: /**
735: * Return a list of all the entries contained here.
736: *
737: * @param entries The list of entries contained here. Entries in this list
738: * must be subclasses of <code>AbstractAnalysis</code>.
739: */
740: abstract protected ArrayList getContainedEntries();
741:
742: /**
743: * Return the class hash code, as specified in "The Common Object
744: * Request Broker: Architecture and Specification" (01-02-33),
745: * section 10.6.2.
746: */
747: protected void calculateClassHashCode() {
748: // The simple cases
749: if (cls.isInterface())
750: classHashCode = 0;
751: else if (!Serializable.class.isAssignableFrom(cls))
752: classHashCode = 0;
753: else if (Externalizable.class.isAssignableFrom(cls))
754: classHashCode = 1;
755: else
756: // Go ask Util class for the hash code
757: classHashCode = Util.getClassHashCode(cls);
758: }
759:
760: /**
761: * Escape non-ISO characters for an IR name.
762: */
763: protected String escapeIRName(String name) {
764: StringBuffer b = new StringBuffer();
765:
766: for (int i = 0; i < name.length(); ++i) {
767: char c = name.charAt(i);
768:
769: if (c < 256)
770: b.append(c);
771: else
772: b.append("\\U").append(toHexString((int) c));
773: }
774: return b.toString();
775: }
776:
777: /**
778: * Return the IR global ID of the given class or interface.
779: * This is described in section 1.3.5.7.
780: * The returned string is in the RMI hashed format, like
781: * "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8".
782: */
783: protected void calculateRepositoryId() {
784: if (cls.isArray() || cls.isPrimitive())
785: throw new IllegalArgumentException(
786: "Not a class or interface.");
787:
788: if (cls.isInterface()
789: && org.omg.CORBA.Object.class.isAssignableFrom(cls)
790: && org.omg.CORBA.portable.IDLEntity.class
791: .isAssignableFrom(cls)) {
792:
793: StringBuffer b = new StringBuffer("IDL:");
794: b.append(cls.getPackage().getName().replace('.', '/'));
795: b.append('/');
796: String base = cls.getName();
797: base = base.substring(base.lastIndexOf('.') + 1);
798: b.append(base).append(":1.0");
799: repositoryId = b.toString();
800: } else {
801: StringBuffer b = new StringBuffer("RMI:");
802: b.append(escapeIRName(cls.getName()));
803: memberPrefix = b.toString() + ".";
804: String hashStr = toHexString(classHashCode);
805: b.append(':').append(hashStr);
806: ObjectStreamClass osClass = ObjectStreamClass.lookup(cls);
807: if (osClass != null) {
808: long serialVersionUID = osClass.getSerialVersionUID();
809: String SVUID = toHexString(serialVersionUID);
810:
811: if (classHashCode != serialVersionUID)
812: b.append(':').append(SVUID);
813: memberPostfix = ":" + hashStr + ":" + SVUID;
814: } else
815: memberPostfix = ":" + hashStr;
816:
817: repositoryId = b.toString();
818: }
819: }
820:
821: // Private ------------------------------------------------------
822:
823: /**
824: * A cache for the fully qualified IDL name of the IDL module we
825: * belong to.
826: */
827: private String idlModuleName = null;
828:
829: }
|