ONOS-6889 Move mcast from incubator to core

Change-Id: Icfc7294e7017b640321dd9343778cd11c2cd0cb8
diff --git a/core/net/src/main/java/org/onosproject/net/mcast/impl/MulticastRouteManager.java b/core/net/src/main/java/org/onosproject/net/mcast/impl/MulticastRouteManager.java
new file mode 100644
index 0000000..913dcdb
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/mcast/impl/MulticastRouteManager.java
@@ -0,0 +1,128 @@
+/*
+ * 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.mcast.impl;
+
+import java.util.Set;
+
+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.onosproject.event.AbstractListenerManager;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.mcast.McastEvent;
+import org.onosproject.net.mcast.McastListener;
+import org.onosproject.net.mcast.McastRoute;
+import org.onosproject.net.mcast.McastStore;
+import org.onosproject.net.mcast.McastStoreDelegate;
+import org.onosproject.net.mcast.MulticastRouteService;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * An implementation of a multicast route table.
+ */
+@Component(immediate = true)
+@Service
+public class MulticastRouteManager
+        extends AbstractListenerManager<McastEvent, McastListener>
+        implements MulticastRouteService {
+    //TODO: add MulticastRouteAdminService
+
+    private Logger log = getLogger(getClass());
+
+    private final McastStoreDelegate delegate = new InternalMcastStoreDelegate();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected McastStore store;
+
+    @Activate
+    public void activate() {
+        eventDispatcher.addSink(McastEvent.class, listenerRegistry);
+        store.setDelegate(delegate);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        store.unsetDelegate(delegate);
+        eventDispatcher.removeSink(McastEvent.class);
+        log.info("Stopped");
+    }
+
+    @Override
+    public void add(McastRoute route) {
+        checkNotNull(route, "Route cannot be null");
+        store.storeRoute(route, McastStore.Type.ADD);
+    }
+
+    @Override
+    public void remove(McastRoute route) {
+        checkNotNull(route, "Route cannot be null");
+        store.storeRoute(route, McastStore.Type.REMOVE);
+    }
+
+    @Override
+    public Set<McastRoute> getRoutes() {
+        return store.getRoutes();
+    }
+
+    @Override
+    public void addSource(McastRoute route, ConnectPoint connectPoint) {
+        checkNotNull(route, "Route cannot be null");
+        checkNotNull(connectPoint, "Source cannot be null");
+        store.storeSource(route, connectPoint);
+    }
+
+    @Override
+    public void addSink(McastRoute route, ConnectPoint connectPoint) {
+        checkNotNull(route, "Route cannot be null");
+        checkNotNull(connectPoint, "Sink cannot be null");
+        store.storeSink(route, connectPoint, McastStore.Type.ADD);
+
+    }
+
+    @Override
+    public void removeSink(McastRoute route, ConnectPoint connectPoint) {
+
+        checkNotNull(route, "Route cannot be null");
+        checkNotNull(connectPoint, "Sink cannot be null");
+
+        store.storeSink(route, connectPoint, McastStore.Type.REMOVE);
+    }
+
+    @Override
+    public ConnectPoint fetchSource(McastRoute route) {
+        return store.sourceFor(route);
+    }
+
+    @Override
+    public Set<ConnectPoint> fetchSinks(McastRoute route) {
+        return store.sinksFor(route);
+    }
+
+    private class InternalMcastStoreDelegate implements McastStoreDelegate {
+        @Override
+        public void notify(McastEvent event) {
+            post(event);
+        }
+    }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/mcast/impl/package-info.java b/core/net/src/main/java/org/onosproject/net/mcast/impl/package-info.java
new file mode 100644
index 0000000..19b8d61
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/mcast/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.
+ */
+
+/**
+ * An implementation of a multicast RIB.
+ */
+package org.onosproject.net.mcast.impl;
diff --git a/core/net/src/test/java/org/onosproject/net/mcast/impl/MulticastRouteManagerTest.java b/core/net/src/test/java/org/onosproject/net/mcast/impl/MulticastRouteManagerTest.java
new file mode 100644
index 0000000..f5b26c2
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/mcast/impl/MulticastRouteManagerTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.mcast.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.packet.IpAddress;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.store.mcast.impl.DistributedMcastStore;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.mcast.McastEvent;
+import org.onosproject.net.mcast.McastListener;
+import org.onosproject.net.mcast.McastRoute;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+import static junit.framework.TestCase.assertEquals;
+import static org.onosproject.net.NetTestTools.did;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+
+/**
+ * Tests for the multicast RIB.
+ */
+public class MulticastRouteManagerTest {
+
+    McastRoute r1 = new McastRoute(IpAddress.valueOf("1.1.1.1"),
+                                   IpAddress.valueOf("1.1.1.2"),
+                                   McastRoute.Type.IGMP);
+
+    McastRoute r11 = new McastRoute(IpAddress.valueOf("1.1.1.1"),
+                                    IpAddress.valueOf("1.1.1.2"),
+                                    McastRoute.Type.STATIC);
+
+    McastRoute r2 = new McastRoute(IpAddress.valueOf("2.2.2.1"),
+                                   IpAddress.valueOf("2.2.2.2"),
+                                   McastRoute.Type.PIM);
+
+    ConnectPoint cp1 = new ConnectPoint(did("1"), PortNumber.portNumber(1));
+
+    ConnectPoint cp2 = new ConnectPoint(did("2"), PortNumber.portNumber(2));
+
+    private TestMulticastListener listener = new TestMulticastListener();
+
+    private MulticastRouteManager manager;
+
+    private List<McastEvent> events;
+
+    private DistributedMcastStore mcastStore;
+
+    @Before
+    public void setUp() throws Exception {
+        manager = new MulticastRouteManager();
+        mcastStore = new DistributedMcastStore();
+        TestUtils.setField(mcastStore, "storageService", new TestStorageService());
+        injectEventDispatcher(manager, new TestEventDispatcher());
+        events = Lists.newArrayList();
+        manager.store = mcastStore;
+        mcastStore.activate();
+        manager.activate();
+        manager.addListener(listener);
+    }
+
+    @After
+    public void tearDown() {
+        manager.removeListener(listener);
+        manager.deactivate();
+        mcastStore.deactivate();
+    }
+
+    @Test
+    public void testAdd() {
+        manager.add(r1);
+
+        validateEvents(McastEvent.Type.ROUTE_ADDED);
+    }
+
+    @Test
+    public void testRemove() {
+        manager.add(r1);
+
+        manager.remove(r1);
+
+
+        validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.ROUTE_REMOVED);
+    }
+
+    @Test
+    public void testAddSource() {
+        manager.addSource(r1, cp1);
+
+        validateEvents(McastEvent.Type.SOURCE_ADDED);
+        assertEquals("Route is not equal", cp1, manager.fetchSource(r1));
+    }
+
+    @Test
+    public void testAddSink() {
+        manager.addSink(r1, cp1);
+
+        validateEvents(McastEvent.Type.SINK_ADDED);
+        assertEquals("Route is not equal", Sets.newHashSet(cp1), manager.fetchSinks(r1));
+    }
+
+    @Test
+    public void testRemoveSink() {
+
+        manager.addSource(r1, cp1);
+        manager.addSink(r1, cp1);
+        manager.addSink(r1, cp2);
+        manager.removeSink(r1, cp2);
+
+        validateEvents(McastEvent.Type.SOURCE_ADDED,
+                       McastEvent.Type.SINK_ADDED,
+                       McastEvent.Type.SINK_ADDED,
+                       McastEvent.Type.SINK_REMOVED);
+        assertEquals("Route is not equal", Sets.newHashSet(cp1), manager.fetchSinks(r1));
+    }
+
+    private void validateEvents(McastEvent.Type... evs) {
+        if (events.size() != evs.length) {
+            fail(String.format("Mismatch number of events# obtained -> %s : expected %s",
+                               events, evs));
+        }
+
+        for (int i = 0; i < evs.length; i++) {
+            if (evs[i] != events.get(i).type()) {
+                fail(String.format("Mismatched events# obtained -> %s : expected %s",
+                                   events, evs));
+            }
+        }
+    }
+
+    class TestMulticastListener implements McastListener {
+        @Override
+        public void event(McastEvent event) {
+            events.add(event);
+        }
+    }
+
+    private class TestCoreService extends CoreServiceAdapter {
+        @Override
+        public ApplicationId registerApplication(String name) {
+            return new DefaultApplicationId(0, name);
+        }
+    }
+}