Moved VLAN assignment code from MetroPathProvisioner to CarrierEthernetManager.

Change-Id: Iff5e445a8136861157f2ebc28ef6d100d6e744ff
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java
index 7e0b36c..3e02151 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
@@ -30,7 +31,13 @@
 import org.onosproject.ecord.metro.api.MetroPathService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
+import org.onosproject.net.Link;
 import org.onosproject.net.Port;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.link.LinkService;
 import org.slf4j.Logger;
@@ -38,11 +45,15 @@
 import java.time.Duration;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 @Component(immediate = true)
@@ -63,7 +74,23 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CarrierEthernetPacketProvisioner cePktProvisioner;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry cfgRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
+    private final List<ConfigFactory<?, ?>> factories = ImmutableList.of(
+            new ConfigFactory<ConnectPoint, PortVlanConfig>(CONNECT_POINT_SUBJECT_FACTORY,
+                    PortVlanConfig.class, PortVlanConfig.CONFIG_KEY) {
+                @Override
+                public PortVlanConfig createConfig() {
+                    return new PortVlanConfig();
+                }
+            });
+
     private MetroPathListener metroEventListener = new MetroEventListener();
+    private NetworkConfigListener netcfgListener = new InternalNetworkConfigListener();
 
     // Keeps track of the next S-VLAN tag the app will try to use
     private static short curVlanId = 0;
@@ -83,11 +110,16 @@
     // The installed CE UNIs
     private final Map<String, CarrierEthernetUni> uniMap = new ConcurrentHashMap<>();
 
+    // Map of connect points and corresponding VLAN tag
+    private Map<ConnectPoint, VlanId> portVlanMap = new ConcurrentHashMap<>();
+
     /**
      * Activate this component.
      */
     @Activate
     public void activate() {
+        factories.forEach(cfgRegistry::registerConfigFactory);
+        networkConfigService.addListener(netcfgListener);
         metroPathService.addListener(metroEventListener);
     }
 
@@ -98,6 +130,9 @@
     public void deactivate() {
         removeAllServices();
         metroPathService.removeListener(metroEventListener);
+        networkConfigService.removeListener(netcfgListener);
+
+        factories.forEach(cfgRegistry::unregisterConfigFactory);
     }
 
     /**
@@ -305,10 +340,11 @@
                     log.info("Metro connectivity id and status for CE service {}: {}, {}", service.id(),
                             service.metroConnectivity().id(), service.metroConnectivity().status());
 
-                    // FIXME: Temporary hack for ONS: Get vlanId from metro app
                     if (metroConnectId != null) {
-                        Optional<VlanId> vlanId = metroPathService.getVlanId(metroConnectId);
+                        // TODO: find vlanIds for both CO and store to service
+                        Optional<VlanId> vlanId = getVlanTag(metroPathService.getPath(metroConnectId));
                         if (vlanId.isPresent()) {
+                            log.info("VLAN ID {} is assigned to CE service {}", vlanId.get(), service.id());
                             service.setVlanId(vlanId.get());
                         }
                     }
@@ -522,6 +558,24 @@
         }
     }
 
+    /**
+     * Returns VLAN tag assigned to given path.
+     * @param links List of links that composes path
+     * @return VLAN tag if found any. empty if not found.
+     */
+    private Optional<VlanId> getVlanTag(List<Link> links) {
+        checkNotNull(links);
+        Optional<ConnectPoint> edge = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
+                .filter(portVlanMap::containsKey)
+                .findAny();
+
+        if (edge.isPresent()) {
+            return Optional.of(portVlanMap.get(edge.get()));
+        }
+
+        return Optional.empty();
+    }
+
     private class MetroEventListener implements MetroPathListener {
 
         @Override
@@ -560,4 +614,25 @@
         }
     }
 
+
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if (!event.configClass().equals(PortVlanConfig.class)) {
+                return;
+            }
+
+            ConnectPoint cp = (ConnectPoint) event.subject();
+            PortVlanConfig config = networkConfigService.getConfig(cp, PortVlanConfig.class);
+            if (config != null && config.portVlanId().isPresent()) {
+                log.info("VLAN tag {} is assigned to port {}", config.portVlanId().get(), cp);
+                portVlanMap.put(cp, config.portVlanId().get());
+            } else {
+                log.info("VLAN tag is removed from port {}", cp);
+                portVlanMap.remove(cp);
+            }
+        }
+
+    }
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java
index f688768..4f992d4 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java
@@ -37,6 +37,7 @@
     protected String serviceId;
     protected String serviceCfgId;
     protected Type serviceType;
+    // FIXME: single vlanId is a hack for ONS2016.  CE service must store vlanId for each CO.
     protected VlanId vlanId;
     protected boolean isVirtual;
     protected Set<CarrierEthernetUni> uniSet;
