예제 #1
0
    def test__send(self):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac

        # test sending in params
        self.ch._send(NameTrio('xp', 'namen'), 'daten')

        # get our props
        self.assertTrue(ac.basic_publish.called)
        self.assertIn('exchange', ac.basic_publish.call_args[1])
        self.assertIn('routing_key', ac.basic_publish.call_args[1])
        self.assertIn('body', ac.basic_publish.call_args[1])
        self.assertIn('immediate', ac.basic_publish.call_args[1])
        self.assertIn('mandatory', ac.basic_publish.call_args[1])
        self.assertIn('properties', ac.basic_publish.call_args[1])

        props = ac.basic_publish.call_args[1].get('properties')
        self.assertIsInstance(props, BasicProperties)
        self.assertTrue(hasattr(props, 'headers'))
        self.assertEquals(props.headers, {})

        # try another call to _send with a header
        self.ch._send(NameTrio('xp', 'namen'),
                      'daten',
                      headers={'custom': 'val'})

        # make sure our property showed up
        props = ac.basic_publish.call_args[1].get('properties')
        self.assertIn('custom', props.headers)
        self.assertEquals(props.headers['custom'], 'val')
예제 #2
0
파일: exchange.py 프로젝트: swarbhanu/pyon
    def __init__(self, exchange_manager, exchange, exchange_type='topic', durable=False, auto_delete=True):
        XOTransport.__init__(self, exchange_manager=exchange_manager)
        NameTrio.__init__(self, exchange=exchange)

        self._xs_exchange_type = exchange_type
        self._xs_durable       = durable
        self._xs_auto_delete   = auto_delete
예제 #3
0
파일: exchange.py 프로젝트: ooici-dm/pyon
    def __init__(self, exchange_manager, exchange, exchange_type='topic', durable=False, auto_delete=True):
        XOTransport.__init__(self, exchange_manager=exchange_manager)
        NameTrio.__init__(self, exchange=exchange)

        self._xs_exchange_type = exchange_type
        self._xs_durable       = durable
        self._xs_auto_delete   = auto_delete
예제 #4
0
    def test__send(self):
        transport = Mock()
        transport.channel_number = sentinel.channel_number
        self.ch.on_channel_open(transport)

        # test sending in params
        self.ch._send(NameTrio('xp', 'namen'), 'daten')

        # get our props
        self.assertTrue(transport.publish_impl.called)
        self.assertIn('exchange', transport.publish_impl.call_args[1])
        self.assertIn('routing_key', transport.publish_impl.call_args[1])
        self.assertIn('body', transport.publish_impl.call_args[1])
        self.assertIn('immediate', transport.publish_impl.call_args[1])
        self.assertIn('mandatory', transport.publish_impl.call_args[1])
        self.assertIn('properties', transport.publish_impl.call_args[1])

        props = transport.publish_impl.call_args[1].get('properties')
        self.assertEquals(props, {})

        # try another call to _send with a header
        self.ch._send(NameTrio('xp', 'namen'),
                      'daten',
                      headers={'custom': 'val'})

        # make sure our property showed up
        props = transport.publish_impl.call_args[1].get('properties')
        self.assertIn('custom', props)
        self.assertEquals(props['custom'], 'val')
예제 #5
0
파일: exchange.py 프로젝트: daf/pyon
    def __init__(self, exchange_manager, priviledged_transport, name, xs, durable=None, auto_delete=None):
        XOTransport.__init__(self, exchange_manager=exchange_manager, priviledged_transport=priviledged_transport)
        NameTrio.__init__(self, exchange=None, queue=name)

        self._xs             = xs

        if durable is not None:     self._xn_durable = durable
        if auto_delete is not None: self._xn_auto_delete = auto_delete
예제 #6
0
파일: exchange.py 프로젝트: ooici-dm/pyon
    def __init__(self, exchange_manager, name, xs, xptype=None):
        xptype = xptype or 'ttree'

        XOTransport.__init__(self, exchange_manager=exchange_manager)
        NameTrio.__init__(self, exchange=name)

        self._xs = xs
        self._xptype = xptype
