/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.trace;

import java.io.PrintStream;
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 org.apache.log4j.Level;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public final class ThreadInspector {
    
    private static final String FQCN = ThreadInspector.class.getName();
    
    private ThreadInspector() {
        // utility class
    }
    
    public static ThreadInfo currentInfo() {
        long[] cid = new long[]{ Thread.currentThread().getId() };
        return Li.THREAD_INFO.getThreadInfo(cid, true, true)[0];
    }
    
    public static void printLocks(PrintStream stream) {
        ThreadInfo info = currentInfo();
        stream.format("THREAD: %s 0x%08X%n", 
            info.getThreadName(), 
            info.getThreadId()
        );
        for(MonitorInfo item : info.getLockedMonitors()) {
            stream.format(" - MONITOR : %s 0x%08X @ %s%n",
                item.getClassName(),
                item.getIdentityHashCode(),
                item.getLockedStackFrame()
            );
        }
        
        for(LockInfo item : info.getLockedSynchronizers()) {
            stream.format(" - LOCK : %s 0x%08X%n", 
                item.getClassName(), 
                item.getIdentityHashCode()
            );
        }
        
    }
    
    public static void logLocks(Level level, AdvLogger logger) {
        if( !logger.isEnabledFor(level) ) {
            return;
        }
        ThreadInfo info = currentInfo();
        
        if( 0 == info.getLockedMonitors().length && 0 == info.getLockedSynchronizers().length ) {
            return;
        }

        logger.log(FQCN, level, String.format("THREAD: %s 0x%08X", 
            info.getThreadName(), 
            info.getThreadId()
        ),null);
        for(MonitorInfo item : info.getLockedMonitors()) {
            logger.log(FQCN, level, String.format("MONITOR : %s 0x%08X @ %s",
                item.getClassName(),
                item.getIdentityHashCode(),
                item.getLockedStackFrame()
            ),null);
        }
        
        for(LockInfo item : info.getLockedSynchronizers()) {
            logger.log(FQCN, level, String.format("LOCK : %s 0x%08X", 
                item.getClassName(), 
                item.getIdentityHashCode()
            ),null);
        }
        
    }
    
    public static int countLocks() {
        ThreadInfo info = currentInfo();
        return
            info.getLockedMonitors().length +
            info.getLockedSynchronizers().length;
    }
    
    private static final class Li { // NOPMD lazy init idiom 
        
        public static final ThreadMXBean THREAD_INFO = ManagementFactory.getThreadMXBean();
    }
    
}
