Package flex.messaging.services.messaging

Source Code of flex.messaging.services.messaging.ThrottleManager$ThrottleMark

/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
*  [2002] - [2007] Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any.  The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated
* and its suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*/
package flex.messaging.services.messaging;

import java.util.HashMap;
import java.util.Map;

import flex.management.ManageableComponent;
import flex.management.runtime.messaging.services.messaging.ThrottleManagerControl;
import flex.messaging.MessageException;
import flex.messaging.config.ThrottleSettings;
import flex.messaging.log.LogCategories;
import flex.messaging.messages.Message;

/**
* The ThrottleManager provides functionality to limit the frequency of messages
* routed through the system in message/second terms. Message frequency can be managed
* on a per-client basis and also on a per-destination basis by tweaking different
* parameters. Each MessageDestination has one ThrottleManager.
*
* Message frequency can be throttled differently for incoming messages, which are messages
* published by Flash/Flex producers, and for outgoing messages, which are messages 
* consumed by Flash/Flex subscribers that may have bene produced by either Flash clients
* or external message producers (such as data feeds, JMS publishers, etc).
* @author neville
*/
public class ThrottleManager extends ManageableComponent
{
    public static final String LOG_CATEGORY = LogCategories.SERVICE_MESSAGE;
       
    public static final String TYPE = "ThrottleManager";
    private static final Object classMutex = new Object();
    private static int instanceCount = 0;     
   
    private Map inboundClientMarks;
    private Map outboundClientMarks;
    private ThrottleMark inboundDestinationMark;
    private ThrottleMark outboundDestinationMark;
    private ThrottleSettings settings;
   
    public static final int RESULT_OK = 0;
    public static final int RESULT_IGNORE = 1;
    public static final int RESULT_REPLACE = 2;
    public static final int RESULT_ERROR = 3;

    // TODO: QUESTION: Seth, make this configurable?
    static final int MESSAGE_HISTORY_SIZE = 15;

    public ThrottleManager()
    {
        this(false);
    }
   
    public ThrottleManager(boolean enableManagement)
    {
        super(enableManagement);
        synchronized (classMutex)
        {
            super.setId(TYPE + ++instanceCount);
        }

        settings = new ThrottleSettings();
    }
    
    // This component's id should never be changed as it's generated internally
    public void setId(String id)
    {
        // No-op
    }
   
    public void setThrottleSettings(ThrottleSettings throttleSettings)
    {
        settings = throttleSettings;       
        if (settings.isDestinationThrottleEnabled())
        {
            inboundDestinationMark = new ThrottleMark(settings.getDestinationName());
            outboundDestinationMark = new ThrottleMark(settings.getDestinationName());
        }
        if (settings.isClientThrottleEnabled())
        {
            inboundClientMarks = new HashMap();
            outboundClientMarks = new HashMap();
        }
    }
   
    public int throttleIncomingMessage(Message msg)
    {
        // destination-level throttling comes before client-level,
        // because if it fails then it doesn't matter what the client-level
        // throttle reports
        int n = RESULT_OK;
       
        if (settings.getInboundPolicy() != ThrottleSettings.POLICY_NONE)
        {
            n = throttleDestinationLevel(msg, true);
          if (n == RESULT_OK)
          {
              // client-level throttling allows the system to further refine a
              // different throttle for individual clients, which may be a subset
              // but never a superset of destination-level throttle settings
              n = throttleClientLevel(msg, msg.getClientId(), true);               
          }
        }
        return n;
    }
   
    public int throttleOutgoingMessage(Message msg, Object clientId)
    {
        int n = RESULT_OK;
        if (settings.getOutboundPolicy() != ThrottleSettings.POLICY_NONE)
        {
          if (clientId == null)
              n = throttleDestinationLevel(msg, false);
          else
              n = throttleClientLevel(msg, clientId, false);
        }
        return n;
    }
   
    private int throttleDestinationLevel(Message msg, boolean incoming)
    {
        int throttleResult = RESULT_OK;
        if (settings.isDestinationThrottleEnabled())
        {
            if (incoming)
            {
                try
                {
                    inboundDestinationMark.assertValid(msg, settings.getIncomingDestinationFrequency());
                }
                catch (RuntimeException e)
                {
                    String s = "Message throttled: Too many messages sent to destination "
                        + inboundDestinationMark.id + " in too small of a time interval.  " + e.getMessage();
                    MessageException me = new MessageException(s);
                    try
                    {
                        throttleResult = handleError(settings.getInboundPolicy(), me);
                    }
                    catch (MessageException m)
                    {
                        throttleResult = RESULT_ERROR;
                        throw m;
                    }
                    finally
                    {
                        if (throttleResult != RESULT_OK && isManaged())
                            ((ThrottleManagerControl)getControl()).incrementDestinationIncomingMessageThrottleCount();
                    }                   
                }
            }
            else
            {
                try
                {
                    outboundDestinationMark.assertValid(msg, settings.getOutgoingDestinationFrequency());
                }
                catch (RuntimeException e)
                {
                    String s = "Message throttled: Too many messages routed by destination "
                        + outboundDestinationMark.id + " in too small of a time interval";
                    MessageException me = new MessageException(s);
                    try
                    {
                        throttleResult = handleError(settings.getOutboundPolicy(), me);
                    }
                    catch (MessageException m)
                    {
                        throttleResult = RESULT_ERROR;
                        throw m;
                    }
                    finally
                    {
                        if (throttleResult != RESULT_OK && isManaged())
                            ((ThrottleManagerControl)getControl()).incrementDestinationOutgoingMessageThrottleCount();                           
                    }                   
                }
            }
        }
        return throttleResult;
    }

