# @(#) $Id: Container.py,v 1.59 2012/06/21 15:24:08 acaproni Exp $
#
# Copyright (C) 2001
# Associated Universities, Inc. Washington DC, USA.
#
# Produced for the ALMA project
#
# This library is free software; you can redistribute it and/or modify it under
# the terms of the GNU Library General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
# details.
#
# You should have received a copy of the GNU Library General Public License
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 675 Massachusetts Ave, Cambridge, MA 02139, USA.  Correspondence concerning
# ALMA should be addressed as follows:
#
# Internet email: alma-sw-admin@nrao.edu
# "@(#) $Id: Container.py,v 1.59 2012/06/21 15:24:08 acaproni Exp $"
#
# who       when        what
# --------  ----------  ----------------------------------------------
# dfugate   2003/08/04  Created.
#------------------------------------------------------------------------------
'''
This module includes the implementation of a Python Container for the
maci::Container IDL interface.

TODO LIST:
- integrate with the new ACS Error System
- fix the interfaces param to ComponentInfo in activate_component(...)
- a ComponentLifecycleException has been defined in IDL now...
'''

__revision__ = "$Id: Container.py,v 1.59 2012/06/21 15:24:08 acaproni Exp $"

#--REGULAR IMPORTS-------------------------------------------------------------
from time      import sleep
from time      import time
from signal    import signal, SIGINT
from new       import instance
from traceback import print_exc
import sys
from os        import environ
from threading import Event, Thread
#--CORBA STUBS-----------------------------------------------------------------
import PortableServer
import maci
import maci__POA
import Logging
import Logging__POA
from CORBA import FALSE
from maci  import ComponentInfo
from ACS   import OffShoot
import ACS
from ACSErrTypeCommonImpl              import CORBAProblemExImpl, CouldntCreateObjectExImpl
from ACSErrTypeOKImpl import ACSErrOKCompletionImpl
from maciErrTypeImpl                   import CannotActivateComponentExImpl,\
    CannotActivateComponentCompletionImpl
#--ACS Imports-----------------------------------------------------------------
import Acspy.Common.Log as Log
import Acsalarmpy
from Acspy.Common.CDBAccess                 import CDBaccess
from cdbErrType                             import CDBRecordDoesNotExistEx
from Acspy.Clients.BaseClient               import BaseClient, ManagerAsyncConnector
from Acspy.Servants.ContainerServices       import ContainerServices
from Acspy.Servants.ComponentLifecycle      import ComponentLifecycle
from Acspy.Servants.ComponentLifecycle      import ComponentLifecycleException
from Acspy.Servants.ACSComponent            import ACSComponent
from Acspy.Servants.CharacteristicComponent import CharacteristicComponent
from Acspy.Util                             import ACSCorba
from AcsutilPy.FindFile                     import findFile
from Acspy.Util                             import LoggingConfig_xsd
from Acspy.ContainerActivationMap           import ContainerActivationMap
from AcsContainerLogLTS                     import LOG_CompAct_Loading_OK
from AcsContainerLogLTS                     import LOG_CompAct_Instance_OK
from AcsContainerLogLTS                     import LOG_CompAct_Corba_OK
from AcsContainerLogLTS                     import LOG_CompAct_Init_OK
from maciErrTypeImpl                        import ComponentDeactivationFailedExImpl, ComponentDeactivationUncleanExImpl
from ACS                  import CBDescOut
#--GLOBALS---------------------------------------------------------------------
#Manager commands to this container
ACTIVATOR_RELOAD = 0
ACTIVATOR_REBOOT = 1
ACTIVATOR_EXIT   = 2

#The fields of a component dictionary entry
HANDLE      = 'HANDLE'
NAME        = 'NAME'
EXEID       = 'EXEID'
EXE         = 'EXE'
TYPE        = 'TYPE'
POA         = 'POA'
PYCLASS     = 'PYCLASS'
PYREF       = 'PYREF'
CORBAREF    = 'CORBAREF'
COMPONENTINFO     = 'COMPONENTINFO'
POAOFFSHOOT = 'POAOFFSHOOT'
COMPMODULE  = 'COMPMODULE'
#------------------------------------------------------------------------------
class ContainerLogThrottleAlarmer(Log.LogThrottleAlarmerBase):
    def __init__(self, cont):
        '''
        cont Is the container to invoke sendAlarm to send alarms
        '''
        self.container=cont
        
    def sendThrottleAlarm(self, active):
        '''
        See Log.LogThrottleAlarmerBase
        '''
        self.container.sendAlarm("Logging", self.container.name, 10, active)
#------------------------------------------------------------------------------
class AsyncComponentActivator(Thread):
    '''
    This thread activates the component asynchronously by delegating to
    Container#activate_component(...) 
    '''
    def __init__(self,logger, container,h, execution_id, componentName, exe, type, callback, desc):
        '''
        Constructor
        
        Parameters:
        - logger The logger
        - container A reference to the container
        - h is the handle the component will be given
        - name is simply the components name
        - exe is the name of the Python module that has to be imported for the
              components implementation
        - idl_type is the the IR Location for the component
        - callback To callback to notify that the component has been activated 
                   or report an error
        '''
        Thread.__init__(self,name="ComponentAsyncActivator thread for component "+componentName)
        #The logger
        self.logger=logger
        
        # The reference to the container, to call activate_component
        self.container=container
        
        # Store the params to activate the component
        self.h=h
        self.execution_id=execution_id
        self.componentName=componentName
        self.exe=exe
        self.type=type
        self.callback=callback
        self.desc=desc
        
        # It is a daemon so that it does not prevent the application to terminate
        self.daemon=True
    
    def run(self):
        self.logger.logDebug("Activating "+self.componentName+" (type "+self.type+")")
        descOut=CBDescOut(0L,self.desc.id_tag)
        try:
            componentInfo=self.container.activate_component(self.h, self.execution_id, self.componentName, self.exe, self.type)
        except Exception, e:
            e2 = CannotActivateComponentCompletionImpl(exception=e)
            dummyCI=ComponentInfo(type,  #string type;
                                  self.exe,  #string code;
                                  None,  #Object reference;
                                  self.componentName,  #string name;
                                  [],  #HandleSeq clients;
                                  self.container.token.h,  #Handle activator;
                                  self.container.name,   #string container_name;
                                  self.h,  #Handle h;
                                  0,  #AccessDescriptor access;
                                  []  #stringSeq interfaces;
                                  )
            try:
                self.logger.logDelouse("Invoking callback to notify activation of "+self.componentName);
                self.callback.done(dummyCI, e2 , descOut)
                self.logger.logDelouse("Callback invoked for "+self.componentName);
            finally:
                return
        if componentInfo is None:
            self.logger.logDebug("Got a null component for "+self.componentName);
            e2 = CannotActivateComponentCompletionImpl()
            # Error activating component
            dummyCI=ComponentInfo(self.type,  #string type;
                                  self.exe,  #string code;
                                  None,  #Object reference;
                                  self.componentName,  #string name;
                                  [],  #HandleSeq clients;
                                  self.container.token.h,  #Handle activator;
                                  self.container.name,   #string container_name;
                                  self.h,  #Handle h;
                                  0,  #AccessDescriptor access;
                                  []  #stringSeq interfaces;
                                  )
            try:
                self.logger.logDelouse("Invoking callback to notify the failed activation of "+self.componentName);
                self.callback.done(dummyCI, e2, descOut)
                self.logger.logDelouse("Callback invoked for "+self.componentName);
            finally:
                return
        
        retry=0
        while retry<3:
            okCompletion=ACSErrOKCompletionImpl() 
            try:
                self.logger.logDelouse("Calling maci::CBComponentInfo::done with descOut.id_tag = "+str(descOut.id_tag)+" for '"+self.componentName+"'");
                self.callback.done(componentInfo,okCompletion , descOut);
                self.logger.logDelouse("Call to maci::CBComponentInfo::done with descOut.id_tag = "+str(descOut.id_tag)+" for '"+self.componentName+"' completed");
                return
            except Exception, e:
                retry=retry+1
                self.logger.logDelouse("Call to maci::CBComponentInfo::done with descOut.id_tag = "+str(descOut.id_tag)+" for '"+self.componentName+"' failed, retrying...");
                sleep(1)
        self.logger.logError("Call to maci::CBComponentInfo::done with descOut.id_tag = "+str(descOut.id_tag)+" for '"+self.componentName+"' failed, deactivating the component.");
        try:
            self.container.deactivate_component(h)
        except:
            self.logger.logError("Deactivation of component failed descOut.id_tag = "+str(descOut.id_tag)+" for '"+self.componentName+"'");
