NeLocationProvider 07/37607/14
authorMatej Perina <matej.perina@pantheon.sk>
Thu, 12 May 2016 08:39:50 +0000 (10:39 +0200)
committerMatej Perina <matej.perina@pantheon.sk>
Thu, 12 May 2016 08:39:50 +0000 (10:39 +0200)
Change-Id: I903687c182265592e2f3b904e804655128793c1c
Signed-off-by: Matej Perina <matej.perina@pantheon.sk>
21 files changed:
artifacts/pom.xml
features/pom.xml
features/src/main/features/features.xml
groupbasedpolicy/pom.xml
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/NetUtils.java [new file with mode: 0644]
groupbasedpolicy/src/main/yang/model/base-endpoint.yang
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/util/IidFactoryTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/util/NetUtilsTest.java [new file with mode: 0644]
location-providers/ne-location-provider/pom.xml [new file with mode: 0644]
location-providers/ne-location-provider/src/main/config/default-config.xml [new file with mode: 0644]
location-providers/ne-location-provider/src/main/java/org/opendaylight/controller/config/yang/config/ne/location/provider/cfg/NeLocationProviderModule.java [new file with mode: 0644]
location-providers/ne-location-provider/src/main/java/org/opendaylight/controller/config/yang/config/ne/location/provider/cfg/NeLocationProviderModuleFactory.java [new file with mode: 0644]
location-providers/ne-location-provider/src/main/java/org/opendaylight/groupbasedpolicy/ne/location/provider/EndpointsListener.java [new file with mode: 0644]
location-providers/ne-location-provider/src/main/java/org/opendaylight/groupbasedpolicy/ne/location/provider/NeLocationProvider.java [new file with mode: 0644]
location-providers/ne-location-provider/src/main/yang/ne-location-provider-cfg.yang [new file with mode: 0644]
location-providers/ne-location-provider/src/main/yang/network-elements.yang [new file with mode: 0644]
location-providers/ne-location-provider/src/test/java/org/opendaylight/groupbasedpolicy/ne/location/provider/EndpointsListenerTest.java [new file with mode: 0644]
location-providers/ne-location-provider/src/test/java/org/opendaylight/groupbasedpolicy/ne/location/provider/NeLocationProviderTest.java [new file with mode: 0644]
location-providers/pom.xml [new file with mode: 0644]
pom.xml

index a023995e393f7860363c26e5f08013f4a60f8c23..6eef12e7d57f9a857be7a7712d898a4a080f9c61 100755 (executable)
         <artifactId>ovssfc-renderer</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>ne-location-provider</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>${project.groupId}</groupId>
         <artifactId>neutron-mapper</artifactId>
         <type>xml</type>
         <classifier>config</classifier>
       </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>ne-location-provider</artifactId>
+        <version>${project.version}</version>
+        <type>xml</type>
+        <classifier>config</classifier>
+      </dependency>
       <dependency>
         <groupId>${project.groupId}</groupId>
         <artifactId>neutron-mapper</artifactId>
index d13c8c1b8c5ad7801ebc58de1528c9fbeb62749c..12389e640a9e14ba6f234e7a1af232b88e6a44df 100755 (executable)
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>iovisor-renderer</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>ne-location-provider</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>neutron-mapper</artifactId>
       <type>xml</type>
       <classifier>config</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>ne-location-provider</artifactId>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>neutron-mapper</artifactId>
index 52907b6609b55c86b602b9ca659c66bbf3798dfa..218acd53b8ccb9257c50f93c7818972a9fd3c158 100755 (executable)
@@ -39,6 +39,7 @@
         <feature version="${controller.mdsal.version}">odl-mdsal-broker</feature>
         <feature version='${mdsal.version}'>odl-mdsal-binding-base</feature>
         <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
+        <bundle>mvn:commons-net/commons-net/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy/{{VERSION}}</bundle>
         <configfile finalname="${config.configfile.directory}/15-groupbasedpolicy-base.xml">mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy/{{VERSION}}/xml/config</configfile>
     </feature>
         <bundle>mvn:org.opendaylight.groupbasedpolicy/sxp-mapper/{{VERSION}}</bundle>
         <configfile finalname="${config.configfile.directory}/15-groupbasedpolicy-sxp-mapper.xml">mvn:org.opendaylight.groupbasedpolicy/sxp-mapper/{{VERSION}}/xml/config</configfile>
     </feature>
+
+    <!--
+         NE Location Provider
+    -->
+    <feature name='odl-groupbasedpolicy-ne-location-provider' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: NE location provider'>
+        <feature version="${project.version}">odl-groupbasedpolicy-base</feature>
+        <bundle>mvn:org.opendaylight.groupbasedpolicy/ne-location-provider/{{VERSION}}</bundle>
+        <configfile finalname="${config.configfile.directory}/15-ne-location-provider.xml">mvn:org.opendaylight.groupbasedpolicy/ne-location-provider/{{VERSION}}/xml/config</configfile>
+    </feature>
 </features>
index 258fb435bf6e152937fb36f898754d47d7c53dfe..d4db9198546f631fea2bbb3dbaef3207abe43a19 100755 (executable)
       <groupId>org.opendaylight.mdsal.model</groupId>
       <artifactId>yang-ext</artifactId>
     </dependency>
+    <!-- net utils dependencies -->
+    <dependency>
+      <groupId>com.googlecode.java-ipv6</groupId>
+      <artifactId>java-ipv6</artifactId>
+      <version>0.16</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
+    </dependency>
     <!-- testing dependencies -->
     <dependency>
       <groupId>junit</groupId>
@@ -76,6 +86,7 @@
               org.opendaylight.groupbasedpolicy.dto,
               org.opendaylight.groupbasedpolicy.util,
             </Export-Package>
+            <Embed-Dependency>java-ipv6</Embed-Dependency>
           </instructions>
         </configuration>
       </plugin>
