KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > corba > se > impl > orbutil > ObjectStreamClassUtil_1_3


1 /*
2  * @(#)ObjectStreamClassUtil_1_3.java 1.7 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.corba.se.impl.orbutil;
9
10 // for computing the structural UID
11
import java.security.MessageDigest JavaDoc;
12 import java.security.NoSuchAlgorithmException JavaDoc;
13 import java.security.DigestOutputStream JavaDoc;
14 import java.security.AccessController JavaDoc;
15 import java.security.PrivilegedExceptionAction JavaDoc;
16 import java.security.PrivilegedActionException JavaDoc;
17 import java.security.PrivilegedAction JavaDoc;
18 import java.io.DataOutputStream JavaDoc;
19 import java.io.ByteArrayOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21
22 import java.util.Arrays JavaDoc;
23 import java.util.Comparator JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26 import java.lang.reflect.Array JavaDoc;
27 import java.lang.reflect.Member JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.lang.reflect.Constructor JavaDoc;
30
31
32 import com.sun.corba.se.impl.io.ObjectStreamClass;
33
34 public final class ObjectStreamClassUtil_1_3 {
35
36     // maintained here for backward compatability with JDK 1.3, where
37
// writeObject method was not being checked at all, so there is
38
// no need to lookup the ObjectStreamClass
39

40     public static long computeSerialVersionUID(final Class JavaDoc cl) {
41     
42     long csuid = ObjectStreamClass.getSerialVersionUID(cl);
43     if (csuid == 0)
44         return csuid; // for non-serializable/proxy classes
45

46     csuid = (ObjectStreamClassUtil_1_3.getSerialVersion(csuid, cl).longValue());
47     return csuid;
48     }
49     
50
51     // to maintain same suid as the JDK 1.3, we pick
52
// up suid only for classes with private,static,final
53
// declarations, and compute it for all others
54

55     private static Long JavaDoc getSerialVersion(final long csuid, final Class JavaDoc cl)
56     {
57         return (Long JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
58           public Object JavaDoc run() {
59         long suid;
60         try {
61                 final Field JavaDoc f = cl.getDeclaredField("serialVersionUID");
62             int mods = f.getModifiers();
63             if (Modifier.isStatic(mods) &&
64                     Modifier.isFinal(mods) && Modifier.isPrivate(mods)) {
65                 suid = csuid;
66              } else {
67             suid = _computeSerialVersionUID(cl);
68              }
69           } catch (NoSuchFieldException JavaDoc ex) {
70               suid = _computeSerialVersionUID(cl);
71               //} catch (IllegalAccessException ex) {
72
// suid = _computeSerialVersionUID(cl);
73
}
74           return new Long JavaDoc(suid);
75        }
76     });
77     }
78
79     public static long computeStructuralUID(boolean hasWriteObject, Class JavaDoc cl) {
80     ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
81         
82     long h = 0;
83     try {
84
85         if ((!java.io.Serializable JavaDoc.class.isAssignableFrom(cl)) ||
86         (cl.isInterface())){
87         return 0;
88         }
89             
90         if (java.io.Externalizable JavaDoc.class.isAssignableFrom(cl)) {
91         return 1;
92         }
93
94         MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
95         DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull, md);
96         DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(mdo);
97
98         //In the old case, for the caller class, the write Method wasn't considered
99
// for rep-id calculations correctly, but for parent classes it was taken
100
// into account. That is the reason there is the klude of getting the write
101
// Object method in there
102

103         // Get SUID of parent
104
Class JavaDoc parent = cl.getSuperclass();
105         if ((parent != null) && (parent != java.lang.Object JavaDoc.class)) {
106             boolean hasWriteObjectFlag = false;
107             Class JavaDoc [] args = {java.io.ObjectOutputStream JavaDoc.class};
108                 Method JavaDoc hasWriteObjectMethod = ObjectStreamClassUtil_1_3.getDeclaredMethod(parent, "writeObject", args,
109                    Modifier.PRIVATE, Modifier.STATIC);
110             if (hasWriteObjectMethod != null)
111                 hasWriteObjectFlag = true;
112         data.writeLong(ObjectStreamClassUtil_1_3.computeStructuralUID(hasWriteObjectFlag, parent));
113         }
114
115         if (hasWriteObject)
116             data.writeInt(2);
117         else
118             data.writeInt(1);
119
120         /* Sort the field names to get a deterministic order */
121         Field JavaDoc[] field = ObjectStreamClassUtil_1_3.getDeclaredFields(cl);
122         Arrays.sort(field, compareMemberByName);
123             
124         for (int i = 0; i < field.length; i++) {
125         Field JavaDoc f = field[i];
126                 
127                 /* Include in the hash all fields except those that are
128                  * transient or static.
129                  */

130         int m = f.getModifiers();
131         if (Modifier.isTransient(m) || Modifier.isStatic(m))
132             continue;
133                 
134         data.writeUTF(f.getName());
135         data.writeUTF(getSignature(f.getType()));
136         }
137             
138         /* Compute the hash value for this class.
139          * Use only the first 64 bits of the hash.
140          */

