/* * 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.apache.synapse.commons.throttle.core; import org.apache.axiom.om.OMElement; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.neethi.Policy; import org.apache.neethi.PolicyEngine; import org.apache.neethi.builders.xml.XmlPrimtiveAssertion; import org.apache.synapse.commons.throttle.core.factory.CallerConfigurationFactory; import org.apache.synapse.commons.throttle.core.factory.ThrottleConfigurationFactory; import org.apache.synapse.commons.throttle.core.factory.ThrottleContextFactory; import javax.xml.namespace.QName; import java.util.Iterator; import java.util.List; /** * Factory for creating a throttle instance using throttle policy */ public class ThrottleFactory { private ThrottleFactory() { } private static Log log = LogFactory.getLog(ThrottleFactory.class); /** * Abstraction for processing module policy assertion and create a throttle based on it * * @param policy Throttle policy * @return Throttle instance , if there any module policy assertion , otherwise null * @throws ThrottleException */ public static Throttle createModuleThrottle(Policy policy) throws ThrottleException { return createThrottle(policy, ThrottleConstants.MODULE_THROTTLE_ASSERTION_QNAME); } /** * Abstraction for processing service policy assertion and create a throttle based on it * * @param policy Throttle policy * @return Throttle instance , if there any service policy assertion , otherwise null * @throws ThrottleException */ public static Throttle createServiceThrottle(Policy policy) throws ThrottleException { return createThrottle(policy, ThrottleConstants.SERVICE_THROTTLE_ASSERTION_QNAME); } /** * Abstraction for processing operation policy assertion and create a throttle based on it * * @param policy Throttle policy * @return Throttle instance , if there any operation policy assertion , otherwise null * @throws ThrottleException */ public static Throttle createOperationThrottle(Policy policy) throws ThrottleException { return createThrottle(policy, ThrottleConstants.OPERATION_THROTTLE_ASSERTION_QNAME); } /** * Abstraction for processing mediator policy assertion and create a throttle based on it * * @param policy Throttle policy * @return Throttle instance , if there any mediator policy assertion , otherwise null * @throws ThrottleException */ public static Throttle createMediatorThrottle(Policy policy) throws ThrottleException { return createThrottle(policy, ThrottleConstants.MEDIATOR_THROTTLE_ASSERTION_QNAME); } /** * Factory method to create a throttle from a given throttle policy * * @param policy Throttle policy * @param forceRoot Root assertion QName for select correct policy assertion * @return Throttle instance * @throws ThrottleException */ private static Throttle createThrottle(Policy policy, QName forceRoot) throws ThrottleException { if (policy == null) { if (log.isDebugEnabled()) { log.debug("Policy cannot be found"); } //if policy is not available ,then return null for ThrottleConfiguration return null; // no policy is available in the module description } if (forceRoot == null) { if (log.isDebugEnabled()) { log.debug("Given root assertion QName is null"); } return null; } for (Iterator iterator = policy.getAlternatives(); iterator.hasNext(); ) { Object object = iterator.next(); if (object instanceof List) { List list = (List) object; for (Iterator it = list.iterator(); it.hasNext(); ) { Object assertObj = it.next(); if (assertObj instanceof XmlPrimtiveAssertion) { XmlPrimtiveAssertion primitiveAssertion = (XmlPrimtiveAssertion) assertObj; QName qName = primitiveAssertion.getName(); if (qName == null) { handleException("Invalid Throttle Policy - QName of the " + "assertion cannot be null."); } // top policy must contains ThrottleAssertion Policy throttlePolicy = PolicyEngine. getPolicy(primitiveAssertion.getValue()); if (ThrottleConstants.THROTTLE_ASSERTION_QNAME.equals(qName)) { return ThrottlePolicyProcessor.processPolicy(throttlePolicy); } else if (forceRoot.equals(qName)) { return buildThrottle(throttlePolicy); } else { if (log.isDebugEnabled()) { log.debug("There is no throttle policy " + "for given QName : " + forceRoot); } } } } } } return null; } /** * Factory method to help to create a throttle * * @param throtlePolicy Throttle assertion policy * @return Throttle instance * @throws ThrottleException */ private static Throttle buildThrottle(Policy throtlePolicy) throws ThrottleException { Throttle throttle = new Throttle(); // throttle instance ThrottleConfiguration configuration = null; // configuration data List list = throtlePolicy.getPolicyComponents(); if (list == null || (list != null && list.isEmpty())) { handleException("Empty the policy components" + " as ThrottleAssertion's children"); } for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { Object object = iterator.next(); if (object instanceof Policy) { // boolean isOtherConfiguration = false; // // To track default callerConfiguration for all ips CallerConfiguration callerConfiguration = null; Policy policy = null; List assertList = ((Policy) object).getAssertions(); if (assertList != null) { for (Iterator assertIterator = assertList.iterator(); assertIterator.hasNext(); ) { Object ca = assertIterator.next(); if (ca instanceof XmlPrimtiveAssertion) { XmlPrimtiveAssertion id = (XmlPrimtiveAssertion) ca; configuration = createThrottleConfiguration(id, throttle); if (configuration == null) { handleException("Invalid throttle - Throttle configuration " + "cannot be created from given policy"); } if (configuration.getType() == ThrottleConstants.IP_BASE) { //create a caller context for ip based throttle callerConfiguration = CallerConfigurationFactory. createCallerConfiguration( ThrottleConstants.IP_BASE); } else if (configuration.getType() == ThrottleConstants.DOMAIN_BASE) { //create a caller context for ip based throttle callerConfiguration = CallerConfigurationFactory. createCallerConfiguration( ThrottleConstants.DOMAIN_BASE); } else if (configuration.getType() == ThrottleConstants.ROLE_BASE) { //create a caller context for ip based throttle callerConfiguration = CallerConfigurationFactory. createCallerConfiguration( ThrottleConstants.ROLE_BASE); } else { handleException("Invalid throttle type - Only" + " support IP ,DOMAIN and ROLE as types "); } if (callerConfiguration != null) { OMElement element = id.getValue(); // Name of the policy assertion String name = element.getLocalName(); // Value of the policy assertion String value = element.getText(); // If Value and Name are null, // then it is a invalid policy configuration if (name == null || value == null) { handleException("Either Value or" + " Name of the policy cannot be null"); } else if (name.equals(ThrottleConstants.ID_PARAMETER_NAME)) { if (!value.equals("")) { callerConfiguration.setID(value); } else { handleException("Value of ID cannot find " + "- invalid configuration"); } } else { handleException("Undefined policy property for" + " throttle - Expect ID "); } } } else if (ca instanceof Policy) { policy = (Policy) ca; } } } if (callerConfiguration != null) { if (policy != null) { fillCallerConfiguration(policy, callerConfiguration); configuration.addCallerConfiguration(callerConfiguration); } } else { if (log.isDebugEnabled()) { log.debug("Couldn't find a callerConfiguration for a throttle" + " configuration for an one caller "); } } } else if (object instanceof XmlPrimtiveAssertion) { XmlPrimtiveAssertion xmlPrimitiveAssertion = (XmlPrimtiveAssertion) object; OMElement element = xmlPrimitiveAssertion.getValue(); // Name of the policy assertion String name = element.getLocalName(); //Value of the policy assertion String value = element.getText(); //if Value and Name are null,then // it is a invalid policy configuration if (name == null || value == null) { handleException("Either value or name of the policy cannot be null"); } else if (name.equals( ThrottleConstants.MAXIMUM_CONCURRENT_ACCESS_PARAMETER_NAME)) { int intValue = 0; try { intValue = Integer.parseInt(value.trim()); } catch (NumberFormatException ignored) { log.error("Error occurred - Invalid number for maximum " + "concurrent access ", ignored); } if (intValue > 0) { throttle.setConcurrentAccessController( new ConcurrentAccessController(intValue)); } } else { handleException("Invalid throttle policy configuration : unexpected policy " + "element with name " + name); } } } return throttle; } /** * Factory method to create a Throttle Configuration instance * * @param id Policy assertion relates to a particular caller * @param throttle Throttle instance * @return Throttle Configuration instance * @throws ThrottleException */ private static ThrottleConfiguration createThrottleConfiguration(XmlPrimtiveAssertion id, Throttle throttle) throws ThrottleException { OMElement element = id.getValue(); ThrottleConfiguration configuration = null; String type = element.getAttributeValue( ThrottleConstants.THROTTLE_TYPE_ATTRIBUTE_QNAME); if (type == null) { handleException("Type of Throttle " + "in the policy cannot be null"); } if ("IP".equals(type)) { // create a ip based throttle context and configuration configuration = throttle.getThrottleConfiguration (ThrottleConstants.IP_BASED_THROTTLE_KEY); if (configuration == null) { configuration = ThrottleConfigurationFactory. createThrottleConfiguration( ThrottleConstants.IP_BASE); throttle.addThrottleContext( ThrottleConstants.IP_BASED_THROTTLE_KEY, ThrottleContextFactory.createThrottleContext( ThrottleConstants.IP_BASE, configuration)); throttle.addThrottleConfiguration( ThrottleConstants.IP_BASED_THROTTLE_KEY, configuration); } } else if (("DOMAIN".equals(type))) { // create a domain based throttle context and configuration configuration = throttle.getThrottleConfiguration( ThrottleConstants.DOMAIN_BASED_THROTTLE_KEY); if (configuration == null) { configuration = ThrottleConfigurationFactory. createThrottleConfiguration( ThrottleConstants.DOMAIN_BASE); throttle.addThrottleContext( ThrottleConstants.DOMAIN_BASED_THROTTLE_KEY, ThrottleContextFactory.createThrottleContext( ThrottleConstants.DOMAIN_BASE, configuration)); throttle.addThrottleConfiguration( ThrottleConstants.DOMAIN_BASED_THROTTLE_KEY, configuration); } //create a caller context for domain based throttle } else if (("ROLE".equals(type))) { // create a domain based throttle context and configuration configuration = throttle.getThrottleConfiguration( ThrottleConstants.ROLE_BASED_THROTTLE_KEY); if (configuration == null) { configuration = ThrottleConfigurationFactory. createThrottleConfiguration( ThrottleConstants.ROLE_BASE); throttle.addThrottleContext( ThrottleConstants.ROLE_BASED_THROTTLE_KEY, ThrottleContextFactory.createThrottleContext( ThrottleConstants.ROLE_BASE, configuration)); throttle.addThrottleConfiguration( ThrottleConstants.ROLE_BASED_THROTTLE_KEY, configuration); } //create a caller context for domain based throttle } else { handleException("Unsupported throttle type : " + type); } return configuration; } /** * Fills the caller configuration information based on given policy * * @param policy Policy instance * @param callerConfiguration Caller configuration instance * @throws ThrottleException */ private static void fillCallerConfiguration(Policy policy, CallerConfiguration callerConfiguration) throws ThrottleException { List list = policy.getPolicyComponents(); for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { Object object = iterator.next(); XmlPrimtiveAssertion primitiveAssertion = (XmlPrimtiveAssertion) object; OMElement element = primitiveAssertion.getValue(); // Name of the policy assertion String name = element.getLocalName(); if (name.equals( ThrottleConstants.ALLOW_PARAMETER_NAME)) { callerConfiguration.setAccessState( ThrottleConstants.ACCESS_ALLOWED); } else if (name.equals( ThrottleConstants.DENY_PARAMETER_NAME)) { callerConfiguration.setAccessState( ThrottleConstants.ACCESS_DENIED); } else if (name.equals( ThrottleConstants.CONTROL_PARAMETER_NAME)) { callerConfiguration.setAccessState( ThrottleConstants.ACCESS_CONTROLLED); OMElement controlElement = primitiveAssertion.getValue(); if (controlElement == null) { handleException("Invalid throttle configuration - " + "Control assertion cannot be empty"); } Policy controlPolicy = PolicyEngine.getPolicy(controlElement); if (controlPolicy != null) { fillControlConfiguration(controlPolicy, callerConfiguration); } else { handleException("Invalid throttle configuration - " + "Cannot create a policy object(Control Assertion ) " + "form given policy file "); } } else { handleException("Invalid Throttle" + " Policy configuration"); } } } /** * Helper method to process control assertion * * @param policy Policy for Control Assertion * @param callerConfiguration Caller to whom control need to be applied. * @throws ThrottleException */ private static void fillControlConfiguration(Policy policy, CallerConfiguration callerConfiguration) throws ThrottleException { boolean isFoundMaxCount = false; boolean isFoundUnitTime = false; List list = policy.getPolicyComponents(); for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { Object obj = iterator.next(); if (obj instanceof Policy) { List controlList = ((Policy) obj).getPolicyComponents(); for (Iterator controlIterator = controlList.iterator(); controlIterator.hasNext(); ) { Object object = controlIterator.next(); if (object instanceof XmlPrimtiveAssertion) { XmlPrimtiveAssertion primitiveAssertion = (XmlPrimtiveAssertion) object; OMElement element = primitiveAssertion.getValue(); // Name of the policy assertion String name = element.getLocalName(); //Value of the policy assertion String value = element.getText(); //if Value and Name are null,then it is a // invalid policy configuration if (name == null || value == null) { handleException("Either Value or " + "Name of the policy cannot be null"); } if (!value.equals("")) { if (name.equals( ThrottleConstants. MAXIMUM_COUNT_PARAMETER_NAME)) { isFoundMaxCount = true; try { callerConfiguration.setMaximumRequestPerUnitTime( Integer.parseInt(value.trim())); } catch (NumberFormatException ignored) { log.error("Error occurred - " + "Invalid number for maximum " + "request number ", ignored); if (log.isDebugEnabled()) { log.debug("Access" + " will be fully allowed"); } callerConfiguration.setAccessState( ThrottleConstants.ACCESS_ALLOWED); } } else if (name.equals( ThrottleConstants. UNIT_TIME_PARAMETER_NAME)) { //TODO need to verify that value is in milisecond long timeInMilliSec = 0; try { timeInMilliSec = Long.parseLong(value.trim()); } catch (NumberFormatException ignored) { log.error("Error occurred " + "- Invalid number for unit time", ignored); } if (timeInMilliSec == 0) { handleException("Unit Time cannot " + "find - invalid throttle " + "policy configuration"); } isFoundUnitTime = true; callerConfiguration.setUnitTime(timeInMilliSec); } else if (name.equals( ThrottleConstants. PROHIBIT_TIME_PERIOD_PARAMETER_NAME)) { try { callerConfiguration.setProhibitTimePeriod( Long.parseLong(value.trim())); } catch (NumberFormatException ignored) { log.error("Error occurred - Invalid" + " number for prohibit time ", ignored); } } else { handleException("Undefined Policy" + " property for Throttle Policy"); } } else { if (!name.equals( ThrottleConstants. PROHIBIT_TIME_PERIOD_PARAMETER_NAME)) { handleException("The policy which have " + " defined as optional " + "should have value "); } } } } } else { handleException("Invalid policy - " + "Control Assertion must contain a wsp:Policy as child "); } } if (!isFoundUnitTime && !isFoundMaxCount) { handleException("Maximum Count and UnitTime are " + "Mandatory in Throttle Policy "); } } /** * Helper method to handle exception * * @param message Debug message * @throws ThrottleException */ private static void handleException(String message) throws ThrottleException { String msg = "Error was occurred during throttle policy processing : " + message; log.error(msg); throw new ThrottleException(msg); } }