def process(self, _edObject=None):
     EDPluginControl.process(self)
     self.DEBUG("EDPluginControlIndexingIndicatorsv1_1.process")
     edActionCluster = EDActionCluster()
     edActionCluster.addAction(self.edPluginIndexingLabelit)
     edActionCluster.addAction(self.edPluginControlIndicators)
     self.edPluginIndexingLabelit.connectSUCCESS(self.doSuccessLabelitIndexing)
     self.edPluginIndexingLabelit.connectFAILURE(self.doFailureLabelitIndexing)
     self.edPluginControlIndicators.connectSUCCESS(self.doSuccessControlIndicators)
     self.edPluginControlIndicators.connectFAILURE(self.doFailureControlIndicators)
     edActionCluster.execute()
     edActionCluster.synchronize()
 def process(self, _edObject=None):
     EDPluginControl.process(self)
     self.DEBUG("EDPluginControlIndexingIndicatorsv10.process")
     edActionCluster = EDActionCluster()
     edActionCluster.addAction(self.__edPluginMOSFLMIndexing)
     edActionCluster.addAction(self.__edPluginControlIndicators)
     self.__edPluginMOSFLMIndexing.connectSUCCESS(self.doSuccessMOSFLMIndexing)
     self.__edPluginMOSFLMIndexing.connectFAILURE(self.doFailureMOSFLMIndexing)
     self.__edPluginControlIndicators.connectSUCCESS(self.doSuccessControlIndicators)
     self.__edPluginControlIndicators.connectFAILURE(self.doFailureControlIndicators)
     edActionCluster.execute()
     edActionCluster.synchronize()
Exemple #3
0
 def process(self, _edObject=None):
     EDPluginControl.process(self)
     self.DEBUG("EDPluginControlIndexingIndicatorsv10.process")
     edActionCluster = EDActionCluster()
     edActionCluster.addAction(self.__edPluginMOSFLMIndexing)
     edActionCluster.addAction(self.__edPluginControlIndicators)
     self.__edPluginMOSFLMIndexing.connectSUCCESS(
         self.doSuccessMOSFLMIndexing)
     self.__edPluginMOSFLMIndexing.connectFAILURE(
         self.doFailureMOSFLMIndexing)
     self.__edPluginControlIndicators.connectSUCCESS(
         self.doSuccessControlIndicators)
     self.__edPluginControlIndicators.connectFAILURE(
         self.doFailureControlIndicators)
     edActionCluster.execute()
     edActionCluster.synchronize()
Exemple #4
0
 def process(self, _edObject=None):
     EDPluginControl.process(self)
     self.DEBUG("EDPluginControlIndexingIndicatorsv1_1.process")
     edActionCluster = EDActionCluster()
     if self.bDoLabelitIndexing:
         edActionCluster.addAction(self.edPluginIndexingLabelit)
         self.edPluginIndexingLabelit.connectSUCCESS(
             self.doSuccessLabelitIndexing)
         self.edPluginIndexingLabelit.connectFAILURE(
             self.doFailureLabelitIndexing)
     edActionCluster.addAction(self.edPluginControlIndicators)
     self.edPluginControlIndicators.connectSUCCESS(
         self.doSuccessControlIndicators)
     self.edPluginControlIndicators.connectFAILURE(
         self.doFailureControlIndicators)
     edActionCluster.execute()
     edActionCluster.synchronize()
