ios-xe renderer - listeners+cache 20/39120/5
authorMichal Rehak <mirehak@cisco.com>
Wed, 18 May 2016 17:30:30 +0000 (19:30 +0200)
committerMichal Rehak <mirehak@cisco.com>
Wed, 25 May 2016 15:29:37 +0000 (17:29 +0200)
    - added listeners for template and renderer-policy
    - wired listeners
    - added cache for templates
    - tests

Signed-off-by: Michal Rehak <mirehak@cisco.com>
Change-Id: I307091a0d4791b731ea418b926475954dffa09e7

16 files changed:
renderers/ios-xe/pom.xml
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/api/cache/DSTreeBasedCache.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/IosXeRendererProviderImpl.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyCacheImpl.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyTemplateCacheKey.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyTemplateCacheKeyFactory.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/config/IosXeProviderModule.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/EpPolicyTemplateBySgtListenerImpl.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/RendererConfigurationListenerImpl.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/AddressEndpointKeyEquivalence.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/RendererPolicyUtil.java [new file with mode: 0644]
renderers/ios-xe/src/main/yang/ios-xe-provider-impl.yang
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyCacheImplTest.java [new file with mode: 0644]
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/EpPolicyTemplateBySgtListenerImplTest.java [new file with mode: 0644]
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/RendererConfigurationListenerImplTest.java [new file with mode: 0644]
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/RendererPolicyUtilTest.java [new file with mode: 0644]

index 244118e0a426540a13f52cf89d4f436d2b966838..7678cc58d810877150f26da3cc4e16753f9206c6 100755 (executable)
@@ -5,73 +5,79 @@
   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>
+  <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>org.opendaylight.groupbasedpolicy</groupId>
-        <artifactId>groupbasedpolicy-renderers</artifactId>
-        <version>0.4.0-SNAPSHOT</version>
-        <relativePath>../</relativePath>
-    </parent>
+  <parent>
+    <groupId>org.opendaylight.groupbasedpolicy</groupId>
+    <artifactId>groupbasedpolicy-renderers</artifactId>
+    <version>0.4.0-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
 
-    <artifactId>ios-xe-renderer</artifactId>
-    <packaging>bundle</packaging>
+  <artifactId>ios-xe-renderer</artifactId>
+  <packaging>bundle</packaging>
 
-    <dependencies>
-        <!-- testing dependencies -->
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal-binding-broker-impl</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.groupbasedpolicy</groupId>
-            <artifactId>groupbasedpolicy</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
+  <dependencies>
+    <!-- model dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>sxp-mapper</artifactId>
+    </dependency>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>config</id>
-                        <goals>
-                            <goal>generate-sources</goal>
-                        </goals>
-                        <configuration>
-                            <codeGenerators>
-                                <generator>
-                                    <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
-                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
-                                    <additionalConfiguration>
-                                        <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
-                                        <namespaceToPackage2>urn:opendaylight:params:xml:ns:yang:groupbasedpolicy:renderer==org.opendaylight.groupbasedpolicy.renderer</namespaceToPackage2>
-                                    </additionalConfiguration>
-                                </generator>
-                            </codeGenerators>
-                            <inspectDependencies>true</inspectDependencies>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+    <!-- testing dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>groupbasedpolicy</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>config</id>
+            <goals>
+              <goal>generate-sources</goal>
+            </goals>
+            <configuration>
+              <codeGenerators>
+                <generator>
+                  <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                  <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                  <additionalConfiguration>
+                    <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                    <namespaceToPackage2>urn:opendaylight:params:xml:ns:yang:groupbasedpolicy:renderer==org.opendaylight.groupbasedpolicy.renderer</namespaceToPackage2>
+                  </additionalConfiguration>
+                </generator>
+              </codeGenerators>
+              <inspectDependencies>true</inspectDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 
 </project>
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/api/cache/DSTreeBasedCache.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/api/cache/DSTreeBasedCache.java
new file mode 100644 (file)
index 0000000..cd99cfc
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+/**
+ * Purpose: specify a cache driven by {@link DataTreeModification} where lookup key might differ from key used in
+ * dataStore and retrieved value is expected to be subset of &lt;T&gt;
+ *
+ * @param <T> dataStore object type
+ * @param <K> lookup key type
+ * @param <V> lookup result type
+ */
+public interface DSTreeBasedCache<T extends DataObject, K, V> {
+
+    /**
+     * @param exSource to be removed from cache
+     */
+    void invalidate(T exSource);
+
+    /**
+     * @param newSource to be added to chache
+     */
+    void add(T newSource);
+
+    /**
+     * update existing value
+     *
+     * @param before old value
+     * @param after  new value
+     */
+    void update(T before, T after);
+
+    /**
+     * @param key for finding cached value
+     * @return found value pair to given key or null
+     */
+    V lookupValue(K key);
+
+
+    /**
+     * dispose of all cached values
+     */
+    void invalidateAll();
+}
index 687474446e56902f930233c4d2088fe140c6d0b2..c43c41e49353d92ffb18b181d317a8b8a4e05994 100644 (file)
@@ -13,6 +13,10 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.IosXeRendererProvider;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache.EpPolicyCacheImpl;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.listener.EpPolicyTemplateBySgtListenerImpl;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.listener.RendererConfigurationListenerImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -23,26 +27,45 @@ public class IosXeRendererProviderImpl implements IosXeRendererProvider, Binding
 
     private static final Logger LOG = LoggerFactory.getLogger(IosXeRendererProviderImpl.class);
 
