Package org.jboss.errai.bus.server

Source Code of org.jboss.errai.bus.server.ServerMessageBusImpl

/*
* Copyright 2009 JBoss, a divison Red Hat, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jboss.errai.bus.server;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.jboss.errai.bus.client.api.*;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.bus.client.api.base.RuleDelegateMessageCallback;
import org.jboss.errai.bus.client.api.base.TaskManagerFactory;
import org.jboss.errai.bus.client.framework.*;
import org.jboss.errai.bus.client.protocols.BusCommands;
import org.jboss.errai.bus.client.protocols.MessageParts;
import org.jboss.errai.bus.server.api.*;
import org.jboss.errai.bus.server.async.SchedulerService;
import org.jboss.errai.bus.server.async.SimpleSchedulerService;
import org.jboss.errai.bus.server.async.TimedTask;
import org.jboss.errai.bus.server.io.JSONMessageServer;
import org.jboss.errai.bus.server.service.ErraiServiceConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static org.jboss.errai.bus.client.api.base.MessageBuilder.createConversation;
import static org.jboss.errai.bus.client.protocols.MessageParts.ReplyTo;
import static org.jboss.errai.bus.client.protocols.SecurityCommands.MessageNotDelivered;
import static org.jboss.errai.bus.client.util.ErrorHelper.handleMessageDeliveryFailure;
import static org.jboss.errai.bus.server.util.ServerBusUtils.encodeJSON;

/**
* The <tt>ServerMessageBusImpl</tt> implements the <tt>ServerMessageBus</tt>, making it possible for the server to
* send and receive messages
*
* @author Mike Brock
*/
@Singleton
public class ServerMessageBusImpl implements ServerMessageBus {
    private static final String ERRAI_BUS_QUEUESIZE = "errai.bus.queuesize";

    private final static int DEFAULT_QUEUE_SIZE = 250;

    private int queueSize = DEFAULT_QUEUE_SIZE;

    private final List<MessageListener> listeners = new ArrayList<MessageListener>();

    private final Map<String, List<MessageCallback>> subscriptions = new ConcurrentHashMap<String, List<MessageCallback>>();
    private final Map<String, Set<MessageQueue>> remoteSubscriptions = new ConcurrentHashMap<String, Set<MessageQueue>>();

    private final Map<QueueSession, MessageQueue> messageQueues = new ConcurrentHashMap<QueueSession, MessageQueue>();
    private final Map<MessageQueue, List<MarshalledMessage>> deferredQueue = new ConcurrentHashMap<MessageQueue, List<MarshalledMessage>>();
    private final Map<String, QueueSession> sessionLookup = new ConcurrentHashMap<String, QueueSession>();

    private final List<SubscribeListener> subscribeListeners = new LinkedList<SubscribeListener>();
    private final List<UnsubscribeListener> unsubscribeListeners = new LinkedList<UnsubscribeListener>();
    private final List<QueueClosedListener> queueClosedListeners = new LinkedList<QueueClosedListener>();

    private final SchedulerService houseKeeper = new SimpleSchedulerService();

    private Logger log = LoggerFactory.getLogger(getClass());

    private BusMonitor busMonitor;

    private Set<String> reservedNames = new HashSet<String>();

