001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2000,2008 Oracle. All rights reserved.
005: *
006: * $Id: SerialOutput.java,v 1.19.2.3 2008/01/07 15:14:05 cwl Exp $
007: */
008:
009: package com.sleepycat.bind.serial;
010:
011: import java.io.ByteArrayOutputStream;
012: import java.io.IOException;
013: import java.io.ObjectOutputStream;
014: import java.io.ObjectStreamClass;
015: import java.io.ObjectStreamConstants;
016: import java.io.OutputStream;
017:
018: import com.sleepycat.je.DatabaseException;
019: import com.sleepycat.util.RuntimeExceptionWrapper;
020:
021: /**
022: * A specialized <code>ObjectOutputStream</code> that stores class description
023: * information in a <code>ClassCatalog</code>. It is used by
024: * <code>SerialBinding</code>.
025: *
026: * <p>This class is used instead of an {@link ObjectOutputStream}, which it
027: * extends, to write a compact object stream. For writing objects to a
028: * database normally one of the serial binding classes is used. {@link
029: * SerialOutput} is used when an {@link ObjectOutputStream} is needed along
030: * with compact storage. A {@link ClassCatalog} must be supplied, however, to
031: * stored shared class descriptions.</p>
032: *
033: * <p>The {@link ClassCatalog} is used to store class definitions rather than
034: * embedding these into the stream. Instead, a class format identifier is
035: * embedded into the stream. This identifier is then used by {@link
036: * SerialInput} to load the class format to deserialize the object.</p>
037: *
038: * @author Mark Hayes
039: */
040: public class SerialOutput extends ObjectOutputStream {
041:
042: /*
043: * Serialization version constants. Instead of hardcoding these we get them
044: * by creating a SerialOutput, which itself guarantees that we'll always
045: * use a PROTOCOL_VERSION_2 header.
046: */
047: private final static byte[] STREAM_HEADER;
048: static {
049: ByteArrayOutputStream baos = new ByteArrayOutputStream();
050: try {
051: new SerialOutput(baos, null);
052: } catch (IOException e) {
053: throw new RuntimeExceptionWrapper(e);
054: }
055: STREAM_HEADER = baos.toByteArray();
056: }
057:
058: private ClassCatalog classCatalog;
059:
060: /**
061: * Creates a serial output stream.
062: *
063: * @param out is the output stream to which the compact serialized objects
064: * will be written.
065: *
066: * @param classCatalog is the catalog to which the class descriptions for
067: * the serialized objects will be written.
068: */
069: public SerialOutput(OutputStream out, ClassCatalog classCatalog)
070: throws IOException {
071:
072: super (out);
073: this .classCatalog = classCatalog;
074:
075: /* guarantee that we'll always use the same serialization format */
076:
077: useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
078: }
079:
080: // javadoc is inherited
081: protected void writeClassDescriptor(ObjectStreamClass classdesc)
082: throws IOException {
083:
084: try {
085: byte[] id = classCatalog.getClassID(classdesc);
086: writeByte(id.length);
087: write(id);
088: } catch (DatabaseException e) {
089: /*
090: * Do not throw IOException from here since ObjectOutputStream
091: * will write the exception to the stream, which causes another
092: * call here, etc.
093: */
094: throw new RuntimeExceptionWrapper(e);
095: } catch (ClassNotFoundException e) {
096: throw new RuntimeExceptionWrapper(e);
097: }
098: }
099:
100: /**
101: * Returns the fixed stream header used for all serialized streams in
102: * PROTOCOL_VERSION_2 format. To save space this header can be removed and
103: * serialized streams before storage and inserted before deserializing.
104: * {@link SerialOutput} always uses PROTOCOL_VERSION_2 serialization format
105: * to guarantee that this header is fixed. {@link SerialBinding} removes
106: * this header from serialized streams automatically.
107: *
108: * @return the fixed stream header.
109: */
110: public static byte[] getStreamHeader() {
111:
112: return STREAM_HEADER;
113: }
114: }
|