예제 #7
0
파일: exchange.py 프로젝트: ooici-dm/pyon
    def __init__(self, exchange_manager, name, xs, durable=None, auto_delete=None):
        XOTransport.__init__(self, exchange_manager=exchange_manager)
        NameTrio.__init__(self, exchange=None, queue=name)

        self._xs = xs

        if durable:     self._xn_durable        = durable
        if auto_delete: self._xn_auto_delete    = auto_delete
예제 #8
0
파일: exchange.py 프로젝트: ooici-dm/pyon
    def __init__(self, exchange_manager, name, xs, xptype=None):
        xptype = xptype or 'ttree'

        XOTransport.__init__(self, exchange_manager=exchange_manager)
        NameTrio.__init__(self, exchange=name)

        self._xs        = xs
        self._xptype    = xptype
예제 #9
0
파일: exchange.py 프로젝트: swarbhanu/pyon
    def __init__(self, exchange_manager, name, xs, durable=None, auto_delete=None):
        XOTransport.__init__(self, exchange_manager=exchange_manager)
        NameTrio.__init__(self, exchange=None, queue=name)

        self._xs = xs

        if durable is not None:     self._xn_durable        = durable
        if auto_delete is not None: self._xn_auto_delete    = auto_delete
예제 #10
0
파일: exchange.py 프로젝트: mkl-/scioncc
    def __init__(self, exchange_manager, privileged_transport, node, name, xs, xptype=None):
        xptype = xptype or "ttree"

        XOTransport.__init__(
            self, exchange_manager=exchange_manager, privileged_transport=privileged_transport, node=node
        )
        NameTrio.__init__(self, exchange=name)

        self._xs = xs
        self._xptype = xptype
예제 #11
0
    def __init__(self, exchange_manager, privileged_transport, node, name, xs, xptype=None):
        xptype = xptype or 'ttree'

        XOTransport.__init__(self,
                             exchange_manager=exchange_manager,
                             privileged_transport=privileged_transport,
                             node=node)
        NameTrio.__init__(self, exchange=name)

        self._xs        = xs
        self._xptype    = xptype
예제 #12
0
    def test_setup_listener_existing_recv_name_with_differing_name(self):
        ch = self._create_channel()

        recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding)
        ch._recv_name = recv_name

        ch.setup_listener(
            name=NameTrio(sentinel.xp, sentinel.queue, sentinel.notbinding))
        self.assertNotEquals(ch._recv_name, recv_name)

        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)
        self.assertEquals(ch._recv_name.binding, sentinel.notbinding)
예제 #13
0
파일: endpoint.py 프로젝트: ooici-dm/pyon
    def __init__(self, node=None, name=None, from_name=None, binding=None):
        BaseEndpoint.__init__(self, node=node)

        if name:
            log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead")
        self._recv_name = from_name or name

        # ensure NameTrio
        if not isinstance(self._recv_name, NameTrio):
            self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding)   # if _recv_name is tuple it takes precedence

        self._ready_event = event.Event()
        self._binding = binding
예제 #14
0
    def on_start(self):
        TransformDataProcess.on_start(self)

        # set up subscriber to *
        self._bt_sub = Subscriber(callback=lambda m, h: self.call_process(m),
                                  from_name=NameTrio(get_sys_name(),
                                                     'bench_queue', '*'))

        # spawn listener
        self._sub_gl = spawn(self._bt_sub.listen)

        # set up publisher to anything!
        self._bt_pub = Publisher(to_name=NameTrio(get_sys_name(),
                                                  str(uuid.uuid4())[0:6]))
    def _unbind_subscription(self, exchange_point, exchange_name, routing_key):

        try:
            channel = self.container.node.channel(BindingChannel)
            channel._recv_name = NameTrio(exchange_point, exchange_name)
            channel._recv_name = NameTrio(
                channel._recv_name.exchange,
                '.'.join([exchange_point, exchange_name]))
            channel._recv_binding = routing_key
            channel._destroy_binding()

        except TransportError, te:
            log.exception(
                'Raised transport error during deactivate_subscription. Assuming that it is due to deleting a binding that was already deleted and continuing!'
            )
    def _bind_subscription(self, exchange_point, exchange_name, routing_key):

        try:
            channel = self.container.node.channel(BindingChannel)
            channel.setup_listener(NameTrio(exchange_point, exchange_name),
                                   binding=routing_key)

        except TransportError:
            log.exception(
                'Caught Transport Error while creating a binding. Trying Subscriber Binding to make the queue first'
            )

            channel = self.container.node.channel(SubscriberChannel)
            channel.setup_listener(NameTrio(exchange_point, exchange_name),
                                   binding=routing_key)