diff --git a/ecord/metro/src/main/java/org/onosproject/ecord/metro/CeVlanConfig.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/PortVlanConfig.java
similarity index 71%
rename from ecord/metro/src/main/java/org/onosproject/ecord/metro/CeVlanConfig.java
rename to ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/PortVlanConfig.java
index c2f4576..15566ea 100644
--- a/ecord/metro/src/main/java/org/onosproject/ecord/metro/CeVlanConfig.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/PortVlanConfig.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.ecord.metro;
+package org.onosproject.ecord.carrierethernet.app;
 
 import org.onlab.packet.VlanId;
 import org.onosproject.net.ConnectPoint;
@@ -24,12 +24,12 @@
 /**
  * Configuration information for edge connect point and corresponding VLAN tag.
  */
-public class CeVlanConfig extends Config<ConnectPoint> {
-    public static final String CONFIG_KEY = "ceVlan";
+public class PortVlanConfig extends Config<ConnectPoint> {
+    public static final String CONFIG_KEY = "portVlan";
 
     public static final String CE_VLAN_TAG_KEY = "tag";
 
-    public Optional<VlanId> ceVlanId() {
+    public Optional<VlanId> portVlanId() {
         String s = get(CE_VLAN_TAG_KEY, null);
         if (s == null) {
             return Optional.empty();
@@ -37,10 +37,10 @@
         return Optional.of(VlanId.vlanId(Short.valueOf(s)));
     }
 
-    public CeVlanConfig ceVlanId(VlanId vlanId) {
+    public PortVlanConfig portVlanId(VlanId vlanId) {
         if (vlanId == null) {
-            return (CeVlanConfig) setOrClear(CE_VLAN_TAG_KEY, (String) null);
+            return (PortVlanConfig) setOrClear(CE_VLAN_TAG_KEY, (String) null);
         }
-        return (CeVlanConfig) setOrClear(CE_VLAN_TAG_KEY, String.valueOf(vlanId.toShort()));
+        return (PortVlanConfig) setOrClear(CE_VLAN_TAG_KEY, String.valueOf(vlanId.toShort()));
     }
 }
diff --git a/ecord/metro/src/main/java/org/onosproject/ecord/metro/MetroPathProvisioner.java b/ecord/metro/src/main/java/org/onosproject/ecord/metro/MetroPathProvisioner.java
index d50152d..31ff6ca 100644
--- a/ecord/metro/src/main/java/org/onosproject/ecord/metro/MetroPathProvisioner.java
+++ b/ecord/metro/src/main/java/org/onosproject/ecord/metro/MetroPathProvisioner.java
@@ -25,7 +25,6 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
-import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.NodeId;
@@ -47,10 +46,6 @@
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.Path;
 import org.onosproject.net.Port;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.intent.Intent;
@@ -93,7 +88,6 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
 
 /**
  * Main component to configure metro area connectivity.
@@ -132,22 +126,11 @@
     protected StorageService storageService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigRegistry cfgRegistry;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigService networkConfigService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceService resourceService;
 
-    private final List<ConfigFactory<?, ?>> factories = ImmutableList.of(
-            new ConfigFactory<ConnectPoint, CeVlanConfig>(CONNECT_POINT_SUBJECT_FACTORY,
-                    CeVlanConfig.class, CeVlanConfig.CONFIG_KEY) {
-                @Override
-                public CeVlanConfig createConfig() {
-                    return new CeVlanConfig();
-                }
-            });
 
     private ApplicationId appId;
 
@@ -155,7 +138,6 @@
 
     private LinkListener linkListener = new InternalLinkListener();
     private IntentListener intentListener = new InternalIntentListener();
-    private NetworkConfigListener netcfgListener = new InternalNetworkConfigListener();
 
     private Map<PacketLinkRealizedByOptical, MetroConnectivity> linkPathMap = new ConcurrentHashMap<>();
 
@@ -166,12 +148,8 @@
     // Map of cross connect link and installed path which uses the link
     private Set<Link> usedCrossConnectLinks = Sets.newConcurrentHashSet();
 
-    // Map of connect points and corresponding VLAN tag
-    private Map<ConnectPoint, VlanId> portVlanMap = new ConcurrentHashMap<>();
-
     @Activate
     protected void activate() {
-        factories.forEach(cfgRegistry::registerConfigFactory);
         appId = coreService.registerApplication("org.onosproject.ecord.metro");
 
         idCounter = storageService.atomicCounterBuilder()
@@ -183,19 +161,15 @@
         eventDispatcher.addSink(MetroPathEvent.class, listenerRegistry);
         linkService.addListener(linkListener);
         intentService.addListener(intentListener);
-        networkConfigService.addListener(netcfgListener);
 
         log.info("Started");
     }
 
     @Deactivate
     protected void deactivate() {
-        networkConfigService.removeListener(netcfgListener);
         intentService.removeListener(intentListener);
         linkService.removeListener(linkListener);
 
-        factories.forEach(cfgRegistry::unregisterConfigFactory);
-
         log.info("Stopped");
     }
 
@@ -307,18 +281,6 @@
         return ImmutableList.copyOf(connectivity.links());
     }
 
-    @Override
-    public Optional<VlanId> getVlanId(MetroConnectivityId id) {
-        checkNotNull(id);
-
-        MetroConnectivity connectivity = connectivities.get(id);
-        if (connectivity != null) {
-            return getVlanTag(connectivity.links());
-        }
-
-        return Optional.empty();
-    }
-
     /**
      * Returns list of (optical, packet) pairs of cross connection points of missing optical path sections.
      *
@@ -541,22 +503,6 @@
         log.debug("DONE releasing bandwidth for {}", connectivity.getIntentId());
     }
 
-    /**
-     * Returns VLAN tag assigned to given path.
-     * @param links Path
-     * @return VLAN tag if found any. empty if not found.
-     */
-    private Optional<VlanId> getVlanTag(List<Link> links) {
-        Optional<ConnectPoint> edge = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
-                .filter(portVlanMap::containsKey)
-                .findAny();
-
-        if (edge.isPresent()) {
-            return Optional.of(portVlanMap.get(edge.get()));
-        }
-        return Optional.empty();
-    }
-
     private class BandwidthLinkWeight implements LinkWeight {
         private Bandwidth bandwidth = null;
 
@@ -712,25 +658,6 @@
         }
     }
 
-    private class InternalNetworkConfigListener implements NetworkConfigListener {
-
-        @Override
-        public void event(NetworkConfigEvent event) {
-            if (event.configClass() != CeVlanConfig.class) {
-                return;
-            }
-
-            ConnectPoint cp = (ConnectPoint) event.subject();
-            CeVlanConfig config = networkConfigService.getConfig(cp, CeVlanConfig.class);
-            if (config != null && config.ceVlanId().isPresent()) {
-                log.info("VLAN tag {} is assigned to port {}", config.ceVlanId().get(), cp);
-                portVlanMap.put(cp, config.ceVlanId().get());
-            } else {
-                portVlanMap.remove(cp);
-            }
-        }
-
-    }
 
     private class InternalLinkListener implements LinkListener {
 
diff --git a/ecord/metro/src/main/java/org/onosproject/ecord/metro/api/MetroPathService.java b/ecord/metro/src/main/java/org/onosproject/ecord/metro/api/MetroPathService.java
index 2377b7f..db4d92b 100644
--- a/ecord/metro/src/main/java/org/onosproject/ecord/metro/api/MetroPathService.java
+++ b/ecord/metro/src/main/java/org/onosproject/ecord/metro/api/MetroPathService.java
@@ -16,7 +16,6 @@
 package org.onosproject.ecord.metro.api;
 
 import com.google.common.annotations.Beta;
-import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.event.ListenerService;
 import org.onosproject.net.ConnectPoint;
@@ -25,7 +24,6 @@
 
 import java.time.Duration;
 import java.util.List;
-import java.util.Optional;
 
 /**
  * Service to setup metro domain connectivity.
@@ -69,7 +67,4 @@
      * @return list of link that compose a path. null if ID is invalid.
      */
     List<Link> getPath(MetroConnectivityId id);
-
-    // FIXME This is for ONS2016 demo use only
-    Optional<VlanId> getVlanId(MetroConnectivityId id);
 }
diff --git a/ecord/metro/src/main/java/org/onosproject/ecord/metro/cli/AddMetroConnectivityCommand.java b/ecord/metro/src/main/java/org/onosproject/ecord/metro/cli/AddMetroConnectivityCommand.java
index 05fc378..8a0d351 100644
--- a/ecord/metro/src/main/java/org/onosproject/ecord/metro/cli/AddMetroConnectivityCommand.java
+++ b/ecord/metro/src/main/java/org/onosproject/ecord/metro/cli/AddMetroConnectivityCommand.java
@@ -17,7 +17,6 @@
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
-import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.ecord.metro.api.MetroConnectivityId;
@@ -26,8 +25,6 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 
-import java.util.Optional;
-
 @Command(scope = "onos", name = "add-metro-connectivity",
         description = "Configure metro domain connectivity")
 public class AddMetroConnectivityCommand extends AbstractShellCommand {
@@ -70,12 +67,6 @@
             return;
         }
         print("Metro path ID : %s", id.value());
-        Optional<VlanId> vlanId = metroPathService.getVlanId(id);
-        if (vlanId.isPresent()) {
-            print("  -- VLAN ID %d was assigned.", vlanId.get().toShort());
-        } else {
-            print("  -- No VLAN ID was assigned.");
-        }
     }
 
     private ConnectPoint readConnectPoint(String str) {