141         data.flush();
142         byte hasharray[] = md.digest();
143         int minimum = Math.min(8, hasharray.length);
144         for (int i = minimum; i > 0; i--) {
145         h += (long)(hasharray[i] & 255) << (i * 8);
146         }
147     } catch (IOException JavaDoc ignore) {
148         /* can't happen, but be deterministic anyway. */
149         h = -1;
150     } catch (NoSuchAlgorithmException JavaDoc complain) {
151         throw new SecurityException JavaDoc(complain.getMessage());
152     }
153     return h;
154     }
155
156     /*
157      * Compute a hash for the specified class. Incrementally add
158      * items to the hash accumulating in the digest stream.
159      * Fold the hash into a long. Use the SHA secure hash function.
160      */

161     private static long _computeSerialVersionUID(Class JavaDoc cl) {
162     ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
163
164     long h = 0;
165     try {
166         MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
167         DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull, md);
168         DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(mdo);
169
170
171         data.writeUTF(cl.getName());
172
173         int classaccess = cl.getModifiers();
174         classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
175                 Modifier.INTERFACE | Modifier.ABSTRACT);
176
177         /* Workaround for javac bug that only set ABSTRACT for
178          * interfaces if the interface had some methods.
179          * The ABSTRACT bit reflects that the number of methods > 0.
180          * This is required so correct hashes can be computed
181          * for existing class files.
182          * Previously this hack was previously present in the VM.
183          */

184             Method JavaDoc[] method = cl.getDeclaredMethods();
185         if ((classaccess & Modifier.INTERFACE) != 0) {
186         classaccess &= (~Modifier.ABSTRACT);
187         if (method.length > 0) {
188             classaccess |= Modifier.ABSTRACT;
189         }
190         }
191
192         data.writeInt(classaccess);
193
194         /*
195          * Get the list of interfaces supported,
196          * Accumulate their names their names in Lexical order
197          * and add them to the hash
198          */

199             if (!cl.isArray()) {
200                 /* In 1.2fcs, getInterfaces() was modified to return
201                  * {java.lang.Cloneable, java.io.Serializable} when
202                  * called on array classes. These values would upset
203                  * the computation of the hash, so we explicitly omit
204                  * them from its computation.
205                  */

206
207             Class JavaDoc interfaces[] = cl.getInterfaces();
208             Arrays.sort(interfaces, compareClassByName);
209
210             for (int i = 0; i < interfaces.length; i++) {
211             data.writeUTF(interfaces[i].getName());
212             }
213         }
214
215         /* Sort the field names to get a deterministic order */
216             Field JavaDoc[] field = cl.getDeclaredFields();
217         Arrays.sort(field, compareMemberByName);
218
219         for (int i = 0; i < field.length; i++) {
220         Field JavaDoc f = field[i];
221
222         /* Include in the hash all fields except those that are
223          * private transient and private static.
224          */

225         int m = f.getModifiers();
226         if (Modifier.isPrivate(m) &&
227             (Modifier.isTransient(m) || Modifier.isStatic(m)))
228             continue;
229
230         data.writeUTF(f.getName());
231         data.writeInt(m);
232         data.writeUTF(getSignature(f.getType()));
233         }
234
235         // need to find the java replacement for hasStaticInitializer
236
if (hasStaticInitializer(cl)) {
237         data.writeUTF("<clinit>");
238         data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
239
data.writeUTF("()V");
240         }
241
242         /*
243          * Get the list of constructors including name and signature
244          * Sort lexically, add all except the private constructors
245          * to the hash with their access flags
246          */