예제 #17
0
    def test_listen_exception_in_handling(self):

        # make a listen loop that will return one message (to blow up in processing)
        chmock = MagicMock(spec=ListenChannel)
        chmock.accept.return_value = Mock()
        chmock.accept.return_value.recv = Mock(
            return_value=(sentinel.msg, sentinel.headers,
                          sentinel.delivery_tag))
        chmock.accept.return_value._recv_queue.qsize.return_value = 1

        nodemock = Mock(spec=NodeB)
        nodemock.channel.return_value = chmock

        recv_name = NameTrio(sentinel.ex, sentinel.queue)

        ep = ListeningBaseEndpoint(node=nodemock, from_name=recv_name)

        # make msg received error out!
        ep.create_endpoint = Mock(return_value=Mock(spec=EndpointUnit))
        ep.create_endpoint.return_value._message_received.side_effect = TestError
        ep.create_endpoint.return_value.intercept_in.return_value = (
            sentinel.msg, sentinel.headers)

        self.assertRaises(TestError, ep.listen)
        chmock.setup_listener.assert_called_once_with(recv_name,
                                                      binding=sentinel.queue)
        chmock.start_consume.assert_called_once_with()

        chmock.accept.assert_called_once_with(n=1, timeout=None)
        chmock.accept.return_value.recv.assert_called_once_with()
        ep.create_endpoint.assert_called_once_with(
            existing_channel=chmock.accept.return_value)
예제 #18
0
 def _create_accepted_channel(self, amq_chan, msg):
     send_name = NameTrio(tuple(msg[1].get('reply-to').split(',')))    # @TODO: stringify is not the best
     ch = self.BidirAcceptChannel()
     ch._recv_name = self._recv_name     # for debugging only
     ch.attach_underlying_channel(amq_chan)
     ch.connect(send_name)
     return ch
예제 #19
0
    def test_purge(self):
        # declare both ex and queue
        self.transport.declare_exchange_impl(self.ex_name)
        self.transport.declare_queue_impl(self.queue_name)

        self.addCleanup(self.transport.delete_queue_impl, self.queue_name)
        #self.addCleanup(self.container.ex_manager.delete_exchange, self.ex_name)   #@TODO exchange AD takes care of this when delete of queue

        # declare a bind
        self.transport.bind_impl(self.ex_name, self.queue_name, self.bind_name)

        # deliver some messages
        ch = self.container.node.channel(SendChannel)
        ch._send_name = NameTrio(self.ex_name, self.bind_name)

        ch.send('one')
        ch.send('two')

        ch.close()

        # should have two messages after routing happens (non-deterministic)
        time.sleep(2)

        queue_info = self.container.ex_manager.get_queue_info(self.queue_name)
        self.assertEquals(queue_info['messages'], 2)

        # now purge it
        self.transport.purge_impl(self.queue_name)

        time.sleep(2)

        queue_info = self.container.ex_manager.get_queue_info(self.queue_name)
        self.assertEquals(queue_info['messages'], 0)
