/*
 * Copyright 2002 Sun Microsystems, Inc. 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 Sun Microsystems, Inc. or 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.*;


/**
 * This example shows how to use the readResolve method.
 * This method resolves the object
 * read from the stream before it is returned to the caller.
 * The writeReplacea method allows an object to nominate its 
 * own replacement in the stream before the object is written.  
 *
 * This example creates a symbol class for which only a single instance of
 * each symbol binding exists. The Symbol class defines the
 * readResolve method. A symbol is created from outside using the 
 * symbollookup method, which finds and returns a symbol if one already 
 * exists and creates one, if one does not. This assures uniqueness within
 * one VM. Then, when readResolve is called when the symbol is being read, 
 * a preexisting equivalent Symbol object is substituted from the hashtable 
 * to maintain the unique identity constraint, if such a symbol exists. 
 * Otherwise, the new symbol is added to the hashtable and returned. This 
 * assures uniqueness when we are dealing with more than one VM.
 *
 *
 * How to Run:
 *             Compile this file: javac Substitute.java
 *             Run this file:     java Substitute
 *
 * This will print out a confirmation that the two symbols that were
 * serialized separately but had the same name are indeed the same symbol.
 *
 *
 * Compiled and Tested with JDK1.2
 */

public class Substitute {
   
    /** 
     * Basically, serialize and deserialize two symbols with the same
     *  name and show that they are actually the same symbol.
     */
    public static void main(String args[]) {
	
	// create a few symbols to be serialized
	Symbol s1 = Symbol.symbolLookup("blue");
	Symbol s2 = Symbol.symbolLookup("pink");
	Symbol s3 = Symbol.symbolLookup("blue");

	// use these to deserialize the symbols
	Symbol obj1 = null, obj2 = null, obj3 = null;


	// serialize the symbols
	try {
 	    FileOutputStream fo = new FileOutputStream("symbol.tmp");
	    ObjectOutputStream so = new ObjectOutputStream(fo);
	    so.writeObject(s1);
	    so.writeObject(s2);
	    so.writeObject(s3);
	    so.flush();
	} catch (Exception e) {
	    System.out.println(e);
	    System.exit(1);
	}
	
	// deserialize the symbols
	try {
	    FileInputStream fi = new FileInputStream("symbol.tmp");
	    ObjectInputStream si = new ObjectInputStream(fi);
	    obj1 = (Symbol) si.readObject();
	    obj2 = (Symbol) si.readObject();
	    obj3 = (Symbol) si.readObject();
	} catch (Exception e) {
	    System.out.println(e);
	    System.exit(1);
	}

	// show the uniqueness 
	if (obj1 == obj3) {
	    System.out.println("Symbol1 and Symbol3 are the same!");
	}
    }
}


/** 
 * The class implementing the readResolve method.
 */
class Symbol implements Serializable {

    /**
     * @serial
     */
    String symbolname;

    /* 
     * Hashtable is **static** because we need to use the same one for
     * all symbol objects. 
     */
    static Hashtable ht = new Hashtable();
    
    /** 
     * This method serves as the constructor. It looks in the hashtable and
     * if that symbol exists, will return that symbol... otherwise, will 
     * create a symbol with that name and will add it to the hashtable. This
     * will assure that the symbols are always unique.
     */
    static Symbol symbolLookup(String symname) {
	if (ht.containsKey(symname)) {
	    return (Symbol)(ht.get(symname));
	}
	else {
	    Symbol newSym = new Symbol(symname);
	    ht.put(symname, newSym);
	    return(newSym);
	}
    }

    /** 
     * Private constructor because we want "outsiders" to use 
     *  symbolLookup instead to force uniqueness.
     */
    private Symbol (String name) {
	symbolname = name;
    }

    /** 
     * Deals with the issue of uniqueness when we are dealing with more
     * than one VM by adding the read symbol to the hash table, if it
     * isn't already there.
     */
    public Object readResolve() throws ObjectStreamException {
	if (!ht.containsKey(symbolname))
	    ht.put(symbolname, this);
	return (Symbol) (ht.get(symbolname));
    }
}









