/*
* Copyright 2013 eXo Platform SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package juzu.io;
import juzu.impl.common.Tools;
import juzu.impl.io.AppendableStream;
import juzu.impl.io.BinaryOutputStream;
import juzu.impl.io.SinkStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.LinkedList;
/** @author Julien Viet */
public abstract class OutputStream implements Stream, Closeable {
/** . */
public static final int BUFFER_SIZE = 512;
/** . */
private LinkedList<Error> errors = null;
public static OutputStream create(Charset charset, Appendable out) {
return new AppendableStream(charset, out);
}
public static OutputStream create(Charset charset, Appendable out, Flushable flushable, Closeable closeable) {
return new AppendableStream(charset, out, flushable, closeable);
}
public static OutputStream create(Charset charset, java.io.OutputStream out) {
return new BinaryOutputStream(charset, out);
}
public static SinkStream create() {
return SinkStream.INSTANCE;
}
public void provide(Chunk chunk) {
try {
if (chunk instanceof Chunk.Data) {
Chunk.Data data = (Chunk.Data)chunk;
if (data instanceof Chunk.Data.Bytes) {
append(((Chunk.Data.Bytes)data).data);
} else if (data instanceof Chunk.Data.Chars) {
append(CharBuffer.wrap(((Chunk.Data.Chars)data).data));
} else if (data instanceof Chunk.Data.CharSequence) {
Chunk.Data.CharSequence cs = (Chunk.Data.CharSequence)data;
append(cs.data, cs.start, cs.end);
} else if (data instanceof Chunk.Data.Char) {
Chunk.Data.Char cs = (Chunk.Data.Char)data;
append(cs.value);
} else if (data instanceof Chunk.Data.InputStream) {
ByteArrayOutputStream baos = Tools.copy(((Chunk.Data.InputStream)data).data, new ByteArrayOutputStream());
append(baos.toByteArray());
} else if (data instanceof Chunk.Data.Readable) {
Readable readable = ((Chunk.Data.Readable)data).data;
CharBuffer buffer = CharBuffer.allocate(512);
for (int i = readable.read(buffer);i != -1;i = readable.read(buffer)) {
buffer.flip();
append(buffer);
buffer.clear();
}
if (readable instanceof Closeable) {
Tools.safeClose((Closeable)readable);
}
} else {
throw new IOException("Not yet handled");
}
}
}
catch (IOException e) {
reportError(e);
}
}
public void close(Thread.UncaughtExceptionHandler errorHandler) {
try {
close();
}
catch (Exception e) {
reportError(e);
}
if (errorHandler != null && errors != null) {
for (Error error : errors) {
errorHandler.uncaughtException(error.thread, error.uncaught);
}
}
}
private void reportError(Throwable t) {
if (errors == null) {
errors = new LinkedList<Error>();
}
errors.add(new Error(Thread.currentThread(), t));
}
public abstract void append(CharBuffer buffer) throws IOException;
public abstract void append(CharSequence csq) throws IOException;
public abstract void append(CharSequence csq, int start, int end) throws IOException;
public abstract void append(ByteBuffer buffer) throws IOException;
public abstract void append(char c) throws IOException;
public abstract void append(byte[] data) throws IOException;
public abstract void append(byte[] data, int off, int len) throws IOException;
private static class Error {
final Thread thread;
final Throwable uncaught;
private Error(Thread thread, Throwable uncaught) {
this.thread = thread;
this.uncaught = uncaught;
}
}
}