# IPBaseThrottleConfiguration.java

    /*
    * Copyright 2005,2006 WSO2, Inc. http://www.wso2.org
    *
    * 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.apache.synapse.commons.throttle.core.impl.ipbase;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.apache.synapse.commons.throttle.core.CallerConfiguration;
    import org.apache.synapse.commons.throttle.core.ThrottleConfiguration;
    import org.apache.synapse.commons.throttle.core.ThrottleConstants;

    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;

    public class IPBaseThrottleConfiguration implements ThrottleConfiguration {

        private static Log log = LogFactory.getLog(IPBaseThrottleConfiguration.class.getName());

        /* The key for "Other" configuration */
        private String keyOfOther;

        /* The default configuration for a throttle and this will apply to callersMap
        that have not a custom configuration */
        private CallerConfiguration defaultCallerConfiguration;

        /* To hold configurations */
        private Map configurationsMap;

        public IPBaseThrottleConfiguration() {
            this.configurationsMap = new HashMap();
        }

        /**
         * To get a IPBaseCallerConfiguration - if a configuration for given key found ,it returns ,
         * other wise , the default configuration will return.
         *
         * @param ID - The Remote caller id (IP)
         * @return Returns the corresponding configuration for the caller with given ID
         */
        public CallerConfiguration getCallerConfiguration(String ID) {

            if (ID.equals(ThrottleConstants.KEY_OF_DEFAULT_CONFIGURATION_FOR_OTHER)) {
                return defaultCallerConfiguration;
            } else {
                String key = getConfigurationKeyOfCaller(ID);
                if (key != null) {
                    if (key.equals(ThrottleConstants.KEY_OF_DEFAULT_CONFIGURATION_FOR_OTHER)) {
                        return defaultCallerConfiguration;
                    }
                    return (CallerConfiguration) configurationsMap.get(key);
                }
            }
            return null;
        }

        /**
         * To add a IPBaseCallerConfiguration
         *
         * @param configuration The configuration for a caller
         */
        public void addCallerConfiguration(CallerConfiguration configuration) {
            //TODO need to allow overlapping of ip with FirstPartOfIPRange
            IPBaseCallerConfiguration ipBaseCallerConfiguration =
                    (IPBaseCallerConfiguration) configuration;
            String key = ipBaseCallerConfiguration.getFirstPartOfIPRange();
            if (key == null) {
                return;
            }
            key = key.trim();
            if (key.equals(ThrottleConstants.KEY_OF_DEFAULT_CONFIGURATION_FOR_OTHER)) {
                keyOfOther = ThrottleConstants.KEY_OF_DEFAULT_CONFIGURATION_FOR_OTHER;
                defaultCallerConfiguration = ipBaseCallerConfiguration;
            } else {
                configurationsMap.put(key, ipBaseCallerConfiguration);
            }
        }

        /**
         * To get key for access configuration
         *
         * @param callerID The remote caller id (ip)
         * @return Object-String representation of  corrected epr-key for get configuration
         */
        public String getConfigurationKeyOfCaller(String callerID) {

            if (callerID != null) {
                callerID = callerID.trim();
                //if there is a unique IP
                if (configurationsMap.containsKey(callerID)) {
                    return callerID;
                } else {
                    int index = callerID.lastIndexOf(".");
                    if (index > 0) {
                        String net = callerID.substring(0, index);     // get the network portion
                        String host = callerID.substring(index + 1, callerID.length());
                        //get the host portion
                        if (net != null && host != null) {
                            Set keys = configurationsMap.keySet();
                            if (keys != null && !keys.isEmpty()) {
                                for (Iterator it = keys.iterator(); it.hasNext(); ) {
                                    String key = (String) it.next();
                                    if (key != null && key.startsWith(net) && isAfter(key, host)) {
                                        // all ips with in same network
                                        IPBaseCallerConfiguration con =
                                                (IPBaseCallerConfiguration) configurationsMap.get(key);
                                        if (con != null) {
                                            String secondPart = con.getSecondPartOfIPRange();
                                            if (secondPart != null && isBefore(secondPart, host)) {
                                                return key;
                                            }
                                        }
                                    }
                                }
                                String all = net + ".*";
                                if (configurationsMap.containsKey(all)) {
                                    return all;
                                }
                            }
                        }
                    }
                }
            }
            return keyOfOther;
        }

        /**
         * Helper method to check the ip with the given host is exists  after the given  ip
         *
         * @param ip   The lower IP
         * @param host host
         * @return true if the ip with host is higher than given ip ,ow. false
         */
        private boolean isAfter(String ip, String host) {
            int index = ip.lastIndexOf(".");
            if (index > 0) {
                // host of first part of ip
                String hostfromip = ip.substring(index + 1, ip.length());
                if (hostfromip != null && host != null) {

                    return toInt(hostfromip) <= toInt(host);
                }
            }
            return false;
        }

        /**
         * Helper method to check the ip with the given host is exists  before the given  ip
         *
         * @param ip   the higher ip
         * @param host host
         * @return true if the ip with host is lower than given ip ,ow. false
         */
        private boolean isBefore(String ip, String host) {
            int index = ip.lastIndexOf(".");
            if (index > 0) {
                // host of second part of ip
                String hostfromip = ip.substring(index + 1, ip.length());
                if (hostfromip != null && host != null) {

                    return toInt(hostfromip) >= toInt(host);

                }
            }
            return false;
        }

        public int getType() {
            return ThrottleConstants.IP_BASE;
        }

        private int toInt(String str) {

            if (str == null || "".equals(str)) {
                handleException("Invalid string - null value");
            }

            try {
                return Integer.parseInt(str.trim());
            } catch (NumberFormatException e) {
                handleException("Invalid string '" + str + "' , except an integer value ");
            }
            return -1;
        }

        private void handleException(String message) {
            String msg = "Error was occurred during ip(ip-range) processing  " + message;
            log.error(msg);
            throw new IllegalArgumentException(msg);
        }
    }