/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.ignite.internal.util.test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Print stream that prints each thread group into a separate buffer. Use
* any of the {@code purge(...)} methods to print the contents of the buffer
* to the parent base stream or to a stream of your choice.
*/
public class GridTestPrintStream extends PrintStream {
/** */
private final Map<ThreadGroup, BytePrintStream> streams = new HashMap<>();
/** */
private final ThreadGroup baseGrp;
/**
* Creates test print stream around the base stream passed in.
* Root thread group is the parent of current thread group.
*
* @param out Base print stream.
*/
public GridTestPrintStream(PrintStream out) {
super(out);
baseGrp = Thread.currentThread().getThreadGroup().getParent();
}
/**
* Creates test print stream around the base stream passed in also
* specifying root thread group.
*
* @param out Base print stream.
* @param baseGrp Thread group.
*/
public GridTestPrintStream(PrintStream out, ThreadGroup baseGrp) {
super(out);
assert baseGrp != null;
this.baseGrp = baseGrp;
}
/**
* Gets print stream for current thread group.
*
* @param release Whether or not to clear all the memory associated with thread group.
* @return Gets {@link PrintStream} for current thread group.
*/
private BytePrintStream out(boolean release) {
BytePrintStream out;
synchronized (streams) {
ThreadGroup grp = Thread.currentThread().getThreadGroup();
while (grp != null && grp.getParent() != baseGrp)
grp = grp.getParent();
out = release == true ? streams.remove(grp) : streams.get(grp);
if (out == null) {
if (release)
return new BytePrintStream();
streams.put(grp, out = new BytePrintStream());
}
return out;
}
}
/**
* Purges print stream for this thread group to parent print stream.
*
* @throws IOException If any error happened.
*/
public void purge() throws IOException {
out(true).writeTo(out);
}
/**
* Purges print stream for this thread group to the stream passed in.
*
* @param out Stream to purge to.
* @throws IOException If any error happened.
*/
public void purge(OutputStream out) throws IOException {
out(true).writeTo(out);
}
/** {@inheritDoc} */
@Override public void println() {
out(false).println();
}
/** {@inheritDoc} */
@Override public void print(char c) {
out(false).print(c);
}
/** {@inheritDoc} */
@Override public void println(char x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(double d) {
out(false).print(d);
}
/** {@inheritDoc} */
@Override public void println(double x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(float f) {
out(false).print(f);
}
/** {@inheritDoc} */
@Override public void println(float x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(int i) {
out(false).print(i);
}
/** {@inheritDoc} */
@Override public void println(int x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(long l) {
out(false).print(l);
}
/** {@inheritDoc} */
@Override public void println(long x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(boolean b) {
out(false).print(b);
}
/** {@inheritDoc} */
@Override public void println(boolean x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(char[] s) {
out(false).print(s);
}
/** {@inheritDoc} */
@Override public void println(char[] x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(Object obj) {
out(false).print(obj);
}
/** {@inheritDoc} */
@Override public void println(Object x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void print(String s) {
out(false).print(s);
}
/** {@inheritDoc} */
@Override public void println(String x) {
out(false).println(x);
}
/** {@inheritDoc} */
@Override public void write(byte[] buf, int off, int len) {
out(false).write(buf, off, len);
}
/** {@inheritDoc} */
@Override public void close() {
out(false).close();
}
/** {@inheritDoc} */
@Override public void flush() {
out(false).flush();
}
/** {@inheritDoc} */
@Override public void write(int b) {
out(false).write(b);
}
/** {@inheritDoc} */
@Override public void write(byte[] b) throws IOException {
out(false).write(b);
}
/** {@inheritDoc} */
@Override public PrintStream append(CharSequence csq) {
return out(false).append(csq);
}
/** {@inheritDoc} */
@Override public PrintStream append(CharSequence csq, int start, int end) {
return out(false).append(csq, start, end);
}
/** {@inheritDoc} */
@Override public PrintStream append(char c) {
return out(false).append(c);
}
/** {@inheritDoc} */
@Override public PrintStream printf(String format, Object... args) {
return out(false).printf(format, args);
}
/** {@inheritDoc} */
@Override public PrintStream printf(Locale l, String format, Object... args) {
return out(false).printf(l, format, args);
}
/** {@inheritDoc} */
@Override public PrintStream format(String format, Object... args) {
return out(false).format(format, args);
}
/** {@inheritDoc} */
@Override public PrintStream format(Locale l, String format, Object... args) {
return out(false).format(l, format, args);
}
/**
* Wrapper around print stream that allows purging to any print stream.
*/
private static class BytePrintStream extends PrintStream {
/**
* Default constructor.
*/
BytePrintStream() {
super(new ByteArrayOutputStream());
}
/**
* Writes contents of the internal byte array stream to the stream passed
* in.
*
* @param out Stream to write to.
* @throws IOException If any error happened.
*/
void writeTo(OutputStream out) throws IOException {
flush();
ByteArrayOutputStream byteOut = (ByteArrayOutputStream)this.out;
byteOut.writeTo(out);
// Go back to beginning.
byteOut.reset();
}
}
}