static bool AddWmeChildrenToXML( AgentSML* pAgentSML, wme* pRoot, soarxml::ElementXML* pTagResult, std::list< wme* >& traversedList ) { if (!pRoot || !pTagResult) return false ; for (wme* w = pRoot->value->id.input_wmes; w != NIL; w = w->next) { TagWme* pTagWme = OutputListener::CreateTagWme( pAgentSML, w ) ; #ifdef _DEBUG // Set a break point in here to look at the message as a string char *pStr = pTagWme->GenerateXMLString(true) ; pTagWme->DeleteString(pStr) ; #endif // Add this wme into the result pTagResult->AddChild(pTagWme) ; // If this is an identifier then add all of its children too if ( w->value->sc.common_symbol_info.symbol_type == IDENTIFIER_SYMBOL_TYPE ) { if ( std::find( traversedList.begin(), traversedList.end(), w ) == traversedList.end() ) { traversedList.push_back( w ); AddWmeChildrenToXML( pAgentSML, w, pTagResult, traversedList ); } } } return true ; }
TagWme* OutputListener::CreateTagWme(AgentSML* pAgent, wme* wme) { // Create the wme tag TagWme* pTag = new TagWme() ; // Look up the type of value this is char const* pValueType = AgentSML::GetValueType(wme->value->symbol_type) ; // For additions we send everything pTag->SetIdentifier(wme->id->to_string(true)); pTag->SetAttribute(wme->attr->to_string()); pTag->SetValue(wme->value->to_string(), pValueType) ; int64_t clientTimetag = pAgent->GetClientTimetag(wme->timetag); if (clientTimetag < 0) { // valid client timetag pTag->SetTimeTag(clientTimetag) ; } else { pTag->SetTimeTag(wme->timetag) ; } pTag->SetActionAdd() ; return pTag ; }
void DeltaList::RemoveWME(long long timeTag) { // BADBAD: We should scan the existing list of tags and if we are adding this value // just delete that tag and don't add anything to the delta list. // (This will happen if we change a value twice within a commit cycle). // We probably shouldn't do this if the object being removed is an identifier // as we might leave pending adds that are children of the object. // (Then again, that might be ok as presumably those adds would fail when we // got to the kernel, possibly saving a bunch of time in the matcher). // Create the wme tag TagWme* pTag = new TagWme() ; // For removes, we just use the time tag pTag->SetTimeTag(timeTag) ; pTag->SetActionRemove() ; m_DeltaList.push_back(pTag) ; }
void DeltaList::AddWME(WMElement* pWME) { // Create the wme tag TagWme* pTag = new TagWme() ; // For adds we send everything pTag->SetIdentifier(pWME->GetIdentifier()->GetIdentifierSymbol()) ; pTag->SetAttribute(pWME->GetAttribute()) ; std::string temp; pTag->SetValue(pWME->GetValueAsString(temp), pWME->GetValueType()) ; pTag->SetTimeTag(pWME->GetTimeTag()) ; pTag->SetActionAdd() ; m_DeltaList.push_back(pTag) ; }
void OutputListener::SendOutput(smlWorkingMemoryEventId eventId, AgentSML* pAgentSML, int /*outputMode*/, io_wme* io_wmelist) { if (eventId != smlEVENT_OUTPUT_PHASE_CALLBACK) { return ; } // Get the first listener for this event (or return if there are none) ConnectionListIter connectionIter ; if (!EventManager<smlWorkingMemoryEventId>::GetBegin(eventId, &connectionIter)) { return ; } // We need the first connection for when we're building the message. Perhaps this is a sign that // we shouldn't have rolled these methods into Connection. Connection* pConnection = *connectionIter ; // Build the SML message we're doing to send. soarxml::ElementXML* pMsg = pConnection->CreateSMLCommand(sml_Names::kCommand_Output) ; // Add the agent parameter and as a side-effect, get a pointer to the <command> tag. This is an optimization. ElementXML_Handle hCommand = pConnection->AddParameterToSMLCommand(pMsg, sml_Names::kParamAgent, pAgentSML->GetName()) ; soarxml::ElementXML command(hCommand) ; // We are passed a list of all wmes in the transitive closure (TC) of the output link. // We need to decide which of these we've already seen before, so we can just send the // changes over to the client (rather than sending the entire TC each time). // Reset everything in the current list of tags to "not in use". After we've processed all wmes, // any still in this state have been removed. for (OutputTimeTagIter iter = m_TimeTags.begin() ; iter != m_TimeTags.end() ; iter++) { iter->second = false ; } // Start with the output link itself // The kernel seems to only output this itself during link initialization // and we might be connecting up after that. Including it twice will not hurt on the client side. output_link* ol = pAgentSML->GetSoarAgent()->existing_output_links ; // This is technically a list but we only support one output link TagWme* pOutputLinkWme = OutputListener::CreateTagWme(pAgentSML, ol->link_wme) ; command.AddChild(pOutputLinkWme) ; for (io_wme* wme = io_wmelist ; wme != NIL ; wme = wme->next) { // Build the list of WME changes uint64_t timeTag = wme->timetag ; // See if we've already sent this wme to the client OutputTimeTagIter iter = m_TimeTags.find(timeTag) ; if (iter != m_TimeTags.end()) { // This is a time tag we've already sent over, so mark it as still being in use iter->second = true ; continue ; } // If we reach here we need to send the wme to the client and add it to the list // of tags currently in use. m_TimeTags[timeTag] = true ; // Create the wme tag TagWme* pTag = CreateTagIOWme(pAgentSML, wme) ; // Add it as a child of the command tag command.AddChild(pTag) ; } // At this point we check the list of time tags and any which are not marked as "in use" must // have been deleted, so we need to send them over to the client as deletions. for (OutputTimeTagIter iter = m_TimeTags.begin() ; iter != m_TimeTags.end() ;) { // Ignore time tags that are still in use. if (iter->second == true) { // We have to do manual iteration because we're deleting elements // as we go and that invalidates iterators if we're not careful. iter++ ; continue ; } uint64_t timeTag = iter->first ; // Create the wme tag TagWme* pTag = new TagWme() ; // For deletions we just send the time tag pTag->SetTimeTag(static_cast<int64_t>(timeTag)) ; pTag->SetActionRemove() ; // Add it as a child of the command tag command.AddChild(pTag) ; // Delete the entry from the time tag map m_TimeTags.erase(iter++); } // This is important. We are working with a subpart of pMsg. // If we retain ownership of the handle and delete the object // it will release the handle...deleting part of our message. command.Detach() ; smlWorkingMemoryEventId eventID = smlEVENT_OUTPUT_PHASE_CALLBACK ; #ifdef _DEBUG // Convert the XML to a string so we can look at it in the debugger char* pStr = pMsg->GenerateXMLString(true) ; #endif // Send the message out AnalyzeXML response ; SendEvent(pAgentSML, pConnection, pMsg, &response, connectionIter, GetEnd(eventID)) ; #ifdef _DEBUG pMsg->DeleteString(pStr) ; #endif // Clean up delete pMsg ; }