Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
63 changes: 20 additions & 43 deletions quickfixj-core/src/test/java/quickfix/test/util/ReflectionUtil.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
/*******************************************************************************
* 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;
import java.lang.reflect.Method;
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 {
Expand Down Expand Up @@ -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
}
}

}
Original file line number Diff line number Diff line change
@@ -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[]{};
}

}