/* *  This  unpublished work,  first created  in 2010  and updated  * */

/* *  thereafter,  is protected  under the  copyright laws  of the  * */

/* *  United States  and of other countries  throughout the world.  * */

/* *  Use, disassembly,  reproduction, distribution,  etc. without  * */

/* *  the   express  written   consent   of  United   Technologies  * */

/* *  Corporation is prohibited.                                    * */

/* *  Copyright United Technologies Corporation 2010.               * */

/* *  All  rights   reserved.  Information  contained   herein  is  * */

/* *  proprietary and confidential and  improper use or disclosure  * */

/* *  may result in civil and penal sanctions.                      * */



package meta.util;







/**

 * A grab bag of utilities for threads

 */

public class ThreadUtils {



	/**

	 * Report the root thread group

	 * @return  The root group

	 */

	public static ThreadGroup getRootThreadGroup() {

		ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();

		while (root.getParent() != null) {

		    root = root.getParent();

		}

		return root;

	}

	

	/**

	 * Find a thread with the given name

	 * @param threadName  The thread name

	 * @return  The first found thread with this name or null if none found

	 */

	public static Thread findThread(String threadName) {

		ThreadGroup group  = getRootThreadGroup();

		Thread      thread = findThreadInGroup(group, threadName);

		return thread;

	}

	

	/**

	 * Recursively find a thread in a particular thread group with a given name

	 * @param group       The starting thread group

	 * @param threadName  The thread name

	 * @return  The first found thread with this name or null if none found

	 */

	public static Thread findThreadInGroup(ThreadGroup group, String threadName) {

		

    // Get threads in `group'. Note that if we supply

		// a threads array size that's too small, enumerate only fills

		// in up to the array size. The JavaDocs say to check that the

		// number returned is strictly smaller than the array size

		int      thdCnt = group.activeCount();

		int      numAct = 0;

		Thread[] threads = null;

		do {

			threads = new Thread[thdCnt*2];

			numAct = group.enumerate(threads, false);

			if (numAct >= threads.length) {

				thdCnt *= 2;

			}

		} while (numAct > 0  &&  numAct >= threads.length);



    // Check each thread in `group'

		Thread thread = null;

    for (int i = 0; thread == null  &&  i< numAct; i++) {

    	if (threadName.equals(threads[i].getName())) {

    		thread = threads[i];

    	}

    }



    // Recursively check subgroups

		if (thread == null) {

			

	    // Get thread subgroups of `group'. Note that if we supply

			// a groups array size that's too small, enumerate only fills

			// in up to the array size. The JavaDocs say to check that the

			// number returned is strictly smaller than the array size

			int           grpCnt = group.activeGroupCount();

			numAct               = 0;

			ThreadGroup[] groups = null;

			do {

				groups = new ThreadGroup[grpCnt*2];

				numAct = group.enumerate(groups, false);

				if (numAct >= groups.length) {

					grpCnt *= 2;

				}

			} while (numAct > 0  &&  numAct >= groups.length);



	    // Recursively visit each subgroup

	    for (int i=0; i < numAct; i++) {

	    	thread = findThreadInGroup(groups[i], threadName);

	    	if (thread != null)

	    		break;

	    }

		}

		return thread;

	}

	

	/**

	 * Sleep while a thread with a given name is running

	 * @param threadName  The name of the thread

	 */

	public static void sleepIfActive(String threadName) {

		final int  TIME   = 3;

		

		@SuppressWarnings("unused")

		Thread thread;

		while ((thread = findThread(threadName)) != null) {

			ThreadUtils.sleep(TIME*1000);

		}

	}

	

	/**

	 * Sleep and ignore exceptions

	 * @param millis Number of milliseconds to sleep

	 */

	public static void sleep(long millis) {

		try {

			Thread.sleep(millis);

		} catch (InterruptedException e) {

		}

	}

}

