/*
* Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.groupbasedpolicy.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.concurrent.Immutable;
import org.opendaylight.groupbasedpolicy.dto.EgKey;
import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ConsumerSelectionRelator;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ProviderSelectionRelator;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.QualityMatcher;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Policy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Target;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ConsumerNamedSelector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ConsumerTargetSelector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ProviderNamedSelector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ProviderTargetSelector;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
class ContractResolverUtils {
private ContractResolverUtils() {
throw new UnsupportedOperationException("Cannot create an instance");
}
/**
* Choose the contracts that are in scope for each pair of endpoint groups,
* then perform subject selection for the pair
*/
static Table<EgKey, EgKey, List<ContractMatch>> selectContracts(Set<IndexedTenant> tenants) {
Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches = HashBasedTable.create();
Table<EgKey, EgKey, List<ContractMatch>> contractMatches = HashBasedTable.create();
for (IndexedTenant tenant : tenants) {
selectContracts(consumerMatches, contractMatches, tenant.getTenant());
}
return contractMatches;
}
static void selectContracts(Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches,
Table<EgKey, EgKey, List<ContractMatch>> contractMatches, Tenant tenant) {
// For each endpoint group, match consumer selectors
// against contracts to get a set of matching consumer selectors
Policy policy = tenant.getPolicy();
if (policy == null || policy.getEndpointGroup() == null) {
return;
}
for (EndpointGroup group : policy.getEndpointGroup()) {
List<ConsumerContractMatch> r = matchConsumerContracts(tenant, group);
for (ConsumerContractMatch ccm : r) {
List<ConsumerContractMatch> cms = consumerMatches.get(tenant.getId(), ccm.contract.getId());
if (cms == null) {
cms = new ArrayList<>();
consumerMatches.put(tenant.getId(), ccm.contract.getId(), cms);
}
cms.add(ccm);
}
}
// Match provider selectors, and check each match for a corresponding
// consumer selector match.
for (EndpointGroup group : policy.getEndpointGroup()) {
List<ContractMatch> matches = matchProviderContracts(tenant, group, consumerMatches);
for (ContractMatch cm : matches) {
EgKey consumerKey = new EgKey(cm.consumerTenant.getId(), cm.consumer.getId());
EgKey providerKey = new EgKey(cm.providerTenant.getId(), cm.provider.getId());
List<ContractMatch> egPairMatches = contractMatches.get(consumerKey, providerKey);
if (egPairMatches == null) {
egPairMatches = new ArrayList<>();
contractMatches.put(consumerKey, providerKey, egPairMatches);
}
egPairMatches.add(cm);
}
}
}
private static List<ConsumerContractMatch> matchConsumerContracts(Tenant tenant,
EndpointGroup consumer) {
List<ConsumerContractMatch> matches = new ArrayList<>();
Policy policy = tenant.getPolicy();
if (policy == null || policy.getContract() == null) {
return matches;
}
if (consumer.getConsumerNamedSelector() != null) {
for (ConsumerNamedSelector cns : consumer.getConsumerNamedSelector()) {
if (cns.getContract() == null) {
continue;
}
for (ContractId contractId : cns.getContract()) {
Contract contract =
TenantUtils.findContract(tenant, contractId);
if (contract == null) {
continue;
}
matches.add(new ConsumerContractMatch(tenant, contract,
tenant, consumer,
cns));
}
}
}
if (consumer.getConsumerTargetSelector() != null) {
for (ConsumerTargetSelector cts : consumer.getConsumerTargetSelector()) {
for (Contract contract : policy.getContract()) {
if (contract.getTarget() == null) {
continue;
}
for (Target t : contract.getTarget()) {
boolean match = true;
if (cts.getQualityMatcher() != null) {
for (QualityMatcher m : cts.getQualityMatcher()) {
if (!MatcherUtils.applyQualityMatcher(m, t)) {
match = false;
break;
}
}
}
if (match) {
matches.add(new ConsumerContractMatch(tenant,
contract,
tenant,
consumer,
cts));
}
}
}
}
}
// TODO match selectors also against contract references
// for (ConsumerTargetSelector cts :
// consumer.getConsumerTargetSelector()) {
// if (tenant.getContractRef() == null) continue;
// for (ContractRef c : tenant.getContractRef()) {
//
// }
// }
return matches;
}
private static List<ContractMatch> matchProviderContracts(Tenant tenant, EndpointGroup provider,
Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches) {
List<ContractMatch> matches = new ArrayList<>();
Policy policy = tenant.getPolicy();
if (policy == null || policy.getContract() == null) {
return matches;
}
if (provider.getProviderNamedSelector() != null) {
for (ProviderNamedSelector pns : provider.getProviderNamedSelector()) {
if (pns.getContract() == null) {
continue;
}
for (ContractId contractId : pns.getContract()) {
Contract c = TenantUtils.findContract(tenant, contractId);
if (c == null)
continue;
List<ConsumerContractMatch> cMatches = consumerMatches.get(tenant.getId(), c.getId());
amendContractMatches(matches, cMatches, tenant, provider, pns);
}
}
}
if (provider.getProviderTargetSelector() != null) {
for (ProviderTargetSelector pts : provider.getProviderTargetSelector()) {
for (Contract c : policy.getContract()) {
if (c.getTarget() == null)
continue;
for (Target t : c.getTarget()) {
boolean match = true;
if (pts.getQualityMatcher() != null) {
for (QualityMatcher m : pts.getQualityMatcher()) {
if (!MatcherUtils.applyQualityMatcher(m, t)) {
match = false;
break;
}
}
}
if (match) {
List<ConsumerContractMatch> cMatches = consumerMatches.get(tenant.getId(), c.getId());
amendContractMatches(matches, cMatches, tenant, provider, pts);
}
}
}
}
}
return matches;
}
private static void amendContractMatches(List<ContractMatch> matches,
List<ConsumerContractMatch> cMatches,
Tenant tenant, EndpointGroup provider,
ProviderSelectionRelator relator) {
if (cMatches == null) {
return;
}
for (ConsumerContractMatch cMatch : cMatches) {
matches.add(new ContractMatch(cMatch, tenant, provider, relator));
}
}
/**
* Represents a selected contract made by endpoint groups matching it using
* selection relators. This is the result of the contract selection phase.
*
* @author readams
*/
@Immutable
static class ContractMatch extends ConsumerContractMatch {
/**
* The tenant ID of the provider endpoint group
*/
final Tenant providerTenant;
/**
* The provider endpoint group
*/
final EndpointGroup provider;
/**
* The provider selection relator that was used to match the contract
*/
final ProviderSelectionRelator providerRelator;
public ContractMatch(ConsumerContractMatch consumerMatch, Tenant providerTenant, EndpointGroup provider,
ProviderSelectionRelator providerRelator) {
super(consumerMatch.contractTenant, consumerMatch.contract, consumerMatch.consumerTenant,
consumerMatch.consumer, consumerMatch.consumerRelator);
this.providerTenant = providerTenant;
this.provider = provider;
this.providerRelator = providerRelator;
}
}
@Immutable
static class ConsumerContractMatch {
/**
* The tenant of the matching contract
*/
final Tenant contractTenant;
/**
* The matching contract
*/
final Contract contract;
/**
* The tenant for the endpoint group
*/
final Tenant consumerTenant;
/**
* The consumer endpoint group
*/
final EndpointGroup consumer;
/**
* The consumer selection relator that was used to match the contract
*/
final ConsumerSelectionRelator consumerRelator;
public ConsumerContractMatch(Tenant contractTenant, Contract contract, Tenant consumerTenant,
EndpointGroup consumer, ConsumerSelectionRelator consumerRelator) {
super();
this.contractTenant = contractTenant;
this.contract = contract;
this.consumerTenant = consumerTenant;
this.consumer = consumer;
this.consumerRelator = consumerRelator;
}
}
}