Home Site Map Search Contact Us About Us About Us
Copyright © 2000
Java Service

/**************************************************************************
 *
 * Class   : Daemon.Manager
 *
 * Purpose : Generic NT service that runs MTS/COM+ objects as a service. 
 *
 **************************************************************************
 * Revision History
 *
 *      V1.0.0  03/07/2000  James Bischoff 
 *         Created  
 *
 *************************************************************************/

/**************************************************************************
 * System Classes
 *************************************************************************/
import com.ms.service.*;			// Service
import com.ms.wfc.app.*;			// Registry

/**************************************************************************
 * Custom Classes
 *************************************************************************/
import com.upperbay.Message;	// Custom Galaxy Local Messenger wrapper

/**************************************************************************
 * Class   : Manager
 * Purpose : The main service class.
 *************************************************************************/
public class Manager extends Service
{
	
	/***********************************************************************
	 *	Class Constants
	 **********************************************************************/	
	private final static String gcstrClassName = new String("Daemon.Manager");
	private final static String gcstrRegistryRoot = "Software\\UpperBay\\DaemonManager\\1.0\\";

	/***********************************************************************
	*	Class Globals
	***********************************************************************/			
	private static com.upperbay.Message gobjMessage = null;
	private static int gintTraceLevel = 1;
	private static int gintWaitHintSec = 5;
	private static String[] gastrProgIDs = null;
	private static int gintServiceAction = ServiceAction.STOP;
	private static Monitor gobjMonitor = null;
		
	/***********************************************************************
	 *	Method  : Class Constructor
	 * Purpose : Called when the class is instantiated (service started)
	 **********************************************************************/					
	public Manager (String[] args) throws Throwable {

		final String cstrMethodName = new String("Manager Constructor");
		
		try {			
			gobjMessage = new com.upperbay.Message();
			gobjMessage.SetTraceLevel(gintTraceLevel);
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			LoadRegistryValues();
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Sending updated pending status");
			CheckPoint(1000);
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Sending running status with all controls");
			setRunning(ACCEPT_SHUTDOWN | ACCEPT_PAUSE_CONTINUE | ACCEPT_STOP);						
			
			gobjMonitor = new Monitor();
			gintServiceAction = ServiceAction.START;
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start COM Object Threads");
			for (int i = 0; i < gastrProgIDs.length; i++) {
				gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start [" + gastrProgIDs[i] + "]");													
				com.ms.com.ComLib.startMTAThread(new Thread(new COMThread(this, gobjMonitor, gobjMessage, gastrProgIDs[i])));
			}
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "DaemonManager Service Started");
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
			throw exc;
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}		  		
	}
	
	/***********************************************************************
	 *	Method  : handleStop
	 * Purpose : Handles stop events.  
	 **********************************************************************/				
	protected boolean handleStop () {
		
		final String cstrMethodName = new String("handleStop");		
		
		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");			
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Notify COMThreads");
			gintServiceAction = ServiceAction.STOP;
			gobjMonitor.Unlock();						
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Wait for COMThreads to stop");
			synchronized (this) {              
				wait(gintWaitHintSec * 1000);
			}       			

			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Dying");
			setStopping(gintWaitHintSec * 1000);						
			
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
			return true;
		}
	}

	/***********************************************************************
	 *	Method  : handlePause
	 * Purpose : Handles pause events.  
	 **********************************************************************/				
	protected boolean handlePause () {
		 
		final String cstrMethodName = new String("handlePause");

		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");

			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Pausing");
			setPausing(gintWaitHintSec * 1000);			

			gintServiceAction = ServiceAction.PAUSE;
			gobjMonitor.Unlock();

			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Paused");
			setPaused();
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
			return false;
		}
	}

	/***********************************************************************
	 *	Method  : handleContinue
	 * Purpose : Handles continue events.  
	 **********************************************************************/				
	protected boolean handleContinue () {

		final String cstrMethodName = new String("handleContinue");

		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Continuing");
			setContinuing(gintWaitHintSec * 1000);

			gintServiceAction = ServiceAction.CONTINUE;
			gobjMonitor.Unlock();
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Running");
			setRunning();
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
			return false;
		}
	}

	/***********************************************************************
	 *	Method  : handleShutdown
	 * Purpose : Handles system shutdown events.  
	 **********************************************************************/				
	protected boolean handleShutdown () {

		final String cstrMethodName = new String("handleShutdown");
		
		boolean blnStatus = false;

		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Treat As Stop");
			blnStatus = handleStop();
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
			return blnStatus;
		}
   }

	/***********************************************************************
	 *	Method  : handleInterrogate
	 * Purpose : Handles interrogate events.  
	 **********************************************************************/				
	protected boolean handleInterrogate () {

		final String cstrMethodName = new String("handleInterrogate");

		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Sent Status For Interrogate");
			setServiceStatus(getServiceStatus());
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
			return false;
		}
   }

	/***********************************************************************
	 *	Method  : GetServiceAction
	 * Purpose : Obtain the last service action.
	 **********************************************************************/					
	public static int GetServiceAction() {	
		return gintServiceAction;
	}
	
	/***********************************************************************
	 *	Method  : LoadRegistryValues
	 * Purpose : Load all class cconfiguration values from the registry.  
	 **********************************************************************/				
	private void LoadRegistryValues() throws Throwable {
		
		final String cstrMethodName = new String("LoadRegistryValues");
		
		String strTemp = null;
		com.ms.wfc.app.RegistryKey hKey = null;
		
		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
						
			if ((hKey = Registry.LOCAL_MACHINE.getSubKey(gcstrRegistryRoot)) == null)
				gobjMessage.SendError(gcstrClassName, cstrMethodName, 
					"Unable to open registry key [" + gcstrRegistryRoot + "]");
			else {
		
				if ((strTemp = (String) hKey.getValue("TRACE_LEVEL")) != null)
					gintTraceLevel = Integer.parseInt(strTemp);	
			
				if ((strTemp = (String) hKey.getValue("WAIT_HINT_SECONDS")) != null)
					gintWaitHintSec = Integer.parseInt(strTemp);	
				
				gastrProgIDs = hKey.getSubKeyNames();
				gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Found [" + hKey.getSubKeyCount() + "] Service Objects");
					
				hKey.close();
			}
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString()); 
			throw exc;
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, 
				"TRACE_LEVEL = [" + gintTraceLevel + "]");
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, 
				"WAIT_HINT_SECONDS = [" + gintWaitHintSec + "]");
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}
	}			
}
/**************************************************************************
 *
 * Class   : Daemon.COMThread
 *
 * Purpose : Thread that hosts a single COM object 
 *
 **************************************************************************
 * Revision History
 *
 *      V1.0.0  03/07/2000  James Bischoff 
 *         Created  
 *
 *************************************************************************/