247
248         MethodSignature[] constructors =
249         MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
250         for (int i = 0; i < constructors.length; i++) {
251         MethodSignature c = constructors[i];
252         String JavaDoc mname = "<init>";
253         String JavaDoc desc = c.signature;
254         desc = desc.replace('/', '.');
255         data.writeUTF(mname);
256         data.writeInt(c.member.getModifiers());
257         data.writeUTF(desc);
258         }
259
260         /* Include in the hash all methods except those that are
261          * private transient and private static.
262          */

263         MethodSignature[] methods =
264         MethodSignature.removePrivateAndSort(method);
265         for (int i = 0; i < methods.length; i++ ) {
266         MethodSignature m = methods[i];
267         String JavaDoc desc = m.signature;
268         desc = desc.replace('/', '.');
269         data.writeUTF(m.member.getName());
270         data.writeInt(m.member.getModifiers());
271         data.writeUTF(desc);
272         }
273
274         /* Compute the hash value for this class.
275          * Use only the first 64 bits of the hash.
276          */

277         data.flush();
278         byte hasharray[] = md.digest();
279         for (int i = 0; i < Math.min(8, hasharray.length); i++) {
280         h += (long)(hasharray[i] & 255) << (i * 8);
281         }
282     } catch (IOException JavaDoc ignore) {
283         /* can't happen, but be deterministic anyway. */
284         h = -1;
285     } catch (NoSuchAlgorithmException JavaDoc complain) {
286         throw new SecurityException JavaDoc(complain.getMessage());
287     }
288     return h;
289     }
290
291     /*
292      * Comparator object for Classes and Interfaces
293      */

294     private static Comparator JavaDoc compareClassByName =
295         new CompareClassByName();
296
297     private static class CompareClassByName implements Comparator JavaDoc {
298     public int compare(Object JavaDoc o1, Object JavaDoc o2) {
299         Class JavaDoc c1 = (Class JavaDoc)o1;
300         Class JavaDoc c2 = (Class JavaDoc)o2;
301         return (c1.getName()).compareTo(c2.getName());
302     }
303     }
304
305     /*
306      * Comparator object for Members, Fields, and Methods
307      */

308     private static Comparator JavaDoc compareMemberByName =
309         new CompareMemberByName();
310
311     private static class CompareMemberByName implements Comparator JavaDoc {
312         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
313             String JavaDoc s1 = ((Member JavaDoc)o1).getName();
314             String JavaDoc s2 = ((Member JavaDoc)o2).getName();
315
316             if (o1 instanceof Method JavaDoc) {
317                 s1 += getSignature((Method JavaDoc)o1);
318                 s2 += getSignature((Method JavaDoc)o2);
319             } else if (o1 instanceof Constructor JavaDoc) {
320                 s1 += getSignature((Constructor JavaDoc)o1);
321                 s2 += getSignature((Constructor JavaDoc)o2);
322             }
323             return s1.compareTo(s2);
324         }
325     }
326
327     /**
328      * Compute the JVM signature for the class.
329      */

