Moved the Intent handling functions from the McastForward class
to the McastIntentManager class, since Intents are going to
change as the result of a number of different inputs, such
as PIM Emulation, IGMP and others, not just packet forwarding.

Modified the mcast-show command to display the intent key
if an intent has been installed.

Added the @Service annotation to the the McastIntentManager.

Change-Id: Ie7cf85b4c67f8769f18e08f79028304356b9c8fc
diff --git a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
index 9a9e6a0..3898577 100644
--- a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
+++ b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
@@ -35,8 +35,6 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.intent.SinglePointToMultiPointIntent;
-import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
@@ -60,12 +58,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected IntentService intentService;
-
     private ReactivePacketProcessor processor = new ReactivePacketProcessor();
     private McastRouteTable mrib;
-    private ApplicationId appId;
+    private static ApplicationId appId;
 
     /**
      * Active MulticastForwardingIntent.
@@ -99,6 +94,14 @@
     }
 
     /**
+     * Get the application ID, used by the McastIntentManager.
+     * @return the application ID
+     */
+    public static ApplicationId getAppId() {
+        return appId;
+    }
+
+    /**
      * Packet processor responsible for forwarding packets along their paths.
      */
     private class ReactivePacketProcessor implements PacketProcessor {
@@ -174,8 +177,17 @@
                 return;
             }
 
-            // Otherwise forward and be done with it.
-            setIntent(context, entry);
+            /*
+             * This is odd, we should not have received a punted packet if an
+             * intent was installed unless the intent was not installed
+             * correctly.
+             */
+            if (entry.getIntentKey() != null) {
+                return;
+            }
+
+            McastIntentManager im = McastIntentManager.getInstance();
+            im.setIntent(entry);
 
             // Send the pack out each of the egress devices & port
             forwardPacketToDst(context, entry);
@@ -203,41 +215,5 @@
         }
     }
 
-    /**
-     * Install the PointToMultipoint forwarding intent.
-     * @param context packet context
-     * @param mroute multicast route entry
-     */
-    private void setIntent(PacketContext context, McastRoute mroute) {
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
 
-        if (mroute.getIngressPoint() == null ||
-                mroute.getEgressPoints().isEmpty()) {
-            return;
-        }
-
-        /*
-         * Match the group AND source addresses.  We will also check ether type to
-         * determine if we are doing ipv4 or ipv6.
-         *
-         * If we really wanted to be pendantic we could put in a
-         * condition to make sure the ethernet MAC address was also
-         * mcast.
-         */
-        selector.matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(mroute.getGaddr())
-                .matchIPSrc(mroute.getSaddr());
-
-        SinglePointToMultiPointIntent intent =
-                SinglePointToMultiPointIntent.builder()
-                        .appId(appId)
-                        .selector(selector.build())
-                        .treatment(treatment)
-                        .ingressPoint(mroute.getIngressPoint())
-                        .egressPoints(mroute.getEgressPoints()).
-                        build();
-
-        intentService.submit(intent);
-    }
 }
diff --git a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
new file mode 100644
index 0000000..4a96eea
--- /dev/null
+++ b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.mfwd.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+
+@Component(immediate = true)
+@Service(value = org.onosproject.mfwd.impl.McastIntentManager.class)
+public class McastIntentManager {
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentService intentService;
+
+    private static McastIntentManager instance;
+
+    public McastIntentManager() {
+        instance = this;
+    }
+
+    /**
+     * Active this component.
+     */
+    @Activate
+    public void activate() { }
+
+    /**
+     * Deactivate this component.
+     */
+    @Deactivate
+    public void deactivate() {
+    }
+
+    /**
+     * Get instance of this intentManager.
+     * @return the instance of this intent manager.
+     */
+    public static McastIntentManager getInstance() {
+        if (instance == null) {
+            instance = new McastIntentManager();
+        }
+        return instance;
+    }
+
+    /**
+     * Install the PointToMultipoint forwarding intent.
+     * @param mroute multicast route entry
+     */
+    public void setIntent(McastRoute mroute) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+        if (mroute.getIngressPoint() == null ||
+                mroute.getEgressPoints().isEmpty()) {
+            return;
+        }
+
+        /*
+         * Match the group AND source addresses.  We will also check ether type to
+         * determine if we are doing ipv4 or ipv6.
+         *
+         * If we really wanted to be pendantic we could put in a
+         * condition to make sure the ethernet MAC address was also
+         * mcast.
+         */
+        selector.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(mroute.getGaddr())
+                .matchIPSrc(mroute.getSaddr());
+
+        SinglePointToMultiPointIntent intent =
+                SinglePointToMultiPointIntent.builder()
+                        .appId(McastForwarding.getAppId())
+                        .selector(selector.build())
+                        .treatment(treatment)
+                        .ingressPoint(mroute.getIngressPoint())
+                        .egressPoints(mroute.getEgressPoints()).
+                        build();
+
+        intentService.submit(intent);
+        mroute.setIntent(intent);
+    }
+
+    /**
+     * Withdraw the intent from the network.
+     * @param mroute the multicast route representing the intent
+     */
+    public void withdrawIntent(McastRoute mroute) {
+        Key key = mroute.getIntentKey();
+    }
+}
diff --git a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
index 1c5f550..b67fca3 100644
--- a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
+++ b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
@@ -17,6 +17,8 @@
 
 import org.onlab.packet.IpPrefix;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
 
 import java.util.Set;
 
