Author: indika
Date: Sun Dec 2 22:50:16 2007
New Revision: 10402
Added:
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/AccessRateController.java
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/CallerContext.java
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/factory/CallerContextFactory.java
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/impl/domainbase/DomainBaseCallerContext.java
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/impl/ipbase/IPBaseCallerContext.java
Log:
merging with 2.1 branch
Added:
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/AccessRateController.java
==============================================================================
--- (empty file)
+++
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/AccessRateController.java
Sun Dec 2 22:50:16 2007
@@ -0,0 +1,126 @@
+/*
+* Copyright 2005,2006 WSO2, Inc. http://wso2.com
+*
+* Licensed 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 org.wso2.throttle;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.throttle.factory.CallerContextFactory;
+
+/**
+ * Controls the access of remote callers according to the controlling policy .
+ * This provides abstraction that need to control access based on caller IP or
caller domain name.
+ * This implementation is thread safe.
+ *
+ */
+
+public class AccessRateController {
+
+ private static Log log =
LogFactory.getLog(AccessRateController.class.getName());
+
+ private static final String ACCESS_DENIED_TEMPORALLY =
+ "You cannot access this service since you have exceeded the allocated
quota.";
+
+ private static final String ACCESS_DENIED =
+ "You cannot access this service since you have prohibited
permanently.";
+
+ /* The Object for used to lock in synchronizing */
+ private final Object lock = new Object();
+
+ private boolean debugOn = false; //is debug enable
+
+ public AccessRateController() {
+ debugOn = log.isDebugEnabled();
+ }
+
+ /**
+ * To check wheather caller can access not not base on the controlling
policy
+ *
+ * @param throttleContext - current states of throttle - RunTime Data
+ * @param callerID - Identifer for remote caller - ex: ip or
domainname
+ * @param callerType - the type of the caller
+ * @return boolean - true if current remote user can continue access
+ * @throws ThrottleException
+ */
+ public boolean canAccess(ThrottleContext throttleContext,
+ String callerID, int callerType) throws
ThrottleException {
+
+ String type = ThrottleConstants.IP_BASE == callerType ? "IP address" :
"domain";
+
+ ThrottleConfiguration throttleConfigurationBean =
throttleContext.getThrottleConfiguration();
+
+ if (throttleConfigurationBean == null) {
+ if (debugOn) {
+ log.debug("Thorttle Configuration couldn't find - Throttling
will not occur");
+ }
+ return true;
+ }
+
+ if (callerID == null) {
+ if (debugOn) {
+ log.debug("Caller host or ip couldn't find !! - Access will
be denied ");
+ }
+ return false;
+ }
+
+ CallerConfiguration configuration =
+ throttleConfigurationBean.getCallerConfiguration(callerID);
+ if (configuration == null) {
+ if (debugOn) {
+ log.debug("Caller configuration couldn't find for " + type + "
and for caller " + callerID);
+ }
+ return true;
+ }
+ if (configuration.getAccessState() == ThrottleConstants.ACCESS_DENIED)
{
+ log.info(ACCESS_DENIED);
+ return false;
+ } else if (configuration.getAccessState() ==
ThrottleConstants.ACCESS_ALLOWED) {
+ return true;
+ } else if (configuration.getAccessState() ==
ThrottleConstants.ACCESS_CONTROLLED) {
+ synchronized (lock) {
+ CallerContext caller =
throttleContext.getCallerContext(callerID);
+ if (caller == null) {
+ //if caller has not already registered ,then create new
caller description and
+ //set it in throttle
+ caller = CallerContextFactory.createCaller(callerType,
callerID);
+ }
+ if (caller != null) {
+ long currentTime = System.currentTimeMillis();
+
+ if (!caller.canAccess(throttleContext, configuration,
currentTime)) {
+ //if current caller cannot access , then perform
cleaning
+ log.info(ACCESS_DENIED_TEMPORALLY);
+ throttleContext.processCleanList(currentTime);
+ return false;
+ } else {
+ if (debugOn) {
+ log.debug("Access from " + type + " " + callerID
+ " is successful.");
+ }
+ return true;
+ }
+ } else {
+ if (debugOn) {
+ log.debug("Caller " + type + " not found! " +
callerID);
+ }
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+}
\ No newline at end of file
Added:
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/CallerContext.java
==============================================================================
--- (empty file)
+++
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/CallerContext.java
Sun Dec 2 22:50:16 2007
@@ -0,0 +1,325 @@
+/*
+* Copyright 2005,2006 WSO2, Inc. http://wso2.com
+*
+* Licensed 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 org.wso2.throttle;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+
+/**
+ * Contains all runtime data for a particular remote caller.
+ * provides the default rate based access controller algorithm implementation.
+ * This is not thread-safe
+ *
+ */
+
+public abstract class CallerContext implements Serializable {
+
+ private static Log log = LogFactory.getLog(CallerContext.class.getName());
+
+ /* next access time - the end of prohibition */
+ private long nextAccessTime = 0;
+ /* frist access time - when caller came across the on frist time */
+ private long firstAccessTime = 0;
+ /* The nextTimeWindow - begining of next unit time period- end of current
unit time period */
+ private long nextTimeWindow = 0;
+ /* The count to keep track number of request */
+ private int count = 0;
+ /* The Id of caller */
+ private String ID;
+
+ private static final long serialVersionUID = 1652165180220263492L;
+
+ public CallerContext(String ID) {
+ this.ID = ID;
+ }
+
+ /**
+ * @return Returns Id of caller
+ */
+ public String getID() {
+ return this.ID;
+ }
+
+ /**
+ * Init the access for a particular caller , caller will registered with
context
+ *
+ * @param configuration -The Configuration for this caller
+ * @param throttleContext -The Throttle Context
+ * @param currentTime -The system current time in milliseconds
+ */
+ private void initAccess(CallerConfiguration configuration, ThrottleContext
throttleContext, long currentTime) {
+ this.firstAccessTime = currentTime; // set the first access time
+ // the end of this time window
+ this.nextTimeWindow = currentTime + configuration.getUnitTime();
+ throttleContext.addCallerContext(this); // register this in the
throttle
+ }
+
+ /**
+ * To verify access if the unit time has already not overred
+ *
+ * @param configuration - -The Configuration for this caller
+ * @param throttleContext -The Throttle Context
+ * @param currentTime -The system current time
+ * @return boolean -The boolean value which say access will
allolw or not
+ */
+ private boolean canAccessIfUnitTimeNotOver(CallerConfiguration
configuration, ThrottleContext throttleContext,long currentTime) {
+ boolean canAcess = false;
+ int maxRequest = configuration.getMaximumRequestPerUnitTime();
+ if (!(maxRequest == 0)) {
+ if (this.count <= maxRequest - 1) { //If the count is less than
max request
+ if (log.isDebugEnabled()) {
+ log.debug("Access allowed :: " + (maxRequest - this.count)
+ + " of available of " + maxRequest + " connections");
+ }
+ canAcess = true; // can continue access
+ this.count++;
+
+ throttleContext.flushCaller(this); // Send the current state
to others (clustered env)
+ // can complete access
+
+ } else {
+ //else , if caller has not already prohibit
+ if (this.nextAccessTime == 0) {
+ //and if there is no prohibit time period in configuration
+ long prohititTime = configuration.getProhibitTimePeriod();
+ if (prohititTime == 0) {
+ //prohibit access untill unit time period is over
+ this.nextAccessTime = this.firstAccessTime +
+ configuration.getUnitTime();
+ } else {
+ //if there is a prohibit time period in configuartion
,then
+ //set it as prohibit period
+ this.nextAccessTime = currentTime + prohititTime;
+ }
+ if (log.isDebugEnabled()) {
+ String type = ThrottleConstants.IP_BASE ==
configuration.getType() ?
+ "IP address" : "domain";
+ log.debug("Maximum Number of requests are reached for
caller with "
+ + type + " - " + this.ID);
+ }
+ throttleContext.flushCaller(this); // Send the current
state to others (clustered env)
+
+ } else {
+ // else , if the caller has already prohabit and prohabit
+ // time period has already overed
+ if (this.nextAccessTime
+ <= currentTime) {
+ if (log.isDebugEnabled()) {
+ log.debug("Access allowed :: " + (maxRequest)
+ + " of available of " + maxRequest + "
connections");
+ }
+ // remove previous caller context
+ if(this.nextTimeWindow!= 0){
+ throttleContext.removeCallerContext((new
Long(this.nextTimeWindow)));
+ }
+ // reset the states so that, this is the first access
+ this.nextAccessTime = 0;
+ canAcess = true;
+ this.count = 1;// can access the system and this is
same as fristAccess
+ this.firstAccessTime = currentTime;
+ this.nextTimeWindow = currentTime +
configuration.getUnitTime();
+ // registers caller
+ throttleContext.addCallerContext(this);
+ throttleContext.flush();// Send the current state to
others (clustered env)
+
+ } else {
+ if (log.isDebugEnabled()) {
+ String type = ThrottleConstants.IP_BASE ==
configuration.getType() ?
+ "IP address" : "domain";
+ log.debug("Prohibit period is not yet over for
caller with "
+ + type + " - " + this.ID);
+ }
+ }
+ }
+ }
+
+ }
+ return canAcess;
+ }
+
+ /**
+ * To verify access if unit time has already overred
+ *
+ * @param configuration -The Configuration for this caller
+ * @param throttleContext -The Throttle that caller having pass
+ * @param currentTime -The system current time
+ * @return boolean -The boolean value which say access will
allolw or not
+ */
+ private boolean canAccessIfUnitTimeOver(CallerConfiguration configuration,
ThrottleContext throttleContext, long currentTime) {
+
+ boolean canAcess = false;
+ // if number of access for a unit time is less than MAX and
+ // if the unit time period (session time) has just overed
+ int maxRequest = configuration.getMaximumRequestPerUnitTime();
+ if (!(maxRequest == 0)) {
+ if (this.count <= maxRequest - 1) {
+ if (this.nextTimeWindow != 0) {
+ throttleContext.removeCallerContext(new
Long(this.nextTimeWindow));
+ throttleContext.flush();// Send the current state to
others (clustered env)
+ }
+ canAcess = true; // this is bounus access
+ //next time callers can access as a new one
+ } else {
+ // if number of access for a unit time has just been greater
than MAX
+ // now same as a new session
+ // OR
+ // if caller in prohabit session and prohabit period has
just overed
+ if ((this.nextAccessTime == 0) ||
+ (this.nextAccessTime <= currentTime)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Access allowed :: " + (maxRequest) + " of
available of "
+ + maxRequest + " connections");
+ }
+ //remove previous callercontext instance
+ if (this.nextTimeWindow != 0) {
+ throttleContext.removeCallerContext(new
Long(this.nextTimeWindow));
+ }
+ // reset the states so that, this is the first access
+ this.nextAccessTime = 0;
+ canAcess = true;
+ this.count = 1;// can access the system and this is same
as frist Access
+ this.firstAccessTime = currentTime;
+ this.nextTimeWindow = currentTime +
configuration.getUnitTime();
+ // registers caller
+ throttleContext.addCallerContext(this);
+ throttleContext.flush();// Send the current state to
others (clustered env)
+
+ } else {
+ // if caller in prohabit session and prohabit period has
not overed
+ if (log.isDebugEnabled()) {
+ String type = ThrottleConstants.IP_BASE ==
configuration.getType() ?
+ "IP address" : "domain";
+ log.debug("Even unit time has overed , CallerContext
in prohibit state :"
+ + type + " - " + this.ID);
+ }
+ }
+ }
+
+ }
+ return canAcess;
+
+ }
+
+ /**
+ * Clean up the callers - remove all callers that have expired their time
window
+ * @param configuration -The Configuration for this caller
+ * @param throttleContext -The Throttle that caller having pass
+ * @param currentTime -The system current time
+ */
+ public void cleanUpCallers(CallerConfiguration configuration,
ThrottleContext throttleContext, long currentTime) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Cleaning up the inactive caller's states ... ");
+ }
+ if (configuration == null) {
+ if(log.isDebugEnabled()){
+ log.debug("Couldn't find the configuration .");
+ }
+ return;
+ }
+ // if number of access for a unit time is less than MAX and
+ // if the unit time period (session time) has overed
+
+ int maxRequest = configuration.getMaximumRequestPerUnitTime();
+ if (!(maxRequest == 0)) {
+ if (this.count <= maxRequest - 1) {
+ if (this.nextTimeWindow != 0) {
+ if(log.isDebugEnabled()){
+ log.debug("Removing caller with id "+this.ID);
+ }
+ //remove the previous callercontext
+ throttleContext.removeCallerContext(new
Long(nextTimeWindow));
+ throttleContext.flush();// Sends the current state to
others (clustered env)
+ }
+ } else {
+ // if number of access for a unit time has just been greater
than MAX
+ // now same as a new session
+ // OR
+ // if caller in prohabit session and prohabit period has
just overed
+ if ((this.nextAccessTime == 0) ||
+ (this.nextAccessTime <= currentTime)) {
+ if (this.nextTimeWindow != 0) {
+ if (log.isDebugEnabled()) {
+ log.debug("Removing caller with id " + this.ID);
+ }
+ //remove the previous callercontext
+ throttleContext.removeCallerContext(new
Long(this.nextTimeWindow));
+ throttleContext.flush();// Sends the current state to
others (clustered env)
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Check whether that caller can access or not ,based on curret state and
pre-defined policy
+ *
+ * @param throttleContext -The Context for this caller - runtime state
+ * @param configuration -The Configuration for this caller - data from
policy
+ * @param currentTime - The current system time
+ * @return boolean -The boolean value which say access will
allolw or not
+ * @throws ThrottleException throws for invalid throttle configuration
+ */
+ public boolean canAccess(ThrottleContext throttleContext,
CallerConfiguration configuration, long currentTime) throws ThrottleException {
+ boolean canAcess;
+ if (configuration == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Couldn't find the configuration .");
+ }
+ return true;
+ }
+ if (configuration.getMaximumRequestPerUnitTime() < 0
+ || configuration.getUnitTime() <= 0
+ || configuration.getProhibitTimePeriod() < 0) {
+ throw new ThrottleException("Invalid Throttle Configuration");
+ }
+
+ // if caller access first time in his new session
+ if (this.firstAccessTime == 0) {
+ initAccess(configuration, throttleContext, currentTime);
+ }
+ // if unit time period (session time) is not over
+ if (this.nextTimeWindow > currentTime) {
+ canAcess =
canAccessIfUnitTimeNotOver(configuration,throttleContext, currentTime);
+ } else {
+ canAcess = canAccessIfUnitTimeOver(configuration, throttleContext,
currentTime);
+ }
+
+ return canAcess;
+
+ }
+
+ /**
+ * Returns the next time window
+ *
+ * @return long value of next time window
+ */
+ public long getNextTimeWindow() {
+ return this.nextTimeWindow;
+ }
+
+ /**
+ * Gets type of throttle that this caller belong ex : ip/domain
+ * @return Returns the type of the throttle
+ */
+ public abstract int getType();
+
+}
Added:
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/factory/CallerContextFactory.java
==============================================================================
--- (empty file)
+++
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/factory/CallerContextFactory.java
Sun Dec 2 22:50:16 2007
@@ -0,0 +1,49 @@
+/*
+* Copyright 2004,2005 The Apache Software Foundation.
+*
+* Licensed 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 org.wso2.throttle.factory;
+
+import org.wso2.throttle.CallerContext;
+import org.wso2.throttle.ThrottleConstants;
+import org.wso2.throttle.ThrottleException;
+import org.wso2.throttle.impl.domainbase.DomainBaseCallerContext;
+import org.wso2.throttle.impl.ipbase.IPBaseCallerContext;
+
+/**
+ * Factory for creating a CallerContext
+ *
+ */
+
+public class CallerContextFactory {
+
+ /**
+ * To create a CallerContext(the run time data holder for a remote caller)
for the given throttle type.
+ * Needs to provide the ID(ip | domain) of the remote caller (ip/domain
accoding to the policy)
+ *
+ * @param throttletype - The type of the throttle
+ * @param id - The id of the caller
+ * @return caller - The corresponding caller context for the given
throttle type
+ * @throws ThrottleException - Throws for if the throttle type is unknown
+ */
+ public static CallerContext createCaller(int throttletype, String id)
throws ThrottleException {
+ if (ThrottleConstants.IP_BASE == throttletype) {
+ return new IPBaseCallerContext(id);
+ } else if (ThrottleConstants.DOMAIN_BASE == throttletype) {
+ return new DomainBaseCallerContext(id);
+ } else {
+ throw new ThrottleException("unknown throttle type");
+ }
+ }
+}
Added:
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/impl/domainbase/DomainBaseCallerContext.java
==============================================================================
--- (empty file)
+++
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/impl/domainbase/DomainBaseCallerContext.java
Sun Dec 2 22:50:16 2007
@@ -0,0 +1,41 @@
+/*
+* 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 org.wso2.throttle.impl.domainbase;
+
+import org.wso2.throttle.CallerContext;
+import org.wso2.throttle.ThrottleConstants;
+
+import java.io.Serializable;
+
+/**
+ *Caller Context implementation for domain name based throttle type caller
+ */
+
+public class DomainBaseCallerContext extends CallerContext implements
Serializable {
+
+ private static final long serialVersionUID = 5681795068518758365L;
+
+ public DomainBaseCallerContext(String ID) {
+ super(ID);
+ }
+
+ public int getType() {
+ return ThrottleConstants.DOMAIN_BASE;
+ }
+}
Added:
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/impl/ipbase/IPBaseCallerContext.java
==============================================================================
--- (empty file)
+++
trunk/commons/throttle/modules/core/src/main/java/org/wso2/throttle/impl/ipbase/IPBaseCallerContext.java
Sun Dec 2 22:50:16 2007
@@ -0,0 +1,45 @@
+/*
+* Copyright 2005,2006 WSO2, Inc. http://wso2.com
+*
+* Licensed 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 org.wso2.throttle.impl.ipbase;
+
+import org.wso2.throttle.CallerContext;
+import org.wso2.throttle.ThrottleConstants;
+
+import java.io.Serializable;
+
+/**
+ * Caller Context implementation for ip name based throttle type caller
+ *
+ */
+
+public class IPBaseCallerContext extends CallerContext implements Serializable
{
+
+ private static final long serialVersionUID = 635051645003581667L;
+
+ public IPBaseCallerContext(String ID) {
+ super(ID);
+ }
+
+ /**
+ * @return int value that indicate the type of throttle
+ */
+ public int getType() {
+ return ThrottleConstants.IP_BASE;
+ }
+}
\ No newline at end of file
_______________________________________________
Commons-dev mailing list
[email protected]
http://wso2.org/cgi-bin/mailman/listinfo/commons-dev