/** * This is called remotely from other cluster members when a new remote subscription is * identified. * * <p>We add or remove a remote subscription... */ public void subscribeFromPeer( String destinationId, Boolean subscribe, String selector, String subtopic, Object remoteAddress) { Destination destination = getDestination(destinationId); RemoteSubscriptionManager subMgr = ((MessageDestination) destination).getRemoteSubscriptionManager(); if (destination instanceof MessageDestination) { if (debug) Log.getLogger(MessageService.LOG_CATEGORY) .debug( "Received subscription from peer: " + remoteAddress + " subscribe? " + subscribe + " selector: " + selector + " subtopic: " + subtopic); if (subscribe) subMgr.addSubscriber(remoteAddress, selector, subtopic, null); else subMgr.removeSubscriber(remoteAddress, selector, subtopic, null); } else if (Log.isError()) Log.getLogger(LOG_CATEGORY) .error( "subscribeFromPeer called with destination: " + destinationId + " that is not a MessageDestination"); }
@Override public void start() { String serviceType = getClass().getName(); ClusterManager clm = getMessageBroker().getClusterManager(); super.start(); /* * For any destinations which are not using broadcast mode, * we need to init the remote subscriptions. First we send out * the requestSubscription messages, then we wait for the sendSubscriptions * messages to come in. */ for (String destName : destinations.keySet()) { MessageDestination dest = (MessageDestination) getDestination(destName); if (!dest.getServerSettings().isBroadcastRoutingMode() && dest.isClustered()) { initRemoteSubscriptions(destName); } } /* Now go through and wait for the response to these messages... */ for (String destName : destinations.keySet()) { MessageDestination dest = (MessageDestination) getDestination(destName); if (!dest.getServerSettings().isBroadcastRoutingMode() && dest.isClustered()) { List members = clm.getClusterMemberAddresses(serviceType, destName); for (Object addr : members) { if (!clm.getLocalAddress(serviceType, destName).equals(addr)) { RemoteSubscriptionManager subMgr = dest.getRemoteSubscriptionManager(); subMgr.waitForSubscriptions(addr); } } } } debug = Log.isDebug(); }
/** * This method is invoked remotely via jgroups. It builds a snapshot of the local subscription * state and sends it back to the requesting server by calling its receiveSubscriptions method. * * @exclude */ public void sendSubscriptions(String destinationId, Object remoteAddress) { MessageDestination destination = (MessageDestination) getDestination(destinationId); Object subscriptions; /* * Avoid trying to use the cluster stuff if this destination does not * exist or is not clustered on this server. */ if (destination == null) { if (Log.isError()) Log.getLogger(LOG_CATEGORY) .error( "Destination: " + destinationId + " does not exist on this server but we received a request for the subscription info from a peer server where the destination exists as clustered. Check the cluster configuration for this destination and make sure it matches on all servers."); return; } else if (!destination.isClustered()) { if (Log.isError()) Log.getLogger(LOG_CATEGORY) .error( "Destination: " + destinationId + " is not clustered on this server but we received a request for the subscription info from a peer server which is clustered. Check the cluster configuration for this destination and make sure it matches on all servers."); return; } RemoteSubscriptionManager subMgr = destination.getRemoteSubscriptionManager(); /* * The remote server has no subscriptions initially since it has not * started yet. We initialize the server here so that when it sends * the first add subscription request, we'll receive it. This is because * servers will not process remote add/remove subscribe requests until * they have received the subscription state from each server. */ subMgr.setSubscriptionState(Collections.EMPTY_LIST, remoteAddress); /* * To ensure that we send the remote server a clean copy of the subscription * table we need to block out the code which adds/removes subscriptions and sends * them to remote servers between here... */ try { subscribeLock.writeLock().lock(); subscriptions = destination.getSubscriptionManager().getSubscriptionState(); ClusterManager clm = getMessageBroker().getClusterManager(); clm.invokePeerToPeerOperation( getClass().getName(), destinationId, "receiveSubscriptions", new Object[] {destinationId, subscriptions}, remoteAddress); } finally { /* ... And here */ subscribeLock.writeLock().unlock(); } }
/** * Same as the previous method but it accepts a destination parameter as well to avoid potentially * costly destination lookup. * * @param message The <code>Message</code> to push to peer server nodes in the cluster. * @param destination The destination to push the message to. * @param evalSelector <code>true</code> to evaluate each remote subscriber's selector before * pushing the message to them; <code>false</code> to skip selector evaluation. */ public void sendPushMessageFromPeer( Message message, MessageDestination destination, boolean evalSelector) { if (!destination.isClustered()) return; ClusterManager clm = getMessageBroker().getClusterManager(); if (destination.getServerSettings().isBroadcastRoutingMode()) { if (debug) Log.getLogger(LOG_CATEGORY) .debug( "Broadcasting message to peer servers: " + message + " evalSelector: " + evalSelector); // tell the message service on other nodes to push the message clm.invokeServiceOperation( getClass().getName(), message.getDestination(), "pushMessageFromPeer", new Object[] {message, evalSelector}); } else { RemoteSubscriptionManager mgr = destination.getRemoteSubscriptionManager(); Set serverAddresses = mgr.getSubscriberIds(message, evalSelector); if (debug) Log.getLogger(LOG_CATEGORY) .debug( "Sending message to peer servers: " + serverAddresses + StringUtils.NEWLINE + " message: " + message + StringUtils.NEWLINE + " evalSelector: " + evalSelector); for (Object remoteAddress : serverAddresses) { clm.invokePeerToPeerOperation( getClass().getName(), message.getDestination(), "pushMessageFromPeerToPeer", new Object[] {message, evalSelector}, remoteAddress); } } }