/** * 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(); } }
/** * 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"); }
/** Return an entry from the property descrpitor cache for a class. */ private PropertyDescriptorCacheEntry getPropertyDescriptorCacheEntry(Class c) { PropertyDescriptorCacheEntry pce = (PropertyDescriptorCacheEntry) propertyDescriptorCache.get(c); try { if (pce == null) { BeanInfo beanInfo = Introspector.getBeanInfo(c, stopClass); pce = new PropertyDescriptorCacheEntry(); pce.propertyDescriptors = beanInfo.getPropertyDescriptors(); pce.propertiesByName = createPropertiesByNameMap(pce.propertyDescriptors, c.getFields()); if (cachePropertiesDescriptors) { synchronized (propertyDescriptorCache) { PropertyDescriptorCacheEntry pce2 = (PropertyDescriptorCacheEntry) propertyDescriptorCache.get(c); if (pce2 == null) propertyDescriptorCache.put(c, pce); else pce = pce2; } } } } catch (IntrospectionException ex) { // Log failed property set errors if (Log.isError()) { Logger log = Log.getLogger(LOG_CATEGORY); log.error( "Failed to introspect object of type: " + c + " error: " + ExceptionUtil.toString(ex)); } // Return an empty descriptor rather than crashing pce = new PropertyDescriptorCacheEntry(); pce.propertyDescriptors = new PropertyDescriptor[0]; pce.propertiesByName = new TreeMap(); } return pce; }
/** * This method is provided for a cluster peer broadcast, it is not invoked locally. It is used by * remote clients to send their subscription table to this server. * * @exclude */ public void receiveSubscriptions( String destinationId, Object subscriptions, Object senderAddress) { Destination destination = getDestination(destinationId); if (destination instanceof MessageDestination) ((MessageDestination) destination) .getRemoteSubscriptionManager() .setSubscriptionState(subscriptions, senderAddress); else if (subscriptions != null && Log.isError()) Log.getLogger(LOG_CATEGORY) .error( "receiveSubscriptions called with non-null value but destination: " + destinationId + " is not a MessageDestination"); }
/** * A utility method to handle incoming throttling results in a common way. * * @param message The message that is being throttled. * @param throttleResult The throttling result. * @param isClientLevel Whether the message is being throttled at the client level or not. */ protected void handleIncomingThrottleResult( Message message, ThrottleResult throttleResult, boolean isClientLevel) { Result result = throttleResult.getResult(); // Update the management metrics. if (result != Result.OK && isManaged()) { if (isClientLevel) ((ThrottleManagerControl) getControl()).incrementClientIncomingMessageThrottleCount(); else ((ThrottleManagerControl) getControl()).incrementDestinationIncomingMessageThrottleCount(); } // Result can be IGNORE or ERROR (or NONE which means no throttling). if (result == Result.IGNORE || result == Result.ERROR) { if (isClientLevel) throttleResult.setDetail( "Message '" + message.getMessageId() + "' throttled: Too many messages sent by the client '" + message.getClientId() + "' in too small of a time interval " + throttleResult.getDetail()); else throttleResult.setDetail( "Message '" + message.getMessageId() + "' throttled: Too many messages sent to destination '" + message.getDestination() + "' in too small of a time interval " + throttleResult.getDetail()); String detail = throttleResult.getDetail(); if (result == Result.ERROR) { if (Log.isError()) Log.getLogger(LOG_CATEGORY).error(detail); // And, throw an exception, so the client gets the error. MessageException me = new MessageException(detail); throw me; } // Otherwise, just log it. if (Log.isInfo()) Log.getLogger(LOG_CATEGORY).info(detail); } }