Refactors IGMPProxy application in API and APP bundles

Change-Id: I465d6c0f49079804ae8e0a1f464581c25c6d2300
diff --git a/app/src/main/java/org/opencord/igmpproxy/impl/GroupMember.java b/app/src/main/java/org/opencord/igmpproxy/impl/GroupMember.java
new file mode 100644
index 0000000..a05b962
--- /dev/null
+++ b/app/src/main/java/org/opencord/igmpproxy/impl/GroupMember.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2017-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.opencord.igmpproxy.impl;
+
+import org.onlab.packet.IGMPMembership;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Date struct to keep Igmp member infomations.
+ */
+public final class  GroupMember {
+
+    private final VlanId vlan;
+    private final DeviceId deviceId;
+    private final PortNumber portNumber;
+    private final Ip4Address groupIp;
+    private final boolean v2;
+    private byte recordType = IGMPMembership.MODE_IS_INCLUDE;
+    private ArrayList<Ip4Address> sourceList = new ArrayList<>();
+    private int keepAliveQueryInterval = 0;
+    private int keepAliveQueryCount = 0;
+    private int lastQueryInterval = 0;
+    private int lastQueryCount = 0;
+    private boolean leave = false;
+
+    public GroupMember(Ip4Address groupIp, VlanId vlan, DeviceId deviceId, PortNumber portNum, boolean isV2) {
+        this.groupIp = groupIp;
+        this.vlan = vlan;
+        this.deviceId = deviceId;
+        this.portNumber = portNum;
+        v2 = isV2;
+    }
+
+    static String getkey(Ip4Address groupIp, DeviceId deviceId, PortNumber portNum) {
+        return groupIp.toString() + deviceId.toString() + portNum.toString();
+    }
+
+    public String getkey() {
+        return GroupMember.getkey(groupIp, deviceId, portNumber);
+    }
+
+    public String getId() {
+        return getkey();
+    }
+
+    public VlanId getvlan() {
+        return vlan;
+    }
+
+    public DeviceId getDeviceId() {
+        return deviceId;
+    }
+
+    public PortNumber getPortNumber() {
+        return portNumber;
+    }
+
+    public Ip4Address getGroupIp() {
+        return groupIp;
+    }
+
+    public byte getRecordType() {
+        return recordType;
+    }
+
+    public boolean getv2() {
+        return v2;
+    }
+
+    public ArrayList<Ip4Address> getSourceList() {
+        return sourceList;
+    }
+
+
+    public void updateList(byte recordType, ArrayList<Ip4Address> newSourceList) {
+        this.recordType = recordType;
+        this.sourceList.clear();
+        this.sourceList.addAll(newSourceList);
+
+        /*TODO : support SSM
+        if (this.recordType == IGMPMembership.MODE_IS_INCLUDE) {
+            switch (recordType) {
+                case IGMPMembership.MODE_IS_INCLUDE:
+                case IGMPMembership.CHANGE_TO_INCLUDE_MODE:
+                    //however , set to include<B> anyway
+                    this.sourceList = sourceList;
+                    this.recordType = IGMPMembership.MODE_IS_INCLUDE;
+                    break;
+                case IGMPMembership.MODE_IS_EXCLUDE:
+                case IGMPMembership.CHANGE_TO_EXCLUDE_MODE:
+                    //set to exclude<B>
+                    this.sourceList = sourceList;
+                    this.recordType = IGMPMembership.MODE_IS_EXCLUDE;
+                    break;
+                case IGMPMembership.ALLOW_NEW_SOURCES:
+                    //set to include <A+B>
+                    join(this.sourceList, sourceList);
+                    break;
+                case IGMPMembership.BLOCK_OLD_SOURCES:
+                    //set to include <A-B>
+                    exclude(this.sourceList, sourceList);
+                    break;
+                default:
+                    break;
+            }
+        } else if (this.recordType == IGMPMembership.MODE_IS_EXCLUDE) {
+            switch (recordType) {
+                case IGMPMembership.MODE_IS_INCLUDE:
+                case IGMPMembership.CHANGE_TO_INCLUDE_MODE:
+                    //set to include<B>
+                    this.recordType = IGMPMembership.MODE_IS_INCLUDE;
+                    this.sourceList = sourceList;
+                    break;
+                case IGMPMembership.MODE_IS_EXCLUDE:
+                case IGMPMembership.CHANGE_TO_EXCLUDE_MODE:
+                    this.sourceList = sourceList;
+                    this.recordType = IGMPMembership.MODE_IS_EXCLUDE;
+                    break;
+                case IGMPMembership.ALLOW_NEW_SOURCES:
+                    //set to exclude <A-B>
+                    exclude(this.sourceList, sourceList);
+                    break;
+                case IGMPMembership.BLOCK_OLD_SOURCES:
+                    //set to exclude <A+B>
+                    join(this.sourceList, sourceList);
+                    break;
+                default:
+                    break;
+            }
+        }*/
+
+        return;
+    }
+
+
+    /*join B to A (A+B)*/
+    private void join(ArrayList<Integer> listA, ArrayList<Integer> listB) {
+        Iterator<Integer> iterA = null;
+        Iterator<Integer> iterB = listB.iterator();
+        boolean exists;
+        while (iterB.hasNext()) {
+            iterA = listA.iterator();
+            exists = false;
+            int ipToAdd = iterB.next();
+            while (iterA.hasNext()) {
+                if (iterA.next().equals(ipToAdd)) {
+                    exists = true;
+                    break;
+                }
+            }
+            if (!exists) {
+                listA.add(ipToAdd);
+            }
+        }
+    }
+
+    /* include A and B (A*B)*/
+    private void intersection(ArrayList<Integer> listA, ArrayList<Integer> listB) {
+        Iterator<Integer> iterA = listA.iterator();
+        Iterator<Integer> iterB;
+        boolean exists;
+
+        while (iterA.hasNext()) {
+            iterB = listB.iterator();
+            int ipToInclude = iterA.next();
+            exists = false;
+            while (iterB.hasNext()) {
+                if (iterB.next().equals(ipToInclude)) {
+                    exists = true;
+                    break;
+                }
+            }
+            if (!exists) {
+                iterA.remove();
+            }
+        }
+    }
+
+    /*exclude B from A (A-B)*/
+    private void exclude(ArrayList<Integer> listA, ArrayList<Integer> listB) {
+        Iterator<Integer> iterA = null;
+        Iterator<Integer> iterB = listB.iterator();
+
+        while (iterB.hasNext()) {
+            iterA = listA.iterator();
+            int ipToDel = iterB.next();
+            while (iterA.hasNext()) {
+                if (iterA.next().equals(ipToDel)) {
+                    iterA.remove();
+                    break;
+                }
+            }
+        }
+    }
+
+    public void setLeave(boolean l) {
+        leave = l;
+    }
+
+    public boolean isLeave() {
+        return leave;
+    }
+
+    public int getKeepAliveQueryInterval() {
+        return keepAliveQueryInterval;
+    }
+
+    public int getKeepAliveQueryCount() {
+        return keepAliveQueryCount;
+    }
+
+    public int getLastQueryInterval() {
+        return lastQueryInterval;
+    }
+
+    public int getLastQueryCount() {
+        return lastQueryCount;
+    }
+
+    public void keepAliveQueryCount(boolean add) {
+        if (add) {
+            keepAliveQueryCount++;
+        } else {
+            keepAliveQueryCount = 0;
+        }
+    }
+
+    public void lastQueryCount(boolean add) {
+        if (add) {
+            lastQueryCount++;
+        } else {
+            lastQueryCount = 0;
+        }
+    }
+
+    public void keepAliveInterval(boolean add) {
+        if (add) {
+            keepAliveQueryInterval++;
+        } else {
+            keepAliveQueryInterval = 0;
+        }
+    }
+
+    public void lastQueryInterval(boolean add) {
+        if (add) {
+            lastQueryInterval++;
+        } else {
+            lastQueryInterval = 0;
+        }
+    }
+
+    public void resetAllTimers() {
+        keepAliveQueryInterval = 0;
+        keepAliveQueryCount = 0;
+        lastQueryInterval = 0;
+        lastQueryCount = 0;
+    }
+}