Merge changes I8490a721,I71941875
authorKeith Burns <alagalah@gmail.com>
Tue, 12 May 2015 16:18:14 +0000 (16:18 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 12 May 2015 16:18:14 +0000 (16:18 +0000)
* changes:
  Bug 3166 ui-backend introduced
  Moved util methods from PolicyResolver

17 files changed:
commons/parent/pom.xml
features/pom.xml
features/src/main/resources/features.xml
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ContractResolverUtils.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolverUtils.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/SubjectResolverUtils.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolverTest.java
pom.xml
ui-backend-config/pom.xml [new file with mode: 0644]
ui-backend-config/src/main/resources/initial/15-ui-backend.xml [new file with mode: 0755]
ui-backend/pom.xml [new file with mode: 0644]
ui-backend/src/main/java/org/opendaylight/controller/config/yang/config/ui_backend/impl/UiBackendModule.java [new file with mode: 0644]
ui-backend/src/main/java/org/opendaylight/controller/config/yang/config/ui_backend/impl/UiBackendModuleFactory.java [new file with mode: 0644]
ui-backend/src/main/java/org/opendaylight/groupbasedpolicy/ui/backend/UiBackendServiceImpl.java [new file with mode: 0755]
ui-backend/src/main/yang/ui-backend-impl.yang [new file with mode: 0644]
ui-backend/src/main/yang/ui-backend.yang [new file with mode: 0755]

index 7e441e58cebdd795a683f19cd9351192a693ea23..d859cae995a45b8b7a993fe6001ffa7f4eb34cbc 100644 (file)
@@ -30,6 +30,7 @@
     <generated.yang.docs>${project.build.directory}/site/models</generated.yang.docs>
     <config.version>0.3.0-SNAPSHOT</config.version>
     <mdsal.version>1.2.0-SNAPSHOT</mdsal.version>
+    <restconf.version>1.2.0-SNAPSHOT</restconf.version>
     <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
     <openflowplugin.version>0.1.0-SNAPSHOT</openflowplugin.version>
     <neutron.version>0.5.0-SNAPSHOT</neutron.version>
         <artifactId>neutron-mapper</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.groupbasedpolicy</groupId>
+        <artifactId>ui-backend</artifactId>
+        <version>${project.version}</version>
+      </dependency>
 
       <!-- Yangtools and Controller infrastructure -->
       <dependency>
index e7ee8e178fc9f4306b6bd1b74c4ee9b8effc89a1..b203d0d6b036285a2ad9a17ce4c1c502c021c976 100644 (file)
@@ -25,6 +25,7 @@
     <config.groupbasedpolicy.opflexconfigfile>15-groupbasedpolicy-opflex.xml</config.groupbasedpolicy.opflexconfigfile>
     <config.groupbasedpolicy.openstackendpointconfigfile>15-groupbasedpolicy-openstackendpoint.xml</config.groupbasedpolicy.openstackendpointconfigfile>
     <config.groupbasedpolicy.neutronmapperconfigfile>15-neutron-mapper.xml</config.groupbasedpolicy.neutronmapperconfigfile>
+    <config.groupbasedpolicy.uibackendconfigfile>15-ui-backend.xml</config.groupbasedpolicy.uibackendconfigfile>
   </properties>
 
   <dependencies>
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>neutron-mapper</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>ui-backend</artifactId>
+    </dependency>
 
     <!-- gbp configuration dependencies -->
     <dependency>
       <type>xml</type>
       <classifier>config</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>ui-backend-config</artifactId>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
 
     <!-- testing dependencies -->
     <dependency>
index 4e4180d6836c378e0c731beb5ff1f5adc01ebac6..e16767b8ef2330578917bd520ab09eaeff421872 100644 (file)
@@ -23,6 +23,9 @@
     <!-- Repos needed by the Neutron Mapper -->
     <repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
 
+    <!-- Repos needed by the UI Backend -->
+    <repository>mvn:org.opendaylight.controller/features-restconf/${restconf.version}/xml/features</repository>
+
     <!-- The common GBP components -->
     <feature name='odl-groupbasedpolicy-base' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: Base Copmonents'>
         <feature version="${mdsal.version}">odl-mdsal-broker</feature>
@@ -77,7 +80,6 @@
         <configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.openstackendpointconfigfile}">mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-openstackendpoint-config/${project.version}/xml/config</configfile>
     </feature>
 
-
     <!--
          The Neutron provider
     -->
         <bundle>mvn:org.opendaylight.groupbasedpolicy/neutron-mapper/${project.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.neutronmapperconfigfile}">mvn:org.opendaylight.groupbasedpolicy/neutron-mapper-config/${project.version}/xml/config</configfile>
     </feature>
+
+    <!--
+         The UI Backend
+    -->
+    <feature name='odl-groupbasedpolicy-uibackend' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: UI Backend provides APIs for UI '>
+        <feature version="${mdsal.version}">odl-mdsal-broker</feature>
+        <feature version="${project.version}">odl-groupbasedpolicy-base</feature>
+        <feature version="${restconf.version}">odl-restconf</feature>
+        <bundle>mvn:org.opendaylight.groupbasedpolicy/ui-backend/${project.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.uibackendconfigfile}">mvn:org.opendaylight.groupbasedpolicy/ui-backend-config/${project.version}/xml/config</configfile>
+    </feature>
 </features>
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ContractResolverUtils.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ContractResolverUtils.java
new file mode 100644 (file)
index 0000000..ccbea04
--- /dev/null
@@ -0,0 +1,269 @@
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+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.Contract;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Target;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderTargetSelector;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+
+public 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
+     */
+    protected 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;
+    }
+
+    protected 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
+        if (tenant.getEndpointGroup() == null)
+            return;
+        for (EndpointGroup group : tenant.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 : tenant.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<>();
+        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()) {
+                if (tenant.getContract() == null)
+                    continue;
+                for (Contract contract : tenant.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<>();
+        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()) {
+                if (tenant.getContract() == null)
+                    continue;
+                for (Contract c : tenant.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
+    protected 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
+    protected 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;
+        }
+    }
+
+}
index 8fe0a5ddecced97539a172b34ae7798b5e9ef77a..6afeb3ec847ca307046b179279f302ca83d600f6 100644 (file)
@@ -8,9 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.resolver;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -31,32 +29,8 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
 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.Matcher.MatchType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ProviderSelectionRelator;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
-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.Contract;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Target;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.GroupIdentificationConstraints;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.GroupRequirementConstraintCase;
-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;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.GroupCapabilityConstraintCase;
-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;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderTargetSelector;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -65,9 +39,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Table;
 import com.google.common.collect.Table.Cell;