330     private static String JavaDoc getSignature(Class JavaDoc clazz) {
331     String JavaDoc type = null;
332     if (clazz.isArray()) {
333         Class JavaDoc cl = clazz;
334         int dimensions = 0;
335         while (cl.isArray()) {
336         dimensions++;
337         cl = cl.getComponentType();
338         }
339         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
340         for (int i = 0; i < dimensions; i++) {
341         sb.append("[");
342         }
343         sb.append(getSignature(cl));
344         type = sb.toString();
345     } else if (clazz.isPrimitive()) {
346         if (clazz == Integer.TYPE) {
347         type = "I";
348         } else if (clazz == Byte.TYPE) {
349         type = "B";
350         } else if (clazz == Long.TYPE) {
351         type = "J";
352         } else if (clazz == Float.TYPE) {
353         type = "F";
354         } else if (clazz == Double.TYPE) {
355         type = "D";
356         } else if (clazz == Short.TYPE) {
357         type = "S";
358         } else if (clazz == Character.TYPE) {
359         type = "C";
360         } else if (clazz == Boolean.TYPE) {
361         type = "Z";
362         } else if (clazz == Void.TYPE) {
363         type = "V";
364         }
365     } else {
366         type = "L" + clazz.getName().replace('.', '/') + ";";
367     }
368     return type;
369     }
370
371     /*
372      * Compute the JVM method descriptor for the method.
373      */

374     private static String JavaDoc getSignature(Method JavaDoc meth) {
375     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
376
377     sb.append("(");
378
379     Class JavaDoc[] params = meth.getParameterTypes(); // avoid clone
380
for (int j = 0; j < params.length; j++) {
381         sb.append(getSignature(params[j]));
382     }
383     sb.append(")");
384     sb.append(getSignature(meth.getReturnType()));
385     return sb.toString();
386     }
387
388     /*
389      * Compute the JVM constructor descriptor for the constructor.
390      */

391     private static String JavaDoc getSignature(Constructor JavaDoc cons) {
392     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
393
394     sb.append("(");
395
396     Class JavaDoc[] params = cons.getParameterTypes(); // avoid clone
397
for (int j = 0; j < params.length; j++) {
398         sb.append(getSignature(params[j]));
399     }
400     sb.append(")V");
401     return sb.toString();
402     }
403
404     private static Field JavaDoc[] getDeclaredFields(final Class JavaDoc clz) {
405         return (Field JavaDoc[]) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
406             public Object JavaDoc run() {
407                 return clz.getDeclaredFields();
408             }
409         });
410     }
411
412     private static class MethodSignature implements Comparator JavaDoc {
413     Member JavaDoc member;
414     String JavaDoc signature; // cached parameter signature
415

416     /* Given an array of Method or Constructor members,
417        return a sorted array of the non-private members.*/

418     /* A better implementation would be to implement the returned data
419        structure as an insertion sorted link list.*/

420     static MethodSignature[] removePrivateAndSort(Member JavaDoc[] m) {
421         int numNonPrivate = 0;
422         for (int i = 0; i < m.length; i++) {
423         if (! Modifier.isPrivate(m[i].getModifiers())) {
424             numNonPrivate++;
425         }
426         }
427         MethodSignature[] cm = new MethodSignature[numNonPrivate];
428         int cmi = 0;
429         for (int i = 0; i < m.length; i++) {
430         if (! Modifier.isPrivate(m[i].getModifiers())) {
431             cm[cmi] = new MethodSignature(m[i]);
432             cmi++;
433         }
434         }
435         if (cmi > 0)
436         Arrays.sort(cm, cm[0]);
437         return cm;
438     }
439
440     /* Assumes that o1 and o2 are either both methods
441        or both constructors.*/

442     public int compare(Object JavaDoc o1, Object JavaDoc o2) {
443         /* Arrays.sort calls compare when o1 and o2 are equal.*/
444         if (o1 == o2)
445         return 0;
446
447         MethodSignature c1 = (MethodSignature)o1;
448         MethodSignature c2 = (MethodSignature)o2;
449
450         int result;
451         if (isConstructor()) {
452         result = c1.signature.compareTo(c2.signature);
453         } else { // is a Method.
454
result = c1.member.getName().compareTo(c2.member.getName());
455         if (result == 0)
456             result = c1.signature.compareTo(c2.signature);
457         }
458         return result;
459     }
460
461     final private boolean isConstructor() {
462         return member instanceof Constructor JavaDoc;
463     }
464     private MethodSignature(Member JavaDoc m) {
465         member = m;
466         if (isConstructor()) {
467         signature = ObjectStreamClassUtil_1_3.getSignature((Constructor JavaDoc)m);
468         } else {
469         signature = ObjectStreamClassUtil_1_3.getSignature((Method JavaDoc)m);
470         }
471     }
472     }
473
474     /* Find out if the class has a static class initializer <clinit> */
475     // use java.io.ObjectStream's hasStaticInitializer method
476
// private static native boolean hasStaticInitializer(Class cl);
477

