/**
 * Société Générale
 */
package deai.ft.archi.common.debug;

import java.lang.management.ThreadInfo;

import junit.framework.TestCase;

/**
 * @version $Revision: 1.2 $
 * @author <a href="mailto:christophe.lallement@sgcib.com">Christophe Lallement </a>
 * 
 * <!-- $CVSHeader: Common/Server/src/test/deai/ft/archi/common/debug/ThreadWarningSystemTest.java,v 1.2 2006/08/16 12:21:25 clalleme Exp $ -->
 * 
 */
public class ThreadWarningSystemTest
    extends TestCase
{
    /**
     * @version $Revision: 1.0 $
     * @author <a href="mailto:christophe.lallement@sgcib.com">Christophe Lallement </a>
     *
     * <!-- $CVSHeader: $  -->
     *
     */
    private static class DeadlockingThread
        extends Thread
    {
        private final transient Object lock1;
        private final transient Object lock2;

        public DeadlockingThread(String name, Object aLock1, Object aLock2)
        {
            super(name);
            this.lock1 = aLock1;
            this.lock2 = aLock2;
            start();
        }

        public void run()
        {
            while (true)
            {
                f();
            }
        }

        private void f()
        {
            synchronized (lock1)
            {
                g();
            }
        }

        private void g()
        {
            synchronized (lock2)
            {
                // do some work...
                for (int i = 0; i < 1000 * 1000; i++)
                    ;
            }
        }
    }

    private static void createBatchOfThreads()
    {
        for (int i = 0; i < 1000; i++)
        {
            new Thread() {
                {
                    start();
                }

                public void run()
                {
                    try
                    {
                        Thread.sleep(5000);
                    }
                    catch (InterruptedException e)
                    {
                    }
                }
            };
        }
    }

    public void testTooManyThreads()
    {
        ThreadWarningSystem tws = new ThreadWarningSystem(500);
        tws.addListener(new ThreadWarningSystem.Listener() {
            public void deadlockDetected(ThreadInfo thread)
            {
            }

            public void thresholdExceeded(ThreadInfo[] threads)
            {
                System.out.println("Threshold Exceeded");
                System.out.println("threads.length = " + threads.length);

            }
        });
        createBatchOfThreads();
        try
        {
            Thread.sleep(10000);
        }
        catch (InterruptedException exception)
        {
            // TODO Auto-generated catch block
            exception.printStackTrace();
        }
        System.out.println("We should've dipped below the threshold");
        createBatchOfThreads();
    }

    public void testDeadlockedThreads()
    {
        ThreadWarningSystem tws = new ThreadWarningSystem();
        tws.addListener(new ThreadWarningSystem.Listener() {
            public void deadlockDetected(ThreadInfo inf)
            {
                System.out.println("Deadlocked Thread:");
                System.out.println("------------------");
                System.out.println(inf);
                for (StackTraceElement ste : inf.getStackTrace())
                {
                    System.out.println("\t" + ste);
                }
            }

            public void thresholdExceeded(ThreadInfo[] threads)
            {
            }
        });

        // deadlock with three locks
        final Object lock1 = "lock1";
        final Object lock2 = "lock2";
        final Object lock3 = "lock3";

        new DeadlockingThread("t1", lock1, lock2);
        new DeadlockingThread("t2", lock2, lock3);
        new DeadlockingThread("t3", lock3, lock1);

        // deadlock with two locks
        final Object lock4 = "lock4";
        Object lock5 = "lock5";

        new DeadlockingThread("t4", lock4, lock5);
        new DeadlockingThread("t5", lock5, lock4);
    }

    public static void main(String[] args)
    {
        ThreadWarningSystemTest test = new ThreadWarningSystemTest();
        test.testTooManyThreads();
        test.testDeadlockedThreads();
    }
}