    /**
     * Sets up the <tt>ServerMessageBusImpl</tt> with the configuration supplied. Also, initializes the bus' callback
     * functions, scheduler, and monitor
     * <p/>
     * When deploying services on the server-side, it is possible to obtain references to the
     * <tt>ErraiServiceConfigurator</tt> by declaring it as injection dependencies
     *
     * @param config - the configuration used to initialize the server message bus
     */
    @Inject
    public ServerMessageBusImpl(ErraiServiceConfigurator config) {

        /**
         * Define the default ServerBus service used for intrabus communication.
         */
        subscribe("ServerBus", new MessageCallback() {
            @SuppressWarnings({"unchecked"})
            public void callback(Message message) {
                QueueSession session = getSession(message);
                MessageQueueImpl queue;

                switch (BusCommands.valueOf(message.getCommandType())) {
                    case Heartbeat:
                        if (messageQueues.containsKey(session)) {
                            messageQueues.get(session).heartBeat();
                        }
                        break;

                    case RemoteSubscribe:
                        if (message.hasPart("SubjectsList")) {
                            queue = (MessageQueueImpl) messageQueues.get(session);
                            for (String subject : (List<String>) message.get(List.class, "SubjectsList")) {
                                remoteSubscribe(session, queue, subject);
                            }
                        } else {
                            remoteSubscribe(session, messageQueues.get(session),
                                    message.get(String.class, MessageParts.Subject));
                        }
                        break;

                    case RemoteUnsubscribe:
                        remoteUnsubscribe(session, messageQueues.get(session),
                                message.get(String.class, MessageParts.Subject));
                        break;

                    case FinishStateSync:
                        queue = (MessageQueueImpl) messageQueues.get(session);
                        queue.finishInit();

                        drainDeferredDeliveryQueue(queue);
                        break;

                    case ConnectToQueue:
                        List<MarshalledMessage> deferred = null;
                        synchronized (messageQueues) {
                            if (messageQueues.containsKey(session)) {
                                MessageQueue q = messageQueues.get(session);
                                synchronized (q) {
                                    if (deferredQueue.containsKey(q)) {
                                        deferred = deferredQueue.remove(q);
                                    }
                                }

                                messageQueues.get(session).stopQueue();
                            }

                            addQueue(session, queue = new MessageQueueImpl(queueSize, ServerMessageBusImpl.this, session));

                            if (deferred != null) {
                                deferredQueue.put(queue, deferred);
                            }

                            remoteSubscribe(session, queue, "ClientBus");
                        }

                        if (isMonitor()) {
                            busMonitor.notifyQueueAttached(session.getSessionId(), queue);
                        }

                        List<String> subjects = new LinkedList<String>();
                        try {
                            for (String service : subscriptions.keySet()) {
                                if (service.startsWith("local:")) {
                                    continue;
                                } else {
                                    subjects.add(service);
                                }
                            }
                        }
                        catch (Throwable t) {
                            t.printStackTrace();
                        }

                        createConversation(message)
                                .toSubject("ClientBus")
                                .command(BusCommands.RemoteSubscribe)
                                .with("SubjectsList", subjects)
                                .noErrorHandling().sendNowWith(ServerMessageBusImpl.this, false);

                        createConversation(message)
                                .toSubject("ClientBus")
                                .command(BusCommands.FinishStateSync)
                                .noErrorHandling().sendNowWith(ServerMessageBusImpl.this, false);
                        /**
                         * Now the session is established, turn WindowPolling on.
                         */
                        getQueue(session).setWindowPolling(true);

                        break;
                }
            }
        });

        addSubscribeListener(new SubscribeListener() {
            public void onSubscribe(SubscriptionEvent event) {
                if (event.isRemote() || event.getSubject().startsWith("local:")) return;
                synchronized (messageQueues) {
                    if (messageQueues.isEmpty()) return;

                    MessageBuilder.createMessage()
                            .toSubject("ClientBus")
                            .command(BusCommands.RemoteSubscribe)
                            .with(MessageParts.Subject, event.getSubject())
                            .noErrorHandling().sendGlobalWith(ServerMessageBusImpl.this);
                }
            }
        });

        addUnsubscribeListener(new UnsubscribeListener() {
            public void onUnsubscribe(SubscriptionEvent event) {
                if (event.isRemote() || event.getSubject().startsWith("local:")) return;
                synchronized (messageQueues) {
                    if (messageQueues.isEmpty()) return;

                    MessageBuilder.createMessage()
                            .toSubject("ClientBus")
                            .command(BusCommands.RemoteUnsubscribe)
                            .with(MessageParts.Subject, event.getSubject())
                            .noErrorHandling().sendGlobalWith(ServerMessageBusImpl.this);
                }
            }
        });

        houseKeeper.addTask(new TimedTask() {
            {
                this.period = (1000 * 10);
            }

            public void setExitHandler(Runnable runnable) {
            }

            public void run() {
                boolean houseKeepingPerformed = false;
                List<MessageQueue> endSessions = new LinkedList<MessageQueue>();

                while (!houseKeepingPerformed) {
                    try {
                        Iterator<MessageQueue> iter = ServerMessageBusImpl.this.messageQueues.values().iterator();
                        MessageQueue q;
                        while (iter.hasNext()) {
                            if ((q = iter.next()).isStale()) {
                                iter.remove();
                                endSessions.add(q);
                            }
                        }

                        houseKeepingPerformed = true;
                    }
                    catch (ConcurrentModificationException cme) {
                        // fall-through and try again.
                    }
                }


                for (MessageQueue ref : endSessions) {
                    for (String subject : new HashSet<String>(ServerMessageBusImpl.this.remoteSubscriptions.keySet())) {
                        ServerMessageBusImpl.this.remoteUnsubscribe(ref.getSession(), ref, subject);
                    }

                    ServerMessageBusImpl.this.closeQueue(ref);
                    ref.getSession().endSession();
                    deferredQueue.remove(ref);
                }
            }

            public boolean isFinished() {
                return false;
            }

            @Override
            public String toString() {
                return "Bus Housekeeper";
            }
        });

        houseKeeper.start();
    }