예제 #20
0
파일: endpoint.py 프로젝트: ooici-dm/pyon
    def _send(self, msg, headers=None, **kwargs):

        # could have a specified timeout in kwargs
        if 'timeout' in kwargs and kwargs['timeout'] is not None:
            timeout = kwargs['timeout']
        else:
            timeout = CFG.endpoint.receive.timeout or 10

        log.debug("RequestEndpointUnit.send (timeout: %s)", timeout)

        if not self._recv_greenlet:
            self.channel.setup_listener(NameTrio(self.channel._send_name.exchange)) # anon queue
            self.channel.start_consume()
            self.spawn_listener()

        self.response_queue = event.AsyncResult()
        self.message_received = lambda m, h: self.response_queue.set((m, h))

        BidirectionalEndpointUnit._send(self, msg, headers=headers)

        try:
            result_data, result_headers = self.response_queue.get(timeout=timeout)
        except Timeout:
            raise exception.Timeout('Request timed out (%d sec) waiting for response from %s' % (timeout, str(self.channel._send_name)))

        log.debug("Got response to our request: %s, headers: %s", result_data, result_headers)
        return result_data, result_headers
예제 #21
0
    def test_str(self):
        nt = NameTrio(sentinel.exchange, sentinel.queue, sentinel.binding)
        strnt = str(nt)

        self.assertIn(str(sentinel.exchange), strnt)
        self.assertIn(str(sentinel.queue), strnt)
        self.assertIn(str(sentinel.binding), strnt)
예제 #22
0
 def launch_benchmark(transform_number=1, primer=1, message_length=4):
     import gevent
     from gevent.greenlet import Greenlet
     from pyon.util.containers import DotDict
     from pyon.net.transport import NameTrio
     from pyon.net.endpoint import Publisher
     import uuid
     num = transform_number
     msg_len = message_length
     transforms = list()
     pids = 1
     TransformBenchTesting.message_length = message_length
     cc = Container.instance
     pub = Publisher(to_name=NameTrio(get_sys_name(),
                                      str(uuid.uuid4())[0:6]))
     for i in xrange(num):
         tbt = cc.proc_manager._create_service_instance(
             str(pids), 'tbt', 'prototype.transforms.linear',
             'TransformInPlace',
             DotDict({
                 'process': {
                     'name': 'tbt%d' % pids,
                     'transform_id': pids
                 }
             }))
         tbt.init()
         tbt.start()
         gevent.sleep(0.2)
         for i in xrange(primer):
             pub.publish(list(xrange(msg_len)))
         g = Greenlet(tbt.perf)
         g.start()
         transforms.append(tbt)
         pids += 1
예제 #23
0
        def listen(lch):
            """
            The purpose of the this listen method is to trigger waits in code below.
            By setting up a listener that subscribes to both 3 and 5, and putting received
            messages into the appropriate gevent-queues client side, we can assume that
            the channel we're actually testing with get_stats etc has had the message delivered
            too.
            """
            lch._queue_auto_delete = False
            lch.setup_listener(
                NameTrio(bootstrap.get_sys_name(), 'alternate_listener'),
                'routed.3')
            lch._bind('routed.5')
            lch.start_consume()

            while True:
                try:
                    with lch.accept() as newchan:
                        m, h, d = newchan.recv()
                        count = m.rsplit(',', 1)[-1]
                        if m.startswith('5,'):
                            self.five_events.put(int(count))
                            newchan.ack(d)
                        elif m.startswith('3,'):
                            self.three_events.put(int(count))
                            newchan.ack(d)
                        else:
                            raise StandardError("unknown message: %s" % m)

                except ChannelClosedError:
                    break
예제 #24
0
 def test_connect(self):
     self.ch.connect(NameTrio('xp', 'key'))
     self.assertTrue(hasattr(self.ch._send_name, 'exchange'))
     self.assertTrue(hasattr(self.ch._send_name, 'queue'))
     self.assertEquals(self.ch._send_name.exchange, 'xp')
     self.assertEquals(self.ch._send_name.queue, 'key')
     self.assertEquals(self.ch._exchange, 'xp')
예제 #25
0
 def test_init_tuples_both(self):
     # exchange kwarg has priority over queue kwarg
     nt = NameTrio(exchange=(sentinel.exchange1, ),
                   queue=(sentinel.exchange2, sentinel.queue))
     self.assertEquals(nt._exchange, sentinel.exchange1)
     self.assertEquals(nt._queue, None)
     self.assertEquals(nt._binding, None)
