/** * Copyright 2016 Yahoo Inc. * * 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 com.yahoo.pulsar.common.policies.impl; import java.util.HashMap; import java.util.Map; import java.util.SortedSet; import com.yahoo.pulsar.common.naming.NamespaceName; import com.yahoo.pulsar.common.policies.NamespaceIsolationPolicy; import com.yahoo.pulsar.common.policies.data.BrokerAssignment; import com.yahoo.pulsar.common.policies.data.BrokerStatus; import com.yahoo.pulsar.common.policies.data.NamespaceIsolationData; public class NamespaceIsolationPolicies { private Map<String, NamespaceIsolationData> policies = null; public NamespaceIsolationPolicies() { policies = new HashMap<String, NamespaceIsolationData>(); } public NamespaceIsolationPolicies(Map<String, NamespaceIsolationData> policiesMap) { policies = policiesMap; } /** * Access method to get the namespace isolation policy by the policy name * * @param policyName * @return */ public NamespaceIsolationPolicy getPolicyByName(String policyName) { if (policies.get(policyName) == null) { return null; } return new NamespaceIsolationPolicyImpl(policies.get(policyName)); } /** * Get the namespace isolation policy for the specified namespace * * <p> * There should only be one namespace isolation policy defined for the specific namespace. If multiple policies * match, the first one will be returned. * <p> * * @param namespace * @return */ public NamespaceIsolationPolicy getPolicyByNamespace(NamespaceName namespace) { for (NamespaceIsolationData nsPolicyData : policies.values()) { if (this.namespaceMatches(namespace, nsPolicyData)) { return new NamespaceIsolationPolicyImpl(nsPolicyData); } } return null; } private boolean namespaceMatches(NamespaceName namespace, NamespaceIsolationData nsPolicyData) { for (String nsnameRegex : nsPolicyData.namespaces) { if (namespace.toString().matches(nsnameRegex)) { return true; } } return false; } /** * Set the policy data for a single policy * * @param policyName * @param policyData */ public void setPolicy(String policyName, NamespaceIsolationData policyData) { policyData.validate(); policies.put(policyName, policyData); } /** * Delete a policy * * @param policyName */ public void deletePolicy(String policyName) { policies.remove(policyName); } /** * Get the full policy map * * @return All policy data in a map */ public Map<String, NamespaceIsolationData> getPolicies() { return this.policies; } /** * Check to see whether a broker is in the shared broker pool or not * * @param host * @return */ public boolean isSharedBroker(String host) { for (NamespaceIsolationData policyData : this.policies.values()) { NamespaceIsolationPolicyImpl policy = new NamespaceIsolationPolicyImpl(policyData); if (policy.isPrimaryBroker(host)) { // not free for sharing, this is some properties' primary broker return false; } } return true; } /** * Get the broker assignment based on the namespace name * * @param nsname * The namespace name * @param brokerAddress * The broker adderss is the format of host:port * @return The broker assignment: {primary, secondary, shared} */ private BrokerAssignment getBrokerAssignment(NamespaceIsolationPolicy nsPolicy, String brokerAddress) { if (nsPolicy != null) { if (nsPolicy.isPrimaryBroker(brokerAddress)) { return BrokerAssignment.primary; } else if (nsPolicy.isSecondaryBroker(brokerAddress)) { return BrokerAssignment.secondary; } throw new IllegalArgumentException("The broker " + brokerAddress + " is not among the assigned broker pools for the controlled namespace."); } // Only uncontrolled namespace will be assigned to the shared pool if (!this.isSharedBroker(brokerAddress)) { throw new IllegalArgumentException("The broker " + brokerAddress + " is not among the shared broker pools for the uncontrolled namespace."); } return BrokerAssignment.shared; } public void assignBroker(NamespaceName nsname, BrokerStatus brkStatus, SortedSet<BrokerStatus> primaryCandidates, SortedSet<BrokerStatus> secondaryCandidates, SortedSet<BrokerStatus> sharedCandidates) { NamespaceIsolationPolicy nsPolicy = this.getPolicyByNamespace(nsname); BrokerAssignment brokerAssignment = this.getBrokerAssignment(nsPolicy, brkStatus.getBrokerAddress()); if (brokerAssignment == BrokerAssignment.primary) { // Only add to candidates if allowed by policy if (nsPolicy != null && nsPolicy.isPrimaryBrokerAvailable(brkStatus)) { primaryCandidates.add(brkStatus); } } else if (brokerAssignment == BrokerAssignment.secondary) { secondaryCandidates.add(brkStatus); } else if (brokerAssignment == BrokerAssignment.shared) { sharedCandidates.add(brkStatus); } } }