[ONOS-4478][ONOS-4479] Implement scalable gateway get methods and gateway node management

 - Implements scalable gateway interface methods
 - Implements gateway node management

Change-Id: Ie5eb400b52df49dc36aef951e356e04b6238d59d
diff --git a/apps/scalablegateway/pom.xml b/apps/scalablegateway/pom.xml
index 8124baf..a3da966 100644
--- a/apps/scalablegateway/pom.xml
+++ b/apps/scalablegateway/pom.xml
@@ -47,6 +47,12 @@
         <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onos-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
         </dependency>
     </dependencies>
 </project>
diff --git a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/GatewayNodeConfig.java b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/GatewayNodeConfig.java
new file mode 100644
index 0000000..9f89c41
--- /dev/null
+++ b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/GatewayNodeConfig.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016-present 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.scalablegateway.api;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
+
+/**
+ * Configuration object for OpensatckNode service.
+ */
+public class GatewayNodeConfig extends Config<ApplicationId> {
+
+    protected final Logger log = getLogger(getClass());
+
+    public static final String NODES = "nodes";
+    public static final String BRIDGE_ID = "bridgeId";
+    public static final String DATAPLANE_IP = "dataPlaneIp";
+    public static final String EXTERNAL_INTERFACE_NAME = "gatewayExternalInterfaceName";
+
+    /**
+     * Returns the set of nodes read from network config.
+     *
+     * @return set of OpensatckNodeConfig or null
+     */
+    public Set<GatewayNode> gatewayNodes() {
+
+        Set<GatewayNode> nodes = Sets.newHashSet();
+
+        JsonNode jsonNodes = object.get(NODES);
+        if (jsonNodes == null) {
+            return null;
+        }
+
+        jsonNodes.forEach(jsonNode -> {
+            try {
+                nodes.add(new GatewayNode.Builder()
+                        .gatewayDeviceId(DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText()))
+                        .gatewayExternalInterfaceNames(
+                                getExternalInterfaceName(jsonNode.path(EXTERNAL_INTERFACE_NAME).asText()))
+                        .dataIpAddress(Ip4Address.valueOf(jsonNode.path(DATAPLANE_IP).asText())).build());
+            } catch (IllegalArgumentException | NullPointerException e) {
+                log.error("Failed to read {}", e.toString());
+            }
+        });
+        return nodes;
+    }
+
+    private List<String> getExternalInterfaceName(String s) {
+        List<String> list = Lists.newArrayList();
+        return Collections.addAll(list, s.split(",")) ? list : null;
+    }
+
+    @Override
+    public boolean isValid() {
+        return hasOnlyFields(NODES, BRIDGE_ID, DATAPLANE_IP, EXTERNAL_INTERFACE_NAME) &&
+                isIpAddress(DATAPLANE_IP, MANDATORY) && isString(BRIDGE_ID, MANDATORY) &&
+                isString(EXTERNAL_INTERFACE_NAME, MANDATORY);
+    }
+
+}
diff --git a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/package-info.java b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/package-info.java
index 7eaa692..6a0333e 100644
--- a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/package-info.java
+++ b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/api/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Application for ScaleableGateway management.
+ * Application api for Scaleable Gateway management.
  */
 package org.onosproject.scalablegateway.api;
\ No newline at end of file
diff --git a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/ScalableGatewayManager.java b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/ScalableGatewayManager.java
index 3294a09..f837546 100644
--- a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/ScalableGatewayManager.java
+++ b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/ScalableGatewayManager.java
@@ -16,51 +16,196 @@
 
 package org.onosproject.scalablegateway.impl;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+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.core.ApplicationId;
+import org.onosproject.core.CoreService;
+
 import org.onosproject.core.GroupId;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+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.config.basics.SubjectFactories;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.scalablegateway.api.GatewayNode;
+import org.onosproject.scalablegateway.api.GatewayNodeConfig;
 import org.onosproject.scalablegateway.api.ScalableGatewayService;
 
 import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Manages gateway node for gateway scalability.
  */
