/*
* Copyright (C) 2004, 2005 Joe Walnes.
* Copyright (C) 2006, 2007, 2014 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
*
* Created on 23. August 2004 by Joe Walnes
*/
package com.thoughtworks.xstream.core.util;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.DataHolder;
public class CustomObjectOutputStream extends ObjectOutputStream {
private final FastStack<StreamCallback> callbacks = new FastStack<StreamCallback>(1);
private final FastStack<CustomPutField> customFields = new FastStack<CustomPutField>(1);
private static final String DATA_HOLDER_KEY = CustomObjectOutputStream.class.getName();
public static synchronized CustomObjectOutputStream getInstance(final DataHolder whereFrom,
final StreamCallback callback) {
try {
CustomObjectOutputStream result = (CustomObjectOutputStream)whereFrom.get(DATA_HOLDER_KEY);
if (result == null) {
result = new CustomObjectOutputStream(callback);
whereFrom.put(DATA_HOLDER_KEY, result);
} else {
result.pushCallback(callback);
}
return result;
} catch (final IOException e) {
throw new ConversionException("Cannot create CustomObjectStream", e);
}
}
public static interface StreamCallback {
void writeToStream(Object object) throws IOException;
void writeFieldsToStream(Map<String, Object> fields) throws IOException;
void defaultWriteObject() throws IOException;
void flush() throws IOException;
void close() throws IOException;
}
/**
* Warning, this object is expensive to create (due to functionality inherited from superclass). Use the static
* fetch() method instead, wherever possible.
*
* @see #getInstance(com.thoughtworks.xstream.converters.DataHolder,
* com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback)
*/
public CustomObjectOutputStream(final StreamCallback callback) throws IOException, SecurityException {
callbacks.push(callback);
}
/**
* Allows the CustomObjectOutputStream (which is expensive to create) to be reused.
*/
public void pushCallback(final StreamCallback callback) {
callbacks.push(callback);
}
public StreamCallback popCallback() {
return callbacks.pop();
}
public StreamCallback peekCallback() {
return callbacks.peek();
}
/*** Methods to delegate to callback ***/
@Override
public void defaultWriteObject() throws IOException {
peekCallback().defaultWriteObject();
}
@Override
protected void writeObjectOverride(final Object obj) throws IOException {
peekCallback().writeToStream(obj);
}
@Override
public void writeBoolean(final boolean val) throws IOException {
peekCallback().writeToStream(Boolean.valueOf(val));
}
@Override
public void writeByte(final int val) throws IOException {
peekCallback().writeToStream(Byte.valueOf((byte)val));
}
@Override
public void writeInt(final int val) throws IOException {
peekCallback().writeToStream(Integer.valueOf(val));
}
@Override
public void writeChar(final int val) throws IOException {
peekCallback().writeToStream(Character.valueOf((char)val));
}
@Override
public void writeDouble(final double val) throws IOException {
peekCallback().writeToStream(Double.valueOf(val));
}
@Override
public void writeFloat(final float val) throws IOException {
peekCallback().writeToStream(Float.valueOf(val));
}
@Override
public void writeLong(final long val) throws IOException {
peekCallback().writeToStream(Long.valueOf(val));
}
@Override
public void writeShort(final int val) throws IOException {
peekCallback().writeToStream(Short.valueOf((short)val));
}
@Override
public void write(final byte[] buf) throws IOException {
peekCallback().writeToStream(buf);
}
@Override
public void writeChars(final String str) throws IOException {
peekCallback().writeToStream(str.toCharArray());
}
@Override
public void writeUTF(final String str) throws IOException {
peekCallback().writeToStream(str);
}
@Override
public void write(final int val) throws IOException {
peekCallback().writeToStream(Byte.valueOf((byte)val));
}
@Override
public void write(final byte[] buf, final int off, final int len) throws IOException {
final byte[] b = new byte[len];
System.arraycopy(buf, off, b, 0, len);
peekCallback().writeToStream(b);
}
@Override
public void flush() throws IOException {
peekCallback().flush();
}
@Override
public void close() throws IOException {
peekCallback().close();
}
@Override
public PutField putFields() {
final CustomPutField result = new CustomPutField();
customFields.push(result);
return result;
}
@Override
public void writeFields() throws IOException {
final CustomPutField customPutField = customFields.pop();
peekCallback().writeFieldsToStream(customPutField.asMap());
}
private class CustomPutField extends PutField {
private final Map<String, Object> fields = new LinkedHashMap<String, Object>();
public Map<String, Object> asMap() {
return fields;
}
@Override
public void write(final ObjectOutput out) throws IOException {
peekCallback().writeToStream(asMap());
}
@Override
public void put(final String name, final Object val) {
fields.put(name, val);
}
@Override
public void put(final String name, final byte val) {
put(name, Byte.valueOf(val));
}
@Override
public void put(final String name, final char val) {
put(name, Character.valueOf(val));
}
@Override
public void put(final String name, final double val) {
put(name, Double.valueOf(val));
}
@Override
public void put(final String name, final float val) {
put(name, Float.valueOf(val));
}
@Override
public void put(final String name, final int val) {
put(name, Integer.valueOf(val));
}
@Override
public void put(final String name, final long val) {
put(name, Long.valueOf(val));
}
@Override
public void put(final String name, final short val) {
put(name, Short.valueOf(val));
}
@Override
public void put(final String name, final boolean val) {
put(name, Boolean.valueOf(val));
}
}
/****** Unsupported methods ******/
@Override
public void reset() {
throw new UnsupportedOperationException();
}
@Override
public void useProtocolVersion(final int version) {
throw new UnsupportedOperationException();
}
@Override
public void writeBytes(final String str) {
throw new UnsupportedOperationException();
}
@Override
public void writeUnshared(final Object obj) {
throw new UnsupportedOperationException();
}
}