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.ObjectOutput;
016: import java.io.ObjectOutputStream;
017: import java.util.Map;
018:
019: import com.thoughtworks.xstream.converters.ConversionException;
020: import com.thoughtworks.xstream.converters.DataHolder;
021:
022: public class CustomObjectOutputStream extends ObjectOutputStream {
023:
024: private FastStack callbacks = new FastStack(1);
025: private FastStack customFields = new FastStack(1);
026:
027: private static final String DATA_HOLDER_KEY = CustomObjectOutputStream.class
028: .getName();
029:
030: public static synchronized CustomObjectOutputStream getInstance(
031: DataHolder whereFrom, StreamCallback callback) {
032: try {
033: CustomObjectOutputStream result = (CustomObjectOutputStream) whereFrom
034: .get(DATA_HOLDER_KEY);
035: if (result == null) {
036: result = new CustomObjectOutputStream(callback);
037: whereFrom.put(DATA_HOLDER_KEY, result);
038: } else {
039: result.pushCallback(callback);
040: }
041: return result;
042: } catch (IOException e) {
043: throw new ConversionException(
044: "Cannot create CustomObjectStream", e);
045: }
046: }
047:
048: public static interface StreamCallback {
049: void writeToStream(Object object) throws IOException;
050:
051: void writeFieldsToStream(Map fields) throws IOException;
052:
053: void defaultWriteObject() throws IOException;
054:
055: void flush() throws IOException;
056:
057: void close() throws IOException;
058: }
059:
060: /**
061: * Warning, this object is expensive to create (due to functionality inherited from superclass).
062: * Use the static fetch() method instead, wherever possible.
063: *
064: * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback)
065: */
066: public CustomObjectOutputStream(StreamCallback callback)
067: throws IOException, SecurityException {
068: this .callbacks.push(callback);
069: }
070:
071: /**
072: * Allows the CustomObjectOutputStream (which is expensive to create) to be reused.
073: */
074: public void pushCallback(StreamCallback callback) {
075: this .callbacks.push(callback);
076: }
077:
078: public StreamCallback popCallback() {
079: return (StreamCallback) this .callbacks.pop();
080: }
081:
082: public StreamCallback peekCallback() {
083: return (StreamCallback) this .callbacks.peek();
084: }
085:
086: /*** Methods to delegate to callback ***/
087:
088: public void defaultWriteObject() throws IOException {
089: peekCallback().defaultWriteObject();
090: }
091:
092: protected void writeObjectOverride(Object obj) throws IOException {
093: peekCallback().writeToStream(obj);
094: }
095:
096: public void writeBoolean(boolean val) throws IOException {
097: peekCallback()
098: .writeToStream(val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly
099: }
100:
101: public void writeByte(int val) throws IOException {
102: peekCallback().writeToStream(new Byte((byte) val));
103: }
104:
105: public void writeInt(int val) throws IOException {
106: peekCallback().writeToStream(new Integer(val));
107: }
108:
109: public void writeChar(int val) throws IOException {
110: peekCallback().writeToStream(new Character((char) val));
111: }
112:
113: public void writeDouble(double val) throws IOException {
114: peekCallback().writeToStream(new Double(val));
115: }
116:
117: public void writeFloat(float val) throws IOException {
118: peekCallback().writeToStream(new Float(val));
119: }
120:
121: public void writeLong(long val) throws IOException {
122: peekCallback().writeToStream(new Long(val));
123: }
124:
125: public void writeShort(int val) throws IOException {
126: peekCallback().writeToStream(new Short((short) val));
127: }
128:
129: public void write(byte[] buf) throws IOException {
130: peekCallback().writeToStream(buf);
131: }
132:
133: public void writeChars(String str) throws IOException {
134: peekCallback().writeToStream(str.toCharArray());
135: }
136:
137: public void writeUTF(String str) throws IOException {
138: peekCallback().writeToStream(str);
139: }
140:
141: public void write(int val) throws IOException {
142: peekCallback().writeToStream(new Byte((byte) val));
143: }
144:
145: public void write(byte[] buf, int off, int len) throws IOException {
146: byte[] b = new byte[len];
147: System.arraycopy(buf, off, b, 0, len);
148: peekCallback().writeToStream(b);
149: }
150:
151: public void flush() throws IOException {
152: peekCallback().flush();
153: }
154:
155: public void close() throws IOException {
156: peekCallback().close();
157: }
158:
159: public PutField putFields() {
160: CustomPutField result = new CustomPutField();
161: customFields.push(result);
162: return result;
163: }
164:
165: public void writeFields() throws IOException {
166: CustomPutField customPutField = (CustomPutField) customFields
167: .pop();
168: peekCallback().writeFieldsToStream(customPutField.asMap());
169: }
170:
171: private class CustomPutField extends PutField {
172:
173: private final Map fields = new OrderRetainingMap();
174:
175: public Map asMap() {
176: return fields;
177: }
178:
179: public void write(ObjectOutput out) throws IOException {
180: peekCallback().writeToStream(asMap());
181: }
182:
183: public void put(String name, Object val) {
184: fields.put(name, val);
185: }
186:
187: public void put(String name, byte val) {
188: put(name, new Byte(val));
189: }
190:
191: public void put(String name, char val) {
192: put(name, new Character(val));
193: }
194:
195: public void put(String name, double val) {
196: put(name, new Double(val));
197: }
198:
199: public void put(String name, float val) {
200: put(name, new Float(val));
201: }
202:
203: public void put(String name, int val) {
204: put(name, new Integer(val));
205: }
206:
207: public void put(String name, long val) {
208: put(name, new Long(val));
209: }
210:
211: public void put(String name, short val) {
212: put(name, new Short(val));
213: }
214:
215: public void put(String name, boolean val) {
216: put(name, val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly
217: }
218:
219: }
220:
221: /****** Unsupported methods ******/
222:
223: public void reset() {
224: throw new UnsupportedOperationException();
225: }
226:
227: public void useProtocolVersion(int version) {
228: throw new UnsupportedOperationException();
229: }
230:
231: public void writeBytes(String str) {
232: throw new UnsupportedOperationException();
233: }
234:
235: public void writeUnshared(Object obj) {
236: throw new UnsupportedOperationException();
237: }
238:
239: }
|