+
+@Service
+@Component(immediate = true)
 public class ScalableGatewayManager implements ScalableGatewayService {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private ApplicationId appId;
+    private static final String APP_ID = "org.onosproject.scalablegateway";
+    private static final String APP_NAME = "scalablegateway";
+    private static final String GATEWAYNODE_CAN_NOT_BE_NULL = "The gateway node can not be null";
+    private static final String PORT_CAN_NOT_BE_NULL = "The port can not be null";
+    private static final String FAIL_ADD_GATEWAY = "Adding process is failed as existing deivce id";
+    private static final String FAIL_REMOVE_GATEWAY = "Removing process is failed as unknown deivce id";
+    private static final String PORT_NAME = "portName";
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService configService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry configRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    private GatewayNodeConfig config;
+
+    private final NetworkConfigListener configListener = new InternalConfigListener();
+
+    private final ConfigFactory configFactory =
+            new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, GatewayNodeConfig.class, APP_NAME) {
+                @Override
+                public GatewayNodeConfig createConfig() {
+                    return new GatewayNodeConfig();
+                }
+            };
+    private Map<DeviceId, GatewayNode> gatewayNodeMap = Maps.newHashMap(); // Map<GatewayNode`s Id, GatewayNode object>
+
+    @Activate
+    protected void activate() {
+        appId = coreService.registerApplication(APP_ID);
+        configRegistry.registerConfigFactory(configFactory);
+        configService.addListener(configListener);
+
+        readConfiguration();
+
+        log.info("started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        gatewayNodeMap.clear();
+
+        configService.removeListener(configListener);
+
+        log.info("stopped");
+    }
 
     @Override
     public GatewayNode getGatewayNode(DeviceId deviceId) {
-        return null;
+        return checkNotNull(gatewayNodeMap.get(deviceId), GATEWAYNODE_CAN_NOT_BE_NULL);
     }
 
     @Override
     public List<PortNumber> getGatewayExternalPorts(DeviceId deviceId) {
-        return null;
+        GatewayNode gatewayNode = checkNotNull(gatewayNodeMap.get(deviceId), GATEWAYNODE_CAN_NOT_BE_NULL);
+        List<PortNumber> portNumbers = Lists.newArrayList();
+        gatewayNode.getGatewayExternalInterfaceNames()
+                .stream()
+                .forEach(name -> portNumbers.add(findPortNumFromPortName(gatewayNode.getGatewayDeviceId(), name)));
+        return portNumbers;
+    }
+
+    private PortNumber findPortNumFromPortName(DeviceId gatewayDeviceId, String name) {
+        Port port = deviceService.getPorts(gatewayDeviceId)
+                .stream()
+                .filter(p -> p.annotations().value(PORT_NAME).equals(name))
+                .iterator()
+                .next();
+        return checkNotNull(port, PORT_CAN_NOT_BE_NULL).number();
+
     }
 
     @Override
     public GroupId getGroupIdForGatewayLoadBalance(DeviceId srcDeviceId) {
+        //TODO: Implement group generation method by handler
         return null;
     }
 
     @Override
     public List<GatewayNode> getGatewayNodes() {
-        return null;
+        List<GatewayNode> gatewayNodeList = Lists.newArrayList();
+        gatewayNodeMap.values()
+                .stream()
+                .forEach(gatewayNode -> gatewayNodeList.add(gatewayNode));
+        return gatewayNodeList;
+
     }
 
     @Override
     public List<DeviceId> getGatewayDeviceIds() {
-        return null;
+        List<DeviceId> deviceIdList = Lists.newArrayList();
+        gatewayNodeMap.values()
+                .stream()
+                .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId()));
+        return deviceIdList;
+
     }
 
     @Override
     public boolean addGatewayNode(GatewayNode gatewayNode) {
-        return false;
+        gatewayNodeMap.putIfAbsent(gatewayNode.getGatewayDeviceId(), gatewayNode);
+        return true;
     }
 
     @Override
     public boolean deleteGatewayNode(GatewayNode gatewayNode) {
-        return false;
+        return gatewayNodeMap.remove(gatewayNode.getGatewayDeviceId(), gatewayNode);
+    }
+
+    private class InternalConfigListener implements NetworkConfigListener {
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if (!event.configClass().equals(GatewayNodeConfig.class)) {
+                return;
+            }
+            switch (event.type()) {
+                case CONFIG_UPDATED:
+                    gatewayNodeMap.clear();
+                    readConfiguration();
+                    break;
+                case CONFIG_ADDED:
+                    readConfiguration();
+                    break;
+                default:
+                    log.debug("Unsupportable event type is occurred");
+                    break;
+            }
+        }
+    }
+
+    private void readConfiguration() {
+        config = configService.getConfig(appId, GatewayNodeConfig.class);
+        if (config == null) {
+            log.error("No configuration found");
+            return;
+        }
+
+        config.gatewayNodes().forEach(gatewayNode -> addGatewayNode(gatewayNode));
+
+        log.info("ScalableGateway configured");
     }
 }
diff --git a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/package-info.java b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/package-info.java
index f666d0c..7774a85 100644
--- a/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/package-info.java
+++ b/apps/scalablegateway/src/main/java/org/onosproject/scalablegateway/impl/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Application for ScaleableGateway management.
+ * Application for Scaleable Gateway management.
  */
 package org.onosproject.scalablegateway.impl;
\ No newline at end of file