    private void addQueue(QueueSession session, MessageQueueImpl queue) {
        messageQueues.put(session, queue);
        sessionLookup.put(session.getSessionId(), session);
    }

    /**
     * Configures the server message bus with the specified <tt>ErraiServiceConfigurator</tt>. It only takes the queue
     * size specified by the configuration
     *
     * @param config -
     */
    public void configure(ErraiServiceConfigurator config) {
        queueSize = DEFAULT_QUEUE_SIZE;
        if (config.hasProperty(ERRAI_BUS_QUEUESIZE)) {
            queueSize = Integer.parseInt(config.getProperty(ERRAI_BUS_QUEUESIZE));
        }
    }

    /**
     * Sends a message globally to all subscriptions containing the same subject as the specified message.
     *
     * @param message - The message to be sent.
     */
    public void sendGlobal(final Message message) {
        message.commit();
        final String subject = message.getSubject();

        if (!subscriptions.containsKey(subject) && !remoteSubscriptions.containsKey(subject)) {
            throw new NoSubscribersToDeliverTo("for: " + subject + " [commandType:" + message.getCommandType() + "]");
        }

        if (!fireGlobalMessageListeners(message)) {
            if (message.hasPart(ReplyTo) && message.hasResource("Session")) {
                /**
                 * Inform the sender that we did not dispatchGlobal the message.
                 */

                Map<String, Object> rawMsg = new HashMap<String, Object>();
                rawMsg.put(MessageParts.CommandType.name(), MessageNotDelivered.name());

                try {
                    enqueueForDelivery(getQueueByMessage(message),
                            message.get(String.class, ReplyTo),
                            encodeJSON(rawMsg));
                }
                catch (NoSubscribersToDeliverTo nstdt) {
                    handleMessageDeliveryFailure(this, message, nstdt.getMessage(), nstdt, false);
                }
            }

            return;
        }

        final String jsonMessage = message instanceof HasEncoded ? ((HasEncoded) message).getEncoded() :
                encodeJSON(message.getParts());

        if (isMonitor()) {
            if (message.isFlagSet(RoutingFlags.FromRemote)) {
                busMonitor.notifyIncomingMessageFromRemote(
                        message.getResource(QueueSession.class, "Session").getSessionId(), message);
            } else {
                if (subscriptions.containsKey(subject)) {
                    busMonitor.notifyInBusMessage(message);
                }

                if (remoteSubscriptions.containsKey(subject)) {
                    for (Map.Entry<QueueSession, MessageQueue> entry : messageQueues.entrySet()) {
                        busMonitor.notifyOutgoingMessageToRemote(entry.getValue().getSession().getSessionId(), message);
                    }
                }
            }
        }

        if (subscriptions.containsKey(subject)) {
            for (MessageCallback c : subscriptions.get(subject)) {
                c.callback(message);
            }
        }

        if (remoteSubscriptions.containsKey(subject)) {
            TaskManagerFactory.get().execute(new Runnable() {
                public void run() {
                    for (MessageQueue queue : remoteSubscriptions.get(subject)) {
                        queue.offer(new MarshalledMessage() {
                            public String getSubject() {
                                return subject;
                            }

                            public Object getMessage() {
                                return jsonMessage;
                            }
                        });
                    }
                }
            });
        }
    }