-    private final DataBroker dataBrokerDependency;
+    private final DataBroker dataBroker;
+    private final RendererName rendererName;
+    private RendererConfigurationListenerImpl rendererConfigurationListener;
+    private EpPolicyTemplateBySgtListenerImpl epPolicyTemplateBySgtListener;
+    private EpPolicyCacheImpl epPolicyCache;
 
-    public IosXeRendererProviderImpl(final DataBroker dataBrokerDependency, final BindingAwareBroker brokerDependency) {
+    public IosXeRendererProviderImpl(final DataBroker dataBroker, final BindingAwareBroker broker,
+                                     final RendererName rendererName) {
         LOG.debug("ios-xe renderer bootstrap");
-        this.dataBrokerDependency = Preconditions.checkNotNull(dataBrokerDependency, "missing dataBroker dependency");
-        brokerDependency.registerProvider(this);
+        this.dataBroker = Preconditions.checkNotNull(dataBroker, "missing dataBroker dependency");
+        this.rendererName = Preconditions.checkNotNull(rendererName, "missing rendererName param");
+        broker.registerProvider(this);
     }
 
     @Override
     public void close() {
         //TODO
         LOG.info("closing ios-xe renderer");
+        if (rendererConfigurationListener != null) {
+            rendererConfigurationListener.close();
+        }
+        if (epPolicyTemplateBySgtListener != null) {
+            epPolicyTemplateBySgtListener.close();
+        }
+        if (epPolicyCache != null) {
+            epPolicyCache.invalidateAll();
+        }
     }
 
     @Override
     public void onSessionInitiated(final BindingAwareBroker.ProviderContext providerContext) {
         LOG.info("starting ios-xe renderer");
         //TODO register listeners:
-        // renderer-configuration endpoints
         // ep-policy-template-by-sgt
+        epPolicyCache = new EpPolicyCacheImpl();
+        epPolicyTemplateBySgtListener = new EpPolicyTemplateBySgtListenerImpl(dataBroker, epPolicyCache);
+        // renderer-configuration endpoints
+        rendererConfigurationListener = new RendererConfigurationListenerImpl(dataBroker, rendererName, epPolicyCache);
         // supported node list maintenance
+        // TODO: upkeep of available renderer-nodes
     }
 }
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyCacheImpl.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyCacheImpl.java
new file mode 100644 (file)
index 0000000..8752c04
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache.DSTreeBasedCache;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+
+/**
+ * Purpose: cache for {@link EndpointPolicyTemplateBySgt}
+ */
+public class EpPolicyCacheImpl implements DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> {
+
+    private final ConcurrentMap<EpPolicyTemplateCacheKey, Sgt> cache;
+    private final EpPolicyTemplateCacheKeyFactory keyFactory;
+
+    public EpPolicyCacheImpl() {
+        cache = new ConcurrentHashMap<>();
+        keyFactory = new EpPolicyTemplateCacheKeyFactory(RendererPolicyUtil.createEndpointGroupIdOrdering(),
+                RendererPolicyUtil.createConditionNameOrdering());
+    }
+
+    @Override
+    public void invalidate(final EndpointPolicyTemplateBySgt exSource) {
+        cache.remove(keyFactory.createKey(exSource));
+    }
+
+    @Override
+    public void add(final EndpointPolicyTemplateBySgt newSource) {
+        final EpPolicyTemplateCacheKey key = keyFactory.createKey(newSource);
+        cache.put(key, newSource.getSgt());
+    }
+
+    @Override
+    public void update(final EndpointPolicyTemplateBySgt before, final EndpointPolicyTemplateBySgt after) {
+        cache.remove(keyFactory.createKey(before));
+        cache.put(keyFactory.createKey(after), after.getSgt());
+    }
+
+    @Override
+    public Sgt lookupValue(final EpPolicyTemplateCacheKey key) {
+        return cache.get(keyFactory.createKey(key));
+    }
+
+    @Override
+    public void invalidateAll() {
+        cache.clear();
+    }
+}
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyTemplateCacheKey.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyTemplateCacheKey.java
new file mode 100644 (file)
index 0000000..d9a18bb
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+
+/**
+ * Purpose: composite key holcer for {@link EndpointPolicyTemplateBySgt}
+ */
+public class EpPolicyTemplateCacheKey {
+
+    private final TenantId tenantId;
+    private final List<EndpointGroupId> epgId;
+    private final List<ConditionName> conditionName;
+
+    public EpPolicyTemplateCacheKey(final TenantId tenantId, final List<EndpointGroupId> epgId, final List<ConditionName> conditionName) {
+        this.tenantId = tenantId;
+        this.epgId = epgId;
+        this.conditionName = conditionName;
+    }
+
+    public EpPolicyTemplateCacheKey(AddressEndpointWithLocation endpoint) {
+        this(endpoint.getTenant(), endpoint.getEndpointGroup(), endpoint.getCondition());
+    }
+
+    public TenantId getTenantId() {
+        return tenantId;
+    }
+
+    public List<EndpointGroupId> getEpgId() {
+        return epgId;
+    }
+
+    public List<ConditionName> getConditionName() {
+        return conditionName;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final EpPolicyTemplateCacheKey that = (EpPolicyTemplateCacheKey) o;
+
+        if (tenantId != null ? !tenantId.equals(that.tenantId) : that.tenantId != null) return false;
+        if (epgId != null ? !epgId.equals(that.epgId) : that.epgId != null) return false;
+        return conditionName != null ? conditionName.equals(that.conditionName) : that.conditionName == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return tenantId != null ? tenantId.hashCode() : 0;
+    }
+}
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyTemplateCacheKeyFactory.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyTemplateCacheKeyFactory.java
new file mode 100644 (file)
index 0000000..2bffb36
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache;
+
+import com.google.common.collect.Ordering;
+import java.util.Collections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+
+/**
+ * Purpose: create cache keys with ordered lists inside
+ */
+public class EpPolicyTemplateCacheKeyFactory {
+    private final Ordering<EndpointGroupId> epgIdOrdering;
+    private final Ordering<ConditionName> conditionOrdering;
+
+    public EpPolicyTemplateCacheKeyFactory(final Ordering<EndpointGroupId> epgIdOrdering,
+                                           final Ordering<ConditionName> conditionOrdering) {
+        this.epgIdOrdering = epgIdOrdering;
+        this.conditionOrdering = conditionOrdering;
+    }
+
+    public EpPolicyTemplateCacheKey createKey(final EndpointPolicyTemplateBySgt newSource) {
+        Collections.sort(newSource.getEndpointGroups(), epgIdOrdering);
+        Collections.sort(newSource.getConditions(), conditionOrdering);
+
+        return new EpPolicyTemplateCacheKey(
+                newSource.getTenant(), newSource.getEndpointGroups(), newSource.getConditions());
+    }
+
+    public EpPolicyTemplateCacheKey createKey(final EpPolicyTemplateCacheKey existingKey) {
+        Collections.sort(existingKey.getEpgId(), epgIdOrdering);
+        Collections.sort(existingKey.getConditionName(), conditionOrdering);
+        return existingKey;
+    }
+}
index b49b0dc0f8e22af3b2d4435a74d3cc8c3330aa36..c65289202d64d429c43f6d6a213b5d5a2e1bcf0f 100644 (file)
@@ -26,7 +26,7 @@ public class IosXeProviderModule extends org.opendaylight.groupbasedpolicy.rende
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new IosXeRendererProviderImpl(getDataBrokerDependency(), getBrokerDependency());
+        return new IosXeRendererProviderImpl(getDataBrokerDependency(), getBrokerDependency(), getRendererName());
     }
 
 }
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/EpPolicyTemplateBySgtListenerImpl.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/EpPolicyTemplateBySgtListenerImpl.java
new file mode 100644 (file)
index 0000000..26aa107
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.listener;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache.DSTreeBasedCache;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache.EpPolicyTemplateCacheKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.SxpMapper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: listen to {@link EndpointPolicyTemplateBySgt} changes for caching purposes
+ */
+public class EpPolicyTemplateBySgtListenerImpl implements DataTreeChangeListener<EndpointPolicyTemplateBySgt>, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EpPolicyTemplateBySgtListenerImpl.class);
+
+    private final ListenerRegistration<EpPolicyTemplateBySgtListenerImpl> listenerRegistration;
+    private final DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> cache;
+
+    public EpPolicyTemplateBySgtListenerImpl(final DataBroker dataBroker,
+                                             final DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> cache) {
+        this.cache = Preconditions.checkNotNull(cache, "missing ep-policy-template cache");
+        final InstanceIdentifier<EndpointPolicyTemplateBySgt> templatePath = InstanceIdentifier.create(SxpMapper.class)
+                .child(EndpointPolicyTemplateBySgt.class);
+
+        final DataTreeIdentifier<EndpointPolicyTemplateBySgt> treePath = new DataTreeIdentifier<>(
+                LogicalDatastoreType.CONFIGURATION, templatePath);
+        listenerRegistration = dataBroker.registerDataTreeChangeListener(treePath, this);
+        LOG.info("ep-policy-template listener registered");
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<EndpointPolicyTemplateBySgt>> collection) {
+        LOG.debug("ep-policy-template changed");
+        for (DataTreeModification<EndpointPolicyTemplateBySgt> epPolicyTemplateModification : collection) {
+            final DataObjectModification<EndpointPolicyTemplateBySgt> rootNode = epPolicyTemplateModification
+                    .getRootNode();
+            final DataObjectModification.ModificationType modificationType = rootNode.getModificationType();
+            switch (modificationType) {
+                case DELETE:
+                    // invalidate cache
+                    cache.invalidate(rootNode.getDataBefore());
+                    break;
+                case WRITE:
+                    // extend cache
+                    cache.add(rootNode.getDataAfter());
+                    break;
+                case SUBTREE_MODIFIED:
+                    // update cache
+                    cache.update(rootNode.getDataBefore(), rootNode.getDataAfter());
+                    break;
+                default:
+                    LOG.warn("modification type not supported: {}", modificationType);
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        listenerRegistration.close();
+    }
+}
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/RendererConfigurationListenerImpl.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/RendererConfigurationListenerImpl.java
new file mode 100644 (file)
index 0000000..c5cc717
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.listener;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache.DSTreeBasedCache;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache.EpPolicyTemplateCacheKey;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: process changes of configured renderer policies
+ */
+public class RendererConfigurationListenerImpl implements DataTreeChangeListener<RendererPolicy>, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RendererConfigurationListenerImpl.class);
+    private final ListenerRegistration<RendererConfigurationListenerImpl> listenerRegistration;
+    private final DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> epPolicyCache;
+
+    public RendererConfigurationListenerImpl(final DataBroker dataBroker, final RendererName rendererName,
+                                             final DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> epPolicyCache) {
+        this.epPolicyCache = Preconditions.checkNotNull(epPolicyCache, "missing endpoint template cache");
+        final InstanceIdentifier<RendererPolicy> policyPath = InstanceIdentifier.create(Renderers.class)
+                .child(Renderer.class, new RendererKey(rendererName))
+                .child(RendererPolicy.class);
+
+        final DataTreeIdentifier<RendererPolicy> treePath = new DataTreeIdentifier<>(
+                LogicalDatastoreType.CONFIGURATION,
+                policyPath);
+        listenerRegistration = dataBroker.registerDataTreeChangeListener(treePath, this);
+        LOG.info("renderer-policy listener registered");
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<RendererPolicy>> collection) {
+        LOG.debug("renderer policy configuration changed");
+        for (DataTreeModification<RendererPolicy> rendererPolicyDataTreeModification : collection) {
+            final DataObjectModification<RendererPolicy> rootNode = rendererPolicyDataTreeModification.getRootNode();
+
+            final RendererPolicy dataAfter = rootNode.getDataAfter();
+            if (dataAfter != null && dataAfter.getConfiguration() != null) {
+                // find sgt
+                final Configuration configuration = dataAfter.getConfiguration();
+                for (RendererEndpoint rendererEndpoint : configuration.getRendererEndpoints().getRendererEndpoint()) {
+                    // lookup endpoints 1 source | * destination
+                    AddressEndpointWithLocation sourceEp = RendererPolicyUtil.lookupEndpoint(rendererEndpoint, configuration.getEndpoints().getAddressEndpointWithLocation());
+                    //resolve sgt
+                    final Sgt sourceSgt = epPolicyCache.lookupValue(new EpPolicyTemplateCacheKey(sourceEp));
+                    for (PeerEndpointWithPolicy peerEndpoint : rendererEndpoint.getPeerEndpointWithPolicy()) {
+                        AddressEndpointWithLocation destinationEp = RendererPolicyUtil.lookupEndpoint(peerEndpoint, configuration.getEndpoints().getAddressEndpointWithLocation());
+                        //resolve sgt
+                        final Sgt destinationSgt = epPolicyCache.lookupValue(new EpPolicyTemplateCacheKey(destinationEp));
+                        // invoke policy manager
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        listenerRegistration.close();
+    }
+}
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/AddressEndpointKeyEquivalence.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/AddressEndpointKeyEquivalence.java
new file mode 100644 (file)
index 0000000..e06c32a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
+
+import com.google.common.base.Equivalence;
+import com.google.common.base.Objects;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
+
+/**
+ * Purpose: hashCode and equals wrapper for any child of {@link AddressEndpointKey}
+ */
+public class AddressEndpointKeyEquivalence extends Equivalence<AddressEndpointKey> {
+
+    @Override
+    protected boolean doEquivalent(final AddressEndpointKey a, final AddressEndpointKey b) {
+        if (!Objects.equal(a.getContextType(), b.getContextType())) {
+            return false;
+        }
+        if (!Objects.equal(a.getAddressType(), b.getAddressType())) {
+            return false;
+        }
+        if (!Objects.equal(a.getAddress(), b.getAddress())) {
+            return false;
+        }
+        if (!Objects.equal(a.getContextId(), b.getContextId())) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    protected int doHash(final AddressEndpointKey addressEndpointKey) {
+        return Objects.hashCode(
+                addressEndpointKey.getAddress(),
+                addressEndpointKey.getAddressType(),
+                addressEndpointKey.getContextId(),
+                addressEndpointKey.getContextType());
+    }
+}
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/RendererPolicyUtil.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/RendererPolicyUtil.java
new file mode 100644 (file)
index 0000000..16f5fc2
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
+
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Ordering;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+
+/**
+ * Purpose: provide util methods handling {@link RendererPolicy}
+ */
+public final class RendererPolicyUtil {
+
+    private static final AddressEndpointKeyEquivalence ADDRESS_EP_KEY_EQUIVALENCE = new AddressEndpointKeyEquivalence();
+    private static final Comparable EMPTY_COMPARABLE = "";
+
+    private RendererPolicyUtil() {
+        throw new IllegalAccessError("Shall not instantiate util class.");
+    }
+
+
+    /**
+     * @param rendererEp                  lightweight endpoint key
+     * @param addressEndpointWithLocation collection of heavyweight endpoint definitions
+     * @return full address endpoint found by given key
+     */
+    public static AddressEndpointWithLocation lookupEndpoint(final AddressEndpointKey rendererEp, final List<AddressEndpointWithLocation> addressEndpointWithLocation) {
+        final Predicate<AddressEndpointKey> addressEndpointKeyPredicate = ADDRESS_EP_KEY_EQUIVALENCE.equivalentTo(rendererEp);
+        AddressEndpointWithLocation needle = null;
+
+        for (AddressEndpointWithLocation ep : addressEndpointWithLocation) {
+            if (addressEndpointKeyPredicate.apply(ep)) {
+                needle = ep;
+                break;
+            }
+        }
+        return needle;
+    }
+
+    public static Ordering<EndpointGroupId> createEndpointGroupIdOrdering() {
+        return Ordering.natural().onResultOf(new Function<EndpointGroupId, Comparable>() {
+            @Nullable
+            @Override
+            public Comparable apply(@Nullable final EndpointGroupId input) {
+                if (input == null) {
+                    return EMPTY_COMPARABLE;
+                }
+                return MoreObjects.firstNonNull(input.getValue(), EMPTY_COMPARABLE);
+            }
+        });
+    }
+
+    public static Ordering<ConditionName> createConditionNameOrdering() {
+        return Ordering.natural().onResultOf(new Function<ConditionName, Comparable>() {
+            @Nullable
+            @Override
+            public Comparable apply(@Nullable final ConditionName input) {
+                if (input == null) {
+                    return EMPTY_COMPARABLE;
+                }
+                return MoreObjects.firstNonNull(input.getValue(), EMPTY_COMPARABLE);
+            }
+        });
+    }
+}
index a02fc456d030c4d749923825feb14b3dfbfd524a..355ff11568c538318787a9978dda277d6916dc0d 100755 (executable)
@@ -13,9 +13,8 @@ module ios-xe-provider-impl {
 
     import config { prefix config; revision-date 2013-04-05; }
     import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
-    import ietf-yang-types { prefix "yang"; revision-date 2010-09-24; }
-    import opendaylight-sal-binding-broker-impl { prefix sal-broker; revision-date 2013-10-28;}
     import groupbasedpolicy-cfg { prefix gbpcfg; revision-date 2015-11-06; }
+    import renderer { prefix gbprenderer; revision-date 2015-11-03; }
 
     description
         "This module contains the base YANG definitions for
@@ -63,6 +62,10 @@ module ios-xe-provider-impl {
                     }
                 }
             }
+
+            leaf renderer-name {
+                type gbprenderer:renderer-name;
+            }
         }
     }
 }
