/*
 * Copyright 1999 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

/* @test
 * @bug 4227189
 * @summary Ensure that class descriptor read, write hooks exist, are backwards
 *          compatible, and work as advertised.
 */

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

class Foo implements Serializable {
    private static final long serialVersionUID = 1L;
    Short s = new Short((short) 1);
    Integer i = new Integer(2);
    Long l = new Long(3);

    public boolean equals(Object obj) {
        if (obj instanceof Foo) {
            Foo ofoo = (Foo) obj;
            return s.equals(ofoo.s) && i.equals(ofoo.i) && l.equals(ofoo.l);
        }
        return false;
    }
}

class CustomOutputStream extends ObjectOutputStream {

    boolean hookCalled = false;

    CustomOutputStream(OutputStream out) throws IOException {
        super(out);
        useProtocolVersion(PROTOCOL_VERSION_2);
    }

    protected void writeClassDescriptor(ObjectStreamClass desc)
        throws IOException
    {
        writeUTF(desc.getName());
        hookCalled = true;
    }
}

class CustomInputStream extends ObjectInputStream {

    boolean hookCalled = false;

    CustomInputStream(InputStream in) throws IOException {
        super(in);
    }

    protected ObjectStreamClass readClassDescriptor()
        throws IOException, ClassNotFoundException
    {
        hookCalled = true;
        return ObjectStreamClass.lookup(Class.forName(readUTF()));
    }
}

public class ClassDescHooks implements ObjectStreamConstants {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream bout;
        ByteArrayInputStream bin;
        ObjectOutputStream oout;
        ObjectInputStream oin;
        FileInputStream fin;
        File foof;
        CustomOutputStream cout;
        CustomInputStream cin;

        // test for backwards compatibility
        bout = new ByteArrayOutputStream();
        foof = new File(System.getProperty("test.src", "."), "Foo.ser");
        fin = new FileInputStream(foof);
        while (fin.available() > 0)
            bout.write(fin.read());
        byte[] buf1 = bout.toByteArray();

        bout = new ByteArrayOutputStream();
        oout = new ObjectOutputStream(bout);
        Foo foo = new Foo();
        oout.writeObject(foo);
        oout.flush();
        byte[] buf2 = bout.toByteArray();

        if (! Arrays.equals(buf1, buf2))
            throw new Error("Incompatible stream format (write)");

        fin = new FileInputStream(foof);
        oin = new ObjectInputStream(fin);
        Foo foocopy = (Foo) oin.readObject();
        if (! foo.equals(foocopy))
            throw new Error("Incompatible stream format (read)");

        // make sure write hook not called when old protocol in use
        bout = new ByteArrayOutputStream();
        cout = new CustomOutputStream(bout);
        cout.useProtocolVersion(PROTOCOL_VERSION_1);
        cout.writeObject(foo);
        if (cout.hookCalled)
            throw new Error("write descriptor hook should not be called");

        // write custom class descriptor representations
        bout = new ByteArrayOutputStream();
        cout = new CustomOutputStream(bout);
        cout.writeObject(foo);
        cout.flush();
        bin = new ByteArrayInputStream(bout.toByteArray());
        cin = new CustomInputStream(bin);
        foocopy = (Foo) cin.readObject();
        if (! cout.hookCalled)
            throw new Error("write descriptor hook never called");
        if (! cin.hookCalled)
            throw new Error("read descriptor hook never called");
        if (! foo.equals(foocopy))
            throw new Error("serialization failed when hooks active");
    }
}