@@ -81,6 +83,18 @@
     public Set<ConnectPoint> getEgressPoints();
 
     /**
+     * Set the Intent key.
+     * @param intent
+     */
+    public void setIntent(SinglePointToMultiPointIntent intent);
+
+    /**
+     * Get the intent key.
+     * @return the intentKey
+     */
+    public Key getIntentKey();
+
+    /**
      * Pretty print the the route.
      * @return a pretty string
      */
diff --git a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
index 014fb7b..c3b7b26 100644
--- a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
+++ b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
@@ -21,6 +21,8 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+import org.onosproject.net.intent.Key;
 
 import java.util.Set;
 import java.util.HashSet;
@@ -38,6 +40,12 @@
     protected boolean isGroup = false;
 
     /**
+     * If the intentKey is null that means no intent has
+     * been installed.
+     */
+    protected Key intentKey = null;
+
+    /**
      * Create a multicast route. This is the parent class for both the Group
      * and the source.
      *
@@ -51,7 +59,6 @@
         } else {
             this.saddr = IpPrefix.valueOf(checkNotNull(gaddr));
         }
-
         this.init();
     }
 
@@ -193,13 +200,33 @@
     }
 
     /**
+     * Set the Intent key.
+     * @param intent
+     */
+    public void setIntent(SinglePointToMultiPointIntent intent) {
+        intentKey = intent.key();
+    }
+
+    /**
+     * Get the intent key represented by this route.
+     * @return intentKey
+     */
+    public Key getIntentKey() {
+        return this.intentKey;
+    }
+
+    /**
      * Pretty Print this Multicast Route.  Works for McastRouteSource and McastRouteGroup.
      * @return pretty string of the multicast route
      */
     public String toString() {
-        String out = String.format("(%s, %s)\n\tingress: %s ",
-                saddr.toString(), gaddr.toString(),
-                (ingressPoint == null) ? "NULL" : ingressPoint.toString());
+        String out = String.format("(%s, %s)\n\t",
+                saddr.toString(), gaddr.toString());
+
+        out += "intent: ";
+        out += (intentKey == null) ? "not installed" : this.intentKey.toString();
+        out += "\n\tingress: ";
+        out += (ingressPoint == null) ? "NULL" : ingressPoint.toString();
         out += "\n\tegress: {\n";
         if (egressPoints != null && !egressPoints.isEmpty()) {
             for (ConnectPoint eg : egressPoints) {
diff --git a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
index 01df321..6837ebb 100644
--- a/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
+++ b/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
@@ -261,19 +261,11 @@
 
         // Hard code group interest for a couple different groups and some receive points.
         // XXX this will go away as soon as the mcast-join cli command has been added
-        McastRouteBase g1 = this.addRoute("*", "225.1.1.1/32");
-        g1.addIngressPoint("of:0000000000000023", 4);
-        g1.addEgressPoint("of:0000000000000023", 3);
-
         McastRouteBase s1 = this.addRoute("10.1.1.1/32", "225.1.1.1/32");
-        s1.addIngressPoint("of:0000000000000011", 3);
-        s1.addEgressPoint("of:0000000000000023", 3);
-        s1.addEgressPoint("of:0000000000000023", 4);
-
-        McastRouteBase s2 = this.addRoute("10.1.1.2/32", "226.1.1.1/32");
-        s2.addIngressPoint("of:0000000000000012", 3);
-        s2.addEgressPoint("of:0000000000000023", 4);
-        s2.addEgressPoint("of:0000000000000023", 5);
+        s1.addIngressPoint("of:0000000000000001", 1);
+        s1.addEgressPoint("of:000000000000002", 1);
+        s1.addEgressPoint("of:000000000000003", 1);
+        s1.addEgressPoint("of:000000000000004", 1);
     }
 
     /**