/************************************************************* * @brief Takes an incoming SML message and responds with * an appropriate response message. * * @param pConnection The connection this message came in on. * @param pIncoming The incoming message *************************************************************/ soarxml::ElementXML* KernelSML::ProcessIncomingSML(Connection* pConnection, soarxml::ElementXML* pIncomingMsg) { if (!pIncomingMsg || !pConnection) return NULL ; // Make sure only one thread is executing commands in the kernel at a time. // This is really just an insurance policy as I don't think we'll ever execute // commands on different threads within kernelSML because we // only allow one embedded connection to the kernel, but it's nice to be sure. soar_thread::Lock lock(m_pKernelMutex) ; #ifdef DEBUG // For debugging, it's helpful to be able to look at the incoming message as an XML string char* pIncomingXML = pIncomingMsg->GenerateXMLString(true) ; #endif soarxml::ElementXML* pResponse = pConnection->CreateSMLResponse(pIncomingMsg) ; // Fatal error creating the response if (!pResponse) return NULL ; // Analyze the message and find important tags AnalyzeXML msg ; msg.Analyze(pIncomingMsg) ; // Get the "name" attribute from the <command> tag char const* pCommandName = msg.GetCommandName() ; if (pCommandName) { ProcessCommand(pCommandName, pConnection, &msg, pResponse) ; } else { // The message wasn't something we recognize. if (!msg.GetCommandTag()) AddErrorMsg(pConnection, pResponse, "Incoming message did not contain a <command> tag") ; else AddErrorMsg(pConnection, pResponse, "Incoming message did not contain a name attribute in the <command> tag") ; } #ifdef DEBUG // For debugging, it's helpful to be able to look at the response as XML char* pResponseXML = pResponse->GenerateXMLString(true) ; // Set a break point on this next line if you wish to see the incoming // and outgoing as XML before they get deleted. soarxml::ElementXML::DeleteString(pIncomingXML) ; soarxml::ElementXML::DeleteString(pResponseXML) ; #endif return pResponse ; }
void InputListener::ProcessPendingInput(AgentSML* pAgentSML, int ) { PendingInputList* pPending = pAgentSML->GetPendingInputList() ; bool ok = true ; for (PendingInputListIter iter = pPending->begin() ; iter != pPending->end() ; iter = pPending->erase(iter)) { soarxml::ElementXML* pInputMsg = *iter ; // Analyze the message and find important tags AnalyzeXML msg ; msg.Analyze(pInputMsg) ; // Get the "name" attribute from the <command> tag char const* pCommandName = msg.GetCommandName() ; // Only input commands should be stored in the pending input list (void)pCommandName; // silences warning in release mode assert(!strcmp(pCommandName, "input")) ; soarxml::ElementXML const* pCommand = msg.GetCommandTag() ; int nChildren = pCommand->GetNumberChildren() ; soarxml::ElementXML wmeXML(NULL) ; soarxml::ElementXML* pWmeXML = &wmeXML ; if (kDebugInput) PrintDebugFormat("--------- %s starting input ----------", pAgentSML->GetName()) ; for (int i = 0 ; i < nChildren ; i++) { pCommand->GetChild(&wmeXML, i) ; // Ignore tags that aren't wmes. if (!pWmeXML->IsTag(sml_Names::kTagWME)) continue ; // Find out if this is an add or a remove char const* pAction = pWmeXML->GetAttribute(sml_Names::kWME_Action) ; if (!pAction) continue ; bool add = IsStringEqual(pAction, sml_Names::kValueAdd) ; bool remove = IsStringEqual(pAction, sml_Names::kValueRemove) ; if (add) { char const* pID = pWmeXML->GetAttribute(sml_Names::kWME_Id) ; // May be a client side id value (e.g. "o3" not "O3") char const* pAttribute = pWmeXML->GetAttribute(sml_Names::kWME_Attribute) ; char const* pValue = pWmeXML->GetAttribute(sml_Names::kWME_Value) ; char const* pType = pWmeXML->GetAttribute(sml_Names::kWME_ValueType) ; // Can be NULL (=> string) char const* pTimeTag = pWmeXML->GetAttribute(sml_Names::kWME_TimeTag) ; // May be a client side time tag (e.g. -3 not +3) // Set the default value if (!pType) pType = sml_Names::kTypeString ; // Check we got everything we need if (!pID || !pAttribute || !pValue || !pTimeTag) continue ; if (kDebugInput) { PrintDebugFormat("%s Add %s ^%s %s (type %s tag %s)", pAgentSML->GetName(), pID, pAttribute, pValue, pType, pTimeTag) ; } // Add the wme ok = pAgentSML->AddInputWME( pID, pAttribute, pValue, pType, pTimeTag) && ok ; } else if (remove) { char const* pTimeTag = pWmeXML->GetAttribute(sml_Names::kWME_TimeTag) ; // May be (will be?) a client side time tag (e.g. -3 not +3) if (kDebugInput) { PrintDebugFormat("%s Remove tag %s", pAgentSML->GetName(), pTimeTag) ; } // Remove the wme ok = pAgentSML->RemoveInputWME(pTimeTag) && ok ; } } delete pInputMsg ; } std::list<DirectInputDelta>* pBufferedDirect = pAgentSML->GetBufferedDirectList(); for (std::list<DirectInputDelta>::iterator iter = pBufferedDirect->begin() ; iter != pBufferedDirect->end() ; iter = pBufferedDirect->erase(iter)) { DirectInputDelta& delta = *iter; switch (delta.type) { case DirectInputDelta::kRemove: pAgentSML->RemoveInputWME(delta.clientTimeTag); break; case DirectInputDelta::kAddString: pAgentSML->AddStringInputWME(delta.id.c_str(), delta.attribute.c_str(), delta.svalue.c_str(), delta.clientTimeTag); break; case DirectInputDelta::kAddInt: pAgentSML->AddIntInputWME(delta.id.c_str(), delta.attribute.c_str(), delta.ivalue, delta.clientTimeTag); break; case DirectInputDelta::kAddDouble: pAgentSML->AddDoubleInputWME(delta.id.c_str(), delta.attribute.c_str(), delta.dvalue, delta.clientTimeTag); break; case DirectInputDelta::kAddId: pAgentSML->AddIdInputWME(delta.id.c_str(), delta.attribute.c_str(), delta.svalue.c_str(), delta.clientTimeTag); break; default: assert(false); break; } } }