/**************************************************************************
 * System Classes
 *************************************************************************/
import com.ms.com.*;
import com.ms.win32.*;

/**************************************************************************
 * Custom Classes
 *************************************************************************/
import com.upperbay.Message;	// Custom Galaxy Local Messenger wrapper

/**************************************************************************
 * Class   : COMThread
 * Purpose : The main thread class.
 *************************************************************************/
public class COMThread implements Runnable
{

	/***********************************************************************
	 *	Class Constants
	 **********************************************************************/	
	private final static String gcstrClassName = new String("Daemon.COMThread");
	
	/***********************************************************************
	*	Class Globals
	***********************************************************************/			
	private static Message gobjMessage = null;
	private static _Guid IID_IUnknown = new _Guid("{00000000-0000-0000-C000-000000000046}");	
	private String gstrProgID;	
	private Monitor gobjMonitor;
	private Manager gobjManager;

	/***********************************************************************
	*	Native Functions
	***********************************************************************/				
	/** @dll.import("ole32", ole) */ 
	private static native IUnknown CoCreateInstance(_Guid clsid, 
                                                 IUnknown punkOuter, 
                                                 int context, 
                                                 _Guid riid); 
	/** @dll.import("ole32", ole) */ 
	private static native _Guid CLSIDFromString(String str);
  		
	/**************************************************************************
	* Class   : COMThread
	* Purpose : COMThread Constructor.
	 *************************************************************************/
	COMThread(Manager objManager, 
				 Monitor objMonitor, 
				 String strProgID) throws Throwable {
	
		final String cstrMethodName = new String("COMThread Constructor");

		try {				
			gobjMessage = new Message();
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			gstrProgID = strProgID;
			gobjMonitor = objMonitor;
			gobjManager = objManager;
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
			throw exc;
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}		
	}
	
