2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.resolver;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ConcurrentMap;
21 import java.util.concurrent.CopyOnWriteArrayList;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.atomic.AtomicReference;
25 import javax.annotation.concurrent.Immutable;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
32 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ConsumerSelectionRelator;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Matcher.MatchType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ProviderSelectionRelator;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.QualityMatcher;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Target;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.GroupIdentificationConstraints;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.GroupRequirementConstraintCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.group.requirement.constraint._case.RequirementMatcher;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.GroupCapabilityConstraintCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.group.capability.constraint._case.CapabilityMatcher;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.RuleBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelector;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderTargetSelector;
64 import org.opendaylight.yangtools.concepts.ListenerRegistration;
65 import org.opendaylight.yangtools.yang.binding.DataObject;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
70 import com.google.common.base.Optional;
71 import com.google.common.base.Predicate;
72 import com.google.common.collect.HashBasedTable;
73 import com.google.common.collect.ImmutableSet;
74 import com.google.common.collect.Ordering;
75 import com.google.common.collect.Sets;
76 import com.google.common.collect.Table;
77 import com.google.common.collect.Table.Cell;
78 import com.google.common.util.concurrent.FutureCallback;
79 import com.google.common.util.concurrent.Futures;
80 import com.google.common.util.concurrent.ListenableFuture;
83 * The policy resolver is a utility for renderers to help in resolving
84 * group-based policy into a form that is easier to apply to the actual network.
86 * For any pair of endpoint groups, there is a set of rules that could apply to
87 * the endpoints on that group based on the policy configuration. The exact list
88 * of rules that apply to a given pair of endpoints depends on the conditions
89 * that are active on the endpoints.
91 * We need to be able to query against this policy model, enumerate the relevant
92 * classes of traffic and endpoints, and notify renderers when there are changes
93 * to policy as it applies to active sets of endpoints and endpoint groups.
95 * The policy resolver will maintain the necessary state for all tenants in its
96 * control domain, which is the set of tenants for which policy listeners have
100 public class PolicyResolver implements AutoCloseable {
101 private static final Logger LOG = LoggerFactory.getLogger(PolicyResolver.class);
103 private final DataBroker dataProvider;
104 private final ScheduledExecutorService executor;
107 * Keep track of the current relevant policy scopes.
109 protected CopyOnWriteArrayList<PolicyScope> policyListenerScopes;
111 protected ConcurrentMap<TenantId, TenantContext> resolvedTenants;
114 * Store a policy object for each endpoint group pair. The table is stored
115 * with the key as (consumer, provider). Two endpoints could appear in both
116 * roles at the same time, in which case both policies would apply.
118 AtomicReference<PolicyInfo> policy = new AtomicReference<>();
120 public PolicyResolver(DataBroker dataProvider,
121 ScheduledExecutorService executor) {
123 this.dataProvider = dataProvider;
124 this.executor = executor;
125 policyListenerScopes = new CopyOnWriteArrayList<>();
126 resolvedTenants = new ConcurrentHashMap<>();
127 LOG.debug("Initialized renderer common policy resolver");
135 public void close() throws Exception {
136 for (TenantContext ctx : resolvedTenants.values()) {
137 if (ctx.registration != null)
138 ctx.registration.close();
142 // *************************
143 // PolicyResolver public API
144 // *************************
147 * Get a snapshot of the current policy
149 * @return the {@link PolicyInfo} object representing an immutable snapshot
150 * of the policy state
152 public PolicyInfo getCurrentPolicy() {
157 * Get the normalized tenant for the given ID
161 * @return the {@link Tenant}
163 public IndexedTenant getTenant(TenantId tenant) {
164 TenantContext tc = resolvedTenants.get(tenant);
167 return tc.tenant.get();
171 * Register a listener to receive update events.
174 * the {@link PolicyListener} object to receive the update events
176 public PolicyScope registerListener(PolicyListener listener) {
177 PolicyScope ps = new PolicyScope(this, listener);
178 policyListenerScopes.add(ps);
184 * Remove the listener registered for the given {@link PolicyScope}.
187 * the scope to remove
188 * @see PolicyResolver#registerListener(PolicyListener)
190 public void removeListener(PolicyScope scope) {
191 policyListenerScopes.remove(scope);
199 * Atomically update the active policy and notify policy listeners of
203 * the new policy to set
204 * @param egConditions
205 * the map of endpoint groups to relevant condition sets
206 * @return the set of groups with updated policy
208 protected Set<EgKey> updatePolicy(Table<EgKey, EgKey, Policy> policyMap,
209 Map<EgKey, Set<ConditionSet>> egConditions,
210 List<PolicyScope> policyListenerScopes) {
211 PolicyInfo newPolicy = new PolicyInfo(policyMap, egConditions);
212 PolicyInfo oldPolicy = policy.getAndSet(newPolicy);
214 HashSet<EgKey> notifySet = new HashSet<>();
216 for (Cell<EgKey, EgKey, Policy> cell : newPolicy.getPolicyMap().cellSet()) {
217 Policy newp = cell.getValue();
219 if (oldPolicy != null)
220 oldp = oldPolicy.getPolicyMap().get(cell.getRowKey(),
221 cell.getColumnKey());
222 if (oldp == null || !newp.equals(oldp)) {
223 notifySet.add(cell.getRowKey());
224 notifySet.add(cell.getColumnKey());
227 if (oldPolicy != null) {
228 for (Cell<EgKey, EgKey, Policy> cell : oldPolicy.getPolicyMap().cellSet()) {
229 if (!newPolicy.getPolicyMap().contains(cell.getRowKey(),
230 cell.getColumnKey())) {
231 notifySet.add(cell.getRowKey());
232 notifySet.add(cell.getColumnKey());
240 * Notify the policy listeners about a set of updated groups
242 private void notifyListeners(Set<EgKey> updatedGroups) {
243 for (final PolicyScope scope : policyListenerScopes) {
244 Set<EgKey> filtered =
245 Sets.filter(updatedGroups, new Predicate<EgKey>() {
247 public boolean apply(EgKey input) {
248 return scope.contains(input.getTenantId(),
252 if (!filtered.isEmpty()) {
253 scope.getListener().policyUpdated(filtered);
259 * Subscribe the resolver to updates related to a particular tenant Make
260 * sure that this can't be called concurrently with subscribe
263 * the tenant ID to subscribe to
265 protected void subscribeTenant(TenantId tenantId) {
266 if (!resolvedTenants.containsKey(tenantId))
267 updateTenant(tenantId);
271 * Unsubscribe the resolver from updates related to a particular tenant Make
272 * sure that this can't be called concurrently with subscribe
275 * the tenant ID to subscribe to
277 protected void unsubscribeTenant(TenantId tenantId) {
278 TenantContext context = resolvedTenants.get(tenantId);
279 if (context != null) {
280 resolvedTenants.remove(tenantId);
281 context.registration.close();
285 private void updateTenant(final TenantId tenantId) {
286 if (dataProvider == null)
289 TenantContext context = resolvedTenants.get(tenantId);
290 if (context == null) {
291 ListenerRegistration<DataChangeListener> registration = null;
292 registration = dataProvider
293 .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
294 TenantUtils.tenantIid(tenantId),
295 new PolicyChangeListener(tenantId),
296 DataChangeScope.SUBTREE);
298 context = new TenantContext(registration);
299 TenantContext oldContext =
300 resolvedTenants.putIfAbsent(tenantId, context);
301 if (oldContext != null) {
302 // already registered in a different thread; just use the other
304 registration.close();
305 context = oldContext;
307 LOG.info("Added tenant {} to policy scope", tenantId);
311 // Resolve the new tenant and update atomically
312 final AtomicReference<IndexedTenant> tenantRef = context.tenant;
313 final IndexedTenant ot = tenantRef.get();
314 ReadOnlyTransaction transaction =
315 dataProvider.newReadOnlyTransaction();
316 final InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
317 ListenableFuture<Optional<Tenant>> unresolved;
319 unresolved = transaction.read(LogicalDatastoreType.CONFIGURATION, tiid);
321 Futures.addCallback(unresolved, new FutureCallback<Optional<Tenant>>() {
323 public void onSuccess(Optional<Tenant> result) {
324 if (!result.isPresent()) {
325 LOG.warn("Tenant {} not found", tenantId);
328 Tenant t = InheritanceUtils.resolveTenant(result.get());
329 IndexedTenant it = new IndexedTenant(t);
330 if (!tenantRef.compareAndSet(ot, it)) {
331 // concurrent update of tenant policy. Retry
332 updateTenant(tenantId);
334 // Update the policy cache and notify listeners
335 WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
336 wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true);
343 public void onFailure(Throwable t) {
344 LOG.error("Count not get tenant {}", tenantId, t);
349 protected void updatePolicy() {
351 Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
352 Table<EgKey, EgKey, Policy> policyMap =
353 resolvePolicy(resolvedTenants.values(),
355 Set<EgKey> updatedGroups =
356 updatePolicy(policyMap,
358 policyListenerScopes);
360 notifyListeners(updatedGroups);
361 } catch (Exception e) {
362 LOG.error("Failed to update policy", e);
367 * Resolve the policy in three phases: (1) select contracts that in scope
368 * based on contract selectors. (2) select subjects that are in scope for
369 * each contract based on matchers in clauses (3) resolve the set of
370 * in-scope contracts into a list of subjects that apply for each pair of
371 * endpoint groups and the conditions that can apply for for each endpoint
374 protected Table<EgKey, EgKey, Policy>
375 resolvePolicy(Collection<TenantContext> tenants,
376 Map<EgKey, Set<ConditionSet>> egConditions) {
377 // select contracts that apply for the given tenant
378 Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
379 selectContracts(tenants);
381 // select subjects for the matching contracts and resolve the policy
382 // for endpoint group pairs. This does phase (2) and (3) as one step
383 return selectSubjects(contractMatches, egConditions);
387 * Choose the contracts that are in scope for each pair of endpoint groups,
388 * then perform subject selection for the pair
390 protected Table<EgKey, EgKey, List<ContractMatch>>
391 selectContracts(Collection<TenantContext> tenants) {
392 Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches =
393 HashBasedTable.create();
394 Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
395 HashBasedTable.create();
397 for (TenantContext tenant : tenants) {
398 IndexedTenant t = tenant.tenant.get();
401 selectContracts(consumerMatches,
405 return contractMatches;
408 protected void selectContracts(Table<TenantId,
410 List<ConsumerContractMatch>> consumerMatches,
412 List<ContractMatch>> contractMatches,
414 // For each endpoint group, match consumer selectors
415 // against contracts to get a set of matching consumer selectors
416 if (tenant.getEndpointGroup() == null)
418 for (EndpointGroup group : tenant.getEndpointGroup()) {
419 List<ConsumerContractMatch> r =
420 matchConsumerContracts(tenant, group);
421 for (ConsumerContractMatch ccm : r) {
422 List<ConsumerContractMatch> cms =
423 consumerMatches.get(tenant.getId(),
424 ccm.contract.getId());
426 cms = new ArrayList<>();
427 consumerMatches.put(tenant.getId(),
428 ccm.contract.getId(), cms);
434 // Match provider selectors, and check each match for a corresponding
435 // consumer selector match.
436 for (EndpointGroup group : tenant.getEndpointGroup()) {
437 List<ContractMatch> matches =
438 matchProviderContracts(tenant, group, consumerMatches);
439 for (ContractMatch cm : matches) {
440 EgKey consumerKey = new EgKey(cm.consumerTenant.getId(),
441 cm.consumer.getId());
442 EgKey providerKey = new EgKey(cm.providerTenant.getId(),
443 cm.provider.getId());
444 List<ContractMatch> egPairMatches =
445 contractMatches.get(consumerKey, providerKey);
446 if (egPairMatches == null) {
447 egPairMatches = new ArrayList<>();
448 contractMatches.put(consumerKey, providerKey,
452 egPairMatches.add(cm);
457 private boolean clauseMatches(Clause clause, ContractMatch match) {
458 if (clause.getConsumerMatchers() != null) {
459 GroupIdentificationConstraints groupIdentificationConstraintsConsumer = clause.getConsumerMatchers()
460 .getGroupIdentificationConstraints();
461 if (groupIdentificationConstraintsConsumer instanceof GroupRequirementConstraintCase) {
462 List<RequirementMatcher> reqMatchers = ((GroupRequirementConstraintCase) groupIdentificationConstraintsConsumer)
463 .getRequirementMatcher();
464 if (reqMatchers != null) {
465 for (RequirementMatcher reqMatcher : reqMatchers) {
466 if (!MatcherUtils.applyReqMatcher(reqMatcher,
467 match.consumerRelator)) {
474 if (clause.getProviderMatchers() != null) {
475 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.GroupIdentificationConstraints groupIdentificationConstraintsProvider = clause
476 .getProviderMatchers().getGroupIdentificationConstraints();
477 if (groupIdentificationConstraintsProvider instanceof GroupCapabilityConstraintCase) {
478 List<CapabilityMatcher> capMatchers = ((GroupCapabilityConstraintCase) groupIdentificationConstraintsProvider)
479 .getCapabilityMatcher();
481 if (capMatchers != null) {
482 for (CapabilityMatcher capMatcher : capMatchers) {
483 if (!MatcherUtils.applyCapMatcher(capMatcher,
484 match.providerRelator)) {
494 private ConditionSet buildConditionSet(List<ConditionMatcher> condMatchers) {
495 if (condMatchers == null)
496 return ConditionSet.EMPTY;
498 ImmutableSet.Builder<ConditionName> allb = ImmutableSet.builder();
499 ImmutableSet.Builder<ConditionName> noneb = ImmutableSet.builder();
500 ImmutableSet.Builder<Set<ConditionName>> anyb =
501 ImmutableSet.builder();
502 for (ConditionMatcher condMatcher : condMatchers) {
503 if (condMatcher.getCondition() == null)
505 MatchType type = condMatcher.getMatchType();
507 type = MatchType.All;
508 if (type.equals(MatchType.Any)) {
509 ImmutableSet.Builder<ConditionName> a =
510 ImmutableSet.builder();
511 for (Condition c : condMatcher.getCondition()) {
516 for (Condition c : condMatcher.getCondition()) {
521 noneb.add(c.getName());
525 allb.add(c.getName());
531 return new ConditionSet(allb.build(), noneb.build(), anyb.build());
534 private ConditionSet buildConsConditionSet(Clause clause) {
535 if (clause.getConsumerMatchers() != null) {
536 List<ConditionMatcher> condMatchers =
537 clause.getConsumerMatchers().getConditionMatcher();
538 return buildConditionSet(condMatchers);
540 return ConditionSet.EMPTY;
543 private ConditionSet buildProvConditionSet(Clause clause) {
544 if (clause.getProviderMatchers() != null) {
545 List<ConditionMatcher> condMatchers =
546 clause.getProviderMatchers().getConditionMatcher();
547 return buildConditionSet(condMatchers);
549 return ConditionSet.EMPTY;
552 private Policy resolvePolicy(Tenant contractTenant,
556 Table<ConditionSet, ConditionSet,
557 List<Subject>> subjectMap) {
558 Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap =
559 HashBasedTable.create();
561 ruleMap.putAll(merge.ruleMap);
563 for (Cell<ConditionSet, ConditionSet, List<Subject>> entry : subjectMap.cellSet()) {
564 List<RuleGroup> rules = new ArrayList<>();
565 ConditionSet rowKey = entry.getRowKey();
566 ConditionSet columnKey = entry.getColumnKey();
569 columnKey = entry.getRowKey();
571 List<RuleGroup> oldrules =
572 ruleMap.get(rowKey, columnKey);
573 if (oldrules != null) {
574 rules.addAll(oldrules);
576 for (Subject s : entry.getValue()) {
577 if (s.getRule() == null)
581 srules = reverseRules(s.getRule());
584 .from(TenantUtils.RULE_COMPARATOR)
585 .immutableSortedCopy(s.getRule());
587 RuleGroup rg = new RuleGroup(srules, s.getOrder(),
588 contractTenant, contract,
592 Collections.sort(rules);
593 ruleMap.put(rowKey, columnKey,
594 Collections.unmodifiableList(rules));
596 return new Policy(ruleMap);
599 private List<Rule> reverseRules(List<Rule> rules) {
600 ArrayList<Rule> nrules = new ArrayList<>();
601 for (Rule input : rules) {
602 if (input.getClassifierRef() == null ||
603 input.getClassifierRef().size() == 0) {
608 List<ClassifierRef> classifiers = new ArrayList<>();
609 for (ClassifierRef clr : input.getClassifierRef()) {
610 Direction nd = Direction.Bidirectional;
611 if (clr.getDirection() != null) {
612 switch (clr.getDirection()) {
621 nd = Direction.Bidirectional;
624 classifiers.add(new ClassifierRefBuilder(clr)
625 .setDirection(nd).build());
627 nrules.add(new RuleBuilder(input)
628 .setClassifierRef(Collections.unmodifiableList(classifiers))
631 Collections.sort(nrules, TenantUtils.RULE_COMPARATOR);
632 return Collections.unmodifiableList(nrules);
636 * Get the "natural" direction for the policy for the given pair of endpoint
640 * The first endpoint group
642 * The second endpoint group
643 * @return true if the order should be reversed in the index
645 protected static boolean shouldReverse(EgKey one, EgKey two) {
646 if (one.compareTo(two) < 0) {
652 private void addConditionSet(EgKey eg, ConditionSet cs,
653 Map<EgKey, Set<ConditionSet>> egConditions) {
654 if (egConditions == null)
656 Set<ConditionSet> cset = egConditions.get(eg);
658 egConditions.put(eg, cset = new HashSet<>());
664 * Choose the set of subjects that in scope for each possible set of
665 * endpoint conditions
667 protected Table<EgKey, EgKey, Policy>
668 selectSubjects(Table<EgKey, EgKey,
669 List<ContractMatch>> contractMatches,
670 Map<EgKey, Set<ConditionSet>> egConditions) {
671 // TODO: Note that it's possible to further simplify the resulting
673 // in the case of things like repeated rules, condition sets that
674 // cover other condition sets, etc. This would be a good thing to do
676 Table<EgKey, EgKey, Policy> policy = HashBasedTable.create();
678 for (List<ContractMatch> matches : contractMatches.values()) {
679 for (ContractMatch match : matches) {
680 List<Clause> clauses = match.contract.getClause();
684 List<Subject> subjectList = match.contract.getSubject();
685 if (subjectList == null)
688 EgKey ckey = new EgKey(match.consumerTenant.getId(),
689 match.consumer.getId());
690 EgKey pkey = new EgKey(match.providerTenant.getId(),
691 match.provider.getId());
694 boolean reverse = shouldReverse(ckey, pkey);
699 Policy existing = policy.get(one, two);
701 HashMap<SubjectName, Subject> subjects = new HashMap<>();
702 for (Subject s : subjectList) {
703 subjects.put(s.getName(), s);
706 Table<ConditionSet, ConditionSet, List<Subject>> subjectMap =
707 HashBasedTable.create();
709 for (Clause clause : clauses) {
710 if (clause.getSubjectRefs() != null &&
711 clauseMatches(clause, match)) {
712 ConditionSet consCSet = buildConsConditionSet(clause);
713 addConditionSet(ckey, consCSet, egConditions);
714 ConditionSet provCSet = buildProvConditionSet(clause);
715 addConditionSet(pkey, provCSet, egConditions);
716 List<Subject> clauseSubjects =
717 subjectMap.get(consCSet, provCSet);
718 if (clauseSubjects == null) {
719 clauseSubjects = new ArrayList<>();
720 subjectMap.put(consCSet, provCSet, clauseSubjects);
722 for (SubjectName sn : clause.getSubjectRefs()) {
723 Subject s = subjects.get(sn);
725 clauseSubjects.add(s);
731 resolvePolicy(match.contractTenant,
742 private List<ConsumerContractMatch> matchConsumerContracts(Tenant tenant,
743 EndpointGroup consumer) {
744 List<ConsumerContractMatch> matches = new ArrayList<>();
745 if (consumer.getConsumerNamedSelector() != null) {
746 for (ConsumerNamedSelector cns : consumer.getConsumerNamedSelector()) {
747 if (cns.getContract() == null)
749 for (ContractId contractId : cns.getContract()) {
751 TenantUtils.findContract(tenant, contractId);
752 if (contract == null)
754 matches.add(new ConsumerContractMatch(tenant, contract,
760 if (consumer.getConsumerTargetSelector() != null) {
761 for (ConsumerTargetSelector cts : consumer.getConsumerTargetSelector()) {
762 if (tenant.getContract() == null)
764 for (Contract contract : tenant.getContract()) {
765 if (contract.getTarget() == null)
767 for (Target t : contract.getTarget()) {
768 boolean match = true;
769 if (cts.getQualityMatcher() != null) {
770 for (QualityMatcher m : cts.getQualityMatcher()) {
771 if (!MatcherUtils.applyQualityMatcher(m, t)) {
778 matches.add(new ConsumerContractMatch(tenant,
788 // TODO match selectors also against contract references
789 // for (ConsumerTargetSelector cts :
790 // consumer.getConsumerTargetSelector()) {
791 // if (tenant.getContractRef() == null) continue;
792 // for (ContractRef c : tenant.getContractRef()) {
799 private void amendContractMatches(List<ContractMatch> matches,
800 List<ConsumerContractMatch> cMatches,
801 Tenant tenant, EndpointGroup provider,
802 ProviderSelectionRelator relator) {
803 if (cMatches == null)
805 for (ConsumerContractMatch cMatch : cMatches) {
806 matches.add(new ContractMatch(cMatch, tenant, provider, relator));
810 private List<ContractMatch>
811 matchProviderContracts(Tenant tenant, EndpointGroup provider,
814 List<ConsumerContractMatch>> consumerMatches) {
815 List<ContractMatch> matches = new ArrayList<>();
816 if (provider.getProviderNamedSelector() != null) {
817 for (ProviderNamedSelector pns : provider.getProviderNamedSelector()) {
818 if (pns.getContract() == null)
820 for (ContractId contractId : pns.getContract()) {
821 Contract c = TenantUtils.findContract(tenant, contractId);
824 List<ConsumerContractMatch> cMatches =
825 consumerMatches.get(tenant.getId(), c.getId());
826 amendContractMatches(matches, cMatches, tenant, provider, pns);
830 if (provider.getProviderTargetSelector() != null) {
831 for (ProviderTargetSelector pts : provider.getProviderTargetSelector()) {
832 if (tenant.getContract() == null)
834 for (Contract c : tenant.getContract()) {
835 if (c.getTarget() == null)
837 for (Target t : c.getTarget()) {
838 boolean match = true;
839 if (pts.getQualityMatcher() != null) {
840 for (QualityMatcher m : pts.getQualityMatcher()) {
841 if (!MatcherUtils.applyQualityMatcher(m, t)) {
848 List<ConsumerContractMatch> cMatches =
849 consumerMatches.get(tenant.getId(),
851 amendContractMatches(matches, cMatches, tenant,
862 protected static class TenantContext {
863 ListenerRegistration<DataChangeListener> registration;
865 AtomicReference<IndexedTenant> tenant = new AtomicReference<>();
867 public TenantContext(ListenerRegistration<DataChangeListener> registration) {
869 this.registration = registration;
874 * Represents a selected contract made by endpoint groups matching it using
875 * selection relators. This is the result of the contract selection phase.
881 protected static class ContractMatch extends ConsumerContractMatch {
883 * The tenant ID of the provider endpoint group
885 final Tenant providerTenant;
888 * The provider endpoint group
890 final EndpointGroup provider;
893 * The provider selection relator that was used to match the contract
895 final ProviderSelectionRelator providerRelator;
897 public ContractMatch(ConsumerContractMatch consumerMatch,
898 Tenant providerTenant, EndpointGroup provider,
899 ProviderSelectionRelator providerRelator) {
900 super(consumerMatch.contractTenant,
901 consumerMatch.contract,
902 consumerMatch.consumerTenant,
903 consumerMatch.consumer,
904 consumerMatch.consumerRelator);
905 this.providerTenant = providerTenant;
906 this.provider = provider;
907 this.providerRelator = providerRelator;
912 private static class ConsumerContractMatch {
914 * The tenant of the matching contract
916 final Tenant contractTenant;
919 * The matching contract
921 final Contract contract;
924 * The tenant for the endpoint group
926 final Tenant consumerTenant;
929 * The consumer endpoint group
931 final EndpointGroup consumer;
934 * The consumer selection relator that was used to match the contract
936 final ConsumerSelectionRelator consumerRelator;
938 public ConsumerContractMatch(Tenant contractTenant,
940 Tenant consumerTenant,
941 EndpointGroup consumer,
942 ConsumerSelectionRelator consumerRelator) {
944 this.contractTenant = contractTenant;
945 this.contract = contract;
946 this.consumerTenant = consumerTenant;
947 this.consumer = consumer;
948 this.consumerRelator = consumerRelator;
953 private class PolicyChangeListener implements DataChangeListener {
954 final TenantId tenantId;
956 public PolicyChangeListener(TenantId tenantId) {
958 this.tenantId = tenantId;
962 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> arg0) {
963 updateTenant(tenantId);