@@ -345,13 +316,9 @@ public class PolicyResolver implements AutoCloseable {
     protected void updatePolicy() {
         try {
             Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
-            Table<EgKey, EgKey, Policy> policyMap =
-                    resolvePolicy(resolvedTenants.values(),
-                            egConditions);
-            Set<EgKey> updatedGroups =
-                    updatePolicy(policyMap,
-                            egConditions,
-                            policyListenerScopes);
+            Set<IndexedTenant> indexedTenants = getIndexedTenants(resolvedTenants.values());
+            Table<EgKey, EgKey, Policy> policyMap = PolicyResolverUtils.resolvePolicy(indexedTenants, egConditions);
+            Set<EgKey> updatedGroups = updatePolicy(policyMap, egConditions, policyListenerScopes);
 
             notifyListeners(updatedGroups);
         } catch (Exception e) {
@@ -359,444 +326,14 @@ public class PolicyResolver implements AutoCloseable {
         }
     }
 
-    /**
-     * Resolve the policy in three phases: (1) select contracts that in scope
-     * based on contract selectors. (2) select subjects that are in scope for
-     * each contract based on matchers in clauses (3) resolve the set of
-     * in-scope contracts into a list of subjects that apply for each pair of
-     * endpoint groups and the conditions that can apply for for each endpoint
-     * in those groups.
-     */
-    protected Table<EgKey, EgKey, Policy>
-            resolvePolicy(Collection<TenantContext> tenants,
-                    Map<EgKey, Set<ConditionSet>> egConditions) {
-        // select contracts that apply for the given tenant
-        Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                selectContracts(tenants);
-
-        // select subjects for the matching contracts and resolve the policy
-        // for endpoint group pairs. This does phase (2) and (3) as one step
-        return selectSubjects(contractMatches, egConditions);
-    }
-
-    /**
-     * Choose the contracts that are in scope for each pair of endpoint groups,
-     * then perform subject selection for the pair
-     */
-    protected Table<EgKey, EgKey, List<ContractMatch>>
-            selectContracts(Collection<TenantContext> tenants) {
-        Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches =
-                HashBasedTable.create();
-        Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                HashBasedTable.create();
-
-        for (TenantContext tenant : tenants) {
+    private Set<IndexedTenant> getIndexedTenants(Collection<TenantContext> tenantCtxs) {
+        Set<IndexedTenant> result = new HashSet<>();
+        for (TenantContext tenant : tenantCtxs) {
             IndexedTenant t = tenant.tenant.get();
-            if (t == null)
-                continue;
-            selectContracts(consumerMatches,
-                    contractMatches,
-                    t.getTenant());
-        }
-        return contractMatches;
-    }
-
-    protected 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
-        if (tenant.getEndpointGroup() == null)
-            return;
-        for (EndpointGroup group : tenant.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 : tenant.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 boolean clauseMatchesByGroupReqAndCapConstraints(Clause clause, ContractMatch match) {
-        if (clause.getConsumerMatchers() != null) {
-            GroupIdentificationConstraints groupIdentificationConstraintsConsumer = clause.getConsumerMatchers()
-                    .getGroupIdentificationConstraints();
-            if (groupIdentificationConstraintsConsumer instanceof GroupRequirementConstraintCase) {
-                List<RequirementMatcher> reqMatchers = ((GroupRequirementConstraintCase) groupIdentificationConstraintsConsumer)
-                        .getRequirementMatcher();
-                if (reqMatchers != null) {
-                    for (RequirementMatcher reqMatcher : reqMatchers) {
-                        if (!MatcherUtils.applyReqMatcher(reqMatcher,
-                                match.consumerRelator)) {
-                            return false;
-                        }
-                    }
-                }
-            }
-        }
-        if (clause.getProviderMatchers() != null) {
-            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.GroupIdentificationConstraints groupIdentificationConstraintsProvider = clause
-                    .getProviderMatchers().getGroupIdentificationConstraints();
-            if (groupIdentificationConstraintsProvider instanceof GroupCapabilityConstraintCase) {
-                List<CapabilityMatcher> capMatchers = ((GroupCapabilityConstraintCase) groupIdentificationConstraintsProvider)
-                        .getCapabilityMatcher();
-
-                if (capMatchers != null) {
-                    for (CapabilityMatcher capMatcher : capMatchers) {
-                        if (!MatcherUtils.applyCapMatcher(capMatcher,
-                                match.providerRelator)) {
-                            return false;
-                        }
-                    }
-                }
-            }
+            if (t != null)
+                result.add(t);
         }
-        return true;
-    }
-
-    private ConditionSet buildConditionSet(List<ConditionMatcher> condMatchers) {
-        if (condMatchers == null)
-            return ConditionSet.EMPTY;
-
-        ImmutableSet.Builder<ConditionName> allb = ImmutableSet.builder();
-        ImmutableSet.Builder<ConditionName> noneb = ImmutableSet.builder();
-        ImmutableSet.Builder<Set<ConditionName>> anyb =
-                ImmutableSet.builder();
-        for (ConditionMatcher condMatcher : condMatchers) {
-            if (condMatcher.getCondition() == null)
-                continue;
-            MatchType type = condMatcher.getMatchType();
-            if (type == null)
-                type = MatchType.All;
-            if (type.equals(MatchType.Any)) {
-                ImmutableSet.Builder<ConditionName> a =
-                        ImmutableSet.builder();
-                for (Condition c : condMatcher.getCondition()) {
-                    a.add(c.getName());
-                }
-                anyb.add(a.build());
-            } else {
-                for (Condition c : condMatcher.getCondition()) {
-                    switch (type) {
-                    case Any:
-                        break;
-                    case None:
-                        noneb.add(c.getName());
-                        break;
-                    case All:
-                    default:
-                        allb.add(c.getName());
-                        break;
-                    }
-                }
-            }
-        }
-        return new ConditionSet(allb.build(), noneb.build(), anyb.build());
-    }
-
-    private ConditionSet buildConsConditionSet(Clause clause) {
-        if (clause.getConsumerMatchers() != null) {
-            List<ConditionMatcher> condMatchers =
-                    clause.getConsumerMatchers().getConditionMatcher();
-            return buildConditionSet(condMatchers);
-        }
-        return ConditionSet.EMPTY;
-    }
-
-    private ConditionSet buildProvConditionSet(Clause clause) {
-        if (clause.getProviderMatchers() != null) {
-            List<ConditionMatcher> condMatchers =
-                    clause.getProviderMatchers().getConditionMatcher();
-            return buildConditionSet(condMatchers);
-        }
-        return ConditionSet.EMPTY;
-    }
-
-    private Policy resolvePolicy(Tenant contractTenant,
-            Contract contract,
-            Policy merge,
-            Table<ConditionSet, ConditionSet,
-            List<Subject>> subjectMap) {
-        Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap =
-                HashBasedTable.create();
-        if (merge != null) {
-            ruleMap.putAll(merge.getRuleMap());
-        }
-        for (Cell<ConditionSet, ConditionSet, List<Subject>> entry : subjectMap.cellSet()) {
-            List<RuleGroup> rules = new ArrayList<>();
-            ConditionSet consConds = entry.getRowKey();
-            ConditionSet provConds = entry.getColumnKey();
-            List<RuleGroup> oldrules = ruleMap.get(consConds, provConds);
-            if (oldrules != null) {
-                rules.addAll(oldrules);
-            }
-            for (Subject s : entry.getValue()) {
-                if (s.getRule() == null)
-                    continue;
-
-                RuleGroup rg = new RuleGroup(s.getRule(), s.getOrder(),
-                        contractTenant, contract,
-                        s.getName());
-                rules.add(rg);
-            }
-            Collections.sort(rules);
-            ruleMap.put(consConds, provConds, Collections.unmodifiableList(rules));
-        }
-        return new Policy(ruleMap);
-    }
-
-    /**
-     * Get the "natural" direction for the policy for the given pair of endpoint
-     * groups.
-     *
-     * @param one
-     *            The first endpoint group
-     * @param two
-     *            The second endpoint group
-     * @return true if the order should be reversed in the index
-     */
-    protected static boolean shouldReverse(EgKey one, EgKey two) {
-        if (one.compareTo(two) < 0) {
-            return true;
-        }
-        return false;
-    }
-
-    private void addConditionSet(EgKey eg, ConditionSet cs,
-            Map<EgKey, Set<ConditionSet>> egConditions) {
-        if (egConditions == null)
-            return;
-        Set<ConditionSet> cset = egConditions.get(eg);
-        if (cset == null) {
-            egConditions.put(eg, cset = new HashSet<>());
-        }
-        cset.add(cs);
-    }
-
-    /**
-     * Choose the set of subjects that in scope for each possible set of
-     * endpoint conditions
-     */
-    // TODO Li msunal do we really need contractMatches to be a type Table<EgKey, EgKey, List<ContractMatch>>
-    // it should be sufficient to be just List<ContractMatch>
-    protected Table<EgKey, EgKey, Policy>
-            selectSubjects(Table<EgKey, EgKey,
-                    List<ContractMatch>> contractMatches,
-                    Map<EgKey, Set<ConditionSet>> egConditions) {
-        // TODO: Note that it's possible to further simplify the resulting
-        // policy
-        // in the case of things like repeated rules, condition sets that
-        // cover other condition sets, etc. This would be a good thing to do
-        // at some point
-        Table<EgKey, EgKey, Policy> policy = HashBasedTable.create();
-
-        for (List<ContractMatch> matches : contractMatches.values()) {
-            for (ContractMatch match : matches) {
-                List<Clause> clauses = match.contract.getClause();
-                if (clauses == null)
-                    continue;
-
-                List<Subject> subjectList = match.contract.getSubject();
-                if (subjectList == null)
-                    continue;
-
-                EgKey ckey = new EgKey(match.consumerTenant.getId(),
-                        match.consumer.getId());
-                EgKey pkey = new EgKey(match.providerTenant.getId(),
-                        match.provider.getId());
-                Policy existing = policy.get(ckey, pkey);
-
-                HashMap<SubjectName, Subject> subjects = new HashMap<>();
-                for (Subject s : subjectList) {
-                    subjects.put(s.getName(), s);
-                }
-
-                Table<ConditionSet, ConditionSet, List<Subject>> subjectMap =
-                        HashBasedTable.create();
-
-                for (Clause clause : clauses) {
-                    if (clause.getSubjectRefs() != null &&
-                            clauseMatchesByGroupReqAndCapConstraints(clause, match)) {
-                        ConditionSet consCSet = buildConsConditionSet(clause);
-                        addConditionSet(ckey, consCSet, egConditions);
-                        ConditionSet provCSet = buildProvConditionSet(clause);
-                        addConditionSet(pkey, provCSet, egConditions);
-                        List<Subject> clauseSubjects =
-                                subjectMap.get(consCSet, provCSet);
-                        if (clauseSubjects == null) {
-                            clauseSubjects = new ArrayList<>();
-                            subjectMap.put(consCSet, provCSet, clauseSubjects);
-                        }
-                        for (SubjectName sn : clause.getSubjectRefs()) {
-                            Subject s = subjects.get(sn);
-                            if (s != null)
-                                clauseSubjects.add(s);
-                        }
-                    }
-                }
-
-                policy.put(ckey, pkey,
-                        resolvePolicy(match.contractTenant,
-                                match.contract,
-                                existing,
-                                subjectMap));
-            }
-        }
-
-        return policy;
-    }
-
-    private List<ConsumerContractMatch> matchConsumerContracts(Tenant tenant,
-            EndpointGroup consumer) {
-        List<ConsumerContractMatch> matches = new ArrayList<>();
-        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()) {
-                if (tenant.getContract() == null)
-                    continue;
-                for (Contract contract : tenant.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 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));
-        }
-    }
-
-    private List<ContractMatch>
-            matchProviderContracts(Tenant tenant, EndpointGroup provider,
-                    Table<TenantId,
-                    ContractId,
-                    List<ConsumerContractMatch>> consumerMatches) {
-        List<ContractMatch> matches = new ArrayList<>();
-        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()) {
-                if (tenant.getContract() == null)
-                    continue;
-                for (Contract c : tenant.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;
+        return result;
     }
 
     protected static class TenantContext {
@@ -810,85 +347,6 @@ public class PolicyResolver implements AutoCloseable {
         }
     }
 
-    /**
-     * 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
-    protected 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
-    private 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;
-        }
-    }
-
     @Immutable
     private class PolicyChangeListener implements DataChangeListener {
         final TenantId tenantId;
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolverUtils.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolverUtils.java
new file mode 100644 (file)
index 0000000..fe36a85
--- /dev/null
@@ -0,0 +1,49 @@
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.groupbasedpolicy.resolver.ContractResolverUtils.ContractMatch;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Table;
+
+public class PolicyResolverUtils {
+
+    private PolicyResolverUtils() {
+        throw new UnsupportedOperationException("Cannot create an instance");
+    }
+
+    /**
+     * Resolve the policy in three phases: <br>
+     * (1) select contracts that in scope based on contract selectors. <br>
+     * (2) select subjects that are in scope for each contract based on matchers in clauses <br>
+     * (3) resolve the set of in-scope contracts into a list of subjects that apply for each pair of
+     * endpoint groups and the conditions that can apply for for each endpoint in those groups.
+     */
+    public static Table<EgKey, EgKey, Policy> resolvePolicy(Set<IndexedTenant> tenants) {
+        return resolvePolicy(tenants, new HashMap<EgKey, Set<ConditionSet>>());
+    }
+
+    /**
+     * Resolve the policy in three phases: <br>
+     * (1) select contracts that in scope based on contract selectors. <br>
+     * (2) select subjects that are in scope for each contract based on matchers in clauses <br>
+     * (3) resolve the set of in-scope contracts into a list of subjects that apply for each pair of
+     * endpoint groups and the conditions that can apply for for each endpoint in those groups.
+     */
+    protected static Table<EgKey, EgKey, Policy> resolvePolicy(Set<IndexedTenant> tenants,
+            Map<EgKey, Set<ConditionSet>> egConditions) {
+        Preconditions.checkNotNull(tenants);
+        Preconditions.checkNotNull(egConditions);
+        // select contracts that apply for the given tenant
+        Table<EgKey, EgKey, List<ContractMatch>> contractMatches = ContractResolverUtils.selectContracts(tenants);
+
+        // select subjects for the matching contracts and resolve the policy
+        // for endpoint group pairs. This does phase (2) and (3) as one step
+        return SubjectResolverUtils.selectSubjects(contractMatches, egConditions);
+    }
+
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/SubjectResolverUtils.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/SubjectResolverUtils.java
new file mode 100644 (file)
index 0000000..3541c95
--- /dev/null
@@ -0,0 +1,248 @@
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.groupbasedpolicy.resolver.ContractResolverUtils.ContractMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Matcher.MatchType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
+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.Contract;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.GroupIdentificationConstraints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.group.identification.constraints.GroupRequirementConstraintCase;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.group.identification.constraints.GroupCapabilityConstraintCase;
+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;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
+
+
+public class SubjectResolverUtils {
+
+    private SubjectResolverUtils() {
+        throw new UnsupportedOperationException("Cannot create an instance");
+    }
+
+    /**
+     * Choose the set of subjects that in scope for each possible set of
+     * endpoint conditions
+     */
+    // TODO Li msunal do we really need contractMatches to be a type Table<EgKey, EgKey, List<ContractMatch>>
+    // it should be sufficient to be just List<ContractMatch>
+    protected static Table<EgKey, EgKey, Policy> selectSubjects(
+            Table<EgKey, EgKey, List<ContractMatch>> contractMatches, Map<EgKey, Set<ConditionSet>> egConditions) {
+        // TODO: Note that it's possible to further simplify the resulting
+        // policy
+        // in the case of things like repeated rules, condition sets that
+        // cover other condition sets, etc. This would be a good thing to do
+        // at some point
+        Table<EgKey, EgKey, Policy> policy = HashBasedTable.create();
+
+        for (List<ContractMatch> matches : contractMatches.values()) {
+            for (ContractMatch match : matches) {
+                List<Clause> clauses = match.contract.getClause();
+                if (clauses == null)
+                    continue;
+
+                List<Subject> subjectList = match.contract.getSubject();
+                if (subjectList == null)
+                    continue;
+
+                EgKey ckey = new EgKey(match.consumerTenant.getId(),
+                        match.consumer.getId());
+                EgKey pkey = new EgKey(match.providerTenant.getId(),
+                        match.provider.getId());
+                Policy existing = policy.get(ckey, pkey);
+
+                HashMap<SubjectName, Subject> subjects = new HashMap<>();
+                for (Subject s : subjectList) {
+                    subjects.put(s.getName(), s);
+                }
+
+                Table<ConditionSet, ConditionSet, List<Subject>> subjectMap =
+                        HashBasedTable.create();
+
+                for (Clause clause : clauses) {
+                    if (clause.getSubjectRefs() != null &&
+                            clauseMatchesByGroupReqAndCapConstraints(clause, match)) {
+                        ConditionSet consCSet = buildConsConditionSet(clause);
+                        addConditionSet(ckey, consCSet, egConditions);
+                        ConditionSet provCSet = buildProvConditionSet(clause);
+                        addConditionSet(pkey, provCSet, egConditions);
+                        List<Subject> clauseSubjects =
+                                subjectMap.get(consCSet, provCSet);
+                        if (clauseSubjects == null) {
+                            clauseSubjects = new ArrayList<>();
+                            subjectMap.put(consCSet, provCSet, clauseSubjects);
+                        }
+                        for (SubjectName sn : clause.getSubjectRefs()) {
+                            Subject s = subjects.get(sn);
+                            if (s != null)
+                                clauseSubjects.add(s);
+                        }
+                    }
+                }
+
+                policy.put(ckey, pkey,
+                        resolvePolicy(match.contractTenant,
+                                match.contract,
+                                existing,
+                                subjectMap));
+            }
+        }
+
+        return policy;
+    }
+
+    private static boolean clauseMatchesByGroupReqAndCapConstraints(Clause clause, ContractMatch match) {
+        if (clause.getConsumerMatchers() != null) {
+            GroupIdentificationConstraints groupIdentificationConstraintsConsumer = clause.getConsumerMatchers()
+                    .getGroupIdentificationConstraints();
+            if (groupIdentificationConstraintsConsumer instanceof GroupRequirementConstraintCase) {
+                List<RequirementMatcher> reqMatchers = ((GroupRequirementConstraintCase) groupIdentificationConstraintsConsumer)
+                        .getRequirementMatcher();
+                if (reqMatchers != null) {
+                    for (RequirementMatcher reqMatcher : reqMatchers) {
+                        if (!MatcherUtils.applyReqMatcher(reqMatcher,
+                                match.consumerRelator)) {
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        if (clause.getProviderMatchers() != null) {
+            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.GroupIdentificationConstraints groupIdentificationConstraintsProvider = clause
+                    .getProviderMatchers().getGroupIdentificationConstraints();
+            if (groupIdentificationConstraintsProvider instanceof GroupCapabilityConstraintCase) {
+                List<CapabilityMatcher> capMatchers = ((GroupCapabilityConstraintCase) groupIdentificationConstraintsProvider)
+                        .getCapabilityMatcher();
+
+                if (capMatchers != null) {
+                    for (CapabilityMatcher capMatcher : capMatchers) {
+                        if (!MatcherUtils.applyCapMatcher(capMatcher,
+                                match.providerRelator)) {
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private static void addConditionSet(EgKey eg, ConditionSet cs,
+            Map<EgKey, Set<ConditionSet>> egConditions) {
+        if (egConditions == null)
+            return;
+        Set<ConditionSet> cset = egConditions.get(eg);
+        if (cset == null) {
+            egConditions.put(eg, cset = new HashSet<>());
+        }
+        cset.add(cs);
+    }
+
+    private static ConditionSet buildConsConditionSet(Clause clause) {
+        if (clause.getConsumerMatchers() != null) {
+            List<ConditionMatcher> condMatchers =
+                    clause.getConsumerMatchers().getConditionMatcher();
+            return buildConditionSet(condMatchers);
+        }
+        return ConditionSet.EMPTY;
+    }
+
+    private static ConditionSet buildProvConditionSet(Clause clause) {
+        if (clause.getProviderMatchers() != null) {
+            List<ConditionMatcher> condMatchers =
+                    clause.getProviderMatchers().getConditionMatcher();
+            return buildConditionSet(condMatchers);
+        }
+        return ConditionSet.EMPTY;
+    }
+
+    private static ConditionSet buildConditionSet(List<ConditionMatcher> condMatchers) {
+        if (condMatchers == null)
+            return ConditionSet.EMPTY;
+
+        ImmutableSet.Builder<ConditionName> allb = ImmutableSet.builder();
+        ImmutableSet.Builder<ConditionName> noneb = ImmutableSet.builder();
+        ImmutableSet.Builder<Set<ConditionName>> anyb =
+                ImmutableSet.builder();
+        for (ConditionMatcher condMatcher : condMatchers) {
+            if (condMatcher.getCondition() == null)
+                continue;
+            MatchType type = condMatcher.getMatchType();
+            if (type == null)
+                type = MatchType.All;
+            if (type.equals(MatchType.Any)) {
+                ImmutableSet.Builder<ConditionName> a =
+                        ImmutableSet.builder();
+                for (Condition c : condMatcher.getCondition()) {
+                    a.add(c.getName());
+                }
+                anyb.add(a.build());
+            } else {
+                for (Condition c : condMatcher.getCondition()) {
+                    switch (type) {
+                    case Any:
+                        break;
+                    case None:
+                        noneb.add(c.getName());
+                        break;
+                    case All:
+                    default:
+                        allb.add(c.getName());
+                        break;
+                    }
+                }
+            }
+        }
+        return new ConditionSet(allb.build(), noneb.build(), anyb.build());
+    }
+
+    private static Policy resolvePolicy(Tenant contractTenant,
+            Contract contract,
+            Policy merge,
+            Table<ConditionSet, ConditionSet,
+            List<Subject>> subjectMap) {
+        Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap =
+                HashBasedTable.create();
+        if (merge != null) {
+            ruleMap.putAll(merge.getRuleMap());
+        }
+        for (Cell<ConditionSet, ConditionSet, List<Subject>> entry : subjectMap.cellSet()) {
+            List<RuleGroup> rules = new ArrayList<>();
+            ConditionSet consConds = entry.getRowKey();
+            ConditionSet provConds = entry.getColumnKey();
+            List<RuleGroup> oldrules = ruleMap.get(consConds, provConds);
+            if (oldrules != null) {
+                rules.addAll(oldrules);
+            }
+            for (Subject s : entry.getValue()) {
+                if (s.getRule() == null)
+                    continue;
+
+                RuleGroup rg = new RuleGroup(s.getRule(), s.getOrder(),
+                        contractTenant, contract,
+                        s.getName());
+                rules.add(rg);
+            }
+            Collections.sort(rules);
+            ruleMap.put(consConds, provConds, Collections.unmodifiableList(rules));
+        }
+        return new Policy(ruleMap);
+    }
+}
index 72d516e5c7ac2fb1527bea498f26dde930ac5cc1..a4d1be121d162abd3ccfba2ac1e109c4283ac2df 100644 (file)
@@ -12,8 +12,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -22,7 +20,7 @@ import java.util.Set;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver.ContractMatch;
+import org.opendaylight.groupbasedpolicy.resolver.ContractResolverUtils.ContractMatch;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver.TenantContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityMatcherName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityName;
@@ -338,11 +336,10 @@ public class PolicyResolverTest {
     public void testContractSelection() throws Exception {
         // named selectors
         TenantContext tc = new TenantContext(null);
-        Collection<TenantContext> tCol = Collections.singleton(tc);
 
         tc.tenant.set(new IndexedTenant(tenant1));
         Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                resolver.selectContracts(tCol);
+                ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         assertEquals(1, contractMatches.size());
         List<ContractMatch> matches =
                 contractMatches.get(new EgKey(tenant1.getId(), eg1.getId()),
@@ -353,7 +350,7 @@ public class PolicyResolverTest {
 
 
         tc.tenant.set(new IndexedTenant(tenant2));
-        contractMatches = resolver.selectContracts(tCol);
+        contractMatches = ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         assertEquals(2, contractMatches.size());
         matches = contractMatches.get(new EgKey(tenant2.getId(), eg1.getId()),
                                       new EgKey(tenant2.getId(), eg2.getId()));
@@ -369,7 +366,7 @@ public class PolicyResolverTest {
 
         // target selectors
         tc.tenant.set(new IndexedTenant(tenant3));
-        contractMatches = resolver.selectContracts(tCol);
+        contractMatches = ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         assertEquals(1, contractMatches.size());
         matches = contractMatches.get(new EgKey(tenant3.getId(), eg4.getId()),
                                       new EgKey(tenant3.getId(), eg5.getId()));
@@ -379,11 +376,11 @@ public class PolicyResolverTest {
 
         // empty matches
         tc.tenant.set(new IndexedTenant(tenant0));
-        contractMatches = resolver.selectContracts(tCol);
+        contractMatches = ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         assertEquals(0, contractMatches.size());
 
         tc.tenant.set(new IndexedTenant(tenant00));
-        contractMatches = resolver.selectContracts(tCol);
+        contractMatches = ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         assertEquals(0, contractMatches.size());
     }
 
@@ -395,14 +392,13 @@ public class PolicyResolverTest {
                                  ImmutableSet.of(ImmutableSet.of(cond1.getName(),
                                                                  cond2.getName())));
         TenantContext tc = new TenantContext(null);
-        Collection<TenantContext> tCol = Collections.singleton(tc);
 
         tc.tenant.set(new IndexedTenant(tenant1));
         Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                resolver.selectContracts(tCol);
+                ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
         Table<EgKey, EgKey, Policy> policy =
-                resolver.selectSubjects(contractMatches, egConditions);
+                SubjectResolverUtils.selectSubjects(contractMatches, egConditions);
         assertEquals(1, policy.size());
         Policy p = policy.get(new EgKey(tenant1.getId(), eg1.getId()), new EgKey(tenant1.getId(), eg2.getId()));
         List<RuleGroup> rules = p.getRuleMap().get(cs, ConditionSet.EMPTY);
@@ -416,9 +412,9 @@ public class PolicyResolverTest {
         assertEquals(rule1.getName(), rg.rules.get(0).getName());
 
         tc.tenant.set(new IndexedTenant(tenant2));
-        contractMatches = resolver.selectContracts(tCol);
+        contractMatches = ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         egConditions = new HashMap<>();
-        policy = resolver.selectSubjects(contractMatches, egConditions);
+        policy = SubjectResolverUtils.selectSubjects(contractMatches, egConditions);
 
         assertEquals(2, policy.size());
         p = policy.get(new EgKey(tenant2.getId(), eg3.getId()),
@@ -456,9 +452,9 @@ public class PolicyResolverTest {
         assertEquals(rule1.getName(), rg.rules.get(0).getName());
 
         tc.tenant.set(new IndexedTenant(tenant3));
-        contractMatches = resolver.selectContracts(tCol);
+        contractMatches = ContractResolverUtils.selectContracts(ImmutableSet.of(tc.tenant.get()));
         egConditions = new HashMap<>();
-        policy = resolver.selectSubjects(contractMatches, egConditions);
+        policy = SubjectResolverUtils.selectSubjects(contractMatches, egConditions);
 
         assertEquals(1, policy.size());
         p = policy.get(new EgKey(tenant3.getId(), eg4.getId()),
diff --git a/pom.xml b/pom.xml
index 33936d916e15762d40d6b58ed768f296040366e8..c3d75a4ad48f345bdd40c8fc9844f3fb77f1cf8b 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -2,9 +2,7 @@
 <!-- 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 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  and is available at http://www.eclipse.org/legal/epl-v10.html --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
@@ -31,6 +29,8 @@
     <module>groupbasedpolicy-openstackendpoint-config</module>
     <module>neutron-mapper</module>
     <module>neutron-mapper-config</module>
+    <module>ui-backend</module>
+    <module>ui-backend-config</module>
     <module>distribution-karaf</module>
     <module>features</module>
   </modules>
@@ -54,4 +54,4 @@
     <tag>HEAD</tag>
     <url>https://wiki.opendaylight.org/view/Group_Policy:Main</url>
   </scm>
-</project>
+</project>
\ No newline at end of file
diff --git a/ui-backend-config/pom.xml b/ui-backend-config/pom.xml
new file mode 100644 (file)
index 0000000..5f69f29
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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 -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.groupbasedpolicy</groupId>
+    <artifactId>commons.groupbasedpolicy</artifactId>
+    <version>0.2.0-SNAPSHOT</version>
+    <relativePath>../commons/parent</relativePath>
+  </parent>
+
+  <artifactId>ui-backend-config</artifactId>
+  <description>Controller Configuration files for ui-backend</description>
+  <packaging>jar</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <phase>package</phase>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/15-ui-backend.xml</file>
+                  <type>xml</type>
+                  <classifier>config</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ui-backend-config/src/main/resources/initial/15-ui-backend.xml b/ui-backend-config/src/main/resources/initial/15-ui-backend.xml
new file mode 100755 (executable)
index 0000000..d8d9945
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+ Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.\r
+\r
+ This program and the accompanying materials are made available under the\r
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<snapshot>\r
+  <configuration>\r
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\r
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">\r
+        <module>\r
+          <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:config:ui-backend:impl">\r
+            binding-impl:ui-backend-impl\r
+          </type>\r
+          <name>ui-backend-impl</name>\r
+\r
+          <data-broker>\r
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">\r
+              binding:binding-async-data-broker\r
+            </type>\r
+            <name>binding-data-broker</name>\r
+          </data-broker>\r
+\r
+          <rpc-registry>\r
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">\r
+              binding:binding-rpc-registry\r
+            </type>\r
+            <name>binding-rpc-broker</name>\r
+          </rpc-registry>\r
+        </module>\r
+      </modules>\r
+    </data>\r
+  </configuration>\r
+\r
+  <required-capabilities>\r
+    <capability>urn:opendaylight:params:xml:ns:yang:controller:config:ui-backend:impl?module=ui-backend-impl&amp;revision=2015-05-11\r
+    </capability>\r
+  </required-capabilities>\r
+</snapshot>\r
diff --git a/ui-backend/pom.xml b/ui-backend/pom.xml
new file mode 100644 (file)
index 0000000..b4a95b8
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.groupbasedpolicy</groupId>
+    <artifactId>groupbasedpolicy.project</artifactId>
+    <version>0.2.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>ui-backend</artifactId>
+  <packaging>bundle</packaging>
+
+  <!-- project build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+            </Export-Package>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <redirectTestOutputToFile>true</redirectTestOutputToFile>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>groupbasedpolicy</artifactId>
+    </dependency>
+
+    <!-- controller dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-config</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/ui-backend/src/main/java/org/opendaylight/controller/config/yang/config/ui_backend/impl/UiBackendModule.java b/ui-backend/src/main/java/org/opendaylight/controller/config/yang/config/ui_backend/impl/UiBackendModule.java
new file mode 100644 (file)
index 0000000..ae82bc8
--- /dev/null
@@ -0,0 +1,43 @@
+package org.opendaylight.controller.config.yang.config.ui_backend.impl;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.groupbasedpolicy.ui.backend.UiBackendServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class UiBackendModule extends org.opendaylight.controller.config.yang.config.ui_backend.impl.AbstractUiBackendModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UiBackendModule.class);
+
+    public UiBackendModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public UiBackendModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.ui_backend.impl.UiBackendModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        DataBroker dataProvider = Preconditions.checkNotNull(getDataBrokerDependency());
+        final UiBackendServiceImpl pgnApplicationService = new UiBackendServiceImpl(dataProvider,
+                getRpcRegistryDependency());
+        LOG.info("ui-backend started.");
+
+        return new AutoCloseable() {
+
+            @Override
+            public void close() throws Exception {
+                pgnApplicationService.close();
+            }
+        };
+    }
+
+}
diff --git a/ui-backend/src/main/java/org/opendaylight/controller/config/yang/config/ui_backend/impl/UiBackendModuleFactory.java b/ui-backend/src/main/java/org/opendaylight/controller/config/yang/config/ui_backend/impl/UiBackendModuleFactory.java
new file mode 100644 (file)
index 0000000..7bc7f64
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: ui-backend-impl yang module local name: ui-backend-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Mon May 11 01:23:43 CEST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.ui_backend.impl;
+public class UiBackendModuleFactory extends org.opendaylight.controller.config.yang.config.ui_backend.impl.AbstractUiBackendModuleFactory {
+
+}
diff --git a/ui-backend/src/main/java/org/opendaylight/groupbasedpolicy/ui/backend/UiBackendServiceImpl.java b/ui-backend/src/main/java/org/opendaylight/groupbasedpolicy/ui/backend/UiBackendServiceImpl.java
new file mode 100755 (executable)
index 0000000..392cf09
--- /dev/null
@@ -0,0 +1,243 @@
+/*\r
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.ui.backend;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.concurrent.Future;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;\r
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;\r
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;\r
+import org.opendaylight.groupbasedpolicy.resolver.EgKey;\r
+import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;\r
+import org.opendaylight.groupbasedpolicy.resolver.Policy;\r
+import org.opendaylight.groupbasedpolicy.resolver.PolicyResolverUtils;\r
+import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.GetEndpointsFromEndpointGroupInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.GetEndpointsFromEndpointGroupOutput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.GetEndpointsFromEndpointGroupOutputBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.GetSubjectsBetweenEndpointGroupsInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.GetSubjectsBetweenEndpointGroupsOutput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.GetSubjectsBetweenEndpointGroupsOutputBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.UiBackendService;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.endpoints.from.endpoint.group.output.UiEndpoint;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.endpoints.from.endpoint.group.output.UiEndpointBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.input.FromOperData;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.output.EndpointGroupPairWithSubject;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.output.EndpointGroupPairWithSubjectBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.output.endpoint.group.pair.with.subject.UiSubject;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.output.endpoint.group.pair.with.subject.UiSubjectBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.output.endpoint.group.pair.with.subject.ui.subject.UiRule;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ui.backend.rev150511.get.subjects.between.endpoint.groups.output.endpoint.group.pair.with.subject.ui.subject.UiRuleBuilder;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.opendaylight.yangtools.yang.common.RpcResult;\r
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.google.common.base.Function;\r
+import com.google.common.base.Optional;\r
+import com.google.common.base.Preconditions;\r
+import com.google.common.collect.ImmutableSet;\r
+import com.google.common.collect.Table;\r
+import com.google.common.collect.Table.Cell;\r
+import com.google.common.util.concurrent.CheckedFuture;\r
+import com.google.common.util.concurrent.Futures;\r
+\r
+public class UiBackendServiceImpl implements UiBackendService, AutoCloseable {\r
+\r
+    private static final Logger LOG = LoggerFactory.getLogger(UiBackendServiceImpl.class);\r
+\r
+    private final DataBroker dataProvider;\r
+    private final BindingAwareBroker.RpcRegistration<UiBackendService> rpcRegistration;\r
+    private final InstanceIdentifier<Endpoints> ENDPOINTS_IID = InstanceIdentifier.builder(Endpoints.class).build();\r
+\r
+    public UiBackendServiceImpl(DataBroker dataBroker, RpcProviderRegistry rpcRegistry) {\r
+        Preconditions.checkNotNull(dataBroker);\r
+        Preconditions.checkNotNull(rpcRegistry);\r
+        this.dataProvider = dataBroker;\r
+        rpcRegistration = rpcRegistry.addRpcImplementation(UiBackendService.class, this);\r
+    }\r
+\r
+    @Override\r
+    public Future<RpcResult<GetEndpointsFromEndpointGroupOutput>> getEndpointsFromEndpointGroup(\r
+            GetEndpointsFromEndpointGroupInput input) {\r
+        LOG.trace("getEndpointsFromEndpointGroup: {}", input);\r
+        final TenantId tenantId = input.getTenantId();\r
+        if (tenantId == null) {\r
+            throw new IllegalArgumentException("Missing tenant-Id in RPC input.");\r
+        }\r
+        final EndpointGroupId epgId = input.getEndpointGroupId();\r
+        if (epgId == null) {\r
+            throw new IllegalArgumentException("Missing endpoint-group-id in RPC input.");\r
+        }\r
+        ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();\r
+        CheckedFuture<Optional<Endpoints>, ReadFailedException> futureEndpoints = rTx.read(\r
+                LogicalDatastoreType.OPERATIONAL, ENDPOINTS_IID);\r
+        return Futures.transform(futureEndpoints,\r
+                new Function<Optional<Endpoints>, RpcResult<GetEndpointsFromEndpointGroupOutput>>() {\r
+\r
+                    @Override\r
+                    public RpcResult<GetEndpointsFromEndpointGroupOutput> apply(Optional<Endpoints> potentialEndpoints) {\r
+                        GetEndpointsFromEndpointGroupOutputBuilder outputBuilder = new GetEndpointsFromEndpointGroupOutputBuilder();\r
+                        if (!potentialEndpoints.isPresent() || potentialEndpoints.get().getEndpoint() == null) {\r
+                            LOG.trace("No endpoint in datastore.");\r
+                            return RpcResultBuilder.success(outputBuilder.build()).build();\r
+                        }\r
+\r
+                        List<Endpoint> endpoints = potentialEndpoints.get().getEndpoint();\r
+                        List<UiEndpoint> uiEndpoints = new ArrayList<>();\r
+                        for (Endpoint ep : endpoints) {\r
+                            if (tenantId.equals(ep.getTenant()) && isEpInEpg(ep, epgId)) {\r
+                                uiEndpoints.add(new UiEndpointBuilder(ep).build());\r
+                            }\r
+                        }\r
+                        outputBuilder.setUiEndpoint(uiEndpoints);\r
+                        return RpcResultBuilder.success(outputBuilder.build()).build();\r
+                    }\r
+                });\r
+    }\r
+\r
+    private boolean isEpInEpg(Endpoint ep, EndpointGroupId epgId) {\r
+        if (epgId.equals(ep.getEndpointGroup())) {\r
+            return true;\r
+        }\r
+        if (ep.getEndpointGroups() != null) {\r
+            for (EndpointGroupId epgFromEp : ep.getEndpointGroups()) {\r
+                if (epgId.equals(epgFromEp)) {\r
+                    return true;\r
+                }\r
+            }\r
+        }\r
+        return false;\r
+    }\r
+\r
+    @Override\r
+    public Future<RpcResult<GetSubjectsBetweenEndpointGroupsOutput>> getSubjectsBetweenEndpointGroups(\r
+            GetSubjectsBetweenEndpointGroupsInput input) {\r
+        LOG.trace("getSubjectsBetweenEndpointGroups: {}", input);\r
+        final TenantId tenantId = input.getTenantId();\r
+        if (tenantId == null) {\r
+            throw new IllegalArgumentException("Missing tenant-Id in RPC input.");\r
+        }\r
+        final FromOperData fromOperData = input.getFromOperData();\r
+        InstanceIdentifier<Tenant> tenantIid = InstanceIdentifier.builder(Tenants.class)\r
+            .child(Tenant.class, new TenantKey(tenantId))\r
+            .build();\r
+        CheckedFuture<Optional<Tenant>, ReadFailedException> futureTenant;\r
+        try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {\r
+            if (fromOperData == null) {\r
+                futureTenant = rTx.read(LogicalDatastoreType.CONFIGURATION, tenantIid);\r
+            } else {\r
+                futureTenant = rTx.read(LogicalDatastoreType.OPERATIONAL, tenantIid);\r
+            }\r
+        }\r
+        return Futures.transform(futureTenant,\r
+                new Function<Optional<Tenant>, RpcResult<GetSubjectsBetweenEndpointGroupsOutput>>() {\r
+\r
+                    @Override\r
+                    public RpcResult<GetSubjectsBetweenEndpointGroupsOutput> apply(Optional<Tenant> potentialTenant) {\r
+                        GetSubjectsBetweenEndpointGroupsOutputBuilder outputBuilder = new GetSubjectsBetweenEndpointGroupsOutputBuilder();\r
+                        if (!potentialTenant.isPresent()) {\r
+                            LOG.trace(\r
+                                    "No tenant with id {} in {} datastore",\r
+                                    tenantId.getValue(),\r
+                                    fromOperData == null ? LogicalDatastoreType.CONFIGURATION : LogicalDatastoreType.OPERATIONAL);\r
+                            return RpcResultBuilder.success(outputBuilder.build()).build();\r
+                        }\r
+\r
+                        Tenant tenant = potentialTenant.get();\r
+                        Table<EgKey, EgKey, Policy> resolvedPolicy = PolicyResolverUtils.resolvePolicy(ImmutableSet.of(new IndexedTenant(\r
+                                tenant)));\r
+                        List<EndpointGroupPairWithSubject> epgPairsWithSubjects = new ArrayList<>();\r
+                        for (Cell<EgKey, EgKey, Policy> policyByConsProvEpg : resolvedPolicy.cellSet()) {\r
+                            Policy policy = policyByConsProvEpg.getValue();\r
+                            List<RuleGroup> subjects = getUniqueSortedSubjects(policy);\r
+                            List<UiSubject> uiSubjects = new ArrayList<>();\r
+                            for (RuleGroup subject : subjects) {\r
+                                UiSubject uiSubject = new UiSubjectBuilder().setName(subject.getRelatedSubject())\r
+                                    .setOrder(subject.getOrder())\r
+                                    .setUiRule(getUiRules(subject.getRules()))\r
+                                    .build();\r
+                                uiSubjects.add(uiSubject);\r
+                            }\r
+                            EgKey consEgKey = policyByConsProvEpg.getRowKey();\r
+                            EgKey provEgKey = policyByConsProvEpg.getColumnKey();\r
+                            LOG.trace(\r
+                                    "Resolved policies from {} datastore: \nConsumer EPG: {}\nProvider EPG: {}\nPolicy: {}",\r
+                                    fromOperData == null ? LogicalDatastoreType.CONFIGURATION : LogicalDatastoreType.OPERATIONAL,\r
+                                    consEgKey, provEgKey, policy);\r
+                            EndpointGroupPairWithSubject epgPairWithSubject = new EndpointGroupPairWithSubjectBuilder().setConsumerEndpointGroupId(\r
+                                    consEgKey.getEgId())\r
+                                .setConsumerTenantId(consEgKey.getTenantId())\r
+                                .setProviderEndpointGroupId(provEgKey.getEgId())\r
+                                .setProviderTenantId(provEgKey.getTenantId())\r
+                                .setUiSubject(uiSubjects)\r
+                                .build();\r
+                            epgPairsWithSubjects.add(epgPairWithSubject);\r
+                        }\r
+                        GetSubjectsBetweenEndpointGroupsOutput result = outputBuilder.setEndpointGroupPairWithSubject(\r
+                                epgPairsWithSubjects).build();\r
+                        return RpcResultBuilder.success(result).build();\r
+                    }\r
+                });\r
+    }\r
+\r
+    private List<RuleGroup> getUniqueSortedSubjects(Policy policy) {\r
+        Set<RuleGroup> uniqueSubjects = new HashSet<>();\r
+        for (List<RuleGroup> subjects : policy.getRuleMap().values()) {\r
+            for (RuleGroup subject : subjects) {\r
+                uniqueSubjects.add(subject);\r
+            }\r
+        }\r
+        ArrayList<RuleGroup> sortedSubjects = new ArrayList<>(uniqueSubjects);\r
+        Collections.sort(sortedSubjects);\r
+        return sortedSubjects;\r
+    }\r
+\r
+    private List<UiRule> getUiRules(List<Rule> rules) {\r
+        if (rules == null) {\r
+            return Collections.emptyList();\r
+        }\r
+        List<UiRule> uiRules = new ArrayList<>();\r
+        for (Rule rule : rules) {\r
+            UiRule uiRule = new UiRuleBuilder().setName(rule.getName())\r
+                .setOrder(rule.getOrder())\r
+                .setClassifierRef(rule.getClassifierRef())\r
+                .setActionRef(rule.getActionRef())\r
+                .build();\r
+            uiRules.add(uiRule);\r
+        }\r
+        return uiRules;\r
+    }\r
+\r
+    /**\r
+     * @see java.lang.AutoCloseable#close()\r
+     */\r
+    @Override\r
+    public void close() throws Exception {\r
+        rpcRegistration.close();\r
+    }\r
+\r
+}\r
diff --git a/ui-backend/src/main/yang/ui-backend-impl.yang b/ui-backend/src/main/yang/ui-backend-impl.yang
new file mode 100644 (file)
index 0000000..bd3f9cc
--- /dev/null
@@ -0,0 +1,52 @@
+module ui-backend-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:ui-backend:impl";
+    prefix "ui-backend-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+        ui-backend implementation.";
+
+    revision "2015-05-11" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of the service implementation as a module identity.
+    identity ui-backend-impl {
+        base config:module-type;
+
+        // Specifies the prefix for generated java classes.
+        config:java-name-prefix UiBackend;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+    augment "/config:modules/config:module/config:configuration" {
+        case ui-backend-impl {
+            when "/config:modules/config:module/config:type = 'ui-backend-impl'";
+
+            container data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-async-data-broker;
+                    }
+                }
+            }
+
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui-backend/src/main/yang/ui-backend.yang b/ui-backend/src/main/yang/ui-backend.yang
new file mode 100755 (executable)
index 0000000..e2e0edd
--- /dev/null
@@ -0,0 +1,105 @@
+module ui-backend {\r
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:ui-backend";\r
+    prefix "ui-backend";\r
+\r
+    import policy {prefix gbp-policy;}\r
+    import gbp-common {prefix gbp-common;}\r
+    import endpoint {prefix endpoint;}\r
+\r
+    description\r
+        "Module contains RPC definitions for more easier interaction of the GUI with the GBP APIs.";\r
+\r
+    revision "2015-05-11" {\r
+        description "Initial revision of ui-backend model";\r
+    }\r
+\r
+    grouping endpoint-group-identifier-fields {\r
+        leaf tenant-id {\r
+            type gbp-common:tenant-id;\r
+        }\r
+        leaf endpoint-group-id {\r
+            type gbp-common:endpoint-group-id;\r
+        }\r
+    }\r
+\r
+    grouping consumer-endpoint-group-ref {\r
+        leaf consumer-tenant-id {\r
+            type leafref {\r
+                path "/gbp-policy:tenants/gbp-policy:tenant/gbp-policy:id";\r
+            }\r
+        }\r
+        leaf consumer-endpoint-group-id {\r
+            type leafref {\r
+                path "/gbp-policy:tenants/gbp-policy:tenant/gbp-policy:endpoint-group/gbp-policy:id";\r
+            }\r
+        }\r
+    }\r
+\r
+    grouping provider-endpoint-group-ref {\r
+        leaf provider-tenant-id {\r
+            type leafref {\r
+                path "/gbp-policy:tenants/gbp-policy:tenant/gbp-policy:id";\r
+            }\r
+        }\r
+        leaf provider-endpoint-group-id {\r
+            type leafref {\r
+                path "/gbp-policy:tenants/gbp-policy:tenant/gbp-policy:endpoint-group/gbp-policy:id";\r
+            }\r
+        }\r
+    }\r
+\r
+    rpc get-endpoints-from-endpoint-group {\r
+        description "Returns endpoints which are in the given endpoint group.";\r
+        input {\r
+            uses endpoint-group-identifier-fields;\r
+        }\r
+        output {\r
+            list ui-endpoint {\r
+                description\r
+                    "Endpoints indexed by layer 2 addreses.";\r
+                key "l2-context mac-address";\r
+                uses endpoint:endpoint-fields;\r
+            }\r
+        }\r
+    }\r
+\r
+    rpc get-subjects-between-endpoint-groups {\r
+        description "Returns subjects between endpoint group pairs where endpoint groups are from the given tenant.";\r
+        input {\r
+            leaf tenant-id {\r
+                description "Tenant ID of the tenant.";\r
+                type gbp-common:tenant-id;\r
+                mandatory true;\r
+            }\r
+            container from-oper-data {\r
+                presence "Resolve subjects for endpoint gorup pairs based on operational data.";\r
+            }\r
+        }\r
+        output {\r
+            list endpoint-group-pair-with-subject {\r
+                key "consumer-endpoint-group-id consumer-tenant-id provider-endpoint-group-id provider-tenant-id";\r
+                uses consumer-endpoint-group-ref;\r
+                uses provider-endpoint-group-ref;\r
+                list ui-subject {\r
+                    key "name";\r
+                    leaf name {\r
+                        description "A name for the subject";\r
+                        type gbp-common:subject-name;\r
+                    }\r
+                    list ui-rule {\r
+                        key "name";\r
+                        leaf name {\r
+                            description "A name for the rule";\r
+                            type gbp-common:rule-name;\r
+                        }\r
+                        uses gbp-policy:has-classifier-refs;\r
+                        uses gbp-policy:has-action-refs;\r
+                        uses gbp-policy:has-order;\r
+                    }\r
+                    uses gbp-policy:has-order;\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+}\r