ONOS-6886 Move interface classes from incubator to core

Change-Id: Iaae4d98279e4b77fc3f0b5a63d547921f93aeb46
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index 183a0ba..cda9e04 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -29,7 +29,7 @@
 import org.onlab.packet.VlanId;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
-import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.intf.InterfaceService;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.edge.EdgePortService;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
index 52829ba..950bedd 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
@@ -23,7 +23,7 @@
 import org.onlab.packet.VlanId;
 import org.onlab.packet.ndp.NeighborSolicitation;
 import org.onlab.util.SharedScheduledExecutors;
-import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.intf.InterfaceService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Host;
 import org.onosproject.net.edge.EdgePortService;
diff --git a/core/net/src/main/java/org/onosproject/net/intf/impl/InterfaceManager.java b/core/net/src/main/java/org/onosproject/net/intf/impl/InterfaceManager.java
new file mode 100644
index 0000000..5693db5
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intf/impl/InterfaceManager.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.intf.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+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.IpAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.incubator.net.config.basics.InterfaceConfig;
+import org.onosproject.net.intf.Interface;
+import org.onosproject.net.intf.InterfaceAdminService;
+import org.onosproject.net.intf.InterfaceEvent;
+import org.onosproject.net.intf.InterfaceListener;
+import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toSet;
+
+/**
+ * Manages the inventory of interfaces in the system.
+ */
+@Service
+@Component(immediate = true)
+public class InterfaceManager extends ListenerRegistry<InterfaceEvent, InterfaceListener>
+        implements InterfaceService, InterfaceAdminService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final Class<ConnectPoint> SUBJECT_CLASS = ConnectPoint.class;
+    private static final Class<InterfaceConfig> CONFIG_CLASS = InterfaceConfig.class;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService configService;
+
+    private final InternalConfigListener listener = new InternalConfigListener();
+
+    private final Map<ConnectPoint, Set<Interface>> interfaces = Maps.newConcurrentMap();
+
+    @Activate
+    public void activate() {
+        configService.addListener(listener);
+
+        // TODO address concurrency issues here
+        for (ConnectPoint subject : configService.getSubjects(SUBJECT_CLASS, CONFIG_CLASS)) {
+            InterfaceConfig config = configService.getConfig(subject, CONFIG_CLASS);
+
+            if (config != null) {
+                updateInterfaces(config);
+            }
+        }
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        configService.removeListener(listener);
+
+        log.info("Stopped");
+    }
+
+    @Override
+    public Set<Interface> getInterfaces() {
+        return interfaces.values()
+                .stream()
+                .flatMap(set -> set.stream())
+                .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
+    }
+
+    @Override
+    public Interface getInterfaceByName(ConnectPoint connectPoint, String name) {
+        Optional<Interface> intf =
+                interfaces.getOrDefault(connectPoint, Collections.emptySet())
+                .stream()
+                .filter(i -> i.name().equals(name))
+                .findAny();
+
+        return intf.orElse(null);
+    }
+
+    @Override
+    public Set<Interface> getInterfacesByPort(ConnectPoint port) {
+        Set<Interface> intfs = interfaces.get(port);
+        if (intfs == null) {
+            return Collections.emptySet();
+        }
+        return ImmutableSet.copyOf(intfs);
+    }
+
+    @Override
+    public Set<Interface> getInterfacesByIp(IpAddress ip) {
+        return interfaces.values()
+                .stream()
+                .flatMap(Collection::stream)
+                .filter(intf -> intf.ipAddressesList()
+                        .stream()
+                        .anyMatch(ia -> ia.ipAddress().equals(ip)))
+                .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
+    }
+
+    @Override
+    public Interface getMatchingInterface(IpAddress ip) {
+        return getMatchingInterfacesStream(ip).findFirst().orElse(null);
+    }
+
+    @Override
+    public Set<Interface> getMatchingInterfaces(IpAddress ip) {
+        return getMatchingInterfacesStream(ip).collect(toSet());
+    }
+
+    private Stream<Interface> getMatchingInterfacesStream(IpAddress ip) {
+        return interfaces.values()
+                .stream()
+                .flatMap(Collection::stream)
+                .filter(intf -> intf.ipAddressesList()
+                        .stream()
+                        .anyMatch(intfIp -> intfIp.subnetAddress().contains(ip)));
+    }
+
+    @Override
+    public Set<Interface> getInterfacesByVlan(VlanId vlan) {
+        return interfaces.values()
+                .stream()
+                .flatMap(Collection::stream)
+                .filter(intf -> intf.vlan().equals(vlan))
+                .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
+    }
+
+    private void updateInterfaces(InterfaceConfig intfConfig) {
+        try {
+            Set<Interface> old = interfaces.put(intfConfig.subject(),
+                    Sets.newHashSet(intfConfig.getInterfaces()));
+
+            if (old == null) {
+                old = Collections.emptySet();
+            }
+
+            for (Interface intf : intfConfig.getInterfaces()) {
+                if (intf.name().equals(Interface.NO_INTERFACE_NAME)) {
+                    process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
+                } else {
+                    Optional<Interface> oldIntf = findInterface(intf, old);
+                    if (oldIntf.isPresent()) {
+                        old.remove(oldIntf.get());
+                        if (!oldIntf.get().equals(intf)) {
+                            process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_UPDATED, intf, oldIntf.get()));
+                        }
+                    } else {
+                        process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
+                    }
+                }
+            }
+
+            for (Interface intf : old) {
+                if (!intf.name().equals(Interface.NO_INTERFACE_NAME)) {
+                    process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, intf));
+                }
+            }
+        } catch (ConfigException e) {
+            log.error("Error in interface config", e);
+        }
+    }
+
+    private Optional<Interface> findInterface(Interface intf, Set<Interface> set) {
+        return set.stream().filter(i -> i.name().equals(intf.name())).findAny();
+    }
+
+    private void removeInterfaces(ConnectPoint port) {
+        Set<Interface> old = interfaces.remove(port);
+
+        old.stream()
+                .filter(i -> !i.name().equals(Interface.NO_INTERFACE_NAME))
+                .forEach(i -> process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, i)));
+    }
+
+    @Override
+    public void add(Interface intf) {
+        InterfaceConfig config =
+                configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
+
+        config.addInterface(intf);
+
+        configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
+    }
+
+    @Override
+    public boolean remove(ConnectPoint connectPoint, String name) {
+        InterfaceConfig config = configService.addConfig(connectPoint, CONFIG_CLASS);
+        config.removeInterface(name);
+
+        try {
+            if (config.getInterfaces().isEmpty()) {
+                configService.removeConfig(connectPoint, CONFIG_CLASS);
+            } else {
+                configService.applyConfig(connectPoint, CONFIG_CLASS, config.node());
+            }
+        } catch (ConfigException e) {
+            log.error("Error reading interfaces JSON", e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Listener for network config events.
+     */
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if (event.configClass() == CONFIG_CLASS) {
+                switch (event.type()) {
+                case CONFIG_ADDED:
+                case CONFIG_UPDATED:
+                    InterfaceConfig config =
+                            configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class);
+                    updateInterfaces(config);
+                    break;
+                case CONFIG_REMOVED:
+                    removeInterfaces((ConnectPoint) event.subject());
+                    break;
+                case CONFIG_REGISTERED:
+                case CONFIG_UNREGISTERED:
+                default:
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intf/impl/package-info.java b/core/net/src/main/java/org/onosproject/net/intf/impl/package-info.java
new file mode 100644
index 0000000..e5884c5
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intf/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementation of service for interacting with interfaces.
+ */
+package org.onosproject.net.impl;