1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2000,2008 Oracle. All rights reserved. 5 * 6 * $Id: SerialOutput.java,v 12.9 2008/02/07 17:12:25 mark Exp $ 7 */ 8 9package com.sleepycat.bind.serial; 10 11import java.io.ByteArrayOutputStream; 12import java.io.IOException; 13import java.io.ObjectOutputStream; 14import java.io.ObjectStreamClass; 15import java.io.ObjectStreamConstants; 16import java.io.OutputStream; 17 18import com.sleepycat.db.DatabaseException; 19import com.sleepycat.util.RuntimeExceptionWrapper; 20 21/** 22 * A specialized <code>ObjectOutputStream</code> that stores class description 23 * information in a <code>ClassCatalog</code>. It is used by 24 * <code>SerialBinding</code>. 25 * 26 * <p>This class is used instead of an {@link ObjectOutputStream}, which it 27 * extends, to write a compact object stream. For writing objects to a 28 * database normally one of the serial binding classes is used. {@link 29 * SerialOutput} is used when an {@link ObjectOutputStream} is needed along 30 * with compact storage. A {@link ClassCatalog} must be supplied, however, to 31 * stored shared class descriptions.</p> 32 * 33 * <p>The {@link ClassCatalog} is used to store class definitions rather than 34 * embedding these into the stream. Instead, a class format identifier is 35 * embedded into the stream. This identifier is then used by {@link 36 * SerialInput} to load the class format to deserialize the object.</p> 37 * 38 * @author Mark Hayes 39 */ 40public class SerialOutput extends ObjectOutputStream { 41 42 /* 43 * Serialization version constants. Instead of hardcoding these we get them 44 * by creating a SerialOutput, which itself guarantees that we'll always 45 * use a PROTOCOL_VERSION_2 header. 46 */ 47 private final static byte[] STREAM_HEADER; 48 static { 49 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 50 try { 51 new SerialOutput(baos, null); 52 } catch (IOException e) { 53 throw new RuntimeExceptionWrapper(e); 54 } 55 STREAM_HEADER = baos.toByteArray(); 56 } 57 58 private ClassCatalog classCatalog; 59 60 /** 61 * Creates a serial output stream. 62 * 63 * @param out is the output stream to which the compact serialized objects 64 * will be written. 65 * 66 * @param classCatalog is the catalog to which the class descriptions for 67 * the serialized objects will be written. 68 */ 69 public SerialOutput(OutputStream out, ClassCatalog classCatalog) 70 throws IOException { 71 72 super(out); 73 this.classCatalog = classCatalog; 74 75 /* guarantee that we'll always use the same serialization format */ 76 77 useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2); 78 } 79 80 // javadoc is inherited 81 protected void writeClassDescriptor(ObjectStreamClass classdesc) 82 throws IOException { 83 84 try { 85 byte[] id = classCatalog.getClassID(classdesc); 86 writeByte(id.length); 87 write(id); 88 } catch (DatabaseException e) { 89 /* 90 * Do not throw IOException from here since ObjectOutputStream 91 * will write the exception to the stream, which causes another 92 * call here, etc. 93 */ 94 throw new RuntimeExceptionWrapper(e); 95 } catch (ClassNotFoundException e) { 96 throw new RuntimeExceptionWrapper(e); 97 } 98 } 99 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} 115