home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / ObjectStreamClass.java < prev    next >
Text File  |  1998-01-23  |  23KB  |  760 lines

  1. /*
  2.  * @(#)ObjectStreamClass.java    1.31 97/10/06
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  */
  21.  
  22. package java.io;
  23.  
  24. import sun.misc.Ref;
  25. import java.security.MessageDigest;
  26. import java.security.NoSuchAlgorithmException;
  27. import java.security.DigestOutputStream;
  28. import java.lang.reflect.Modifier;
  29.  
  30. /**
  31.  * A ObjectStreamClass describes a class that can be serialized to a stream
  32.  * or a class that was serialized to a stream.  It contains the name
  33.  * and the serialVersionUID of the class.
  34.  * <br>
  35.  * The ObjectStreamClass for a specific class loaded in this Java VM can
  36.  * be found using the lookup method.
  37.  *
  38.  * @author  unascribed
  39.  * @version 1.31, 10/06/97
  40.  * @since   JDK1.1
  41.  */
  42. public class ObjectStreamClass implements java.io.Serializable {
  43.     /** Find the descriptor for a class that can be serialized.  Null
  44.      * is returned if the specified class does not implement
  45.      * java.io.Serializable or java.io.Externalizable.
  46.      * @since   JDK1.1
  47.      */
  48.     public static ObjectStreamClass lookup(Class cl)
  49.     {
  50.     /* Synchronize on the hashtable so no two threads will do
  51.      * this at the same time.
  52.      */
  53.     ObjectStreamClass v = null;
  54.     synchronized (descriptorFor) {
  55.         /* Find the matching descriptor if it already known */
  56.         v = findDescriptorFor(cl);
  57.         if (v != null) {
  58.         return v;
  59.         }
  60.         
  61.         /* Check if it's serializable or externalizable.
  62.          * Since Externalizable extends Serializiable, return
  63.          * null immediately if it's not Serializable.
  64.          */
  65.         boolean serializable = classSerializable.isAssignableFrom(cl);
  66.         if (!serializable)
  67.         return null;
  68.  
  69.         /* Test if it's Externalizable, clear the serializable flag
  70.          * only one or the other may be set in the protocol.
  71.          */
  72.         boolean externalizable = classExternalizable.isAssignableFrom(cl);
  73.         if (externalizable)
  74.         serializable = false;
  75.  
  76.         /* If the class is only Serializable,
  77.          * lookup the descriptor for the superclass.
  78.          */
  79.         ObjectStreamClass superdesc = null;
  80.         if (serializable) {
  81.         Class superclass = cl.getSuperclass();
  82.         if (superclass != null) 
  83.             superdesc = lookup(superclass);
  84.         }
  85.  
  86.         /* Create a new version descriptor,
  87.          * it put itself in the known table.
  88.          */
  89.         v = new ObjectStreamClass(cl, superdesc,
  90.                       serializable, externalizable);
  91.     }
  92.     return v;
  93.     }
  94.     
  95.     /**
  96.      * The name of the class described by this descriptor.
  97.      * @since   JDK1.1
  98.      */
  99.     public String getName() {
  100.     return name;
  101.     }
  102.  
  103.     /**
  104.      * Return the serialVersionUID for this class.
  105.      * The serialVersionUID defines a set of classes all with the same name
  106.      * that have evolved from a common root class and agree to be serialized
  107.      * and deserialized using a common format.
  108.      * @since   JDK1.1
  109.      */
  110.     public long getSerialVersionUID() {
  111.     return suid;
  112.     }
  113.  
  114.     /**
  115.      * Return the class in the local VM that this version is mapped to.
  116.      * Null is returned if there is no corresponding local class.
  117.      * @since   JDK1.1
  118.      */
  119.     public Class forClass() {
  120.     return ofClass;
  121.     }
  122.     
  123.     /**
  124.      * Return a string describing this ObjectStreamClass.
  125.      * @since   JDK1.1
  126.      */
  127.     public String toString() {
  128.     StringBuffer sb = new StringBuffer();
  129.  
  130.     sb.append(name);
  131.     sb.append(": static final long serialVersionUID = ");
  132.     sb.append(Long.toString(suid));
  133.     sb.append("L;");
  134.     return sb.toString();
  135.     }
  136.  
  137.     /*
  138.      * Create a new ObjectStreamClass from a loaded class.
  139.      * Don't call this directly, call lookup instead.
  140.      */
  141.     private ObjectStreamClass(java.lang.Class cl, ObjectStreamClass superdesc,
  142.                   boolean serial, boolean extern)
  143.     {
  144.     int i;
  145.     ofClass = cl;        /* created from this class */
  146.  
  147.     name = cl.getName();
  148.     superclass = superdesc;
  149.     serializable = serial;
  150.     externalizable = extern;
  151.  
  152.     /*
  153.      * Enter this class in the table of known descriptors.
  154.      * Otherwise, when the fields are read it may recurse
  155.      * trying to find the descriptor for itself.
  156.      */
  157.     insertDescriptorFor(this);
  158.  
  159.     if (externalizable || name.equals("java.lang.String")) {
  160.         fields = new ObjectStreamField[0];
  161.     } else {
  162.         /* Fill in the list of persistent fields. */
  163.         fields = getFields0(cl);
  164.  
  165.         if (fields.length > 0) {
  166.         /* sort the fields by type and name,
  167.          * primitive fields come first, sorted by name,
  168.          * then object fields, sorted by name.
  169.          */
  170.         boolean done;
  171.         do {
  172.             done = true;
  173.             for (i = fields.length - 1 ; i > 0 ; i--) {
  174.             if (fields[i - 1].compare(fields[i]) > 0) {
  175.                 ObjectStreamField exch = fields[i];
  176.                 fields[i] = fields[i-1];
  177.                 fields[i-1] = exch;
  178.                 done = false;
  179.             }
  180.             }
  181.         } while (!done);
  182.  
  183.         computeFieldSequence();
  184.         }
  185.     }
  186.  
  187.     /* Get the serialVersionUID from the class */
  188.     suid = getSerialVersionUID(cl);
  189.     if (suid == 0) {
  190.         suid = computeSerialVersionUID(cl);
  191.     }
  192.     hasWriteObjectMethod = hasWriteObject(cl);
  193.     }
  194.  
  195.     /*
  196.      * Create an empty ObjectStreamClass for a class about to be read.
  197.      * This is separate from read so ObjectInputStream can assign the
  198.      * wire handle early, before any nested ObjectStreamClasss might
  199.      * be read.
  200.      */
  201.     ObjectStreamClass(String n, long s) {
  202.     name = n;
  203.     suid = s;
  204.     superclass = null;
  205.     }
  206.  
  207.     /*
  208.      * Set the class this version descriptor matches.
  209.      * The name and serializable hash  must match.
  210.      * Compute and fill in the fieldSequence that will be used
  211.      * for reading.
  212.      */
  213.     void setClass(Class cl) throws InvalidClassException {
  214.     if (cl == null) {
  215.  
  216.         /* There is no local equivalent of this class read from the serialized
  217.          * stream. Initialize this class to always discard data associated with
  218.          * this class.
  219.          */
  220.         localClassDesc = null;
  221.         ofClass = null;
  222.         for (int i = 0; i < fields.length; i++ ) {
  223.         fields[i].offset = -1; // discard data read from stream.
  224.         }
  225.         computeFieldSequence();
  226.         return;
  227.     }
  228.  
  229.     localClassDesc = lookup(cl);
  230.     
  231.     if (!cl.getName().equals(name) ||
  232.         suid != localClassDesc.suid) {
  233.         throw new InvalidClassException(cl.getName(), "Local class not compatible");
  234.     }
  235.     /*
  236.      * Test that both implement either serializable or externalizable.
  237.      */
  238.     if (serializable != localClassDesc.serializable ||
  239.         externalizable != localClassDesc.externalizable)
  240.         throw new InvalidClassException(cl.getName(),
  241.                     "Serialization incompatible with Externalization");
  242.  
  243.     /* Compute the offsets in the class where each field in this descriptor
  244.      * should be stored.  The fieldSequence is computed from the offsets
  245.      * and used by the native code to read and store the values.
  246.      * Each field in this ObjectStreamClass (the source) is located (by name) in
  247.      * the ObjectStreamClass of the class(the destination).
  248.      * In the usual (non-versioned case) the field is in both
  249.      * descriptors and the types match, so the offset is copied.
  250.      * If the type does not match, a InvalidClass exception is thrown.
  251.      * If the field is not present in the class, the offset is set to -1
  252.      * so the field will be read but discarded.
  253.      * If extra fields are present in the class they are ignored. Their
  254.      * values will be set to the default value by the object allocator.
  255.      * Both the src and dest field list are sorted by type and name.
  256.      */
  257.  
  258.     ObjectStreamField[] destfield = localClassDesc.getFields();
  259.     ObjectStreamField[] srcfield = fields;
  260.  
  261.     int j = 0;
  262.     nextsrc:
  263.     for (int i = 0; i < srcfield.length; i++ ) {
  264.         /* Find this field in the dest*/
  265.         for (int k = j; k < destfield.length; k++) {
  266.           if (srcfield[i].name.equals(destfield[k].name)) {
  267.           /* found match */
  268.           if (!srcfield[i].typeEquals(destfield[k])) {
  269.               throw new InvalidClassException(cl.getName(),
  270.                           "The type of field " +
  271.                                srcfield[i].name +
  272.                                " of class " + name +
  273.                                " is incompatible.");
  274.           }
  275.  
  276.           /* Skip over any fields in the dest that are not in the src */
  277.            j = k; 
  278.           
  279.           srcfield[i].offset = destfield[j].offset;
  280.           // go on to the next source field
  281.           continue nextsrc;
  282.           }
  283.         }
  284.         /* Source field not found in dest, mark field to discard. */
  285.         srcfield[i].offset = -1;
  286.     }
  287.  
  288.     /* Setup the field sequence for native code */
  289.     computeFieldSequence();
  290.  
  291.     /* Remember the class this represents */
  292.     ofClass = cl;
  293.     }
  294.  
  295.     /*
  296.      * Compare the types of two class descriptors.
  297.      * The match if they have the same name and suid
  298.      */
  299.     boolean typeEquals(ObjectStreamClass other) {
  300.     return (suid == other.suid) && name.equals(other.name);
  301.     }
  302.     
  303.     /*
  304.      * Return the array of persistent fields for this class.
  305.      */
  306.     ObjectStreamField[] getFields(){
  307.     return fields;
  308.     }
  309.     
  310.     /*
  311.      * Return the superclass descriptor of this descriptor.
  312.      */
  313.     void setSuperclass(ObjectStreamClass s) {
  314.     superclass = s;
  315.     }
  316.  
  317.     /*
  318.      * Return the superclass descriptor of this descriptor.
  319.      */
  320.     ObjectStreamClass getSuperclass() {
  321.     return superclass;
  322.     }
  323.     
  324.     /*
  325.      * Return whether the class has a writeObject method
  326.      */
  327.     boolean hasWriteObject() {
  328.     return hasWriteObjectMethod;
  329.     }
  330.     
  331.     /*
  332.      * Return the ObjectStreamClass of the local class this one is based on.
  333.      */
  334.     ObjectStreamClass localClassDescriptor() {
  335.     return localClassDesc;
  336.     }
  337.     
  338.     /*
  339.      * Get the externalizability of the class.
  340.      */
  341.     boolean isExternalizable() {
  342.     return externalizable;
  343.     }
  344.  
  345.     /*
  346.      * Get the sequence of fields for this Class.
  347.      */
  348.     int[] getFieldSequence() {
  349.     return fieldSequence;
  350.     }
  351.  
  352.     /*
  353.      * Create the array used by the native code containing
  354.      * the types and offsets to store value read from the stream.
  355.      * The array is an array of int's with the even numbered elements
  356.      * containing the type (first character) and the odd elements
  357.      * containing the offset into the object where the value should be
  358.      * stored.  An offset of -1 means the value should be discarded.
  359.      */
  360.     private void computeFieldSequence() {
  361.     fieldSequence = new int[fields.length*2];
  362.     for (int i = 0; i < fields.length; i++ ) {
  363.         fieldSequence[i*2] = fields[i].type;
  364.         fieldSequence[i*2+1] = fields[i].offset;
  365.     }
  366.     }
  367.     
  368.     /*
  369.      * Compute a hash for the specified class.  Incrementally add
  370.      * items to the hash accumulating in the digest stream.
  371.      * Fold the hash into a long.  Use the SHA secure hash function.
  372.      */
  373.     private static long computeSerialVersionUID(Class thisclass) {
  374.     ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  375.  
  376.     long h = 0;
  377.     try {
  378.         MessageDigest md = MessageDigest.getInstance("SHA");
  379.         DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  380.         DataOutputStream data = new DataOutputStream(mdo);
  381.  
  382.         data.writeUTF(thisclass.getName());
  383.         
  384.         int classaccess = getClassAccess(thisclass);
  385.         classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  386.                 Modifier.INTERFACE | Modifier.ABSTRACT);
  387.         data.writeInt(classaccess);
  388.         
  389.         /* 
  390.          * Get the list of interfaces supported,
  391.          * Accumulate their names their names in Lexical order
  392.          * and add them to the hash
  393.          */
  394.         Class interfaces[] = thisclass.getInterfaces();
  395.         quicksort(interfaces);
  396.         
  397.         for (int i = 0; i < interfaces.length; i++) {
  398.         data.writeUTF(interfaces[i].getName());
  399.         }
  400.  
  401.         /* Sort the field names to get a deterministic order */
  402.         String fields[] = getFieldSignatures(thisclass);
  403.         quicksort(fields);
  404.         
  405.         /* Include in the hash all fields except those that are
  406.          * private transient and private static.
  407.          */
  408.         for (int i = 0; i < fields.length; i++) {
  409.         String field = fields[i];
  410.         int access = getFieldAccess(thisclass, field);
  411.         if ((access & M_PRIVATE) == M_PRIVATE &&
  412.             (((access & M_TRANSIENT) == M_TRANSIENT)||
  413.              ((access & M_STATIC) == M_STATIC)))
  414.             continue;
  415.         int offset = field.indexOf(' ');
  416.         String name = field.substring(0, offset);
  417.         String desc = field.substring(offset+1);
  418.         data.writeUTF(name);
  419.         data.writeInt(access);
  420.         data.writeUTF(desc);
  421.         }
  422.  
  423.         /*
  424.          * Get the list of methods including name and signature
  425.          * Sort lexically, add all except the private methods
  426.          * to the hash with their access flags
  427.          */
  428.         String methods[] = getMethodSignatures(thisclass);
  429.         quicksort(methods);
  430.         
  431.         for (int i = 0; i < methods.length; i++) {
  432.         String method = methods[i];
  433.         int access = getMethodAccess(thisclass, method);
  434.         if ((access & M_PRIVATE) != 0)
  435.             continue;
  436.         int offset = method.indexOf(' ');
  437.         String mname = method.substring(0, offset);
  438.         String desc = method.substring(offset+1);
  439.         desc = desc.replace('/', '.');
  440.         data.writeUTF(mname);
  441.         data.writeInt(access);
  442.         data.writeUTF(desc);
  443.         }
  444.  
  445.         /* Compute the hash value for this class.
  446.          * Use only the first 64 bits of the hash.
  447.          */
  448.         byte hasharray[] = md.digest();
  449.         for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  450.         h += (long)(hasharray[i] & 255) << (i * 8);
  451.         }
  452.     } catch (IOException ignore) {
  453.         /* can't happen, but be deterministic anyway. */
  454.         h = -1;
  455.     } catch (NoSuchAlgorithmException complain) {
  456.         throw new SecurityException(complain.getMessage());
  457.     }
  458.     return h;
  459.     }
  460.  
  461.     /* These are in this class so that there is no chance they can be used
  462.      * outside the class.
  463.      */
  464.     private static native int getClassAccess(Class aclass);
  465.  
  466.     private static native String[] getMethodSignatures(Class aclass);
  467.     private static native int getMethodAccess(Class aclass, String methodsig);
  468.  
  469.     private static native String[] getFieldSignatures(Class aclass);
  470.     private static native int getFieldAccess(Class aclass, String fieldsig);
  471.  
  472.     private static final int M_TRANSIENT = 0x0080;
  473.     private static final int M_PRIVATE = 0x0002;
  474.     private static final int M_STATIC = 0x0008;
  475.  
  476.     /*
  477.      * locate the ObjectStreamClass for this class and write it to the stream.
  478.      */
  479.     void write(ObjectOutputStream s) throws IOException {
  480.     
  481.     /* write the flag indicating that this class has write/read object methods */
  482.     int flags = 0;
  483.     if (hasWriteObjectMethod)
  484.         flags |= ObjectStreamConstants.SC_WRITE_METHOD;
  485.     if (serializable)
  486.         flags |= ObjectStreamConstants.SC_SERIALIZABLE;
  487.     if (externalizable)
  488.         flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
  489.     s.writeByte(flags);
  490.     
  491.     /* write the total number of fields */
  492.     s.writeShort(fields.length);
  493.     
  494.     /* Write out the descriptors of the primitive fields Each
  495.      * descriptor consists of the UTF fieldname, a short for the
  496.      * access modes, and the first byte of the signature byte.
  497.      * For the object types, ('[' and 'L'), a reference to the
  498.      * type of the field follows.
  499.      */
  500.     for (int i = 0; i < fields.length; i++ ) {
  501.         ObjectStreamField f = fields[i];
  502.         s.writeByte(f.type);
  503.         s.writeUTF(f.name);
  504.         if (!f.isPrimitive()) {
  505.         s.writeObject(f.typeString);
  506.         }
  507.     }
  508.     }
  509.  
  510.     /*
  511.      * Read the version descriptor from the stream.
  512.      * Write the count of field descriptors
  513.      * for each descriptor write the first character of its type,
  514.      * the name of the field.
  515.      * If the type is for an object either array or object, write
  516.      * the type typedescriptor for the type
  517.      */
  518.     void read(ObjectInputStream s) throws IOException, ClassNotFoundException {
  519.     
  520.     /* read flags and determine whether the source class had
  521.          * write/read methods.
  522.      */
  523.     byte flags = s.readByte();
  524.     hasWriteObjectMethod = (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
  525.     serializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
  526.     externalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
  527.  
  528.     /* Read the number of fields described.
  529.      * For each field read the type byte, the name.
  530.      */    
  531.     int count = s.readShort();
  532.     fields = new ObjectStreamField[count];
  533.     for (int i = 0; i < count; i++ ) {
  534.         char type = (char)s.readByte();
  535.         String name = s.readUTF();
  536.         String ftype = null;
  537.         if (type == '[' || type == 'L') {
  538.         ftype = (String)s.readObject();
  539.         }
  540.         fields[i] = new ObjectStreamField(name, type, -1, ftype);
  541.     }
  542.     }
  543.  
  544.  
  545.     /*
  546.      * Cache of Class -> ClassDescriptor Mappings.
  547.      */
  548.     static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  549.  
  550.     /*
  551.      * findDescriptorFor a Class.
  552.      * This looks in the cache for a mapping from Class -> ObjectStreamClass mappings.
  553.      * The hashCode of the Class is used for the lookup since the Class is the key.
  554.      * The entries are extended from sun.misc.Ref so the gc will be able to free them
  555.      * if needed.
  556.      */
  557.     private static ObjectStreamClass findDescriptorFor(Class cl) {
  558.  
  559.     int hash = cl.hashCode();
  560.     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  561.     ObjectStreamClassEntry e;
  562.     ObjectStreamClassEntry prev;
  563.     
  564.     /* Free any initial entries whose refs have been cleared */
  565.     while ((e = descriptorFor[index]) != null && e.check() == null) {
  566.         descriptorFor[index] = e.next;
  567.     }
  568.  
  569.     /* Traverse the chain looking for a descriptor with ofClass == cl.
  570.      * unlink entries that are unresolved.
  571.      */
  572.     prev = e;
  573.     while (e != null ) {
  574.         ObjectStreamClass desc = (ObjectStreamClass)(e.check());
  575.         if (desc == null) {
  576.         // This entry has been cleared,  unlink it
  577.         prev.next = e.next;
  578.         } else {
  579.         if (desc.ofClass == cl)
  580.             return desc;
  581.         prev = e;
  582.         }
  583.         e = e.next;
  584.     }
  585.     return null;
  586.     }
  587.  
  588.     /*
  589.      * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  590.      */
  591.     private static void insertDescriptorFor(ObjectStreamClass desc) {
  592.     // Make sure not already present
  593.     if (findDescriptorFor(desc.ofClass) != null) {
  594.         return;
  595.     }
  596.  
  597.     int hash = desc.ofClass.hashCode();
  598.     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  599.     ObjectStreamClassEntry e = new ObjectStreamClassEntry();
  600.     e.setThing(desc);
  601.     e.next = descriptorFor[index];
  602.            descriptorFor[index] = e;
  603.     }
  604.  
  605.     /*
  606.      * The name of this descriptor
  607.      */
  608.     private String name;
  609.     
  610.     /*
  611.      * The descriptor of the supertype.
  612.      */
  613.     private ObjectStreamClass superclass;
  614.  
  615.     /*
  616.      * Flags for Serializable and Externalizable.
  617.      */
  618.     private boolean serializable;
  619.     private boolean externalizable;
  620.     
  621.     /*
  622.      * Array of persistent fields of this class, sorted by
  623.      * type and name.
  624.      */
  625.     private ObjectStreamField[] fields;
  626.     
  627.     /*
  628.      * Class that is a descriptor for in this virtual machine.
  629.      */
  630.     private Class ofClass;
  631.     
  632.     /* 
  633.      * SerialVersionUID for this class.
  634.      */
  635.     private long suid;
  636.     
  637.     /*
  638.      * This sequence of type, byte offset of the fields to be
  639.      * serialized and deserialized.
  640.      */
  641.     private int[] fieldSequence;
  642.  
  643.     /* True if this class has/had a writeObject method */
  644.     private boolean hasWriteObjectMethod;
  645.     
  646.     /*
  647.      * ObjectStreamClass that this one was built from.
  648.      */
  649.     private ObjectStreamClass localClassDesc;
  650.     
  651.     /* Get the array of non-static and non-transient fields */
  652.     private native ObjectStreamField[] getFields0(Class cl);
  653.     
  654.     /* Get the serialVersionUID from the specified class */
  655.     private static native long getSerialVersionUID(Class cl);
  656.     
  657.     /* Get the boolean as to whether the class has/had a writeObject method. */
  658.     private static native boolean hasWriteObject(Class cl);
  659.     
  660.     /* The Class Object for java.io.Serializable */
  661.     private static Class classSerializable = null;
  662.     private static Class classExternalizable = null;
  663.  
  664.     /*
  665.      * Resolve java.io.Serializable at load time.
  666.      */
  667.     static {
  668.     try {
  669.         classSerializable = Class.forName("java.io.Serializable");
  670.         classExternalizable = Class.forName("java.io.Externalizable");
  671.     } catch (Throwable e) {
  672.         System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
  673.     }
  674.     }
  675.  
  676.     /* Support for quicksort */
  677.  
  678.     /*
  679.      * Implement the doCompare method.
  680.      * Strings are compared directly.
  681.      * Classes are compared using their names.
  682.      * ObjectStreamField objects are compared by type and name
  683.      * and then their descriptors (as strings).
  684.      */
  685.     private static int doCompare(Object o1, Object o2) {
  686.     String s1, s2;
  687.     if (o1 instanceof String && o2 instanceof String) {
  688.         s1 = (String)o1;
  689.         s2 = (String)o2;
  690.     } else if (o1 instanceof Class && o2 instanceof Class) {
  691.         Class c1 = (Class)o1;
  692.         Class c2 = (Class)o2;
  693.         s1 = c1.getName();
  694.         s2 = c2.getName();
  695.     } else if (o1 instanceof ObjectStreamField &&
  696.            o2 instanceof ObjectStreamField) {
  697.         ObjectStreamField f1 = (ObjectStreamField)o1;
  698.         ObjectStreamField f2 = (ObjectStreamField)o2;
  699.         s1 = f1.name;
  700.         s2 = f2.name;
  701.     } else {
  702.         throw new Error("Unsupported types");
  703.     }
  704.     return s1.compareTo(s2);
  705.     }
  706.  
  707.     private static void swap(Object arr[], int i, int j) {
  708.     Object tmp;
  709.  
  710.     tmp = arr[i];
  711.     arr[i] = arr[j];
  712.     arr[j] = tmp;
  713.     }
  714.  
  715.     /*
  716.      * quicksort the array of objects.
  717.      *
  718.      * @param arr[] - an array of objects
  719.      * @param left - the start index - from where to begin sorting
  720.      * @param right - the last index.
  721.      */
  722.     private static void quicksort(Object arr[], int left, int right)
  723.     {
  724.     int i, last;
  725.  
  726.     if (left >= right) { /* do nothing if array contains fewer than two */
  727.         return;          /* two elements */
  728.     }
  729.     swap(arr, left, (left+right) / 2);
  730.     last = left;
  731.     for (i = left+1; i <= right; i++) {
  732.         if (doCompare(arr[i], arr[left]) < 0) {
  733.         swap(arr, ++last, i);
  734.         }
  735.     }
  736.     swap(arr, left, last);
  737.     quicksort(arr, left, last-1);
  738.     quicksort(arr, last+1, right);
  739.     }
  740.  
  741.     /*
  742.      * Preform a sort using the specified comparitor object.
  743.      */       
  744.     private static void quicksort(Object arr[]) {
  745.         quicksort(arr, 0, arr.length-1);
  746.     }
  747. }
  748.  
  749.  
  750. /*
  751.  * Entries held in the Cache of known ObjectStreamClass objects.
  752.  * Entries are chained together with the same hash value (modulo array size).
  753.  */
  754. class ObjectStreamClassEntry extends sun.misc.Ref {
  755.     ObjectStreamClassEntry next;
  756.     public Object reconstitute() {
  757.     return null;
  758.     }
  759. }
  760.