index 7cb3f3be39602370d1a3e99900e61e50a3e1f458..2116d12e1cc838a1f5871b85e630fd7b62c3a503 100644 (file)
@@ -13,6 +13,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.ContainmentEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
@@ -20,6 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
@@ -37,8 +40,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.ProviderName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProviderKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
+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.policy.rev140421.SubjectFeatureDefinitions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
@@ -97,6 +106,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecord;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecordKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 
 public class IidFactory {
 
@@ -383,4 +393,11 @@ public class IidFactory {
             .build();
     }
 
+    public static InstanceIdentifierBuilder<ProviderAddressEndpointLocation> providerAddressEndpointLocationIid(String provider,
+            Class<? extends AddressType> addrType, String addr, Class<? extends ContextType> cType,
+            ContextId containment) {
+        return InstanceIdentifier.builder(LocationProviders.class)
+                .child(LocationProvider.class, new LocationProviderKey(new ProviderName(provider)))
+            .child(ProviderAddressEndpointLocation.class, new ProviderAddressEndpointLocationKey(addr, addrType, containment, cType));
+    }
 }
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/NetUtils.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/NetUtils.java
new file mode 100644 (file)
index 0000000..a650f11
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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.util;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+
+import com.google.common.base.Strings;
+import com.googlecode.ipv6.IPv6NetworkMask;
+
+public final class NetUtils {
+
+    /**
+     * Extract prefix length from prefix form
+     * Works for both IPv4 and IPv6
+     *
+     * @param prefix {@code String} to extract prefix length from
+     * @return prefix length as {@code int}
+     */
+    public static int getMaskFromPrefix(@Nullable String prefix) {
+        String newPrefix = Strings.nullToEmpty(prefix);
+        int slashIndex = newPrefix.indexOf("/");
+        if (slashIndex == -1) {
+            slashIndex = newPrefix.length() - 1;
+        }
+        return Integer.parseInt(newPrefix.substring(slashIndex + 1));
+    }
+
+    /**
+     * Extract IP adress from prefix form
+     * Works for both IPv4 and IPv6
+     *
+     * @param prefix {@code String} to extract IP address from
+     * @return IP address as a {@code String}
+     */
+    public static @Nonnull String getIpAddrFromPrefix(@Nullable String prefix) {
+        String newPrefix = Strings.nullToEmpty(prefix);
+        int slashIndex = newPrefix.indexOf("/");
+        if (slashIndex == -1) {
+            slashIndex = newPrefix.length();
+        }
+        return newPrefix.substring(0, slashIndex);
+    }
+
+    /**
+     * Mask IPv6 address from prefix with provided prefix length
+     *
+     * @param ipv6Prefix {@link Ipv6Prefix} to apply mask on
+     * @param ipv6MaskLength prefix length
+     * @return resulting network IP address as {@link Ipv6Address}
+     */
+    public static @Nullable Ipv6Address applyMaskOnIpv6Prefix(@Nullable Ipv6Prefix ipv6Prefix, int ipv6MaskLength) {
+        if (ipv6Prefix == null) {
+            return null;
+        }
+        return applyMaskOnIpv6Address(new Ipv6Address(getIpAddrFromPrefix(ipv6Prefix.getValue())), ipv6MaskLength);
+    }
+
+    /**
+     * Mask IPv6 address with provided prefix length
+     *
+     * @param ipv6Address {@link Ipv6Prefix} to apply mask on
+     * @param ipv6MaskLength prefix length
+     * @return resulting network address as {@link Ipv6Address}, {@code null} if provided address is null
+     */
+    public static @Nullable Ipv6Address applyMaskOnIpv6Address(@Nullable Ipv6Address ipv6Address, int ipv6MaskLength) {
+        if (ipv6Address == null) {
+            return null;
+        }
+        com.googlecode.ipv6.IPv6Address ip = com.googlecode.ipv6.IPv6Address.fromString(ipv6Address.getValue());
+        IPv6NetworkMask mask = IPv6NetworkMask.fromPrefixLength(ipv6MaskLength);
+        ip = ip.maskWithNetworkMask(mask);
+        return new Ipv6Address(ip.toString());
+    }
+
+    /**
+     * Check if two IpPrefixes represents same network. Must be identical in network address and prefix length.
+     * Works for both IPv4 and IPv6
+     *
+     * @param prefix1 {@link IpPrefix} to compare
+     * @param prefix2 {@link IpPrefix} to compare
+     * @return {@code true} if provided prefixes are identical, otherwise return {@code false}
+     */
+    public static boolean samePrefix(@Nullable IpPrefix prefix1, @Nullable IpPrefix prefix2) {
+        if (prefix1 == null || prefix2 == null) {
+            return false;
+        }
+        if (prefix1.getIpv4Prefix() != null && prefix2.getIpv4Prefix() != null) {
+            SubnetUtils fromPrefix1 = new SubnetUtils(prefix1.getIpv4Prefix().getValue());
+            SubnetUtils fromPrefix2 = new SubnetUtils(prefix2.getIpv4Prefix().getValue());
+            if (fromPrefix1.getInfo().isInRange(fromPrefix2.getInfo().getHighAddress())
+                    && fromPrefix2.getInfo().isInRange(fromPrefix1.getInfo().getHighAddress())) {
+                return true;
+            }
+        } else if (prefix1.getIpv6Prefix() != null && prefix2.getIpv6Prefix() != null) {
+            int ipv6MaskLength1 = getMaskFromPrefix(prefix1.getIpv6Prefix().getValue());
+            int ipv6MaskLength2 = getMaskFromPrefix(prefix2.getIpv6Prefix().getValue());
+            if (ipv6MaskLength1 != ipv6MaskLength2) {
+                return false;
+            }
+            Ipv6Address ipv6Network = applyMaskOnIpv6Prefix(prefix1.getIpv6Prefix(), ipv6MaskLength1);
+            Ipv6Address hostv6Network = applyMaskOnIpv6Prefix(prefix2.getIpv6Prefix(), ipv6MaskLength1);
+            if (ipv6Network.getValue().equals(hostv6Network.getValue())) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
index b297b0e97414f4961d27eb09839aae16d6c7468b..dbecfb9a1a7991b65ba667051be4529c699dc829 100644 (file)
@@ -144,10 +144,10 @@ module base-endpoint {
     grouping has-location {
         container real-location {
             choice location-type {
-                case regular-location {
+                case regular-location-case {
                     uses has-regular-location;
                 }
-                case external-location {
+                case external-location-case {
                     uses has-external-location;
                 }
             }
index 1479001d31ba4de73b25c6fab4d701e3e53bd3e4..30222acf0b8dfcf0199a342e64e7ab4eb769c22d 100755 (executable)
@@ -16,11 +16,14 @@ import org.junit.Test;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
@@ -36,6 +39,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
@@ -65,6 +71,11 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class IidFactoryTest {
 
+    private final String LOCATION_PROVIDER_NAME = "location-provider";
+    private final String IP_ADDRESS = "192.68.50.71";
+    private final String IP_PREFIX = "192.168.50.0/24";
+    private final String L3_CONTEXT_ID = "l3Context";
+
     private TenantId tenantId;
     private EndpointGroupId epgId;
     private ContractId contractId;
@@ -329,4 +340,32 @@ public class IidFactoryTest {
         Assert.assertEquals(epgId, identifier.firstKeyOf(ExternalImplicitGroup.class).getId());
     }
 
+    @Test
+    public void testProviderAddressEndpointLocationIid() {
+        ContextId l3Context = new ContextId(L3_CONTEXT_ID);
+        InstanceIdentifier<ProviderAddressEndpointLocation> identifier = IidFactory
+            .providerAddressEndpointLocationIid(LOCATION_PROVIDER_NAME, IpPrefixType.class, IP_ADDRESS,
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context.class,
+                    l3Context)
+            .build();
+        Assert.assertEquals(LOCATION_PROVIDER_NAME,
+                identifier.firstKeyOf(LocationProvider.class).getProvider().getValue());
+        Assert.assertEquals(IP_ADDRESS, identifier.firstKeyOf(ProviderAddressEndpointLocation.class).getAddress());
+        Assert.assertEquals(l3Context, identifier.firstKeyOf(ProviderAddressEndpointLocation.class).getContextId());
+    }
+
+    @Test
+    public void testAddressEndpointIid() {
+        ContextId l3Context = new ContextId(L3_CONTEXT_ID);
+        InstanceIdentifier<AddressEndpoint> identifier =
+                IidFactory.addressEndpointIid(new AddressEndpointKey(IP_ADDRESS, IpPrefixType.class, new ContextId(l3Context),
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context.class
+                        ));
+        Assert.assertEquals(IpPrefixType.class, identifier.firstKeyOf(AddressEndpoint.class).getAddressType());
+        Assert.assertEquals(IP_ADDRESS, identifier.firstKeyOf(AddressEndpoint.class).getAddress());
+        Assert.assertEquals(
+                org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context.class,
+                identifier.firstKeyOf(AddressEndpoint.class).getContextType());
+        Assert.assertEquals(l3Context, identifier.firstKeyOf(AddressEndpoint.class).getContextId());
+    }
 }
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/util/NetUtilsTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/util/NetUtilsTest.java
new file mode 100644 (file)
index 0000000..6bc60e2
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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.util;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+
+public class NetUtilsTest {
+
+    private final String IPV4_ADDRESS_1 = "192.168.50.20";
+    private final String IPV4_ADDRESS_2 = "10.0.0.1";
+    private final String IPV6_HOST_ADDRESS = "DEAD:BEEF::1";
+    private final String IPV6_NETWORK_ADDRESS_1 = "DEAD:BEEF::";
+    private final String IPV6_NETWORK_ADDRESS_2 = "DEAF:BABE::";
+    private final String MASK_16 = "/16";
+    private final String MASK_24 = "/24";
+    private final String MASK_32 = "/32";
+    private final String MASK_64 = "/64";
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void testGetMaskFromPrefix_FromNull () {
+        thrown.expect(NumberFormatException.class);
+        NetUtils.getMaskFromPrefix(null);
+    }
+
+    @Test
+    public void testGetMaskFromPrefix_StringWithouPrefix () {
+        thrown.expect(NumberFormatException.class);
+        NetUtils.getMaskFromPrefix(IPV4_ADDRESS_1);
+    }
+
+    @Test
+    public void testGetMaskFromPrefix_Correct () {
+        int result = NetUtils.getMaskFromPrefix(IPV4_ADDRESS_1 + MASK_24);
+        Assert.assertEquals(24, result);
+    }
+
+    @Test
+    public void testGetIpAddrFromPrefix_FromNull () {
+        String result = NetUtils.getIpAddrFromPrefix(null);
+        Assert.assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testGetIpAddrFromPrefix_StringWithouPrefixLength () {
+        String result = NetUtils.getIpAddrFromPrefix(IPV4_ADDRESS_1);
+        Assert.assertEquals(IPV4_ADDRESS_1, result);
+    }
+
+    @Test
+    public void testGetIpAddrFromPrefix_Ipv4Prefix () {
+        String result = NetUtils.getIpAddrFromPrefix(IPV4_ADDRESS_1 + MASK_24);
+        Assert.assertEquals(IPV4_ADDRESS_1, result);
+    }
+
+    @Test
+    public void testGetIpAddrFromPrefix_Ipv6Prefix () {
+        String result = NetUtils.getIpAddrFromPrefix(IPV6_HOST_ADDRESS + MASK_64);
+        Assert.assertEquals(IPV6_HOST_ADDRESS, result);
+    }
+
+    @Test
+    public void testApplyMaskOnIpv6Prefix_NullPrefix () {
+        Ipv6Address result = NetUtils.applyMaskOnIpv6Prefix(null, 0);
+        Assert.assertNull(result);
+    }
+
+    @Test
+    public void testApplyMaskOnIpv6Prefix_PrefixLengthOutOfRange () {
+        Ipv6Prefix prefix = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_64);
+        thrown.expect(IllegalArgumentException.class);
+        NetUtils.applyMaskOnIpv6Prefix(prefix, 130);
+    }
+
+    @Test
+    public void testApplyMaskOnIpv6Prefix_Correct () {
+        Ipv6Prefix prefix = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_64);
+        Ipv6Address result = NetUtils.applyMaskOnIpv6Prefix(prefix, 64);
+        Assert.assertTrue(IPV6_NETWORK_ADDRESS_1.equalsIgnoreCase(result.getValue()));
+    }
+
+    @Test
+    public void testApplyMaskOnIpv6Address_NullAddress () {
+        Ipv6Address result = NetUtils.applyMaskOnIpv6Address(null, 0);
+        Assert.assertNull(result);
+    }
+
+    @Test
+    public void testApplyMaskOnIpv6Address_PrefixLengthOutOfRange () {
+        Ipv6Address prefix = new Ipv6Address(IPV6_HOST_ADDRESS);
+        thrown.expect(IllegalArgumentException.class);
+        NetUtils.applyMaskOnIpv6Address(prefix, 130);
+    }
+
+    @Test
+    public void testApplyMaskOnIpv6Address_Correct () {
+        Ipv6Address prefix = new Ipv6Address(IPV6_HOST_ADDRESS);
+        Ipv6Address result = NetUtils.applyMaskOnIpv6Address(prefix, 64);
+        Assert.assertTrue(IPV6_NETWORK_ADDRESS_1.equalsIgnoreCase(result.getValue()));
+    }
+
+    @Test
+    public void testSamePrefix_NullInput () {
+        Ipv4Prefix prefix = new Ipv4Prefix(IPV4_ADDRESS_1 + MASK_24);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix), null);
+        Assert.assertFalse(result);
+        result = NetUtils.samePrefix(null, new IpPrefix(prefix));
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv6AndIpv4 () {
+        Ipv4Prefix prefix4 = new Ipv4Prefix(IPV4_ADDRESS_1 + MASK_24);
+        Ipv6Prefix prefix6 = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_64);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix4), new IpPrefix(prefix6));
+        Assert.assertFalse(result);
+        result = NetUtils.samePrefix(new IpPrefix(prefix6), new IpPrefix(prefix4));
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv4DifferentNetwork () {
+        Ipv4Prefix prefix1 = new Ipv4Prefix(IPV4_ADDRESS_1 + MASK_24);
+        Ipv4Prefix prefix2 = new Ipv4Prefix(IPV4_ADDRESS_2 + MASK_24);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix1), new IpPrefix(prefix2));
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv6DifferentNetwork () {
+        Ipv6Prefix prefix1 = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_64);
+        Ipv6Prefix prefix2 = new Ipv6Prefix(IPV6_NETWORK_ADDRESS_2 + MASK_64);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix1), new IpPrefix(prefix2));
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv4DifferentPrefix () {
+        Ipv4Prefix prefix1 = new Ipv4Prefix(IPV4_ADDRESS_1 + MASK_24);
+        Ipv4Prefix prefix2 = new Ipv4Prefix(IPV4_ADDRESS_1 + MASK_16);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix1), new IpPrefix(prefix2));
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv6DifferentPrefix () {
+        Ipv6Prefix prefix1 = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_64);
+        Ipv6Prefix prefix2 = new Ipv6Prefix(IPV6_NETWORK_ADDRESS_2 + MASK_32);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix1), new IpPrefix(prefix2));
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv4SamePrefix () {
+        Ipv6Prefix prefix = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_24);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix), new IpPrefix(prefix));
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testSamePrefix_Ipv6SamePrefix () {
+        Ipv6Prefix prefix = new Ipv6Prefix(IPV6_HOST_ADDRESS + MASK_64);
+        boolean result = NetUtils.samePrefix(new IpPrefix(prefix), new IpPrefix(prefix));
+        Assert.assertTrue(result);
+    }
+}
\ No newline at end of file
diff --git a/location-providers/ne-location-provider/pom.xml b/location-providers/ne-location-provider/pom.xml
new file mode 100644 (file)
index 0000000..befc7a1
--- /dev/null
@@ -0,0 +1,73 @@
+<?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>groupbasedpolicy-location-providers</artifactId>
+    <version>0.4.0-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+
+  <artifactId>ne-location-provider</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.groupbasedpolicy</groupId>
+      <artifactId>groupbasedpolicy</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <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.controller.model</groupId>
+        <artifactId>model-inventory</artifactId>
+        <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <!-- project build -->
+  <build>
+    <!-- We use the maven-resources-plugin to copy a class from the groupbasepolicy
+      bundle that we need in order to run some unit tests in the renderer (classes
+      in the test directory aren't packaged in bundles, and instead of keeping
+      separate copies, we just copy the file(s) needed in order to run the test). -->
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ne.location.provider.rev160421.*
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/location-providers/ne-location-provider/src/main/config/default-config.xml b/location-providers/ne-location-provider/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..82b8b4b
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 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
+-->
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:ne-location="urn:opendaylight:params:xml:ns:yang:controller:config:ne:location:provider:cfg">
+                        ne-location:ne-location-provider
+                    </type>
+                    <name>ne-location-provider</name>
+
+                    <data-broker>
+                      <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+                      <name>binding-data-broker</name>
+                    </data-broker>
+                </module>
+            </modules>
+        </data>
+
+    </configuration>
+
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:ne:location:provider:cfg?module=ne-location-provider-cfg&amp;revision=2016-04-21</capability>
+    </required-capabilities>
+
+</snapshot>
diff --git a/location-providers/ne-location-provider/src/main/java/org/opendaylight/controller/config/yang/config/ne/location/provider/cfg/NeLocationProviderModule.java b/location-providers/ne-location-provider/src/main/java/org/opendaylight/controller/config/yang/config/ne/location/provider/cfg/NeLocationProviderModule.java
new file mode 100644 (file)
index 0000000..44b1643
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.controller.config.yang.config.ne.location.provider.cfg;
+
+import org.opendaylight.groupbasedpolicy.ne.location.provider.NeLocationProvider;
+
+public class NeLocationProviderModule extends org.opendaylight.controller.config.yang.config.ne.location.provider.cfg.AbstractNeLocationProviderModule {
+    public NeLocationProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NeLocationProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.ne.location.provider.cfg.NeLocationProviderModule 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() {
+        return new NeLocationProvider(getDataBrokerDependency());
+    }
+
+}
diff --git a/location-providers/ne-location-provider/src/main/java/org/opendaylight/controller/config/yang/config/ne/location/provider/cfg/NeLocationProviderModuleFactory.java b/location-providers/ne-location-provider/src/main/java/org/opendaylight/controller/config/yang/config/ne/location/provider/cfg/NeLocationProviderModuleFactory.java
new file mode 100644 (file)
index 0000000..89479de
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * 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.controller.config.yang.config.ne.location.provider.cfg;
+public class NeLocationProviderModuleFactory extends org.opendaylight.controller.config.yang.config.ne.location.provider.cfg.AbstractNeLocationProviderModuleFactory {
+
+}
diff --git a/location-providers/ne-location-provider/src/main/java/org/opendaylight/groupbasedpolicy/ne/location/provider/EndpointsListener.java b/location-providers/ne-location-provider/src/main/java/org/opendaylight/groupbasedpolicy/ne/location/provider/EndpointsListener.java
new file mode 100644 (file)
index 0000000..21feda6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.ne.location.provider;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EndpointsListener implements DataTreeChangeListener<AddressEndpoint>{
+
+    private static final Logger LOG = LoggerFactory.getLogger(EndpointsListener.class);
+
+    private NeLocationProvider listener;
+    private ListenerRegistration<EndpointsListener> listenerRegistration;
+
+    public EndpointsListener (DataBroker dataBroker, NeLocationProvider listener) {
+        this.listener = listener;
+        this.listenerRegistration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.builder(Endpoints.class)
+                .child(AddressEndpoints.class).child(AddressEndpoint.class).build()), this);
+        LOG.info("NE location provider registered for Endpoints listening");
+    }
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<AddressEndpoint>> changes) {
+        listener.onEndpointsChange(changes);
+    }
+
+    public void close() {
+        this.listenerRegistration.close();
+    }
+}
diff --git a/location-providers/ne-location-provider/src/main/java/org/opendaylight/groupbasedpolicy/ne/location/provider/NeLocationProvider.java b/location-providers/ne-location-provider/src/main/java/org/opendaylight/groupbasedpolicy/ne/location/provider/NeLocationProvider.java
new file mode 100644 (file)
index 0000000..a25469f
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * 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.ne.location.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+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.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.util.NetUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.location.RealLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.location.RealLocationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.location.real.location.location.type.RegularLocationCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElements;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElementsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.NetworkElement;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element._interface.EndpointNetwork;
+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.L3Context;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+
+public class NeLocationProvider implements DataTreeChangeListener<NetworkElements>, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeLocationProvider.class);
+    public static final String NE_LOCATION_PROVIDER_NAME = "ne-location-provider";
+
+    private List<AddressEndpoint> endpoints;
+    private NetworkElements networkElements;
+    private DataBroker dataBroker;
+    private ListenerRegistration<NeLocationProvider> listenerRegistration;
+    private EndpointsListener endpointsListener;
+
+    public NeLocationProvider(DataBroker dataBroker) {
+        this.listenerRegistration =
+                dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.builder(NetworkElements.class).build()), this);
+        this.endpoints = new ArrayList<>();
+        this.networkElements = new NetworkElementsBuilder().build();
+        this.dataBroker = dataBroker;
+        this.endpointsListener = new EndpointsListener(dataBroker, this);
+        LOG.info("NE location provider created");
+    }
+
+    @Override
+    public void close() {
+        this.listenerRegistration.close();
+        this.endpointsListener.close();
+    }
+
+    public synchronized void onEndpointsChange(Collection<DataTreeModification<AddressEndpoint>> changes) {
+        for (DataTreeModification<AddressEndpoint> change : changes) {
+            switch (change.getRootNode().getModificationType()) {
+                case DELETE: {
+                    AddressEndpoint endpoint = change.getRootNode().getDataBefore();
+                    removeLocationForEndpoint(endpoint);
+                    this.endpoints.remove(endpoint);
+                    break;
+                }
+                case WRITE: {
+                    AddressEndpoint endpoint = change.getRootNode().getDataBefore();
+                    if (endpoint != null) {
+                        this.endpoints.remove(endpoint);
+                        this.endpoints.add(change.getRootNode().getDataAfter());
+                        break;
+                    }
+                    endpoint = change.getRootNode().getDataAfter();
+                    createLocationForEndpoint(endpoint);
+                    this.endpoints.add(endpoint);
+                    break;
+                }
+                case SUBTREE_MODIFIED: {
+                    this.endpoints.remove(change.getRootNode().getDataBefore());
+                    this.endpoints.add(change.getRootNode().getDataAfter());
+                    break;
+                }
+            }
+        }
+    }
+
+    private void createLocationForEndpoint(AddressEndpoint endpoint) {
+        for (NetworkElement ne : nullToEmpty(networkElements.getNetworkElement())) {
+            for (Interface iface : nullToEmpty(ne.getInterface())) {
+                for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                    if (endpoint.getContextType().isAssignableFrom(L3Context.class)
+                            && endpoint.getContextId().equals(en.getL3ContextId())
+                            && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class) && NetUtils
+                                .samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
+                        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+                        InstanceIdentifier<RealLocation> iid = IidFactory
+                            .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
+                                    endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
+                            .child(RealLocation.class)
+                            .build();
+                        wtx.put(LogicalDatastoreType.OPERATIONAL, iid, createRealLocation(ne.getIid(), iface.getIid()),
+                                true);
+                        wtx.submit();
+                        LOG.debug("New location created for endpoint {}", endpoint);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    private void removeLocationForEndpoint(AddressEndpoint endpoint) {
+        for (NetworkElement ne : nullToEmpty(networkElements.getNetworkElement())) {
+            for (Interface iface : nullToEmpty(ne.getInterface())) {
+                for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                    if (endpoint.getContextType().isAssignableFrom(L3Context.class)
+                            && endpoint.getContextId().equals(en.getL3ContextId())
+                            && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class) && NetUtils
+                                .samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
+                        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+                        InstanceIdentifier<RealLocation> iid = IidFactory
+                            .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
+                                    endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
+                            .child(RealLocation.class)
+                            .build();
+                        wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
+                        wtx.submit();
+                        LOG.debug("Location deleted for endpoint {}", endpoint);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public synchronized void onDataTreeChanged(Collection<DataTreeModification<NetworkElements>> changes) {
+        for (DataTreeModification<NetworkElements> change : changes) {
+            switch (change.getRootNode().getModificationType()) {
+                case DELETE: {
+                    NetworkElements nes = change.getRootNode().getDataBefore();
+                    for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
+                        for (Interface iface : nullToEmpty(ne.getInterface())) {
+                            for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                                processDeletedEN(en, ne.getIid(), iface.getIid());
+                            }
+                        }
+                    }
+                    networkElements = new NetworkElementsBuilder().build();
+                    LOG.debug("Network elements removed");
+                    break;
+                }
+                case WRITE: {
+                    NetworkElements nes = change.getRootNode().getDataBefore();
+                    if (nes != null) {
+                        for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
+                            for (Interface iface : nullToEmpty(ne.getInterface())) {
+                                for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                                    processDeletedEN(en, ne.getIid(), iface.getIid());
+                                }
+                            }
+                        }
+                    }
+                    nes = change.getRootNode().getDataAfter();
+                    for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
+                        for (Interface iface : nullToEmpty(ne.getInterface())) {
+                            for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                                processCreatedEN(en, ne.getIid(), iface.getIid());
+                            }
+                        }
+                    }
+                    networkElements = nes;
+                    LOG.debug("New Network elements created {}", change.getRootNode().getDataAfter());
+                    break;
+                }
+                case SUBTREE_MODIFIED: {
+                    List<DataObjectModification<NetworkElement>> modifiedNetworkElements =
+                            getModifiedNetworkElements(change.getRootNode());
+                    for (DataObjectModification<NetworkElement> netElement : modifiedNetworkElements) {
+                        processNetworkElementChange(netElement);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    private List<DataObjectModification<NetworkElement>> getModifiedNetworkElements(
+            DataObjectModification<NetworkElements> modifiedNEs) {
+        Collection<DataObjectModification<? extends DataObject>> potentialModifiedNetworkElements =
+                modifiedNEs.getModifiedChildren();
+        if (potentialModifiedNetworkElements == null) {
+            return Collections.emptyList();
+        }
+        List<DataObjectModification<NetworkElement>> nes = new ArrayList<>();
+        for (DataObjectModification<? extends DataObject> potentialModifiedNetworkElement : potentialModifiedNetworkElements) {
+            if (potentialModifiedNetworkElement.getDataType().isAssignableFrom(NetworkElement.class)) {
+                nes.add((DataObjectModification<NetworkElement>) potentialModifiedNetworkElement);
+            }
+        }
+        return nes;
+    }
+
+    private void processNetworkElementChange(DataObjectModification<NetworkElement> netElement) {
+        switch (netElement.getModificationType()) {
+            case DELETE: {
+                NetworkElement ne = netElement.getDataBefore();
+                for (Interface iface : nullToEmpty(ne.getInterface())) {
+                    for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                        processDeletedEN(en, ne.getIid(), iface.getIid());
+                    }
+                }
+                networkElements.getNetworkElement().remove(ne);
+                LOG.debug("Netowrk element {} removed", netElement.getDataBefore());
+                break;
+            }
+            case WRITE: {
+                NetworkElement ne = netElement.getDataBefore();
+                if (ne != null) {
+                    for (Interface iface : nullToEmpty(ne.getInterface())) {
+                        for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                            processDeletedEN(en, ne.getIid(), iface.getIid());
+                        }
+                    }
+                    networkElements.getNetworkElement().remove(ne);
+                }
+                ne = netElement.getDataAfter();
+                for (Interface iface : nullToEmpty(ne.getInterface())) {
+                    for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                        processCreatedEN(en, ne.getIid(), iface.getIid());
+                    }
+                }
+                networkElements.getNetworkElement().add(ne);
+                LOG.debug("Created new Network element {}", netElement.getDataAfter());
+                break;
+            }
+            case SUBTREE_MODIFIED: {
+                List<DataObjectModification<Interface>> modifiedInterfaces = getModifiedInterfaces(netElement);
+                for (DataObjectModification<Interface> modifiedInterface : modifiedInterfaces) {
+                    processInterfaceChange(modifiedInterface, netElement.getDataBefore());
+                }
+                break;
+            }
+        }
+    }
+
+    private List<DataObjectModification<Interface>> getModifiedInterfaces(
+            DataObjectModification<NetworkElement> netElement) {
+        Collection<DataObjectModification<? extends DataObject>> potentialModifiedInterfaces =
+                netElement.getModifiedChildren();
+        if (potentialModifiedInterfaces == null) {
+            return Collections.emptyList();
+        }
+        List<DataObjectModification<Interface>> interfaces = new ArrayList<>();
+        for (DataObjectModification<? extends DataObject> potentialModifiedInterface : potentialModifiedInterfaces) {
+            if (potentialModifiedInterface.getDataType().isAssignableFrom(Interface.class)) {
+                interfaces.add((DataObjectModification<Interface>) potentialModifiedInterface);
+            }
+        }
+        return interfaces;
+    }
+
+    private void processInterfaceChange(DataObjectModification<Interface> modifiedInterface,
+            NetworkElement nodeBefore) {
+        switch (modifiedInterface.getModificationType()) {
+            case DELETE: {
+                Interface iface = modifiedInterface.getDataBefore();
+                for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                    processDeletedEN(en, nodeBefore.getIid(), iface.getIid());
+                }
+                int nodeIndex = getIndexOf(nodeBefore);
+                networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
+                LOG.debug("Interface {} removed", modifiedInterface.getDataBefore());
+                break;
+            }
+            case WRITE: {
+                Interface iface = modifiedInterface.getDataBefore();
+                int nodeIndex = getIndexOf(nodeBefore);
+                if (iface != null) {
+                    for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                        processDeletedEN(en, nodeBefore.getIid(), iface.getIid());
+                    }
+                    networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
+                }
+                iface = modifiedInterface.getDataAfter();
+                for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
+                    processCreatedEN(en, nodeBefore.getIid(), iface.getIid());
+                }
+                networkElements.getNetworkElement().get(nodeIndex).getInterface().add(iface);
+                LOG.debug("Created new Interface {}", modifiedInterface.getDataAfter());
+                break;
+            }
+            case SUBTREE_MODIFIED: {
+                List<DataObjectModification<EndpointNetwork>> modifiedENs =
+                        getModifiedEndpointNetworks(modifiedInterface);
+                for (DataObjectModification<EndpointNetwork> modifiedEN : modifiedENs) {
+                    processEndpointNetworkChange(modifiedEN, nodeBefore, modifiedInterface.getDataBefore());
+                }
+                break;
+            }
+        }
+    }
+
+    private List<DataObjectModification<EndpointNetwork>> getModifiedEndpointNetworks(
+            DataObjectModification<Interface> modifiedInterface) {
+        Collection<DataObjectModification<? extends DataObject>> potentialModifiedEPs =
+                modifiedInterface.getModifiedChildren();
+        if (potentialModifiedEPs == null) {
+            return Collections.emptyList();
+        }
+        List<DataObjectModification<EndpointNetwork>> eps = new ArrayList<>();
+        for (DataObjectModification<? extends DataObject> potentialModifiedEP : potentialModifiedEPs) {
+            if (potentialModifiedEP.getDataType().isAssignableFrom(EndpointNetwork.class)) {
+                eps.add((DataObjectModification<EndpointNetwork>) potentialModifiedEP);
+            }
+        }
+        return eps;
+    }
+
+    private void processEndpointNetworkChange(DataObjectModification<EndpointNetwork> modifiedEN,
+            NetworkElement nodeBefore, Interface ifaceBefore) {
+        switch (modifiedEN.getModificationType()) {
+            case DELETE: {
+                processDeletedEN(modifiedEN.getDataBefore(), nodeBefore.getIid(), ifaceBefore.getIid());
+                int nodeIndex = getIndexOf(nodeBefore);
+                int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
+                networkElements.getNetworkElement()
+                    .get(nodeIndex)
+                    .getInterface()
+                    .get(ifaceIndex)
+                    .getEndpointNetwork()
+                    .remove(modifiedEN.getDataBefore());
+                LOG.debug("Endpoint network {} removed", modifiedEN.getDataBefore());
+                break;
+            }
+            case WRITE: {
+                processCreatedEN(modifiedEN.getDataAfter(), nodeBefore.getIid(), ifaceBefore.getIid());
+                int nodeIndex = getIndexOf(nodeBefore);
+                int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
+                networkElements.getNetworkElement()
+                    .get(nodeIndex)
+                    .getInterface()
+                    .get(ifaceIndex)
+                    .getEndpointNetwork()
+                    .add(modifiedEN.getDataAfter());
+                LOG.debug("Created new Endpoint network {}", modifiedEN.getDataAfter());
+                break;
+            }
+            case SUBTREE_MODIFIED: {
+                LOG.debug("EndpointNetwork {} changed", modifiedEN.getDataAfter().getKey());
+                break;
+            }
+        }
+    }
+
+    private void processCreatedEN(EndpointNetwork en, InstanceIdentifier<?> nodeIID,
+            InstanceIdentifier<?> connectorIID) {
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        for (AddressEndpoint endpoint : endpoints) {
+            if (endpoint.getContextType().isAssignableFrom(L3Context.class)
+                    && endpoint.getContextId().equals(en.getL3ContextId())
+                    && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
+                    && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
+                InstanceIdentifier<RealLocation> iid = IidFactory
+                    .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
+                            endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
+                    .child(RealLocation.class)
+                    .build();
+                wtx.put(LogicalDatastoreType.OPERATIONAL, iid, createRealLocation(nodeIID, connectorIID), true);
+                wtx.submit();
+                LOG.debug("New location created for endpoint {}", endpoint);
+                return;
+            }
+        }
+    }
+
+    private void processDeletedEN(EndpointNetwork en, InstanceIdentifier<?> nodeIID,
+            InstanceIdentifier<?> connectorIID) {
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        for (AddressEndpoint endpoint : endpoints) {
+            if (endpoint.getContextType().isAssignableFrom(L3Context.class)
+                    && endpoint.getContextId().equals(en.getL3ContextId())
+                    && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
+                    && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
+                InstanceIdentifier<RealLocation> iid = IidFactory
+                    .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
+                            endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
+                    .child(RealLocation.class)
+                    .build();
+                wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
+                wtx.submit();
+                LOG.debug("Location deleted for endpoint {}", endpoint);
+                return;
+            }
+        }
+    }
+
+    private RealLocation createRealLocation(InstanceIdentifier<?> node, InstanceIdentifier<?> iface) {
+        return new RealLocationBuilder()
+            .setLocationType(new RegularLocationCaseBuilder().setNode(node).setNodeConnector(iface).build()).build();
+    }
+
+    private <T> List<T> nullToEmpty(@Nullable List<T> list) {
+        return list == null ? Collections.emptyList() : list;
+    }
+
+    private int getIndexOf(NetworkElement ne) {
+        for (NetworkElement listNE : networkElements.getNetworkElement()) {
+            if (ne.getIid().equals(listNE.getIid())) {
+                return networkElements.getNetworkElement().indexOf(listNE);
+            }
+        }
+        return -1;
+    }
+
+    private int getIndexOf(Interface iface, int nodeIndex) {
+        for (Interface listIface : networkElements.getNetworkElement().get(nodeIndex).getInterface()) {
+            if (iface.getIid().equals(listIface.getIid())) {
+                return networkElements.getNetworkElement().get(nodeIndex).getInterface().indexOf(listIface);
+            }
+        }
+        return -1;
+    }
+
+    @VisibleForTesting
+    synchronized List<AddressEndpoint> getEndpoints() {
+        return endpoints;
+    }
+
+    @VisibleForTesting
+    synchronized NetworkElements getNetworkElements() {
+        return networkElements;
+    }
+}
diff --git a/location-providers/ne-location-provider/src/main/yang/ne-location-provider-cfg.yang b/location-providers/ne-location-provider/src/main/yang/ne-location-provider-cfg.yang
new file mode 100644 (file)
index 0000000..8a58eda
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+module ne-location-provider-cfg {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:ne:location:provider:cfg";
+    prefix "ne-location-provider-cfg";
+
+    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
+          ne location provider implementation.";
+
+    revision "2016-04-21" {
+        description
+            "Initial revision.";
+    }
+
+    identity ne-location-provider {
+        base "config:module-type";
+
+        config:java-name-prefix NeLocationProvider;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+    augment "/config:modules/config:module/config:configuration" {
+        case ne-location-provider {
+            when "/config:modules/config:module/config:type = 'ne-location-provider'";
+
+            // Wires in the data-broker service
+            container data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-async-data-broker;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/location-providers/ne-location-provider/src/main/yang/network-elements.yang b/location-providers/ne-location-provider/src/main/yang/network-elements.yang
new file mode 100644 (file)
index 0000000..c0b3a51
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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
+ */
+
+ module network-elements {
+     yang-version 1;
+
+     namespace "urn:opendaylight:groupbasedpolicy:endpoint:network:elements";
+     prefix "network-elements";
+
+     import gbp-common {
+         prefix gbp-common;
+         revision-date 2014-04-21;
+     }
+
+     import ietf-inet-types {
+         prefix inet;
+         revision-date 2010-09-24;
+     }
+
+     description
+         "This module defines network element structure for location provider.";
+
+     revision "2016-04-07" {
+         description
+             "Initial revision.";
+     }
+
+     container network-elements {
+         list network-element {
+             key iid;
+             leaf iid {
+                 description "Path to the network element
+                     represented in topology of southbound plugin.";
+                 type instance-identifier;
+             }
+             list interface {
+                 key "iid";
+                 leaf iid {
+                     description "Path to the interface
+                         represented in topology of southbound plugin.
+                         This should be more like RelativeSchemaPath
+                         from network-element's IID to interface.";
+                     type instance-identifier;
+                 }
+                 list endpoint-network {
+                     description "Set of networks somewhere behind the interface.
+                         Networks where an endpoint can be connected.";
+                     key "l3-context-id ip-prefix";
+                     leaf l3-context-id {
+                         type gbp-common:context-id;
+                     }
+                     leaf ip-prefix {
+                         type inet:ip-prefix;
+                         description
+                             "The IP prefix where an endpoint can be connected.";
+                     }
+                 }
+             }
+         }
+     }
+
+}
\ No newline at end of file
diff --git a/location-providers/ne-location-provider/src/test/java/org/opendaylight/groupbasedpolicy/ne/location/provider/EndpointsListenerTest.java b/location-providers/ne-location-provider/src/test/java/org/opendaylight/groupbasedpolicy/ne/location/provider/EndpointsListenerTest.java
new file mode 100644 (file)
index 0000000..bb90273
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.ne.location.provider;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class EndpointsListenerTest {
+
+    private EndpointsListener endpointsListener;
+    private NeLocationProvider listener;
+    private DataBroker dataBroker;
+    private ListenerRegistration<EndpointsListener> listenerRegistration;
+
+    @Before
+    public void init () {
+        dataBroker = mock(DataBroker.class);
+        listenerRegistration = mock(ListenerRegistration.class);
+        when(dataBroker.registerDataTreeChangeListener(any(), Matchers.any(EndpointsListener.class)))
+        .thenReturn(listenerRegistration);
+        listener = mock(NeLocationProvider.class);
+        endpointsListener = new EndpointsListener(dataBroker, listener);
+    }
+
+    @Test
+    public void test_RegistrationDone () {
+        verify(dataBroker).registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.builder(Endpoints.class).child(AddressEndpoints.class)
+                .child(AddressEndpoint.class).build()), endpointsListener);
+    }
+
+    @Test
+    public void test_ListenerNotification () {
+        endpointsListener.onDataTreeChanged(null);
+        verify(listener).onEndpointsChange(any());
+    }
+
+    @Test
+    public void test_UnregiserOnClose () {
+        endpointsListener.close();
+        verify(listenerRegistration).close();
+    }
+}
diff --git a/location-providers/ne-location-provider/src/test/java/org/opendaylight/groupbasedpolicy/ne/location/provider/NeLocationProviderTest.java b/location-providers/ne-location-provider/src/test/java/org/opendaylight/groupbasedpolicy/ne/location/provider/NeLocationProviderTest.java
new file mode 100644 (file)
index 0000000..fc32605
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * 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.ne.location.provider;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest;
+import org.opendaylight.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.EndpointLocations;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
+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.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElements;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElementsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.NetworkElement;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.NetworkElementBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.NetworkElementKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element._interface.EndpointNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element._interface.EndpointNetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element._interface.EndpointNetworkKey;
+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.L3Context;
+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.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.CheckedFuture;
+
+public class NeLocationProviderTest extends CustomDataBrokerTest {
+
+    private DataBroker dataBroker;
+    private NeLocationProvider neProvider;
+    private String L3_CONTEXT_ID = "l3Context";
+    private String IPv4_HOST_ADDRESS_1 = "192.168.50.71";
+    private String IPv4_HOST_ADDRESS_2 = "192.168.50.72";
+    private String IPv4_NETWORK_ADDRESS_1 = "192.168.50.0/24";
+    private String IPv4_NETWORK_ADDRESS_2 = "192.168.51.0/24";
+    private String NODE_ID_1 = "node1";
+    private String NODE_ID_2 = "node2";
+    private String CONNECTOR_ID_1 = "connector:1";
+    private String CONNECTOR_ID_2 = "connector:2";
+
+    @Override
+    public Collection<Class<?>> getClassesFromModules() {
+        return ImmutableList.<Class<?>>of(NetworkElements.class, EndpointLocations.class, Endpoints.class, L3Context.class, Nodes.class);
+    }
+
+    @Before
+    public void init() {
+        dataBroker = getDataBroker();
+        neProvider = new NeLocationProvider(dataBroker);
+    }
+
+    @Test
+    public void test_NetworkElementsListenerRegistration() {
+        DataBroker dataBroker = mock(DataBroker.class);
+        NeLocationProvider provider = new NeLocationProvider(dataBroker);
+        verify(dataBroker).registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.builder(NetworkElements.class).build()), provider);
+    }
+
+    @Test
+    public void test_EndpointsListenerRegistration() {
+        DataBroker dataBroker = mock(DataBroker.class);
+        new NeLocationProvider(dataBroker);
+        verify(dataBroker)
+            .registerDataTreeChangeListener(eq(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.builder(Endpoints.class).child(AddressEndpoints.class)
+                    .child(AddressEndpoint.class).build())), isA(EndpointsListener.class));
+    }
+
+    @Test
+    public void test_ListenersUnregistration() {
+        DataBroker dataBroker = mock(DataBroker.class);
+        ListenerRegistration<EndpointsListener> endpointsListenerRegistration = mock(ListenerRegistration.class);
+        when(dataBroker.registerDataTreeChangeListener(any(), isA(EndpointsListener.class)))
+            .thenReturn(endpointsListenerRegistration);
+        ListenerRegistration<NeLocationProvider> NEListenerRegistration = mock(ListenerRegistration.class);
+        when(dataBroker.registerDataTreeChangeListener(any(), isA(NeLocationProvider.class)))
+            .thenReturn(NEListenerRegistration);
+        NeLocationProvider provider = new NeLocationProvider(dataBroker);
+        provider.close();
+        verify(endpointsListenerRegistration).close();
+        verify(NEListenerRegistration).close();
+    }
+
+    @Test
+    public void test_AddressEndpointWrite_NoNE_NoOverwrite() throws Exception {
+        AddressEndpoint endpoint =
+                createAddressEndpoint(IPv4_HOST_ADDRESS_1, IpPrefixType.class, L3_CONTEXT_ID, L3Context.class);
+        InstanceIdentifier<AddressEndpoint> iid = IidFactory.addressEndpointIid(endpoint.getKey());
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.put(LogicalDatastoreType.OPERATIONAL, iid, endpoint, true);
+        wtx.submit().get();
+        List<AddressEndpoint> endpoints = neProvider.getEndpoints();
+        assertEquals(1, endpoints.size());
+        assertEquals(endpoint, endpoints.get(0));
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_AddressEndpointWrite_NoNE_Overwrite() throws Exception {
+        test_AddressEndpointWrite_NoNE_NoOverwrite();
+        NetworkContainment nc = new NetworkContainmentBuilder()
+                .setNetworkDomainId(new NetworkDomainId(L3_CONTEXT_ID))
+                .build();
+        InstanceIdentifier<NetworkContainment> iid = InstanceIdentifier
+                .builder(Endpoints.class)
+                .child(AddressEndpoints.class)
+                .child(AddressEndpoint.class, new AddressEndpointKey(IPv4_HOST_ADDRESS_1, IpPrefixType.class,
+                        new ContextId(L3_CONTEXT_ID), L3Context.class))
+                .child(NetworkContainment.class)
+                .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.put(LogicalDatastoreType.OPERATIONAL, iid, nc);
+        wtx.submit().get();
+        List<AddressEndpoint> l3Endpoint = neProvider.getEndpoints();
+        assertEquals(1, l3Endpoint.size());
+        assertNotNull(l3Endpoint.get(0).getNetworkContainment());
+        assertEquals(nc, l3Endpoint.get(0).getNetworkContainment());
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_EndpointsDelete_NoNE() throws Exception {
+        test_AddressEndpointWrite_NoNE_NoOverwrite();
+        InstanceIdentifier<Endpoints> iid = InstanceIdentifier.builder(Endpoints.class)
+                .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
+        wtx.submit().get();
+        List<AddressEndpoint> l3Endpoint = neProvider.getEndpoints();
+        assertEquals(0, l3Endpoint.size());
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_EndpointsModify_NoNE() throws Exception {
+        test_AddressEndpointWrite_NoNE_NoOverwrite();
+        InstanceIdentifier<Endpoints> iid = InstanceIdentifier.builder(Endpoints.class)
+                .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
+        wtx.submit().get();
+        List<AddressEndpoint> l3Endpoint = neProvider.getEndpoints();
+        assertEquals(0, l3Endpoint.size());
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_NetworkElementsWrite_NoEP_NoOverwrite() throws Exception {
+        NetworkElements nes = createNetworkElements(NODE_ID_1, CONNECTOR_ID_1, L3_CONTEXT_ID, IPv4_NETWORK_ADDRESS_1);
+        InstanceIdentifier<NetworkElements> iid = InstanceIdentifier.builder(NetworkElements.class).build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.put(LogicalDatastoreType.CONFIGURATION, iid, nes);
+        wtx.submit().get();
+        NetworkElements networkElements = neProvider.getNetworkElements();
+        assertEquals(nes, networkElements);
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_NetworkElementsWrite_NoEP_Overwrite() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        NetworkElements nes = createNetworkElements(NODE_ID_2, CONNECTOR_ID_2, L3_CONTEXT_ID, IPv4_NETWORK_ADDRESS_1);
+        InstanceIdentifier<NetworkElements> iid = InstanceIdentifier.builder(NetworkElements.class).build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.put(LogicalDatastoreType.CONFIGURATION, iid, nes);
+        wtx.submit().get();
+        NetworkElements networkElements = neProvider.getNetworkElements();
+        assertEquals(nes, networkElements);
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_NetworkElementWrite_NoEP_Overwrite() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        NetworkElement ne = createNetworkElement(NODE_ID_1, CONNECTOR_ID_1, L3_CONTEXT_ID, IPv4_NETWORK_ADDRESS_2);
+        InstanceIdentifier<NetworkElement> iid = InstanceIdentifier.builder(NetworkElements.class)
+            .child(NetworkElement.class, new NetworkElementKey(ne.getKey()))
+            .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.put(LogicalDatastoreType.CONFIGURATION, iid, ne);
+        wtx.submit().get();
+        NetworkElements nes = neProvider.getNetworkElements();
+        assertNotNull(nes.getNetworkElement());
+        assertEquals(1, nes.getNetworkElement().size());
+        assertEquals(ne, nes.getNetworkElement().get(0));
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_InterfaceWrite_NoEP_Overwrite() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        Interface iface = createInterface(NODE_ID_1, CONNECTOR_ID_1, L3_CONTEXT_ID, IPv4_NETWORK_ADDRESS_2);
+        InstanceIdentifier<Interface> iid = InstanceIdentifier.builder(NetworkElements.class)
+            .child(NetworkElement.class, new NetworkElementKey(createNetworkElementIid(NODE_ID_1)))
+            .child(Interface.class, new InterfaceKey(iface.getKey()))
+            .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.put(LogicalDatastoreType.CONFIGURATION, iid, iface);
+        wtx.submit().get();
+        NetworkElements nes = neProvider.getNetworkElements();
+        assertNotNull(nes.getNetworkElement());
+        assertEquals(1, nes.getNetworkElement().size());
+        assertNotNull(nes.getNetworkElement().get(0).getInterface());
+        assertEquals(1, nes.getNetworkElement().get(0).getInterface().size());
+        assertEquals(iface, nes.getNetworkElement().get(0).getInterface().get(0));
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_EndpointNetworkChange_NoEP() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        EndpointNetwork en = createEndpointNetwork(L3_CONTEXT_ID, IPv4_NETWORK_ADDRESS_2);
+        InstanceIdentifier<EndpointNetwork> iid = InstanceIdentifier.builder(NetworkElements.class)
+            .child(NetworkElement.class, new NetworkElementKey(createNetworkElementIid(NODE_ID_1)))
+            .child(Interface.class, new InterfaceKey(createInterfaceIid(NODE_ID_1, CONNECTOR_ID_1)))
+            .child(EndpointNetwork.class, new EndpointNetworkKey(en.getKey()))
+            .build();
+        InstanceIdentifier<EndpointNetwork> removeIid =
+                InstanceIdentifier.builder(NetworkElements.class)
+                    .child(NetworkElement.class, new NetworkElementKey(createNetworkElementIid(NODE_ID_1)))
+                    .child(Interface.class, new InterfaceKey(createInterfaceIid(NODE_ID_1, CONNECTOR_ID_1)))
+                    .child(EndpointNetwork.class, new EndpointNetworkKey(
+                            new IpPrefix(new Ipv4Prefix(IPv4_NETWORK_ADDRESS_1)),new ContextId(L3_CONTEXT_ID)))
+                    .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.delete(LogicalDatastoreType.CONFIGURATION, removeIid);
+        wtx.put(LogicalDatastoreType.CONFIGURATION, iid, en);
+        wtx.submit().get();
+        NetworkElements nes = neProvider.getNetworkElements();
+        assertNotNull(nes.getNetworkElement());
+        assertEquals(1, nes.getNetworkElement().size());
+        assertNotNull(nes.getNetworkElement().get(0).getInterface());
+        assertEquals(1, nes.getNetworkElement().get(0).getInterface().size());
+        assertNotNull(nes.getNetworkElement().get(0).getInterface().get(0).getEndpointNetwork());
+        assertEquals(1, nes.getNetworkElement().get(0).getInterface().get(0).getEndpointNetwork().size());
+        assertEquals(en, nes.getNetworkElement().get(0).getInterface().get(0).getEndpointNetwork().get(0));
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_NetworkElementsDelete() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        InstanceIdentifier<NetworkElements> iid = InstanceIdentifier.builder(NetworkElements.class).build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        wtx.submit().get();
+        NetworkElements nes = neProvider.getNetworkElements();
+        assertEquals(new NetworkElementsBuilder().build(), nes);
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_NetworkElementDelete() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        InstanceIdentifier<NetworkElement> iid = InstanceIdentifier.builder(NetworkElements.class)
+            .child(NetworkElement.class, new NetworkElementKey(createNetworkElementIid(NODE_ID_1)))
+            .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        wtx.submit().get();
+        NetworkElements nes = neProvider.getNetworkElements();
+        assertNotNull(nes.getNetworkElement());
+        assertTrue(nes.getNetworkElement().isEmpty());
+        verifyEmptyLocations();
+    }
+
+    @Test
+    public void test_InterfaceDelete() throws Exception {
+        test_NetworkElementsWrite_NoEP_NoOverwrite();
+        InstanceIdentifier<Interface> iid = InstanceIdentifier.builder(NetworkElements.class)
+            .child(NetworkElement.class, new NetworkElementKey(createNetworkElementIid(NODE_ID_1)))
+            .child(Interface.class, new InterfaceKey(createInterfaceIid(NODE_ID_1, CONNECTOR_ID_1)))
+            .build();
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        wtx.submit().get();
+        NetworkElements nes = neProvider.getNetworkElements();
+        assertNotNull(nes.getNetworkElement());
+        assertEquals(1, nes.getNetworkElement().size());
+        assertNotNull(nes.getNetworkElement().get(0).getInterface());
+        assertTrue(nes.getNetworkElement().get(0).getInterface().isEmpty());
+        verifyEmptyLocations();
+    }
+
+    private AddressEndpoint createAddressEndpoint(String ipAddr, Class<? extends AddressType> addrType,
+            String context, Class<? extends ContextType> cType) {
+        return new AddressEndpointBuilder().setAddress(ipAddr).setAddressType(addrType)
+                .setContextId(new ContextId(context)).setContextType(cType).build();
+    }
+
+    private NetworkElements createNetworkElements(String node, String iface, String l3c, String prefix) {
+        return new NetworkElementsBuilder()
+            .setNetworkElement(Collections.singletonList(createNetworkElement(node, iface, l3c, prefix))).build();
+    }
+
+    private NetworkElement createNetworkElement(String node, String iface, String l3c, String prefix) {
+        return new NetworkElementBuilder().setIid(createNetworkElementIid(node))
+            .setInterface(Collections.singletonList(createInterface(node, iface, l3c, prefix)))
+            .build();
+    }
+
+    private Interface createInterface(String node, String iface, String l3c, String prefix) {
+        return new InterfaceBuilder().setIid(createInterfaceIid(node, iface))
+            .setEndpointNetwork(Collections.singletonList(createEndpointNetwork(l3c, prefix)))
+            .build();
+    }
+
+    private EndpointNetwork createEndpointNetwork(String l3c, String prefix) {
+        return new EndpointNetworkBuilder().setIpPrefix(new IpPrefix(new Ipv4Prefix(prefix)))
+            .setL3ContextId(new ContextId(l3c))
+            .build();
+    }
+
+    private InstanceIdentifier<?> createNetworkElementIid(String node) {
+        return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId(node))).build();
+    }
+
+    private InstanceIdentifier<?> createInterfaceIid(String node, String connector) {
+        return InstanceIdentifier.builder(Nodes.class)
+            .child(Node.class, new NodeKey(new NodeId(node)))
+            .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(connector)))
+            .build();
+    }
+
+    private void verifyEmptyLocations() throws Exception {
+        ReadOnlyTransaction rtx = dataBroker.newReadOnlyTransaction();
+        InstanceIdentifier<EndpointLocations> locationIid = InstanceIdentifier.builder(EndpointLocations.class).build();
+        CheckedFuture<Optional<EndpointLocations>, ReadFailedException> read =
+                rtx.read(LogicalDatastoreType.OPERATIONAL, locationIid);
+        assertFalse(read.get().isPresent());
+        rtx.close();
+    }
+}
diff --git a/location-providers/pom.xml b/location-providers/pom.xml
new file mode 100644 (file)
index 0000000..68c5aab
--- /dev/null
@@ -0,0 +1,33 @@
+<?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.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.groupbasedpolicy</groupId>
+  <artifactId>groupbasedpolicy-location-providers</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>ne-location-provider</module>
+  </modules>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>groupbasedpolicy</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/pom.xml b/pom.xml
index fbecf22f650302028dc4e18256329f5926314709..257a4c8d5b6ca5864c80229d6e83a2a9033ffbc2 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -19,6 +19,7 @@
     <module>artifacts</module>
     <module>groupbasedpolicy</module>
     <module>renderers</module>
+    <module>location-providers</module>
     <module>neutron-mapper</module>
     <module>neutron-ovsdb</module>
     <module>ui-backend</module>