diff --git a/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyCacheImplTest.java b/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/cache/EpPolicyCacheImplTest.java
new file mode 100644 (file)
index 0000000..6d700a9
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgtBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+
+/**
+ * Test for {@link EpPolicyCacheImpl}.
+ */
+public class EpPolicyCacheImplTest {
+
+    private static final int SGT1 = 1;
+    private static final int SGT2 = 2;
+    private static final String TENANT1 = "tenant1";
+    private static final String TENANT2 = "tenant2";
+
+    private static final EpPolicyTemplateCacheKey KEY_1 = createKey(TENANT1, new String[]{"n1", "n2"});
+    private static final EpPolicyTemplateCacheKey KEY_2 = createKey(TENANT2, new String[]{"n3"});
+
+    private static final EndpointPolicyTemplateBySgt TEMPLATE_1 = createTemplate(SGT1, TENANT1, new String[]{"n1", "n2"});
+    private static final EndpointPolicyTemplateBySgt TEMPLATE_2 = createTemplate(SGT2, TENANT2, new String[]{"n3"});
+
+    private EpPolicyCacheImpl cache;
+
+    @Before
+    public void setUp() throws Exception {
+        cache = new EpPolicyCacheImpl();
+    }
+
+    @Test
+    public void testInvalidate() throws Exception {
+        cache.add(TEMPLATE_1);
+        cache.add(TEMPLATE_2);
+
+        checkValuePresence(KEY_1, SGT1);
+
+        checkValuePresence(KEY_2, SGT2);
+
+        cache.invalidate(TEMPLATE_1);
+        Assert.assertNull(cache.lookupValue(KEY_1));
+        Assert.assertNotNull(cache.lookupValue(KEY_2));
+    }
+
+    @Test
+    public void testAdd() throws Exception {
+        cache.add(TEMPLATE_1);
+        checkValuePresence(KEY_1, SGT1);
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        cache.add(TEMPLATE_1);
+        checkValuePresence(KEY_1, SGT1);
+
+        cache.update(TEMPLATE_1, TEMPLATE_2);
+
+        Assert.assertNull(cache.lookupValue(KEY_1));
+        checkValuePresence(KEY_2, SGT2);
+    }
+
+    @Test
+    public void testLookupValue() throws Exception {
+        cache.add(TEMPLATE_1);
+        checkValuePresence(KEY_1, SGT1);
+    }
+
+    private void checkValuePresence(final EpPolicyTemplateCacheKey key, final int expectedSgt) {
+        final Sgt sgt = cache.lookupValue(key);
+        Assert.assertNotNull(sgt);
+        Assert.assertEquals(expectedSgt, sgt.getValue().intValue());
+    }
+
+    @Test
+    public void testLookupValue_withChangedOrder() throws Exception {
+        Assert.assertNull(cache.lookupValue(KEY_1));
+        cache.add(TEMPLATE_1);
+        checkValuePresence(KEY_1, SGT1);
+
+        final EpPolicyTemplateCacheKey twistedKey1 = createKey(TENANT1, new String[]{"n1", "n2"}, new String[]{"n2", "n1"});
+        checkValuePresence(twistedKey1, SGT1);
+
+        final EpPolicyTemplateCacheKey twistedKey2 = createKey(TENANT1, new String[]{"n2", "n1"}, new String[]{"n1", "n2"});
+        checkValuePresence(twistedKey2, SGT1);
+    }
+
+    @Test
+    public void testInvalidateAll() throws Exception {
+        cache.add(TEMPLATE_1);
+        cache.add(TEMPLATE_2);
+        checkValuePresence(KEY_1, SGT1);
+
+        cache.invalidateAll();
+        Assert.assertNull(cache.lookupValue(KEY_1));
+        Assert.assertNull(cache.lookupValue(KEY_2));
+    }
+
+    private static EndpointPolicyTemplateBySgt createTemplate(final int sgt, final String tenant, final String[] names) {
+        final List<ConditionName> conditions = buildConditions(names);
+        final List<EndpointGroupId> endpointGroupIds = buildEndpointGroupIds(names);
+
+        return new EndpointPolicyTemplateBySgtBuilder()
+                .setSgt(new Sgt(sgt))
+                .setTenant(new TenantId(tenant))
+                .setConditions(conditions)
+                .setEndpointGroups(endpointGroupIds)
+                .build();
+    }
+
+    private static List<EndpointGroupId> buildEndpointGroupIds(final String[] names) {
+        final List<EndpointGroupId> endpointGroupIds = new ArrayList<>();
+        for (String epgId : names) {
+            endpointGroupIds.add(new EndpointGroupId(epgId));
+        }
+        return endpointGroupIds;
+    }
+
+    private static List<ConditionName> buildConditions(final String[] names) {
+        final List<ConditionName> conditions = new ArrayList<>();
+        for (String condition : names) {
+            conditions.add(new ConditionName(condition));
+        }
+        return conditions;
+    }
+
+    private static EpPolicyTemplateCacheKey createKey(final String tenant, final String[] names) {
+        return createKey(tenant, names, names);
+    }
+
+    private static EpPolicyTemplateCacheKey createKey(final String tenant, final String[] epgIds, final String[] conditionNames) {
+        return new EpPolicyTemplateCacheKey(new AddressEndpointWithLocationBuilder()
+                .setTenant(new TenantId(tenant))
+                .setEndpointGroup(buildEndpointGroupIds(epgIds))
+                .setCondition(buildConditions(conditionNames))
+                .build());
+    }
+}
\ No newline at end of file
diff --git a/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/EpPolicyTemplateBySgtListenerImplTest.java b/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/EpPolicyTemplateBySgtListenerImplTest.java
new file mode 100644 (file)
index 0000000..6c6931a
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.listener;
+
+import com.google.common.collect.Lists;
+import java.util.Collections;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache.DSTreeBasedCache;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache.EpPolicyTemplateCacheKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgtBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * Test for {@link EpPolicyTemplateBySgtListenerImpl}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class EpPolicyTemplateBySgtListenerImplTest {
+
+    private static final Sgt SGT1 = new Sgt(1);
+    private static final TenantId TENANT1 = new TenantId("tenant1");
+    private static final TenantId TENANT2 = new TenantId("tenant2");
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> cache;
+    @Mock
+    private ListenerRegistration<EpPolicyTemplateBySgtListenerImpl> listenerRegistration;
+    @Mock
+    private DataTreeModification<EndpointPolicyTemplateBySgt> dataTreeModification;
+    @Mock
+    private DataObjectModification<EndpointPolicyTemplateBySgt> rootNode;
+
+    private final EndpointPolicyTemplateBySgt template1;
+    private final EndpointPolicyTemplateBySgt template2;
+
+    private EpPolicyTemplateBySgtListenerImpl listener;
+
+    public EpPolicyTemplateBySgtListenerImplTest() {
+        this.template1 = new EndpointPolicyTemplateBySgtBuilder()
+                .setSgt(SGT1)
+                .setTenant(TENANT1)
+                .setEndpointGroups(Lists.newArrayList(new EndpointGroupId("epg1"), new EndpointGroupId("epg2")))
+                .setConditions(Lists.newArrayList(new ConditionName("condition1"), new ConditionName("condition2")))
+                .build();
+
+        this.template2 = new EndpointPolicyTemplateBySgtBuilder()
+                .setSgt(SGT1)
+                .setTenant(TENANT2)
+                .setEndpointGroups(Lists.newArrayList(new EndpointGroupId("epg3"), new EndpointGroupId("epg4")))
+                .setConditions(Lists.newArrayList(new ConditionName("condition2"), new ConditionName("condition3")))
+                .build();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Mockito.when(dataBroker.registerDataTreeChangeListener(
+                Matchers.<DataTreeIdentifier<EndpointPolicyTemplateBySgt>>any(),
+                Matchers.<EpPolicyTemplateBySgtListenerImpl>any()))
+                .thenReturn(listenerRegistration);
+        listener = new EpPolicyTemplateBySgtListenerImpl(dataBroker, cache);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        Mockito.verifyNoMoreInteractions(cache);
+    }
+
+    @Test
+    public void testOnDataTreeChanged_add() throws Exception {
+        Mockito.when(rootNode.getDataAfter()).thenReturn(template1);
+        Mockito.when(rootNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
+        Mockito.when(dataTreeModification.getRootNode()).thenReturn(rootNode);
+
+        listener.onDataTreeChanged(Collections.singleton(dataTreeModification));
+        Mockito.verify(cache).add(template1);
+    }
+
+    @Test
+    public void testOnDataTreeChanged_remove() throws Exception {
+        Mockito.when(rootNode.getDataBefore()).thenReturn(template1);
+        Mockito.when(rootNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
+        Mockito.when(dataTreeModification.getRootNode()).thenReturn(rootNode);
+
+        listener.onDataTreeChanged(Collections.singleton(dataTreeModification));
+        Mockito.verify(cache).invalidate(template1);
+    }
+
+    @Test
+    public void testOnDataTreeChanged_update() throws Exception {
+        Mockito.when(rootNode.getDataBefore()).thenReturn(template1);
+        Mockito.when(rootNode.getDataAfter()).thenReturn(template2);
+        Mockito.when(rootNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
+        Mockito.when(dataTreeModification.getRootNode()).thenReturn(rootNode);
+
+        listener.onDataTreeChanged(Collections.singleton(dataTreeModification));
+        Mockito.verify(cache).update(template1, template2);
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        Mockito.verify(listenerRegistration, Mockito.never()).close();
+        listener.close();
+        Mockito.verify(listenerRegistration).close();
+        listener.close();
+        Mockito.verify(listenerRegistration, Mockito.times(2)).close();
+    }
+}
\ No newline at end of file
diff --git a/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/RendererConfigurationListenerImplTest.java b/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/listener/RendererConfigurationListenerImplTest.java
new file mode 100644 (file)
index 0000000..2bd9d7a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.listener;
+
+import java.util.Collections;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.cache.DSTreeBasedCache;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.cache.EpPolicyTemplateCacheKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * Test for {@link RendererConfigurationListenerImpl}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class RendererConfigurationListenerImplTest {
+
+    private static final RendererName RENDERER_NAME = new RendererName("renderer1");
+    private final RendererPolicy policy1;
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private DSTreeBasedCache<EndpointPolicyTemplateBySgt, EpPolicyTemplateCacheKey, Sgt> cache;
+    @Mock
+    private ListenerRegistration<RendererConfigurationListenerImpl> listenerRegistration;
+    @Mock
+    private DataTreeModification<RendererPolicy> dataTreeModification;
+    @Mock
+    private DataObjectModification<RendererPolicy> rootNode;
+
+    private RendererConfigurationListenerImpl listener;
+
+    public RendererConfigurationListenerImplTest() {
+        policy1 = new RendererPolicyBuilder().build();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Mockito.when(dataBroker.registerDataTreeChangeListener(
+                Matchers.<DataTreeIdentifier<RendererPolicy>>any(),
+                Matchers.<RendererConfigurationListenerImpl>any()))
+                .thenReturn(listenerRegistration);
+        listener = new RendererConfigurationListenerImpl(dataBroker, RENDERER_NAME, cache);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        Mockito.verifyNoMoreInteractions(listenerRegistration);
+    }
+
+    @Test
+    public void testOnDataTreeChanged_add() throws Exception {
+        Mockito.when(rootNode.getDataAfter()).thenReturn(policy1);
+        Mockito.when(rootNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
+        Mockito.when(dataTreeModification.getRootNode()).thenReturn(rootNode);
+
+        listener.onDataTreeChanged(Collections.singleton(dataTreeModification));
+        //TODO: verify on policy manager
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        Mockito.verify(listenerRegistration, Mockito.never()).close();
+        listener.close();
+        Mockito.verify(listenerRegistration).close();
+        listener.close();
+        Mockito.verify(listenerRegistration, Mockito.times(2)).close();
+    }
+}
\ No newline at end of file
diff --git a/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/RendererPolicyUtilTest.java b/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/RendererPolicyUtilTest.java
new file mode 100644 (file)
index 0000000..c4ead97
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.MacAddressType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationBuilder;
+
+/**
+ * Test for {@link RendererPolicyUtil}.
+ */
+public class RendererPolicyUtilTest {
+
+    @Test
+    public void testLookupEndpoint() throws Exception {
+        final AddressEndpointKey key1 = new AddressEndpointBuilder()
+                .setAddress("address1")
+                .setAddressType(IpPrefixType.class)
+                .setContextId(new ContextId("context1"))
+                .setContextType(L3Context.class)
+                .build();
+
+        final AddressEndpointWithLocation addressEPWithLocation1 =
+                createAddressEPWithLocation("address1", IpPrefixType.class, "context1", L3Context.class);
+        final AddressEndpointWithLocation addressEPWithLocation2 =
+                createAddressEPWithLocation("address2", IpPrefixType.class, "context1", L3Context.class);
+        final AddressEndpointWithLocation addressEPWithLocation3 =
+                createAddressEPWithLocation("address1", MacAddressType.class, "context1", L3Context.class);
+        final AddressEndpointWithLocation addressEPWithLocation4 =
+                createAddressEPWithLocation("address1", IpPrefixType.class, "context2", L3Context.class);
+        final AddressEndpointWithLocation addressEPWithLocation5 =
+                createAddressEPWithLocation("address1", IpPrefixType.class, "context1", L2BridgeDomain.class);
+
+        final List<AddressEndpointWithLocation> endpoints = Lists.newArrayList(
+                addressEPWithLocation2, addressEPWithLocation3,
+                addressEPWithLocation4, addressEPWithLocation5,
+                addressEPWithLocation1
+                );
+
+        final AddressEndpointWithLocation actualEndpoint = RendererPolicyUtil.lookupEndpoint(key1, endpoints);
+        Assert.assertSame(addressEPWithLocation1, actualEndpoint);
+    }
+
+    @Test
+    public void testCreateEndpointGroupIdOrdering() throws Exception {
+        final Ordering<EndpointGroupId> endpointGroupIdOrdering = RendererPolicyUtil.createEndpointGroupIdOrdering();
+        final String epg1 = "epg1";
+        final ArrayList<EndpointGroupId> list = Lists.newArrayList(
+                new EndpointGroupId("epg3"), new EndpointGroupId(epg1), new EndpointGroupId("epg2"));
+
+        Collections.sort(list, endpointGroupIdOrdering);
+        Assert.assertEquals(epg1, list.get(0).getValue());
+
+        Collections.sort(list, endpointGroupIdOrdering.reversed());
+        Assert.assertEquals(epg1, list.get(2).getValue());
+    }
+
+    @Test
+    public void testCreateConditionNameOrdering() throws Exception {
+        final Ordering<ConditionName> conditionNameOrdering = RendererPolicyUtil.createConditionNameOrdering();
+        final String name1 = "name1";
+        final ArrayList<ConditionName> list = Lists.newArrayList(
+                new ConditionName("name3"), new ConditionName(name1), new ConditionName("name2"));
+
+        Collections.sort(list, conditionNameOrdering);
+        Assert.assertEquals(name1, list.get(0).getValue());
+
+        Collections.sort(list, conditionNameOrdering.reversed());
+        Assert.assertEquals(name1, list.get(2).getValue());
+    }
+
+    private AddressEndpointWithLocation createAddressEPWithLocation(final String address,
+                                                                    final Class<? extends AddressType> addressType,
+                                                                    final String context,
+                                                                    final Class<? extends ContextType> contextType) {
+        return new AddressEndpointWithLocationBuilder()
+                .setAddress(address)
+                .setAddressType(addressType)
+                .setContextId(new ContextId(context))
+                .setContextType(contextType)
+                .build();
+    }
+}
\ No newline at end of file