예제 #26
0
    def _setup_mock_channel(self,
                            ch_type=BidirClientChannel,
                            status_code=200,
                            error_message="no problem",
                            value="bidirmsg",
                            op=None):
        """
Sets up a mocked channel, ready for fake bidir communication.

@param ch_type Channel type the mock should spec to.
@param status_code The status code of the operation, relevant only for RR comms.
@param error_message The error message of the operation, relevant only for RR comms.
@param op The op name, relevant only for RR comms.
@param value The msg body to be returned.
"""
        ch = MagicMock(spec=ch_type())
        # set a return value for recv so we get an immediate response
        vals = [(value, {
            'status_code': status_code,
            'error_message': error_message,
            'op': op,
            'conv-id': sentinel.conv_id
        }, sentinel.delivery_tag)]

        def _ret(*args, **kwargs):
            if len(vals):
                return vals.pop()
            raise ChannelClosedError()

        ch.recv.side_effect = _ret

        # need to set a send_name for now
        ch._send_name = NameTrio('', '')

        return ch
예제 #27
0
    def test_setup_listener_existing_recv_name(self):
        ch = self._create_channel()

        recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding)
        ch._recv_name = recv_name

        ch.setup_listener()
        self.assertEquals(ch._recv_name, recv_name)
예제 #28
0
    def test_close_does_delete_if_anonymous_and_not_auto_delete(self):
        ch = SubscriberChannel()
        ch._queue_auto_delete = False
        ch._destroy_queue = Mock()
        ch._recv_name = NameTrio(sentinel.exchange, 'amq.gen-ABCD')

        ch.close_impl()
        ch._destroy_queue.assert_called_once_with()
예제 #29
0
        def every_three():
            p = self.container.node.channel(PublisherChannel)
            p._send_name = NameTrio(bootstrap.get_sys_name(), 'routed.3')
            counter = 0

            while not self.publish_three.wait(timeout=3):
                p.send('3,' + str(counter))
                counter += 1
예제 #30
0
    def test_close_does_not_delete_if_anon_but_auto_delete(self):
        ch = SubscriberChannel()
        ch._queue_auto_delete = True
        ch._destroy_queue = Mock()
        ch._recv_name = NameTrio(sentinel.exchange, 'amq.gen-ABCD')

        ch.close_impl()
        self.assertFalse(ch._destroy_queue.called)
예제 #31
0
    def test_close_does_not_delete_if_named(self):
        ch = SubscriberChannel()
        ch._queue_auto_delete = False
        ch._destroy_queue = Mock()
        ch._recv_name = NameTrio(sentinel.exchange, 'some-named-queue')

        ch.close_impl()
        self.assertFalse(ch._destroy_queue.called)
예제 #32
0
    def test_purge(self):
        transport = Mock()
        self.ch.on_channel_open(transport)
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue)

        self.ch._purge()

        self.ch._transport.purge_impl.assert_called_once_with(
            queue=sentinel.queue)
예제 #33
0
파일: exchange.py 프로젝트: mkl-/scioncc
    def __init__(
        self,
        exchange_manager,
        privileged_transport,
        node,
        exchange,
        exchange_type="topic",
        durable=False,
        auto_delete=True,
    ):
        XOTransport.__init__(
            self, exchange_manager=exchange_manager, privileged_transport=privileged_transport, node=node
        )
        NameTrio.__init__(self, exchange=exchange)

        self._xs_exchange_type = exchange_type
        self._xs_durable = durable
        self._xs_auto_delete = auto_delete
예제 #34
0
    def test_purge(self):
        self.ch._amq_chan = sentinel.amq_chan
        self.ch._transport = Mock()
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue)

        self.ch._purge()

        self.ch._transport.purge_impl.assert_called_once_with(
            sentinel.amq_chan, queue=sentinel.queue)
예제 #35
0
    def test_send(self):
        _sendmock = Mock()
        self.ch._send = _sendmock
        np = NameTrio('xp', 'key')
        self.ch.connect(np)

        self.ch.send('data', {'header': sentinel.headervalue})
        _sendmock.assert_called_once_with(
            np, 'data', headers={'header': sentinel.headervalue})
