- /*
- * @(#)ObjectStreamClassUtil_1_3.java 1.5 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package com.sun.corba.se.internal.orbutil;
-
- // for computing the structural UID
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.security.DigestOutputStream;
- import java.security.AccessController;
- import java.security.PrivilegedExceptionAction;
- import java.security.PrivilegedActionException;
- import java.security.PrivilegedAction;
- import java.io.DataOutputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
-
- import java.util.Arrays;
- import java.util.Comparator;
- import java.lang.reflect.Field;
- import java.lang.reflect.Modifier;
- import java.lang.reflect.Array;
- import java.lang.reflect.Member;
- import java.lang.reflect.Method;
- import java.lang.reflect.Constructor;
-
-
- import com.sun.corba.se.internal.io.ObjectStreamClass;
-
- public final class ObjectStreamClassUtil_1_3 {
-
- // maintained here for backward compatability with JDK 1.3, where
- // writeObject method was not being checked at all, so there is
- // no need to lookup the ObjectStreamClass
-
- public static long computeSerialVersionUID(final Class cl) {
-
- long csuid = ObjectStreamClass.getSerialVersionUID(cl);
- if (csuid == 0)
- return csuid; // for non-serializable/proxy classes
-
- csuid = (ObjectStreamClassUtil_1_3.getSerialVersion(csuid, cl).longValue());
- return csuid;
- }
-
-
- // to maintain same suid as the JDK 1.3, we pick
- // up suid only for classes with private,static,final
- // declarations, and compute it for all others
-
- private static Long getSerialVersion(final long csuid, final Class cl)
- {
- return (Long) AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- long suid;
- try {
- final Field f = cl.getDeclaredField("serialVersionUID");
- int mods = f.getModifiers();
- if (Modifier.isStatic(mods) &&
- Modifier.isFinal(mods) && Modifier.isPrivate(mods)) {
- suid = csuid;
- } else {
- suid = _computeSerialVersionUID(cl);
- }
- } catch (NoSuchFieldException ex) {
- suid = _computeSerialVersionUID(cl);
- //} catch (IllegalAccessException ex) {
- // suid = _computeSerialVersionUID(cl);
- }
- return new Long(suid);
- }
- });
- }
-
- public static long computeStructuralUID(boolean hasWriteObject, Class cl) {
- ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
-
- long h = 0;
- try {
-
- if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
- (cl.isInterface())){
- return 0;
- }
-
- if (java.io.Externalizable.class.isAssignableFrom(cl)) {
- return 1;
- }
-
- MessageDigest md = MessageDigest.getInstance("SHA");
- DigestOutputStream mdo = new DigestOutputStream(devnull, md);
- DataOutputStream data = new DataOutputStream(mdo);
-
- //In the old case, for the caller class, the write Method wasn't considered
- // for rep-id calculations correctly, but for parent classes it was taken
- // into account. That is the reason there is the klude of getting the write
- // Object method in there
-
- // Get SUID of parent
- Class parent = cl.getSuperclass();
- if ((parent != null) && (parent != java.lang.Object.class)) {
- boolean hasWriteObjectFlag = false;
- Class [] args = {java.io.ObjectOutputStream.class};
- Method hasWriteObjectMethod = ObjectStreamClassUtil_1_3.getDeclaredMethod(parent, "writeObject", args,
- Modifier.PRIVATE, Modifier.STATIC);
- if (hasWriteObjectMethod != null)
- hasWriteObjectFlag = true;
- data.writeLong(ObjectStreamClassUtil_1_3.computeStructuralUID(hasWriteObjectFlag, parent));
- }
-
- if (hasWriteObject)
- data.writeInt(2);
- else
- data.writeInt(1);
-
- /* Sort the field names to get a deterministic order */
- Field[] field = ObjectStreamClassUtil_1_3.getDeclaredFields(cl);
- Arrays.sort(field, compareMemberByName);
-
- for (int i = 0; i < field.length; i++) {
- Field f = field[i];
-
- /* Include in the hash all fields except those that are
- * transient or static.
- */
- int m = f.getModifiers();
- if (Modifier.isTransient(m) || Modifier.isStatic(m))
- continue;
-
- data.writeUTF(f.getName());
- data.writeUTF(getSignature(f.getType()));
- }
-
- /* Compute the hash value for this class.
- * Use only the first 64 bits of the hash.
- */
- data.flush();
- byte hasharray[] = md.digest();
- int minimum = Math.min(8, hasharray.length);
- for (int i = minimum; i > 0; i--) {
- h += (long)(hasharray[i] & 255) << (i * 8);
- }
- } catch (IOException ignore) {
- /* can't happen, but be deterministic anyway. */
- h = -1;
- } catch (NoSuchAlgorithmException complain) {
- throw new SecurityException(complain.getMessage());
- }
- return h;
- }
-
- /*
- * Compute a hash for the specified class. Incrementally add
- * items to the hash accumulating in the digest stream.
- * Fold the hash into a long. Use the SHA secure hash function.
- */
- private static long _computeSerialVersionUID(Class cl) {
- ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
-
- long h = 0;
- try {
- MessageDigest md = MessageDigest.getInstance("SHA");
- DigestOutputStream mdo = new DigestOutputStream(devnull, md);
- DataOutputStream data = new DataOutputStream(mdo);
-
-
- data.writeUTF(cl.getName());
-
- int classaccess = cl.getModifiers();
- classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
- Modifier.INTERFACE | Modifier.ABSTRACT);
-
- /* Workaround for javac bug that only set ABSTRACT for
- * interfaces if the interface had some methods.
- * The ABSTRACT bit reflects that the number of methods > 0.
- * This is required so correct hashes can be computed
- * for existing class files.
- * Previously this hack was previously present in the VM.
- */
- Method[] method = cl.getDeclaredMethods();
- if ((classaccess & Modifier.INTERFACE) != 0) {
- classaccess &= (~Modifier.ABSTRACT);
- if (method.length > 0) {
- classaccess |= Modifier.ABSTRACT;
- }
- }
-
- data.writeInt(classaccess);
-
- /*
- * Get the list of interfaces supported,
- * Accumulate their names their names in Lexical order
- * and add them to the hash
- */
- if (!cl.isArray()) {
- /* In 1.2fcs, getInterfaces() was modified to return
- * {java.lang.Cloneable, java.io.Serializable} when
- * called on array classes. These values would upset
- * the computation of the hash, so we explicitly omit
- * them from its computation.
- */
-
- Class interfaces[] = cl.getInterfaces();
- Arrays.sort(interfaces, compareClassByName);
-
- for (int i = 0; i < interfaces.length; i++) {
- data.writeUTF(interfaces[i].getName());
- }
- }
-
- /* Sort the field names to get a deterministic order */
- Field[] field = cl.getDeclaredFields();
- Arrays.sort(field, compareMemberByName);
-
- for (int i = 0; i < field.length; i++) {
- Field f = field[i];
-
- /* Include in the hash all fields except those that are
- * private transient and private static.
- */
- int m = f.getModifiers();
- if (Modifier.isPrivate(m) &&
- (Modifier.isTransient(m) || Modifier.isStatic(m)))
- continue;
-
- data.writeUTF(f.getName());
- data.writeInt(m);
- data.writeUTF(getSignature(f.getType()));
- }
-
- // need to find the java replacement for hasStaticInitializer
- if (hasStaticInitializer(cl)) {
- data.writeUTF("<clinit>");
- data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
- data.writeUTF("()V");
- }
-
- /*
- * Get the list of constructors including name and signature
- * Sort lexically, add all except the private constructors
- * to the hash with their access flags
- */
-
- MethodSignature[] constructors =
- MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
- for (int i = 0; i < constructors.length; i++) {
- MethodSignature c = constructors[i];
- String mname = "<init>";
- String desc = c.signature;
- desc = desc.replace('/', '.');
- data.writeUTF(mname);
- data.writeInt(c.member.getModifiers());
- data.writeUTF(desc);
- }
-
- /* Include in the hash all methods except those that are
- * private transient and private static.
- */
- MethodSignature[] methods =
- MethodSignature.removePrivateAndSort(method);
- for (int i = 0; i < methods.length; i++ ) {
- MethodSignature m = methods[i];
- String desc = m.signature;
- desc = desc.replace('/', '.');
- data.writeUTF(m.member.getName());
- data.writeInt(m.member.getModifiers());
- data.writeUTF(desc);
- }
-
- /* Compute the hash value for this class.
- * Use only the first 64 bits of the hash.
- */
- data.flush();
- byte hasharray[] = md.digest();
- for (int i = 0; i < Math.min(8, hasharray.length); i++) {
- h += (long)(hasharray[i] & 255) << (i * 8);
- }
- } catch (IOException ignore) {
- /* can't happen, but be deterministic anyway. */
- h = -1;
- } catch (NoSuchAlgorithmException complain) {
- throw new SecurityException(complain.getMessage());
- }
- return h;
- }
-
- /*
- * Comparator object for Classes and Interfaces
- */
- private static Comparator compareClassByName =
- new CompareClassByName();
-
- private static class CompareClassByName implements Comparator {
- public int compare(Object o1, Object o2) {
- Class c1 = (Class)o1;
- Class c2 = (Class)o2;
- return (c1.getName()).compareTo(c2.getName());
- }
- }
-
- /*
- * Comparator object for Members, Fields, and Methods
- */
- private static Comparator compareMemberByName =
- new CompareMemberByName();
-
- private static class CompareMemberByName implements Comparator {
- public int compare(Object o1, Object o2) {
- String s1 = ((Member)o1).getName();
- String s2 = ((Member)o2).getName();
-
- if (o1 instanceof Method) {
- s1 += getSignature((Method)o1);
- s2 += getSignature((Method)o2);
- } else if (o1 instanceof Constructor) {
- s1 += getSignature((Constructor)o1);
- s2 += getSignature((Constructor)o2);
- }
- return s1.compareTo(s2);
- }
- }
-
- /**
- * Compute the JVM signature for the class.
- */
- private static String getSignature(Class clazz) {
- String type = null;
- if (clazz.isArray()) {
- Class cl = clazz;
- int dimensions = 0;
- while (cl.isArray()) {
- dimensions++;
- cl = cl.getComponentType();
- }
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < dimensions; i++) {
- sb.append("[");
- }
- sb.append(getSignature(cl));
- type = sb.toString();
- } else if (clazz.isPrimitive()) {
- if (clazz == Integer.TYPE) {
- type = "I";
- } else if (clazz == Byte.TYPE) {
- type = "B";
- } else if (clazz == Long.TYPE) {
- type = "J";
- } else if (clazz == Float.TYPE) {
- type = "F";
- } else if (clazz == Double.TYPE) {
- type = "D";
- } else if (clazz == Short.TYPE) {
- type = "S";
- } else if (clazz == Character.TYPE) {
- type = "C";
- } else if (clazz == Boolean.TYPE) {
- type = "Z";
- } else if (clazz == Void.TYPE) {
- type = "V";
- }
- } else {
- type = "L" + clazz.getName().replace('.', '/') + ";";
- }
- return type;
- }
-
- /*
- * Compute the JVM method descriptor for the method.
- */
- private static String getSignature(Method meth) {
- StringBuffer sb = new StringBuffer();
-
- sb.append("(");
-
- Class[] params = meth.getParameterTypes(); // avoid clone
- for (int j = 0; j < params.length; j++) {
- sb.append(getSignature(params[j]));
- }
- sb.append(")");
- sb.append(getSignature(meth.getReturnType()));
- return sb.toString();
- }
-
- /*
- * Compute the JVM constructor descriptor for the constructor.
- */
- private static String getSignature(Constructor cons) {
- StringBuffer sb = new StringBuffer();
-
- sb.append("(");
-
- Class[] params = cons.getParameterTypes(); // avoid clone
- for (int j = 0; j < params.length; j++) {
- sb.append(getSignature(params[j]));
- }
- sb.append(")V");
- return sb.toString();
- }
-
- private static Field[] getDeclaredFields(final Class clz) {
- return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- return clz.getDeclaredFields();
- }
- });
- }
-
- private static class MethodSignature implements Comparator {
- Member member;
- String signature; // cached parameter signature
-
- /* Given an array of Method or Constructor members,
- return a sorted array of the non-private members.*/
- /* A better implementation would be to implement the returned data
- structure as an insertion sorted link list.*/
- static MethodSignature[] removePrivateAndSort(Member[] m) {
- int numNonPrivate = 0;
- for (int i = 0; i < m.length; i++) {
- if (! Modifier.isPrivate(m[i].getModifiers())) {
- numNonPrivate++;
- }
- }
- MethodSignature[] cm = new MethodSignature[numNonPrivate];
- int cmi = 0;
- for (int i = 0; i < m.length; i++) {
- if (! Modifier.isPrivate(m[i].getModifiers())) {
- cm[cmi] = new MethodSignature(m[i]);
- cmi++;
- }
- }
- if (cmi > 0)
- Arrays.sort(cm, cm[0]);
- return cm;
- }
-
- /* Assumes that o1 and o2 are either both methods
- or both constructors.*/
- public int compare(Object o1, Object o2) {
- /* Arrays.sort calls compare when o1 and o2 are equal.*/
- if (o1 == o2)
- return 0;
-
- MethodSignature c1 = (MethodSignature)o1;
- MethodSignature c2 = (MethodSignature)o2;
-
- int result;
- if (isConstructor()) {
- result = c1.signature.compareTo(c2.signature);
- } else { // is a Method.
- result = c1.member.getName().compareTo(c2.member.getName());
- if (result == 0)
- result = c1.signature.compareTo(c2.signature);
- }
- return result;
- }
-
- final private boolean isConstructor() {
- return member instanceof Constructor;
- }
- private MethodSignature(Member m) {
- member = m;
- if (isConstructor()) {
- signature = ObjectStreamClassUtil_1_3.getSignature((Constructor)m);
- } else {
- signature = ObjectStreamClassUtil_1_3.getSignature((Method)m);
- }
- }
- }
-
- /* Find out if the class has a static class initializer <clinit> */
- // use java.io.ObjectStream's hasStaticInitializer method
- // private static native boolean hasStaticInitializer(Class cl);
-
- private static Method hasStaticInitializerMethod = null;
- /**
- * Returns true if the given class defines a static initializer method,
- * false otherwise.
- */
- private static boolean hasStaticInitializer(Class cl) {
- if (hasStaticInitializerMethod == null) {
- Class classWithThisMethod = null;
-
- try {
- try {
- // When using rip-int with Merlin or when this is a Merlin
- // workspace, the method we want is in sun.misc.ClassReflector
- // and absent from java.io.ObjectStreamClass.
- //
- // When compiling rip-int with JDK 1.3.x, we have to get it
- // from java.io.ObjectStreamClass.
- classWithThisMethod = Class.forName("sun.misc.ClassReflector");
- } catch (ClassNotFoundException cnfe) {
- // Do nothing. This is either not a Merlin workspace,
- // or rip-int is being compiled with something other than
- // Merlin, probably JDK 1.3. Fall back on java.io.ObjectStreaClass.
- }
- if (classWithThisMethod == null)
- classWithThisMethod = java.io.ObjectStreamClass.class;
-
- hasStaticInitializerMethod =
- classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
- new Class[] { Class.class });
- } catch (NoSuchMethodException ex) {
- }
-
- if (hasStaticInitializerMethod == null) {
- throw new InternalError("Can't find hasStaticInitializer method on "
- + classWithThisMethod.getName());
- }
- hasStaticInitializerMethod.setAccessible(true);
- }
- try {
- Boolean retval = (Boolean)
- hasStaticInitializerMethod.invoke(null, new Object[] { cl });
- return retval.booleanValue();
- } catch (Exception ex) {
- throw new InternalError("Error invoking hasStaticInitializer: "
- + ex);
- }
- }
-
- private static Method getDeclaredMethod(final Class cl, final String methodName, final Class[] args,
- final int requiredModifierMask,
- final int disallowedModifierMask) {
- return (Method) AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- Method method = null;
- try {
- method =
- cl.getDeclaredMethod(methodName, args);
- int mods = method.getModifiers();
- if ((mods & disallowedModifierMask) != 0 ||
- (mods & requiredModifierMask) != requiredModifierMask) {
- method = null;
- }
- //if (!Modifier.isPrivate(mods) ||
- // Modifier.isStatic(mods)) {
- // method = null;
- //}
- } catch (NoSuchMethodException e) {
- // Since it is alright if methodName does not exist,
- // no need to do anything special here.
- }
- return method;
- }
- });
- }
-
- }