    private int throttleClientLevel(Message msg, Object clientId, boolean incoming)
    {
        int throttleResult = RESULT_OK;
      if (settings.isClientThrottleEnabled())
        {
            ThrottleMark clientLevelMark = null;
          if (incoming)
            {
              if (inboundClientMarks.get(clientId) != null)
                clientLevelMark = (ThrottleMark) inboundClientMarks.get(clientId);
            else
                clientLevelMark = new ThrottleMark(clientId);
              try
              {
                  clientLevelMark.assertValid(msg, settings.getIncomingClientFrequency());
              }
              catch (RuntimeException e)
                {
                    String s = "Message throttled: Too many messages sent by client "
                        + clientId + " in too small of a time interval";
                    MessageException me = new MessageException(s);
                    try
                    {
                        throttleResult = handleError(settings.getInboundPolicy(), me);
                    }
                    catch (MessageException m)
                    {
                        throttleResult = RESULT_ERROR;
                        throw m;
                    }
                    finally
                    {
                        if ((throttleResult != RESULT_OK) && isManaged())
                            ((ThrottleManagerControl)getControl()).incrementClientIncomingMessageThrottleCount();
                    }                   
                }
              finally
              {
                  inboundClientMarks.put(clientId, clientLevelMark);
              }
            }
          else
          {
              if (outboundClientMarks.get(clientId) != null)
                clientLevelMark = (ThrottleMark) outboundClientMarks.get(clientId);
            else
                clientLevelMark = new ThrottleMark(clientId);
              try
              {
                  clientLevelMark.assertValid(msg, settings.getOutgoingClientFrequency());
              }
                catch (RuntimeException e)
                {
                    String s = "Message throttled: Too many messages sent to client "
                        + clientId + " in too small of a time interval";
                    MessageException me = new MessageException(s);
                    try
                    {
                        throttleResult = handleError(settings.getOutboundPolicy(), me);
                    }
                    catch (MessageException m)
                    {
                        throttleResult = RESULT_ERROR;
                        throw m;
                    }
                    finally
                    {
                        if ((throttleResult != RESULT_OK) && isManaged())
                            ((ThrottleManagerControl)getControl()).incrementClientOutgoingMessageThrottleCount();
                    }
                }
              finally
              {
                  outboundClientMarks.put(clientId, clientLevelMark);
              }
          }
        }
        return throttleResult;
    }
   
    private int handleError(int policy, MessageException e)
    {
        int n = 0;
        switch(policy)
        {
            case ThrottleSettings.POLICY_IGNORE:
                n = RESULT_IGNORE;
              break;
            case ThrottleSettings.POLICY_REPLACE:
                // replace can only work as an outgoing option
                // (this is enforced at configuration time)
                n = RESULT_REPLACE;
              break;
            case ThrottleSettings.POLICY_ERROR:
                throw e;
            default:
                break;
        }
        return n;
    }
   
    public void removeClientThrottleMark(Object clientId)
    {
        if (inboundClientMarks != null)
        {
            inboundClientMarks.remove(clientId);
        }
        if (outboundClientMarks != null)
        {
            outboundClientMarks.remove(clientId);
        }
    }
   
    protected String getLogCategory()
    {
        return LOG_CATEGORY;
    }
   
    class ThrottleMark
    {
        Object id;
        int messageCount;
        String lastMessageId;
        long [] lastMessageTimes;
       
        ThrottleMark(Object identifier)
        {
            id = identifier;
            messageCount = 0;
            lastMessageId = "-1";
            lastMessageTimes = new long[MESSAGE_HISTORY_SIZE];
        }
       
        void assertValid(Message msg, int frequency)
        {
            if (frequency > 0)
            {
                int len = lastMessageTimes.length;
                // if we have enough messages to start testing
                if (messageCount >= len)
                {
                    // Time delay between this message and the last "N" messages
                    long interval = msg.getTimestamp() -
                        lastMessageTimes[(messageCount - len) % len];
                    long rate = 1000*len/interval;
                    // If the rate is too high, we toss this message
                    // and do not record it so our history represents the
                    // rate of messages actually delivered.
                    if (rate > frequency)
                    {
                        throw new RuntimeException("actual frequency=" + rate + " max frequency=" + frequency);
                    }
                }
                lastMessageId = msg.getMessageId();
                lastMessageTimes[messageCount++ % len] = msg.getTimestamp();
            }
        }
    }
}
TOP

Related Classes of flex.messaging.services.messaging.ThrottleManager$ThrottleMark

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.