KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > iiop > rmi > Util


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.iiop.rmi;
23
24 import java.io.ByteArrayOutputStream JavaDoc;
25 import java.io.DataOutputStream JavaDoc;
26 import java.io.Externalizable JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.ObjectOutputStream JavaDoc;
29 import java.io.ObjectStreamClass JavaDoc;
30 import java.io.Serializable JavaDoc;
31 import java.lang.reflect.Field JavaDoc;
32 import java.lang.reflect.Method JavaDoc;
33 import java.lang.reflect.Modifier JavaDoc;
34 import java.security.MessageDigest JavaDoc;
35 import java.security.NoSuchAlgorithmException JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.Comparator JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.SortedSet JavaDoc;
41 import java.util.TreeSet JavaDoc;
42 import java.util.WeakHashMap JavaDoc;
43
44 import org.omg.CORBA.Any JavaDoc;
45
46 /**
47  * This is a RMI/IIOP metadata conversion utility class.
48  *
49  * Routines here are conforming to the "Java(TM) Language to IDL Mapping
50  * Specification", version 1.1 (01-06-07).
51  *
52  * @author <a HREF="mailto:osh@sparre.dk">Ole Husgaard</a>
53  * @version $Revision: 42314 $
54  */

55 public class Util
56 {
57    // Constants -----------------------------------------------------
58

59    // Attributes ----------------------------------------------------
60

61    // Static --------------------------------------------------------
62

63    private static final org.jboss.logging.Logger logger =
64                org.jboss.logging.Logger.getLogger(Util.class);
65
66    /**
67     * Return the IDL type name for the given class.
68     * Here we use the mapping for parameter types and return values.
69     */

70    public static String JavaDoc getTypeIDLName(Class JavaDoc cls)
71       throws RMIIIOPViolationException
72    {
73       logger.debug("getTypeIDLName " + cls);
74       
75       if (cls.isPrimitive())
76          return PrimitiveAnalysis.getPrimitiveAnalysis(cls).getIDLName();
77
78       if (cls.isArray())
79       {
80          // boxedRMI 1.3.6
81
Class JavaDoc componentClass = cls;
82          int sequence = 0;
83          while (componentClass.isArray())
84          {
85             componentClass = componentClass.getComponentType();
86             ++sequence;
87          }
88          
89          String JavaDoc idlName = getTypeIDLName(componentClass);
90          int idx = idlName.lastIndexOf("::");
91          String JavaDoc idlModule = idlName.substring(0, idx+2);
92          String JavaDoc baseName = idlName.substring(idx+2);
93          return "::org::omg::boxedRMI" + idlModule + "seq" + sequence + "_" + baseName;
94       }
95
96       // special classes
97
if (cls == java.lang.String JavaDoc.class)
98          return "::CORBA::WStringValue";
99       if (cls == java.lang.Object JavaDoc.class)
100          return "::java::lang::_Object";
101       if (cls == java.lang.Class JavaDoc.class)
102          return "::javax::rmi::CORBA::ClassDesc";
103       if (cls == java.io.Serializable JavaDoc.class)
104          return "::java::io::Serializable";
105       if (cls == java.io.Externalizable JavaDoc.class)
106          return "::java::io::Externalizable";
107       if (cls == java.rmi.Remote JavaDoc.class)
108          return "::java::rmi::Remote";
109       if (cls == org.omg.CORBA.Object JavaDoc.class)
110          return "::CORBA::Object";
111
112
113       // remote interface?
114
if (cls.isInterface() && java.rmi.Remote JavaDoc.class.isAssignableFrom(cls)) {
115          InterfaceAnalysis ia = InterfaceAnalysis.getInterfaceAnalysis(cls);
116
117          return ia.getIDLModuleName() + "::" + ia.getIDLName();
118       }
119       
120       // IDL interface?
121
if (cls.isInterface() &&
122           org.omg.CORBA.Object JavaDoc.class.isAssignableFrom(cls) &&
123           org.omg.CORBA.portable.IDLEntity JavaDoc.class.isAssignableFrom(cls)) {
124          InterfaceAnalysis ia = InterfaceAnalysis.getInterfaceAnalysis(cls);
125
126          return ia.getIDLModuleName() + "::" + ia.getIDLName();
127       }
128
129       // exception?
130
if (Throwable JavaDoc.class.isAssignableFrom(cls)) {
131          if (Exception JavaDoc.class.isAssignableFrom(cls) &&
132              !RuntimeException JavaDoc.class.isAssignableFrom(cls)) {
133             ExceptionAnalysis ea = ExceptionAnalysis.getExceptionAnalysis(cls);
134
135             return ea.getIDLModuleName() + "::" + ea.getIDLName();
136          }
137       }
138
139       // got to be value
140
ValueAnalysis va = ValueAnalysis.getValueAnalysis(cls);
141
142       return va.getIDLModuleName() + "::" + va.getIDLName();
143    }
144
145    /**
146     * Check if this class is valid for RMI/IIOP mapping.
147     * This method will either throw an exception or return true.
148     */

149    public static boolean isValidRMIIIOP(Class JavaDoc cls)
150       throws RMIIIOPViolationException
151    {
152       if (cls.isPrimitive())
153          return true;
154
155       if (cls.isArray())
156          return isValidRMIIIOP(cls.getComponentType());
157
158       // special interfaces
159
if (cls == Serializable JavaDoc.class || cls == Externalizable JavaDoc.class)
160          return true;
161
162       // interface?
163
if (cls.isInterface() && java.rmi.Remote JavaDoc.class.isAssignableFrom(cls)) {
164          logger.debug("Util.isValidRMIIIOP(): doing interface analysis on " +
165                       cls.getName());
166          InterfaceAnalysis.getInterfaceAnalysis(cls);
167          return true;
168       }
169
170       // exception?
171
if (Throwable JavaDoc.class.isAssignableFrom(cls)) {
172          if (Exception JavaDoc.class.isAssignableFrom(cls) &&
173              !RuntimeException JavaDoc.class.isAssignableFrom(cls)) {
174             logger.debug("Util.isValidRMIIIOP(): doing exception analysis on "
175                          + cls.getName());
176             ExceptionAnalysis.getExceptionAnalysis(cls);
177          }
178          return true;
179       }
180
181       // special values
182
if (cls == Object JavaDoc.class || cls == String JavaDoc.class || cls == Class JavaDoc.class)
183          return true;
184
185       // got to be value
186
logger.debug("Util.isValidRMIIIOP(): doing value analysis on " +
187                    cls.getName());
188       ValueAnalysis.getValueAnalysis(cls);
189       return true;
190    }
191
192    /**
193     * Insert a java primitive into an Any.
194     * The primitive is assumed to be wrapped in one of the primitive
195     * wrapper classes.
196     */

197    public static void insertAnyPrimitive(Any JavaDoc any, Object JavaDoc primitive)
198    {
199       Class JavaDoc type = primitive.getClass();
200
201       if (type == Boolean JavaDoc.class)
202          any.insert_boolean(((Boolean JavaDoc)primitive).booleanValue());
203       else if (type == Character JavaDoc.class)
204          any.insert_wchar(((Character JavaDoc)primitive).charValue());
205       else if (type == Byte JavaDoc.class)
206          any.insert_octet(((Byte JavaDoc)primitive).byteValue());
207       else if (type == Short JavaDoc.class)
208          any.insert_short(((Short JavaDoc)primitive).shortValue());
209       else if (type == Integer JavaDoc.class)
210          any.insert_long(((Integer JavaDoc)primitive).intValue());
211       else if (type == Long JavaDoc.class)
212          any.insert_longlong(((Long JavaDoc)primitive).longValue());
213       else if (type == Float JavaDoc.class)
214         any.insert_float(((Float JavaDoc)primitive).floatValue());
215       else if (type == Double JavaDoc.class)
216         any.insert_double(((Double JavaDoc)primitive).doubleValue());
217       else
218          throw new IllegalArgumentException JavaDoc("Not a primitive type: " +
219                                             type.getName());
220    }
221
222    /**
223     * Map Java name to IDL name, as per sections 1.3.2.3, 1.3.2.4 and
224     * 1.3.2.2.
225     * This only works for a single name component, without a qualifying
226     * dot.
227     */

228    public static String JavaDoc javaToIDLName(String JavaDoc name)
229    {
230       if (name == null)
231          throw new IllegalArgumentException JavaDoc("Null name.");
232
233       if ("".equals(name))
234          throw new IllegalArgumentException JavaDoc("Empty name.");
235
236       if (name.indexOf('.') != -1)
237          throw new IllegalArgumentException JavaDoc("No qualified name allowed here.");
238
239       StringBuffer JavaDoc res = new StringBuffer JavaDoc(name.length());
240
241       if (name.charAt(0) == '_')
242          res.append('J'); // 1.3.2.3
243

244       for (int i = 0; i < name.length(); ++i) {
245          char c = name.charAt(i);
246
247          if (isLegalIDLIdentifierChar(c))
248             res.append(c);
249          else // 1.3.2.4
250
res.append('U').append(toHexString((int)c));
251       }
252
253       String JavaDoc s = res.toString();
254
255       if (isReservedIDLKeyword(s))
256          return "_" + s;
257       else
258          return s;
259    }
260
261    /**
262     * Return the IR global ID of the given class or interface.
263     * This is described in section 1.3.5.7.
264     * The returned string is in the RMI hashed format, like
265     * "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8".
266     */

267    public static String JavaDoc getIRIdentifierOfClass(Class JavaDoc cls)
268    {
269       if (cls.isPrimitive())
270          throw new IllegalArgumentException JavaDoc("Primitives have no IR IDs.");
271
272       String JavaDoc result = (String JavaDoc)classIRIdentifierCache.get(cls);
273       if (result != null)
274         return result;
275
276       String JavaDoc name = cls.getName();
277       StringBuffer JavaDoc b = new StringBuffer JavaDoc("RMI:");
278
279       for (int i = 0; i < name.length(); ++i) {
280          char c = name.charAt(i);
281
282          if (c < 256)
283             b.append(c);
284          else
285             b.append("\\U").append(toHexString((int)c));
286       }
287
288       long clsHash = getClassHashCode(cls);
289
290       b.append(':').append(toHexString(clsHash));
291
292       ObjectStreamClass JavaDoc osClass = ObjectStreamClass.lookup(cls);
293       if (osClass != null) {
294          long serialVersionUID = osClass.getSerialVersionUID();
295
296          if (clsHash != serialVersionUID)
297             b.append(':').append(toHexString(serialVersionUID));
298       }
299
300       result = b.toString();
301
302       classIRIdentifierCache.put(cls, result);
303
304       return result;
305    }
306
307
308    // Private -------------------------------------------------------
309

310    /**
311     * A cache for calculated class hash codes.
312     */

313    private static Map JavaDoc classHashCodeCache =
314                                 Collections.synchronizedMap(new WeakHashMap JavaDoc());
315
316    /**
317     * A cache for class IR identifiers.
318     */

319    private static Map JavaDoc classIRIdentifierCache =
320                                 Collections.synchronizedMap(new WeakHashMap JavaDoc());
321
322    /**
323     * Reserved IDL keywords.
324     *
325     * Section 1.3.2.2 says that Java identifiers with these names
326     * should have prepended an underscore.
327     */

328    private static final String JavaDoc[] reservedIDLKeywords = new String JavaDoc[] {
329       "abstract",
330       "any",
331       "attribute",
332       "boolean",
333       "case",
334       "char",
335       "const",
336       "context",
337       "custom",
338       "default",
339       "double",
340       "exception",
341       "enum",
342       "factory",
343       "FALSE",
344       "fixed",
345       "float",
346       "in",
347       "inout",
348       "interface",
349       "local",
350       "long",
351       "module",
352       "native",
353       "Object",
354       "octet",
355       "oneway",
356       "out",
357       "private",
358       "public",
359       "raises",
360       "readonly",
361       "sequence",
362       "short",
363       "string",
364       "struct",
365       "supports",
366       "switch",
367       "TRUE",
368       "truncatable",
369       "typedef",
370       "unsigned",
371       "union",
372       "ValueBase",
373       "valuetype",
374       "void",
375       "wchar",
376       "wstring"
377    };
378
379    static {
380       // Initialize caches
381
classHashCodeCache = Collections.synchronizedMap(new WeakHashMap JavaDoc());
382
383       classIRIdentifierCache = Collections.synchronizedMap(new WeakHashMap JavaDoc());
384    }
385
386    /**
387     * Convert an integer to a 16-digit hex string.
388     */

389    private static String JavaDoc toHexString(int i)
390    {
391       String JavaDoc s = Integer.toHexString(i).toUpperCase();
392
393       if (s.length() < 8)
394          return "00000000".substring(8 - s.length()) + s;
395       else
396          return s;
397    }
398    /**
399     * Convert a long to a 16-digit hex string.
400     */

401    private static String JavaDoc toHexString(long l)
402    {
403       String JavaDoc s = Long.toHexString(l).toUpperCase();
404
405       if (s.length() < 16)
406          return "0000000000000000".substring(16 - s.length()) + s;
407       else
408          return s;
409    }
410
411    /**
412     * Determine if the argument is a reserved IDL keyword.
413     */

414    private static boolean isReservedIDLKeyword(String JavaDoc s)
415    {
416       // TODO: faster lookup
417
for (int i = 0; i < reservedIDLKeywords.length; ++i)
418          if (reservedIDLKeywords[i].equals(s))
419             return true;
420       return false;
421    }
422
423    /**
424     * Determine if a <code>char</code> is a legal IDL identifier character.
425     */

426    private static boolean isLegalIDLIdentifierChar(char c)
427    {
428       if (c >= 0x61 && c <= 0x7a)
429          return true; // lower case letter
430

431       if (c >= 0x30 && c <= 0x39)
432          return true; // digit
433

434       if (c >= 0x41 && c <= 0x5a)
435          return true; // upper case letter
436

437       if (c == '_')
438          return true; // underscore
439

440       return false;
441    }
442
443    /**
444     * Determine if a <code>char</code> is legal start of an IDL identifier.
445     */

446    private static boolean isLegalIDLStartIdentifierChar(char c)
447    {
448       if (c >= 0x61 && c <= 0x7a)
449          return true; // lower case letter
450

451       if (c >= 0x41 && c <= 0x5a)
452          return true; // upper case letter
453

454       return false;
455    }
456
457    /**
458     * Return the class hash code, as specified in "The Common Object
459     * Request Broker: Architecture and Specification" (01-02-33),
460     * section 10.6.2.
461     */

462    static long getClassHashCode(Class JavaDoc cls)
463    {
464       // The simple cases
465
if (cls.isInterface())
466          return 0;
467       if (!Serializable JavaDoc.class.isAssignableFrom(cls))
468          return 0;
469       if (Externalizable JavaDoc.class.isAssignableFrom(cls))
470          return 1;
471
472       // Try cache
473
Long JavaDoc l = (Long JavaDoc)classHashCodeCache.get(cls);
474       if (l != null)
475          return l.longValue();
476
477       // Has to calculate the hash.
478

479       ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(256);
480       DataOutputStream JavaDoc dos = new DataOutputStream JavaDoc(baos);
481
482       // Step 1
483
Class JavaDoc superClass = cls.getSuperclass();
484       if (superClass != null && superClass != Object JavaDoc.class) {
485          try {
486             dos.writeLong(getClassHashCode(superClass));
487          } catch (IOException JavaDoc ex) {
488             throw new RuntimeException JavaDoc("Unexpected IOException: " + ex);
489          }
490       }
491
492       // Step 2
493
boolean hasWriteObject = false;
494       try {
495          Method JavaDoc m;
496          int mods;
497
498          m = cls.getDeclaredMethod("writeObject",
499                                    new Class JavaDoc[] { ObjectOutputStream JavaDoc.class });
500          mods = m.getModifiers();
501
502          if (!Modifier.isPrivate(mods) && !Modifier.isStatic(mods))
503             hasWriteObject = true;
504       } catch (NoSuchMethodException JavaDoc ex) {
505          // ignore
506
}
507       try {
508          dos.writeInt(hasWriteObject ? 2 : 1);
509       } catch (IOException JavaDoc ex) {
510          throw new RuntimeException JavaDoc("Unexpected IOException: " + ex);
511       }
512
513       // Step 3
514
Field JavaDoc[] fields = cls.getDeclaredFields();
515       SortedSet JavaDoc set = new TreeSet JavaDoc(new FieldComparator());
516
517       for (int i = 0; i < fields.length; ++i) {
518          int mods = fields[i].getModifiers();
519
520          if (!Modifier.isStatic(mods) && !Modifier.isTransient(mods))
521             set.add(fields[i]);
522       }
523       Iterator JavaDoc iter = set.iterator();
524       try {
525          while (iter.hasNext()) {
526             Field JavaDoc f = (Field JavaDoc)iter.next();
527
528             dos.writeUTF(f.getName());
529             dos.writeUTF(getSignature(f.getType()));
530          }
531       } catch (IOException JavaDoc ex) {
532          throw new RuntimeException JavaDoc("Unexpected IOException: " + ex);
533       }
534
535       // Convert to byte[]
536
try {
537          dos.flush();
538       } catch (IOException JavaDoc ex) {
539          throw new RuntimeException JavaDoc("Unexpected IOException: " + ex);
540       }
541       byte[] bytes = baos.toByteArray();
542
543       // Calculate SHA digest
544
MessageDigest JavaDoc digest;
545       try {
546          digest = MessageDigest.getInstance("SHA");
547       } catch (NoSuchAlgorithmException JavaDoc ex) {
548          throw new RuntimeException JavaDoc("No SHA MEssageDigest: " + ex);
549       }
550       digest.update(bytes);
551       byte[] sha = digest.digest();
552       
553       // Calculate hash as per section 10.6.2
554
long hash = 0;
555       for (int i = 0; i < Math.min(8, sha.length); i++) {
556          hash += (long)(sha[i] & 255) << (i * 8);
557       }
558
559       // Save in cache
560
classHashCodeCache.put(cls, new Long JavaDoc(hash));
561
562       return hash;
563    }
564
565    /**
566     * Calculate the signature of a class, according to the Java VM
567     * specification, section 4.3.2.
568     */

569    private static String JavaDoc getSignature(Class JavaDoc cls)
570    {
571       if (cls.isArray())
572          return "[" + cls.getComponentType();
573
574       if (cls.isPrimitive()) {
575          if (cls == Byte.TYPE)
576             return "B";
577          if (cls == Character.TYPE)
578             return "C";
579          if (cls == Double.TYPE)
580             return "D";
581          if (cls == Float.TYPE)
582             return "F";
583          if (cls == Integer.TYPE)
584             return "I";
585          if (cls == Long.TYPE)
586             return "J";
587          if (cls == Short.TYPE)
588             return "S";
589          if (cls == Boolean.TYPE)
590             return "Z";
591          throw new RuntimeException JavaDoc("Unknown primitive class.");
592       }
593
594       return "L" + cls.getName().replace('.', '/') + ";";
595    }
596
597    /**
598     * Calculate the signature of a method, according to the Java VM
599     * specification, section 4.3.3.
600     */

601    private static String JavaDoc getSignature(Method JavaDoc method)
602    {
603       StringBuffer JavaDoc b = new StringBuffer JavaDoc("(");
604       Class JavaDoc[] parameterTypes = method.getParameterTypes();
605
606       for (int i = 0; i < parameterTypes.length; ++i)
607          b.append(getSignature(parameterTypes[i]));
608       
609       b.append(')').append(getSignature(method.getReturnType()));
610
611       return b.toString();
612    }
613
614    /**
615     * Handle mappings for primitive types, as per section 1.3.3.
616     */

617    static String JavaDoc primitiveTypeIDLName(Class JavaDoc type)
618    {
619       if (type == Void.TYPE)
620          return "void";
621       if (type == Boolean.TYPE)
622          return "boolean";
623       if (type == Character.TYPE)
624          return "wchar";
625       if (type == Byte.TYPE)
626          return "octet";
627       if (type == Short.TYPE)
628          return "short";
629       if (type == Integer.TYPE)
630          return "long";
631       if (type == Long.TYPE)
632          return "long long";
633       if (type == Float.TYPE)
634          return "float";
635       if (type == Double.TYPE)
636          return "double";
637       throw new IllegalArgumentException JavaDoc("Not a primitive type.");
638    }
639
640
641    // Inner classes -------------------------------------------------
642

643    /**
644     * A <code>Comparator</code> for <code>Field</code>s, ordering the
645     * fields according to the lexicographic ordering of their Java names.
646     */

647    private static class FieldComparator
648       implements Comparator JavaDoc
649    {
650       public int compare(Object JavaDoc o1, Object JavaDoc o2)
651       {
652          if (o1 == o2)
653             return 0;
654  
655          String JavaDoc n1 = ((Field JavaDoc)o1).getName();
656          String JavaDoc n2 = ((Field JavaDoc)o2).getName();
657  
658          return n1.compareTo(n2);
659       }
660    }
661
662 }
663
Popular Tags