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.TCDataInput;
007: import com.tc.object.dna.api.DNAEncoding;
008: import com.tc.object.dna.impl.DNAEncodingImpl;
009:
010: import java.io.EOFException;
011: import java.io.IOException;
012: import java.io.InputStream;
013: import java.io.ObjectInput;
014:
015: /**
016: * <p>
017: * ObjectOutputStream/ObjectInputStream is totally inefficient when writing just a small amount of data. It creates a
018: * lot of garbage (2 or 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 readObject() method in this class can only handle reading Literal Objects and will throw an AssertionError for
026: * any other kind of object.
027: * </p>
028: * <p>
029: * TCObjectOutputStream compliments this class. Since methods DataInputStream are final methods and I want a different
030: * write/readUTF() implementation, I have to reimplement DataInputStream.
031: * </p>
032: */
033: public class TCObjectInputStream implements ObjectInput, TCDataInput {
034:
035: private static final DNAEncoding SERIALIZER_ENCODING = new DNAEncodingImpl(
036: DNAEncoding.SERIALIZER);
037:
038: private final InputStream in;
039:
040: public TCObjectInputStream(InputStream in) {
041: this .in = in;
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 readObject() is called only for literal objects. Example : Sleepycat Serialization.
047: *
048: * @see LiteralValues, DNAEncoding
049: */
050: public Object readObject() throws ClassNotFoundException,
051: IOException {
052: return SERIALIZER_ENCODING.decode(this );
053: }
054:
055: public int read() throws IOException {
056: return in.read();
057: }
058:
059: public int read(byte[] b) throws IOException {
060: return in.read(b);
061: }
062:
063: public int read(byte[] b, int off, int len) throws IOException {
064: return in.read(b, off, len);
065: }
066:
067: public long skip(long n) throws IOException {
068: return in.skip(n);
069: }
070:
071: public int available() throws IOException {
072: return in.available();
073: }
074:
075: public void close() throws IOException {
076: in.close();
077: }
078:
079: public void readFully(byte[] b) throws IOException {
080: readFully(b, 0, b.length);
081: }
082:
083: public void readFully(byte[] b, int off, int len)
084: throws IOException {
085: if (len < 0)
086: throw new IndexOutOfBoundsException();
087: int n = 0;
088: while (n < len) {
089: int count = in.read(b, off + n, len - n);
090: if (count < 0)
091: throw new EOFException();
092: n += count;
093: }
094: }
095:
096: public int skipBytes(int n) throws IOException {
097: int total = 0;
098: int cur = 0;
099:
100: while ((total < n) && ((cur = (int) in.skip(n - total)) > 0)) {
101: total += cur;
102: }
103:
104: return total;
105: }
106:
107: public boolean readBoolean() throws IOException {
108: int ch = in.read();
109: if (ch < 0)
110: throw new EOFException();
111: return (ch != 0);
112: }
113:
114: public byte readByte() throws IOException {
115: int ch = in.read();
116: if (ch < 0)
117: throw new EOFException();
118: return (byte) (ch);
119: }
120:
121: public int readUnsignedByte() throws IOException {
122: int ch = in.read();
123: if (ch < 0)
124: throw new EOFException();
125: return ch;
126: }
127:
128: public short readShort() throws IOException {
129: int ch1 = in.read();
130: int ch2 = in.read();
131: if ((ch1 | ch2) < 0)
132: throw new EOFException();
133: return (short) ((ch1 << 8) + (ch2 << 0));
134: }
135:
136: public int readUnsignedShort() throws IOException {
137: int ch1 = in.read();
138: int ch2 = in.read();
139: if ((ch1 | ch2) < 0)
140: throw new EOFException();
141: return (ch1 << 8) + (ch2 << 0);
142: }
143:
144: public char readChar() throws IOException {
145: int ch1 = in.read();
146: int ch2 = in.read();
147: if ((ch1 | ch2) < 0)
148: throw new EOFException();
149: return (char) ((ch1 << 8) + (ch2 << 0));
150: }
151:
152: public int readInt() throws IOException {
153: int ch1 = in.read();
154: int ch2 = in.read();
155: int ch3 = in.read();
156: int ch4 = in.read();
157: if ((ch1 | ch2 | ch3 | ch4) < 0)
158: throw new EOFException();
159: return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
160: }
161:
162: public long readLong() throws IOException {
163: final byte readBuffer[] = new byte[8];
164: readFully(readBuffer, 0, 8);
165: return (((long) readBuffer[0] << 56)
166: + ((long) (readBuffer[1] & 255) << 48)
167: + ((long) (readBuffer[2] & 255) << 40)
168: + ((long) (readBuffer[3] & 255) << 32)
169: + ((long) (readBuffer[4] & 255) << 24)
170: + ((readBuffer[5] & 255) << 16)
171: + ((readBuffer[6] & 255) << 8) + ((readBuffer[7] & 255) << 0));
172: }
173:
174: public float readFloat() throws IOException {
175: return Float.intBitsToFloat(readInt());
176: }
177:
178: public double readDouble() throws IOException {
179: return Double.longBitsToDouble(readLong());
180: }
181:
182: public String readLine() {
183: throw new UnsupportedOperationException(
184: "Use BufferedReader instead.");
185: }
186:
187: /**
188: * This implemetation of writeUTF differes from the DataOutputStream's implementation in the following ways. 1) It
189: * handles null strings. 2) It handles long strings (no 65K limit that UTF Encoding poses) 3) Data should have been
190: * written by TCObjectOutputStream.
191: */
192: public String readUTF() throws IOException {
193: return readString();
194: }
195:
196: /**
197: * This reads a 4 byte length and then the UTF String itself. If the length is negative, then it is a null string.
198: *
199: * @throws IOException
200: * @see writeUTF();
201: */
202: public String readString() throws IOException {
203: int len = readInt();
204: if (len < 0)
205: return null;
206: else if (len == 0)
207: return "";
208: final byte strbytes[] = new byte[len];
209: readFully(strbytes);
210: return new String(strbytes, "UTF-8");
211: }
212:
213: }
|