package com.ttv.acs.jmx;

import java.util.Properties;

import org.apache.log4j.Logger;
import org.jboss.ejb3.annotation.Management;
import org.jboss.ejb3.annotation.Service;

import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;

import com.ttv.acs.util.ADIUtil;
import com.twc.isa.PackageModule.PackageFactory;
import com.twc.isa.PackageModule.PackageFactory_impl;
import com.twc.isa.ServerModule.ServantBase_impl;

/**
 * <b>PackageFactoryerviceMBean<b>. 
 * 
 * @author cbrown@tandbergtv.com
 *
 */
 @Service (objectName="acs:service=PackageFactoryServiceMBean")
 @Management (PackageFactoryService.class)
// @Depends ("jboss.j2ee:service=EARDeployment,url='ACSApplication.ear")
 public class PackageFactoryServiceMBean implements PackageFactoryService {
	 
	 private final Logger log = Logger.getLogger(PackageFactoryServiceMBean.class);
	 
	 private PackageFactoryControl packageFactoryControl = null;
	 
	 // Lifecycle methods
	 
	 public void create() {;}
	 public void destroy() {;}
	 
	 public void 
	 start() throws Exception {
		 log.info("Starting Package Factory.");
		 startPackageFactoryService();
	 }
	 
	 // Lifecycle method
	 public void 
	 stop() {
		 log.info("Stopping PackageFactory.");
		 stopPackageFactoryService();
	 }
	 
	 /**
	  * Unbind the PackageFactory to the name service
	  */
	 public void
	 unbindPackageFactoryService() {
		 
		 if(packageFactoryControl != null) {
			 packageFactoryControl.unbindPackageFactory();
		 }
	 }
	 
	 /**
	  * Rebind the PackageFactory to the name service
	  */
	 public void
	 rebindPackageFactoryService() {
		 
		 if(packageFactoryControl != null) {
			 packageFactoryControl.rebindPackageFactory();
		 }
	 }
	 
	 /**
	  * Start a PackageFactory
	  */
	 private void
	 startPackageFactoryService() {
		 
		 if(packageFactoryControl == null) {
			 packageFactoryControl = new PackageFactoryControl();
			 packageFactoryControl.start();
		 } else {
			 log.debug("PackageFactory already running.");
		 }
	 }
	 
	 /**
	  * Stop the PackageFactory
	  */
	 private void
	 stopPackageFactoryService() {
		 if(packageFactoryControl != null) {
			 packageFactoryControl.stopPackageFactory();
			 log.debug("PackageFactory signalled.");
		 }
	 }
	 
	 
	 
	 /**
	  * 
	  * @author <a href="mailto:cbrown@tandbergtv.com">Corey Brown</a>
	  *
	  */
	 private class PackageFactoryControl extends Thread {
		 
		 private boolean stop = false;
		 
		 private org.omg.CORBA.ORB    orb         = null;
		 private PackageFactory_impl  factoryImpl = null;
		 private PackageFactory       factory     = null;
		 
		 private String[] serverPath = {"Factories", "PackageFactory"};
		 
		 public void
		 stopPackageFactory() {
			 
			 stop = true;
			 
			 try {
				 orb.shutdown(false);
			 } catch(Exception ignore) {;}
		 }
		 
		 public void
		 rebindPackageFactory() {
			 log.debug("orb = " + orb);
			 log.debug("serverPath = " + serverPath);
			 log.debug("factory = " + factory);
			 ServantBase_impl.setFactoryObject(orb, serverPath, factory);
		 }
		 
		 public void
		 unbindPackageFactory() {
			 
			 NamingContextExt ctx = ServantBase_impl.createNamingContext(orb, serverPath, serverPath.length - 1);
			 
			 try {
				 NameComponent[] nameComp = new NameComponent[1]; 
				 nameComp[0] = new NameComponent(serverPath[serverPath.length -1], "Factory");
				 
				 ctx.unbind(nameComp); 
				 log.debug("PackageFactory unbound from NamingContext.");
				 
			 } catch (Exception ex){ 
				 log.error("Failed to locate Name Server", ex); 
			 }
		 }
		 
		 public void
		 run() {
			 
			 while(stop == false) {
				 
				 //
				 // Check to see if the CORBALOC is configured properly before proceeding.
				 //
				 
				 if(ADIUtil.getNameServerAddress() == null || ADIUtil.getNameServerAddress().length() == 0) {
					 log.error("--------------------------------------------------------------------------");
					 log.error("Local NameServer CORBALOC not configured. PackageFactory startup deferred.");
					 log.error("--------------------------------------------------------------------------");
					 
					 try { Thread.sleep(60 * 1000); } catch(Exception ignore) {;}
					 continue;
				 }
			 
				 try {
					 startPackageFactory();
				 } catch(InterruptedException ie) {
					 if(stop == false) {
						 log.error("PackageFactory caught InterruptedException. Restart scheduled.");
					 } else {
						 log.error("PackageFactory Shutdown complete.");
					 }
				 } catch(Exception e) {
					 log.error("PackageFactory caught unexpected exception. Restart scheduled.", e);
				 }
				 
				 try {
					 Thread.sleep(5 * 1000);
				 } catch(Exception ignore) {;}
			 }
			 
			 log.debug("PackageFactory shutdown complete.");
		 }
		 
		 private void
		 startPackageFactory() 
		 throws InterruptedException, Exception {
			 
			 orb = org.omg.CORBA.ORB.init(getOrbMainArgs(), getProperties());
			 
			 //
			 // Get the POA
			 //
			 
			 org.omg.PortableServer.POA rootPOA = org.omg.PortableServer.POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
			 
			 //
			 // Get the POA manager
			 //
			 
			 org.omg.PortableServer.POAManager manager = rootPOA.the_POAManager();
			 manager.activate();
			 
			 //
			 // Create the Factory and activate it.....
			 //
			 
			 factoryImpl = new PackageFactory_impl(orb, "PackageFactory");
			 factory     = factoryImpl._this(orb);
			 
			 factoryImpl.base.setFullPath(serverPath);
			 rebindPackageFactory();
			 
			 //
			 // Activate our object
			 //
			 
			 manager.activate();
			 
			 log.info("Bound PackageFactory to ior:" + factory.toString());
			 
			 //
			 // orb.run never returns. If it does, create a new server and rebind to the NS
			 //
			 
			 orb.run();
		 }
		 
		 private String[] 
		 getOrbMainArgs() {
			 String[] args = new String[2];
			 args[0] = "-ORBInitRef";
			 args[1] = "NameService=" + ADIUtil.getNameServerAddress();
			 return args;
		 }
		 
		private Properties getProperties(){
			Properties p = new Properties();
			p.put("OAPort", ADIUtil.getPackageFactoryPort());
			return p;
		}
	 }
 }