    /**
     * Sends the <tt>message</tt>
     *
     * @param message - the message to send
     */
    public void send(Message message) {
        message.commit();
        if (message.hasResource("Session")) {
            send(getQueueByMessage(message), message, true);
        } else if (message.hasPart(MessageParts.SessionID)) {
            send(getQueueBySession(message.get(String.class, MessageParts.SessionID)), message, true);
        } else {
            sendGlobal(message);
        }
    }

    /**
     * Parses the message appropriately and enqueues it for delivery
     *
     * @param message       - the message to be sent
     * @param fireListeners - true if all listeners attached should be notified of delivery
     */
    public void send(Message message, boolean fireListeners) {
        message.commit();
        if (!message.hasResource("Session")) {
            handleMessageDeliveryFailure(this, message, "cannot automatically route message. no session contained in message.", null, false);
        }

        final MessageQueue queue = getQueue(getSession(message));

        if (queue == null) {
            handleMessageDeliveryFailure(this, message, "cannot automatically route message. no session contained in message.", null, false);

        }

        send(message.hasPart(MessageParts.SessionID) ? getQueueBySession(message.get(String.class, MessageParts.SessionID)) :
                getQueueByMessage(message), message, fireListeners);
    }

    private void send(MessageQueue queue, Message message, boolean fireListeners) {
        try {
            if (fireListeners && !fireGlobalMessageListeners(message)) {
                if (message.hasPart(ReplyTo)) {
                    Map<String, Object> rawMsg = new HashMap<String, Object>();
                    rawMsg.put(MessageParts.CommandType.name(), MessageNotDelivered.name());
                    enqueueForDelivery(queue, message.get(String.class, ReplyTo),
                            encodeJSON(rawMsg));
                }
                return;
            }

            if (isMonitor()) {
                busMonitor.notifyOutgoingMessageToRemote(queue.getSession().getSessionId(), message);
            }

            asyncEnqueue(queue, message);
        }
        catch (NoSubscribersToDeliverTo nstdt) {
            // catch this so we can get a full trace
            handleMessageDeliveryFailure(this, message, nstdt.getMessage(), nstdt, false);
        }
    }

    private void asyncEnqueue(final MessageQueue queue, final Message message) {
        TaskManagerFactory.get().execute(new Runnable() {
            public void run() {
                try {
                    enqueueForDelivery(queue, message.getSubject(), message instanceof HasEncoded ?
                            ((HasEncoded) message).getEncoded() :
                            encodeJSON(message.getParts()));
                }
                catch (QueueOverloadedException e) {
                    handleMessageDeliveryFailure(ServerMessageBusImpl.this, message, e.getMessage(), e, false);
                }
            }
        });
    }

    private void enqueueForDelivery(final MessageQueue queue, final String subject, final Object message) {
        if (queue != null && isAnyoneListening(queue, subject)) {

            queue.offer(new MarshalledMessage() {
                public String getSubject() {
                    return subject;
                }

                public Object getMessage() {
                    return message;
                }
            });

        } else {
            if (queue != null && !queue.isInitialized()) {
                deferDelivery(queue, new MarshalledMessage() {
                    public String getSubject() {
                        return subject;
                    }

                    public Object getMessage() {
                        return message;
                    }
                });
            } else {
                throw new NoSubscribersToDeliverTo("for: " + subject + ":" + isAnyoneListening(queue, subject) + ":" + queue.isInitialized());
            }
        }

    }

    private void deferDelivery(final MessageQueue queue, MarshalledMessage message) {
        synchronized (queue) {
            if (!deferredQueue.containsKey(queue)) deferredQueue.put(queue, new ArrayList<MarshalledMessage>());
            deferredQueue.get(queue).add(message);
        }
    }