478     private static Method JavaDoc hasStaticInitializerMethod = null;
479     /**
480      * Returns true if the given class defines a static initializer method,
481      * false otherwise.
482      */

483     private static boolean hasStaticInitializer(Class JavaDoc cl) {
484         if (hasStaticInitializerMethod == null) {
485             Class JavaDoc classWithThisMethod = null;
486             
487             try {
488                 try {
489                     // When using rip-int with Merlin or when this is a Merlin
490
// workspace, the method we want is in sun.misc.ClassReflector
491
// and absent from java.io.ObjectStreamClass.
492
//
493
// When compiling rip-int with JDK 1.3.x, we have to get it
494
// from java.io.ObjectStreamClass.
495
classWithThisMethod = Class.forName("sun.misc.ClassReflector");
496                 } catch (ClassNotFoundException JavaDoc cnfe) {
497                     // Do nothing. This is either not a Merlin workspace,
498
// or rip-int is being compiled with something other than
499
// Merlin, probably JDK 1.3. Fall back on java.io.ObjectStreaClass.
500
}
501                 if (classWithThisMethod == null)
502                     classWithThisMethod = java.io.ObjectStreamClass JavaDoc.class;
503                 
504                 hasStaticInitializerMethod =
505                     classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
506                                                           new Class JavaDoc[] { Class JavaDoc.class });
507             } catch (NoSuchMethodException JavaDoc ex) {
508             }
509             
510             if (hasStaticInitializerMethod == null) {
511                 throw new InternalError JavaDoc("Can't find hasStaticInitializer method on "
512                                         + classWithThisMethod.getName());
513             }
514             hasStaticInitializerMethod.setAccessible(true);
515         }
516         try {
517             Boolean JavaDoc retval = (Boolean JavaDoc)
518                 hasStaticInitializerMethod.invoke(null, new Object JavaDoc[] { cl });
519             return retval.booleanValue();
520         } catch (Exception JavaDoc ex) {
521             throw new InternalError JavaDoc("Error invoking hasStaticInitializer: "
522                                     + ex);
523         }
524     }
525
526     private static Method JavaDoc getDeclaredMethod(final Class JavaDoc cl, final String JavaDoc methodName, final Class JavaDoc[] args,
527                                      final int requiredModifierMask,
528                                      final int disallowedModifierMask) {
529         return (Method JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
530             public Object JavaDoc run() {
531                 Method JavaDoc method = null;
532                 try {
533                     method =
534                         cl.getDeclaredMethod(methodName, args);
535                         int mods = method.getModifiers();
536                         if ((mods & disallowedModifierMask) != 0 ||
537                             (mods & requiredModifierMask) != requiredModifierMask) {
538                             method = null;
539                         }
540                     //if (!Modifier.isPrivate(mods) ||
541
// Modifier.isStatic(mods)) {
542
// method = null;
543
//}
544
} catch (NoSuchMethodException JavaDoc e) {
545                 // Since it is alright if methodName does not exist,
546
// no need to do anything special here.
547
}
548                 return method;
549         }
550     });
551     }
552
553 }
554
Popular Tags