class ListenerClass(object): """ Main class of the SPEL Listener entity. Listens at a given port waiting for GUI connections. Manages the SPEL Context processes on GUI requests. """ # Client key list clientKeys = [] # Context list contexts = [] # Holds contextID / key pairs contextKeys = {} # Holds contextID / port pairs contextPorts = {} # Context status (available/running) contextStatus = {} # GUI operations delegate GUI_Operations = None # Synchronization issues buffer = None # IPC context interface __ctxIFC = None # IPC gui interface __guiIFC = None # Client lock __clientLock = None # Context lock __ctxLock = None #=========================================================================== def __init__(self, warmStart=False): self.openContexts = {} self.buffer = Queue(1) self.GUI_Operations = GUIOperations(self) # Obtain the list of available contexts from cfg file self.contexts = Config.instance().getAvailableContexts() # Update the context status map (all available) for ctx in self.contexts: self.contextPorts[ctx] = 0 self.contextStatus[ctx] = LstMessages.DATA_CTX_AVAILABLE self.__ctxIFC = IPCinterfaceServer("LST-CTX") self.__guiIFC = IPCinterfaceServer("LST-GUI") self.__clientLock = thread.allocate_lock() self.__ctxLock = thread.allocate_lock() self.__contextRegistry = ProcessRegistry("LST", warmStart) #=========================================================================== def start(self): # Get the port number from configuration port = Config.instance().getProperty(LISTENER, "ListenerPort") LOG("Listening at port: " + str(port), level = LOG_INIT ) # Setup the GUI io channel LOG("Setting up GUI channel", level = LOG_INIT) self.__guiIFC.connect(999, int(port), self.processGuiMessage, self.processGuiRequest, self.clientConnectionLost) self.__guiIFC.start() # Setup the Context io channel LOG("Setting up CTX channel", level = LOG_INIT) self.__ctxIFC.connect(998,0,self.processCtxMessage, self.processCtxRequest, self.contextConnectionLost) self.__ctxIFC.start() LOG("Ready", level = LOG_INIT ) #Restoring warm context for contextInfo in self.__contextRegistry.getProcesses(): #Only during startup we open contexts in warm mode self.openContext(contextInfo.getName(), None, True) #=========================================================================== def stop(self): LOG("Stopping, closing contexts", level = LOG_PROC ) for contextName in self.contexts: if self.isContextRunning(contextName): self.closeContext(contextName) LOG("Killing remaining processes", level = LOG_PROC ) ProcessManager.instance().killAll() self.__guiIFC.disconnect() self.__ctxIFC.disconnect() LOG("Disconnected", level = LOG_INIT ) #=========================================================================== def clientConnectionLost(self, clientKey): if clientKey in self.clientKeys: LOG("Listener lost connection with client: " + repr(clientKey), LOG_ERROR ) self.clientKeys.remove(clientKey) #=========================================================================== def contextConnectionLost(self, contextKey): # Obtain the corresponding name from the key for key in self.contextKeys: if self.contextKeys[key] == contextKey: contextName = key originalStatus = self.contextStatus[contextName] self.contextStatus[contextName] = LstMessages.DATA_CTX_ERROR if not originalStatus == LstMessages.DATA_CTX_STARTING: LOG("Listener lost connection with starting context " + repr(contextName), LOG_ERROR) else: LOG("Listener lost connection with context " + repr(contextName), LOG_ERROR) self.notifyContextCrash(contextName) self.clearContext(contextName) self.__ctxIFC.disconnect(contextKey, eoc = False) LOG("Context-lost done") #=========================================================================== def contextProcessLost(self, contextName, retCode): if (retCode == 0) and not contextName in self.contextKeys: LOG("Context finished with code 0") return self.contextStatus[contextName] = LstMessages.DATA_CTX_ERROR if contextName in self.contexts: LOG("Listener lost track of context " + repr(contextName), LOG_ERROR) self.notifyContextCrash(contextName) self.clearContext(contextName) if contextName in self.contextKeys: contextKey = self.contextKeys[contextName] self.__ctxIFC.disconnect(contextKey, eoc = False) LOG("Done") #=========================================================================== def processGuiMessage(self, msg): self.__clientLock.acquire() LOG("Received GUI message: " + msg.getId(), level = LOG_COMM) guiKey = int(msg.getKey()) if msg.getId() == LstMessages.MSG_GUI_LOGIN: LOG("Client logged in: " + str(guiKey), level = LOG_PROC) self.clientKeys.append(guiKey) elif msg.getId() == LstMessages.MSG_GUI_LOGOUT: self.clientKeys.remove(guiKey) LOG("Client logged out: " + str(guiKey), level = LOG_PROC) else: LOG("ERROR: unknown message from client: " + str(msg.getId()), LOG_ERROR) self.__clientLock.release() #=========================================================================== def processCtxMessage(self, msg): self.__ctxLock.acquire() LOG("Received Context message: " + msg.getId(), level = LOG_COMM) if msg.getId() == LstMessages.MSG_CONTEXT_OPEN: contextName = msg[LstMessages.FIELD_CTX_NAME] LOG("Context logged in: " + contextName, level = LOG_PROC) contextKey = int(msg.getKey()) ctxPort = msg[LstMessages.FIELD_CTX_PORT] self.contextPorts[contextName] = ctxPort self.contextStatus[contextName] = LstMessages.DATA_CTX_RUNNING self.contextKeys[contextName] = contextKey self.buffer.put(ctxPort, True) elif msg.getId() == LstMessages.MSG_CONTEXT_CLOSED: contextName = msg[LstMessages.FIELD_CTX_NAME] contextKey = int(msg.getKey()) LOG("Context logged out: " + contextName + ":" + repr(contextKey), level = LOG_PROC) self.contextStatus[contextName] = LstMessages.DATA_CTX_AVAILABLE self.buffer.put(contextName, True) else: LOG("ERROR: unknown message from context:" + str(msg.getId()), LOG_ERROR) self.__ctxLock.release() #=========================================================================== def processGuiRequest(self, msg): self.__clientLock.acquire() resp = self.GUI_Operations.processRequest(msg) self.__clientLock.release() return resp #=========================================================================== def processCtxRequest(self, msg): self.__ctxLock.acquire() resp = self.createResponse("NONE", msg) self.__ctxLock.release() return resp #=========================================================================== def openContext(self, contextName, clientKey = None, warm = False ): ctxScript = Config.instance().getProperty(LISTENER, "ContextScript") ctxScript = Config.instance().getHome() + os.sep + ctxScript arguments = "-c \"" + Config.instance().filename + "\" -n \"" + contextName + "\"" arguments += " -s " + str(self.__ctxIFC.port) if warm == True: arguments += " -w" pythonBin = os.getenv("PYTHON", "python") ctxScript = pythonBin + " \"" + ctxScript + "\" " + arguments # Set the status as starting (internal) self.contextStatus[contextName] = LstMessages.DATA_CTX_STARTING LOG("Starting context: '" + contextName + "'", level = LOG_PROC ) pid = ProcessManager.instance().startProcess( contextName, ctxScript, self.contextProcessLost ) LOG("Context started with pid " + str(pid), level = LOG_PROC ) LOG("Waiting context port", level = LOG_PROC ) try: ctxPort = self.buffer.get(True,CONTEXT_START_TIMEO) LOG("Context port is " + str(ctxPort), level = LOG_PROC ) # Set the status as started self.contextStatus[contextName] = LstMessages.DATA_CTX_RUNNING self.notifyContextUpdate(contextName,clientKey) self.__contextRegistry.addProcess(pid,contextName) return ctxPort except BaseException,ex: txt = "Failed to open context" reason = "Unable to get context listening port" LOG(txt + ": " + reason, LOG_ERROR) self.killContext(contextName) # Set the status as error self.contextStatus[contextName] = LstMessages.DATA_CTX_ERROR self.notifyContextUpdate(contextName,clientKey,txt,reason) return None
class ContextClass(object): # Holds the context name ctxName = None # Holds the listening port for GUIs port = None # Holds the listener port listenerPort = None # Holds the set of instance numbers for each executor id __executorInstanceNumbers = {} # Holds the set of executor managers __executorManagers = {} # Holds the set of clients __clientInfo = {} # GUI operations delegate GUI_Operations = None # Listener operations delegate LST_Operations = None # Executor operations delegate EXC_Operations = None # IPC interface for clients __guiIFC = None # IPC interface for listener __lstIFC = None # Lock for clients __clientLock = None # Lock for executors __execLock = None # Lock for context process closure __closeLock = None #Process registry for registering opened executors in a file __executorsRegistry = None #=========================================================================== def __init__(self, ctxName, listenerPort, warmStart=False): LOG("Created context", level=LOG_INIT) self.ctxName = ctxName self.port = None self.__executorInstanceNumbers = {} self.__executorManagers = {} self.__clientInfo = {} self.GUI_Operations = GUIOperations(self) self.LST_Operations = LSTOperations(self) self.EXC_Operations = EXCOperations(self) self.__guiIFC = IPCinterfaceServer("CTX-GUI") self.__lstIFC = IPCinterfaceClient("CTX-LST") self.listenerPort = listenerPort self.__clientLock = thread.allocate_lock() self.__execLock = thread.allocate_lock() self.__closeLock = Queue.Queue(1) self.__executorsRegistry = ProcessRegistry("CTX_" + ctxName, warmStart) #=========================================================================== def start(self): LOG("Loading procedures for this context", level=LOG_INIT) ProcedureManager.instance().setup(self.ctxName) LOG("Setting up GUI channel", level=LOG_INIT) # Setup the Gui io channel self.__guiIFC.connect(888, 0, self.processGuiMessage, self.processGuiRequest, self.guiConnectionLost) self.__guiIFC.start() LOG("Connecting to listener", level=LOG_INIT) # Setup the Listener io channel self.__lstIFC.connect("localhost", self.listenerPort, self.processListenerMessage, self.processListenerRequest, self.lstConnectionLost) LOG("Using listening port: " + str(self.__guiIFC.port), level=LOG_INIT) portMsg = MsgHelper.createMessage(LstMessages.MSG_CONTEXT_OPEN) portMsg[LstMessages.FIELD_CTX_NAME] = self.ctxName portMsg[LstMessages.FIELD_CTX_PORT] = str(self.__guiIFC.port) portMsg.setSender("CTX") portMsg.setReceiver("LST") self.__lstIFC.sendMessage(portMsg) LOG("Ready", level=LOG_INIT) sys.stderr.write("*********************************************\n") sys.stderr.write(" SPEL Context (" + ctxName + ") Ready \n") sys.stderr.write("*********************************************\n") #for executorInfo in self.__executorRegistry.getProcesses(): # #Launch executors stored in warm file # self.openExecutor(executorInfo.getName(), clientKey, clientMode) #=========================================================================== def stop(self): # Force closing all executors LOG("Closing executors", level=LOG_PROC) self.closeAll() # Disconnect comm interfaces LOG("Disconnecting from GUI", level=LOG_PROC) self.__guiIFC.disconnect() LOG("Logout from listener", level=LOG_PROC) logoutMsg = MsgHelper.createMessage(LstMessages.MSG_CONTEXT_CLOSED) logoutMsg[LstMessages.FIELD_CTX_NAME] = self.ctxName logoutMsg.setSender("CTX") logoutMsg.setReceiver("LST") self.__lstIFC.sendMessage(logoutMsg) self.__lstIFC.disconnect() LOG("Disconnected", level=LOG_PROC) self.__closeLock.put(1) #=========================================================================== def closeAll(self): if len(self.getExecutors()) == 0: LOG("No executors to be closed") return for procId in self.getExecutors(): LOG("Close all: " + procId) executor = self.getExecutor(procId) if executor: executor.stop() executor.waitForClose() #=========================================================================== def waitForClose(self): self.__closeLock.get(True) #=========================================================================== def guiConnectionLost(self, clientKey): if clientKey in self.getClients(): LOG("Context lost connection with client: " + repr(clientKey), LOG_ERROR) self.removeClient(clientKey) #=========================================================================== def lstConnectionLost(self, lstKey): LOG("Lost connection with listener", LOG_ERROR) self.__lstIFC.disconnect(eoc=False) LOG("Notifying listener connection lost") # Build the notification message msg = MsgHelper.createMessage(CtxMessages.MSG_LISTENER_LOST) msg.setType(MSG_TYPE_ERROR) msg[FIELD_ERROR] = "Lost connection with listener" msg[FIELD_REASON] = " " clientKeys = [] for client in self.getClients(): clientKeys.append(int(client)) if len(clientKeys) > 0: self.messageToClients("CTX", clientKeys, msg) LOG("Done") return #=========================================================================== def processGuiMessage(self, msg): if not self.GUI_Operations.processMessage(msg): # If the message is not processed locally, forward it to executors procId = msg[ExcMessages.FIELD_PROC_ID] # Forward message to the corresponding executor clientKey = int(msg.getKey()) self.messageToExecutor(clientKey, procId, msg) return #=========================================================================== def processGuiRequest(self, msg): LOG("Process GUI request: " + msg.getId(), level=LOG_COMM) resp = None resp = self.GUI_Operations.processRequest(msg) if resp is None: # if the request is not processed locally, forward it to executors procId = msg[ExcMessages.FIELD_PROC_ID] if not procId in self.getExecutors(): resp = MsgHelper.createError( msg.getId(), msg, "Unable to forward request " + msg.getId(), "No such executor: " + repr(procId)) else: clientKey = int(msg.getKey()) LOG("Send GUI request to executor: " + msg.getId(), level=LOG_COMM) resp = self.requestToExecutor(clientKey, procId, msg) LOG("Process GUI request: " + msg.getId() + " finished", level=LOG_COMM) return resp #=========================================================================== def processListenerMessage(self, msg): self.LST_Operations.processMessage(msg) #=========================================================================== def processListenerRequest(self, msg): resp = self.LST_Operations.processRequest(msg) return resp #=========================================================================== def processExecutorMessage(self, msg): self.EXC_Operations.processMessage(msg) #=========================================================================== def processExecutorRequest(self, msg): resp = self.EXC_Operations.processRequest(msg) return resp #=========================================================================== def messageToClients(self, procId, clientKeys, msg): for clientKey in clientKeys: LOG("Forwarding message " + msg.getId() + " from executor " + procId + " to client " + repr(clientKey), level=LOG_COMM) # If the client key is a procedure id, it means the request is to # be sent to another procedure msg.setSender(procId) if type(clientKey) == int: msg.setReceiver("GUI-" + str(clientKey)) resp = self.__guiIFC.sendMessage(msg, clientKey) else: parentProc = clientKey msg.setReceiver(parentProc) resp = self.messageToExecutor(procId, parentProc, msg) #=========================================================================== def requestToClients(self, procId, clientKeys, msg): LOG("Forward executor " + procId + " request " + msg.getId() + " to clients", level=LOG_COMM) firstResp = None if len(clientKeys) == 0: LOG("No clients to attend request. Discarding it", LOG_WARN, level=LOG_COMM) firstResp = MsgHelper.createError(msg.getId(), msg, "Cannot dispatch request", "No clients connected") for clientKey in clientKeys: msg.setSender(procId) # If the client key is a procedure id, it means the request is to # be sent to another procedure if type(clientKey) == int: msg.setReceiver("GUI-" + str(clientKey)) resp = self.__guiIFC.forwardRequest(msg, clientKey) else: parentProc = clientKey msg.setReceiver(parentProc) resp = self.requestToExecutor(procId, parentProc, msg) if firstResp is None: firstResp = resp LOG("Request to clients '" + msg.getId() + "' finished", level=LOG_COMM) return firstResp #=========================================================================== def messageToExecutor(self, clientKey, procId, msg): if procId in self.getExecutors(): exc = self.getExecutor(procId) if exc: exc.messageToExecutor(clientKey, msg) #=========================================================================== def requestToExecutor(self, clientKey, procId, msg): LOG("Forward client " + repr(clientKey) + " request " + msg.getId() + " to executor " + procId, level=LOG_COMM) resp = None if procId in self.getExecutors(): exc = self.getExecutor(procId) if exc: resp = exc.requestToExecutor(clientKey, msg) if resp is None: resp = MsgHelper.createError(msg.getId(), msg, "Unable to forward request", "No such executor") LOG("Request to executor " + msg.getId() + " finished", level=LOG_COMM) return resp #=========================================================================== def createExecutor(self, procId): self.__execLock.acquire() try: LOG("Creating executor manager for " + repr(procId)) manager = ExecutorManagerClass(self, procId) self.__executorManagers[procId] = manager LOG("Manager created") finally: self.__execLock.release() return manager #=========================================================================== def getInstanceId(self, procId): self.__execLock.acquire() try: instance = 0 LOG("Obtain available instance for " + repr(procId)) if procId in self.__executorInstanceNumbers: for i in range(0, 50): if not i in self.__executorInstanceNumbers[procId]: instance = i break self.__executorInstanceNumbers[procId].append(instance) else: self.__executorInstanceNumbers[procId] = [instance] procId = procId + "#" + str(instance) LOG("Instance is " + repr(procId)) finally: self.__execLock.release() return procId #=========================================================================== def openExecutor(self, procId, clientKey, clientMode, openMode={}, arguments=None, condition=None, parentId=None): ctxInfo = Config.instance().getContextConfig(self.ctxName) driverName = ctxInfo.getDriver() maxProcs = int( Config.instance().getDriverConfig(driverName).getMaxProcs()) if maxProcs > 0: activeProcs = self.getNumActiveProcs() if (activeProcs >= maxProcs): raise ContextError( "Could not launch executor. Maximum number of processes reached (" + str(maxProcs) + ")") success = False LOG("Requested opening executor " + repr(procId), level=LOG_PROC) executor = self.createExecutor(procId) # Update the proc id with the instance number procId = executor.getProcId() # Get configuration defaults for open mode and update it #TODO: get open mode defaults from config useOpenMode = {Automatic: False, Visible: True, Blocking: True} useOpenMode.update(openMode) # Set the controlling client key if the procedure is visible if useOpenMode[Visible] == True: clientInfo = self.getClient(clientKey) executor.addClient(clientInfo, True) clientInfo.addExecutor(procId) clientInfo.setMode(clientMode) LOG("Launching executor " + repr(procId) + " in mode " + repr(useOpenMode), level=LOG_PROC) if arguments: executor.setArguments(arguments) if condition: executor.setCondition(condition) if parentId: executor.setParent(parentId) # Set the open mode and open the executor executor.setOpenMode(useOpenMode) executor.start() success = executor.waitForOpen() LOG("Executor launched (" + repr(success) + ")", level=LOG_PROC) if not success: error, reason = executor.getError() self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.killExecutor(procId) self.clearExecutor(procId) raise ContextError("Could not launch executor", error + ":" + reason) else: initialStatus = executor.getStatus() if initialStatus == server.executor.status.ERROR: error, reason = executor.getError() self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.killExecutor(procId) self.clearExecutor(procId) raise ContextError("Executor failed startup", error + ":" + reason) else: pid = executor.getExecutorPid() self.__executorsRegistry.addProcess(pid, procId) LOG("Notifying executor open", level=LOG_PROC) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_OPEN, clientKey, clientMode) LOG("Open finished") return #=========================================================================== def closeExecutor(self, procId): LOG("Requested closing executor " + repr(procId)) executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) LOG("Closing executor") executor.stop() success = executor.waitForClose() LOG("Executor closed (" + repr(success) + ")") if not success: error, reason = executor.getError() self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.killExecutor(procId) self.clearExecutor(procId) raise ContextError("Could not close executor", error + ":" + reason) else: LOG("Notifying executor close", level=LOG_PROC) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.clearExecutor(procId) LOG("Close finished") return #=========================================================================== def clearExecutor(self, procId): LOG("Clearing executor for " + repr(procId)) executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) # Remove executor from client infos clients = executor.getClients() for client in clients: self.getClient(client).delExecutor(procId) self.__execLock.acquire() try: # Remove executor manager del self.__executorManagers[procId] # Remove the corresponding instance from the list idx = procId.find("#") id = procId[0:idx] instance = int(procId[idx + 1:]) # Remove from the registry self.__executorsRegistry.removeProcess(procId) if id in self.__executorInstanceNumbers: self.__executorInstanceNumbers[id].remove(instance) if len(self.__executorInstanceNumbers[id]) == 0: self.__executorInstanceNumbers.pop(id) finally: self.__execLock.release() return #=========================================================================== def killExecutor(self, procId): LOG("Killing executor for " + repr(procId)) executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) executor.stop(True) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_KILL) return True #=========================================================================== def clientAttachExecutor(self, procId, clientKey, clientMode, firstClient): executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) LOG("Client " + str(clientKey) + " requested attaching executor " + procId) clientKey = int(clientKey) clientInfo = self.getClient(clientKey) if not procId in clientInfo.getExecutors(): clientInfo.addExecutor(procId) clientInfo.setMode(clientMode) if not executor.addClient(clientInfo, firstClient): raise ContextError("Cannot add client in mode " + repr(clientMode)) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_ATTACH, clientKey, clientMode) #=========================================================================== def clientDetachExecutor(self, procId, clientKey): executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) LOG("Client " + str(clientKey) + " requested detaching executor " + procId) clientKey = int(clientKey) clientInfo = self.getClient(clientKey) if procId in clientInfo.getExecutors(): self.getClient(clientKey).delExecutor(procId) executor.removeClient(clientKey) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_DETACH, clientKey) #=========================================================================== def createClient(self, clientKey, host, clientMode): self.__clientLock.acquire() try: self.__clientInfo[clientKey] = ClientInfo(clientKey, host, clientMode) finally: self.__clientLock.release() return #=========================================================================== def removeClient(self, clientKey): # Process orphan executors clientInfo = self.getClient(clientKey) self.__clientLock.acquire() try: if clientInfo: execs = clientInfo.getExecutors() # Disconnect the interface self.__guiIFC.disconnect(clientKey, eoc=False) if len(execs) == 0: LOG("No executors linked to client " + repr(clientKey), level=LOG_PROC) else: for procId in execs: executor = self.getExecutor(procId) if executor is not None: executor.clientLost(clientKey) else: LOG("Unknown executor:" + procId) LOG("Unregistering client: " + repr(clientKey)) host = self.__clientInfo[clientKey].getHost() del self.__clientInfo[clientKey] finally: self.__clientLock.release() return #=========================================================================== def getExecutors(self): self.__execLock.acquire() keys = [] try: keys = self.__executorManagers.keys() finally: self.__execLock.release() return keys #=========================================================================== def getExecutor(self, procId): self.__execLock.acquire() exc = None try: exc = self.__executorManagers.get(procId) finally: self.__execLock.release() return exc #=========================================================================== def getClients(self): self.__clientLock.acquire() keys = [] try: keys = self.__clientInfo.keys() finally: self.__clientLock.release() return keys #=========================================================================== def getClient(self, clientKey): self.__clientLock.acquire() clt = None try: if clientKey == NO_CLIENT: clt = None else: clt = self.__clientInfo[clientKey] finally: self.__clientLock.release() return clt #=========================================================================== def notifyClientOperation(self, clientKey, clientMode, host, operation): LOG("Notifying client operation " + repr(operation) + ", " + repr(clientKey)) # Build the notification message msg = MsgHelper.createMessage(CtxMessages.MSG_CLIENT_OP) msg[CtxMessages.FIELD_GUI_KEY] = clientKey msg[CtxMessages.FIELD_GUI_MODE] = clientMode msg[FIELD_HOST] = host msg[CtxMessages.FIELD_CLOP] = operation # Get all connected clients but the logged in one clientKey = int(clientKey) clientKeys = [] for client in self.getClients(): client = int(client) if client != clientKey: clientKeys.append(client) if len(clientKeys) > 0: self.messageToClients("CTX", clientKeys, msg) LOG("Notify done") #=========================================================================== def notifyExecutorOperation(self, procId, operation, clientKey="", clientMode=""): LOG("Notifying executor operation " + repr(operation) + ", " + repr(procId)) # Build the notification message msg = MsgHelper.createMessage(CtxMessages.MSG_EXEC_OP) msg[CtxMessages.FIELD_PROC_ID] = procId msg[CtxMessages.FIELD_EXOP] = operation msg[CtxMessages.FIELD_GUI_KEY] = clientKey msg[CtxMessages.FIELD_GUI_MODE] = clientMode msg[ExcMessages.FIELD_EXEC_STATUS] = self.getExecutor( procId).getStatus() msg[ExcMessages.FIELD_CONDITION] = self.getExecutor( procId).getCondition() msg[CtxMessages.FIELD_OPEN_MODE] = self.getExecutor( procId).getOpenMode() clientKeys = self.getClients() LOG("All clients: " + repr(clientKeys)) # Notify parent procedure also, if it is present executor = self.getExecutor(procId) if executor: parent = executor.getParent() if parent is not None: clientKeys += [parent] LOG("Notifying clients: " + repr(clientKeys)) if len(clientKeys) > 0: self.messageToClients(procId, clientKeys, msg) LOG("Notifying executor operation done") #=========================================================================== def executorError(self, procId, msg): errorText = "Executor fatal error" errorMsg = MsgHelper.createError2(CtxMessages.MSG_EXEC_ERROR, procId, "CLT", errorText, msg) errorMsg[CtxMessages.FIELD_PROC_ID] = procId executor = self.getExecutor(procId) if executor: procClients = executor.getClients() self.messageToClients(procId, procClients, errorMsg) else: LOG("No executor found to notify error", LOG_ERROR) #=========================================================================== def buildExecutorInfo(self, procId, resp): executor = self.getExecutor(procId) pname = ProcedureManager.instance().getProcedure(procId).name() if executor is None: txt = "No such executor: " + repr(procId) reason = " " resp[ExcMessages.FIELD_PROC_ID] = procId resp[ExcMessages.FIELD_PARENT_PROC] = " " resp[ExcMessages.FIELD_PROC_NAME] = pname resp[ExcMessages.FIELD_ASRUN_NAME] = " " resp[ExcMessages.FIELD_LOG_NAME] = " " resp[ExcMessages.FIELD_EXEC_PORT] = "0" resp[ExcMessages.FIELD_EXEC_STATUS] = server.executor.status.UNINIT resp[ExcMessages.FIELD_CONDITION] = "" resp[ExcMessages.FIELD_GUI_LIST] = " " resp[ExcMessages.FIELD_GUI_CONTROL] = " " resp[CtxMessages.FIELD_OPEN_MODE] = " " resp[ExcMessages.FIELD_LINE] = "0" resp[ExcMessages.FIELD_CSP] = procId else: control = executor.getControllingClient() if control is None: control = " " guiList = "" for gui in executor.getMonitoringClients(): if len(guiList) > 0: guiList = guiList + "," guiList = guiList + str(gui) resp[ExcMessages.FIELD_PROC_ID] = procId resp[ExcMessages.FIELD_PARENT_PROC] = executor.getParent() resp[ExcMessages.FIELD_PROC_NAME] = pname resp[ExcMessages.FIELD_ASRUN_NAME] = executor.getAsRunFile() resp[ExcMessages.FIELD_LOG_NAME] = executor.getLogFile() resp[ExcMessages.FIELD_EXEC_PORT] = executor.getPort() resp[ExcMessages.FIELD_EXEC_STATUS] = executor.getStatus() resp[ExcMessages.FIELD_CONDITION] = executor.getCondition() resp[ExcMessages.FIELD_GUI_LIST] = guiList resp[ExcMessages.FIELD_GUI_CONTROL] = control resp[CtxMessages.FIELD_OPEN_MODE] = executor.getOpenMode() resp[ExcMessages.FIELD_CSP] = executor.getStackPosition() return resp #=========================================================================== def getFileData(self, procId, logId): executor = self.getExecutor(procId) if executor is None: return resp code = " " if (logId == ExcMessages.DATA_FILE_ASRUN): filename = executor.getAsRunFile() else: filename = executor.getLogFile() lines = [] if filename and os.path.exists(filename): f = file(filename) lines = f.readlines() return lines #=========================================================================== def getNumActiveProcs(self): activeProcs = 0 for key in self.getExecutors(): executor = self.getExecutor(key) if executor and executor.isActive(): activeProcs += 1 return activeProcs
class ListenerClass(object): """ Main class of the SPEL Listener entity. Listens at a given port waiting for GUI connections. Manages the SPEL Context processes on GUI requests. """ # Client key list clientKeys = [] # Context list contexts = [] # Holds contextID / key pairs contextKeys = {} # Holds contextID / port pairs contextPorts = {} # Context status (available/running) contextStatus = {} # GUI operations delegate GUI_Operations = None # Synchronization issues buffer = None # IPC context interface __ctxIFC = None # IPC gui interface __guiIFC = None # Client lock __clientLock = None # Context lock __ctxLock = None #=========================================================================== def __init__(self, warmStart=False): self.openContexts = {} self.buffer = Queue(1) self.GUI_Operations = GUIOperations(self) # Obtain the list of available contexts from cfg file self.contexts = Config.instance().getAvailableContexts() # Update the context status map (all available) for ctx in self.contexts: self.contextPorts[ctx] = 0 self.contextStatus[ctx] = LstMessages.DATA_CTX_AVAILABLE self.__ctxIFC = IPCinterfaceServer("LST-CTX") self.__guiIFC = IPCinterfaceServer("LST-GUI") self.__clientLock = thread.allocate_lock() self.__ctxLock = thread.allocate_lock() self.__contextRegistry = ProcessRegistry("LST", warmStart) #=========================================================================== def start(self): # Get the port number from configuration port = Config.instance().getProperty(LISTENER, "ListenerPort") LOG("Listening at port: " + str(port), level=LOG_INIT) # Setup the GUI io channel LOG("Setting up GUI channel", level=LOG_INIT) self.__guiIFC.connect(999, int(port), self.processGuiMessage, self.processGuiRequest, self.clientConnectionLost) self.__guiIFC.start() # Setup the Context io channel LOG("Setting up CTX channel", level=LOG_INIT) self.__ctxIFC.connect(998, 0, self.processCtxMessage, self.processCtxRequest, self.contextConnectionLost) self.__ctxIFC.start() LOG("Ready", level=LOG_INIT) #Restoring warm context for contextInfo in self.__contextRegistry.getProcesses(): #Only during startup we open contexts in warm mode self.openContext(contextInfo.getName(), None, True) #=========================================================================== def stop(self): LOG("Stopping, closing contexts", level=LOG_PROC) for contextName in self.contexts: if self.isContextRunning(contextName): self.closeContext(contextName) LOG("Killing remaining processes", level=LOG_PROC) ProcessManager.instance().killAll() self.__guiIFC.disconnect() self.__ctxIFC.disconnect() LOG("Disconnected", level=LOG_INIT) #=========================================================================== def clientConnectionLost(self, clientKey): if clientKey in self.clientKeys: LOG("Listener lost connection with client: " + repr(clientKey), LOG_ERROR) self.clientKeys.remove(clientKey) #=========================================================================== def contextConnectionLost(self, contextKey): # Obtain the corresponding name from the key for key in self.contextKeys: if self.contextKeys[key] == contextKey: contextName = key originalStatus = self.contextStatus[contextName] self.contextStatus[contextName] = LstMessages.DATA_CTX_ERROR if not originalStatus == LstMessages.DATA_CTX_STARTING: LOG( "Listener lost connection with starting context " + repr(contextName), LOG_ERROR) else: LOG("Listener lost connection with context " + repr(contextName), LOG_ERROR) self.notifyContextCrash(contextName) self.clearContext(contextName) self.__ctxIFC.disconnect(contextKey, eoc=False) LOG("Context-lost done") #=========================================================================== def contextProcessLost(self, contextName, retCode): if (retCode == 0) and not contextName in self.contextKeys: LOG("Context finished with code 0") return self.contextStatus[contextName] = LstMessages.DATA_CTX_ERROR if contextName in self.contexts: LOG("Listener lost track of context " + repr(contextName), LOG_ERROR) self.notifyContextCrash(contextName) self.clearContext(contextName) if contextName in self.contextKeys: contextKey = self.contextKeys[contextName] self.__ctxIFC.disconnect(contextKey, eoc=False) LOG("Done") #=========================================================================== def processGuiMessage(self, msg): self.__clientLock.acquire() LOG("Received GUI message: " + msg.getId(), level=LOG_COMM) guiKey = int(msg.getKey()) if msg.getId() == LstMessages.MSG_GUI_LOGIN: LOG("Client logged in: " + str(guiKey), level=LOG_PROC) self.clientKeys.append(guiKey) elif msg.getId() == LstMessages.MSG_GUI_LOGOUT: self.clientKeys.remove(guiKey) LOG("Client logged out: " + str(guiKey), level=LOG_PROC) else: LOG("ERROR: unknown message from client: " + str(msg.getId()), LOG_ERROR) self.__clientLock.release() #=========================================================================== def processCtxMessage(self, msg): self.__ctxLock.acquire() LOG("Received Context message: " + msg.getId(), level=LOG_COMM) if msg.getId() == LstMessages.MSG_CONTEXT_OPEN: contextName = msg[LstMessages.FIELD_CTX_NAME] LOG("Context logged in: " + contextName, level=LOG_PROC) contextKey = int(msg.getKey()) ctxPort = msg[LstMessages.FIELD_CTX_PORT] self.contextPorts[contextName] = ctxPort self.contextStatus[contextName] = LstMessages.DATA_CTX_RUNNING self.contextKeys[contextName] = contextKey self.buffer.put(ctxPort, True) elif msg.getId() == LstMessages.MSG_CONTEXT_CLOSED: contextName = msg[LstMessages.FIELD_CTX_NAME] contextKey = int(msg.getKey()) LOG("Context logged out: " + contextName + ":" + repr(contextKey), level=LOG_PROC) self.contextStatus[contextName] = LstMessages.DATA_CTX_AVAILABLE self.buffer.put(contextName, True) else: LOG("ERROR: unknown message from context:" + str(msg.getId()), LOG_ERROR) self.__ctxLock.release() #=========================================================================== def processGuiRequest(self, msg): self.__clientLock.acquire() resp = self.GUI_Operations.processRequest(msg) self.__clientLock.release() return resp #=========================================================================== def processCtxRequest(self, msg): self.__ctxLock.acquire() resp = self.createResponse("NONE", msg) self.__ctxLock.release() return resp #=========================================================================== def openContext(self, contextName, clientKey=None, warm=False): ctxScript = Config.instance().getProperty(LISTENER, "ContextScript") ctxScript = Config.instance().getHome() + os.sep + ctxScript arguments = "-c \"" + Config.instance( ).filename + "\" -n \"" + contextName + "\"" arguments += " -s " + str(self.__ctxIFC.port) if warm == True: arguments += " -w" pythonBin = os.getenv("PYTHON", "python") ctxScript = pythonBin + " \"" + ctxScript + "\" " + arguments # Set the status as starting (internal) self.contextStatus[contextName] = LstMessages.DATA_CTX_STARTING LOG("Starting context: '" + contextName + "'", level=LOG_PROC) pid = ProcessManager.instance().startProcess(contextName, ctxScript, self.contextProcessLost) LOG("Context started with pid " + str(pid), level=LOG_PROC) LOG("Waiting context port", level=LOG_PROC) try: ctxPort = self.buffer.get(True, CONTEXT_START_TIMEO) LOG("Context port is " + str(ctxPort), level=LOG_PROC) # Set the status as started self.contextStatus[contextName] = LstMessages.DATA_CTX_RUNNING self.notifyContextUpdate(contextName, clientKey) self.__contextRegistry.addProcess(pid, contextName) return ctxPort except BaseException, ex: txt = "Failed to open context" reason = "Unable to get context listening port" LOG(txt + ": " + reason, LOG_ERROR) self.killContext(contextName) # Set the status as error self.contextStatus[contextName] = LstMessages.DATA_CTX_ERROR self.notifyContextUpdate(contextName, clientKey, txt, reason) return None
class ContextClass(object): # Holds the context name ctxName = None # Holds the listening port for GUIs port = None # Holds the listener port listenerPort = None # Holds the set of instance numbers for each executor id __executorInstanceNumbers = {} # Holds the set of executor managers __executorManagers = {} # Holds the set of clients __clientInfo = {} # GUI operations delegate GUI_Operations = None # Listener operations delegate LST_Operations = None # Executor operations delegate EXC_Operations = None # IPC interface for clients __guiIFC = None # IPC interface for listener __lstIFC = None # Lock for clients __clientLock = None # Lock for executors __execLock = None # Lock for context process closure __closeLock = None #Process registry for registering opened executors in a file __executorsRegistry = None #=========================================================================== def __init__(self, ctxName, listenerPort, warmStart = False): LOG("Created context", level = LOG_INIT) self.ctxName = ctxName self.port = None self.__executorInstanceNumbers = {} self.__executorManagers = {} self.__clientInfo = {} self.GUI_Operations = GUIOperations(self) self.LST_Operations = LSTOperations(self) self.EXC_Operations = EXCOperations(self) self.__guiIFC = IPCinterfaceServer("CTX-GUI") self.__lstIFC = IPCinterfaceClient("CTX-LST") self.listenerPort = listenerPort self.__clientLock = thread.allocate_lock() self.__execLock = thread.allocate_lock() self.__closeLock = Queue.Queue(1) self.__executorsRegistry = ProcessRegistry("CTX_" + ctxName, warmStart) #=========================================================================== def start(self): LOG("Loading procedures for this context", level = LOG_INIT) ProcedureManager.instance().setup(self.ctxName) LOG("Setting up GUI channel", level = LOG_INIT) # Setup the Gui io channel self.__guiIFC.connect( 888, 0, self.processGuiMessage, self.processGuiRequest, self.guiConnectionLost) self.__guiIFC.start() LOG("Connecting to listener", level = LOG_INIT) # Setup the Listener io channel self.__lstIFC.connect("localhost",self.listenerPort, self.processListenerMessage, self.processListenerRequest, self.lstConnectionLost) LOG("Using listening port: " + str(self.__guiIFC.port), level = LOG_INIT) portMsg = MsgHelper.createMessage(LstMessages.MSG_CONTEXT_OPEN) portMsg[LstMessages.FIELD_CTX_NAME] = self.ctxName portMsg[LstMessages.FIELD_CTX_PORT] = str(self.__guiIFC.port) portMsg.setSender("CTX") portMsg.setReceiver("LST") self.__lstIFC.sendMessage(portMsg) LOG("Ready", level = LOG_INIT) sys.stderr.write("*********************************************\n") sys.stderr.write(" SPEL Context (" + ctxName + ") Ready \n") sys.stderr.write("*********************************************\n") #for executorInfo in self.__executorRegistry.getProcesses(): # #Launch executors stored in warm file # self.openExecutor(executorInfo.getName(), clientKey, clientMode) #=========================================================================== def stop(self): # Force closing all executors LOG("Closing executors", level = LOG_PROC) self.closeAll() # Disconnect comm interfaces LOG("Disconnecting from GUI", level = LOG_PROC) self.__guiIFC.disconnect() LOG("Logout from listener", level = LOG_PROC) logoutMsg = MsgHelper.createMessage(LstMessages.MSG_CONTEXT_CLOSED) logoutMsg[LstMessages.FIELD_CTX_NAME] = self.ctxName logoutMsg.setSender("CTX") logoutMsg.setReceiver("LST") self.__lstIFC.sendMessage(logoutMsg) self.__lstIFC.disconnect() LOG("Disconnected", level = LOG_PROC) self.__closeLock.put(1) #=========================================================================== def closeAll(self): if len(self.getExecutors())==0: LOG("No executors to be closed") return for procId in self.getExecutors(): LOG("Close all: " + procId) executor = self.getExecutor(procId) if executor: executor.stop() executor.waitForClose() #=========================================================================== def waitForClose(self): self.__closeLock.get(True) #=========================================================================== def guiConnectionLost(self, clientKey): if clientKey in self.getClients(): LOG("Context lost connection with client: " + repr(clientKey), LOG_ERROR) self.removeClient(clientKey) #=========================================================================== def lstConnectionLost(self, lstKey): LOG("Lost connection with listener", LOG_ERROR) self.__lstIFC.disconnect( eoc = False ) LOG("Notifying listener connection lost") # Build the notification message msg = MsgHelper.createMessage(CtxMessages.MSG_LISTENER_LOST) msg.setType(MSG_TYPE_ERROR) msg[FIELD_ERROR] = "Lost connection with listener" msg[FIELD_REASON] = " " clientKeys = [] for client in self.getClients(): clientKeys.append(int(client)) if len(clientKeys)>0: self.messageToClients("CTX", clientKeys, msg) LOG("Done") return #=========================================================================== def processGuiMessage(self, msg): if not self.GUI_Operations.processMessage(msg): # If the message is not processed locally, forward it to executors procId = msg[ExcMessages.FIELD_PROC_ID] # Forward message to the corresponding executor clientKey = int(msg.getKey()) self.messageToExecutor(clientKey, procId, msg) return #=========================================================================== def processGuiRequest(self, msg): LOG("Process GUI request: " + msg.getId(), level = LOG_COMM) resp = None resp = self.GUI_Operations.processRequest(msg) if resp is None: # if the request is not processed locally, forward it to executors procId = msg[ExcMessages.FIELD_PROC_ID] if not procId in self.getExecutors(): resp = MsgHelper.createError(msg.getId(), msg, "Unable to forward request " + msg.getId(), "No such executor: " + repr(procId)) else: clientKey = int(msg.getKey()) LOG("Send GUI request to executor: " + msg.getId(), level = LOG_COMM) resp = self.requestToExecutor(clientKey, procId, msg) LOG("Process GUI request: " + msg.getId() + " finished", level = LOG_COMM) return resp #=========================================================================== def processListenerMessage(self, msg): self.LST_Operations.processMessage(msg) #=========================================================================== def processListenerRequest(self, msg): resp = self.LST_Operations.processRequest(msg) return resp #=========================================================================== def processExecutorMessage(self, msg): self.EXC_Operations.processMessage(msg) #=========================================================================== def processExecutorRequest(self, msg): resp = self.EXC_Operations.processRequest(msg) return resp #=========================================================================== def messageToClients(self, procId, clientKeys, msg): for clientKey in clientKeys: LOG("Forwarding message " + msg.getId() + " from executor " + procId + " to client "+ repr(clientKey), level = LOG_COMM) # If the client key is a procedure id, it means the request is to # be sent to another procedure msg.setSender(procId) if type(clientKey)==int: msg.setReceiver("GUI-" + str(clientKey)) resp = self.__guiIFC.sendMessage(msg,clientKey) else: parentProc = clientKey msg.setReceiver(parentProc) resp = self.messageToExecutor( procId, parentProc, msg) #=========================================================================== def requestToClients(self, procId, clientKeys, msg): LOG("Forward executor " + procId + " request " + msg.getId() + " to clients", level = LOG_COMM) firstResp = None if len(clientKeys)==0: LOG("No clients to attend request. Discarding it", LOG_WARN, level = LOG_COMM) firstResp = MsgHelper.createError(msg.getId(), msg, "Cannot dispatch request", "No clients connected") for clientKey in clientKeys: msg.setSender(procId) # If the client key is a procedure id, it means the request is to # be sent to another procedure if type(clientKey)==int: msg.setReceiver("GUI-" + str(clientKey)) resp = self.__guiIFC.forwardRequest(msg,clientKey) else: parentProc = clientKey msg.setReceiver(parentProc) resp = self.requestToExecutor( procId, parentProc, msg) if firstResp is None: firstResp = resp LOG("Request to clients '" + msg.getId() + "' finished", level = LOG_COMM) return firstResp #=========================================================================== def messageToExecutor(self, clientKey, procId, msg): if procId in self.getExecutors(): exc = self.getExecutor(procId) if exc: exc.messageToExecutor(clientKey,msg) #=========================================================================== def requestToExecutor(self, clientKey, procId, msg): LOG("Forward client " + repr(clientKey) + " request " + msg.getId() + " to executor " + procId, level = LOG_COMM) resp = None if procId in self.getExecutors(): exc = self.getExecutor(procId) if exc: resp = exc.requestToExecutor(clientKey,msg) if resp is None: resp = MsgHelper.createError(msg.getId(), msg, "Unable to forward request", "No such executor") LOG("Request to executor " + msg.getId() + " finished", level = LOG_COMM) return resp #=========================================================================== def createExecutor(self, procId): self.__execLock.acquire() try: LOG("Creating executor manager for " + repr(procId)) manager = ExecutorManagerClass(self,procId) self.__executorManagers[procId] = manager LOG("Manager created") finally: self.__execLock.release() return manager #=========================================================================== def getInstanceId(self, procId): self.__execLock.acquire() try: instance = 0 LOG("Obtain available instance for " + repr(procId)) if procId in self.__executorInstanceNumbers: for i in range(0,50): if not i in self.__executorInstanceNumbers[procId]: instance = i break self.__executorInstanceNumbers[procId].append(instance) else: self.__executorInstanceNumbers[procId] = [instance] procId = procId + "#" + str(instance) LOG("Instance is " + repr(procId)) finally: self.__execLock.release() return procId #=========================================================================== def openExecutor(self, procId, clientKey, clientMode, openMode = {}, arguments = None, condition = None, parentId = None): ctxInfo = Config.instance().getContextConfig(self.ctxName) driverName = ctxInfo.getDriver() maxProcs = int(Config.instance().getDriverConfig(driverName).getMaxProcs()) if maxProcs>0: activeProcs = self.getNumActiveProcs() if (activeProcs >= maxProcs): raise ContextError("Could not launch executor. Maximum number of processes reached (" + str(maxProcs) + ")") success = False LOG("Requested opening executor " + repr(procId), level = LOG_PROC) executor = self.createExecutor(procId) # Update the proc id with the instance number procId = executor.getProcId() # Get configuration defaults for open mode and update it #TODO: get open mode defaults from config useOpenMode = {Automatic:False,Visible:True,Blocking:True} useOpenMode.update(openMode) # Set the controlling client key if the procedure is visible if useOpenMode[Visible] == True: clientInfo = self.getClient(clientKey) executor.addClient(clientInfo, True) clientInfo.addExecutor(procId) clientInfo.setMode(clientMode) LOG("Launching executor " + repr(procId) + " in mode " + repr(useOpenMode), level = LOG_PROC) if arguments: executor.setArguments(arguments) if condition: executor.setCondition(condition) if parentId: executor.setParent(parentId) # Set the open mode and open the executor executor.setOpenMode(useOpenMode) executor.start() success = executor.waitForOpen() LOG("Executor launched (" + repr(success) + ")", level = LOG_PROC) if not success: error,reason = executor.getError() self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.killExecutor(procId) self.clearExecutor(procId) raise ContextError("Could not launch executor",error + ":" + reason) else: initialStatus = executor.getStatus() if initialStatus == server.executor.status.ERROR: error,reason = executor.getError() self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.killExecutor(procId) self.clearExecutor(procId) raise ContextError("Executor failed startup",error + ":" + reason) else: pid = executor.getExecutorPid() self.__executorsRegistry.addProcess(pid,procId) LOG("Notifying executor open", level = LOG_PROC) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_OPEN, clientKey, clientMode) LOG("Open finished") return #=========================================================================== def closeExecutor(self, procId): LOG("Requested closing executor " + repr(procId)) executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) LOG("Closing executor") executor.stop() success = executor.waitForClose() LOG("Executor closed (" + repr(success) + ")") if not success: error,reason = executor.getError() self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.killExecutor(procId) self.clearExecutor(procId) raise ContextError("Could not close executor",error + ":" + reason) else: LOG("Notifying executor close", level = LOG_PROC) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_CLOSE) self.clearExecutor(procId) LOG("Close finished") return #=========================================================================== def clearExecutor(self, procId): LOG("Clearing executor for " + repr(procId)) executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) # Remove executor from client infos clients = executor.getClients() for client in clients: self.getClient(client).delExecutor(procId) self.__execLock.acquire() try: # Remove executor manager del self.__executorManagers[procId] # Remove the corresponding instance from the list idx = procId.find("#") id = procId[0:idx] instance = int(procId[idx+1:]) # Remove from the registry self.__executorsRegistry.removeProcess(procId) if id in self.__executorInstanceNumbers: self.__executorInstanceNumbers[id].remove(instance) if len(self.__executorInstanceNumbers[id])==0: self.__executorInstanceNumbers.pop(id) finally: self.__execLock.release() return #=========================================================================== def killExecutor(self, procId): LOG("Killing executor for " + repr(procId)) executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) executor.stop(True) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_KILL) return True #=========================================================================== def clientAttachExecutor(self, procId, clientKey, clientMode, firstClient): executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) LOG("Client " + str(clientKey) + " requested attaching executor " + procId) clientKey = int(clientKey) clientInfo = self.getClient(clientKey) if not procId in clientInfo.getExecutors(): clientInfo.addExecutor(procId) clientInfo.setMode(clientMode) if not executor.addClient(clientInfo, firstClient): raise ContextError("Cannot add client in mode " + repr(clientMode)) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_ATTACH, clientKey, clientMode) #=========================================================================== def clientDetachExecutor(self, procId, clientKey): executor = self.getExecutor(procId) if executor is None: raise ContextError("No such executor: " + repr(procId)) LOG("Client " + str(clientKey) + " requested detaching executor " + procId) clientKey = int(clientKey) clientInfo = self.getClient(clientKey) if procId in clientInfo.getExecutors(): self.getClient(clientKey).delExecutor(procId) executor.removeClient(clientKey) self.notifyExecutorOperation(procId, CtxMessages.DATA_EXOP_DETACH, clientKey) #=========================================================================== def createClient(self, clientKey, host, clientMode): self.__clientLock.acquire() try: self.__clientInfo[clientKey] = ClientInfo(clientKey,host,clientMode) finally: self.__clientLock.release() return #=========================================================================== def removeClient(self, clientKey): # Process orphan executors clientInfo = self.getClient(clientKey) self.__clientLock.acquire() try: if clientInfo: execs = clientInfo.getExecutors() # Disconnect the interface self.__guiIFC.disconnect(clientKey, eoc = False) if len(execs)==0: LOG("No executors linked to client " + repr(clientKey), level = LOG_PROC ) else: for procId in execs: executor = self.getExecutor(procId) if executor is not None: executor.clientLost(clientKey) else: LOG("Unknown executor:" + procId) LOG("Unregistering client: " + repr(clientKey)) host = self.__clientInfo[clientKey].getHost() del self.__clientInfo[clientKey] finally: self.__clientLock.release() return #=========================================================================== def getExecutors(self): self.__execLock.acquire() keys = [] try: keys = self.__executorManagers.keys() finally: self.__execLock.release() return keys #=========================================================================== def getExecutor(self, procId): self.__execLock.acquire() exc = None try: exc = self.__executorManagers.get(procId) finally: self.__execLock.release() return exc #=========================================================================== def getClients(self): self.__clientLock.acquire() keys = [] try: keys = self.__clientInfo.keys() finally: self.__clientLock.release() return keys #=========================================================================== def getClient(self, clientKey): self.__clientLock.acquire() clt = None try: if clientKey == NO_CLIENT: clt = None else: clt = self.__clientInfo[clientKey] finally: self.__clientLock.release() return clt #=========================================================================== def notifyClientOperation(self, clientKey, clientMode, host, operation): LOG("Notifying client operation " + repr(operation) + ", " + repr(clientKey)) # Build the notification message msg = MsgHelper.createMessage(CtxMessages.MSG_CLIENT_OP) msg[CtxMessages.FIELD_GUI_KEY] = clientKey msg[CtxMessages.FIELD_GUI_MODE] = clientMode msg[FIELD_HOST] = host msg[CtxMessages.FIELD_CLOP] = operation # Get all connected clients but the logged in one clientKey = int(clientKey) clientKeys = [] for client in self.getClients(): client = int(client) if client != clientKey: clientKeys.append(client) if len(clientKeys)>0: self.messageToClients("CTX", clientKeys, msg) LOG("Notify done") #=========================================================================== def notifyExecutorOperation(self, procId, operation, clientKey = "", clientMode = "" ): LOG("Notifying executor operation " + repr(operation) + ", " + repr(procId)) # Build the notification message msg = MsgHelper.createMessage(CtxMessages.MSG_EXEC_OP) msg[CtxMessages.FIELD_PROC_ID] = procId msg[CtxMessages.FIELD_EXOP] = operation msg[CtxMessages.FIELD_GUI_KEY] = clientKey msg[CtxMessages.FIELD_GUI_MODE] = clientMode msg[ExcMessages.FIELD_EXEC_STATUS] = self.getExecutor(procId).getStatus() msg[ExcMessages.FIELD_CONDITION] = self.getExecutor(procId).getCondition() msg[CtxMessages.FIELD_OPEN_MODE] = self.getExecutor(procId).getOpenMode() clientKeys = self.getClients() LOG("All clients: " + repr(clientKeys)) # Notify parent procedure also, if it is present executor = self.getExecutor(procId) if executor: parent = executor.getParent() if parent is not None: clientKeys += [parent] LOG("Notifying clients: " + repr(clientKeys)) if len(clientKeys)>0: self.messageToClients(procId, clientKeys, msg) LOG("Notifying executor operation done") #=========================================================================== def executorError(self, procId, msg): errorText = "Executor fatal error" errorMsg = MsgHelper.createError2(CtxMessages.MSG_EXEC_ERROR, procId, "CLT", errorText, msg) errorMsg[CtxMessages.FIELD_PROC_ID] = procId executor = self.getExecutor(procId) if executor: procClients = executor.getClients() self.messageToClients(procId, procClients, errorMsg) else: LOG("No executor found to notify error", LOG_ERROR) #=========================================================================== def buildExecutorInfo(self, procId, resp ): executor = self.getExecutor(procId) pname = ProcedureManager.instance().getProcedure(procId).name() if executor is None: txt = "No such executor: " + repr(procId) reason = " " resp[ExcMessages.FIELD_PROC_ID] = procId resp[ExcMessages.FIELD_PARENT_PROC] = " " resp[ExcMessages.FIELD_PROC_NAME] = pname resp[ExcMessages.FIELD_ASRUN_NAME] = " " resp[ExcMessages.FIELD_LOG_NAME] = " " resp[ExcMessages.FIELD_EXEC_PORT] = "0" resp[ExcMessages.FIELD_EXEC_STATUS] = server.executor.status.UNINIT resp[ExcMessages.FIELD_CONDITION] = "" resp[ExcMessages.FIELD_GUI_LIST] = " " resp[ExcMessages.FIELD_GUI_CONTROL] = " " resp[CtxMessages.FIELD_OPEN_MODE] = " " resp[ExcMessages.FIELD_LINE] = "0" resp[ExcMessages.FIELD_CSP] = procId else: control = executor.getControllingClient() if control is None: control = " " guiList = "" for gui in executor.getMonitoringClients(): if len(guiList)>0: guiList = guiList + "," guiList = guiList + str(gui) resp[ExcMessages.FIELD_PROC_ID] = procId resp[ExcMessages.FIELD_PARENT_PROC] = executor.getParent() resp[ExcMessages.FIELD_PROC_NAME] = pname resp[ExcMessages.FIELD_ASRUN_NAME] = executor.getAsRunFile() resp[ExcMessages.FIELD_LOG_NAME] = executor.getLogFile() resp[ExcMessages.FIELD_EXEC_PORT] = executor.getPort() resp[ExcMessages.FIELD_EXEC_STATUS] = executor.getStatus() resp[ExcMessages.FIELD_CONDITION] = executor.getCondition() resp[ExcMessages.FIELD_GUI_LIST] = guiList resp[ExcMessages.FIELD_GUI_CONTROL] = control resp[CtxMessages.FIELD_OPEN_MODE] = executor.getOpenMode() resp[ExcMessages.FIELD_CSP] = executor.getStackPosition() resp[ExcMessages.FIELD_ACTION_LABEL] = executor.getUserActionLabel() resp[ExcMessages.FIELD_ACTION_SEV] = executor.getUserActionSeverity() aen = executor.getUserActionEnabled() if aen: resp[ExcMessages.FIELD_ACTION_ENABLED] = "True" else: resp[ExcMessages.FIELD_ACTION_ENABLED] = "False" return resp #=========================================================================== def getFileData(self, procId, logId): executor = self.getExecutor(procId) if executor is None: return resp code = " " if (logId == ExcMessages.DATA_FILE_ASRUN): filename = executor.getAsRunFile() else: filename = executor.getLogFile() lines = [] if filename and os.path.exists(filename): f = file(filename) lines = f.readlines() return lines #=========================================================================== def getNumActiveProcs(self): activeProcs = 0 for key in self.getExecutors(): executor = self.getExecutor(key) if executor and executor.isActive(): activeProcs += 1 return activeProcs