/** * Sets the scope of the <code>FactoryDestination</code> that is used in <code>FactoryInstance * </code> creation. Scope cannot be changed to and from application scope once <code> * FactoryInstance</code> is initialized. * * @param scope */ public void setScope(String scope) { if (factoryInstance != null) { if (FlexFactory.SCOPE_APPLICATION.equals(this.scope) && !FlexFactory.SCOPE_APPLICATION.equals(scope)) { if (Log.isWarn()) Log.getLogger(getLogCategory()) .warn( "Current scope is " + FlexFactory.SCOPE_APPLICATION + " and it cannot be changed to " + scope + " once factory instance is initialized."); return; } else if (!FlexFactory.SCOPE_APPLICATION.equals(this.scope) && FlexFactory.SCOPE_APPLICATION.equals(scope)) { if (Log.isWarn()) Log.getLogger(getLogCategory()) .warn( "Current scope is " + this.scope + " and it cannot be changed to " + FlexFactory.SCOPE_APPLICATION + " once factory instance is initialized."); return; } factoryInstance.setScope(scope); } this.scope = scope; }
/** * @exclude This method is provided for a cluster peer broadcast, it is not intended to be invoked * locally. */ public void pushMessageFromPeer(AsyncMessage message, Boolean evalSelector) { if (!isStarted()) { Log.getLogger(LOG_CATEGORY) .debug( "Received message from peer server before server is started - ignoring: " + message + " evalSelector: " + evalSelector); return; } if (debug) Log.getLogger(LOG_CATEGORY) .debug( "Received message from peer server: " + message + " evalSelector: " + evalSelector); // Update the FlexContext for this thread to indicate we're processing a message from // a server peer. FlexContext.setMessageFromPeer(true); // we are not confirming that replication is enabled again here, so if the remote // peer has replication enabled and therefore broadcast to this peer, then this peer // will complete the operation even if it locally does not have replication enabled pushMessageToClients(message, evalSelector); // And unset. FlexContext.setMessageFromPeer(false); }
/** * 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"); }
/** * Implement a serializer instance which wraps the subscription manager in a transient variable. * It will need to block out all sub/unsub messages before they are broadcast to the remote * server, iterate through the maps of subscriptions and for each "unique" subscription it writes * the selector and subtopic. * * <p>synchronization note: this assumes no add/remove subscriptions are occurring while this * method is called. * * @return a List of subscriptions selectors and subtopics */ public Object getSubscriptionState() { ArrayList<String> subState = new ArrayList<String>(); if (globalSubscribers.defaultSubscriptions != null && !globalSubscribers.defaultSubscriptions.isEmpty()) { subState.add(null); // selector string subState.add(null); // subtopic string } if (globalSubscribers.selectorSubscriptions != null) { for (String s : globalSubscribers.selectorSubscriptions.keySet()) { subState.add(s); subState.add(null); // subtopic } } addSubscriptionState(subState, subscribersPerSubtopic); addSubscriptionState(subState, subscribersPerSubtopicWildcard); if (Log.isDebug()) Log.getLogger(MessageService.LOG_CATEGORY) .debug( "Retrieved subscription state to send to new cluster member for destination: " + destination.getId() + ": " + StringUtils.NEWLINE + subState); return subState; }
/** 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; }
/** * A utility method to handle outgoing 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. */ public void handleOutgoingThrottleResult( Message message, ThrottleResult throttleResult, boolean isClientLevel) { Result result = throttleResult.getResult(); // Update the management metrics. if (result != Result.OK && isManaged()) { if (isClientLevel) ((ThrottleManagerControl) getControl()).incrementClientOutgoingMessageThrottleCount(); else ((ThrottleManagerControl) getControl()).incrementDestinationOutgoingMessageThrottleCount(); } // Result can only be IGNORE (or NONE which means no throttling) if (result == Result.IGNORE) { // Improve the detail message for IGNORE. if (isClientLevel) throttleResult.setDetail( "Message '" + message.getMessageId() + "' ignored: Too many messages sent to client '" + message.getClientId() + "' in too small of a time interval " + throttleResult.getDetail()); else throttleResult.setDetail( "Message '" + message.getMessageId() + "' throttled: Too many messages routed by destination '" + message.getDestination() + "' in too small of a time interval " + throttleResult.getDetail()); if (Log.isInfo()) Log.getLogger(LOG_CATEGORY).info(throttleResult.getDetail()); } }
/** * 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(); } }
/** * Broadcast this subscribe/unsubscribe message to the cluster so everyone is aware of this * server's interest in messages matching this selector and subtopic. * * @param subscribe are we subscribing? * @param selector the selector * @param subtopic the subtopic */ protected void sendSubscriptionToPeer(boolean subscribe, String selector, String subtopic) { if (Log.isDebug()) Log.getLogger(MessageService.LOG_CATEGORY) .debug( "Sending subscription to peers for subscribe? " + subscribe + " selector: " + selector + " subtopic: " + subtopic); ((MessageService) destination.getService()) .sendSubscribeFromPeer(destination.getId(), subscribe, selector, subtopic); }
/** * 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"); }
/** * Gets the value specified by the BeanProperty * * @param instance Object to get the value from * @param bp the property to get * @return the value of the property if it exists */ protected final Object getBeanValue(Object instance, BeanProperty bp) { String propertyName = bp.getName(); if (bp.isRead()) { try { Object value = bp.get(instance); if (value != null && descriptor != null) { SerializationDescriptor subDescriptor = (SerializationDescriptor) descriptor.get(propertyName); if (subDescriptor != null) { PropertyProxy subProxy = PropertyProxyRegistry.getProxyAndRegister(value); subProxy = (PropertyProxy) subProxy.clone(); subProxy.setDescriptor(subDescriptor); subProxy.setDefaultInstance(value); value = subProxy; } } return value; } catch (Exception e) { SerializationContext context = getSerializationContext(); // Log failed property set errors if (Log.isWarn() && logPropertyErrors(context)) { Logger log = Log.getLogger(LOG_CATEGORY); log.warn( "Failed to get property {0} on type {1}.", new Object[] {propertyName, getAlias(instance)}, e); } if (!ignorePropertyErrors(context)) { // Failed to get property '{propertyName}' on type '{className}'. MessageException ex = new MessageException(); ex.setMessage( FAILED_PROPERTY_READ_ERROR, new Object[] {propertyName, getAlias(instance)}); ex.setRootCause(e); throw ex; } } } else { SerializationContext context = getSerializationContext(); if (!ignorePropertyErrors(context)) { // Property '{propertyName}' not readable from class '{alias}'. MessageException ex = new MessageException(); ex.setMessage(NON_READABLE_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)}); throw ex; } } return null; }
/** * Sets the source of the <code>FactoryDestination</code> that is used in <code>FactoryInstance * </code> creation. Source cannot be changed once <code>FactoryInstance</code> is initialized and * the scope is application. * * @param source */ public void setSource(String source) { if (factoryInstance != null) { if (FlexFactory.SCOPE_APPLICATION.equals(scope)) { if (Log.isWarn()) Log.getLogger(getLogCategory()) .warn( "Source of the destination cannot be changed once " + "factory instance is already initialized and it has " + FlexFactory.SCOPE_APPLICATION + " scope"); return; } factoryInstance.setSource(source); } this.source = source; }
@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(); }
/** * 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); } } }
/** * Removes the subscriber, unsubscribing it from all current subscriptions. This is used by the * admin UI. * * @param client the client */ public void removeSubscriber(MessageClient client) { // Sends unsub messages for each subscription for this MessageClient which // should mean we remove the client at the end. client.invalidate(); if (getSubscriber(client.getClientId()) != null) Log.getLogger(MessageService.LOG_CATEGORY) .error("Failed to remove client: " + client.getClientId()); }
/* * Use this method to return to the Error log level in qa-manual app. * <target class="flex.messaging.log.ConsoleTarget" level="Error"> <properties> <prefix>[Flex] </prefix> <includeDate>false</includeDate> <includeTime>true</includeTime> <includeLevel>true</includeLevel> <includeCategory>true</includeCategory> </properties> <filters> <pattern>Service.*</pattern> <pattern>Message.*</pattern> <pattern>DataService.*</pattern> <!--<pattern>Endpoint.*</pattern>--> </filters> </target> */ private short createErrorLogTarget() { // Remove any other targets Log.reset(); // Up the logging level to debug, and create a logging target dynamically ConsoleTarget myTarget = new ConsoleTarget(); myTarget.setLevel(LogEvent.ERROR); myTarget.setPrefix("[Flex] "); myTarget.setIncludeDate(false); myTarget.setIncludeTime(true); myTarget.setIncludeLevel(true); myTarget.setIncludeCategory(true); myTarget.addFilter("Service.*"); myTarget.addFilter("Message.*"); myTarget.addFilter("DataService.*"); Log.addTarget(myTarget); return ((ConsoleTarget) Log.getTargets().get(0)).getLevel(); }
/** * 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); } }
void addTopicSubscribers( TopicSubscription ts, Message message, Set<Object> ids, boolean evalSelector) { if (ts == null) return; Map<Object, MessageClient> subs = ts.defaultSubscriptions; if (subs != null) ids.addAll(subs.keySet()); if (ts.selectorSubscriptions == null) return; for (Map.Entry<String, Map<Object, MessageClient>> entry : ts.selectorSubscriptions.entrySet()) { String selector = entry.getKey(); subs = entry.getValue(); if (!evalSelector) { ids.addAll(subs.keySet()); } else { JMSSelector jmsSel = new JMSSelector(selector); try { if (jmsSel.match(message)) { ids.addAll(subs.keySet()); } } catch (JMSSelectorException jmse) { if (Log.isWarn()) { Log.getLogger(JMSSelector.LOG_CATEGORY) .warn( "Error processing message selector: " + jmsSel + StringUtils.NEWLINE + " incomingMessage: " + message + StringUtils.NEWLINE + " selector: " + selector); } } } } }
/* * The purpose of this method is to replace the default "Error" logging target * with Debug log level and specific filters. * Verification of the log must be manually done against the console output. * <target class="flex.messaging.log.ConsoleTarget" level="Debug"> <properties> <prefix>[LCDS] </prefix> <includeDate>false</includeDate> <includeTime>true</includeTime> <includeLevel>true</includeLevel> <includeCategory>true</includeCategory> </properties> <filters> <pattern>Service.Data.*</pattern> <pattern>Message.*</pattern> </filters> </target> */ private short createDebugLogTarget() { // Remove any other targets Log.reset(); // Up the logging level to debug, and create a logging target dynamically ConsoleTarget myTarget = new ConsoleTarget(); myTarget.setLevel(LogEvent.DEBUG); myTarget.setPrefix("[LCDS] "); // myTarget.setIncludeDate(true); myTarget.setIncludeTime(true); myTarget.setIncludeLevel(true); myTarget.setIncludeCategory(true); // myTarget.addFilter("Startup.*"); myTarget.addFilter("Service.Data.*"); myTarget.addFilter("Message.*"); myTarget.addFilter("Endpoint.*"); // Add the new Debug target Log.addTarget(myTarget); return ((ConsoleTarget) Log.getTargets().get(0)).getLevel(); }
public String createLogTarget(String target) { short currentLevel = ((ConsoleTarget) Log.getTargets().get(0)).getLevel(); String retVal = "Log level did not change. Default target level: " + LogEvent.getLevelString(currentLevel); if (target.equals("Debug")) { currentLevel = createDebugLogTarget(); retVal = LogEvent.getLevelString(currentLevel); } else if (target.equals("Error")) { currentLevel = createErrorLogTarget(); retVal = LogEvent.getLevelString(currentLevel); } return retVal; }
/** * Pushes a message to all clients that are subscribed to the destination targeted by this * message. * * @param message The <code>Message</code> to push to the destination's subscribers. * @param evalSelector <code>true</code> to evaluate each subscriber's selector before pushing the * message to them; <code>false</code> to skip selector evaluation. */ public void pushMessageToClients(Message message, boolean evalSelector) { MessageDestination destination = (MessageDestination) getDestination(message); SubscriptionManager subscriptionManager = destination.getSubscriptionManager(); Set subscriberIds = subscriptionManager.getSubscriberIds(message, evalSelector); if (debug) Log.getLogger(LOG_CATEGORY) .debug( "Sending message: " + message + StringUtils.NEWLINE + " to subscribed clientIds: " + subscriberIds); if ((subscriberIds != null) && !subscriberIds.isEmpty()) { /* We have already filtered based on the selector and so pass false below */ pushMessageToClients(destination, subscriberIds, message, false); } }
/** * @exclude This method is used by messaging adapters to send a message to a specific set of * clients that are directly connected to this server. It does not propagate the message to * other servers in the cluster. */ public void pushMessageToClients( MessageDestination destination, Set subscriberIds, Message message, boolean evalSelector) { if (subscriberIds != null) { try { // Place notifier in thread-local scope. MessageRoutedNotifier routingNotifier = new MessageRoutedNotifier(message); FlexContext.setMessageRoutedNotifier(routingNotifier); SubscriptionManager subscriptionManager = destination.getSubscriptionManager(); for (Object clientId : subscriberIds) { MessageClient client = subscriptionManager.getSubscriber(clientId); // Skip if the client is null or invalidated. if (client == null || !client.isValid()) { if (debug) Log.getLogger(MessageService.LOG_CATEGORY) .debug( "Warning: could not find MessageClient for clientId in pushMessageToClients: " + clientId + " for destination: " + destination.getId()); continue; } pushMessageToClient(client, destination, message, evalSelector); } // Done with the push, notify any listeners. routingNotifier.notifyMessageRouted(); } finally { // Unset the notifier for this message. FlexContext.setMessageRoutedNotifier(null); } } }
/** @exclude */ public Object serviceMessage(Message message, boolean throttle, MessageDestination dest) { if (managed) incrementMessageCount(false, message); if (throttle) { // Throttle the inbound message; also attempts to prevent duplicate messages sent by a client. dest = (MessageDestination) getDestination(message); ThrottleManager throttleManager = dest.getThrottleManager(); if (throttleManager != null && throttleManager.throttleIncomingMessage(message)) return null; // Message throttled. } // Block any sent messages that have a subtopic header containing // wildcards - wildcards are only supported in subscribe/unsubscribe // commands (see serviceCommand() and manageSubscriptions()). Object subtopicObj = message.getHeader(AsyncMessage.SUBTOPIC_HEADER_NAME); List<Subtopic> subtopics = null; if (subtopicObj != null) { if (subtopicObj instanceof Object[]) subtopicObj = Arrays.asList((Object[]) subtopicObj); if (subtopicObj instanceof String) { String subtopicString = (String) subtopicObj; if (subtopicString != null && subtopicString.length() > 0) { if (dest == null) dest = (MessageDestination) getDestination(message); Subtopic subtopic = testProducerSubtopic(dest.getServerSettings().getSubtopicSeparator(), subtopicString); if (subtopics == null) subtopics = new ArrayList<Subtopic>(); subtopics.add(subtopic); } } else if (subtopicObj instanceof List) { @SuppressWarnings("unchecked") List<String> subtopicList = (List<String>) subtopicObj; String subtopicSeperator = null; for (String subtopicString : subtopicList) { if (subtopicString != null && subtopicString.length() > 0) { if (dest == null) dest = (MessageDestination) getDestination(message); subtopicSeperator = dest.getServerSettings().getSubtopicSeparator(); Subtopic subtopic = testProducerSubtopic(subtopicSeperator, subtopicString); if (subtopics == null) subtopics = new ArrayList<Subtopic>(); subtopics.add(subtopic); } } } } // Override TTL if there was one specifically configured for this destination if (dest == null) dest = (MessageDestination) getDestination(message); ServerSettings destServerSettings = dest.getServerSettings(); if (destServerSettings.getMessageTTL() >= 0) message.setTimeToLive(destServerSettings.getMessageTTL()); long start = 0; if (debug) start = System.currentTimeMillis(); // Give MessagingAdapter a chance to block the send. ServiceAdapter adapter = dest.getAdapter(); if (adapter instanceof MessagingAdapter) { MessagingSecurityConstraintManager manager = ((MessagingAdapter) adapter).getSecurityConstraintManager(); if (manager != null) manager.assertSendAuthorization(); } MessagePerformanceUtils.markServerPreAdapterTime(message); Object result = adapter.invoke(message); MessagePerformanceUtils.markServerPostAdapterTime(message); if (debug) { long end = System.currentTimeMillis(); Log.getLogger(TIMING_LOG_CATEGORY) .debug("After invoke service: " + getId() + "; execution time = " + (end - start) + "ms"); } return result; }
/** * Add a subscriber. * * @param clientId the client id * @param selector the selector * @param subtopicString the subtopic * @param endpointId the endpoint * @param maxFrequency maximum frequency */ public void addSubscriber( Object clientId, String selector, String subtopicString, String endpointId, int maxFrequency) { Subtopic subtopic = getSubtopic(subtopicString); MessageClient client = null; TopicSubscription topicSub; Map<Object, MessageClient> subs; Map<Subtopic, TopicSubscription> map; try { // Handle resubscribes from the same client and duplicate subscribes from different clients boolean subscriptionAlreadyExists = (getSubscriber(clientId) != null); client = getMessageClient(clientId, endpointId); FlexClient flexClient = FlexContext.getFlexClient(); if (subscriptionAlreadyExists) { // Block duplicate subscriptions from multiple FlexClients if they // attempt to use the same clientId. (when this is called from a remote // subscription, there won't be a flex client so skip this test). if (flexClient != null && !flexClient.getId().equals(client.getFlexClient().getId())) { ServiceException se = new ServiceException(); se.setMessage(10559, new Object[] {clientId}); throw se; } // It's a resubscribe. Reset the endpoint push state for the subscription to make sure its // current // because a resubscribe could be arriving over a new endpoint or a new session. client.resetEndpoint(endpointId); } ServiceAdapter adapter = destination.getAdapter(); client.updateLastUse(); if (subtopic == null) { topicSub = globalSubscribers; } else { if (!destination.getServerSettings().getAllowSubtopics()) { // Throw an error - the destination doesn't allow subtopics. ServiceException se = new ServiceException(); se.setMessage( SUBTOPICS_NOT_SUPPORTED, new Object[] {subtopicString, destination.getId()}); throw se; } if (subtopic.containsSubtopicWildcard() && destination.getServerSettings().isDisallowWildcardSubtopics()) { // Attempt to subscribe to the subtopic, ''{0}'', on destination, ''{1}'', that does not // allow wilcard subtopics failed. ServiceException se = new ServiceException(); se.setMessage( WILDCARD_SUBTOPICS_NOT_ALLOWED, new Object[] {subtopicString, destination.getId()}); throw se; } // Give a MessagingAdapter a chance to block the subscribe. if ((adapter instanceof MessagingSecurity) && (subtopic != null)) { if (!((MessagingSecurity) adapter).allowSubscribe(subtopic)) { ServiceException se = new ServiceException(); se.setMessage(10557, new Object[] {subtopicString}); throw se; } } /* * If there is a wildcard, we always need to match that subscription * against the producer. If it has no wildcard, we can do a quick * lookup to find the subscribers. */ if (subtopic.containsSubtopicWildcard()) map = subscribersPerSubtopicWildcard; else map = subscribersPerSubtopic; synchronized (this) { topicSub = map.get(subtopic); if (topicSub == null) { topicSub = new TopicSubscription(); map.put(subtopic, topicSub); } } } /* Subscribing with no selector */ if (selector == null) { subs = topicSub.defaultSubscriptions; if (subs == null) { synchronized (this) { if ((subs = topicSub.defaultSubscriptions) == null) topicSub.defaultSubscriptions = subs = new ConcurrentHashMap<Object, MessageClient>(); } } } /* Subscribing with a selector - store all subscriptions under the selector key */ else { synchronized (this) { if (topicSub.selectorSubscriptions == null) topicSub.selectorSubscriptions = new ConcurrentHashMap<String, Map<Object, MessageClient>>(); } subs = topicSub.selectorSubscriptions.get(selector); if (subs == null) { synchronized (this) { if ((subs = topicSub.selectorSubscriptions.get(selector)) == null) topicSub.selectorSubscriptions.put( selector, subs = new ConcurrentHashMap<Object, MessageClient>()); } } } if (subs.containsKey(clientId)) { /* I'd rather this be an error but in 2.0 we allowed this without error */ if (Log.isWarn()) Log.getLogger(JMSSelector.LOG_CATEGORY) .warn( "Client: " + clientId + " already subscribed to: " + destination.getId() + " selector: " + selector + " subtopic: " + subtopicString); } else { client.addSubscription(selector, subtopicString, maxFrequency); synchronized (this) { /* * Make sure other members of the cluster know that we are subscribed to * this info if we are in server-to-server mode * * This has to be done in the synchronized section so that we properly * order subscribe and unsubscribe messages for our peers so their * subscription state matches the one in the local server. */ if (subs.isEmpty() && destination.isClustered() && destination.getServerSettings().getRoutingMode() == RoutingMode.SERVER_TO_SERVER) sendSubscriptionToPeer(true, selector, subtopicString); subs.put(clientId, client); } monitorTimeout( client); // local operation, timeouts on remote host are not started until failover // Finally, if a new MessageClient was created, notify its created // listeners now that MessageClient's subscription state is setup. if (!subscriptionAlreadyExists) client.notifyCreatedListeners(); } } finally { releaseMessageClient(client); } }
void pushMessageToClient( MessageClient client, MessageDestination destination, Message message, boolean evalSelector) { // Normally we'll process the message selector criteria as part of fetching the // clients which should receive this message. However, because the API exposed the evalSelecor // flag // in pushMessageToClients(Set, Message, boolean), we need to run the client.testMessage() // method // here to make sure subtopic and selector expressions are evaluated correctly in this case. // The general code path passes evalSelector as false, so the testMessage() method is not // generally // invoked as part of a message push operation. if (evalSelector && !client.testMessage(message, destination)) { return; } // Push the message to the client. Note that client level outbound throttling // might still happen at the FlexClientOutboundQueueProcessor level. try { // Only update client last use if the message is not a pushed server command. if (!(message instanceof CommandMessage)) client.updateLastUse(); // Remove any data in the base message that should not be included in the multicast copies. Map messageHeaders = message.getHeaders(); messageHeaders.remove(Message.FLEX_CLIENT_ID_HEADER); messageHeaders.remove(Message.ENDPOINT_HEADER); // Add the default message priority headers, if it's not already set. int priority = destination.getServerSettings().getPriority(); if (priority != -1) { Object header = message.getHeader(Message.PRIORITY_HEADER); if (header == null) message.setHeader(Message.PRIORITY_HEADER, priority); } // FIXME: [Pete] Investigate whether this is a performance issue. // We also need to ensure message ids do not expose FlexClient ids // message.setMessageId(UUIDUtils.createUUID()); // We need a unique instance of the message for each client; both to prevent // outbound queue processing for various clients from interfering with each other // as well as needing to target the copy of the message to a specific MessageAgent // instance on the client. Message messageForClient = (Message) message.clone(); // the MPIUTil call will be a no-op if MPI is not enabled. Otherwise it will add // a server pre-push processing timestamp to the MPI object MessagePerformanceUtils.markServerPrePushTime(message); MessagePerformanceUtils.markServerPostAdapterTime(message); MessagePerformanceUtils.markServerPostAdapterExternalTime(message); // Target the message to a specific MessageAgent on the client. messageForClient.setClientId(client.getClientId()); if (debug) Log.getLogger(MessageService.LOG_CATEGORY) .debug( "Routing message to FlexClient id:" + client.getFlexClient().getId() + "', MessageClient id: " + client.getClientId()); getMessageBroker().routeMessageToMessageClient(messageForClient, client); } catch (MessageException ignore) { // Client is subscribed but has disconnected or the network failed. // There's nothing we can do to correct this so just continue server processing. } }
/** {@inheritDoc} */ public void setValue(Object instance, String propertyName, Object value) { BeanProperty bp = getBeanProperty(instance, propertyName); if (bp != null) { if (bp.isWrite()) { try { Class desiredPropClass = bp.getType(); TypeMarshaller marshaller = TypeMarshallingContext.getTypeMarshaller(); value = marshaller.convert(value, desiredPropClass); ClassUtil.validateAssignment(instance, propertyName, value); bp.set(instance, value); } catch (Exception e) { SerializationContext context = getSerializationContext(); // Log ignore failed property set errors if (Log.isWarn() && logPropertyErrors(context)) { Logger log = Log.getLogger(LOG_CATEGORY); log.warn( "Failed to set property {0} on type {1}.", new Object[] {propertyName, getAlias(instance)}, e); } if (!ignorePropertyErrors(context)) { // Failed to get property '{propertyName}' on type '{className}'. MessageException ex = new MessageException(); ex.setMessage( FAILED_PROPERTY_WRITE_ERROR, new Object[] {propertyName, getAlias(instance)}); ex.setRootCause(e); throw ex; } } } else { SerializationContext context = getSerializationContext(); if (Log.isWarn() && logPropertyErrors(context)) { Logger log = Log.getLogger(LOG_CATEGORY); log.warn( "Property {0} not writable on class {1}", new Object[] {propertyName, getAlias(instance)}); } if (!ignorePropertyErrors(context)) { // Property '{propertyName}' not writable on class '{alias}'. MessageException ex = new MessageException(); ex.setMessage( NON_WRITABLE_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)}); throw ex; } } } else { SerializationContext context = getSerializationContext(); if (Log.isWarn() && logPropertyErrors(context)) { Logger log = Log.getLogger(LOG_CATEGORY); log.warn( "Ignoring set property {0} for type {1} as a setter could not be found.", new Object[] {propertyName, getAlias(instance)}); } if (!ignorePropertyErrors(context)) { // Property '{propertyName}' not found on class '{alias}'. MessageException ex = new MessageException(); ex.setMessage(UNKNOWN_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)}); throw ex; } } }