Exemple #5
0
class EDPluginControl(EDPlugin):
    """
    An EDPluginControl is a plugin that is responsible for a EDPluginExec or EDPluginControl plugin execution:
    It is responsible for:
        - The EDPluginExec or EDPluginControl Workflow
        - The data propagation between the EDPluginExec
        - The translation between generic and specific data models via EDHandler classes
        - The error/warning propagation
        - The executive summaries propagation
        - Execution of an "action cluster": a set of plugins can be added to a so called "action cluster"
          with the method "addPluginToActionCluster". All the plugins in the cluster can then be executed
          simultaneously with the method "executeActionCluster" and synchronized with the method
          "synchronizeActionCluster". The number of threads used by the action cluster is by default the
          number of processors available on the computer, but this value can be changed either by
          calling the method "setClusterSize" or by using the configuration parameter "clusterSize".
    """

    def __init__ (self):
        """
        """
        EDPlugin.__init__(self)
        self.__strPluginToBeControlledName = None
        self.__dictControlledPlugins = {}
        self.__edActionCluster = None
        self.__iClusterSize = None
        self.__listOfLoadedPlugins = []


    def configure(self):
        """
        Gets the EDPluginControl parameters from the configuration file and stores them in class member attributes.
        """
        EDPlugin.configure(self)
        EDVerbose.DEBUG("EDPluginControl.configure")
        strControlledPlugins = self.config.get("controlledPlugins", None)
        if (strControlledPlugins != None):
            pyListControlledPlugins = strControlledPlugins.split(",")
            for strControlledPlugin in pyListControlledPlugins:
                strControlledPluginName = self.getStringConfigurationParameterValue(strControlledPlugin)
                if strControlledPluginName != None:
                    self.setControlledPluginName(strControlledPlugin, strControlledPluginName)
                    EDVerbose.DEBUG("EDPluginControl.configure: setting controlled plugin %s to specific plugin %s" % (strControlledPlugin, strControlledPluginName))
        clusterSize = self.config.get("clusterSize", None)
        if (clusterSize != None):
            self.__iClusterSize = int(strClusterSize)
            EDVerbose.DEBUG("EDPluginControl.configure: setting cluster size to %d" % self.__iClusterSize)


    def emptyListOfLoadedPlugin(self):
        """
        Reset all plugins kept in memory
        """
        self.__listOfLoadedPlugins = []
        gc.collect()

    def getListOfLoadedPlugin(self):
        """
        """
        return self.__listOfLoadedPlugins


    def removeLoadedPlugin(self, _plugin):
        """
        Remove a plugin from the list of loaded plugins to free some memory
        @param _plugin: plugin to remove
        @type _plugin: instance of the class EDPlugin
        """
        if _plugin in self.__listOfLoadedPlugins:
            with self.locked():
                self.__listOfLoadedPlugins.remove(_plugin)
            self.DEBUG("EDPluginControl.removeLoadedPlugin: Caught, removed %s unreferenced objects. currently there are %i plugins" % (gc.get_count(), len(self.__listOfLoadedPlugins)))
            gc.collect()
        else:
            self.DEBUG("EDPluginControl.removeLoadedPlugin: Missed. currently there are %i plugins" % len(self.__listOfLoadedPlugins))


    def synchronizePlugins(self):
        EDVerbose.DEBUG("EDPluginControl.synchronizePlugins")
        bSynchronized = False
        while not bSynchronized:
            listPluginOrig = self.__listOfLoadedPlugins[:]
            for edPlugin in listPluginOrig:
                if edPlugin.isStarted() and (not edPlugin.isEnded()):
                    edPlugin.synchronize()
                elif not edPlugin.isStarted():
                    time.sleep(0.01) #release GIL to let plugin start 
                    continue
            time.sleep(0.01)
            with self.locked():
                bSynchronized = (self.__listOfLoadedPlugins == listPluginOrig)


    def loadPlugins(self):
        """
        This method loads and returns a list of references to the plugins to be controlled.
        
        The name of the plugin to be controlled is set set before calling this method using the 
        "setControlledPluginName" method. 
        
        The base name of the plugin to be controlled is used as the working
        directory name of the plugin in question. The name of the plugin is used as 
        base name. 
        """
        EDVerbose.DEBUG("EDPluginControl.loadPlugins")
        listKeys = self.__dictControlledPlugins.keys()
        listLoadedPlugins = []
        for strKey in listKeys:
            strPluginName = self.__dictControlledPlugins[strKey]
            edPlugin = EDFactoryPluginStatic.loadPlugin(strPluginName)
            edPlugin.setBaseDirectory(self.getWorkingDirectory())
            edPlugin.setBaseName(strPluginName)
            listLoadedPlugins.append(edPlugin)
        return listLoadedPlugins


    def loadPlugin(self, _strPluginToBeControlledName=None, _strBaseName=None):
        """
        This method loads and returns a reference to the plugin to be controlled.
        
        The name of the plugin to be controlled can either be passed as an
        argument, or bet set before calling this method using the 
        "setPluginToBeControlledName". 
        
        The base name of the plugin to be controlled is used as the working
        directory name of the plugin in question. If no argument is supplied
        the name of the plugin is used as base name. In the case of creation of
        several plugins to be launched simultaneously, the base name should be
        different for each plugin and hence must be provided explicitly.
        """
        EDVerbose.DEBUG("EDPluginControl.loadPlugin")
        if (_strPluginToBeControlledName is None):
            strPluginName = self.__strPluginToBeControlledName
        else:
            strPluginName = _strPluginToBeControlledName
        edPlugin = EDFactoryPluginStatic.loadPlugin(strPluginName)
        if (edPlugin is None):
            strErrorMessage = "EDPluginControl.loadPlugin : Cannot load plugin %s" % strPluginName
            EDVerbose.error(strErrorMessage)
            self.addErrorMessage(strErrorMessage)
            raise RuntimeError, strErrorMessage
        else:
            self.__listOfLoadedPlugins.append(edPlugin)
        edPlugin.setBaseDirectory(self.getWorkingDirectory())
        if (_strBaseName is None):
            # Check if base name exists. OBS! Not thread safe so please set explicitly
            # _strBaseName for multi-threaded code
            strRenamedPlugin = self.compactPluginName(strPluginName)
            strNewWorkingDirectory = os.path.join(self.getWorkingDirectory(), strRenamedPlugin)
            if (os.path.exists(strNewWorkingDirectory)):
                edPlugin.setBaseName(edPlugin.createBaseName())
            else:
                edPlugin.setBaseName(strRenamedPlugin)
        else:
            edPlugin.setBaseName(_strBaseName)
        return edPlugin


    def setControlledPluginName(self, _strControlledPluginName, _strControlledPluginValue):
        """
        Adds a name-value pair to the dictionary to map the general to the specific name of a plugin to be controlled
        """
        self.__dictControlledPlugins[_strControlledPluginName] = _strControlledPluginValue


    def getControlledPluginName(self, _strControlledPluginName):
        """
        Returns the name of the plugin to be controlled.
        """
        strPluginname = None
        if self.__dictControlledPlugins.has_key(_strControlledPluginName):
            strPluginname = self.__dictControlledPlugins[_strControlledPluginName]
        return strPluginname


    def addWarningMessages(self, _listWarningMessages):
        """
        Adds a list of warning messages in the existing list of warning messages
        """
        EDVerbose.DEBUG("EDPluginControl.addWarningMessages")
        for strWarningMessage in _listWarningMessages:
            self.addWarningMessage(strWarningMessage)


    def addErrorMessages(self, _listErrorMessages):
        """
        Adds a list of error messages in the existing list of error messages
        """
        EDVerbose.DEBUG("EDPluginControl.addErrorMessages")
        for strErrorMessage in _listErrorMessages:
            self.addErrorMessage(strErrorMessage)


    def retrieveFailureMessages(self, _edPlugin, _strMethodCaller):
        """
        Propagates failure messages from a plugin including unexpected errors
        Should be called in the plugin control method invoked when a plugin exec fails (doActionFailure<>)
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveFailureMessages")
        self.retrieveWarningMessages(_edPlugin)
        self.retrieveErrorMessages(_edPlugin, _strMethodCaller, True)


    def retrieveSuccessMessages(self, _edPlugin, _strMethodCaller):
        """
        Propagates success messages from a plugin
        Error messages are retrieved because a plugin could end successfully with errors (depending on the use case)
        In this case, there is no check for unexpected errors
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveSuccessMessages")
        self.retrieveWarningMessages(_edPlugin)
        self.retrieveErrorMessages(_edPlugin, _strMethodCaller, False)


    def retrieveErrorMessages(self, _edPlugin, _strMethodCaller, _bFailure):
        """
        Propagates error messages from a plugin
        if _bFailure is true, this method has been called from retrieveFailureMessages
        in this case, checks for potential unexpected errors coming from the EDPluginExec
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveErrorMessages")
        listErrorMessages = _edPlugin.getListOfErrorMessages()
        if (len(listErrorMessages) == 0) and (_bFailure is True):
            strErrorMessage = "%s : Adding Unexpected error" % _strMethodCaller
            EDVerbose.DEBUG(strErrorMessage)
            listErrorMessages.append(strErrorMessage)
        self.addErrorMessages(listErrorMessages)


    def retrieveWarningMessages(self, _edPlugin):
        """
        Propagates warning messages from a plugin
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveWarningMessages")
        self.addWarningMessages(_edPlugin.getListOfWarningMessages())


    def appendExecutiveSummary(self, _edPlugin, _strPrefix="", _bAddSeparator=True):
        """
        Appends the executive summary from a plugin.
        """
        EDVerbose.DEBUG("EDPluginControl.appendExecutiveSummary")
        if (_bAddSeparator):
            self.addExecutiveSummarySeparator()
        if _edPlugin:
            for strLine in _edPlugin.getListExecutiveSummaryLines():
                if strLine == self.getExecutiveSummarySeparator() and _strPrefix != "":
                    strLine = strLine[ :-len(_strPrefix) ]
            self.addExecutiveSummaryLine(_strPrefix + strLine)


    def addErrorWarningMessagesToExecutiveSummary(self, _strErrorMessage="Error messages:", _strWarningMessage="Warning messages:"):
        """
        Adds error and warning messages (if any) in the executive summary
        """
        if len(self.getListOfErrorMessages()) != 0:
            self.addExecutiveSummarySeparator()
            self.addExecutiveSummaryLine(_strErrorMessage)
            for strErrorMessage in self.getListOfErrorMessages():
                self.addExecutiveSummaryLine(strErrorMessage)
            self.addExecutiveSummarySeparator()
        if len(self.getListOfWarningMessages()) != 0:
            self.addExecutiveSummarySeparator()
            self.addExecutiveSummaryLine(_strWarningMessage)
            for warningMessage in self.getListOfWarningMessages():
                self.addExecutiveSummaryLine(warningMessage)
            self.addExecutiveSummarySeparator()


    def addPluginToActionCluster(self, _edPlugin):
        """
        This method adds a plugin instance to an action cluster.
        """
        if self.__edActionCluster == None:
            self.__edActionCluster = EDActionCluster()
        self.__edActionCluster.addAction(_edPlugin)
        self.__listOfLoadedPlugins.append(_edPlugin)


    def executeActionCluster(self):
        """
        This method executes the action cluster. The action cluster is executed
        asynchronoulsy.
        """
        if self.__iClusterSize != None:
            self.__edActionCluster.setClusterSize(self.__iClusterSize)
        self.__edActionCluster.execute()


    def synchronizeActionCluster(self):
        """
        This method synchronises the action cluster with the control plugin thread.
        """
        self.__edActionCluster.synchronize()


    def setClusterSize(self, _iClusterSize):
        """
        This method sets the size of the action cluster, i.e. the number of threads
        that will be executed simultaneously. 
        """
        self.__iClusterSize = _iClusterSize


    def executePlugin(self, _edPlugin, _bSynchronous=False):
        """
        This method is used to start executable plugins in pipeline asynchronously.
        """
        if _bSynchronous:
            self.executePluginSynchronous(_edPlugin)
        else:
            _edPlugin.execute()


    def executePluginSynchronous(self, _edPlugin):
        """
        This method is used to start executable plugins in pipeline synchronously.
        """
        _edControlSlotSUCCESS = EDSlot()
        _edControlSlotFAILURE = EDSlot()

        map(_edControlSlotSUCCESS.connect, _edPlugin.getSlotSUCCESS().getListMethod())
        map(_edControlSlotFAILURE.connect, _edPlugin.getSlotFAILURE().getListMethod())

        _edPlugin.getSlotSUCCESS().emptyListMethod()
        _edPlugin.getSlotFAILURE().emptyListMethod()

        _edPlugin.executeSynchronous()

        if (not _edPlugin.isFailure()):
            EDVerbose.DEBUG("EDControlPlugin.executeSynchronous slotSUCCESS")
            # Check that something doesn't go wrong in the success method!
            try:
                _edControlSlotSUCCESS.call(_edPlugin)

            except Exception:
                EDVerbose.DEBUG("EDControlPlugin.executeSynchronous: ERROR in slotSUCCESS!")
                EDVerbose.writeErrorTrace()
                _edPlugin.setFailure()

        if (_edPlugin.isFailure()):
            EDVerbose.DEBUG("EDControlPlugin.executeSynchronous slotFAILURE")
            # Check that something doesn't go wrong in the success method!
            try:
                _edControlSlotFAILURE.call(_edPlugin)

            except Exception:
                EDVerbose.DEBUG("EDControlPlugin.executeSynchronous: ERROR in slotFAILURE!")
                EDVerbose.writeErrorTrace()
