/*
 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * -Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the
 *  distribution.
 *
 * Neither the name of Oracle nor the names of
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
 * DAMAGES OR LIABILITIES  SUFFERED BY LICENSEE AS A RESULT OF OR
 * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
 * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
 * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
 * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
 * THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that Software is not designed, licensed or
 * intended for use in the design, construction, operation or
 * maintenance of any nuclear facility.
 */

import java.io.*;
import java.util.*;

/**
 * When Java objects use serialization to store objects, the potential arises
 * that the version of the class reading the data is different from the version
 * of class that wrote that data

 *
 * This example demonstratres some of the compatible changes that Serialization
 * handles without class-specific methods
 *
 * For directions of How to Run: see the Original Class file.
 *
 * Compiled and Tested with JDK1.2
 * This file contains the evolved class.
 * The original class is in file called EvolutionExampleOriginalClass.java
 */
public class EvolutionExampleEvolvedClass {

    /**
     *  There are two options: either a user can serialize an object or
     *  deserialize it. (using the -s or -d flag). These options allow
     *  for the demonstration of bidirection readability and writeability
     *  between the original and the evolved class. In other words,
     *  one can serialize an object here and deserialize it with the evolved
     *  class or vice versa.
     */
    public static void main(String args[]) {

        AClass serializeclass = new AClass(20, "serializedByEvolvedClass");
        AClass deserializeclass = null;

        boolean serialize = false;
        boolean deserialize = false;
        /*
         * see if we are serializing or deserializing.
         * The ability to deserialize or serialize allows
         * us to see the bidirectional readability and writeability
         */
        if (args.length == 1) {
            if (args[0].equals("-d")) {
                deserialize = true;
            } else if (args[0].equals("-s")) {
                serialize = true;
            } else {
                usage();
                System.exit(0);
            }
        } else {
            usage();
            System.exit(0);
        }

        /*
         * Serialize the original class if that's the option chosen
         */
        if (serialize) {
            try {
                FileOutputStream fo = new FileOutputStream("evolve.tmp");
                ObjectOutputStream so = new ObjectOutputStream(fo);
                so.writeObject(serializeclass);
                so.flush();
            } catch (Exception e) {
                System.out.println(e);
                System.exit(1);
            }
        }

        /*
         * Deserialize, if that's the option chosen and print the name
         * of the object, which will allow us to see who serialized the
         * object, the original class or the evolved class file
         */
        if (deserialize) {
            try {
                FileInputStream fi = new FileInputStream("evolve.tmp");
                ObjectInputStream si = new ObjectInputStream(fi);
                deserializeclass = (AClass) si.readObject();
            } catch (Exception e) {
                System.out.println(e);
                System.exit(1);
            }

            /*
             * Print out to see that it is indeed the same object as it was
             * when it was serialized (depending on whether it was the original
             * class that serialized it or the evolved class)
             */
            System.out.println("Now printing deserialized object's name: ");
            System.out.println();
            System.out.println("name: " + deserializeclass.name);
            System.out.println();
        }
  }
     /**
      * Prints out the usage
      */
    static void usage() {
        System.out.println("Usage:");
        System.out.println("      -s (in order to serialize)");
        System.out.println("      -d (in order to deserialize)");
    }
}


    /**
     * Evolved Class
     * Has the following compatible changes
     * 1) add a field
     * 2) change a access to a field (for example -> public to private)
     * 3) Remove the writeObject/readObject methods
     * 4) change a static field to non-static - this is equivalent to adding
     *    a field.

     * Compatible changes that are NOT demonstrated by this example
     * 1) Adding classes/Removing classes
     * 2) Adding writeObject/readObject methods
     */
class AClass implements Serializable {

    // mandatory suid field (gotten using serialver on the original Aclass)
    static final long serialVersionUID = -6756364686697947626L;

    // Change: removed the private
    /**
     * @serial
     */
    int num;

    // Change: added this field
    /**
     * @serial
     */
    boolean b;

    /**
     * @serial
     */
    String name;

    // Change: removed the static.. so this field will now be serialized
    // equivalent to adding a field
    /**
     * @serial
     */
    Hashtable ht = new Hashtable();
    // ...
    // ...
    // ...

    AClass(int n, String s) {
        num = n;
        name = s;
        boolean b = true;
    }

    // some methods...
    // ...
    // ...

    /**
     * These writeObject and readObject merely defaultwriteObject and
     * defaultreadObject - so they don't do anything.. but they are placed
     * here so that we can show that we can remove them in the evolved
     * class without any effect.
     *
     * @serialData Write serializable fields. No optional data written.
     */
    private void writeObject(ObjectOutputStream s)
        throws IOException {
        s.defaultWriteObject();
    }

    /**
     * readObject - just calls defaultreadObject()
     *
     * @serialData Read serializable fields. No optional data read.
     */
    private void readObject(ObjectInputStream s)
        throws IOException, ClassNotFoundException {
            s.defaultReadObject();
    }
}