# Path: coilmq/scheduler.py
# class FavorReliableSubscriberScheduler(SubscriberPriorityScheduler):
#     """
#     A random delivery scheduler which prefers reliable subscribers.
#     """
# 
#     def choice(self, subscribers, message):
#         """
#         Choose a random connection, favoring those that are reliable from
#         subscriber pool to deliver specified message.
# 
#         @param subscribers: Collection of subscribed connections to destination. 
#         @type subscribers: C{list} of L{coilmq.server.StompConnection}
# 
#         @param message: The message to be delivered. 
#         @type message: L{stompclient.frame.Frame}
# 
#         @return: A random subscriber from the list or None if list is empty.
#         @rtype: L{coilmq.server.StompConnection}
#         """
#         if not subscribers:
#             return None
#         reliable_subscribers = [
#             s for s in subscribers if s.reliable_subscriber]
#         if reliable_subscribers:
#             return random.choice(reliable_subscribers)
#         else:
#             return random.choice(subscribers)
# 
# class RandomQueueScheduler(QueuePriorityScheduler):
#     """
#     Implementation of L{QueuePriorityScheduler} that selects a random queue from the list.
#     """
# 
#     def choice(self, queues, connection):
#         """
#         Chooses a random queue for messages to specified connection.
# 
#         @param queues: A C{dict} mapping queue name to queues (sets of frames) to which 
#                         specified connection is subscribed.
#         @type queues:  C{dict} of C{str} to C{set} of L{stompclient.frame.Frame}
# 
#         @param connection: The connection that is going to be delivered the frame(s).
#         @type connection: L{coilmq.server.StompConnection}
# 
#         @return: A random queue destination or None if list is empty.
#         @rtype: C{str}
#         """
#         if not queues:
#             return None
#         return random.choice(list(queues.keys()))
# 
# Path: coilmq/util/concurrency.py
# def synchronized(lock):
#     def synchronize(func):
#         """
#         Decorator to lock and unlock a method (Phillip J. Eby).
# 
#         This function is to be used with object instance methods; the object must
#         have a _lock variable (of type C{threading.Lock} or C{threading.RLock}).
# 
#         @param func: Method to decorate
#         @type func: C{callable}
#         """
#         @functools.wraps(func)
#         def wrapper(*args, **kwargs):
#             with lock:
#                 return func(*args, **kwargs)
#         return wrapper
#     return synchronize