#------------------------------------------------------------------------------
class Container(BaseClient, maci__POA.Container, Logging__POA.LoggingConfigurable):
    '''
    The Python implementation of a MACI Container.

    This implies it implements both the Container and Client interfaces. It is
    multi-threaded and currently supports components derived from
    ACSComponent, ContainerServices, and the LifeCycle classes.
    '''
    #--------------------------------------------------------------------------
    def __init__ (self, name):
        '''
        Constructor.

        Initializes member variables and CORBA

        Parameters: name is the stringified name of this container.

        Raises: ???
        '''

        print maci.Container.ContainerStatusStartupBeginMsg

        #Member variables
        
        # Set to delay calls to activate_component
        self.ready=Event()
        self.ready.clear() 
        
        self.running = 1  #As long as this is true, container is not shutdown
        self.name = name  #Container Name
        self.canRecover = True  #Whether this container is capable of recovery
        self.components = {}  #A dict where components are referenced by name
        self.compHandles = {}  #A dict where comp names are referenced by handles
        self.shutdownHandles = []
        self.containerPOA = None  #POA to activate this container
        self.componentPOA = None  #POA to create POAs for components
        self.compPolicies = []  #Policy[] for components
        self.offShootPolicies = []  #Policy[] for offshoots
        self.corbaRef = None  #reference to this object's CORBA reference
        self.logger = Log.getLogger(name) # Container's logger
        self.client_type = maci.CONTAINER_TYPE
        self.cdbContainerInfo = {}
        self.autoLoadPackages = []
        #dictionary which maps package names to the number of active components
        #using said package
        self.compModuleCount = {}
        
        # A reference to the thread to autoreconnect
        # @see slef.disconnect()
        self.reconnectionThread = None
        
        # Initialize the alarm factory
        Acsalarmpy.AlarmSystemInterfaceFactory.init(ACSCorba.getManager())
        # The alarm source
        self.alarmSource = None
        
        # The interface to receive notification from the LogThrottle 
        # for sending alarms
        self.clta=ContainerLogThrottleAlarmer(self)

        #Configure CORBA
        print maci.Container.ContainerStatusORBInitBeginMsg
        self.configCORBA()
        print maci.Container.ContainerStatusORBInitEndMsg

        #call superclass constructor
        print maci.Container.ContainerStatusMgrInitBeginMsg
        BaseClient.__init__(self, self.name)
        print maci.Container.ContainerStatusMgrInitEndMsg

        self.logger.logTrace('CORBA configured for Container: ' + self.name)

        self.cdbAccess = CDBaccess()

        self.logger.logTrace('Starting Container: ' + self.name)

        #get info from the CDB
        self.getCDBInfo()
        self.refresh_logging_config()
        self.configureComponentLogger(name)
        
        # The map to serialize activation/deactivation of the same component
        #
        # This map is used to reduce the size of the critical sections
        # so that concurrent activations of components with different 
        # names can proceed in parallel while the activation/deactivation of
        # components with the same name is serialized
        self.activationMap=ContainerActivationMap(self.logger)

        #Run everything
        self.logger.logInfo('Container ' + self.name + ' waiting for requests')
        self.ready.set() 
        print maci.Container.ContainerStatusStartupEndMsg
        sys.stdout.flush()
        
    #--CLIENT IDL--------------------------------------------------------------
    def disconnect(self): # pragma: NO COVER
        '''
        Disconnect from manager.

        oneway void disconnect ();
        
        The container overrides BaseClient.disconnect() because it tries 
        to reconnect to the manager.
        '''
        self.logger.logTrace('Disconnect called for Container: ' + self.name)
        BaseClient.disconnect(self)
        self.logger.logInfo("Logged out from manager")
        
        # Give time to the manger to shutdown or whatever else
        sleep(10)
        
        # Start the thread to autoreconenct to the manager
        try:
            retries=int(self.cdbContainerInfo[0]['ManagerRetry'])
        except:
            # no entry in CDB: default to 10
            retries=10
        if self.reconnectionThread is not None:
            if self.reconnectionThread.isAlive():
                # This method has been before the previous attempt terminated
                # so we ignore the call
                self.logger.logWarning("The thread to aysnchronously reconnect to the Manager is already running")
                return
            
        self.reconnectionThread=ManagerAsyncConnector(client=self,attempts=retries,logger=self.logger)
        self.reconnectionThread.daemon=True
        self.reconnectionThread.start()
        
    #--CLIENT IDL--------------------------------------------------------------
    def taggedmessage (self, message_type, message_id, message): # pragma: NO COVER
        '''
        The Manager and administrators use this method for sending textual messages
        to the client.

        This implementation first attempts to use the ACS logging mechanism to
        display the message and if that fails for any reason, it is only sent
        to standard out.

        Parameters:
        - message_type is an integer defined as a constant in the Client interface
        - message is a string

        Returns: Nothing

        Raises: Nothing

        oneway void message (in short message_type, in string message)
        '''
        if message_id == maci.Client.MSGID_AUTOLOAD_START:
            print maci.Container.ContainerStatusCompAutoloadBeginMsg
        if message_type == maci.Client.MSG_ERROR:
            self.logger.logWarning("Error message from the manager: " + message)
            sys.stdout.flush()

        elif message_type == maci.Client.MSG_INFORMATION:
            self.logger.logInfo("Info message from the manager: " + message)
            sys.stdout.flush()

        else:
            self.logger.logInfo("Message of unknown type from the manager: " + message)
            sys.stdout.flush()
        if message_id == maci.Client.MSGID_AUTOLOAD_END:
            print maci.Container.ContainerStatusCompAutoloadEndMsg
            print maci.Container.ContainerStatusReadyMsg
            sys.stdout.flush()

    #--CONTAINER IDL-----------------------------------------------------------
    def get_handle(self):
        '''
        Returns the handle of this container given by the manager at login.
        
        Parameters: None

        Returns: handle, 0 if not (yet) logged in.
        
        Raises: Nothing

        Handle get_handle();
        '''
        return self.token.h
    #--CONTAINER IDL-----------------------------------------------------------
    def activate_component(self, h, exeid, name, exe, idl_type):
        '''
        Activates a component (or returns a reference to it if already exists).

        Parameters:
        - h is the handle the component will be given
        - name is simply the components name
        - exe is the name of the Python module that has to be imported for the
        components implementation
        - idl_type is the the IR Location for the component

        Raises: CannotActivateComponentExImpl exception when invalid

        Returns: a ComponentInfo structure for manager to use.

        activate_component(in Handle h,in string name,in string exe,in string idl_type)
        '''
        # Delays the activation of components until the container has been initialized 
        self.ready.wait()
        
        # Signal the map that the container is going to start a component
        #
        # If another thread is already activating (or deactivating) a component
        # with this same name then aboutToActivate blocks until it finishes
        self.activationMap.aboutToActivate(name)

        #Check to see if this Component already exists
        comp = self.getExistingComponent(name)
        if comp != None:
            self.activationMap.activated(name)
            return comp[COMPONENTINFO]

        #Create a dictionary record for this component
        self.components[name] = None
        temp = {}
        try:
            temp[HANDLE] = h  #Handle of the component that is being activated
            temp[NAME] = name  #Name-redundant but possibly useful
            temp[EXEID] = exeid  #Execution ID number for the component being activated.
            temp[EXE] = exe  #Python module containing servant implementation
            temp[TYPE] = idl_type  #The type of the component to instantiate
            temp[POA] = self.createPOAForComponent(name)  #POA for this component
            temp[POAOFFSHOOT] = temp[POA].create_POA("OffShootPOA", ACSCorba.getPOAManager(), self.offShootPolicies)
            temp[PYCLASS] = None  #Class object used for this component
            temp[PYREF] = None  #Reference to the python object
            temp[CORBAREF] = None  #Reference to the CORBA object
            temp[COMPONENTINFO] = None  #An IDL struct given to manager
            temp[PYCLASS] = temp[TYPE].split(':')[1].split('/').pop() #get class name

            start = time()
            temp[COMPMODULE] = __import__(temp[EXE], globals(), locals(), [temp[PYCLASS]]) #get module
            interval = time() - start

            log = LOG_CompAct_Loading_OK()
            log.setTimeMillis(int(interval*1000))
            log.setCompName(name)
            log.log()

            try:
                temp[PYCLASS] = temp[EXE].split('.').pop() #get class name
                temp[PYCLASS] = temp[COMPMODULE].__dict__.get(temp[PYCLASS]) #get class
                try: # First try if it's a Simulator
		    temp[PYREF] = temp[PYCLASS].__call__(temp[TYPE]) #create Python object
                except TypeError, e: # When TypeError is thrown, this means that is not a Simulator, let's try like a normal component 
		    temp[PYREF] = temp[PYCLASS].__new__(temp[PYCLASS]) #create Python object
            except Exception, e:
                temp[PYCLASS] = temp[COMPMODULE].__dict__.get(temp[PYCLASS]) #get class
                try: # First try if it's a Simulator
		    temp[PYREF] = temp[PYCLASS].__call__(temp[TYPE]) #create Python object
                except TypeError, e: # When TypeError is thrown, this means that is not a Simulator, let's try like a normal component
		    temp[PYREF] = temp[PYCLASS].__new__(temp[PYCLASS]) #create Python object

        except (TypeError, ImportError, AttributeError), e:
            e2 = CannotActivateComponentExImpl(exception=e)
            if isinstance(e,TypeError):
                e2.setDetailedReason("Verify that the name of implementation class matches the module name *%s*" % temp[EXE].split('.').pop())
            else:
                e2.setDetailedReason("Verify that CDB Code entry and Python install path match for module *%s*" % temp[EXE])

            self.failedActivation(temp)
            e2.log(self.logger)
            self.activationMap.activated(name)
            raise e2
        except Exception, e:
            self.logger.logWarning("Failed to create Python object for: " + name)
            print_exc()
            self.failedActivation(temp)
            self.activationMap.activated(name)
            return None

        #these are some non-standard members needed by the component simulator
        temp[PYREF].ir = temp[TYPE]
        temp[PYREF].library = temp[EXE]

        #instance(...) does not call the constructor!
        try:
            start = time()
            try:
                if temp[PYREF].__init__.func_code.co_argcount == 2: # First try if it's a Simulator
                    temp[PYREF].__init__(temp[TYPE])
                else: # It's not the Simulator
                    temp[PYREF].__init__() 
            except AttributeError: # Could be that func_code is not defined so in this case an exception will be thrown
                temp[PYREF].__init__()
            interval = time() - start

            log = LOG_CompAct_Instance_OK()
            log.setTimeMillis(int(interval*1000))
            log.setCompName(name)
            log.log()
        except:
            print_exc()
            self.logger.logWarning("Standard constructor does not exist for: " + name)

        #Check to see if its derived from ContainerServices
        if isinstance(temp[PYREF], ContainerServices):
            temp[PYREF].setAll(temp[NAME],  #string-name of component
                               self.token,   #Security handle from manager
                               temp[HANDLE],  #Security handle from manager
                               self.activateOffShoot,  #Container's method
                               self.name # Container's Name
                               )

        #Check to see if it's an ACSComponent next
        if isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent):
            temp[PYREF].setName(temp[NAME])

        #DWF-should check to see if it's derived from CharacteristicComponent next!!!
        
        #Check to see if it's derived from ComponentLifeCycle next!!!
        #If it is, we have to mess with the state model and invoke the lifecycle
        #methods accordingly.
        if isinstance(temp[PYREF], ComponentLifecycle):

            start = time()
            try:
                #Have to mess with the state model
                if isinstance(temp[PYREF], ACSComponent):
                    #this assumes the component's constructor will NOT change
                    #the state!
                    temp[PYREF].setComponentState(ACS.COMPSTATE_INITIALIZING)
                #actually initialize the sucker
                temp[PYREF].initialize()
                #if it's an ACSComponent...
                temp_state = temp[PYREF]._get_componentState()
                if (isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent)) and (temp_state==ACS.COMPSTATE_INITIALIZED or temp_state==ACS.COMPSTATE_INITIALIZING):
                    #good...initialize did not fail.
                    temp[PYREF].setComponentState(ACS.COMPSTATE_INITIALIZED)
                elif isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent):
                    #bad...the developer has changed the state from the initialize method.  warn the user but continue
                    self.logger.logWarning("initialize method of " +
                                           "ComponentLifecycle failed for the '" +
                                           temp[NAME] + "' component changed the component's state to something unexpected!")

            except ComponentLifecycleException, e:
                print_exc()
                self.logger.logWarning("initializeComponent method of " +
                                       "ComponentLifecycle failed for the '" +
                                       temp[NAME] + "' component with this message: " +
                                       str(e.args))
                #Have to mess with the state model
                if isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent):
                    temp[PYREF].setComponentState(ACS.COMPSTATE_ERROR)

            except Exception, e:
                print_exc()
                self.logger.logCritical("initializeComponent method of " +
                                        "ComponentLifecycle failed for the '" +
                                        temp[NAME] + "'.\n" + str(e.args) + "\nDestroying!")
                self.failedActivation(temp)
                self.activationMap.activated(name)
                return None

        #Next activate it as a CORBA object.
        try:
            start = time()
            temp[POA].activate_object_with_id(temp[NAME], temp[PYREF])
            temp[CORBAREF] = temp[POA].servant_to_reference(temp[PYREF])
            interval = time() - start

            log = LOG_CompAct_Corba_OK()
            log.setTimeMillis(int(interval*1000))
            log.setCompName(name)
            log.log()
            if(temp[CORBAREF]==None):
                self.logger.logWarning("CORBA object Nil for: " + name)
                self.failedActivation(temp)
                self.activationMap.activated(name)
                return None
            #hack to give the component access to it's own CORBA reference
            temp[PYREF]._corbaRef = temp[CORBAREF]
        except:
            print_exc()
            self.logger.logWarning("Failed to create CORBA object for: " + name)
            self.failedActivation(temp)
            self.activationMap.activated(name)
            return None

        #Create the structure and give it to manager
        #DWF-FIX ME!!! The next line screws everything up for some reason!
        #temp[PYREF]._get_interface()
        #DWF-warning...this assumes temp[TYPE] is the IR ID...
        interfaces = ["IDL:omg.org/CORBA/Object:1.0", temp[TYPE]]
        temp[COMPONENTINFO] = ComponentInfo(temp[TYPE],  #string type;
                                            temp[EXE],  #string code;
                                            temp[CORBAREF],  #Object reference;
                                            name,  #string name;
                                            [],  #HandleSeq clients;
                                            self.token.h,  #Handle activator;
                                            self.name,   #string container_name;
                                            temp[HANDLE],  #Handle h;
                                            0,  #AccessDescriptor access;
                                            interfaces  #stringSeq interfaces;
                                            )
        
        #Make a copy of everything for the container
        self.compHandles[temp[HANDLE]] = temp[NAME]
        self.components[name] = temp
        
        #Check to see if it's derived from ComponentLifeCycle next!!!
        #If it is, we have to mess with the state model and invoke the lifecycle
        #methods accordingly.
        if isinstance(temp[PYREF], ComponentLifecycle):
            start = time()
            try:
                temp[PYREF].execute()

                #Have to mess with the state model
                temp_state = temp[PYREF]._get_componentState()
                if (isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent)) and (temp_state==ACS.COMPSTATE_INITIALIZED or temp_state==ACS.COMPSTATE_OPERATIONAL):
                    temp[PYREF].setComponentState(ACS.COMPSTATE_OPERATIONAL)
                elif isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent):
                    #bad...the developer has changed the state from the initialize method.  warn the user but continue
                    self.logger.logWarning("execute method of " +
                                           "ComponentLifecycle failed for the '" +
                                           temp[NAME] + "' component: changed the component's state to something unexpected!")
            except ComponentLifecycleException, e:
                print_exc()
                self.logger.logWarning("executeComponent method of " +
                                       "ComponentLifecycle failed for the '" +
                                       temp[NAME] + "' component with this message: " +
                                       str(e.args))
                #Have to mess with the state model
                if isinstance(temp[PYREF], ACSComponent) or isinstance(temp[PYREF], CharacteristicComponent):
                    temp[PYREF].setComponentState(ACS.COMPSTATE_ERROR)


            except Exception, e:
                print_exc()
                self.logger.logCritical("executeComponent method of " +
                                        "ComponentLifecycle failed for the '" +
                                        temp[NAME] + "'.\n" + str(e.args) + "\nDestroying!")
                self.failedActivation(temp)
                self.activationMap.activated(name)
                return None

            interval = time() - start

            log = LOG_CompAct_Init_OK()
            log.setTimeMillis(int(interval*1000))
            log.setCompName(name)
            log.log()

        #keep track of how many components are using the package
        if not self.compModuleCount.has_key(temp[COMPMODULE]):
            self.compModuleCount[temp[COMPMODULE]] = 1
        else:
            self.compModuleCount[temp[COMPMODULE]] = self.compModuleCount[temp[COMPMODULE]] + 1
        #configure the components logger from the CDB
        self.configureComponentLogger(name)

        self.logger.logInfo("Activated component: " + name)

        ret=self.components[name][COMPONENTINFO]
        self.activationMap.activated(name)
        return ret

    def activate_component_async(self, h, execution_id, name, exe, type, callback, desc):
        '''
        Activates a component asynchronously.
        
        Parameters:
        - h is the handle the component will be given
        - name is simply the components name
        - exe is the name of the Python module that has to be imported for the
              components implementation
        - idl_type is the the IR Location for the component
        - callback To callback to notify that the component has been activated 
                   or report an error
        '''
        self.logger.logDelouse("Starting async activation of "+name+"(type "+type+")")
        activatorThread=AsyncComponentActivator(
                                                self.logger,
                                                self,
                                                h, 
                                                execution_id, 
                                                name, 
                                                exe, 
                                                type, 
                                                callback, 
                                                desc)
        activatorThread.start()
        
        
    #--------------------------------------------------------------------------
    def failedActivation(self, comp_entry): # pragma: NO COVER
        '''
        Helper method used to destroy various things if the component cannot
        be created.
        
        Mutual exclusion is ensured by self.activationMap that 
        serializes activation/deactivation of components with the same name

        Parameters:
        comp_entry - dictionary describing the component
        '''
        #release the corba reference
        try:
            comp_entry[CORBAREF]._release()
        except:
            pass

        #destroy the Offshoot POA
        try:
            comp_entry[POAOFFSHOOT].destroy(FALSE, FALSE)
        except:
            pass

        #deactivate the component's underlying CORBA object
        try:
            comp_entry[POA].deactivate_object(comp_entry[NAME])
        except:
            pass

        #destroy the component's "personal" POA
        try:
            comp_entry[POA].destroy(FALSE, FALSE)
        except:
            pass

        if self.components.has_key(comp_entry[NAME]):
            del self.components[comp_entry[NAME]]
        if  self.compHandles.has_key(comp_entry[HANDLE]):
            del self.compHandles[comp_entry[HANDLE]]

    #--ACTIVATOR IDL-----------------------------------------------------------
    def deactivate_component(self, handle):
        '''
        Deactivate all components whose handles are given.

        Deactivation is the inverse process of activation: component is detached from
        the POA, and thus made unavailable through CORBA, and its resources are
        freed. If its code-base is no longer used, it is unloaded from memory.

        Parameters: handle, specifies a component handle

        void deactivate_component (in Handle h)
        '''
        deactivationUncleanEx = None
        deactivationFailedEx = None
        compName=None
        try:
            comp_entry = self.components[self.compHandles[handle]]
            compName=comp_entry[NAME]
            self.activationMap.aboutToDeactivate(compName)
        except:
            self.logger.logWarning("No entry for handle: " + str(handle))
            print_exc()
            return
        self.logger.logInfo("Deactivating component: " + comp_entry[NAME])

        #release the corba reference
        comp_entry[CORBAREF]._release()

        #destroy the Offshoot POA
        comp_entry[POAOFFSHOOT].destroy(FALSE, FALSE)

        #deactivate the component's underlying CORBA object
        comp_entry[POA].deactivate_object(comp_entry[NAME])

        #Have to mess with the state model
        if isinstance(comp_entry[PYREF], ACSComponent) or isinstance(comp_entry[PYREF], CharacteristicComponent):
            comp_entry[PYREF].setComponentState(ACS.COMPSTATE_DESTROYING)

        try:  #Invoke the cleanUp method if implemented...
            comp_entry[PYREF].cleanUp()
        except Exception, e:
            self.logger.logAlert("Failed to invoke 'cleanUp' LifeCycle method of: " + comp_entry[NAME])
            print_exc()
            deactivationUncleanEx = ComponentDeactivationUncleanExImpl(exception = e)
            deactivationUncleanEx.setCURL(self.compHandles[handle]);
            deactivationUncleanEx.setReason("Failed to invoke 'cleanUp' LifeCycle method of: " + comp_entry[NAME]);

        #destroy the component's "personal" POA
        comp_entry[POA].destroy(FALSE, FALSE)

        #Have to mess with the state model
        if isinstance(comp_entry[PYREF], ACSComponent) or isinstance(comp_entry[PYREF], CharacteristicComponent):
            comp_entry[PYREF].setComponentState(ACS.COMPSTATE_DEFUNCT)

        #remove one from the container's list of modules
        self.compModuleCount[comp_entry[COMPMODULE]] = self.compModuleCount[comp_entry[COMPMODULE]] - 1

        #if the number of references to this module falls to zero, it should be reloaded
        if self.compModuleCount[comp_entry[COMPMODULE]] == 0:
            try:
                reload(comp_entry[COMPMODULE])
            except:
                self.logger.logWarning("Unable to reload:" + str(comp_entry[COMPMODULE]))
                print_exc()

            #remove it from the container's list
            del self.compModuleCount[comp_entry[COMPMODULE]]

        #Finally delete our references so the garbage collector can be used
        del self.components[self.compHandles[handle]]
        del self.compHandles[handle]
        
        self.activationMap.deactivated(compName)
                
        if deactivationFailedEx is not None:
            raise deactivationFailedEx
        if deactivationUncleanEx is not None:
            raise deactivationUncleanEx
        return
    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def configureComponentLogger(self, name):
        '''
        Configure the logger for the given component name from the values in the CDB.

        Parameters:
        name is the name of the component
        '''
        # Each component has an associated logger instance
        clogger = Log.getLogger(name)

        # Default levels are used for missing values
        defaultlevels = Log.getDefaultLevels()
        
        try:
            #Get the global unnamed logging config to retrieve the maxLogsPerSecond attribute
            logconfigG = self.cdbAccess.getElement("MACI/Containers/"  + self.name + "/LoggingConfig", "LoggingConfig")
            maxLogsPerSec = int(logconfigG[0]['maxLogsPerSecond'])
        except:
            # No value was supplied so default is used
            maxLogsPerSec = -1
        
        try:
            # Process all the named logger configurations
            logconfig = self.cdbAccess.getElement("MACI/Containers/"  + self.name + "/LoggingConfig", "LoggingConfig/log:_")
            for cfg in logconfig:
                if cfg["Name"] == name:
                    try:
                        centrallevel = int(cfg['minLogLevel'])
                    except KeyError:
                        # No value was supplied so default is used
                        centrallevel = defaultlevels.minLogLevel
                    try:
                        locallevel = int(cfg['minLogLevelLocal'])
                    except KeyError:
                        # No value was supplied so default is used
                        locallevel = defaultlevels.minLogLevelLocal
                    
                    clogger.setLevels(Logging.LoggingConfigurable.LogLevels(False, centrallevel, locallevel))
                    clogger.configureLogging(maxLogsPerSec)
                    # There should only be one entry per logger so we are done
                    break
            else:
                # No matching named logger was found so the default values are used
                clogger.setLevels(Logging.LoggingConfigurable.LogLevels(True, 0, 0))
        except Exception:
            # No named loggers were defined so the default values are used
            clogger.setLevels(Logging.LoggingConfigurable.LogLevels(True, 0, 0))

    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def get_default_logLevels(self): # pragma: NO COVER
        '''
        Retrieve the default log levels used in this container.

        Returns: Logging.LoggingConfigurable.LogLevels instance containing default log level values

        Raises: Nothing
        '''
        return Log.getDefaultLevels()

    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def set_default_logLevels(self, levels): # pragma: NO COVER
        '''
        Set the default log level for this container.

        Parameter:
        levels - Logging.LoggingConfigurable.LogLevels instance containing default log level values

        Raises: Nothing
        '''
        Log.setDefaultLevels(levels)

    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def get_logger_names(self): # pragma: NO COVER
        '''
        Retrieve the names of the currently active loggers

        Returns: list of logger name strings
        '''
        return Log.getLoggerNames()

    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def get_logLevels(self, logger_name):
        """
        Retrieve the log levels for a given component.

        Parameter:
        logger_name - name of the component's logger

        Returns: Logging.LoggingConfigurable.LogLevels instance containing the logger's log level values

        Raises: Logging.LoggerDoesNotExistEx if the logger is not active.
        """
        if Log.doesLoggerExist(logger_name):
            return Log.getLogger(logger_name).getLevels()
        else:
            raise Logging.LoggerDoesNotExistEx(logger_name)

    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def set_logLevels(self, logger_name, levels):
        """
        Set the default log level for this component.

        Parameter:
        logger_name - name of the component's logger
        levels - Logging.LoggingConfigurable.LogLevels instance containing default log level values

        Raises: Logging.LoggerDoesNotExistEx if the logger is not active.
        """
        if Log.doesLoggerExist(logger_name):
            Log.getLogger(logger_name).setLevels(levels)
        else:
            raise Logging.LoggerDoesNotExistEx(logger_name)

    #--LOGGINGCONFIGURABLE IDL-----------------------------------------------------------
    def refresh_logging_config(self):
        '''
        Reset the logging configuration to the original CDB settings.

        Returns:  Nothing

        Raises:  Nothing
        '''

        # Default values from the XML Schema
        lcfg = LoggingConfig_xsd.LoggingConfig()
        centrallevel = lcfg.minLogLevel
        locallevel = lcfg.minLogLevelLocal
        cap = lcfg.maxLogQueueSize
        batch = lcfg.dispatchPacketSize
        displevel = lcfg.immediateDispatchLevel
        flush = lcfg.flushPeriodSeconds

        # Retrieve the CDB information
        try:
            logconfig = self.cdbAccess.getElement("MACI/Containers/"  + self.name + "/LoggingConfig", "LoggingConfig")
            try:
                centrallevel = int(logconfig[0]['minLogLevel'])
            except:
                # Default value used because CDB has no setting for this attribute
                pass
            try:
                locallevel = int(logconfig[0]['minLogLevelLocal'])
            except:
                # Default value used because CDB has no setting for this attribute
                pass
            try:
                cap = int(logconfig[0]['maxLogQueueSize'])
            except:
                # Default value used because CDB has no setting for this attribute
                pass
            try:
                batch = int(logconfig[0]['dispatchPacketSize'])
            except:
                # Default value used because CDB has no setting for this attribute
                pass
            try:
                displevel = int(logconfig[0]['immediateDispatchLevel'])
            except:
                # Default value used because CDB has no setting for this attribute
                pass
            try:
                flush = int(logconfig[0]['flushPeriodSeconds'])
            except:
                # Default value used because CDB has no setting for this attribute
                pass

            # Refresh all named loggers from the CDB as well.
            for log in self.get_logger_names():
                self.configureComponentLogger(log)
        except:
            # No logging configuration given in the CDB so defaults are used.
            pass

        # Environment variable takes precedence over the CDB value
        if 'ACS_LOG_CENTRAL' in environ:
            centrallevel = int(environ['ACS_LOG_CENTRAL'])

        if 'ACS_LOG_STDOUT' in environ:
            locallevel = int(environ['ACS_LOG_STDOUT'])

        Log.setDefaultLevels(Logging.LoggingConfigurable.LogLevels(False, centrallevel, locallevel))
        Log.setCapacity(cap)
        Log.setBatchSize(batch)
        Log.setImmediateDispatchLevel(displevel)

        # No need to create another flush thread when one already exists.
        if Log.isFlushRunning():
            Log.setFlushInterval(flush)
        else:
            Log.startPeriodicFlush(flush)

    #--CONTAINER IDL-----------------------------------------------------------
    def shutdown(self, action):
        '''
        Shutdown the Container.

        Normally invoked via CORBA but can also "self terminate" so to speak.

        Parameters:
        - action is an encrypted value that tells the container what action to take

        oneway void shutdown (in unsigned long action)
        '''
        
        if self.reconnectionThread is not None:
            # Signal the thread to terminate
            self.reconnectionThread.terminateThread()
            
        action = (action >> 8) & 0xFF

        if (action == ACTIVATOR_EXIT) or (action == ACTIVATOR_REBOOT) or (action == ACTIVATOR_RELOAD):

            self.logger.logTrace("Shutting down container: " + self.name)

            #Logout from manager
            BaseClient.managerLogout(self)

            if (action == ACTIVATOR_REBOOT) or (action == ACTIVATOR_RELOAD):
                print "Container.shutdown(): Action may not work correctly...-", str(action)
                self.__init__(self.name)
            else:
                # Close the alarm interface factory
                Acsalarmpy.AlarmSystemInterfaceFactory.done()
                #tell the main thread of execution to stop
                self.running = 0
                Log.stopPeriodicFlush()
        else:
            self.logger.logWarning("Unable to process 'shutdown' request at this time: " + str(action))
        

    #----------------------------------------------------------------------------
    def set_component_shutdown_order(self, handles): # pragma: NO COVER
        '''
        Set component shutdown order.

        void set_component_shutdown_order(in HandleSeq h);
        '''
        self.shutdownHandles = handles
    #----------------------------------------------------------------------------
    def get_component_info(self, handles):
        '''
        Returns information about a subset of components that are currently hosted by
        the Container.

        Note:  If the list of handles is empty, information about all components hosted
        by the activator is returned!

        Parmaters: handles is a sequence of integers specifiying component handles.
        Return: Information about the selected components.

        ComponentInfoSeq get_component_info (in HandleSeq h);
        '''
        return_seq=[]

        if (handles == None) or (handles == []):
            for record in self.components.keys():
                return_seq.append(self.components[record][COMPONENTINFO])
            return return_seq

        for handle in handles:
            if self.compHandles.has_key(handle):
                return_seq.append(self.components[self.compHandles[handle]][COMPONENTINFO])
            else:
                self.logger.logWarning("Container has no components with handle:" + str(handle))
        return return_seq
    #--------------------------------------------------------------------------
    def getCDBInfo(self):
        '''
        getCDBInfo is a helper method which is responsible for retrieving info
        from the CDB associated with this container.

        Parameters: None

        Return: None

        Raises: ???
        '''
        #obtain generic container information
        try:
            self.cdbContainerInfo = self.cdbAccess.getElement("MACI/Containers/"  + self.name, "Container")
        except:
            self.logger.logDebug("No container information found in the CDB")
            return

        #get a list of libraries to preload
        # [{'string': 'baci'}]
        temp_list = []
        try:
            temp_list = self.cdbAccess.getElement("MACI/Containers/" + self.name + "/Autoload", "Autoload/cdb:_")
        except:
            self.logger.logDebug("No autoload elemnt found in the CDB")
            return

        #get rid of libraries that can't be found!
        for temp_dict in temp_list:
            package = temp_dict['string']
            package = findFile("bin/" + str(package))[0]
            if package != "":
                #if it really exists add it
                self.autoLoadPackages.append(package)
            else:
                self.logger.logAlert("The '" + str(temp_dict['string']) + "' Python script specified by this container's CDB Autoload element cannot be found!")

        #now try loading the packages!
        for temp_package in self.autoLoadPackages:
            try:
                execfile(temp_package)
            except:
                self.logger.logCritical("There was a problem autoloading the '" + str(temp_package) + "' Python script!")
                print_exc()
                
        try:
            #Get the global unnamed logging config to retrieve the maxLogsPerSecond attribute
            logconfigG = self.cdbAccess.getElement("MACI/Containers/"  + self.name + "/LoggingConfig", "LoggingConfig")
            maxLogsPerSec = int(logconfigG[0]['maxLogsPerSecond'])
        except:
            # No value was supplied so default is used
            maxLogsPerSec = -1
        self.logger.configureLogging(maxLogsPerSec,self.clta)


    #--------------------------------------------------------------------------
    def configCORBA(self): # pragma: NO COVER
        '''
        configCORBA is a helper method responsible for initializing the ORB,
        POAs, etc.

        Parameters: None

        Return: None

        Raises: ???
        '''

        #Create the Container's POA
        try:
            cont_policies = []  #CORBA.PolicyList
            cont_policies.append(ACSCorba.getPOARoot().create_id_assignment_policy(PortableServer.USER_ID))
            cont_policies.append(ACSCorba.getPOARoot().create_lifespan_policy(PortableServer.PERSISTENT))
            cont_policies.append(ACSCorba.getPOARoot().create_request_processing_policy(PortableServer.USE_ACTIVE_OBJECT_MAP_ONLY))
            cont_policies.append(ACSCorba.getPOARoot().create_servant_retention_policy(PortableServer.RETAIN))
            self.containerPOA = ACSCorba.getPOARoot().create_POA("ContainerPOA", ACSCorba.getPOAManager(), cont_policies)
            for policy in cont_policies:
                policy.destroy()
        except Exception, e:
            self.logger.logWarning("Unable to create the container's POA - " + str(e))
            print_exc()
            raise CouldntCreateObjectExImpl()

        #Create the Components POA
        try:
            self.compPolicies.append(ACSCorba.getPOARoot().create_id_assignment_policy(PortableServer.USER_ID))
            self.compPolicies.append(ACSCorba.getPOARoot().create_lifespan_policy(PortableServer.PERSISTENT))
            self.compPolicies.append(ACSCorba.getPOARoot().create_request_processing_policy(PortableServer.USE_SERVANT_MANAGER))
            self.compPolicies.append(ACSCorba.getPOARoot().create_servant_retention_policy(PortableServer.RETAIN))
            self.componentPOA = ACSCorba.getPOARoot().create_POA("ComponentPOA", ACSCorba.getPOAManager(), self.compPolicies)
        except Exception, e:
            self.logger.logWarning("Unable to create the components' POA - " + str(e))
            print_exc()
            raise CouldntCreateObjectExImpl()

        #Create the Offshoot Policies
        try:
            self.offShootPolicies.append(ACSCorba.getPOARoot().create_id_assignment_policy(PortableServer.SYSTEM_ID))
            self.offShootPolicies.append(ACSCorba.getPOARoot().create_lifespan_policy(PortableServer.TRANSIENT))
            self.offShootPolicies.append(ACSCorba.getPOARoot().create_request_processing_policy(PortableServer.USE_ACTIVE_OBJECT_MAP_ONLY))
            self.offShootPolicies.append(ACSCorba.getPOARoot().create_servant_retention_policy(PortableServer.RETAIN))
        except Exception, e:
            self.logger.logWarning("Unable to create the OffShoots' POA - " + str(e))
            print_exc()
            raise CouldntCreateObjectExImpl()

        # register this object with the Container POA and have
        # it come alive
        try:
            self.containerPOA.activate_object_with_id(self.name, self)
        except Exception, e:
            self.logger.logWarning("Unable to activate this container as a CORBA servant - " +
                                   str(e))
            print_exc()
            raise CORBAProblemExImpl()
    #--------------------------------------------------------------------------
    def getManagerHost(self): # pragma: NO COVER
        '''
        Helper function returns a string consisting of managers host.

        Return: hostname where manager is running.

        Raises: ???
        '''
        temp = ACSCorba.getManagerCorbaloc()
        # words end up as ['corbaloc', '', 'condor', 'xxxx/Manager']
        words = temp.split(':')
        return words[2]
    #--------------------------------------------------------------------------
    def run(self): # pragma: NO COVER
        '''
        Runs the container until a sig-int is caught.

        This is a blocking call!

        Raises: ???
        '''
        signal(SIGINT, self.handler)
        while(self.running):
            sleep(1)
        self.destroyCORBA()
        print "Goodbye"
        sys.stdout.flush()
    #--------------------------------------------------------------------------
    def handler(self, signum, frame): # pragma: NO COVER
        '''
        Catches SIGINTs and shuts down the container.

        Used only by the run method.

        Parameters: signum is the signal being caught
        frame is the execution frame.

        Return: None

        Raises: ???
        '''
        #to make pychecker happy
        signum = None

        #to make pychecker happy
        frame = None

        print "-->Signal Interrupt caught...shutting everything down cleanly"
        
        if (self.reconnectionThread is not None) and self.reconnectionThread.isAlive():
            self.reconnectionThread.terminateThread()

        #Destroy what manager has told us about first
        for h in self.shutdownHandles:
            self.deactivate_component(h)
        self.shutdownHandles = []
        #Double-check to see if there's any extra components manager did not
        #let us know about!
        for h in self.compHandles.keys():
            self.deactivate_component(h)
        self.shutdown(ACTIVATOR_EXIT<<8)
    #--------------------------------------------------------------------------
    def createPOAForComponent(self, comp_name): # pragma: NO COVER
        '''
        Creates a new POA that is responsible for exactly one component and
        the new POA is created as a child of the ComponentPOA.

        Parameters: comp_name is the components stringified name.

        Return: a new POA.

        Raises: ???
        '''
        return self.componentPOA.create_POA("ComponentPOA" + comp_name, ACSCorba.getPOAManager(), self.compPolicies)
    #--------------------------------------------------------------------------
    def destroyCORBA(self): # pragma: NO COVER
        '''
        Helper function designed to shutdown/destroy all CORBA associated with
        this specific container.

        Raises: ???
        '''
        for policy in self.compPolicies:
            policy.destroy()

        for policy in self.offShootPolicies:
            policy.destroy()

        try:
            self.corbaRef._release()
            self.componentPOA.destroy(FALSE, FALSE)
            self.containerPOA.destroy(FALSE, FALSE)
        except Exception, e:
            self.logger.logWarning("Failed to destroy the container's CORBA object: " + str(e))
            print_exc()
    #--------------------------------------------------------------------------
    def getExistingComponent(self, name): # pragma: NO COVER
        '''
        Searches to see if the component "name" has already been activated by
        this container.

        Parameters: name of the component.

        Return: component record if found; else None.
        '''
        if self.components.has_key(name):
            return self.components[name]
        return None
    #--------------------------------------------------------------------------
    #--CONTAINER SERVICES METHODS----------------------------------------------
    #--------------------------------------------------------------------------
    def activateOffShoot(self, comp_name, os_corba_ref):
        '''
        Activates an OffShoot derived object.

        Actually this will work on any CORBA object because its Python.

        Parameters:
        - comp_name is the components name.
        - os_corba_ref is a reference to the Python object to become a CORBA object.

        Return: a reference to the CORBA object that almost definitely needs to
        be narrowed to the correct type.  If anything goes wrong though, returns
        None.

        Raises: ???
        '''
        comp = self.getExistingComponent(comp_name)
        if comp == None:
            self.logger.logWarning("Component '" + comp_name + "' does not exist")
            return None
        elif not isinstance(os_corba_ref, OffShoot):
            #Not an offshoot but try activating it anyways!
            self.logger.logWarning("Not an OffShoot '" + str(os_corba_ref) + "'")

        try:
            comp[POAOFFSHOOT].activate_object(os_corba_ref)
            return comp[POAOFFSHOOT].servant_to_reference(os_corba_ref)
        except Exception, e:
            self.logger.logWarning("Unable to activate '" + str(os_corba_ref) + "'")
            print_exc()
            return None
    #--------------------------------------------------------------------------
    def getMyCorbaRef(self):
        '''
        Overriden from BaseClient
        '''

        #if this object has not already been activated as a CORBA object...
        if self.corbaRef == None:
            try:
                #...activate it using the default POA
                self.corbaRef = self.containerPOA.servant_to_reference(self)
            except Exception, e:
                self.logger.logWarning("Cannot activate self as a CORBA servant")
                print_exc()
                raise CORBAProblemExImpl()

            #sanity check
            if self.corbaRef == None:
                # without a client, we can't go on
                self.logger.logWarning("Cannot activate self as a CORBA servant")
                raise CORBAProblemExImpl()

            #OK to return at this point
            return self.corbaRef

        #otherwise return the saved reference
        else: # pragma: NO COVER
            return self.corbaRef
    #--------------------------------------------------------------------------
    def getCode(self): # pragma: NO COVER
        '''
        Overriden from BaseClient
        '''
        if self.canRecover:
            return "AR"
        else:
            return "A"
    #--------------------------------------------------------------------------
    def sendAlarm(self, family, member, code, active):
        '''
        Raise or clear an alarm with the passed triplet

        family: FaultFamily
        member: FaultMember
        code: FaultCode
        active: if True raise the alarm otherwise clear the alarm
        '''
        if self.alarmSource==None:
            self.alarmSource = Acsalarmpy.AlarmSystemInterfaceFactory.createSource("ALARM_SYSTEM_SOURCES")

        # Create a test fault
        fltstate = Acsalarmpy.AlarmSystemInterfaceFactory.createFaultState(family,member, code)
        if active:
            fltstate.descriptor = Acsalarmpy.FaultState.ACTIVE_STRING
        else:
            fltstate.descriptor = Acsalarmpy.FaultState.TERMINATE_STRING
        fltstate.userTimestamp = Acsalarmpy.Timestamp.Timestamp()
        
        # The heart of the test
        self.alarmSource.push(fltstate)
    #--------------------------------------------------------------------------
    def setToken(self,newToken):
        '''
        Override BaseClient.setToken to handle the case of
        a failure connecting to the manager
        '''
        if newToken is not None:
            BaseClient.setToken(self, newToken)
            self.logger.logInfo("Successfully reconnected to the Manager")
        else:
            # Terminate the container
            self.logger.logError("Manager not available: bailing out!")
            self.shutdown(ACTIVATOR_EXIT<<8)
            
    #-- ACSLoggingStatistics Interface ------------------------------------------------------
    def get_statistics_logger_configuration(self):
        '''
        Gets the names and status of all statistics modules of all loggers, to allow configuring them individually.
        If the logger statistics module has never been configured yet, then it will provide "Undefined"
        as elementName 
        '''
        # exit structure
        statsInfoList = []
        
        # Retrieve logger names
        for loggerName in self.get_logger_names():            
            # Retrieve logger
            retrievedLogger = Log.getLogger(loggerName)
            
            # Store relevant information
            statsInfoList.append ( Logging.ACSLogStatistics.LogStatsInformation(
                                                            retrievedLogger.stats.getStatisticsIdentification(),
                                                            loggerName,
                                                            retrievedLogger.stats.getDisableStatistics(),
                                                            retrievedLogger.stats.getStatisticsCalculationPeriod(),
                                                            retrievedLogger.stats.getStatisticsGranularity() ) )
        # Return info
        return statsInfoList
        
    
    def get_statistics_logger_configuration_byname(self, logger_name):
        '''
        Gets the names and status of statistics module of requested logger.
        If the logger statistics module has never been configured yet, then it will provide "Undefined"
        as elementName 
        Throws LoggerDoesNotExistEx if a the logger is not found
        '''
        
        # Verification if logger does exist
        if Log.doesLoggerExist(logger_name) is False:
            # Raise exception
            inexistantLoggerEx = Logging.LoggerDoesNotExistEx(logger_name)
            raise inexistantLoggerEx
        
        # Retrieve logger
        retrievedLogger = Log.getLogger(logger_name)
        
        # Store relevant information
        statsInfo = Logging.ACSLogStatistics.LogStatsInformation(
                                            retrievedLogger.stats.getStatisticsIdentification(),
                                            logger_name,
                                            retrievedLogger.stats.getDisableStatistics(),
                                            retrievedLogger.stats.getStatisticsCalculationPeriod(),
                                            retrievedLogger.stats.getStatisticsGranularity() )
        # Return info
        return statsInfo
    
    def set_statistics_logger_configuration_byname(self, logger_name, statsInformation):
        '''
        Sets logger statistics configuration for a particular named logger.
        Throws LoggerDoesNotExistEx if a the logger is not found 
        '''
        
        # Verification if logger does exist
        if Log.doesLoggerExist(logger_name) is False:
            # Raise exception
            inexistantLoggerEx = Logging.LoggerDoesNotExistEx(logger_name)
            raise inexistantLoggerEx
        
        # Retrieve logger
        retrievedLogger = Log.getLogger(logger_name)
                  
        # Configure the logger
        retrievedLogger.stats.configureStatistics(statsInformation.statsId,
                statsInformation.statsStatus,
                statsInformation.statsPeriodConfiguration,
                statsInformation.statsGranularityConfiguration)
            
        return
