001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.io.serializer;
005:
006: import com.tc.io.TCDataOutput;
007: import com.tc.object.dna.api.DNAEncoding;
008: import com.tc.object.dna.impl.DNAEncodingImpl;
009:
010: import java.io.IOException;
011: import java.io.ObjectOutput;
012: import java.io.OutputStream;
013: import java.io.UnsupportedEncodingException;
014:
015: /**
016: * <p>
017: * ObjectOutputStream is totally inefficient when writing just a small amount of data. It creates a lot of garbage (2 or
018: * 3 KB to just a create it) plus it also writes all the header/block header into the stream.
019: * </p>
020: * <p>
021: * In the server when we serialize the ManagedObjects to sleepycat, we really dont need all the fancy things and we cant
022: * afford to create such overhead. This class is an attempt to solve these problems without getting too complicated.
023: * </p>
024: * <p>
025: * The writeObject() method in this class can only handle writing Literal Objects and will throw an AssertionError for
026: * any other kind of object.
027: * </p>
028: * <p>
029: * TCObjectInputStream compliments this class. Since TCDataOutput doesnt throw IOException and DataOutputStream has all
030: * final methods, I have to reimplement DataOutputStream to not throw IOException.
031: * </p>
032: */
033: public class TCObjectOutputStream implements ObjectOutput, TCDataOutput {
034:
035: private static final DNAEncoding SERIALIZER_ENCODING = new DNAEncodingImpl(
036: DNAEncoding.SERIALIZER);
037:
038: protected final OutputStream out;
039:
040: public TCObjectOutputStream(OutputStream out) {
041: this .out = out;
042: }
043:
044: /**
045: * This method is the reason I am writing this class. This implementation only can handle Literal Objects and is
046: * designed to be used where writeObject() is called only for literal objects. Example : Sleepycat Serialization.
047: *
048: * @see LiteralValues, DNAEncoding
049: */
050: public void writeObject(Object obj) {
051: if (obj != null && obj.getClass().getName().charAt(0) == '[') {
052: SERIALIZER_ENCODING.encodeArray(obj, this );
053: } else {
054: SERIALIZER_ENCODING.encode(obj, this );
055: }
056: }
057:
058: /**
059: * This writes a 4 byte length and then the UTF String itself. If the length is negative, then it is a null string.
060: *
061: * @throws IOException
062: * @see writeUTF();
063: */
064: public void writeString(String string) {
065: if (string == null) {
066: writeInt(-1);
067: return;
068: }
069: try {
070: byte strbytes[] = string.getBytes("UTF-8");
071: writeInt(strbytes.length);
072: write(strbytes);
073: } catch (UnsupportedEncodingException e) {
074: throw new AssertionError(e);
075: }
076: }
077:
078: public void flush() {
079: try {
080: out.flush();
081: } catch (IOException e) {
082: throw new AssertionError(e);
083: }
084: }
085:
086: public void writeBytes(String s) {
087: int len = s.length();
088: try {
089: for (int i = 0; i < len; i++) {
090: out.write((byte) s.charAt(i));
091: }
092: } catch (IOException e) {
093: throw new AssertionError(e);
094: }
095: }
096:
097: public void writeChars(String s) {
098: int len = s.length();
099: try {
100: for (int i = 0; i < len; i++) {
101: int v = s.charAt(i);
102: out.write((v >>> 8) & 0xFF);
103: out.write((v >>> 0) & 0xFF);
104: }
105: } catch (IOException e) {
106: throw new AssertionError(e);
107: }
108: }
109:
110: /**
111: * This implemetation of writeUTF differes from the DataOutputStream's implementation in the following ways. 1) It
112: * handles null strings. 2) It handles long strings (no 65K limit that UTF Encoding poses) 3) Cant be read by
113: * DataInputStream. Use TCObjectInputStream.
114: */
115: public void writeUTF(String str) {
116: writeString(str);
117: }
118:
119: public void close() {
120: flush();
121: try {
122: out.close();
123: } catch (IOException e) {
124: throw new AssertionError(e);
125: }
126: }
127:
128: public void write(int b) {
129: try {
130: out.write(b);
131: } catch (IOException e) {
132: throw new AssertionError(e);
133: }
134: }
135:
136: public void write(byte[] value) {
137: write(value, 0, value.length);
138: }
139:
140: public void write(byte[] value, int offset, int length) {
141: try {
142: out.write(value, offset, length);
143: } catch (IOException e) {
144: throw new AssertionError(e);
145: }
146: }
147:
148: public void writeBoolean(boolean value) {
149: try {
150: out.write(value ? 1 : 0);
151: } catch (IOException e) {
152: throw new AssertionError(e);
153: }
154: }
155:
156: public void writeByte(int value) {
157: try {
158: out.write(value);
159: } catch (IOException e) {
160: throw new AssertionError(e);
161: }
162: }
163:
164: public void writeChar(int v) {
165: try {
166: out.write((v >>> 8) & 0xFF);
167: out.write((v >>> 0) & 0xFF);
168: } catch (IOException e) {
169: throw new AssertionError(e);
170: }
171: }
172:
173: public void writeDouble(double value) {
174: writeLong(Double.doubleToLongBits(value));
175: }
176:
177: public void writeFloat(float value) {
178: writeInt(Float.floatToIntBits(value));
179: }
180:
181: public void writeInt(int v) {
182: try {
183: out.write((v >>> 24) & 0xFF);
184: out.write((v >>> 16) & 0xFF);
185: out.write((v >>> 8) & 0xFF);
186: out.write((v >>> 0) & 0xFF);
187: } catch (IOException e) {
188: throw new AssertionError(e);
189: }
190:
191: }
192:
193: public void writeLong(long v) {
194: final byte writeBuffer[] = new byte[8];
195: writeBuffer[0] = (byte) (v >>> 56);
196: writeBuffer[1] = (byte) (v >>> 48);
197: writeBuffer[2] = (byte) (v >>> 40);
198: writeBuffer[3] = (byte) (v >>> 32);
199: writeBuffer[4] = (byte) (v >>> 24);
200: writeBuffer[5] = (byte) (v >>> 16);
201: writeBuffer[6] = (byte) (v >>> 8);
202: writeBuffer[7] = (byte) (v >>> 0);
203: try {
204: out.write(writeBuffer, 0, 8);
205: } catch (IOException e) {
206: throw new AssertionError(e);
207: }
208: }
209:
210: public void writeShort(int v) {
211: try {
212: out.write((v >>> 8) & 0xFF);
213: out.write((v >>> 0) & 0xFF);
214: } catch (IOException e) {
215: throw new AssertionError(e);
216: }
217: }
218:
219: }
|