
info.monitorenter.util.ExceptionUtil Maven / Gradle / Ivy
/*
* ExceptionUtil, utility class for exceptions.
* Copyright (C) 2004 - 2011 Achim Westermann.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* If you modify or optimize the code in a useful way please let me know.
* [email protected]
*
*/
package info.monitorenter.util;
import info.monitorenter.io.MultiplexingOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.nio.charset.Charset;
/**
* Nice static helpers for working with Strings.
*
* Maybe not always the fastest solution to call in here, but working. Also usable for seeing
* examples and cutting code for manual inlining.
*
*
* @author [email protected]
* @version $Revision: 1.1 $
*/
public final class ExceptionUtil {
/** Singleton instance. */
private static ExceptionUtil instance = null;
/**
* Returns an input stream that contains what will written in this Application to
* {@link System#err}.
*
* Caution
* If you do not consume the bytes to read from the result you may block the whole application. Do
* only use this for debugging purposes or end to end test code!
*
* Attempting to read from the result in the same thread that called here is not recommended as it
* may deadlock the thread. Also the thread reading from the stream result should not write
* anything to {@link System#err}.
*
* Prefer using {@link #findMatchInSystemErr(String)} to avoid deadlocks.
*
*
* @param teeToOriginalSysErr
* if true, all writes to the newly installed {@link System#err} will also sent to the
* original one (thus be visible on the console if the original one was untouched
* before).
* @return an input stream that contains what will written in this Application to
* {@link System#err}.
* @throws java.io.IOException
* if something goes wrong.
*/
public static InputStream captureSystemErrForDebuggingPurposesOnly(
final boolean teeToOriginalSysErr) throws IOException {
PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream(pipeOut);
OutputStream out = pipeOut;
if (teeToOriginalSysErr) {
out = new MultiplexingOutputStream(System.err, pipeOut);
}
PrintStream streamOut = new PrintStream(out);
System.setErr(streamOut);
return pipeIn;
}
/**
* Returns an input stream that contains what will written in this Application to
* {@link System#out}.
*
* Caution
* If you do not consume the bytes to read from the result you may block the whole application. Do
* only use this for debugging purposes or end to end test code!
*
* Attempting to read from the result in the same thread that called here is not recommended as it
* may deadlock the thread. Also the thread reading from the stream result should not write
* anything to {@link System#out}.
*
* Prefer using {@link #findMatchInSystemOut(String)} to avoid deadlocks.
*
*
* @param teeToOriginalSysOut
* if true, all writes to the newly installed {@link System#out} will also sent to the
* original one (thus be visible on the console if the original one was untouched
* before).
* @return an input stream that contains what will written in this Application to
* {@link System#out}.
* @throws java.io.IOException
* if something goes wrong.
*/
public static InputStream captureSystemOutForDebuggingPurposesOnly(
final boolean teeToOriginalSysOut) throws IOException {
PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream(pipeOut);
OutputStream out = pipeOut;
if (teeToOriginalSysOut) {
out = new MultiplexingOutputStream(System.out, pipeOut);
}
PrintStream streamOut = new PrintStream(out);
System.setOut(streamOut);
return pipeIn;
}
/**
* Returns an instance to a runnable running in a separate Thread that tries to match the expected
* output in {@link System#out}.
*
* Ensure that you found the expected String in the input stream given by calling
* {@link info.monitorenter.util.ExceptionUtil.InputStreamTracer#isMatched()}. But take into account that it is time -
* critical (concurrency) if your result was found.
*
* Prefer this instead of {@link #captureSystemOutForDebuggingPurposesOnly(boolean)} as this will
* avoid blocking your application.
*
*
* @return an instance to a runnable running in a separate Thread that tries to match the expected
* output in {@link System#out}.
* @throws java.io.IOException
* if something goes wrong.
*/
public static InputStreamTracer findMatchInSystemOut(final String expectMatch) throws IOException {
InputStream systemout = captureSystemOutForDebuggingPurposesOnly(true);
InputStreamTracer result = new InputStreamTracer(systemout, expectMatch,
Charset.defaultCharset());
Thread traceThread = new Thread(result);
traceThread.setDaemon(true);
traceThread.start();
return result;
}
/**
* Returns an instance to a runnable running in a separate Thread that tries to match the expected
* output in {@link System#err}.
*
* Ensure that you found the expected String in the input stream given by calling
* {@link info.monitorenter.util.ExceptionUtil.InputStreamTracer#isMatched()}. But take into account that it is time -
* critical (concurrency) if your result was found.
*
* Prefer this instead of {@link #captureSystemErrForDebuggingPurposesOnly(boolean)} as this will
* avoid blocking your application.
*
*
* @return an instance to a runnable running in a separate Thread that tries to match the expected
* output in {@link System#out}.
* @throws java.io.IOException
* if something goes wrong.
*/
public static InputStreamTracer findMatchInSystemErr(final String expectMatch) throws IOException {
InputStream systemout = captureSystemErrForDebuggingPurposesOnly(true);
InputStreamTracer result = new InputStreamTracer(systemout, expectMatch,
Charset.defaultCharset());
Thread traceThread = new Thread(result);
traceThread.setDaemon(true);
traceThread.start();
return result;
}
/**
* Helper runnable to find a String within an output stream.
*
* This should be run in a separate thread.
*
* Ensure that you found the expected String in the input stream given by calling
* {@link info.monitorenter.util.ExceptionUtil.InputStreamTracer#isMatched()}. But take into account that it is time -
* critical (concurrency) if your result was found.
*
*
* @author Achim Westermann
* @version $Revision: 1.1 $
*/
public static class InputStreamTracer implements Runnable {
/** The input stream to search for occurrence of word. */
private InputStream m_streamToTrace;
/** The string that is tried to be matched. */
private String m_match;
/** The encoding of the input stream to use for detecting the match. */
private Charset m_charset;
/** If true the output was matched. */
private boolean m_matched;
/**
* Returns true if the expected String was matched in the input stream.
*
* Note that it may be time - critical when to call this and take for granted that the match was
* not made in the input stream (concurrency).
*
*
* @return true if the expected String was matched in the input stream.
*/
public boolean isMatched() {
return this.m_matched;
}
public InputStreamTracer(final InputStream toTrace, final String match, final Charset charset) {
this.m_streamToTrace = toTrace;
this.m_match = match;
this.m_charset = charset;
}
/**
* @see Runnable#run()
*/
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(this.m_streamToTrace,
this.m_charset));
String line;
try {
do {
line = reader.readLine();
if (line != null && line.contains(this.m_match)) {
this.m_matched = true;
break;
}
} while (line != null);
} catch (IOException ioex) {
throw new RuntimeException(ioex);
}
}
}
/**
* Prints out the current Thread stack to the given stream.
*
*
* @see Thread#getStackTrace()
* @param outprint
* the stream to print to (e.g. {@link System#err}
).
*/
public static void dumpThreadStack(PrintStream outprint) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String stackTraceString = StringUtil.arrayToString(stackTrace, "\n");
outprint.println(stackTraceString);
}
/**
* Returns the singleton instance of this class.
*
* This method is useless for now as all methods are static. It may be used in future if VM-global
* configuration will be put to the state of the instance.
*
*
* @return the singleton instance of this class.
*/
public static ExceptionUtil instance() {
if (ExceptionUtil.instance == null) {
ExceptionUtil.instance = new ExceptionUtil();
}
return ExceptionUtil.instance;
}
}