Exemple #6
0
class EDPluginControl(EDPlugin):
    """
    An EDPluginControl is a plugin that is responsible for a EDPluginExec or EDPluginControl plugin execution:
    It is responsible for:
        - The EDPluginExec or EDPluginControl Workflow
        - The data propagation between the EDPluginExec
        - The translation between generic and specific data models via EDHandler classes
        - The error/warning propagation
        - The executive summaries propagation
        - Execution of an "action cluster": a set of plugins can be added to a so called "action cluster"
          with the method "addPluginToActionCluster". All the plugins in the cluster can then be executed
          simultaneously with the method "executeActionCluster" and synchronized with the method
          "synchronizeActionCluster". The number of threads used by the action cluster is by default the
          number of processors available on the computer, but this value can be changed either by
          calling the method "setClusterSize" or by using the configuration parameter "clusterSize".
    """
    def __init__(self):
        """
        """
        EDPlugin.__init__(self)
        self.__strPluginToBeControlledName = None
        self.__dictControlledPlugins = {}
        self.__edActionCluster = None
        self.__iClusterSize = None
        self.__listOfLoadedPlugins = []

    def configure(self):
        """
        Gets the EDPluginControl parameters from the configuration file and stores them in class member attributes.
        """
        EDPlugin.configure(self)
        EDVerbose.DEBUG("EDPluginControl.configure")
        strControlledPlugins = self.config.get("controlledPlugins", None)
        if (strControlledPlugins != None):
            pyListControlledPlugins = strControlledPlugins.split(",")
            for strControlledPlugin in pyListControlledPlugins:
                strControlledPluginName = self.getStringConfigurationParameterValue(
                    strControlledPlugin)
                if strControlledPluginName != None:
                    self.setControlledPluginName(strControlledPlugin,
                                                 strControlledPluginName)
                    EDVerbose.DEBUG(
                        "EDPluginControl.configure: setting controlled plugin %s to specific plugin %s"
                        % (strControlledPlugin, strControlledPluginName))
        clusterSize = self.config.get("clusterSize", None)
        if (clusterSize != None):
            self.__iClusterSize = int(strClusterSize)
            EDVerbose.DEBUG(
                "EDPluginControl.configure: setting cluster size to %d" %
                self.__iClusterSize)

    def emptyListOfLoadedPlugin(self):
        """
        Reset all plugins kept in memory
        """
        self.__listOfLoadedPlugins = []
        gc.collect()

    def getListOfLoadedPlugin(self):
        """
        """
        return self.__listOfLoadedPlugins

    def removeLoadedPlugin(self, _plugin):
        """
        Remove a plugin from the list of loaded plugins to free some memory
        @param _plugin: plugin to remove
        @type _plugin: instance of the class EDPlugin
        """
        if _plugin in self.__listOfLoadedPlugins:
            with self.locked():
                self.__listOfLoadedPlugins.remove(_plugin)
            self.DEBUG(
                "EDPluginControl.removeLoadedPlugin: Caught, removed %s unreferenced objects. currently there are %i plugins"
                % (gc.get_count(), len(self.__listOfLoadedPlugins)))
            gc.collect()
        else:
            self.DEBUG(
                "EDPluginControl.removeLoadedPlugin: Missed. currently there are %i plugins"
                % len(self.__listOfLoadedPlugins))

    def synchronizePlugins(self):
        EDVerbose.DEBUG("EDPluginControl.synchronizePlugins")
        bSynchronized = False
        while not bSynchronized:
            listPluginOrig = self.__listOfLoadedPlugins[:]
            for edPlugin in listPluginOrig:
                if edPlugin.isStarted() and (not edPlugin.isEnded()):
                    edPlugin.synchronize()
                elif not edPlugin.isStarted():
                    time.sleep(0.01)  #release GIL to let plugin start
                    continue
            time.sleep(0.01)
            with self.locked():
                bSynchronized = (self.__listOfLoadedPlugins == listPluginOrig)

    def loadPlugins(self):
        """
        This method loads and returns a list of references to the plugins to be controlled.
        
        The name of the plugin to be controlled is set set before calling this method using the 
        "setControlledPluginName" method. 
        
        The base name of the plugin to be controlled is used as the working
        directory name of the plugin in question. The name of the plugin is used as 
        base name. 
        """
        EDVerbose.DEBUG("EDPluginControl.loadPlugins")
        listKeys = self.__dictControlledPlugins.keys()
        listLoadedPlugins = []
        for strKey in listKeys:
            strPluginName = self.__dictControlledPlugins[strKey]
            edPlugin = EDFactoryPluginStatic.loadPlugin(strPluginName)
            edPlugin.setBaseDirectory(self.getWorkingDirectory())
            edPlugin.setBaseName(strPluginName)
            listLoadedPlugins.append(edPlugin)
        return listLoadedPlugins

    def loadPlugin(self, _strPluginToBeControlledName=None, _strBaseName=None):
        """
        This method loads and returns a reference to the plugin to be controlled.
        
        The name of the plugin to be controlled can either be passed as an
        argument, or bet set before calling this method using the 
        "setPluginToBeControlledName". 
        
        The base name of the plugin to be controlled is used as the working
        directory name of the plugin in question. If no argument is supplied
        the name of the plugin is used as base name. In the case of creation of
        several plugins to be launched simultaneously, the base name should be
        different for each plugin and hence must be provided explicitly.
        """
        EDVerbose.DEBUG("EDPluginControl.loadPlugin")
        if (_strPluginToBeControlledName is None):
            strPluginName = self.__strPluginToBeControlledName
        else:
            strPluginName = _strPluginToBeControlledName
        edPlugin = EDFactoryPluginStatic.loadPlugin(strPluginName)
        if (edPlugin is None):
            strErrorMessage = "EDPluginControl.loadPlugin : Cannot load plugin %s" % strPluginName
            EDVerbose.error(strErrorMessage)
            self.addErrorMessage(strErrorMessage)
            raise RuntimeError, strErrorMessage
        else:
            self.__listOfLoadedPlugins.append(edPlugin)
        edPlugin.setBaseDirectory(self.getWorkingDirectory())
        if (_strBaseName is None):
            # Check if base name exists. OBS! Not thread safe so please set explicitly
            # _strBaseName for multi-threaded code
            strRenamedPlugin = self.compactPluginName(strPluginName)
            strNewWorkingDirectory = os.path.join(self.getWorkingDirectory(),
                                                  strRenamedPlugin)
            if (os.path.exists(strNewWorkingDirectory)):
                edPlugin.setBaseName(edPlugin.createBaseName())
            else:
                edPlugin.setBaseName(strRenamedPlugin)
        else:
            edPlugin.setBaseName(_strBaseName)
        return edPlugin

    def setControlledPluginName(self, _strControlledPluginName,
                                _strControlledPluginValue):
        """
        Adds a name-value pair to the dictionary to map the general to the specific name of a plugin to be controlled
        """
        self.__dictControlledPlugins[
            _strControlledPluginName] = _strControlledPluginValue

    def getControlledPluginName(self, _strControlledPluginName):
        """
        Returns the name of the plugin to be controlled.
        """
        strPluginname = None
        if self.__dictControlledPlugins.has_key(_strControlledPluginName):
            strPluginname = self.__dictControlledPlugins[
                _strControlledPluginName]
        return strPluginname

    def addWarningMessages(self, _listWarningMessages):
        """
        Adds a list of warning messages in the existing list of warning messages
        """
        EDVerbose.DEBUG("EDPluginControl.addWarningMessages")
        for strWarningMessage in _listWarningMessages:
            self.addWarningMessage(strWarningMessage)

    def addErrorMessages(self, _listErrorMessages):
        """
        Adds a list of error messages in the existing list of error messages
        """
        EDVerbose.DEBUG("EDPluginControl.addErrorMessages")
        for strErrorMessage in _listErrorMessages:
            self.addErrorMessage(strErrorMessage)

    def retrieveFailureMessages(self, _edPlugin, _strMethodCaller):
        """
        Propagates failure messages from a plugin including unexpected errors
        Should be called in the plugin control method invoked when a plugin exec fails (doActionFailure<>)
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveFailureMessages")
        self.retrieveWarningMessages(_edPlugin)
        self.retrieveErrorMessages(_edPlugin, _strMethodCaller, True)

    def retrieveSuccessMessages(self, _edPlugin, _strMethodCaller):
        """
        Propagates success messages from a plugin
        Error messages are retrieved because a plugin could end successfully with errors (depending on the use case)
        In this case, there is no check for unexpected errors
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveSuccessMessages")
        self.retrieveWarningMessages(_edPlugin)
        self.retrieveErrorMessages(_edPlugin, _strMethodCaller, False)

    def retrieveErrorMessages(self, _edPlugin, _strMethodCaller, _bFailure):
        """
        Propagates error messages from a plugin
        if _bFailure is true, this method has been called from retrieveFailureMessages
        in this case, checks for potential unexpected errors coming from the EDPluginExec
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveErrorMessages")
        listErrorMessages = _edPlugin.getListOfErrorMessages()
        if (len(listErrorMessages) == 0) and (_bFailure is True):
            strErrorMessage = "%s : Adding Unexpected error" % _strMethodCaller
            EDVerbose.DEBUG(strErrorMessage)
            listErrorMessages.append(strErrorMessage)
        self.addErrorMessages(listErrorMessages)

    def retrieveWarningMessages(self, _edPlugin):
        """
        Propagates warning messages from a plugin
        """
        EDVerbose.DEBUG("EDPluginControl.retrieveWarningMessages")
        self.addWarningMessages(_edPlugin.getListOfWarningMessages())

    def appendExecutiveSummary(self,
                               _edPlugin,
                               _strPrefix="",
                               _bAddSeparator=True):
        """
        Appends the executive summary from a plugin.
        """
        EDVerbose.DEBUG("EDPluginControl.appendExecutiveSummary")
        if (_bAddSeparator):
            self.addExecutiveSummarySeparator()
        if _edPlugin:
            for strLine in _edPlugin.getListExecutiveSummaryLines():
                if strLine == self.getExecutiveSummarySeparator(
                ) and _strPrefix != "":
                    strLine = strLine[:-len(_strPrefix)]
            self.addExecutiveSummaryLine(_strPrefix + strLine)

    def addErrorWarningMessagesToExecutiveSummary(
            self,
            _strErrorMessage="Error messages:",
            _strWarningMessage="Warning messages:"):
        """
        Adds error and warning messages (if any) in the executive summary
        """
        if len(self.getListOfErrorMessages()) != 0:
            self.addExecutiveSummarySeparator()
            self.addExecutiveSummaryLine(_strErrorMessage)
            for strErrorMessage in self.getListOfErrorMessages():
                self.addExecutiveSummaryLine(strErrorMessage)
            self.addExecutiveSummarySeparator()
        if len(self.getListOfWarningMessages()) != 0:
            self.addExecutiveSummarySeparator()
            self.addExecutiveSummaryLine(_strWarningMessage)
            for warningMessage in self.getListOfWarningMessages():
                self.addExecutiveSummaryLine(warningMessage)
            self.addExecutiveSummarySeparator()

    def addPluginToActionCluster(self, _edPlugin):
        """
        This method adds a plugin instance to an action cluster.
        """
        if self.__edActionCluster == None:
            self.__edActionCluster = EDActionCluster()
        self.__edActionCluster.addAction(_edPlugin)
        self.__listOfLoadedPlugins.append(_edPlugin)

    def executeActionCluster(self):
        """
        This method executes the action cluster. The action cluster is executed
        asynchronoulsy.
        """
        if self.__iClusterSize != None:
            self.__edActionCluster.setClusterSize(self.__iClusterSize)
        self.__edActionCluster.execute()

    def synchronizeActionCluster(self):
        """
        This method synchronises the action cluster with the control plugin thread.
        """
        self.__edActionCluster.synchronize()

    def setClusterSize(self, _iClusterSize):
        """
        This method sets the size of the action cluster, i.e. the number of threads
        that will be executed simultaneously. 
        """
        self.__iClusterSize = _iClusterSize

    def executePlugin(self, _edPlugin, _bSynchronous=False):
        """
        This method is used to start executable plugins in pipeline asynchronously.
        """
        if _bSynchronous:
            self.executePluginSynchronous(_edPlugin)
        else:
            _edPlugin.execute()

    def executePluginSynchronous(self, _edPlugin):
        """
        This method is used to start executable plugins in pipeline synchronously.
        """
        _edControlSlotSUCCESS = EDSlot()
        _edControlSlotFAILURE = EDSlot()

        map(_edControlSlotSUCCESS.connect,
            _edPlugin.getSlotSUCCESS().getListMethod())
        map(_edControlSlotFAILURE.connect,
            _edPlugin.getSlotFAILURE().getListMethod())

        _edPlugin.getSlotSUCCESS().emptyListMethod()
        _edPlugin.getSlotFAILURE().emptyListMethod()

        _edPlugin.executeSynchronous()

        if (not _edPlugin.isFailure()):
            EDVerbose.DEBUG("EDControlPlugin.executeSynchronous slotSUCCESS")
            # Check that something doesn't go wrong in the success method!
            try:
                _edControlSlotSUCCESS.call(_edPlugin)

            except Exception:
                EDVerbose.DEBUG(
                    "EDControlPlugin.executeSynchronous: ERROR in slotSUCCESS!"
                )
                EDVerbose.writeErrorTrace()
                _edPlugin.setFailure()

        if (_edPlugin.isFailure()):
            EDVerbose.DEBUG("EDControlPlugin.executeSynchronous slotFAILURE")
            # Check that something doesn't go wrong in the success method!
            try:
                _edControlSlotFAILURE.call(_edPlugin)

            except Exception:
                EDVerbose.DEBUG(
                    "EDControlPlugin.executeSynchronous: ERROR in slotFAILURE!"
                )
                EDVerbose.writeErrorTrace()
class EDPluginExecMeasureOffsetv2_0(EDPluginControl):
    """
    An exec plugin that takes two images and measures the offset between the two.
    In facts it is not an ExecPlugin but a control plugin that:
    * Converts the pair of images in colored JPEG
    * Extract the SIFT descriptor of each image
    * Measure the offset between the two images using the Autopano tool
    * return the measured offset and the file describing the control points.
    """


    def __init__(self):
        """
        """
        EDPluginControl.__init__(self)
        self.setXSDataInputClass(XSDataInputMeasureOffset)
        self.__strControlledPluginThumbnail = "EDPluginExecThumbnailv10"
        self.__strControlledPluginSift = "EDPluginExecSiftDescriptorv1_0"
        self.__strControlledPluginAutopano = "EDPluginExecSiftOffsetv1_0"
        self.semThumbnail = threading.Semaphore()
        self.semSift = threading.Semaphore()
        self.ACThumbnail = EDActionCluster()
        self.ACSift = EDActionCluster()
        self.xsdImages = []
        self.xsdThumb = []
        self.xsdKeys = []
        self.xsdIdx = []
        self.tCrop = [0, 0]
        self.inputImages = []
        self.tOffset = None
        self.xsdPTO = None

    def checkParameters(self):
        """
        Checks the mandatory parameters.
        """
        EDVerbose.DEBUG("EDPluginControlMeasureOffsetv2_0.checkParameters")
        self.checkMandatoryParameters(self.getDataInput(), "Data Input is None")


    def preProcess(self, _edObject=None):
        EDPluginControl.preProcess(self)
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.preProcess")
        sdi = self.getDataInput()

        crop = sdi.getCropBorders()
        if len(crop) == 2:
            self.tCrop = (crop[0].getValue(), crop[1].getValue())
        elif len(crop) == 1:
            self.tCrop = (crop[0].getValue(), crop[0].getValue())

#
        if len(sdi.getImage()) == 2:
            for i in sdi.getImage():

                array = openimage(i.getPath().getValue()).data
                shape = array.shape
                if (self.tCrop != [0, 0]) and (shape[0] > self.tCrop[0]) and (shape[1] > self.tCrop[1]):
                    array = array[self.tCrop[0]:-self.tCrop[0], self.tCrop[1]:-self.tCrop[1] ]
                    EDVerbose.DEBUG("After Crop, images have shape : (%s,%s) " % (array.shape))
                self.xsdImages.append(EDUtilsArray.arrayToXSData(array))
        elif len(sdi.getArray()) == 2:
            if (self.tCrop == [0, 0]) :
                self.xsdImages = sdi.getArray()
            else:
                for xsdArray  in  sdi.getArray():
                    array = EDUtilsArray.xsDataToArray(xsdArray)
                    shape = array.shape
                    if (shape[0] > self.tCrop[0]) and (shape[1] > self.tCrop[1]):
                        array = array[self.tCrop[0]:-self.tCrop[0], self.tCrop[1]:-self.tCrop[1] ]
                        EDVerbose.DEBUG("After Crop, images have shape : (%s,%s) " % (array.shape))
                    self.xsdImages.append(EDUtilsArray.arrayToXSData(array))
        else:
            strError = "EDPluginExecMeasureOffsetv2_0.preProcess: You should either provide two images or two arrays, but I got: %s" % sdi.marshal()
            EDVerbose.ERROR(strError)
            self.setFailure()
            raise RuntimeError(strError)
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.xsdImages len=%i %s" % (len(self.xsdImages), self.xsdImages))
        EDAssert.equal(self.xsdImages[0].getShape() , self.xsdImages[1].getShape(), "Images have the same size")
        self.xsdIdx = sdi.getIndex()
        if len(self.xsdIdx) < len(self.xsdImages):
            self.xsdIdx = [XSDataInteger(i) for i in range(len(self.xsdImages))]


    def process(self, _edObject=None):
        """
        """
        for  i in range(2):
            execPlugin = self.loadPlugin(self.__strControlledPluginThumbnail)
            xsdin = XSDataInputExecThumbnail()
            xsdin.setInputArray(self.xsdImages[i])
            xsdFile = XSDataFile()
            xsdFile.setPath(XSDataString(os.path.join(self.getWorkingDirectory(), "image%i.jpg" % self.xsdIdx[i].getValue())))
            xsdin.setOutputPath(xsdFile)
            xsdin.setLevelsColorize(XSDataBoolean(1))
            xsdin.setLevelsEqualize(XSDataBoolean(1))

            execPlugin.setDataInput(xsdin)
            execPlugin.connectSUCCESS(self.doSuccessThumb)
            execPlugin.connectFAILURE(self.doFailureThumb)
            self.ACThumbnail.addAction(execPlugin)
        self.ACThumbnail.execute()

        while len(self.xsdThumb) < 2:
            time.sleep(1)

        for  oneImage in self.xsdThumb:
            execPlugin = self.loadPlugin(self.__strControlledPluginSift)
            xsdin = XSDataInputSiftDescriptor()
            xsdin.setImage(oneImage)
            execPlugin.setDataInput(xsdin)
            execPlugin.connectSUCCESS(self.doSuccessSift)
            execPlugin.connectFAILURE(self.doFailureSift)
            self.ACSift.addAction(execPlugin)
        self.ACSift.execute()
#
#        else:
#            strError = "There are only %s images in self.xsdThumb" % len(self.xsdThumb)
#            EDVerbose.ERROR(strError)
#            self.setFailure()
#            raise RuntimeError(strError)

################################################################################
# This should be executed only after the Sift actions cluster finishes 
################################################################################
        while len(self.xsdKeys) < 2:
            time.sleep(1)

        execPlugin = self.loadPlugin(self.__strControlledPluginAutopano)
        xsdin = XSDataInputMeasureOffsetSift()
        xsdin.setDescriptorFile(self.xsdKeys)
        execPlugin.setDataInput(xsdin)
        execPlugin.connectSUCCESS(self.doSuccessAutopano)
        execPlugin.connectFAILURE(self.doFailureAutopano)
        execPlugin.executeSynchronous()




    def postProcess(self, _edObject=None):
        EDPluginControl.postProcess(self)
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.postProcess")
        # Create some output data
        xsDataResult = XSDataResultMeasureOffset()
        xsDataResult.setOffset(self.tOffset)
        xsDataResult.setPanoFile(self.xsdPTO)
        self.setDataOutput(xsDataResult)
        self.xsdImages = []

    def doSuccessThumb(self, _edPlugin=None):
        self.semThumbnail.acquire()
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.doSuccessThumb")
        self.retrieveSuccessMessages(_edPlugin, "EDPluginExecMeasureOffsetv2_0.doSuccessThumb")
        self.xsdThumb.append(_edPlugin.getDataOutput().getThumbnailPath())
        self.semThumbnail.release()


    def doFailureThumb(self, _edPlugin=None):
        self.semThumbnail.acquire()
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.doFailureThumb")
        self.retrieveFailureMessages(_edPlugin, "EDPluginExecMeasureOffsetv2_0.doFailureThumb")
        self.setFailure()
        strError = "Error in converting to Jpeg with this input: %s" % _edPlugin.getDataInput().marshal()
        EDVerbose.ERROR(strError)
        self.semThumbnail.release()
        raise RuntimeError(strError)


    def doSuccessSift(self, _edPlugin=None):
        self.semSift.acquire()
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.doSuccessSift")
        self.retrieveSuccessMessages(_edPlugin, "EDPluginExecMeasureOffsetv2_0.doSuccessSift")
        self.xsdKeys.append(_edPlugin.getDataOutput().getDescriptorFile())
        self.semSift.release()


    def doFailureSift(self, _edPlugin=None):
        self.semSift.acquire()
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.doFailureSift")
        self.retrieveFailureMessages(_edPlugin, "EDPluginExecMeasureOffsetv2_0.doFailureSift")
        self.setFailure()
        strError = "Error in extracting SIFT keys with this input: %s" % _edPlugin.getDataInput().marshal()
        EDVerbose.ERROR(strError)
        self.semSift.release()
        raise RuntimeError(strError)


    def doSuccessAutopano(self, _edPlugin=None):
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.doSuccessAutopano")
        self.retrieveSuccessMessages(_edPlugin, "EDPluginExecMeasureOffsetv2_0.doSuccessSift")
        self.tOffset = _edPlugin.getDataOutput().getOffset()
        self.xsdPTO = _edPlugin.getDataOutput().getPanoFile()


    def doFailureAutopano(self, _edPlugin=None):
        EDVerbose.DEBUG("EDPluginExecMeasureOffsetv2_0.doFailureAutopano")
        self.retrieveFailureMessages(_edPlugin, "EDPluginExecMeasureOffsetv2_0.doFailureAutopano")
        self.setFailure()
        strError = "Error in Autopano execution of with this input: %s" % _edPlugin.getDataInput().marshal()
        EDVerbose.ERROR(strError)
        raise RuntimeError(strError)