001: /*
002: * Copyright (C) 2004, 2005 Joe Walnes.
003: * Copyright (C) 2006, 2007 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 23. August 2004 by Joe Walnes
011: */
012: package com.thoughtworks.xstream.core.util;
013:
014: import java.io.IOException;
015: import java.io.InvalidObjectException;
016: import java.io.NotActiveException;
017: import java.io.ObjectInputStream;
018: import java.io.ObjectInputValidation;
019: import java.io.ObjectStreamClass;
020: import java.io.StreamCorruptedException;
021: import java.util.Map;
022:
023: import com.thoughtworks.xstream.converters.ConversionException;
024: import com.thoughtworks.xstream.converters.DataHolder;
025:
026: public class CustomObjectInputStream extends ObjectInputStream {
027:
028: private FastStack callbacks = new FastStack(1);
029:
030: private static final String DATA_HOLDER_KEY = CustomObjectInputStream.class
031: .getName();
032:
033: public static interface StreamCallback {
034: Object readFromStream() throws IOException;
035:
036: Map readFieldsFromStream() throws IOException;
037:
038: void defaultReadObject() throws IOException;
039:
040: void registerValidation(ObjectInputValidation validation,
041: int priority) throws NotActiveException,
042: InvalidObjectException;
043:
044: void close() throws IOException;
045: }
046:
047: public static synchronized CustomObjectInputStream getInstance(
048: DataHolder whereFrom,
049: CustomObjectInputStream.StreamCallback callback) {
050: try {
051: CustomObjectInputStream result = (CustomObjectInputStream) whereFrom
052: .get(DATA_HOLDER_KEY);
053: if (result == null) {
054: result = new CustomObjectInputStream(callback);
055: whereFrom.put(DATA_HOLDER_KEY, result);
056: } else {
057: result.pushCallback(callback);
058: }
059: return result;
060: } catch (IOException e) {
061: throw new ConversionException(
062: "Cannot create CustomObjectStream", e);
063: }
064: }
065:
066: /**
067: * Warning, this object is expensive to create (due to functionality inherited from superclass).
068: * Use the static fetch() method instead, wherever possible.
069: *
070: * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectInputStream.StreamCallback)
071: */
072: public CustomObjectInputStream(StreamCallback callback)
073: throws IOException, SecurityException {
074: super ();
075: this .callbacks.push(callback);
076: }
077:
078: /**
079: * Allows the CustomObjectInputStream (which is expensive to create) to be reused.
080: */
081: public void pushCallback(StreamCallback callback) {
082: this .callbacks.push(callback);
083: }
084:
085: public StreamCallback popCallback() {
086: return (StreamCallback) this .callbacks.pop();
087: }
088:
089: public StreamCallback peekCallback() {
090: return (StreamCallback) this .callbacks.peek();
091: }
092:
093: public void defaultReadObject() throws IOException {
094: peekCallback().defaultReadObject();
095: }
096:
097: protected Object readObjectOverride() throws IOException {
098: return peekCallback().readFromStream();
099: }
100:
101: public Object readUnshared() throws IOException,
102: ClassNotFoundException {
103: return readObject();
104: }
105:
106: public boolean readBoolean() throws IOException {
107: return ((Boolean) peekCallback().readFromStream())
108: .booleanValue();
109: }
110:
111: public byte readByte() throws IOException {
112: return ((Byte) peekCallback().readFromStream()).byteValue();
113: }
114:
115: public int readUnsignedByte() throws IOException {
116: int b = ((Byte) peekCallback().readFromStream()).byteValue();
117: if (b < 0) {
118: b += Byte.MAX_VALUE;
119: }
120: return b;
121: }
122:
123: public int readInt() throws IOException {
124: return ((Integer) peekCallback().readFromStream()).intValue();
125: }
126:
127: public char readChar() throws IOException {
128: return ((Character) peekCallback().readFromStream())
129: .charValue();
130: }
131:
132: public float readFloat() throws IOException {
133: return ((Float) peekCallback().readFromStream()).floatValue();
134: }
135:
136: public double readDouble() throws IOException {
137: return ((Double) peekCallback().readFromStream()).doubleValue();
138: }
139:
140: public long readLong() throws IOException {
141: return ((Long) peekCallback().readFromStream()).longValue();
142: }
143:
144: public short readShort() throws IOException {
145: return ((Short) peekCallback().readFromStream()).shortValue();
146: }
147:
148: public int readUnsignedShort() throws IOException {
149: int b = ((Short) peekCallback().readFromStream()).shortValue();
150: if (b < 0) {
151: b += Short.MAX_VALUE;
152: }
153: return b;
154: }
155:
156: public String readUTF() throws IOException {
157: return (String) peekCallback().readFromStream();
158: }
159:
160: public void readFully(byte[] buf) throws IOException {
161: readFully(buf, 0, buf.length);
162: }
163:
164: public void readFully(byte[] buf, int off, int len)
165: throws IOException {
166: byte[] b = (byte[]) peekCallback().readFromStream();
167: System.arraycopy(b, 0, buf, off, len);
168: }
169:
170: public int read() throws IOException {
171: return readUnsignedByte();
172: }
173:
174: public int read(byte[] buf, int off, int len) throws IOException {
175: byte[] b = (byte[]) peekCallback().readFromStream();
176: if (b.length != len) {
177: throw new StreamCorruptedException("Expected " + len
178: + " bytes from stream, got " + b.length);
179: }
180: System.arraycopy(b, 0, buf, off, len);
181: return len;
182: }
183:
184: public int read(byte b[]) throws IOException {
185: return read(b, 0, b.length);
186: }
187:
188: public GetField readFields() throws IOException {
189: return new CustomGetField(peekCallback().readFieldsFromStream());
190: }
191:
192: private class CustomGetField extends GetField {
193:
194: private Map fields;
195:
196: public CustomGetField(Map fields) {
197: this .fields = fields;
198: }
199:
200: public ObjectStreamClass getObjectStreamClass() {
201: throw new UnsupportedOperationException();
202: }
203:
204: private Object get(String name) {
205: return fields.get(name);
206: }
207:
208: public boolean defaulted(String name) {
209: return !fields.containsKey(name);
210: }
211:
212: public byte get(String name, byte val) {
213: return defaulted(name) ? val : ((Byte) get(name))
214: .byteValue();
215: }
216:
217: public char get(String name, char val) {
218: return defaulted(name) ? val : ((Character) get(name))
219: .charValue();
220: }
221:
222: public double get(String name, double val) {
223: return defaulted(name) ? val : ((Double) get(name))
224: .doubleValue();
225: }
226:
227: public float get(String name, float val) {
228: return defaulted(name) ? val : ((Float) get(name))
229: .floatValue();
230: }
231:
232: public int get(String name, int val) {
233: return defaulted(name) ? val : ((Integer) get(name))
234: .intValue();
235: }
236:
237: public long get(String name, long val) {
238: return defaulted(name) ? val : ((Long) get(name))
239: .longValue();
240: }
241:
242: public short get(String name, short val) {
243: return defaulted(name) ? val : ((Short) get(name))
244: .shortValue();
245: }
246:
247: public boolean get(String name, boolean val) {
248: return defaulted(name) ? val : ((Boolean) get(name))
249: .booleanValue();
250: }
251:
252: public Object get(String name, Object val) {
253: return defaulted(name) ? val : get(name);
254: }
255:
256: }
257:
258: public void registerValidation(ObjectInputValidation validation,
259: int priority) throws NotActiveException,
260: InvalidObjectException {
261: peekCallback().registerValidation(validation, priority);
262: }
263:
264: public void close() throws IOException {
265: peekCallback().close();
266: }
267:
268: /****** Unsupported methods ******/
269:
270: public int available() {
271: throw new UnsupportedOperationException();
272: }
273:
274: public String readLine() {
275: throw new UnsupportedOperationException();
276: }
277:
278: public int skipBytes(int len) {
279: throw new UnsupportedOperationException();
280: }
281:
282: public long skip(long n) {
283: throw new UnsupportedOperationException();
284: }
285:
286: public void mark(int readlimit) {
287: throw new UnsupportedOperationException();
288: }
289:
290: public void reset() {
291: throw new UnsupportedOperationException();
292: }
293:
294: public boolean markSupported() {
295: return false;
296: }
297:
298: }
|