	/**************************************************************************
	* Class   : COMThread
	* Purpose : COMThread Constructor with Message object.
	 *************************************************************************/
	COMThread(Manager objManager, 
				 Monitor objMonitor, 
				 Message objMessage, 
				 String strProgID) throws Throwable {
	
		final String cstrMethodName = new String("COMThread Constructor");

		try {				
			gobjMessage = objMessage;			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			gstrProgID = strProgID;
			gobjMonitor = objMonitor;
			gobjManager = objManager;
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
			throw exc;
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}		
	}

	/***********************************************************************
	 *	Method  : SetUpMessenger
	 * Purpose : Use parent's messenger.
	 **********************************************************************/					
	public void SetUpMessenger(Message objMessage) {
	
		final String cstrMethodName = new String("SetUpMessenger");
		
		try {	
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			gobjMessage = null;
			gobjMessage = objMessage;
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}
	}
	
	/***********************************************************************
	 *	Method  : run
	 * Purpose : Start the forever loop.
	 **********************************************************************/					
	public void run() {
		
		final String cstrMethodName = new String("COMThread run");

		Object objCOMObject = null;
		int intServiceAction;
		boolean blnRun = true;
		
		try {				
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Create COM Object");
			objCOMObject = CreateObject(gstrProgID);
			
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Call COM Object SvcStart");
			Dispatch.callSub(objCOMObject,"SvcStart");
			
			while(blnRun) {
				gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Wait For Service State Change");
				gobjMonitor.Lock();
				
				gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Get New Service State");
				intServiceAction = gobjManager.GetServiceAction();
				
				switch (intServiceAction) {
				case ServiceAction.STOP:
						gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Call COM Object SvcStop");
						Dispatch.callSub(objCOMObject,"SvcStop");	
						
						gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Wait For COM Object Release");
						com.ms.com.ComLib.release(objCOMObject);						
						synchronized (this) {              
							wait(500);
						}       			
						blnRun = false;
						break;
				case ServiceAction.START:
						gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Call COM Object SvcStart");
						Dispatch.callSub(objCOMObject,"SvcStart");
						break;
				case ServiceAction.PAUSE:
						gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Call COM Object SvcPause");
						Dispatch.callSub(objCOMObject,"SvcPause");
						break;
				case ServiceAction.CONTINUE:
						gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Call COM Object SvcContinue");
						Dispatch.callSub(objCOMObject,"SvcContinue");
						break;
				}
			}
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}
	}
	
	/***********************************************************************
	 *	Method  : CreateObject
	 * Purpose : Create a COM object from its Prog ID.
	 **********************************************************************/					
	private Object CreateObject(String strProgID) throws Throwable {

		final String cstrMethodName = new String("CreateObject");
		
		Object objObject = null;
		_Guid guidClassID = null;
		int intContext;

		try {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "Start");
			
			guidClassID = com.ms.win32.Ole32.CLSIDFromProgID(strProgID);
			intContext = ComContext.INPROC_SERVER | com.ms.win32.win.CLSCTX_LOCAL_SERVER;
			
			objObject = com.ms.win32.Ole32.CoCreateInstance(
								guidClassID, 
								null, 
								intContext, 
								IID_IUnknown); 
			
			return objObject;
		}
		catch (Throwable exc) {
			gobjMessage.SendError(gcstrClassName, cstrMethodName, exc.toString());
			throw exc;
		}
		finally {
			gobjMessage.SendDebug(gcstrClassName, cstrMethodName, "End");
		}
  }  		
}

/**************************************************************************
 *
 * Class   : Daemon.Monitor
 *
 * Purpose : Generic object monitor used to stop and start threads.
 *
 **************************************************************************
 * Revision History
 *
 *      V1.0.0  03/07/2000  James Bischoff 
 *         Created  
 *
 *************************************************************************/

public class Monitor
{
	public Monitor() {}

	public synchronized void Unlock() {
		notifyAll();
	}

	public synchronized void  Lock() {
	   try {
			wait(); 
		}
      catch (InterruptedException ex) {
		}
	}
}

/**************************************************************************
 *
 * Class   : Daemon.ServiceAction
 *
 * Purpose : Service action enum constants.
 *
 **************************************************************************
 * Revision History
 *
 *      V1.0.0  03/07/2000  James Bischoff 
 *         Created  
 *
 *************************************************************************/

public class ServiceAction extends com.ms.wfc.core.Enum {

	public static final int STOP = 0;
	public static final int START = 1;
	public static final int PAUSE = 2;
	public static final int CONTINUE = 3;
	
   public static boolean valid(int value) {
      if (value < 0 || value > 3) 
			return false;
		return true;  
   }
}