diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index 3590333291..54a65befbf 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -33,7 +33,7 @@ import quickfix.mina.SingleThreadedEventHandlingStrategy; import quickfix.mina.ssl.SSLSupport; import quickfix.test.acceptance.ATServer; -import quickfix.test.util.ReflectionUtil; +import quickfix.test.util.StackTraceUtil; import java.io.File; import java.io.IOException; @@ -527,7 +527,7 @@ private void assertLoggedOn(ClientApplication clientApplication, Session clientS } if ( clientApplication.logonLatch.getCount() > 0 ) { System.err.println("XXX Dumping threads since latch count is not zero..."); - ReflectionUtil.dumpStackTraces(); + StackTraceUtil.dumpStackTraces(); } }); } finally { @@ -544,7 +544,7 @@ private void assertLoggedOut(ClientApplication clientApplication, Session client assertNotNull("no client session", clientSession); final boolean await = clientApplication.logoutLatch.await(20, TimeUnit.SECONDS); if (!await) { - ReflectionUtil.dumpStackTraces(); + StackTraceUtil.dumpStackTraces(); } assertTrue("Expected logout did not occur", await); assertFalse("client session logged in?", clientSession.isLoggedOn()); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java index cbed9a2bac..3a0c0807a1 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java @@ -38,7 +38,7 @@ import quickfix.mina.ProtocolFactory; import quickfix.mina.acceptor.AbstractSocketAcceptor; import quickfix.mina.ssl.SSLSupport; -import quickfix.test.util.ReflectionUtil; +import quickfix.test.util.StackTraceUtil; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; @@ -195,7 +195,7 @@ public void run() { final boolean await = shutdownLatch.await(30, TimeUnit.MINUTES); if (!await) { log.error("ShutdownLatch timed out. Dumping threads..."); - ReflectionUtil.dumpStackTraces(); + StackTraceUtil.dumpStackTraces(log); final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java index ba4e3ac33e..121aa5248c 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java @@ -23,7 +23,7 @@ import org.junit.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import quickfix.test.util.ReflectionUtil; +import quickfix.test.util.StackTraceUtil; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; @@ -77,7 +77,7 @@ public void run(TestResult result, final TestConnection connection) throws Inter CharSequence message = connection.readMessage(clientId, TIMEOUT_IN_MS); if (message == null) { log.info("Dumping threads due to timeout when expecting a message..."); - ReflectionUtil.dumpStackTraces(); + StackTraceUtil.dumpStackTraces(log); final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java index a754d5ad4c..dc13668d91 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java @@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory; import quickfix.mina.ProtocolFactory; import quickfix.mina.message.FIXProtocolCodecFactory; -import quickfix.test.util.ReflectionUtil; +import quickfix.test.util.StackTraceUtil; import java.io.IOException; import java.lang.management.ManagementFactory; @@ -147,7 +147,7 @@ public IoSession getSession() { boolean await = sessionCreatedLatch.await(70, TimeUnit.SECONDS); // 10 seconds more than retry time in ATServer.run() if (!await) { log.error("sessionCreatedLatch timed out. Dumping threads..."); - ReflectionUtil.dumpStackTraces(); + StackTraceUtil.dumpStackTraces(log); final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); diff --git a/quickfixj-core/src/test/java/quickfix/test/util/ReflectionUtil.java b/quickfixj-core/src/test/java/quickfix/test/util/ReflectionUtil.java index e9c57276b5..55dc837504 100644 --- a/quickfixj-core/src/test/java/quickfix/test/util/ReflectionUtil.java +++ b/quickfixj-core/src/test/java/quickfix/test/util/ReflectionUtil.java @@ -1,9 +1,24 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + package quickfix.test.util; -import java.beans.BeanInfo; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -11,7 +26,7 @@ import java.util.Arrays; /** - * Helper class for using reflection. Initially it's focussed on + * Helper class for using reflection. Initially it's focused on * invoking methods, but other tools may be added in the future. */ public class ReflectionUtil { @@ -150,42 +165,4 @@ public static Object callStaticMethod(String methodFqn, Object[] args) return getMatchingMethod(targetClass, methodName, args).invoke(null, args); } - public static void dumpStackTraces() { - try { - Object threadMXBean = ReflectionUtil.callStaticMethod( - "java.lang.management.ManagementFactory.getThreadMXBean", null); - Class threadMXBeanInterface = Class.forName("java.lang.management.ThreadMXBean"); - long[] threadIds = (long[]) ReflectionUtil.callMethod(threadMXBean, - threadMXBeanInterface, "getAllThreadIds", null); - Object[] threadInfos = (Object[]) ReflectionUtil.callMethod(threadMXBean, - threadMXBeanInterface, "getThreadInfo", new Object[] { threadIds, 10 }); - for (Object threadInfo : threadInfos) { - System.out.println((String) ReflectionUtil.callMethod(threadInfo, - "getThreadName", null)); - BeanInfo info = Introspector.getBeanInfo(threadInfo.getClass()); - PropertyDescriptor[] parameters = info.getPropertyDescriptors(); - for (PropertyDescriptor parameter : parameters) { - if (parameter.getReadMethod() != null) { - Object value = parameter.getReadMethod().invoke(threadInfo, - (Object[]) null); - if (value != null && value.getClass().isArray()) { - System.out.println(" " + parameter.getName() + ":"); - for (int a = 0; a < Array.getLength(value); a++) { - System.out.println(" " + Array.get(value, a)); - } - } else { - if (value != null) { - System.out.println(" " + parameter.getName() + ": " + value); - } - } - } - } - System.out.println(); - } - } catch (Exception e) { - e.printStackTrace(); - // ignore, probably wrong JVM version - } - } - } diff --git a/quickfixj-core/src/test/java/quickfix/test/util/StackTraceUtil.java b/quickfixj-core/src/test/java/quickfix/test/util/StackTraceUtil.java new file mode 100644 index 0000000000..598a141151 --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/test/util/StackTraceUtil.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ +package quickfix.test.util; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import org.slf4j.Logger; + +public class StackTraceUtil { + + private static final String DEADLOCKED_THREADS_STRING = "DEADLOCKED threads:" + System.lineSeparator(); + + private StackTraceUtil() { + } + + /** + * Prints stack traces for all threads via System.out. + */ + public static void dumpStackTraces() { + ThreadInfo[] threadInfos = getThreadInfos(); + printThreadInfo(threadInfos, null); + ThreadInfo[] deadlockedThreads = findDeadlockedThreads(null); + printThreadInfo(deadlockedThreads, null); + } + + /** + * Prints stack traces for all threads via passed Logger. + * + * @param log Logger instance to use + */ + public static void dumpStackTraces(Logger log) { + ThreadInfo[] threadInfos = getThreadInfos(); + printThreadInfo(threadInfos, log); + ThreadInfo[] deadlockedThreads = findDeadlockedThreads(log); + printThreadInfo(deadlockedThreads, log); + } + + private static void printThreadInfo(ThreadInfo[] threadInfos, Logger log) { + for (ThreadInfo threadInfo : threadInfos) { + if (log != null) { + log.error(threadInfo.toString()); + } else { + System.out.println(threadInfo.toString()); + } + } + } + + private static ThreadInfo[] getThreadInfos() { + ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + long[] threadIds = bean.getAllThreadIds(); + ThreadInfo[] threadInfos = bean.getThreadInfo(threadIds, 15); + return threadInfos; + } + + private static ThreadInfo[] findDeadlockedThreads(Logger log) { + ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + long[] deadlockedThreadsIDs = bean.findDeadlockedThreads(); + if (deadlockedThreadsIDs != null) { + if (log != null) { + log.error(DEADLOCKED_THREADS_STRING); + } else { + System.out.println(DEADLOCKED_THREADS_STRING); + } + return bean.getThreadInfo(deadlockedThreadsIDs); + } + return new ThreadInfo[]{}; + } + +}