예제 #36
0
    def test_get_stats(self):
        self.ch._amq_chan = sentinel.amq_chan
        self.ch._transport = Mock()
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue)

        self.ch.get_stats()

        self.ch._transport.get_stats.assert_called_once_with(
            sentinel.amq_chan, queue=sentinel.queue)
예제 #37
0
파일: endpoint.py 프로젝트: tgiguere/pyon
    def __init__(self, node=None, name=None, from_name=None, binding=None):
        BaseEndpoint.__init__(self, node=node)

        if name:
            log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead")
        self._recv_name = from_name or name

        # ensure NameTrio
        if not isinstance(self._recv_name, NameTrio):
            self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding)   # if _recv_name is tuple it takes precedence

        self._ready_event = event.Event()
        self._binding = binding
예제 #38
0
 def __str__(self):
     return self.xn_type + "-" + NameTrio.__str__(self)
예제 #39
0
파일: endpoint.py 프로젝트: tgiguere/pyon
class ListeningBaseEndpoint(BaseEndpoint):
    """
    Establishes channel type for a host of derived, listen/react endpoint factories.
    """
    channel_type = ListenChannel

    def __init__(self, node=None, name=None, from_name=None, binding=None):
        BaseEndpoint.__init__(self, node=node)

        if name:
            log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead")
        self._recv_name = from_name or name

        # ensure NameTrio
        if not isinstance(self._recv_name, NameTrio):
            self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding)   # if _recv_name is tuple it takes precedence

        self._ready_event = event.Event()
        self._binding = binding

    def _create_channel(self, **kwargs):
        """
        Overrides the BaseEndpoint create channel to supply a transport if our recv name is one.
        """
        if isinstance(self._recv_name, BaseTransport):
            kwargs.update({'transport':self._recv_name})

        return BaseEndpoint._create_channel(self, **kwargs)

    def get_ready_event(self):
        """
        Returns an async event you can .wait() on.
        Used to indicate when listen() is ready to start listening.
        """
        return self._ready_event

    def _setup_listener(self, name, binding=None):
        self._chan.setup_listener(name, binding=binding)

    def listen(self, binding=None):
        log.debug("LEF.listen: binding %s", binding)

        binding = binding or self._binding or self._recv_name.binding

        self._ensure_node()
        kwargs = {}
        if isinstance(self._recv_name, BaseTransport):
            kwargs.update({'transport':self._recv_name})
        self._chan = self.node.channel(self.channel_type, **kwargs)

        # @TODO this does not feel right
        if isinstance(self._recv_name, BaseTransport):
            self._recv_name.setup_listener(binding, self._setup_listener)
            self._chan._recv_name = self._recv_name
        else:
            self._setup_listener(self._recv_name, binding=binding)
        self._chan.start_consume()

        # notify any listeners of our readiness
        self._ready_event.set()

        while True:
            log.debug("LEF: %s blocking, waiting for a message" % str(self._recv_name))
            try:
                newchan = self._chan.accept()
                msg, headers, delivery_tag = newchan.recv()

                log.debug("LEF %s received message %s, headers %s, delivery_tag %s", self._recv_name, msg, headers, delivery_tag)
                log_message(self._recv_name, msg, headers, delivery_tag)

            except ChannelClosedError as ex:
                log.debug('Channel was closed during LEF.listen')
                break

            try:
                e = self.create_endpoint(existing_channel=newchan)
                e._message_received(msg, headers)
            except Exception:
                log.exception("Unhandled error while handling received message")
                raise
            finally:
                # ALWAYS ACK
                newchan.ack(delivery_tag)

    def close(self):
        BaseEndpoint.close(self)
        self._chan.close()
