fipa_acl  1.4
Public Member Functions | List of all members
fipa::acl::ConversationMonitor Class Reference

This library provides a statemachine to monitor a message flow based on performatives. The conversation monitor is capable of monitoring the conversation based on the protocol specified in the messages. There are scxml documents specifying how these protocols are defined. Protocols may contain subprotocols, which is partially supported. More...

#include <conversation_monitor.h>

Public Member Functions

 ConversationMonitor (const AgentID &self, const std::string &protocolDirectory="")
 
virtual ~ConversationMonitor ()
 
ConversationPtr updateConversation (const fipa::acl::ACLMessage &msg)
 
ConversationPtr startConversation (const std::string &topic)
 
bool removeConversation (const fipa::acl::ConversationID &conversationId)
 
ConversationPtr getConversation (const fipa::acl::ConversationID &conversationId)
 
ConversationPtr getOrCreateConversation (const fipa::acl::ConversationID &conversationId)
 
void cleanup ()
 
std::vector< fipa::acl::ConversationIDgetActiveConversations ()
 

Detailed Description

This library provides a statemachine to monitor a message flow based on performatives. The conversation monitor is capable of monitoring the conversation based on the protocol specified in the messages. There are scxml documents specifying how these protocols are defined. Protocols may contain subprotocols, which is partially supported.

The following sections provide an overview how to use the monitor and which constraints it has.

Examples

To verify a conversation, one could do the following:

ConversationMonitor monitor (selfAgentId);
ConversationPtr convPtr = monitor.startConversation("myTopic");
ACLMessage myMsg(ACLMessage::INFORM);
// Continue creating message, e.g. using inform protocol
myMsg.setProtocol("inform");
// ...
convPtr->update(myMsg);
if(convPtr->hasEnded())
{
    // ...
}

If the conversation's protocol has subprotocols, at the point before starting a subProtocol, this becomes necessary:

// ...
convPtr->setNumberOfSubConversations(n);
// where n is the number of subconversations the agent plans to start.

If one wishes to be notified of changes to a conversation, one can use the following after obtaining a ConversationPtr:

ConversationObserverPtr observer(new ConversationObserver());
convPtr->addObserver(observer);
// Method A:
conversation::Event event = observer->waitForNextEvent();
// ...

// Method B:
conversation::Event event;
if(observer->hasEvents() && observer->getNextEvent(event))
{
    // ...
}

Constraints

At the moment, to handle subprotocols correctly a few constraints apply. If the agents to not obey these rules, the monitoring will fail.

Definition at line 75 of file conversation_monitor.h.

Constructor & Destructor Documentation

fipa::acl::ConversationMonitor::ConversationMonitor ( const AgentID self,
const std::string &  protocolDirectory = "" 
)

Construct the conversation monitor using the system configuration object which for example holds the name of the agent

Parameters
selfAgendID of the current agent
protocolDirectoryDirectory of interaction protocols

Definition at line 7 of file conversation_monitor.cpp.

8  : mSelf(self)
9 {
10  LOG_DEBUG("Creating conversation monitor for agent: '%s'", self.getName().c_str());
11  if(!protocolDirectory.empty())
12  {
13  LOG_DEBUG("Setting protocol resource directory: '%s'",protocolDirectory.c_str());
15  }
16 }
static void setProtocolResourceDir(const std::string &resourceDir)
fipa::acl::ConversationMonitor::~ConversationMonitor ( )
virtual

Default deconstructor

Definition at line 18 of file conversation_monitor.cpp.

19 {}

Member Function Documentation

void fipa::acl::ConversationMonitor::cleanup ( )

Cleanup all conversations, that ended

Definition at line 93 of file conversation_monitor.cpp.

94 {
95  LOG_DEBUG_S << "Cleaning up conversation monitor.";
96  boost::unique_lock<boost::mutex> lock(mMutex);
97 
98  std::map<fipa::acl::ConversationID, ConversationPtr>::iterator it = mActiveConversations.begin();
99  std::vector<fipa::acl::ConversationID> endedConversations;
100  std::vector<fipa::acl::ConversationID>::iterator eit;
101 
102  // If conversation has ended move from active conversation to ended conversation after detaching
103  // any existing observers
104  for(; it != mActiveConversations.end(); ++it)
105  {
106  LOG_DEBUG_S << "Cleaning up conversation monitor: Processing conversation " << it->first;
107  ConversationPtr conversation = it->second;
108  assert(it->second);
109  if(conversation->hasEnded())
110  {
111  LOG_DEBUG_S << "Detaching observers from ended conversation " << it->first;
112  conversation->detachObservers();
113  endedConversations.push_back(it->first);
114  }
115  }
116 
117  LOG_DEBUG_S << "Erasing ended conversations from active conversations.";
118  for( eit = endedConversations.begin(); eit != endedConversations.end(); ++eit)
119  {
120  LOG_DEBUG_S << "Erasing ended conversation " << *eit << " from active conversations.";
121  mActiveConversations.erase(*eit);
122  }
123 }
boost::shared_ptr< Conversation > ConversationPtr
Definition: conversation.h:408
std::vector< fipa::acl::ConversationID > fipa::acl::ConversationMonitor::getActiveConversations ( )

Get a list of conversation ids of all active conversations

Returns
List of conversation ids currently active conversations

Definition at line 125 of file conversation_monitor.cpp.

