def __init__(self, participant): self.participant = participant self.conversation_monitor = ConversationMonitor() self.message_adapter = AMQPConversationMessageAdapter() self.invitations = {} self.gateway = ExchangeGateway() self.monitor_enabled = True
class AMQPMessageAdapterTests(unittest.TestCase): def setUp(self): self.message_adapter = AMQPConversationMessageAdapter() def test_from_conversation_msg(self): conv_msg = ConversationMessage(cid=1234, label='Order', content='Hello Worlds', sender_role='seller', receiver_role='buyer') expected_result = "12340006seller0005buyer0005Order0012Hello Worlds0000" actual_result = self.message_adapter.from_converastion_msg(conv_msg) self.assertEqual(actual_result, expected_result) def test_to_conversation_msg(self): row_msg = "12340006seller0005buyer0005Order0012Hello Worlds0000" expected_result = ConversationMessage(cid=1234, label='Order', content='Hello Worlds', sender_role='seller', receiver_role='buyer') actual_result = self.message_adapter.to_conversation_msg(row_msg) self.assertEqual(actual_result.__dict__, expected_result.__dict__) def test_from_invitation_msg(self): inv_msg = Invitation(cid=1234, participant='', role="seller", local_capability="Ala Bala") expected_result = "12340003Adm0006seller0003inv0008Ala Bala00000000" actual_result = self.message_adapter.from_invitation_msg(inv_msg) self.assertEqual(actual_result, expected_result) def test_to_invitation_msg(self): expected_result = Invitation(cid=1234, participant='', role="seller", local_capability="Ala Bala") raw_msg = "12340003Adm0006seller0003inv0008Ala Bala0000" actual_result = self.message_adapter.to_invitation_msg(raw_msg) self.assertEqual(actual_result.__dict__, expected_result.__dict__)
class ExternalMonitor(object): DEFAULT_MONITOR_PORT = 5673 messageAdapter = AMQPConversationMessageAdapter() protocolProvider = DefaultProtocolProvider() def __init__(self, host, port): self.monitor = Monitor(self.protocolProvider) self.connection = pika.BlockingConnection( pika.ConnectionParameters(host='localhost')) self.channel = self.connection.channel() def add_conversation(self, convID, protocolID, initiatre): self.monitor.on_create_conversation(convID, protocolID) roles = self.protocolProvider.get_roles_by_protocolID(protocolID) for role in roles: # 3.1 create queues with queue_name = role, this are queue for the invitations invitationQueueName = Invitation.invitation_queue_name( convID, role) self.channel.queue_declare(queue=invitationQueueName) self.channel.basic_consume(self.on_receive_invitation, queue=invitationQueueName, no_ack=True) self.channel.start_consuming() def on_receive_invitation(self, msg): invitation = self.messageAdapter(msg) self.monitor.on_incoming_invitations(invitation) self.monitor.on_accept_invitation(invitation) # Start listening on this participant queue #invitationQueueName = invitation.getQueueName() self.channel.basic_consume(self.on_receive_msg, queue=invitation.getQueueName) def on_receive_msg(self, msg): convMsg = self.messageAdapter.to_conversation_msg(msg) try: if (convMsg.LocalType == LocalType.RESV): self.monitor.check_incoming_msg(convMsg) else: self.monitor.check_outgoing_msg(convMsg) self.forwardMessage(msg, ) except Exception: self.process_wrong_message(convMsg) def forward_message(self, exchangeName, routingKey, msg): self.channel.basic_publish(exchange=exchangeName, routing_key=routingKey, body=msg) def process_wrong_message(self, convMsg): print "Help. I receive wrong message." def set_message_adapter(self, messageAdapter): self.messageAdapter = messageAdapter
def __init__(self, role, participant, participants_config = None, is_monitorable = False): # Participant attributes self.role = str.lower(role) self.participant = str.lower(participant) # Communication related #self.cid = str(uuid.uuid4()) self.adapter = AMQPConversationMessageAdapter() self.invitation_queue = self.participant #Protocol related self.participants_description = participants_config if participants_config else None self.protocol = None interrupt_msg = None interrup_callback = None #TODO: Fix me!!! self.is_monitorable = is_monitorable self.configure_invitation_bindings()
def __init__(self, cid, role, participant, interactions, lt_file, start_conversation=None): # Participant attributes self.role = str.lower(role) self.participant = str.lower(participant) self.cid = cid self.lt_file = lt_file # Communication related self.adapter = AMQPConversationMessageAdapter() #self.queue_name = str.lower("%s_%s" %(self.participant,self.role)) self.invitation_queue = self.participant self.interactions = interactions self.messages = self.create_messages_from_interactions(interactions) self.next_interaction = 0 #If this is the conversation initiator self.start_conversation = start_conversation self.conversation = None
class ConversationInterceptor(object): DEFAULT_EXCHANGE = '' RESEND = 'RESEND' def __init__(self, participant): self.participant = participant self.conversation_monitor = ConversationMonitor() self.message_adapter = AMQPConversationMessageAdapter() self.invitations = {} self.gateway = ExchangeGateway() self.monitor_enabled = True def start(self): # received all invitations for the participant and forward them to the participant queue self.gateway.start_forwarding( self.DEFAULT_EXCHANGE, #source_exchange self.participant, #destination_exchange self.participant, #source_binding self.on_incoming_invitation, #interceptor self.participant) #source_queue_name self.gateway.consume(self.participant) self.__handle_accept_invitation() """ on_incoming_invitations is meant to be used for checking of send_invitation, check when an invitation arrive, not when it is accepted In the current setting receiving an invitation means accepting it. """ def on_incoming_invitation(self, ch, method, properties, body): # in invitation print "on_incoming_invitation: %s" % (self.participant) invitation = self.message_adapter.to_invitation_msg(body) if self.monitor_enabled: self.conversation_monitor.on_incoming_invitations(invitation) self.invitations.setdefault(self.participant, invitation) # callback_queue properties.reply_to = self.participant return (self.RESEND, method, properties, True, None) def on_outgoing_msg(self, ch, method, properties, body): print 'on_outgoing_msg' conv_msg = self.message_adapter.to_conversation_msg(body) monitor_check = self.conversation_monitor.check_outgoing_msg result = self.__on_msg_intercept(monitor_check, conv_msg) print 'Result from on_outgoing_msg:%s' % (result) return (result, method, properties, False, None) def on_incoming_msg(self, ch, method, properties, body): print 'on_incoming_msg' conv_msg = self.message_adapter.to_conversation_msg(body) monitor_check = self.conversation_monitor.check_incoming_msg result = self.__on_msg_intercept(monitor_check, conv_msg) return (result, method, properties, False, None) def __handle_accept_invitation(self): print "_handle_accept_invitation: exchange: %s" % self.participant invitation = self.invitations.get(self.participant, ) if self.monitor_enabled: self.conversation_monitor.on_accept_invitation(invitation) monitor_queue = 'monitor-%s' % (self.participant) self.gateway.start_forwarding(self.participant, invitation.cid, "*.%s.*" % (invitation.role), self.on_outgoing_msg, monitor_queue) self.gateway.start_forwarding(invitation.cid, self.participant, "*.*.%s" % (invitation.role), self.on_incoming_msg, monitor_queue) self.gateway.consume(monitor_queue) def __on_msg_intercept(self, monitor_check, conv_msg): result = self.RESEND if (conv_msg.label == 'END'): self.gateway.stop_forwarding() return 'DO_NOT_RESEND' elif self.monitor_enabled: try: if monitor_check(conv_msg): result = self.RESEND else: result = 'ERROR' except ExceptionFailAssertion as exf: print "Wro00000000000000000000000000000000000000000ng message for assertions" result = 'ERROR' except ExceptionFSM as exa: print "Wroooooooooooooooooooooooooooooooooooooooooooooooong message for FSM" result = 'ERROR' return result
class Conversation(object): def __init__(self, role, participant, participants_config = None, is_monitorable = False): # Participant attributes self.role = str.lower(role) self.participant = str.lower(participant) # Communication related #self.cid = str(uuid.uuid4()) self.adapter = AMQPConversationMessageAdapter() self.invitation_queue = self.participant #Protocol related self.participants_description = participants_config if participants_config else None self.protocol = None interrupt_msg = None interrup_callback = None #TODO: Fix me!!! self.is_monitorable = is_monitorable self.configure_invitation_bindings() @classmethod def join(cls, configuration, self_role, participant, is_originator = False, is_monitorable = False): conversation = Conversation(self_role, participant, configuration, is_monitorable) conversation.__establish_connection() if (is_originator): conversation.cid = str(uuid.uuid4()) invitations = conversation.create_invitations() conversation.invite_self_role(invitations) conversation.invite_participants(invitations) else: conversation.receive_invitation() return conversation def send(self, other_role, label, *args): conv_msg = ConversationMessage(self.cid, label, args, self.role, other_role) msg = self.adapter.from_converastion_msg(conv_msg) print "Publishing msg to exchange:%s with binding: %s \n message: %s" %(self.exchange_name, conv_msg.get_binding(), msg) self.channel.basic_publish(exchange = self.exchange_name, routing_key = conv_msg.get_binding(), body = msg) def receive(self, role): self.received_msg = None while self.received_msg == None: method_frame, _ , body = self.channel.basic_get(queue=str.lower(self.role), no_ack = True) # It can be empty if the queue is empty so don't do anything if method_frame.NAME == 'Basic.GetEmpty': pika.log.info("Empty Basic.Get Response (Basic.GetEmpty)") # We have data else: self.received_msg = self.adapter.to_conversation_msg(body) # Acknowledge the receipt of the data print 'I have received the message!' print 'The received message is:%s' %(self.received_msg) return self.received_msg def create_invitations(self): invitations = [] [invitations.append(create_invitation(self.cid, node[1], node[0], node[2])) for node in self.participants_description] return invitations def configure_interrup(self, interaction_msg, callback): self.interrupt_msg = interaction_msg self.interrup_callback = callback def configure_invitation_bindings(self): self.invitation_exchange = self.participant if self.is_monitorable else '' def configure_bindings(self): self.exchange_name = str.lower(self.participant) if self.is_monitorable else str(self.cid) def __handle_receive(self, ch, method, properties, body): print 'In received messages!' self.received_msg = self.adapter.to_conversation_msg(body) #self.channel.stop_consuming() #TODO: Handle interrupt message, please #if (self.interrupt_msg and (self.interrupt_msg.label == self.received_msg.label)): # raise InterruptExcpetion('interrupt') def invite_self_role(self, invitations): self_invitation = [inv for inv in invitations if (inv.participant == self.participant)] if (not self_invitation): raise Exception('List of invitations does not have the participant name: %s' %(self.participant)) self_invitation = self_invitation.pop() self.send_invitation(self_invitation) self.receive_invitation() def invite_participants(self, invitations): [self.send_invitation(inv) for inv in invitations if not(inv.participant == self.participant)] def receive_invitation(self): channel= self.channel print "receive_invitation: wait on exchange:%s binding:%s" %(self.invitation_exchange, self.invitation_queue) channel.queue_declare(queue=self.invitation_queue) if not(self.invitation_exchange==''): channel.queue_bind(exchange = self.invitation_exchange, queue=self.invitation_queue, routing_key=self.invitation_queue) channel.basic_consume(self.accept_invitation, queue = self.invitation_queue, no_ack = True) self.channel.start_consuming() def accept_invitation(self, ch, method, properties, body): print "accept_invitation: %s" %(body) self.channel.stop_consuming() invitation = self.adapter.to_invitation_msg(body) awaiting_invitation = create_invitation(invitation.cid, self.role, self.participant, invitation.local_capability) # Monitor also checks the invitation if (awaiting_invitation.participant==invitation.participant): self.cid = invitation.cid self.configure_bindings() self.incoming_binding = str.lower("*.*.%s" %(self.role)) print"in accept: queue%s, exchange: %s" %(self.role, self.exchange_name) self.channel.exchange_declare(exchange = self.exchange_name, type='topic') self.channel.queue_declare(queue=str.lower(self.role)) self.channel.queue_bind(exchange=self.exchange_name, queue=str.lower(self.role), routing_key=self.incoming_binding) else: raise Exception("Invitation:%s does not match with participant awaiting invitation:%s" %(invitation.__dict__, awaiting_invitation.__dict__)) def send_invitation(self, invitation): """ We create participant queue that will handle the invitation to handle the case when the required participant has not yet started """ print "send_invitation: %s" %(invitation) self.channel.queue_declare(queue=invitation.invitation_queue_name()) msg = self.adapter.from_invitation_msg(invitation) self.channel.basic_publish(exchange = '', routing_key=invitation.invitation_queue_name(), body=msg) def __establish_connection(self): print "establish_connection %s" %(self.participant) self.connection = pika.BlockingConnection(pika.ConnectionParameters(host = 'localhost')) self.channel = self.connection.channel() def close(self): self.connection.close() def receive_async(self, role, callback): # FIX me!. I should be asynchronous self.received_msg = None self.callback = callback self.channel.basic_consume(self.__handle_async_receive, queue = str.lower(self.role), no_ack = True) self.channel.start_consuming() def __handle_async_receive(self, ch, method, properties, body): self.channel.stop_consuming() msg = self.adapter.to_conversation_msg(body) self.callback(self, msg)
def setUp(self): self.message_adapter = AMQPConversationMessageAdapter()
class BaseApp(object): def __init__(self, cid, role, participant, interactions, lt_file, start_conversation=None): # Participant attributes self.role = str.lower(role) self.participant = str.lower(participant) self.cid = cid self.lt_file = lt_file # Communication related self.adapter = AMQPConversationMessageAdapter() #self.queue_name = str.lower("%s_%s" %(self.participant,self.role)) self.invitation_queue = self.participant self.interactions = interactions self.messages = self.create_messages_from_interactions(interactions) self.next_interaction = 0 #If this is the conversation initiator self.start_conversation = start_conversation self.conversation = None def set_monitor_off(self): self.exchange_name = str(self.cid) self.invitation_exchange = '' def set_monitor_on(self): self.exchange_name = str.lower(self.participant) self.invitation_exchange = self.participant def create_messages_from_interactions(self, interactions): return [ create_conv_msg(self.cid, self.role, node[0], node[1], node[2], node[3:]) for node in interactions ] def start(self): print 'start client' self.__establish_connection() if (self.start_conversation is not None): self.conversation = self.start_conversation(self.cid) self.join() self.invite_participants() else: self.receive_invitation() self.channel.start_consuming() self.__continue_with_interactions() self.receive() def join(self): self_invitation = [ inv for inv in self.conversation.invitations if (inv.participant == self.participant) ][0] self.receive_invitation() self.send_invitation(self_invitation) self.channel.start_consuming() print "I accept the invitation" def invite_participants(self): [ self.send_invitation(inv) for inv in self.conversation.invitations if not (inv.participant == self.participant) ] def receive_invitation(self): channel = self.channel print "receive_invitation: wait on exchange:%s binding:%s" % ( self.invitation_exchange, self.invitation_queue) channel.exchange_declare(exchange=self.exchange_name, type='topic') channel.queue_declare(queue=self.invitation_queue) if not (self.invitation_exchange == ''): channel.queue_bind(exchange=self.invitation_exchange, queue=self.invitation_queue, routing_key=self.invitation_queue) channel.basic_consume(self.accept_invitation, queue=self.invitation_queue, no_ack=True) def accept_invitation(self, ch, method, properties, body): print "accept_invitation: %s" % (body) self.channel.stop_consuming() invitation = self.adapter.to_invitation_msg(body) awaiting_invitation = create_invitation(invitation.cid, self.role, self.participant, self.lt_file) # TODO: ugly way for comparison. Don't be that lazy # TODO: Add full check participant, role, local_type if (awaiting_invitation.participant == invitation.participant): self.incoming_binding = str.lower("*.*.%s" % (self.role)) print "in accept: queue%s, exchange: %s" % (self.role, self.participant) self.channel.queue_declare(queue=str.lower(self.role)) self.channel.queue_bind(exchange=self.exchange_name, queue=str.lower(self.role), routing_key=self.incoming_binding) else: raise Exception( "Invitation:%s does not match with participant awaiting invitation:%s" % (invitation.__dict__, awaiting_invitation.__dict__)) def send_invitation(self, invitation): """ We create participant queue that will handle the invitation to handle the case when the required participant has not yet started """ print "send_invitation: %s" % (invitation) self.channel.queue_declare(queue=invitation.invitation_queue_name()) msg = self.adapter.from_invitation_msg(invitation) self.channel.basic_publish( exchange='', routing_key=invitation.invitation_queue_name(), body=msg) def receive(self): self.channel.basic_consume(self.__handle_receive, queue=str.lower(self.role), no_ack=True) self.channel.start_consuming() def send(self, conv_msg): msg = self.adapter.from_converastion_msg(conv_msg) print "Publishing msg %d to exchange:%s %s" % ( self.next_interaction, self.exchange_name, msg) self.channel.basic_publish(exchange=self.exchange_name, routing_key=conv_msg.get_binding(), body=msg) self.next_interaction = self.next_interaction + 1 self.__continue_with_interactions() def __handle_receive(self, ch, method, properties, body): print 'Receive %r %s' % (body, method) self.next_interaction = self.next_interaction + 1 self.__continue_with_interactions() def __continue_with_interactions(self): if (self.next_interaction == len(self.messages)): print "I am done, ahu" self.channel.stop_consuming() #self.channel.close() #self.connection.close() return else: print "__continue_with_interactions: next_interaction: %s" % ( self.interactions[self.next_interaction]) while ((self.next_interaction < len(self.interactions)) and (self.interactions[self.next_interaction][0] == LocalType.SEND)): self.send(self.messages[self.next_interaction]) if (self.next_interaction == len(self.messages)): print "iuhu, I am done" self.channel.stop_consuming() #self.channel.close() #self.connection.close() return def __establish_connection(self): print "establish_connection %s" % (self.participant) self.connection = pika.BlockingConnection( pika.ConnectionParameters(host='localhost')) #pika.ConnectionParameters('146.169.4.50')) self.channel = self.connection.channel()