예제 #40
0
파일: endpoint.py 프로젝트: swarbhanu/pyon
class ListeningBaseEndpoint(BaseEndpoint):
    """
    Establishes channel type for a host of derived, listen/react endpoint factories.
    """
    channel_type = ListenChannel

    class MessageObject(object):
        """
        Received message wrapper.

        Contains a body, headers, and a delivery_tag. Internally used by listen, the
        standard method used by ListeningBaseEndpoint, but will be returned to you
        if you use get_one_msg or get_n_msgs. If using the latter, you are responsible
        for calling ack or reject.

        make_body calls the endpoint's interceptor incoming stack - this may potentially
        raise an IonException in normal program flow. If this happens, the body/headers
        attributes will remain None and the error attribute will be set. Calling route()
        will be a no-op, but ack/reject work.
        """
        def __init__(self, msgtuple, ch, e):
            self.channel = ch
            self.endpoint = e

            self.raw_body, self.raw_headers, self.delivery_tag = msgtuple
            self.body = None
            self.headers = None
            self.error = None

        def make_body(self):
            """
            Runs received raw message through the endpoint's interceptors.
            """
            try:
                self.body, self.headers = self.endpoint.intercept_in(self.raw_body, self.raw_headers)
            except IonException as ex:
                log.info("MessageObject.make_body raised an error: \n%s", traceback.format_exc(ex))
                self.error = ex

        def ack(self):
            """
            Passthrough to underlying channel's ack.

            Must call this if using get_one_msg/get_n_msgs.
            """
            self.channel.ack(self.delivery_tag)

        def reject(self, requeue=False):
            """
            Passthrough to underlying channel's reject.

            Must call this if using get_one_msg/get_n_msgs.
            """
            self.channel.reject(self.delivery_tag, requeue=requeue)

        def route(self):
            """
            Call default endpoint's _message_received, where business logic takes place.

            For instance, a Subscriber would call the registered callback, or an RPCServer would
            call the Service's operation.

            You are likely not to use this if using get_one_msg/get_n_msgs.
            """
            if self.error is not None:
                log.info("Refusing to route a MessageObject with an error")
                return

            self.endpoint._message_received(self.body, self.headers)

    def __init__(self, node=None, name=None, from_name=None, binding=None):
        BaseEndpoint.__init__(self, node=node)

        if name:
            log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead")
        self._recv_name = from_name or name

        # ensure NameTrio
        if not isinstance(self._recv_name, NameTrio):
            self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding)   # if _recv_name is tuple it takes precedence

        self._ready_event = event.Event()
        self._binding = binding
        self._chan = None

    def _create_channel(self, **kwargs):
        """
        Overrides the BaseEndpoint create channel to supply a transport if our recv name is one.
        """
        if isinstance(self._recv_name, BaseTransport):
            kwargs.update({'transport':self._recv_name})

        return BaseEndpoint._create_channel(self, **kwargs)

    def get_ready_event(self):
        """
        Returns an async event you can .wait() on.
        Used to indicate when listen() is ready to start listening.
        """
        return self._ready_event

    def _setup_listener(self, name, binding=None):
        self._chan.setup_listener(name, binding=binding)

    def listen(self, binding=None):
        """
        Main driving method for ListeningBaseEndpoint.

        Meant to be spawned in a greenlet. This method creates/sets up a channel to listen,
        starts listening, and consumes messages in a loop until the Endpoint is closed.
        """
        #log.debug("LEF.listen")

        self.prepare_listener(binding=binding)

        # notify any listeners of our readiness
        self._ready_event.set()

        while True:
            #log.debug("LEF: %s blocking, waiting for a message", self._recv_name)
            m = None
            try:
                m = self.get_one_msg()
                m.route()       # call default handler

            except ChannelClosedError as ex:
                break
            finally:
                # ChannelClosedError will go into here too, so make sure we have a message object to ack with
                if m is not None:
                    m.ack()

    def prepare_listener(self, binding=None):
        """
        Creates a channel, prepares it, and begins consuming on it.

        Used by listen.
        """

        #log.debug("LEF.prepare_listener: binding %s", binding)

        self.initialize(binding=binding)
        self.activate()

    def initialize(self, binding=None):
        """
        Creates a channel and prepares it for use.

        After this, the endpoint is inthe ready state.
        """
        binding = binding or self._binding or self._recv_name.binding

        self._ensure_node()
        kwargs = {}
        if isinstance(self._recv_name, BaseTransport):
            kwargs.update({'transport':self._recv_name})
        self._chan = self.node.channel(self.channel_type, **kwargs)

        # @TODO this does not feel right
        if isinstance(self._recv_name, BaseTransport):
            self._recv_name.setup_listener(binding, self._setup_listener)
            self._chan._recv_name = self._recv_name
        else:
            self._setup_listener(self._recv_name, binding=binding)

    def activate(self):
        """
        Begins consuming.

        You must have called initialize first.
        """
        assert self._chan
        self._chan.start_consume()

    def deactivate(self):
        """
        Stops consuming.

        You must have called initialize and activate first.
        """
        assert self._chan
        self._chan.stop_consume()       # channel will yell at you if this is invalid

    def get_stats(self):
        """
        Returns a tuple of the form (# ready messages, # of consumers).

        This endpoint must have been initialized in order to have a valid queue
        to work on.

        Passes down to the channel layer to get this info.
        """
        assert self._chan
        return self._chan.get_stats()

    def _get_n_msgs(self, num=1, timeout=None):
        """
        Internal method to accept n messages, create MessageObject wrappers, return them.

        INBOUND INTERCEPTORS ARE PROCESSED HERE. If the Interceptor stack throws an IonException,
        the response will be sent immediatly and the MessageObject returned to you will not have
        body/headers set and will have error set. You should expect to check body/headers or error.
        """
        assert self._chan, "_get_n_msgs: needs the endpoint to have been initialized"

        mos = []
        newch = self._chan.accept(n=num, timeout=timeout)
        for x in xrange(newch._recv_queue.qsize()):
            mo = self.MessageObject(newch.recv(), newch, self.create_endpoint(existing_channel=newch))
            mo.make_body()      # puts through EP interceptors
            mos.append(mo)
            log_message("MESSAGE RECV >>> RPC-request", mo.raw_body, mo.raw_headers, self._recv_name, mo.delivery_tag, is_send=False)

        return mos

    def get_one_msg(self, timeout=None):
        """
        Receives one message.

        Blocks until one message is received, or the optional timeout is reached.

        INBOUND INTERCEPTORS ARE PROCESSED HERE. If the Interceptor stack throws an IonException,
        the response will be sent immediatly and the MessageObject returned to you will not have
        body/headers set and will have error set. You should expect to check body/headers or error.

        @raises ChannelClosedError  If the channel has been closed.
        @raises Timeout             If no messages available when timeout is reached.
        @returns                    A MessageObject.
        """
        mos = self._get_n_msgs(num=1, timeout=timeout)
        return mos[0]

    def get_n_msgs(self, num, timeout=None):
        """
        Receives num messages.

        INBOUND INTERCEPTORS ARE PROCESSED HERE. If the Interceptor stack throws an IonException,
        the response will be sent immediatly and the MessageObject returned to you will not have
        body/headers set and will have error set. You should expect to check body/headers or error.

        Blocks until all messages received, or the optional timeout is reached.
        @raises ChannelClosedError  If the channel has been closed.
        @raises Timeout             If no messages available when timeout is reached.
        @returns                    A list of MessageObjects.
        """
        return self._get_n_msgs(num, timeout=timeout)

    def get_all_msgs(self, timeout=None):
        """
        Receives all available messages on the queue.

        WARNING: If the queue is not exclusive, there is a possibility this method behaves incorrectly.
        You should always pass a timeout to this method.

        Blocks until all messages received, or the optional timeout is reached.
        @raises ChannelClosedError  If the channel has been closed.
        @raises Timeout             If no messages available when timeout is reached.
        @returns                    A list of MessageObjects.
        """
        n, _ = self.get_stats()
        return self._get_n_msgs(n, timeout=timeout)

    def close(self):
        BaseEndpoint.close(self)
        self._chan.close()

    def get_stats(self):
        """
        Passthrough to channel's get_stats.
        """
        if not self._chan:
            raise EndpointError("No channel attached")

        return self._chan.get_stats()