    private void drainDeferredDeliveryQueue(final MessageQueue queue) {
        synchronized (queue) {
            if (deferredQueue.containsKey(queue)) {
                for (MarshalledMessage message : deferredQueue.get(queue)) {
                    queue.offer(message);
                }

                deferredQueue.remove(queue);
            }
        }
    }

    /**
     * Gets the next message in the form of a <tt>Payload</tt>, which contains one-or-more messages that need to be
     * sent.
     *
     * @param sessionContext - key of messages. Only want to obtain messages that have the same <tt>sessionContext</tt>
     * @param wait           - set to true if the bus will wait for the next message
     * @return the <tt>Payload</tt> containing the next messages to be sent
     */
    public Payload nextMessage(QueueSession sessionContext, boolean wait) {
        try {
            return messageQueues.get(sessionContext).poll(wait);
        }
        catch (MessageQueueExpired e) {
            MessageQueue mq = messageQueues.get(sessionContext);

            if (mq != null) {
                // terminate the queue
                messageQueues.remove(sessionContext);
            }
            throw e;
        }
    }

    /**
     * Gets the queue corresponding to the session id given
     *
     * @param session - the session id of the queue
     * @return the message queue
     */
    public MessageQueue getQueue(QueueSession session) {
        return messageQueues.get(session);
    }

    /**
     * Closes the queue with <tt>sessionId</tt>
     *
     * @param sessionId - the session context of the queue to close
     */
    public void closeQueue(String sessionId) {
        closeQueue(getQueueBySession(sessionId));
    }

    /**
     * Closes the message queue
     *
     * @param queue - the message queue to close
     */
    public void closeQueue(MessageQueue queue) {
        for (Set<MessageQueue> sq : remoteSubscriptions.values()) {
            sq.remove(queue);
        }

        messageQueues.values().remove(queue);
        sessionLookup.values().remove(queue.getSession());

        fireQueueCloseListeners(new QueueCloseEvent(queue));
    }

    /**
     * Adds a rule for a specific subscription. The <tt>BooleanRoutingRule</tt> determines if a message should
     * be routed based on the already specified rules or not.
     *
     * @param subject - the subject of the subscription
     * @param rule    - the <tt>BooleanRoutingRule</tt> instance specifying the routing rules
     */
    public void addRule(String subject, BooleanRoutingRule rule) {
        List<MessageCallback> newCallbacks = new LinkedList<MessageCallback>();
        Iterator<MessageCallback> iter = subscriptions.get(subject).iterator();
        while (iter.hasNext()) {
            newCallbacks.add(new RuleDelegateMessageCallback(iter.next(), rule));
            iter.remove();
        }

        List<MessageCallback> slist = subscriptions.get(subject);
        for (MessageCallback mc : newCallbacks) {
            slist.add(mc);
        }
    }

    /**
     * Adds a subscription
     *
     * @param subject  - the subject to subscribe to
     * @param receiver - the callback function called when a message is dispatched
     */
    public void subscribe(String subject, MessageCallback receiver) {
        if (reservedNames.contains(subject))
            throw new IllegalArgumentException("Attempt to modify lockdown service: " + subject);

        if (!subscriptions.containsKey(subject)) {
            subscriptions.put(subject, new ArrayList<MessageCallback>());
        }

        List<MessageCallback> receivers = subscriptions.get(subject);
        receivers.add(receiver);

        fireSubscribeListeners(new SubscriptionEvent(false, null, receivers.size(), subject));
    }

    /**
     * Adds a new remote subscription and fires subscription listeners
     *
     * @param sessionContext - session context of queue
     * @param queue          - the message queue
     * @param subject        - the subject to subscribe to
     */
    public void remoteSubscribe(QueueSession sessionContext, MessageQueue queue, String subject) {
        if (subscriptions.containsKey(subject) || subject == null) return;


        if (!remoteSubscriptions.containsKey(subject)) {
            remoteSubscriptions.put(subject, new HashSet<MessageQueue>());
        }

        Set<MessageQueue> remotes = remoteSubscriptions.get(subject);
        remotes.add(queue);

        fireSubscribeListeners(new SubscriptionEvent(true, sessionContext.getSessionId(), remotes.size(), subject));
    }

