예제 #1
0
 def __init__(self, participant):
     self.participant = participant
     self.conversation_monitor = ConversationMonitor()
     self.message_adapter = AMQPConversationMessageAdapter()
     self.invitations = {}
     self.gateway = ExchangeGateway()
     self.monitor_enabled = True
예제 #2
0
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__)
예제 #3
0
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
예제 #4
0
 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()
예제 #5
0
    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
예제 #6
0
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
예제 #7
0
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)
예제 #8
0
 def setUp(self):
     self.message_adapter = AMQPConversationMessageAdapter()
예제 #9
0
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()