+
+ @Override
+ public boolean printOpenTransactions(PrintStream ps, int minOpenTXs) {
+ if (transactionChainsRegistry.getAllUnique().isEmpty()
+ && readOnlyTransactionsRegistry.getAllUnique().isEmpty()
+ && writeTransactionsRegistry.getAllUnique().isEmpty()
+ && readWriteTransactionsRegistry.getAllUnique().isEmpty()) {
+
+ ps.println(type + ": No open transactions, great!");
+ return false;
+ }
+
+ ps.println(type + ": " + getClass().getSimpleName()
+ + " found some not yet (or never..) closed transaction[chain]s!");
+ ps.println("[NB: If no stack traces are shown below, then "
+ + "enable transaction-debug-context-enabled in mdsaltrace_config.xml]");
+ ps.println();
+ // Flag to track if we really found any real leaks with more (or equal) to minOpenTXs
+ boolean hasFound = print(readOnlyTransactionsRegistry, ps, " ", minOpenTXs);
+ hasFound |= print(writeTransactionsRegistry, ps, " ", minOpenTXs);
+ hasFound |= print(readWriteTransactionsRegistry, ps, " ", minOpenTXs);
+
+ // Now print details for each non-closed TransactionChain
+ // incl. in turn each ones own read/Write[Only]TransactionsRegistry
+ Set<CloseTrackedRegistryReportEntry<TracingTransactionChain>>
+ entries = transactionChainsRegistry.getAllUnique();
+ if (!entries.isEmpty()) {
+ ps.println(" " + transactionChainsRegistry.getAnchor() + " : "
+ + transactionChainsRegistry.getCreateDescription());
+ }
+ for (CloseTrackedRegistryReportEntry<TracingTransactionChain> entry : entries) {
+ ps.println(" " + entry.getNumberAddedNotRemoved() + "x TransactionChains opened but not closed here:");
+ printStackTraceElements(ps, " ", entry.getStackTraceElements());
+ @SuppressWarnings("resource")
+ TracingTransactionChain txChain = (TracingTransactionChain) entry
+ .getExampleCloseTracked().getRealCloseTracked();
+ hasFound |= print(txChain.getReadOnlyTransactionsRegistry(), ps, " ", minOpenTXs);
+ hasFound |= print(txChain.getWriteTransactionsRegistry(), ps, " ", minOpenTXs);
+ hasFound |= print(txChain.getReadWriteTransactionsRegistry(), ps, " ", minOpenTXs);
+ }
+ ps.println();
+
+ return hasFound;
+ }
+
+ private <T extends CloseTracked<T>> boolean print(
+ CloseTrackedRegistry<T> registry, PrintStream ps, String indent, int minOpenTransactions) {
+ Set<CloseTrackedRegistryReportEntry<T>> unsorted = registry.getAllUnique();
+ if (unsorted.size() < minOpenTransactions) {
+ return false;
+ }
+
+ List<CloseTrackedRegistryReportEntry<T>> entries = new ArrayList<>(unsorted);
+ entries.sort((o1, o2) -> Long.compare(o2.getNumberAddedNotRemoved(), o1.getNumberAddedNotRemoved()));
+
+ if (!entries.isEmpty()) {
+ ps.println(indent + registry.getAnchor() + " : " + registry.getCreateDescription());
+ }
+ entries.forEach(entry -> {
+ ps.println(indent + " " + entry.getNumberAddedNotRemoved()
+ + "x transactions opened here, which are not closed:");
+ printStackTraceElements(ps, indent + " ", entry.getStackTraceElements());
+ });
+ if (!entries.isEmpty()) {
+ ps.println();
+ }
+ return true;
+ }
+
+ private void printStackTraceElements(PrintStream ps, String indent, List<StackTraceElement> stackTraceElements) {
+ boolean ellipsis = false;
+ for (final StackTraceElement stackTraceElement : stackTraceElements) {
+ if (isStackTraceElementInteresting(stackTraceElement)) {
+ ps.println(indent + stackTraceElement);
+ ellipsis = false;
+ } else if (!ellipsis) {
+ ps.println(indent + "(...)");
+ ellipsis = true;
+ }
+ }
+ }
+
+ private boolean isStackTraceElementInteresting(StackTraceElement element) {
+ final String className = element.getClassName();
+ return !className.startsWith(getClass().getPackage().getName())
+ && !className.startsWith(CloseTracked.class.getPackage().getName())
+ && !className.startsWith("Proxy")
+ && !className.startsWith("akka")
+ && !className.startsWith("scala")
+ && !className.startsWith("sun.reflect")
+ && !className.startsWith("java.lang.reflect")
+ && !className.startsWith("org.apache.aries.blueprint")
+ && !className.startsWith("org.osgi.util.tracker");
+ }