1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000,2008 Oracle.  All rights reserved.
5 *
6 * $Id: SerialInput.java,v 12.7 2008/01/08 20:58:35 bostic Exp $
7 */
8
9package com.sleepycat.bind.serial;
10
11import java.io.IOException;
12import java.io.InputStream;
13import java.io.ObjectInputStream;
14import java.io.ObjectStreamClass;
15
16import com.sleepycat.db.DatabaseException;
17import com.sleepycat.util.RuntimeExceptionWrapper;
18
19/**
20 * A specialized <code>ObjectInputStream</code> that gets class description
21 * information from a <code>ClassCatalog</code>.  It is used by
22 * <code>SerialBinding</code>.
23 *
24 * <p>This class is used instead of an {@link ObjectInputStream}, which it
25 * extends, to read an object stream written by the {@link SerialOutput} class.
26 * For reading objects from a database normally one of the serial binding
27 * classes is used.  {@link SerialInput} is used when an {@link
28 * ObjectInputStream} is needed along with compact storage.  A {@link
29 * ClassCatalog} must be supplied, however, to stored shared class
30 * descriptions.</p>
31 *
32 * @author Mark Hayes
33 */
34public class SerialInput extends ObjectInputStream {
35
36    private ClassCatalog classCatalog;
37    private ClassLoader classLoader;
38
39    /**
40     * Creates a serial input stream.
41     *
42     * @param in is the input stream from which compact serialized objects will
43     * be read.
44     *
45     * @param classCatalog is the catalog containing the class descriptions
46     * for the serialized objects.
47     */
48    public SerialInput(InputStream in, ClassCatalog classCatalog)
49        throws IOException {
50
51        this(in, classCatalog, null);
52    }
53
54    /**
55     * Creates a serial input stream.
56     *
57     * @param in is the input stream from which compact serialized objects will
58     * be read.
59     *
60     * @param classCatalog is the catalog containing the class descriptions
61     * for the serialized objects.
62     *
63     * @param classLoader is the class loader to use, or null if a default
64     * class loader should be used.
65     */
66    public SerialInput(InputStream in,
67                       ClassCatalog classCatalog,
68                       ClassLoader classLoader)
69        throws IOException {
70
71        super(in);
72
73        this.classCatalog = classCatalog;
74        this.classLoader = classLoader;
75    }
76
77    // javadoc is specified elsewhere
78    protected ObjectStreamClass readClassDescriptor()
79        throws IOException, ClassNotFoundException {
80
81        try {
82            byte len = readByte();
83            byte[] id = new byte[len];
84            readFully(id);
85
86            return classCatalog.getClassFormat(id);
87        } catch (DatabaseException e) {
88            /*
89             * Do not throw IOException from here since ObjectOutputStream
90             * will write the exception to the stream, which causes another
91             * call here, etc.
92             */
93            throw new RuntimeExceptionWrapper(e);
94        }
95    }
96
97    // javadoc is specified elsewhere
98    protected Class resolveClass(ObjectStreamClass desc)
99        throws IOException, ClassNotFoundException {
100
101        if (classLoader != null) {
102            try {
103                return Class.forName(desc.getName(), false, classLoader);
104            } catch (ClassNotFoundException e) {
105                return super.resolveClass(desc);
106            }
107        } else {
108            return super.resolveClass(desc);
109        }
110    }
111}
112