| /*- |
| * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved. |
| * |
| * This file was distributed by Oracle as part of a version of Oracle Berkeley |
| * DB Java Edition made available at: |
| * |
| * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html |
| * |
| * Please see the LICENSE file included in the top-level directory of the |
| * appropriate version of Oracle Berkeley DB Java Edition for a copy of the |
| * license and additional information. |
| */ |
| |
| package com.sleepycat.bind.serial; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamClass; |
| import java.io.ObjectStreamConstants; |
| import java.io.OutputStream; |
| |
| import com.sleepycat.je.DatabaseException; |
| import com.sleepycat.util.RuntimeExceptionWrapper; |
| |
| /** |
| * A specialized <code>ObjectOutputStream</code> that stores class description |
| * information in a <code>ClassCatalog</code>. It is used by |
| * <code>SerialBinding</code>. |
| * |
| * <p>This class is used instead of an {@link ObjectOutputStream}, which it |
| * extends, to write a compact object stream. For writing objects to a |
| * database normally one of the serial binding classes is used. {@link |
| * SerialOutput} is used when an {@link ObjectOutputStream} is needed along |
| * with compact storage. A {@link ClassCatalog} must be supplied, however, to |
| * stored shared class descriptions.</p> |
| * |
| * <p>The {@link ClassCatalog} is used to store class definitions rather than |
| * embedding these into the stream. Instead, a class format identifier is |
| * embedded into the stream. This identifier is then used by {@link |
| * SerialInput} to load the class format to deserialize the object.</p> |
| * |
| * @see <a href="SerialBinding.html#evolution">Class Evolution</a> |
| * |
| * @author Mark Hayes |
| */ |
| public class SerialOutput extends ObjectOutputStream { |
| |
| /* |
| * Serialization version constants. Instead of hardcoding these we get them |
| * by creating a SerialOutput, which itself guarantees that we'll always |
| * use a PROTOCOL_VERSION_2 header. |
| */ |
| private final static byte[] STREAM_HEADER; |
| static { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| try { |
| new SerialOutput(baos, null); |
| } catch (IOException e) { |
| throw RuntimeExceptionWrapper.wrapIfNeeded(e); |
| } |
| STREAM_HEADER = baos.toByteArray(); |
| } |
| |
| private ClassCatalog classCatalog; |
| |
| /** |
| * Creates a serial output stream. |
| * |
| * @param out is the output stream to which the compact serialized objects |
| * will be written. |
| * |
| * @param classCatalog is the catalog to which the class descriptions for |
| * the serialized objects will be written. |
| * |
| * @throws IOException if an I/O error occurs while writing stream header. |
| */ |
| public SerialOutput(OutputStream out, ClassCatalog classCatalog) |
| throws IOException { |
| |
| super(out); |
| this.classCatalog = classCatalog; |
| |
| /* guarantee that we'll always use the same serialization format */ |
| |
| useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2); |
| } |
| |
| // javadoc is inherited |
| protected void writeClassDescriptor(ObjectStreamClass classdesc) |
| throws IOException { |
| |
| try { |
| byte[] id = classCatalog.getClassID(classdesc); |
| writeByte(id.length); |
| write(id); |
| } catch (DatabaseException e) { |
| |
| /* |
| * Do not throw IOException from here since ObjectOutputStream |
| * will write the exception to the stream, which causes another |
| * call here, etc. |
| */ |
| throw RuntimeExceptionWrapper.wrapIfNeeded(e); |
| } catch (ClassNotFoundException e) { |
| throw RuntimeExceptionWrapper.wrapIfNeeded(e); |
| } |
| } |
| |
| /** |
| * Returns the fixed stream header used for all serialized streams in |
| * PROTOCOL_VERSION_2 format. To save space this header can be removed and |
| * serialized streams before storage and inserted before deserializing. |
| * {@link SerialOutput} always uses PROTOCOL_VERSION_2 serialization format |
| * to guarantee that this header is fixed. {@link SerialBinding} removes |
| * this header from serialized streams automatically. |
| * |
| * @return the fixed stream header. |
| */ |
| public static byte[] getStreamHeader() { |
| |
| return STREAM_HEADER; |
| } |
| } |