    /**
     * Unsubscribes a remote subsciption and fires the appropriate listeners
     *
     * @param sessionContext - session context of queue
     * @param queue          - the message queue
     * @param subject        - the subject to unsubscribe from
     */
    public void remoteUnsubscribe(QueueSession sessionContext, MessageQueue queue, String subject) {
        if (!remoteSubscriptions.containsKey(subject)) {
            return;
        }


        Set<MessageQueue> sessionsToSubject = remoteSubscriptions.get(subject);

        sessionsToSubject.remove(queue);

        if (sessionsToSubject.isEmpty()) {
            remoteSubscriptions.remove(subject);
        }

        try {
            fireUnsubscribeListeners(new SubscriptionEvent(true, sessionsToSubject.isEmpty(), sessionsToSubject.size(),
                    sessionContext.getSessionId(), subject));
        }
        catch (Exception e) {
            e.printStackTrace();
            System.out.println("Exception running listeners");
            return;
        }


        /**
         * Any messages still in the queue for this subject, will now never be delivered.  So we must purge them,
         * like the unwanted and forsaken messages they are.
         */
        Iterator<MarshalledMessage> iter = queue.getQueue().iterator();
        while (iter.hasNext()) {
            if (subject.equals(iter.next().getSubject())) {
                iter.remove();
            }
        }
    }

    /**
     * Unsubscribe all subscriptions attached to <tt>subject</tt>
     *
     * @param subject - the subject to unsubscribe from
     */
    public void unsubscribeAll(String subject) {
        if (reservedNames.contains(subject))
            throw new IllegalArgumentException("Attempt to modify lockdown service: " + subject);

        subscriptions.remove(subject);

        fireUnsubscribeListeners(new SubscriptionEvent(false, null, 0, subject));
    }

    /**
     * Starts a conversation using the specified message
     *
     * @param message  - the message to initiate the conversation
     * @param callback - the message's callback function
     */
    public void conversationWith(Message message, MessageCallback callback) {
        throw new RuntimeException("conversationWith not yet implemented.");
    }

    /**
     * Checks if a subscription exists for <tt>subject</tt>
     *
     * @param subject - the subject to search the subscriptions for
     * @return true if a subscription exists
     */
    public boolean isSubscribed(String subject) {
        return subscriptions.containsKey(subject);
    }

    private boolean isAnyoneListening(MessageQueue queue, String subject) {
        return subscriptions.containsKey(subject) ||
                (remoteSubscriptions.containsKey(subject) && remoteSubscriptions.get(subject).contains(queue));
    }

    public boolean hasRemoteSubscriptions(String subject) {
        return remoteSubscriptions.containsKey(subject);
    }

    private boolean fireGlobalMessageListeners(Message message) {
        boolean allowContinue = true;

        for (MessageListener listener : listeners) {
            if (!listener.handleMessage(message)) {
                allowContinue = false;
            }
        }

        return allowContinue;
    }

    private void fireSubscribeListeners(SubscriptionEvent event) {
        if (isMonitor()) {
            busMonitor.notifyNewSubscriptionEvent(event);
        }

        synchronized (subscribeListeners) {
            event.setDisposeListener(false);

            for (Iterator<SubscribeListener> iter = subscribeListeners.iterator(); iter.hasNext();) {
                iter.next().onSubscribe(event);
                if (event.isDisposeListener()) {
                    iter.remove();
                    event.setDisposeListener(false);
                }
            }
        }

    }

    private void fireUnsubscribeListeners(SubscriptionEvent event) {
        if (isMonitor()) {
            busMonitor.notifyUnSubcriptionEvent(event);
        }

        synchronized (unsubscribeListeners) {
            event.setDisposeListener(false);

            for (Iterator<UnsubscribeListener> iter = unsubscribeListeners.iterator(); iter.hasNext();) {
                iter.next().onUnsubscribe(event);
                if (event.isDisposeListener()) {
                    iter.remove();
                    event.setDisposeListener(false);
                }
            }
        }
    }

