Adding multiple EPG capability to EPs and IntraEPG policy
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / resolver / InheritanceUtils.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.resolver;
10
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;
17
18 import org.opendaylight.groupbasedpolicy.resolver.MatcherUtils.GetLabelName;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityMatcherName;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityName;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionMatcherName;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.LabelName;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.QualityMatcherName;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.QualityName;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RequirementMatcherName;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RequirementName;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TargetName;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Label;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.capabilities.Capability;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcherBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.qualities.Quality;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.requirements.Requirement;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.QualityMatcher;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.QualityMatcherBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.quality.matcher.MatcherQuality;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ContractBuilder;
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.EndpointGroup.IntraGroupPolicy;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.ClauseBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.SubjectBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Target;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.TargetBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.ConsumerMatchers;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.ConsumerMatchersBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.ProviderMatchers;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.ProviderMatchersBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.GroupIdentificationConstraints;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.GroupRequirementConstraintCase;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.GroupRequirementConstraintCaseBuilder;
65 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;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.group.requirement.constraint._case.RequirementMatcherBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.group.requirement.constraint._case.requirement.matcher.MatcherRequirement;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.GroupCapabilityConstraintCase;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.GroupCapabilityConstraintCaseBuilder;
70 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;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.group.capability.constraint._case.CapabilityMatcherBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.group.capability.constraint._case.capability.matcher.MatcherCapability;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.RuleBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelectorBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelector;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelectorBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelectorBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderTargetSelector;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderTargetSelectorBuilder;
83
84 import com.google.common.collect.ImmutableList;
85
86 /**
87  * Utilities useful for resolving the inheritance rules for the various objects
88  * in the system
89  *
90  * @author readams
91  *
92  */
93 public class InheritanceUtils {
94     /**
95      * Fully resolve the specified {@link Tenant}, returning a tenant with all
96      * items fully normalized. This means that no items will have parent/child
97      * relationships and can be interpreted simply without regard to inheritance
98      * rules
99      *
100      * @param unresolvedTenant
101      *            the {@link Tenant} unresolved tenant to resolve
102      * @return the fully-resolved {@link Tenant}
103      */
104     public static Tenant resolveTenant(Tenant unresolvedTenant) {
105         HashMap<EndpointGroupId, EndpointGroup> resolvedEgs = new HashMap<>();
106         HashMap<ContractId, Contract> resolvedContracts = new HashMap<>();
107
108         if (unresolvedTenant.getEndpointGroup() != null) {
109             for (EndpointGroup eg : unresolvedTenant.getEndpointGroup()) {
110                 resolveEndpointGroup(unresolvedTenant, eg, resolvedEgs);
111             }
112         }
113         if (unresolvedTenant.getContract() != null) {
114             for (Contract c : unresolvedTenant.getContract()) {
115                 resolveContract(unresolvedTenant, c, resolvedContracts);
116             }
117         }
118
119         // XXX TODO - inherit from common tenant
120
121         return new TenantBuilder()
122                 .setId(unresolvedTenant.getId())
123                 .setName(unresolvedTenant.getName())
124                 .setDescription(unresolvedTenant.getDescription())
125                 .setEndpointGroup(ImmutableList.copyOf(resolvedEgs.values()))
126                 .setContract(ImmutableList.copyOf(resolvedContracts.values()))
127                 .setContractRef(unresolvedTenant.getContractRef())
128                 .setSubjectFeatureInstances(unresolvedTenant.getSubjectFeatureInstances())
129                 .setL3Context(unresolvedTenant.getL3Context())
130                 .setL2BridgeDomain(unresolvedTenant.getL2BridgeDomain())
131                 .setL2FloodDomain(unresolvedTenant.getL2FloodDomain())
132                 .setSubnet(unresolvedTenant.getSubnet())
133                 .build();
134     }
135
136     // ****************
137     // Helper functions
138     // ****************
139
140     private static void resolveEndpointGroup(Tenant unresolvedTenant,
141             EndpointGroup unresolvedEg,
142             HashMap<EndpointGroupId,
143             EndpointGroup> resolvedEgs) {
144         // put the unresolved object into the data structure to avoid loops
145         resolvedEgs.put(unresolvedEg.getId(), unresolvedEg);
146
147         // resolve parent if it hasn't been resolved already
148         EndpointGroup parent = null;
149         if (unresolvedEg.getParent() != null) {
150             if (!resolvedEgs.containsKey(unresolvedEg.getParent())) {
151                 parent = TenantUtils.findEndpointGroup(unresolvedTenant,
152                         unresolvedEg.getParent());
153                 if (parent != null)
154                     resolveEndpointGroup(unresolvedTenant, parent, resolvedEgs);
155             }
156             parent = resolvedEgs.get(unresolvedEg.getParent());
157         }
158
159         HashMap<SelectorName, ConsumerTargetSelector> resolvedCts =
160                 new HashMap<>();
161         HashMap<SelectorName, ConsumerNamedSelector> resolvedCns =
162                 new HashMap<>();
163         HashMap<SelectorName, ProviderTargetSelector> resolvedPts =
164                 new HashMap<>();
165         HashMap<SelectorName, ProviderNamedSelector> resolvedPns =
166                 new HashMap<>();
167         NetworkDomainId domain = unresolvedEg.getNetworkDomain();
168         IntraGroupPolicy igp = unresolvedEg.getIntraGroupPolicy();
169
170         if (unresolvedEg.getConsumerTargetSelector() != null) {
171             for (ConsumerTargetSelector s : unresolvedEg.getConsumerTargetSelector()) {
172                 resolveCts(unresolvedTenant, unresolvedEg, s, resolvedCts);
173             }
174         }
175         if (unresolvedEg.getConsumerNamedSelector() != null) {
176             for (ConsumerNamedSelector s : unresolvedEg.getConsumerNamedSelector()) {
177                 resolveCns(unresolvedTenant, unresolvedEg, s, resolvedCns);
178             }
179         }
180         if (unresolvedEg.getProviderTargetSelector() != null) {
181             for (ProviderTargetSelector s : unresolvedEg.getProviderTargetSelector()) {
182                 resolvePts(unresolvedTenant, unresolvedEg, s, resolvedPts);
183             }
184         }
185         if (unresolvedEg.getProviderNamedSelector() != null) {
186             for (ProviderNamedSelector s : unresolvedEg.getProviderNamedSelector()) {
187                 resolvePns(unresolvedTenant, unresolvedEg, s, resolvedPns);
188             }
189         }
190
191         if (parent != null) {
192             if (parent.getConsumerTargetSelector() != null) {
193                 for (ConsumerTargetSelector cts : parent.getConsumerTargetSelector()) {
194                     if (!resolvedCts.containsKey(cts.getName()))
195                         resolvedCts.put(cts.getName(), cts);
196                 }
197             }
198             if (parent.getConsumerNamedSelector() != null) {
199                 for (ConsumerNamedSelector cns : parent.getConsumerNamedSelector()) {
200                     if (!resolvedCns.containsKey(cns.getName()))
201                         resolvedCns.put(cns.getName(), cns);
202                 }
203             }
204             if (parent.getProviderTargetSelector() != null) {
205                 for (ProviderTargetSelector pts : parent.getProviderTargetSelector()) {
206                     if (!resolvedPts.containsKey(pts.getName()))
207                         resolvedPts.put(pts.getName(), pts);
208                 }
209             }
210             if (parent.getProviderNamedSelector() != null) {
211                 for (ProviderNamedSelector pns : parent.getProviderNamedSelector()) {
212                     if (!resolvedPns.containsKey(pns.getName()))
213                         resolvedPns.put(pns.getName(), pns);
214                 }
215             }
216             if (domain == null) {
217                 domain = parent.getNetworkDomain();
218             }
219             if (igp == null) {
220                 igp = parent.getIntraGroupPolicy();
221             }
222         }
223
224         // Note: do not set parent, or any of the values that only exist
225         // for inheritance
226         EndpointGroup resolvedEg = new EndpointGroupBuilder()
227                 .setId(unresolvedEg.getId())
228                 .setDescription(unresolvedEg.getDescription())
229                 .setName(unresolvedEg.getName())
230                 .setConsumerTargetSelector(ImmutableList.copyOf(resolvedCts.values()))
231                 .setConsumerNamedSelector(ImmutableList.copyOf(resolvedCns.values()))
232                 .setProviderTargetSelector(ImmutableList.copyOf(resolvedPts.values()))
233                 .setProviderNamedSelector(ImmutableList.copyOf(resolvedPns.values()))
234                 .setNetworkDomain(domain)
235                 .setIntraGroupPolicy(igp)
236                 .build();
237         resolvedEgs.put(resolvedEg.getId(), resolvedEg);
238     }
239
240     private static void resolveCts(Tenant unresolvedTenant,
241             EndpointGroup unresolvedEg,
242             ConsumerTargetSelector unresolvedTs,
243             HashMap<SelectorName,
244             ConsumerTargetSelector> resolvedCts) {
245         HashMap<QualityMatcherName, QualityMatcher> matchers = new HashMap<>();
246         HashMap<RequirementName, Requirement> requirements = new HashMap<>();
247         HashSet<EndpointGroupId> visited = new HashSet<>();
248
249         resolveCtsAttr(unresolvedTenant, unresolvedEg, unresolvedTs.getName(),
250                 matchers, requirements, visited);
251
252         ConsumerTargetSelector resolved = new ConsumerTargetSelectorBuilder()
253                 .setName(unresolvedTs.getName())
254                 .setQualityMatcher(ImmutableList.copyOf(matchers.values()))
255                 .setRequirement(ImmutableList.copyOf(requirements.values()))
256                 .build();
257         resolvedCts.put(resolved.getName(), resolved);
258     }
259
260     private static void resolveCtsAttr(Tenant unresolvedTenant,
261             EndpointGroup unresolvedEg,
262             SelectorName name,
263             HashMap<QualityMatcherName,
264             QualityMatcher> matchers,
265             HashMap<RequirementName,
266             Requirement> requirements,
267             HashSet<EndpointGroupId> visited) {
268         if (unresolvedEg == null)
269             return;
270         if (visited.contains(unresolvedEg.getId()))
271             return;
272         visited.add(unresolvedEg.getId());
273         if (unresolvedEg.getParent() != null) {
274             resolveCtsAttr(unresolvedTenant,
275                     TenantUtils.findEndpointGroup(unresolvedTenant,
276                             unresolvedEg.getParent()),
277                     name,
278                     matchers,
279                     requirements,
280                     visited);
281         }
282         resolveLabels(unresolvedEg.getRequirement(), requirements,
283                 MatcherUtils.getRequirementName);
284         ConsumerTargetSelector unresolvedSelector =
285                 TenantUtils.findCts(unresolvedEg, name);
286         if (unresolvedSelector == null)
287             return;
288         resolveLabels(unresolvedSelector.getRequirement(), requirements,
289                 MatcherUtils.getRequirementName);
290         resolveQualityMatcher(unresolvedSelector.getQualityMatcher(), matchers);
291     }
292
293     private static void resolveCns(Tenant unresolvedTenant,
294             EndpointGroup unresolvedEg,
295             ConsumerNamedSelector unresolvedTs,
296             HashMap<SelectorName,
297             ConsumerNamedSelector> resolvedCns) {
298         HashMap<RequirementName, Requirement> requirements = new HashMap<>();
299         HashSet<ContractId> contracts = new HashSet<>();
300         HashSet<EndpointGroupId> visited = new HashSet<>();
301
302         resolveCnsAttr(unresolvedTenant, unresolvedEg, unresolvedTs.getName(),
303                 requirements, contracts, visited);
304
305         ConsumerNamedSelector resolved = new ConsumerNamedSelectorBuilder()
306                 .setName(unresolvedTs.getName())
307                 .setRequirement(ImmutableList.copyOf(requirements.values()))
308                 .setContract(ImmutableList.copyOf(contracts))
309                 .build();
310         resolvedCns.put(resolved.getName(), resolved);
311     }
312
313     private static void resolveCnsAttr(Tenant unresolvedTenant,
314             EndpointGroup unresolvedEg,
315             SelectorName name,
316             HashMap<RequirementName,
317             Requirement> requirements,
318             HashSet<ContractId> contracts,
319             HashSet<EndpointGroupId> visited) {
320         if (unresolvedEg == null)
321             return;
322         if (visited.contains(unresolvedEg.getId()))
323             return;
324         visited.add(unresolvedEg.getId());
325         if (unresolvedEg.getParent() != null) {
326             resolveCnsAttr(unresolvedTenant,
327                     TenantUtils.findEndpointGroup(unresolvedTenant,
328                             unresolvedEg.getParent()),
329                     name, requirements, contracts, visited);
330         }
331         resolveLabels(unresolvedEg.getRequirement(), requirements,
332                 MatcherUtils.getRequirementName);
333         ConsumerNamedSelector unresolvedSelector =
334                 TenantUtils.findCns(unresolvedEg, name);
335         if (unresolvedSelector == null)
336             return;
337         resolveLabels(unresolvedSelector.getRequirement(), requirements,
338                 MatcherUtils.getRequirementName);
339         if (unresolvedSelector.getContract() != null) {
340             contracts.addAll(unresolvedSelector.getContract());
341         }
342     }
343
344     private static void resolvePts(Tenant unresolvedTenant,
345             EndpointGroup unresolvedEg,
346             ProviderTargetSelector unresolvedTs,
347             HashMap<SelectorName,
348             ProviderTargetSelector> resolvedCts) {
349         HashMap<QualityMatcherName, QualityMatcher> matchers = new HashMap<>();
350         HashMap<CapabilityName, Capability> capabilities = new HashMap<>();
351         HashSet<EndpointGroupId> visited = new HashSet<>();
352
353         resolvePtsAttr(unresolvedTenant, unresolvedEg, unresolvedTs.getName(),
354                 matchers, capabilities, visited);
355
356         ProviderTargetSelector resolved = new ProviderTargetSelectorBuilder()
357                 .setName(unresolvedTs.getName())
358                 .setQualityMatcher(ImmutableList.copyOf(matchers.values()))
359                 .setCapability(ImmutableList.copyOf(capabilities.values()))
360                 .build();
361         resolvedCts.put(resolved.getName(), resolved);
362     }
363
364     private static void resolvePtsAttr(Tenant unresolvedTenant,
365             EndpointGroup unresolvedEg,
366             SelectorName name,
367             HashMap<QualityMatcherName,
368             QualityMatcher> matchers,
369             HashMap<CapabilityName,
370             Capability> capabilities,
371             HashSet<EndpointGroupId> visited) {
372         if (unresolvedEg == null)
373             return;
374         if (visited.contains(unresolvedEg.getId()))
375             return;
376         visited.add(unresolvedEg.getId());
377         if (unresolvedEg.getParent() != null) {
378             resolvePtsAttr(unresolvedTenant,
379                     TenantUtils.findEndpointGroup(unresolvedTenant,
380                             unresolvedEg.getParent()),
381                     name,
382                     matchers,
383                     capabilities, visited);
384         }
385         resolveLabels(unresolvedEg.getCapability(), capabilities,
386                 MatcherUtils.getCapabilityName);
387         ProviderTargetSelector unresolvedSelector =
388                 TenantUtils.findPts(unresolvedEg, name);
389         if (unresolvedSelector == null)
390             return;
391         resolveLabels(unresolvedSelector.getCapability(), capabilities,
392                 MatcherUtils.getCapabilityName);
393         resolveQualityMatcher(unresolvedSelector.getQualityMatcher(), matchers);
394     }
395
396     private static void resolvePns(Tenant unresolvedTenant,
397             EndpointGroup unresolvedEg,
398             ProviderNamedSelector unresolvedTs,
399             HashMap<SelectorName,
400             ProviderNamedSelector> resolvedCns) {
401         HashMap<CapabilityName, Capability> capabilities = new HashMap<>();
402         HashSet<ContractId> contracts = new HashSet<>();
403         HashSet<EndpointGroupId> visited = new HashSet<>();
404
405         resolvePnsAttr(unresolvedTenant, unresolvedEg, unresolvedTs.getName(),
406                 capabilities, contracts, visited);
407
408         ProviderNamedSelector resolved = new ProviderNamedSelectorBuilder()
409                 .setName(unresolvedTs.getName())
410                 .setCapability(ImmutableList.copyOf(capabilities.values()))
411                 .setContract(ImmutableList.copyOf(contracts))
412                 .build();
413         resolvedCns.put(resolved.getName(), resolved);
414     }
415
416     private static void resolvePnsAttr(Tenant unresolvedTenant,
417             EndpointGroup unresolvedEg,
418             SelectorName name,
419             HashMap<CapabilityName,
420             Capability> capabilities,
421             HashSet<ContractId> contracts,
422             HashSet<EndpointGroupId> visited) {
423         if (unresolvedEg == null)
424             return;
425         if (visited.contains(unresolvedEg.getId()))
426             return;
427         visited.add(unresolvedEg.getId());
428         if (unresolvedEg.getParent() != null) {
429             resolvePnsAttr(unresolvedTenant,
430                     TenantUtils.findEndpointGroup(unresolvedTenant,
431                             unresolvedEg.getParent()),
432                     name, capabilities, contracts, visited);
433         }
434         resolveLabels(unresolvedEg.getCapability(), capabilities,
435                 MatcherUtils.getCapabilityName);
436         ProviderNamedSelector unresolvedSelector =
437                 TenantUtils.findPns(unresolvedEg, name);
438         if (unresolvedSelector == null)
439             return;
440         resolveLabels(unresolvedSelector.getCapability(), capabilities,
441                 MatcherUtils.getCapabilityName);
442         if (unresolvedSelector.getContract() != null) {
443             contracts.addAll(unresolvedSelector.getContract());
444         }
445     }
446
447     private static void resolveContract(Tenant unresolvedTenant,
448             Contract unresolvedContract,
449             HashMap<ContractId,
450             Contract> resolvedContracts) {
451         // put the unresolved object into the data structure to avoid loops
452         resolvedContracts.put(unresolvedContract.getId(), unresolvedContract);
453
454         // resolve parent if it hasn't been resolved already
455         Contract parent = null;
456         if (unresolvedContract.getParent() != null) {
457             if (!resolvedContracts.containsKey(unresolvedContract.getParent())) {
458                 parent = TenantUtils.findContract(unresolvedTenant,
459                         unresolvedContract.getParent());
460                 if (parent != null)
461                     resolveContract(unresolvedTenant,
462                             parent,
463                             resolvedContracts);
464             }
465             parent = resolvedContracts.get(unresolvedContract.getParent());
466         }
467
468         HashMap<TargetName, Target> resolvedTargets = new HashMap<>();
469         HashMap<ClauseName, Clause> resolvedClauses = new HashMap<>();
470         HashMap<SubjectName, Subject> resolvedSubjects = new HashMap<>();
471
472         if (unresolvedContract.getTarget() != null) {
473             for (Target t : unresolvedContract.getTarget()) {
474                 resolveTarget(unresolvedTenant, unresolvedContract,
475                         t, resolvedTargets);
476             }
477         }
478         if (unresolvedContract.getClause() != null) {
479             for (Clause c : unresolvedContract.getClause()) {
480                 resolveClause(unresolvedTenant, unresolvedContract,
481                         c, resolvedClauses);
482             }
483         }
484         if (unresolvedContract.getSubject() != null) {
485             for (Subject s : unresolvedContract.getSubject()) {
486                 resolveSubject(unresolvedTenant, unresolvedContract,
487                         s, resolvedSubjects);
488             }
489         }
490
491         if (parent != null) {
492             if (parent.getTarget() != null) {
493                 for (Target t : parent.getTarget()) {
494                     if (!resolvedTargets.containsKey(t.getName()))
495                         resolvedTargets.put(t.getName(), t);
496                 }
497             }
498             if (parent.getClause() != null) {
499                 for (Clause c : parent.getClause()) {
500                     if (!resolvedClauses.containsKey(c.getName()))
501                         resolvedClauses.put(c.getName(), c);
502                 }
503             }
504             if (parent.getSubject() != null) {
505                 for (Subject s : parent.getSubject()) {
506                     if (!resolvedSubjects.containsKey(s.getName()))
507                         resolvedSubjects.put(s.getName(), s);
508                 }
509             }
510         }
511
512         Contract resolvedContract = new ContractBuilder()
513                 .setId(unresolvedContract.getId())
514                 .setDescription(unresolvedContract.getDescription())
515                 .setTarget(ImmutableList.copyOf(resolvedTargets.values()))
516                 .setClause(ImmutableList.copyOf(resolvedClauses.values()))
517                 .setSubject(ImmutableList.copyOf(resolvedSubjects.values()))
518                 .build();
519         resolvedContracts.put(resolvedContract.getId(), resolvedContract);
520     }
521
522     private static void resolveTarget(Tenant unresolvedTenant,
523             Contract unresolvedContract,
524             Target unresolvedTarget,
525             HashMap<TargetName, Target> resolvedTargets) {
526         HashMap<QualityName, Quality> qualities = new HashMap<>();
527         HashSet<ContractId> visited = new HashSet<>();
528
529         resolveTargetAttrs(unresolvedTenant,
530                 unresolvedContract,
531                 unresolvedTarget.getName(),
532                 qualities, visited);
533
534         Target resolved = new TargetBuilder()
535                 .setName(unresolvedTarget.getName())
536                 .setQuality(ImmutableList.copyOf(qualities.values()))
537                 .build();
538         resolvedTargets.put(resolved.getName(), resolved);
539     }
540
541     private static void resolveTargetAttrs(Tenant unresolvedTenant,
542             Contract unresolvedContract,
543             TargetName targetName,
544             HashMap<QualityName, Quality> qualities,
545             HashSet<ContractId> visited) {
546         if (unresolvedContract == null)
547             return;
548         if (visited.contains(unresolvedContract.getId()))
549             return;
550         visited.add(unresolvedContract.getId());
551         if (unresolvedContract.getParent() != null) {
552             resolveTargetAttrs(unresolvedTenant,
553                     TenantUtils.findContract(unresolvedTenant,
554                             unresolvedContract.getParent()),
555                     targetName,
556                     qualities, visited);
557         }
558         resolveLabels(unresolvedContract.getQuality(), qualities,
559                 MatcherUtils.getQualityName);
560         Target unresolvedTarget =
561                 TenantUtils.findTarget(unresolvedContract, targetName);
562         resolveLabels(unresolvedTarget.getQuality(), qualities,
563                 MatcherUtils.getQualityName);
564     }
565
566     private static void
567             resolveQualityMatcher(Collection<QualityMatcher> toResolve,
568                     HashMap<QualityMatcherName,
569                     QualityMatcher> matchers) {
570         if (toResolve == null)
571             return;
572         for (QualityMatcher qm : toResolve) {
573             if (matchers.containsKey(qm.getName())) {
574                 QualityMatcher oqm = matchers.get(qm.getName());
575                 QualityMatcherBuilder qmb = new QualityMatcherBuilder();
576                 qmb.setName(qm.getName());
577                 qmb.setMatchType(oqm.getMatchType());
578                 if (qm.getMatchType() != null)
579                     qmb.setMatchType(qm.getMatchType());
580
581                 HashMap<QualityName, MatcherQuality> qualities =
582                         new HashMap<>();
583                 resolveLabels(oqm.getMatcherQuality(), qualities,
584                         MatcherUtils.getMatcherQualityName);
585                 resolveLabels(qm.getMatcherQuality(), qualities,
586                         MatcherUtils.getMatcherQualityName);
587
588                 qmb.setMatcherQuality(ImmutableList.copyOf(qualities.values()));
589                 matchers.put(qm.getName(), qmb.build());
590             } else {
591                 matchers.put(qm.getName(), qm);
592             }
593         }
594     }
595
596     private static void
597             resolveCapabilityMatcher(Collection<CapabilityMatcher> toResolve,
598                     HashMap<CapabilityMatcherName,
599                     CapabilityMatcher> matchers) {
600         if (toResolve == null)
601             return;
602         for (CapabilityMatcher m : toResolve) {
603             if (matchers.containsKey(m.getName())) {
604                 CapabilityMatcher om = matchers.get(m.getName());
605                 CapabilityMatcherBuilder mb = new CapabilityMatcherBuilder();
606                 mb.setName(m.getName());
607                 mb.setMatchType(om.getMatchType());
608                 if (m.getMatchType() != null)
609                     mb.setMatchType(m.getMatchType());
610
611                 HashMap<CapabilityName, MatcherCapability> labels =
612                         new HashMap<>();
613                 resolveLabels(om.getMatcherCapability(), labels,
614                         MatcherUtils.getMatcherCapabilityName);
615                 resolveLabels(m.getMatcherCapability(), labels,
616                         MatcherUtils.getMatcherCapabilityName);
617
618                 mb.setMatcherCapability(ImmutableList.copyOf(labels.values()));
619                 matchers.put(m.getName(), mb.build());
620             } else {
621                 matchers.put(m.getName(), m);
622             }
623         }
624     }
625
626     private static void
627             resolveRequirementMatcher(Collection<RequirementMatcher> toResolve,
628                     HashMap<RequirementMatcherName,
629                     RequirementMatcher> matchers) {
630         if (toResolve == null)
631             return;
632         for (RequirementMatcher m : toResolve) {
633             if (matchers.containsKey(m.getName())) {
634                 RequirementMatcher om = matchers.get(m.getName());
635                 RequirementMatcherBuilder mb = new RequirementMatcherBuilder();
636                 mb.setName(m.getName());
637                 mb.setMatchType(om.getMatchType());
638                 if (m.getMatchType() != null)
639                     mb.setMatchType(m.getMatchType());
640
641                 HashMap<RequirementName, MatcherRequirement> labels =
642                         new HashMap<>();
643                 resolveLabels(om.getMatcherRequirement(), labels,
644                         MatcherUtils.getMatcherRequirementName);
645                 resolveLabels(m.getMatcherRequirement(), labels,
646                         MatcherUtils.getMatcherRequirementName);
647
648                 mb.setMatcherRequirement(ImmutableList.copyOf(labels.values()));
649                 matchers.put(m.getName(), mb.build());
650             } else {
651                 matchers.put(m.getName(), m);
652             }
653         }
654     }
655
656     private static void
657             resolveConditionMatcher(Collection<ConditionMatcher> toResolve,
658                     HashMap<ConditionMatcherName,
659                     ConditionMatcher> matchers) {
660         if (toResolve == null)
661             return;
662         for (ConditionMatcher m : toResolve) {
663             if (matchers.containsKey(m.getName())) {
664                 ConditionMatcher om = matchers.get(m.getName());
665                 ConditionMatcherBuilder mb = new ConditionMatcherBuilder();
666                 mb.setName(m.getName());
667                 mb.setMatchType(om.getMatchType());
668                 if (m.getMatchType() != null)
669                     mb.setMatchType(m.getMatchType());
670
671                 HashMap<ConditionName, Condition> labels =
672                         new HashMap<>();
673                 resolveLabels(om.getCondition(), labels,
674                         MatcherUtils.getConditionName);
675                 resolveLabels(m.getCondition(), labels,
676                         MatcherUtils.getConditionName);
677
678                 mb.setCondition(ImmutableList.copyOf(labels.values()));
679                 matchers.put(m.getName(), mb.build());
680             } else {
681                 matchers.put(m.getName(), m);
682             }
683         }
684     }
685
686     private static void resolveClause(Tenant unresolvedTenant,
687             Contract unresolvedContract,
688             Clause unresolvedClause,
689             HashMap<ClauseName, Clause> resolvedClauses) {
690         HashMap<CapabilityMatcherName, CapabilityMatcher> capMatchers = new HashMap<>();
691         HashMap<ConditionMatcherName, ConditionMatcher> provCondMatchers = new HashMap<>();
692         HashMap<RequirementMatcherName, RequirementMatcher> reqMatchers = new HashMap<>();
693         HashMap<ConditionMatcherName, ConditionMatcher> consCondMatchers = new HashMap<>();
694         HashSet<SubjectName> subjectRefs = new HashSet<>();
695         HashSet<ContractId> visited = new HashSet<>();
696
697         // TODO: Add GIC choices GroupNameConstraint and GroupAny
698         // TODO: Add EIC (ie L3Prefix) constraint.
699
700         resolveClauseAttr(unresolvedTenant, unresolvedContract,
701                 unresolvedClause.getName(), subjectRefs,
702                 capMatchers, provCondMatchers,
703                 reqMatchers, consCondMatchers, visited);
704
705         Clause resolved = new ClauseBuilder()
706                 .setName(unresolvedClause.getName())
707                 .setSubjectRefs(ImmutableList.copyOf(subjectRefs))
708                 .setProviderMatchers(new ProviderMatchersBuilder()
709                         .setGroupIdentificationConstraints(new GroupCapabilityConstraintCaseBuilder()
710                                 .setCapabilityMatcher(ImmutableList.copyOf(capMatchers.values())).build())
711                         .setConditionMatcher(ImmutableList.copyOf(provCondMatchers.values()))
712                         .build())
713                 .setConsumerMatchers(new ConsumerMatchersBuilder()
714                         .setGroupIdentificationConstraints(new GroupRequirementConstraintCaseBuilder()
715                                 .setRequirementMatcher(ImmutableList.copyOf(reqMatchers.values())).build())
716                         .setConditionMatcher(ImmutableList.copyOf(consCondMatchers.values()))
717                         .build())
718                 .build();
719         resolvedClauses.put(resolved.getName(), resolved);
720     }
721
722     private static void resolveClauseAttr(Tenant unresolvedTenant,
723             Contract unresolvedContract,
724             ClauseName clauseName,
725             HashSet<SubjectName> subjectRefs,
726             HashMap<CapabilityMatcherName,
727             CapabilityMatcher> capMatchers,
728             HashMap<ConditionMatcherName,
729             ConditionMatcher> provCondMatchers,
730             HashMap<RequirementMatcherName,
731             RequirementMatcher> reqMatchers,
732             HashMap<ConditionMatcherName,
733             ConditionMatcher> consCondMatchers,
734             HashSet<ContractId> visited) {
735         if (unresolvedContract == null)
736             return;
737         if (visited.contains(unresolvedContract.getId()))
738             return;
739         visited.add(unresolvedContract.getId());
740         if (unresolvedContract.getParent() != null) {
741             resolveClauseAttr(unresolvedTenant,
742                     TenantUtils.findContract(unresolvedTenant,
743                             unresolvedContract.getParent()),
744                     clauseName,
745                     subjectRefs,
746                     capMatchers,
747                     provCondMatchers,
748                     reqMatchers,
749                     consCondMatchers, visited);
750         }
751
752         Clause unresolvedClause =
753                 TenantUtils.findClause(unresolvedContract, clauseName);
754         if (unresolvedClause == null)
755             return;
756
757         if (unresolvedClause.getProviderMatchers() != null) {
758             ProviderMatchers pms = unresolvedClause.getProviderMatchers();
759             org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.GroupIdentificationConstraints groupIdentificationConstraintsProvider = pms
760                     .getGroupIdentificationConstraints();
761             if (groupIdentificationConstraintsProvider instanceof GroupCapabilityConstraintCase) {
762                 resolveCapabilityMatcher(
763                         ((GroupCapabilityConstraintCase) groupIdentificationConstraintsProvider).getCapabilityMatcher(),
764                         capMatchers);
765             }
766             resolveConditionMatcher(pms.getConditionMatcher(), provCondMatchers);
767         }
768
769         if (unresolvedClause.getConsumerMatchers() != null) {
770             ConsumerMatchers cms = unresolvedClause.getConsumerMatchers();
771             GroupIdentificationConstraints groupIdentificiationConstrainsConsumer = cms
772                     .getGroupIdentificationConstraints();
773             if (groupIdentificiationConstrainsConsumer instanceof GroupRequirementConstraintCase) {
774                 resolveRequirementMatcher(
775                         ((GroupRequirementConstraintCase) groupIdentificiationConstrainsConsumer)
776                                 .getRequirementMatcher(),
777                         reqMatchers);
778             }
779             resolveConditionMatcher(cms.getConditionMatcher(), consCondMatchers);
780
781         }
782         if (unresolvedClause.getSubjectRefs() != null)
783             subjectRefs.addAll(unresolvedClause.getSubjectRefs());
784     }
785
786     private static class Mutable<O> {
787         O value;
788     }
789
790     private static void resolveSubject(Tenant unresolvedTenant,
791             Contract unresolvedContract,
792             Subject unresolvedSubject,
793             HashMap<SubjectName, Subject> resolvedSubjects) {
794         Mutable<Integer> order = new Mutable<>();
795         Mutable<List<Rule>> rules = new Mutable<>();
796         rules.value = Collections.emptyList();
797         HashSet<ContractId> visited = new HashSet<>();
798
799         resolveSubjectAttr(unresolvedTenant, unresolvedContract,
800                 unresolvedSubject.getName(), order, rules, visited);
801
802         Subject resolved = new SubjectBuilder()
803                 .setName(unresolvedSubject.getName())
804                 .setOrder(order.value)
805                 .setRule(rules.value)
806                 .build();
807         resolvedSubjects.put(resolved.getName(), resolved);
808     }
809
810     private static Rule makeRule(Rule r, int order) {
811         return new RuleBuilder()
812                 .setName(r.getName())
813                 .setActionRef(r.getActionRef())
814                 .setClassifierRef(r.getClassifierRef())
815                 .setOrder(order)
816                 .build();
817     }
818
819     private static void resolveSubjectAttr(Tenant unresolvedTenant,
820             Contract unresolvedContract,
821             SubjectName subjectName,
822             Mutable<Integer> order,
823             Mutable<List<Rule>> rules,
824             HashSet<ContractId> visited) {
825         if (unresolvedContract == null)
826             return;
827         if (visited.contains(unresolvedContract.getId()))
828             return;
829         visited.add(unresolvedContract.getId());
830         if (unresolvedContract.getParent() != null) {
831             resolveSubjectAttr(unresolvedTenant,
832                     TenantUtils.findContract(unresolvedTenant,
833                             unresolvedContract.getParent()),
834                     subjectName,
835                     order,
836                     rules, visited);
837         }
838
839         Subject unresolvedSubject =
840                 TenantUtils.findSubject(unresolvedContract, subjectName);
841         if (unresolvedSubject == null)
842             return;
843         if (unresolvedSubject.getOrder() != null)
844             order.value = unresolvedSubject.getOrder();
845         if (unresolvedSubject.getRule() != null) {
846             ImmutableList.Builder<Rule> rbuilder =
847                     new ImmutableList.Builder<Rule>();
848             ArrayList<Rule> nrules =
849                     new ArrayList<>(unresolvedSubject.getRule());
850             Collections.sort(nrules, TenantUtils.RULE_COMPARATOR);
851             int index = 0;
852             for (Rule r : nrules) {
853                 rbuilder.add(makeRule(r, index++));
854             }
855             for (Rule r : rules.value) {
856                 rbuilder.add(makeRule(r, index++));
857             }
858             rules.value = rbuilder.build();
859         }
860     }
861
862     /**
863      * Given a partially-resolved set of labels, add the next item in the
864      * inheritance ordering to the set of resolved labels.
865      *
866      * @param toResolve
867      *            the new set to add
868      * @param labels
869      *            the partially-resolved set
870      * @param getName
871      *            a function object to get the appropriate typed label name
872      */
873     private static <L extends Label, LN extends LabelName> void
874             resolveLabels(Collection<L> toResolve, HashMap<LN, L> labels,
875                     GetLabelName<L, LN> getName) {
876         if (toResolve == null)
877             return;
878         for (L l : toResolve) {
879             if (l.getInclusionRule() != null) {
880                 switch (l.getInclusionRule()) {
881                 case Include:
882                     // override
883                     labels.put(getName.getName(l), l);
884                     break;
885                 case Exclude:
886                     // remove
887                     labels.remove(getName.getName(l));
888                     break;
889                 }
890             } else {
891                 // default to Include
892                 labels.put(getName.getName(l), l);
893             }
894         }
895     }
896 }