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

Reply via email to