Defining a Queue Consumer
=========================

A queue is always linked to one BrokerConnection. So we have to set it up first::

    >>> from affinitic.zamqp.connection import BrokerConnection
    >>> import grokcore.component as grok
    >>> class DummyBrokerConnection(BrokerConnection):
    ...     id = 'bar'
    ...     grok.name(id)
    >>> from affinitic.zamqp.interfaces import IBrokerConnection
    >>> from zope.component import provideUtility
    >>> conn = DummyBrokerConnection()
    >>> provideUtility(conn, IBrokerConnection, name=conn.id)

Now that we have a BrokerConnection, we can define our consumer and link it to the
connection::

    >>> from affinitic.zamqp.consumer import Consumer
    >>> class DummyConsumer(Consumer):
    ...     connection_id = 'bar'
    >>> consumer = DummyConsumer()
    >>> conn = consumer.connection
    >>> conn
    <DummyBrokerConnection object at ...>

And the connection is made once for all::

    >>> conn == consumer.connection
    True

The backend is also defined through the connection::

    >>> consumer.backend
    <carrot.backends.pyamqplib.Backend object at ...>

Consumer callbacks and the Message Translator pattern
=====================================================

Once a message is received, the message:

    1. is marked as providing the marker interface declared in the attribute ``messageInterface``
    2. is marked as providing the ``IMessage`` marker interface
    3. is adapted based on the ``IMessageWrapper`` adapter (if any)
    4. is send to all registered callbacks.

1, 2, 3 implements the Message Translator pattern (see http://www.eaipatterns.com/MessageTranslator.html) by calling an adapter.

To be able to differentiate messages, we define a simple marker interface::

    >>> from zope.interface import Interface
    >>> class IBarMessage(Interface):
    ...     "A marker interface for message coming from the bar consumer"

So let's create a simple adapter that adds a timestamp to the incoming messages marked with IBarMessage::

    >>> from zope.component import provideAdapter, adapts
    >>> from datetime import datetime
    >>> from affinitic.zamqp.message import MessageWrapper
    >>> class MessageWithTimeStamp(MessageWrapper):
    ...     adapts(IBarMessage)
    ...
    ...     @property
    ...     def incomingDate(self):
    ...         return datetime(2010, 1, 1)

    >>> provideAdapter(MessageWithTimeStamp)

We now define our consumer and specify correctly the messageInterface to use for all incoming messages::

    >>> class DummyConsumer(Consumer):
    ...     connection_id = 'bar'
    ...     messageInterface = IBarMessage
    ...     exclusive = True

    >>> consumer = DummyConsumer()

We create a dummy message which fake an incoming message coming from the broker::

    >>> class Message(object):
    ...     body = 'Hello from Message Broker'
    >>> message = Message()

The ``receive`` method on the consumer will call first the ``_markMessage`` method which will add our marker interface on the incoming message::

    >>> message = consumer._markMessage(message)
    >>> IBarMessage.providedBy(message)
    True

Then the ``receive`` method will call the ``_adaptMessage`` method that can adapt our message::

    >>> adaptedMessage = consumer._adaptMessage(message)
    >>> adaptedMessage
    <MessageWithTimeStamp object at ...>

To be able to use the consumer we must define at least one callback otherwise we raise an exception::

    >>> consumer.receive(message.body, message)
    Traceback (most recent call last):
    ...
    NotImplementedError: No consumer callbacks registered

So we define a dummy callback that print the message content::

    >>> def printMessage(message_data, message):
    ...     print '%s received on %s with body "%s"' % (message, message.incomingDate, message_data)
    >>> consumer.register_callback(printMessage)

Now each time a message is received, we adapt the message and print it::

    >>> consumer.receive(message.body, message)
    <MessageWithTimeStamp object at ...> received on 2010-01-01 00:00:00 with body "Hello from Message Broker"

Makes coverage happy. A backend can be assigned separatly

    >>> consumer.backend = 'foo'
    >>> consumer.backend
    'foo'

Interface conformance
=====================

Using ``zope.interface`` to check wheter our implementation does what it promise to implement.

    >>> from zope.interface.verify import verifyObject

Check the Consumer::

    >>> from affinitic.zamqp.interfaces import IConsumer
    >>> from affinitic.zamqp.consumer import Consumer
    >>> verifyObject(IConsumer, Consumer())
    True
