Kaynağa Gözat

#37 javadoc: javac, trace

Ranides Atterwim 4 yıl önce
ebeveyn
işleme
0dd3c48fb2

+ 73 - 4
assira.core/src/main/java/net/ranides/assira/annotations/javac/JavaCompilation.java

@@ -23,6 +23,19 @@ import javax.tools.JavaFileObject;
 import javax.tools.ToolProvider;
 import net.ranides.assira.text.Charsets;
 
+/**
+ * This class allows you to invoke javac compiler using quite simple fluent builder pattern.
+ *
+ * It supports invocation of annotation processors
+ *
+ * It works only if application is executed by JDK with "javac" available.
+ *
+ * It could be used for dynamic compilation, altough getting generated bytecode must be done
+ * manually, by inspection files inside returned JavaCompilationResult.
+ *
+ * Please note, that all generated results are stored in memory by default.
+ * JavaCompilation does not create temporary files.
+ */
 public final class JavaCompilation {
 
     private final List<String> options;
@@ -33,30 +46,86 @@ public final class JavaCompilation {
     
     private final List<String> resources = new ArrayList<>();
 
+    /**
+     * Creates new compilation session.
+     * You passes additional options to "javac"
+     *
+     * @param options options
+     */
     public JavaCompilation(String... options) {
         this.options = Arrays.asList(options);
     }
-    
+
+    /**
+     * Registers annotation processor which will be invoked by javac.
+     * It is possible to register many processors.
+     *
+     * @param processor processor
+     * @return this
+     */
     public JavaCompilation processor(Processor processor) {
         processors.add(processor);
         return this;
     }
-    
+
+    /**
+     * Specifies source to compile.
+     * You can specify multiple source files.
+     *
+     * It takes both class name and class source code.
+     * Source code must contain correct package and class declarations,
+     * compatible with passed "fqname".
+     *
+     * @param fqname fqname
+     * @param source source
+     * @return this
+     */
     public JavaCompilation source(String fqname, String source) {
         sources.add(new JavaCompilationFM.CFOString(fqname, source));
         return this;
     }
-    
+
+    /**
+     * Specifies source to compile.
+     * You can specify multiple source files.
+     *
+     * URL must point to file located in directory structure compatible with package declaration.
+     * URL must be accessible and readable by {@link URL#openStream()}.
+     *
+     * @param resource resource
+     * @return this
+     */
     public JavaCompilation source(URL resource) {
         sources.add(new JavaCompilationFM.CFOResource(resource));
         return this;
     }
-    
+
+    /**
+     * Specifies resource file visible to javac.
+     * You can specify multiple resource files.
+     *
+     * Resource name must ne readable by ClassLoader.
+     *
+     * Resources are copied to JavaCompilationResult
+     *
+     * @param resource resource
+     * @return this
+     */
     public JavaCompilation resource(String resource) {
         resources.add(resource);
         return this;
     }
 
+    /**
+     * Executes "javac" and returns compilation result.
+     *
+     * This result contains all compile messages and generated files.
+     * By default, result is stored in memory and does not use temporary files.
+     *
+     * @return result
+     * @throws IOException if some input file can't be accessed because of I/O error
+     * @throws IllegalStateException if "javac" is not present
+     */
     public JavaCompilationResult compile() throws IOException {
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         if (compiler == null) {

+ 43 - 7
assira.core/src/main/java/net/ranides/assira/annotations/javac/JavaCompilationResult.java

@@ -11,8 +11,12 @@ import java.util.List;
 import javax.tools.Diagnostic;
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
 
 /**
+ * This class represents result of javac compilation session.
+ *
+ * It can't be created directly. Please use {@link JavaCompilation}.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
@@ -34,24 +38,56 @@ public class JavaCompilationResult {
         this.files = new ArrayList<>(generatedFiles);
     }
 
+    /**
+     * Returns true if compilation finished without errors.
+     *
+     * @return boolean
+     */
     public boolean success() {
         return success;
     }
 
+    /**
+     * Returns list of all diagnostic messages, including errors.
+     *
+     * @return list
+     */
     public List<Diagnostic<? extends JavaFileObject>> diagnostics() {
         return diagnostics;
     }
-    
+
+    /**
+     * Returns list of all generated files, including resource files.
+     *
+     * @return list
+     */
     public List<JavaFileObject> files() {
         return files;
     }
-    
-    public JavaFileObject file(JavaFileManager.Location location, String packageName, String relativeName) {
-        return file(JavaCompilationFM.getName(location, packageName, relativeName));
+
+
+    /**
+     * Returns generated file inside standard StandardLocation.CLASS_OUTPUT
+     * This version is preferred when loading resource files.
+     *
+     * @param packageName packageName
+     * @param relativeName relativeName
+     * @return JavaFileObject
+     */
+    public JavaFileObject file(String packageName, String relativeName) {
+        return file(JavaCompilationFM.getName(StandardLocation.CLASS_OUTPUT, packageName, relativeName));
     }
-    
-    public JavaFileObject file(JavaFileManager.Location location, String className, JavaFileObject.Kind kind) {
-        return file(JavaCompilationFM.getName(location, className, kind));
+
+    /**
+     * Returns generated file inside standard StandardLocation.CLASS_OUTPUT
+     * This version is preferred when loading class files.
+     *
+     * @param className className
+     * @param kind kind
+     * @return JavaFileObject
+     */
+    public JavaFileObject file(String className, JavaFileObject.Kind kind) {
+        return file(JavaCompilationFM.getName(StandardLocation.CLASS_OUTPUT, className, kind));
     }
 
     private JavaFileObject file(String name) {

+ 2 - 3
assira.core/src/main/java/net/ranides/assira/events/EventDispatcher.java

@@ -8,13 +8,12 @@ package net.ranides.assira.events;
 
 import java.lang.ref.WeakReference;
 import java.util.*;
-import java.util.function.Function;
 import java.util.function.Supplier;
 
 import net.ranides.assira.collection.maps.OpenMap;
 import net.ranides.assira.text.StringTraits;
 import net.ranides.assira.trace.LoggerUtils;
-import net.ranides.assira.trace.ThreadUtils;
+import net.ranides.assira.trace.ThreadDump;
 import org.slf4j.Logger;
 
 /**
@@ -327,7 +326,7 @@ public class EventDispatcher implements EventRouter {
      */
     @Override
     public boolean signalEvent(Event event) {
-		ThreadUtils.dump(LOGGER.isTraceEnabled(), LOGGER::trace);
+		ThreadDump.printIf(LOGGER.isTraceEnabled(), LOGGER::trace);
         dispatchEvent(event);
         return true;
     }

+ 2 - 2
assira.core/src/main/java/net/ranides/assira/events/EventReactor.java

@@ -11,7 +11,7 @@ import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import net.ranides.assira.trace.LoggerUtils;
-import net.ranides.assira.trace.ThreadUtils;
+import net.ranides.assira.trace.ThreadDump;
 import org.slf4j.Logger;
 
 /**
@@ -203,7 +203,7 @@ public class EventReactor extends EventDispatcher {
      */
     @Override
     public boolean signalEvent(Event event) {
-		ThreadUtils.dump(LOGGER.isTraceEnabled(), LOGGER::trace);
+        ThreadDump.printIf(LOGGER.isTraceEnabled(), LOGGER::trace);
         if(0 == maxtime) {
             return events.offer(event);
         }

+ 31 - 3
assira.core/src/main/java/net/ranides/assira/trace/PreparedException.java

@@ -12,6 +12,7 @@ import lombok.Setter;
 import lombok.experimental.Accessors;
 
 import lombok.experimental.UtilityClass;
+import net.ranides.assira.functional.Functions;
 import net.ranides.assira.functional.special.AnyFunction;
 import net.ranides.assira.functional.Compositor;
 import net.ranides.assira.functional.Compositor.CompositorBuilder;
@@ -20,6 +21,7 @@ import net.ranides.assira.functional.FunctionUtils;
 import net.ranides.assira.functional.Functions.Function0;
 import net.ranides.assira.reflection.IClass;
 
+import java.math.BigDecimal;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
@@ -27,9 +29,26 @@ import java.util.Optional;
 import java.util.function.Supplier;
 
 /**
- * ExceptionMessage encapsulates in one object exception class, message and optional arguments.
+ * PreparedException encapsulates in one object exception class, message and optional arguments.
  * It is useful if we want to simplify throw statements inside method bodies.
  *
+ * It uses {@link MessageFormat#format}
+ * Message patterns should use 0-based argument indexes.
+ *
+ * PreparedException must be constructed using builder.
+ *
+ * Functions.Function3<Integer, Integer, String, IllegalArgumentException> error =
+ *      PreparedException
+ *          .runtime(IllegalArgumentException.class)
+ *          .hideHelpers()
+ *          .message("Expected {0} but {1} is passed inside {2}.")
+ *          .hide(BigDecimal.class)
+ *          .params()
+ *             .withParam(Integer.class)
+ *             .withParam(Integer.class)
+ *             .withParam(String.class)
+ *          .function();
+ *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 @UtilityClass public class PreparedException {
@@ -45,12 +64,21 @@ import java.util.function.Supplier;
         return new ExceptionBuilder<>(IClass.typeinfo(type));
     }
 
+    /**
+     * Prepare new checked exception.
+     *
+     * @param type type of exception
+     * @param <E> type of exception
+     * @return ExceptionBuilder
+     */
+    public static <E extends Exception> ExceptionBuilder<E> checked(Class<E> type) {
+        return new ExceptionBuilder<>(IClass.typeinfo(type));
+    }
+
     /**
      * Builder pattern for PreparedException.
      *
-     * @author mwx1031516 [mariusz.czarnowski@huawei.com]
      * @param <T>
-     * @since 2021-05-01
      */
     @Setter
     @Accessors(fluent = true)

+ 51 - 1
assira.core/src/main/java/net/ranides/assira/trace/PreparedMessage.java

@@ -12,6 +12,7 @@ import lombok.Setter;
 import lombok.experimental.Accessors;
 
 import lombok.experimental.UtilityClass;
+import net.ranides.assira.functional.Functions;
 import net.ranides.assira.functional.special.AnyFunction;
 import net.ranides.assira.functional.Compositor;
 import net.ranides.assira.functional.Compositor.CompositorBuilder;
@@ -19,15 +20,31 @@ import net.ranides.assira.functional.Functions.Function0;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.math.BigDecimal;
 import java.text.MessageFormat;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 
 /**
  * PreparedMessage encapsulates in one object log level, log message and optional log arguments.
- * Internally it uses. It is useful if we want to simplify
+ * It is useful if we want to simplify
  * complex logging statements inside method bodies.
  *
+ * It uses {@link MessageFormat#format}
+ * Message patterns should use 0-based argument indexes.
+ *
+ * PreparedMessage must be constructed using builder.
+ *
+ * Functions.Function3<Integer, String, BigDecimal, Boolean> message =
+ *      PreparedMessage
+ *          .forClass("MyClass")
+ *          .warn("Hello {0} world {1} from {2}")
+ *          .params()
+ *             .withParam(Integer.class)
+ *             .withParam(String.class)
+ *             .withNullable((BigDecimal v) -> v.intValue(), BigDecimal.class)
+ *          .function();
+ *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 @UtilityClass public class PreparedMessage {
@@ -96,6 +113,9 @@ import java.util.function.Consumer;
         }
     }
 
+    /**
+     * Builder pattern for PreparedMessage.
+     */
     @Setter
     @Accessors(fluent = true)
     @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@@ -104,22 +124,52 @@ import java.util.function.Consumer;
         private String message;
         private LoggerLevel level;
 
+        /**
+         * Prepare message with {@link LoggerLevel#ERROR}
+         *
+         * @param text text
+         * @return builder
+         */
         public MessageBuilder error(String text) {
             return level(LoggerLevel.ERROR).message(text);
         }
 
+        /**
+         * Prepare message with {@link LoggerLevel#WARN}
+         *
+         * @param text text
+         * @return builder
+         */
         public MessageBuilder warn(String text) {
             return level(LoggerLevel.WARN).message(text);
         }
 
+        /**
+         * Prepare message with {@link LoggerLevel#INFO}
+         *
+         * @param text text
+         * @return builder
+         */
         public MessageBuilder info(String text) {
             return level(LoggerLevel.INFO).message(text);
         }
 
+        /**
+         * Prepare message with {@link LoggerLevel#DEBUG}
+         *
+         * @param text text
+         * @return builder
+         */
         public MessageBuilder debug(String text) {
             return level(LoggerLevel.DEBUG).message(text);
         }
 
+        /**
+         * Prepare message with {@link LoggerLevel#TRACE}
+         *
+         * @param text text
+         * @return builder
+         */
         public MessageBuilder trace(String text) {
             return level(LoggerLevel.TRACE).message(text);
         }

+ 63 - 17
assira.core/src/main/java/net/ranides/assira/trace/ThreadUtils.java

@@ -14,36 +14,77 @@ import java.lang.management.ThreadMXBean;
 import java.util.function.Consumer;
 
 /**
+ * This class is used to print information about all locks and monitors inside thread.
+ *
+ * Because obtaining this information have high cost, we defined few static conditional methods.
+ * You can use them to avoid unnecessary dump creation if, for example, logging is disabled.
+ *
+ * It is built on top of {@link ThreadInfo}
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
-public final class ThreadUtils {
-	
+public class ThreadDump {
+
 	private final ThreadInfo info;
 
-	private ThreadUtils(long cid) {
+	private ThreadDump(long cid) {
         info = Li.THREAD_INFO.getThreadInfo(new long[]{ cid }, true, true)[0];
 	}
-    
-	public static ThreadUtils get() {
-		return get(Thread.currentThread());
+
+	/**
+	 * Creates dump for current thread.
+	 */
+	public ThreadDump() {
+		this(Thread.currentThread().getId());
 	}
-	
-	public static ThreadUtils get(Thread thread) {
-		return new ThreadUtils(thread.getId());
+
+	/**
+	 * Creates dump for specified thread.
+	 *
+	 * @param thread thread
+	 */
+	public ThreadDump(Thread thread) {
+		this(thread.getId());
 	}
-	
-	public static void dump(boolean condition, Consumer<String> out) {
+
+	/**
+	 * Static conditional method: if condition is true,
+	 * it creates dump of current thread and prints it.
+	 *
+	 * @param condition condition
+	 * @param out out
+	 */
+	public static void printIf(boolean condition, Consumer<String> out) {
 		if(condition) {
-			ThreadUtils info = ThreadUtils.get();
-			if(info.locks() > 0) {
-				info.dump(out);
+			ThreadDump dump = new ThreadDump();
+			if(dump.locks() > 0) {
+				dump.print(out);
 			}
 		}
 	}
-	
-	public void dump(Consumer<String> out) {
-		out.accept(String.format("THREAD: %s 0x%08X (monitors=%d, locks=%d)", 
+
+	/**
+	 * Static conditional method: if condition is true,
+	 * it creates dump of specified thread and prints it.
+	 *
+	 * @param condition condition
+	 * @param thread thread
+	 * @param out out
+	 */
+	public static void printIf(boolean condition, Thread thread, Consumer<String> out) {
+		if(condition) {
+			new ThreadDump(thread).print(out);
+		}
+	}
+
+	/**
+	 * Prints information about this dump:
+	 * thread name, id, locked monitors and locked synchronizers
+	 *
+	 * @param out out
+	 */
+	public void print(Consumer<String> out) {
+		out.accept(String.format("THREAD: %s 0x%08X (monitors=%d, locks=%d)",
             info.getThreadName(), 
             info.getThreadId(),
 			info.getLockedMonitors().length,
@@ -64,6 +105,11 @@ public final class ThreadUtils {
         }
 	}
 
+	/**
+	 * Returns number of locked objects (monitors and synchronizers)
+	 *
+	 * @return int
+	 */
     public int locks() {
         return info.getLockedMonitors().length + info.getLockedSynchronizers().length;
     }

+ 115 - 6
assira.core/src/main/java/net/ranides/assira/trace/TraceUtils.java

@@ -6,6 +6,7 @@
  */
 package net.ranides.assira.trace;
 
+import lombok.experimental.UtilityClass;
 import net.ranides.assira.reflection.*;
 import net.ranides.assira.reflection.util.ServiceScanner;
 
@@ -14,13 +15,33 @@ import java.util.Optional;
 import java.util.function.Predicate;
 
 /**
+ * TraceUtils is used for stack trace inspection.
+ * Most importantly, it allows to check stackframe of the caller.
+ * It can be used to search for specific stackframe too.
+ *
+ * This class tries to optimize operations as much as possible.
+ *
+ * Loading only frame of interest if prefferred over obtaining full list of elements.
+ * Altough even returned lists try to load data lazily.
+ *
+ * Please note, that assira library packaged for different JVM version
+ * could use different implementations.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
-public final class TraceUtils {
+@UtilityClass
+public class TraceUtils {
 
+    /**
+     * Index of callee stack frame.
+     * In other words: index of stack frame of current method.
+     */
     public static final int CALLEE = 1;
 
+    /**
+     * Index of caller stack frame.
+     * In other words: index of stack frame of method which invoked current method.
+     */
     public static final int CALLER = 2;
 
     interface IStackWalker {
@@ -52,73 +73,161 @@ public final class TraceUtils {
         .first()
         .orElse(null);
 
-    private TraceUtils() {
-        /* utility class */
-    }
-
+    /**
+     * Returns list with all stack frames.
+     *
+     * @return list
+     */
     public static List<StackTraceElement> getFrames() {
         return WALKER.getFrames();
     }
 
+    /**
+     * Returns list with all classes from stack frames.
+     *
+     * @return list
+     */
     public static List<Class<?>> getTypes() {
         return WALKER.getTypes();
     }
 
+    /**
+     * Returns list with all class names from stack frames.
+     *
+     * @return list
+     */
     public static List<String> getNames() {
         return WALKER.getNames();
     }
 
+    /**
+     * Returns first frame matching predicate
+     *
+     * @param filter filter
+     * @return optional
+     */
     public static Optional<StackTraceElement> getFrame(Predicate<StackTraceElement> filter) {
         return WALKER.getFrame(filter);
     }
 
+    /**
+     * Returns first class matching predicate
+     *
+     * @param filter filter
+     * @return optional
+     */
     public static Optional<Class<?>> getType(Predicate<Class<?>> filter) {
         return WALKER.getType(filter);
     }
 
+    /**
+     * Returns first class name matching predicate
+     *
+     * @param filter filter
+     * @return optional
+     */
     public static Optional<String> getName(Predicate<String> filter) {
         return WALKER.getName(filter);
     }
 
+    /**
+     * Returns frame at specified index.
+     * Most important indexes are CALLEE and CALLER.
+     *
+     * Behaviour is undefined for invalid indexes.
+     *
+     * @param index index
+     * @return frame
+     */
     public static StackTraceElement getFrame(int index) {
         return WALKER.getFrame(index);
     }
 
+    /**
+     * Returns class at specified index.
+     * Most important indexes are CALLEE and CALLER.
+     *
+     * Behaviour is undefined for invalid indexes.
+     *
+     * @param index index
+     * @return class
+     */
     public static Class<?> getType(int index) {
         return WALKER.getType(index);
     }
 
+    /**
+     * Returns class name at specified index.
+     * Most important indexes are CALLEE and CALLER.
+     *
+     * Behaviour is undefined for invalid indexes.
+     *
+     * @param index index
+     * @return class name
+     */
     public static String getName(int index) {
         return WALKER.getName(index);
     }
 
+    /**
+     * Returns frame of callee method.
+     *
+     * @return frame
+     */
     public static StackTraceElement getCalleeFrame() {
         return getFrame(CALLEE);
     }
 
+    /**
+     * Returns class of callee method.
+     *
+     * @return class
+     */
     public static Class<?> getCalleeType() {
         return getType(CALLEE);
     }
 
+    /**
+     * Returns class name of callee method.
+     *
+     * @return class name
+     */
     public static String getCalleeName() {
         return getName(CALLEE);
     }
 
+    /**
+     * Returns frame of caller method.
+     *
+     * @return frame
+     */
     public static StackTraceElement getCallerFrame() {
         return getFrame(CALLER);
     }
 
+    /**
+     * Returns class of caller method.
+     *
+     * @return class
+     */
     public static Class<?> getCallerType() {
         return getType(CALLER);
     }
 
+    /**
+     * Returns class name of caller method.
+     *
+     * @return class name
+     */
     public static String getCallerName() {
         return getName(CALLER);
     }
 
     /**
      * Finds first public StackFrame invoked by JUnit framework.
-     * @return empty if code is not invoked from unit test
+     * Returns none if code is not invoked from unit test
+     *
+     * @return optional
      */
     public static Optional<StackTraceElement> getTestFrame() {
         List<StackTraceElement> frames = TraceUtils.getFrames();

+ 5 - 5
assira.core/src/test/java/net/ranides/assira/annotations/JavaServiceProcessorTest.java

@@ -61,7 +61,7 @@ public class JavaServiceProcessorTest {
 
         assertTrue(re.success());
         
-        JavaFileObject file1 = re.file(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/net.ranides.assira.events.Event");
+        JavaFileObject file1 = re.file("", "META-INF/services/net.ranides.assira.events.Event");
         assertEquals(String.format("net.ranides.at.HelloWorld%n"), IOStrings.read(file1.openReader(false)));
     }
     
@@ -81,10 +81,10 @@ public class JavaServiceProcessorTest {
 
         assertTrue(re.success());
         
-        JavaFileObject file1 = re.file(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/net.ranides.assira.events.Event");
+        JavaFileObject file1 = re.file("", "META-INF/services/net.ranides.assira.events.Event");
         assertEquals(String.format("net.ranides.at.HelloWorld%nnet.ranides.at.ImpS2%n"), IOStrings.read(file1.openReader(false)));
         
-        JavaFileObject file2 = re.file(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/java.nio.charset.spi.CharsetProvider");
+        JavaFileObject file2 = re.file("", "META-INF/services/java.nio.charset.spi.CharsetProvider");
         assertEquals(String.format("net.ranides.at.CPService%n"), IOStrings.read(file2.openReader(false)));
     }
     
@@ -106,10 +106,10 @@ public class JavaServiceProcessorTest {
 
         assertTrue(re.success());
         
-        JavaFileObject file1 = re.file(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/net.ranides.assira.events.Event");
+        JavaFileObject file1 = re.file("", "META-INF/services/net.ranides.assira.events.Event");
         assertEquals(String.format("net.ranides.at.HelloWorld%nnet.ranides.at.ImpS2%n"), IOStrings.read(file1.openReader(false)));
         
-        JavaFileObject file2 = re.file(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/java.nio.charset.spi.CharsetProvider");
+        JavaFileObject file2 = re.file("", "META-INF/services/java.nio.charset.spi.CharsetProvider");
         assertEquals(String.format("net.ranides.at.CPService%nnet.ranides.assira.reflection.util.ServiceScannerTest$SpecialCharset%n"), IOStrings.read(file2.openReader(false)));
     }
     

+ 12 - 12
assira.core/src/test/java/net/ranides/assira/trace/ThreadUtilsTest.java

@@ -23,19 +23,19 @@ import static org.junit.Assert.*;
 	"PMD",
     "NestedSynchronizedStatement"
 })
-public class ThreadUtilsTest {
+public class ThreadDumpTest {
 	
 	List<String> DUMP = Arrays.asList(
 		"THREAD: main 0x00000001 (monitors=3, locks=1)",
-		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock3 * @ *net.ranides.assira.trace.ThreadUtilsTest.itestDump(ThreadUtilsTest.java:*)",
-		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock2 * @ *net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
-		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock1 * @ *net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock3 * @ *net.ranides.assira.trace.ThreadDumpTest.itestDump(ThreadDumpTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock2 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock1 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
 		" - LOCK : java.util.concurrent.locks.ReentrantLock$NonfairSync *",
 		"1 ...",
 		"THREAD: main 0x00000001 (monitors=3, locks=1)",
-		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock3 * @ *net.ranides.assira.trace.ThreadUtilsTest.itestDump(ThreadUtilsTest.java:*)",
-		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock2 * @ *net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
-		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock1 * @ *net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock3 * @ *net.ranides.assira.trace.ThreadDumpTest.itestDump(ThreadDumpTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock2 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock1 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
 		" - LOCK : java.util.concurrent.locks.ReentrantLock$NonfairSync *",
 		"2 ...",
 		"3 ..."
@@ -58,7 +58,7 @@ public class ThreadUtilsTest {
 	
 	private int itestLocks() {
         synchronized(new Lock3()) {
-            return ThreadUtils.get().locks();
+            return new ThreadDump().locks();
         }
     }
 	
@@ -78,18 +78,18 @@ public class ThreadUtilsTest {
 		
 		
 		List<String> out = new ArrayList<>();
-		ThreadUtils.dump(true, out::add);
+		ThreadDump.printIf(true, out::add);
 		assertEquals(Arrays.asList(), out);
     }
     
     private void itestDump() {
         synchronized(new Lock3()) {
 			List<String> out = new ArrayList<>();
-			ThreadUtils.get().dump(out::add);
+			new ThreadDump().print(out::add);
 			out.add("1 ...");
-			ThreadUtils.dump(true, out::add);
+            ThreadDump.printIf(true, out::add);
 			out.add("2 ...");
-			ThreadUtils.dump(false, out::add);
+            ThreadDump.printIf(false, out::add);
 			out.add("3 ...");
 			NewAssert.assertMatch(DUMP, out, (a,b)->Wildcard.match(a,b));
         }