package org.oddjob.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.oddjob.arooa.ArooaSession;
import org.oddjob.arooa.ArooaValue;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.convert.ArooaConverter;
import org.oddjob.arooa.convert.ConversionFailedException;
import org.oddjob.arooa.convert.ConversionProvider;
import org.oddjob.arooa.convert.ConversionRegistry;
import org.oddjob.arooa.convert.Convertlet;
import org.oddjob.arooa.convert.NoConversionAvailableException;
import org.oddjob.arooa.deploy.annotations.ArooaHidden;
import org.oddjob.arooa.life.ArooaSessionAware;
import org.oddjob.arooa.utils.ListSetterHelper;
/**
* @oddjob.description Split output to multiple other outputs.
*
* @oddjob.example
*
* Copy a buffer to stdout, the log, and to a file.
*
* {@oddjob.xml.resource org/oddjob/io/TeeTypeOutputStream.xml}
*
* @oddjob.example
*
* Copy data to stdout as it is being read during a copy from one buffer to
* another.
*
* {@oddjob.xml.resource org/oddjob/io/TeeTypeInputStream.xml}
*
*
*/
public class TeeType implements ArooaValue, ArooaSessionAware {
private volatile ArooaConverter converter;
private volatile ArooaValue input;
private final List<ArooaValue> outputs =
new ArrayList<ArooaValue>();
public static class Conversions implements ConversionProvider {
public void registerWith(ConversionRegistry registry) {
registry.register(TeeType.class, InputStream.class,
new Convertlet<TeeType, InputStream>() {
@Override
public InputStream convert(TeeType from)
throws ArooaConversionException {
return from.toInputStream();
}
});
registry.register(TeeType.class, OutputStream.class,
new Convertlet<TeeType, OutputStream>() {
@Override
public OutputStream convert(TeeType from)
throws ArooaConversionException {
return from.toOutputStream();
}
});
}
}
@ArooaHidden
@Override
public void setArooaSession(ArooaSession session) {
this.converter = session.getTools().getArooaConverter();
}
/**
* @oddjob.property input
* @oddjob.description An input stream that will be copied to the outputs.
* @oddjob.required Only if this type is required to be an input stream.
*/
public void setInput(ArooaValue input) {
this.input = input;
}
/**
* @oddjob.property outputs
* @oddjob.description List of outputs to split to.
* @oddjob.required No, output will be thrown away if missing.
*/
public void setOutputs(int index, ArooaValue output) {
new ListSetterHelper<ArooaValue>(outputs).set(index, output);
}
public InputStream toInputStream() throws NoConversionAvailableException, ConversionFailedException {
if (input == null) {
return null;
}
InputStream input = converter.convert(this.input, InputStream.class);
return new WireTapInputStream(input, toOutputStream());
}
public OutputStream toOutputStream() throws NoConversionAvailableException, ConversionFailedException {
final List<OutputStream> outputs =
new ArrayList<>();
for (ArooaValue value : this.outputs) {
outputs.add(converter.convert(value, OutputStream.class));
}
return new OutputStream() {
@Override
public void write(int b) throws IOException {
for (OutputStream output : outputs) {
output.write(b);
}
}
@Override
public void write(byte[] b) throws IOException {
for (OutputStream output : outputs) {
output.write(b);
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
for (OutputStream output : outputs) {
output.write(b, off, len);
}
}
@Override
public void flush() throws IOException {
for (OutputStream output : outputs) {
output.flush();
}
}
@Override
public void close() throws IOException {
for (OutputStream output : outputs) {
output.close();
}
}
@Override
public String toString() {
return "TeeOutputStream to " + outputs.size() +
" OutputStreams";
}
};
}
}