Bladeren bron

new: Wildcard
new: ThreadInspector

Ranides Atterwim 10 jaren geleden
bovenliggende
commit
7cdd36c461

+ 46 - 0
assira/src/main/java/net/ranides/assira/text/Wildcard.java

@@ -0,0 +1,46 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.text;
+
+import java.io.Serializable;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class Wildcard implements Serializable, Predicate<String> {
+	
+	private static final long serialVersionUID = 2L;	
+	
+	private static final Pattern  REGEX_SPECIAL = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
+
+	private final Pattern re;
+
+	private Wildcard(Pattern re) {
+		this.re = re;
+	}
+	
+	public static Wildcard compile(String pattern) {
+		return compile(pattern,0);
+	}
+	
+	public static Wildcard compile(String pattern, int flags) {
+		return new Wildcard(Pattern.compile(REGEX_SPECIAL.matcher(pattern).replaceAll("\\\\$1").replace("\\*", ".*"), flags));
+	}
+
+	@Override
+	public boolean test(String text) {
+		return re.matcher(text).matches();
+	}
+	
+	public Pattern asPattern() {
+		return re;
+	}
+	
+}

+ 79 - 0
assira/src/main/java/net/ranides/assira/trace/ThreadInspector.java

@@ -0,0 +1,79 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.trace;
+
+import java.lang.management.LockInfo;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.function.Consumer;
+import org.slf4j.Logger;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class ThreadInspector {
+	
+	private final ThreadInfo info;
+
+	private ThreadInspector(long cid) {
+        info = Li.THREAD_INFO.getThreadInfo(new long[]{ cid }, true, true)[0];
+	}
+    
+	public static ThreadInspector get() {
+		return get(Thread.currentThread());
+	}
+	
+	public static ThreadInspector get(Thread thread) {
+		return new ThreadInspector(thread.getId());
+	}
+	
+	public static void trace(Logger logger) {
+		if(logger.isTraceEnabled()) {
+			ThreadInspector info = ThreadInspector.get();
+			if(info.locks() > 0) {
+				info.dump(logger::trace);
+			}
+		}
+	}
+	
+	public void dump(Consumer<String> out) {
+		out.accept(String.format("THREAD: %s 0x%08X (monitors=%d, locks=%d)", 
+            info.getThreadName(), 
+            info.getThreadId(),
+			info.getLockedMonitors().length,
+			info.getLockedSynchronizers().length
+        ));
+        for(MonitorInfo item : info.getLockedMonitors()) {
+            out.accept(String.format(" - MONITOR : %s 0x%08X @ %s",
+                item.getClassName(),
+                item.getIdentityHashCode(),
+                item.getLockedStackFrame()
+            ));
+        }
+        
+        for(LockInfo item : info.getLockedSynchronizers()) {
+            out.accept(String.format(" - LOCK : %s 0x%08X", 
+                item.getClassName(), 
+                item.getIdentityHashCode()
+            ));
+        }
+	}
+
+    public int locks() {
+        return info.getLockedMonitors().length + info.getLockedSynchronizers().length;
+    }
+
+    private static final class Li { // NOPMD lazy init idiom 
+        
+        public static final ThreadMXBean THREAD_INFO = ManagementFactory.getThreadMXBean();
+		
+    }
+    
+}

+ 27 - 0
assira/src/test/java/net/ranides/assira/text/WildcardTest.java

@@ -0,0 +1,27 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.text;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author ranides
+ */
+public class WildcardTest {
+	
+	@Test
+	public void testTest() {
+		assertTrue(Wildcard.compile("a*b").test("artb"));
+		assertTrue(Wildcard.compile("a*b").test("ab"));
+		assertFalse(Wildcard.compile("a*b").test("abc"));
+		assertTrue(Wildcard.compile("a*b*").test("abc"));
+		assertFalse(Wildcard.compile("a*b*").test("acde"));
+	}
+	
+}

+ 89 - 0
assira/src/test/java/net/ranides/assira/trace/ThreadInspectorTest.java

@@ -0,0 +1,89 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.trace;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+import net.ranides.assira.text.Wildcard;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+@SuppressWarnings({
+	"PMD",
+    "NestedSynchronizedStatement"
+})
+public class ThreadInspectorTest {
+	
+	List<String> DUMP = Arrays.asList(
+		"THREAD: main 0x00000001 (monitors=3, locks=1)",
+		" - MONITOR : net.ranides.assira.trace.ThreadInspectorTest$Lock3 * @ net.ranides.assira.trace.ThreadInspectorTest.itestDump(ThreadInspectorTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadInspectorTest$Lock2 * @ net.ranides.assira.trace.ThreadInspectorTest.testDump(ThreadInspectorTest.java:*)",
+		" - MONITOR : net.ranides.assira.trace.ThreadInspectorTest$Lock1 * @ net.ranides.assira.trace.ThreadInspectorTest.testDump(ThreadInspectorTest.java:*)",
+		" - LOCK : java.util.concurrent.locks.ReentrantLock$NonfairSync *"
+	);
+
+	@Test
+    public void testLocks() {
+		ReentrantLock a = new ReentrantLock();
+		a.lock();
+        synchronized(new Lock1()) {
+            synchronized(new Lock2()) {
+                assertEquals(4,itestLocks());
+            }
+        }
+		a.unlock();
+    }
+	
+	private int itestLocks() {
+        synchronized(new Lock3()) {
+            return ThreadInspector.get().locks();
+        }
+    }
+	
+	@Test
+    public void testDump() {
+		ReentrantLock a = new ReentrantLock();
+		a.lock();
+        synchronized(new Lock1()) {
+            synchronized(new Lock2()) {
+                itestDump();
+            }
+        }
+		a.unlock();
+    }
+    
+    private void itestDump() {
+        synchronized(new Lock3()) {
+			List<String> out = new ArrayList<>();
+			ThreadInspector.get().dump(out::add);
+			assertMatch(DUMP, out);
+        }
+    }
+	
+	private static class Lock1 { }
+    private static class Lock2 { }
+    private static class Lock3 { }
+	
+	private static boolean match(String pattern, String value) {
+		return Wildcard.compile(pattern).test(value);
+	}
+	
+	private static void assertMatch(List<String> patterns, List<String> values) {
+		assertEquals("size of list", patterns.size(), values.size());
+		for(int i=0, n=patterns.size(); i<n; i++) {
+			if(!match(patterns.get(i), values.get(i))) {
+				fail("invalid output line " + i);
+			}
+		}
+	}
+}