    private void fireQueueCloseListeners(QueueCloseEvent event) {
        if (isMonitor()) {
            busMonitor.notifyQueueDetached(event.getQueue().getSession().getSessionId(), event.getQueue());
        }

        synchronized (queueClosedListeners) {
            event.setDisposeListener(false);

            for (Iterator<QueueClosedListener> iter = queueClosedListeners.iterator(); iter.hasNext();) {
                iter.next().onQueueClosed(event);
                if (event.isDisposeListener()) {
                    iter.remove();
                    event.setDisposeListener(false);
                }
            }
        }
    }


    /**
     * Adds a global listener
     *
     * @param listener - global listener to add
     */
    public void addGlobalListener(MessageListener listener) {
        synchronized (listeners) {
            listeners.add(listener);
        }
    }

    /**
     * Adds subscription listener
     *
     * @param listener - subscription listener to add
     */
    public void addSubscribeListener(SubscribeListener listener) {
        synchronized (subscribeListeners) {
            subscribeListeners.add(listener);
        }
    }

    /**
     * Adds unsubscription listener
     *
     * @param listener - adds an unsubscription listener
     */
    public void addUnsubscribeListener(UnsubscribeListener listener) {
        synchronized (unsubscribeListeners) {
            unsubscribeListeners.add(listener);
        }
    }

    private static QueueSession getSession(Message message) {
        return message.getResource(QueueSession.class, "Session");
    }

    private MessageQueue getQueueByMessage(Message message) {
        MessageQueue queue = getQueue(getSession(message));
        if (queue == null)
            throw new QueueUnavailableException("no queue available to send. (queue or session may have expired)");
        return queue;
    }

    private MessageQueue getQueueBySession(String sessionId) {
        return getQueue(sessionLookup.get(sessionId));
    }

    private QueueSession getSessionById(String sessionId) {
        return sessionLookup.get(sessionId);
    }

    /**
     * Gets all the message queues
     *
     * @return a map of the message queues that exist
     */
    public Map<QueueSession, MessageQueue> getMessageQueues() {
        return messageQueues;
    }

    /**
     * Gets the scheduler being used for the housekeeping
     *
     * @return the scheduler
     */
    public SchedulerService getScheduler() {
        return houseKeeper;
    }

    public void addQueueClosedListener(QueueClosedListener listener) {
        synchronized (queueClosedListeners) {
            queueClosedListeners.add(listener);
        }
    }

    {
        new MessageProvider() {
            {
                MessageBuilder.setMessageProvider(this);
            }

            public Message get() {
                return JSONMessageServer.create();
            }
        };
    }

    public List<MessageCallback> getReceivers(String subject) {
        return Collections.unmodifiableList(subscriptions.get(subject));
    }

    private boolean isMonitor() {
        return this.busMonitor != null;
    }

    public void attachMonitor(BusMonitor monitor) {
        if (this.busMonitor != null) {
            log.warn("new monitor attached, but a monitor was already attached: old monitor has been detached.");
        }
        this.busMonitor = monitor;

        for (Map.Entry<QueueSession, MessageQueue> entry : messageQueues.entrySet()) {
            busMonitor.notifyQueueAttached(entry.getKey().getSessionId(), entry.getValue());
        }

        for (String subject : subscriptions.keySet()) {
            busMonitor.notifyNewSubscriptionEvent(new SubscriptionEvent(false, "None", 1, subject));
        }
        for (Map.Entry<String, Set<MessageQueue>> entry : remoteSubscriptions.entrySet()) {
            for (MessageQueue queue : entry.getValue()) {
                busMonitor.notifyNewSubscriptionEvent(new SubscriptionEvent(true, queue.getSession().getSessionId(), 1, entry.getKey()));
            }
        }

        monitor.attach(this);
    }

    public void finishInit() {
        reservedNames.addAll(subscriptions.keySet());
    }
}
TOP

Related Classes of org.jboss.errai.bus.server.ServerMessageBusImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.