blob: da3454a8e2d33645480b2500cbd847d80be865ab [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 flex.messaging.services.messaging;
import flex.messaging.config.ThrottleSettings.Policy;
import flex.messaging.services.messaging.ThrottleManager.ThrottleResult;
import flex.messaging.services.messaging.ThrottleManager.ThrottleResult.Result;
/**
* This class is used by ThrottleManager and FlexClientOutboundQueueProcessor
* to keep track of inbound and outbound message rates per destination and
* per client-subscription.
*/
public class MessageFrequency
{
public final int messageHistorySize;
private int messageCount;
private long [] previousMessageTimes;
/**
* Creates a new MessageFrequency with the specified id.
*
* @param messageHistorySize The number of messages to use in calculating message rates.
*/
public MessageFrequency(int messageHistorySize)
{
this.messageHistorySize = messageHistorySize;
messageCount = 0;
previousMessageTimes = new long[messageHistorySize];
}
/**
* Given the current time and a maximum frequency, checks that the message
* is not exceeding the max frequency limit. If message exceeds the limit,
* returns a throttle result object that is appropriate for the passed in policy.
*
* Callers of checkLimit method should call updateMessageFrequency method
* once a message is successfully sent to the client.
*
* @param maxFrequency The maximum frequency to enforce. If maxFrequency is
* zero, the message frequencies are being kept track but no check happens.
* @param policy The throttling policy.
* @return The ThrottleResult.
*/
public ThrottleResult checkLimit(int maxFrequency, Policy policy)
{
long messageTimestamp = System.currentTimeMillis();
// If we have enough messages to start testing.
if (maxFrequency > -1 && messageCount >= messageHistorySize)
{
// Find the interval between this message and the last n messages.
int index = messageCount % messageHistorySize;
long intervalMillis = messageTimestamp - previousMessageTimes[index];
double intervalSeconds = intervalMillis / 1000d;
// Calculate the message rate in seconds.
double actualFrequency;
if (intervalSeconds > 0)
{
actualFrequency = messageHistorySize / intervalSeconds;
actualFrequency = Math.round(actualFrequency * 100d) / 100d;
}
// If the interval is zero, it means all the messages were sent
// in the same instant. In that case, there's no frequency to
// calculate really, so set it to one more than the limit.
else
{
actualFrequency = maxFrequency + 1;
}
// If the rate is too high, toss this message and do not record it,
// so the history represents the rate of messages actually delivered.
if (maxFrequency > 0 && actualFrequency > maxFrequency)
{
Result result = ThrottleManager.getResult(policy);
String detail = "[actual-frequency=" + actualFrequency + ", max-frequency=" + maxFrequency + "]";
return new ThrottleResult(result, detail);
}
}
// Return the default OK result.
return new ThrottleResult();
}
/**
* Increases the messageCount by one and updates the message time array by the
* current time. This method should be used by callers of checkLimit method
* once a message is successfully sent to the client.
*/
public void updateMessageFrequency()
{
// Handle integer wrap
messageCount = messageCount == Integer.MAX_VALUE? 0 : messageCount;
// Increase the messageCount and update the message times.
previousMessageTimes[messageCount++ % messageHistorySize] = System.currentTimeMillis();
}
}