import logging
import threading
import uuid
from collections import defaultdict
from coilmq.scheduler import FavorReliableSubscriberScheduler, RandomQueueScheduler
from coilmq.util.concurrency import synchronized
    @type _queues: C{dict} of C{str} to C{set} of L{coilmq.server.StompConnection}

    @ivar _pending: All messages waiting for ACK from clients.
    @type _pending: C{dict} of L{coilmq.server.StompConnection} to C{stompclient.frame.Frame}

    @ivar _transaction_frames: Frames that have been ACK'd within a transaction.
    @type _transaction_frames: C{dict} of L{coilmq.server.StompConnection} to C{dict} of C{str} to C{stompclient.frame.Frame}
    """

    def __init__(self, store, subscriber_scheduler=None, queue_scheduler=None):
        """
        @param store: The queue storage backend.
        @type store: L{coilmq.store.QueueStore}

        @param subscriber_scheduler: The scheduler that chooses which subscriber to send
                                    messages to.
        @type subscriber_scheduler: L{coilmq.scheduler.SubscriberPriorityScheduler}

        @param queue_scheduler: The scheduler that chooses which queue to select for sending
                                    backlogs for a single connection.
        @type queue_scheduler: L{coilmq.scheduler.QueuePriorityScheduler}
        """
        self.log = logging.getLogger(
            '%s.%s' % (__name__, self.__class__.__name__))

        # Use default schedulers, if they're not specified
        if subscriber_scheduler is None:
            subscriber_scheduler = FavorReliableSubscriberScheduler()

        if queue_scheduler is None:

# Path: coilmq/scheduler.py
# class FavorReliableSubscriberScheduler(SubscriberPriorityScheduler):
#     """
#     A random delivery scheduler which prefers reliable subscribers.
#     """
# 
#     def choice(self, subscribers, message):
#         """
#         Choose a random connection, favoring those that are reliable from
#         subscriber pool to deliver specified message.
# 
#         @param subscribers: Collection of subscribed connections to destination. 
#         @type subscribers: C{list} of L{coilmq.server.StompConnection}
# 
#         @param message: The message to be delivered. 
#         @type message: L{stompclient.frame.Frame}
# 
#         @return: A random subscriber from the list or None if list is empty.
#         @rtype: L{coilmq.server.StompConnection}
#         """
#         if not subscribers:
#             return None
#         reliable_subscribers = [
#             s for s in subscribers if s.reliable_subscriber]
#         if reliable_subscribers:
#             return random.choice(reliable_subscribers)
#         else:
#             return random.choice(subscribers)
# 
# class RandomQueueScheduler(QueuePriorityScheduler):
#     """
#     Implementation of L{QueuePriorityScheduler} that selects a random queue from the list.
#     """
# 
#     def choice(self, queues, connection):
#         """
#         Chooses a random queue for messages to specified connection.
# 
#         @param queues: A C{dict} mapping queue name to queues (sets of frames) to which 
#                         specified connection is subscribed.
#         @type queues:  C{dict} of C{str} to C{set} of L{stompclient.frame.Frame}
# 
#         @param connection: The connection that is going to be delivered the frame(s).
#         @type connection: L{coilmq.server.StompConnection}
# 
#         @return: A random queue destination or None if list is empty.
#         @rtype: C{str}
#         """
#         if not queues:
#             return None
#         return random.choice(list(queues.keys()))
# 
# Path: coilmq/util/concurrency.py
# def synchronized(lock):
#     def synchronize(func):
#         """
#         Decorator to lock and unlock a method (Phillip J. Eby).
# 
#         This function is to be used with object instance methods; the object must
#         have a _lock variable (of type C{threading.Lock} or C{threading.RLock}).
# 
#         @param func: Method to decorate
#         @type func: C{callable}
#         """
#         @functools.wraps(func)
#         def wrapper(*args, **kwargs):
#             with lock:
#                 return func(*args, **kwargs)
#         return wrapper
#     return synchronize


# Path: coilmq/queue.py
import logging
import threading
import uuid
from collections import defaultdict
from coilmq.scheduler import FavorReliableSubscriberScheduler, RandomQueueScheduler
from coilmq.util.concurrency import synchronized

    @type _queues: C{dict} of C{str} to C{set} of L{coilmq.server.StompConnection}

    @ivar _pending: All messages waiting for ACK from clients.
    @type _pending: C{dict} of L{coilmq.server.StompConnection} to C{stompclient.frame.Frame}

    @ivar _transaction_frames: Frames that have been ACK'd within a transaction.
    @type _transaction_frames: C{dict} of L{coilmq.server.StompConnection} to C{dict} of C{str} to C{stompclient.frame.Frame}
    """

    def __init__(self, store, subscriber_scheduler=None, queue_scheduler=None):
        """
        @param store: The queue storage backend.
        @type store: L{coilmq.store.QueueStore}

        @param subscriber_scheduler: The scheduler that chooses which subscriber to send
                                    messages to.
        @type subscriber_scheduler: L{coilmq.scheduler.SubscriberPriorityScheduler}

        @param queue_scheduler: The scheduler that chooses which queue to select for sending
                                    backlogs for a single connection.
        @type queue_scheduler: L{coilmq.scheduler.QueuePriorityScheduler}
        """
        self.log = logging.getLogger(
            '%s.%s' % (__name__, self.__class__.__name__))

        # Use default schedulers, if they're not specified
        if subscriber_scheduler is None:
            subscriber_scheduler = FavorReliableSubscriberScheduler()

        if queue_scheduler is None:

            queue_scheduler = RandomQueueScheduler()