/*
 * Copyright (c) 1999, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.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");
    }
}