126 {
127  boost::unique_lock<boost::mutex> lock(mMutex);
128  std::map<fipa::acl::ConversationID, ConversationPtr>::iterator it = mActiveConversations.begin();
129  std::vector<fipa::acl::ConversationID> activeConversations;
130 
131  for(; it != mActiveConversations.end(); it++)
132  {
133  activeConversations.push_back(it->first);
134  }
135 
136  return activeConversations;
137 }
ConversationPtr fipa::acl::ConversationMonitor::getConversation ( const fipa::acl::ConversationID conversationId)

Get conversation associated with a certain conversation id User has to verify that id of conversation is unqual to an empty string

Definition at line 66 of file conversation_monitor.cpp.

67 {
68  // get conversation associated with command of uuid
69  boost::unique_lock<boost::mutex> lock(mMutex);
70  std::map<fipa::acl::ConversationID, ConversationPtr>::iterator it = mActiveConversations.find(conversationId);
71  if(it != mActiveConversations.end())
72  return it->second;
73 
74  return ConversationPtr();
75 }
boost::shared_ptr< Conversation > ConversationPtr
Definition: conversation.h:408
ConversationPtr fipa::acl::ConversationMonitor::getOrCreateConversation ( const fipa::acl::ConversationID conversationId)

Get conversation associated with a certain conversation id or create a new one if it does not exist yet

Definition at line 78 of file conversation_monitor.cpp.

79 {
80  // get conversation associated with comman of uuid
81  boost::unique_lock<boost::mutex> lock(mMutex);
82  std::map<fipa::acl::ConversationID, ConversationPtr>::iterator it = mActiveConversations.find(conversationId);
83  if(it != mActiveConversations.end())
84  return it->second;
85 
86  // create if it does not exist
87  ConversationPtr conversation(new Conversation(mSelf.getName(), conversationId));
88  mActiveConversations.insert(std::pair<fipa::acl::ConversationID, ConversationPtr>(conversationId, conversation));
89  LOG_INFO("Create new conversation '%p' with conversation id '%s'", this, conversationId.c_str());
90  return conversation;
91 }
boost::shared_ptr< Conversation > ConversationPtr
Definition: conversation.h:408
const std::string & getName() const
setter and getter methods for all fields; they do not result in deep-copies assignments/retreivals, but this can be easily changed if needed through the overloaded operator which do
Definition: agent_id.h:90
bool fipa::acl::ConversationMonitor::removeConversation ( const fipa::acl::ConversationID conversationId)

Close a conversation with the provided conversationId

Definition at line 50 of file conversation_monitor.cpp.

51 {
52  boost::unique_lock<boost::mutex> lock(mMutex);
53  bool success = mActiveConversations.erase(conversationId);
54  return success;
55 }
ConversationPtr fipa::acl::ConversationMonitor::startConversation ( const std::string &  topic)

Start a conversation without a message - this is required for internal requests refer to OutgoingMessageHandler::operator()() The id will be automatically generated at construction time of Conversation and extended by the topic if required

Parameters
topicTopic to add to the automatically generated conversation id
Returns
Pointer to the created conversation

Definition at line 57 of file conversation_monitor.cpp.

58 {
59  boost::unique_lock<boost::mutex> lock(mMutex);
60  // Start conversation with this agent as owner
61  ConversationPtr conversation(new Conversation(mSelf.getName(), Conversation::generateConversationID(topic) ));
62  mActiveConversations.insert(std::pair<std::string, ConversationPtr>(conversation->getConversationId(), conversation));
63  return conversation;
64 }
static fipa::acl::ConversationID generateConversationID(const std::string &topic="")
boost::shared_ptr< Conversation > ConversationPtr
Definition: conversation.h:408
const std::string & getName() const
setter and getter methods for all fields; they do not result in deep-copies assignments/retreivals, but this can be easily changed if needed through the overloaded operator which do
Definition: agent_id.h:90
ConversationPtr fipa::acl::ConversationMonitor::updateConversation ( const fipa::acl::ACLMessage msg)

When an internal message has been generated as a response or as an initiation of a conversation update the conversation monitor using this function

Parameters
theoutgoing message
Returns
pointer to the conversation
Exceptions
InvalidOperationif conversation does not exist this message
ProtocolErrorif conversation cannot consume the message due to an invalid protocol flow

Definition at line 21 of file conversation_monitor.cpp.

22 {
23  boost::unique_lock<boost::mutex> lock(mMutex);
24  std::map<std::string, ConversationPtr>::iterator it;
25  std::string conversationId = msg.getConversationID();
26  it = mActiveConversations.find(conversationId);
27  // update if conversation already exists
28  if(it != mActiveConversations.end())
29  {
30  bool conversationEnded = false;
31  try {
32  conversationEnded = it->second->hasEnded();
33  } catch(const std::runtime_error& e)
34  {}
35 
36  if(conversationEnded)
37  {
38  std::string errorMsg = "Trying to update already completed conversation: " + conversationId + " performative: '" + msg.getPerformative() + "' content: '" + msg.getContent() + "'";
39  throw conversation::InvalidOperation(errorMsg);
40  } else {
41  LOG_INFO("Update existing conversation '%p' with conversation id '%s'", this, it->second->getConversationId().c_str());
42  it->second->update(msg);
43  return it->second;
44  }
45  }
46 
47  throw conversation::InvalidOperation("Can only update an existing conversation. Possibly the corresponding conversation did already end and this message does not conform to the respective protocol");
48 }
std::string getContent() const
Definition: acl_message.h:294
std::string getPerformative() const
Definition: acl_message.h:139
std::string getConversationID() const
Definition: acl_message.h:227

The documentation for this class was generated from the following files: