Restructured api to multiple packages

Change-Id: I8a3bb2297ef55fa7749bb312b01a4929d1b360f6
diff --git a/src/main/java/org/opencord/cordvtn/api/config/CordVtnConfig.java b/src/main/java/org/opencord/cordvtn/api/config/CordVtnConfig.java
new file mode 100644
index 0000000..9dfa929
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/config/CordVtnConfig.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2015-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.opencord.cordvtn.api.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.opencord.cordvtn.api.node.CordVtnNode;
+import org.opencord.cordvtn.api.node.NetworkAddress;
+import org.opencord.cordvtn.api.node.SshAccessInfo;
+import org.slf4j.Logger;
+
+import java.util.Map;
+import java.util.Set;
+
+import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
+import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Configuration object for CordVtn service.
+ */
+public class CordVtnConfig extends Config<ApplicationId> {
+
+    protected final Logger log = getLogger(getClass());
+
+    private static final String PRIVATE_GATEWAY_MAC = "privateGatewayMac";
+    private static final String PUBLIC_GATEWAYS = "publicGateways";
+    private static final String GATEWAY_IP = "gatewayIp";
+    private static final String GATEWAY_MAC = "gatewayMac";
+    private static final String LOCAL_MANAGEMENT_IP = "localManagementIp";
+    private static final String OVSDB_PORT = "ovsdbPort";
+
+    private static final String CORDVTN_NODES = "nodes";
+    private static final String HOSTNAME = "hostname";
+    private static final String HOST_MANAGEMENT_IP = "hostManagementIp";
+    private static final String HOST_MANAGEMENT_IFACE = "hostManagementIface";
+    private static final String DATA_IP = "dataPlaneIp";
+    private static final String DATA_IFACE = "dataPlaneIntf";
+    private static final String INTEGRATION_BRIDGE_ID = "bridgeId";
+
+    private static final String SSH = "ssh";
+    private static final String SSH_PORT = "sshPort";
+    private static final String SSH_USER = "sshUser";
+    private static final String SSH_KEY_FILE = "sshKeyFile";
+
+    private static final String OPENSTACK = "openstack";
+    private static final String XOS = "xos";
+
+    private static final String ENDPOINT = "endpoint";
+    private static final String TENANT = "tenant";
+    private static final String USER = "user";
+    private static final String PASSWORD = "password";
+
+    // TODO implement isValid
+    @Override
+    public boolean isValid() {
+        // check only allowed fields are present
+        boolean result = hasOnlyFields(
+                PRIVATE_GATEWAY_MAC,
+                PUBLIC_GATEWAYS,
+                LOCAL_MANAGEMENT_IP,
+                OVSDB_PORT,
+                SSH,
+                OPENSTACK,
+                XOS,
+                CORDVTN_NODES);
+
+        if (object.get(CORDVTN_NODES) == null || object.get(CORDVTN_NODES).size() < 1) {
+            final String msg = "No node is present";
+            throw new IllegalArgumentException(msg);
+        }
+
+        // check all mandatory fields are present and valid
+        result = result && isMacAddress(PRIVATE_GATEWAY_MAC, MANDATORY);
+        result = result && isIpPrefix(LOCAL_MANAGEMENT_IP, MANDATORY);
+
+        for (JsonNode node : object.get(CORDVTN_NODES)) {
+            ObjectNode vtnNode = (ObjectNode) node;
+            result = result && hasFields(
+                    vtnNode,
+                    HOSTNAME,
+                    HOST_MANAGEMENT_IP,
+                    DATA_IP,
+                    DATA_IFACE,
+                    INTEGRATION_BRIDGE_ID);
+            result = result && isIpPrefix(vtnNode, HOST_MANAGEMENT_IP, MANDATORY);
+            result = result && isIpPrefix(vtnNode, DATA_IP, MANDATORY);
+
+            NetworkAddress localMgmt = NetworkAddress.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
+            NetworkAddress hostsMgmt = NetworkAddress.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
+            if (hostsMgmt.prefix().contains(localMgmt.prefix()) ||
+                    localMgmt.prefix().contains(hostsMgmt.prefix())) {
+                final String msg = "Host and local management network IP conflict";
+                throw new IllegalArgumentException(msg);
+            }
+        }
+
+        result = result && hasFields(
+                (ObjectNode) object.get(SSH),
+                SSH_PORT,
+                SSH_USER,
+                SSH_KEY_FILE);
+        result = result && isTpPort(
+                (ObjectNode) object.get(SSH),
+                SSH_PORT,
+                MANDATORY);
+
+        result = result && hasFields(
+                (ObjectNode) object.get(OPENSTACK),
+                ENDPOINT,
+                TENANT,
+                USER,
+                PASSWORD);
+
+        result = result && hasFields(
+                (ObjectNode) object.get(XOS),
+                ENDPOINT,
+                USER,
+                PASSWORD);
+
+        // check all optional fields are valid
+        result = result && isTpPort(OVSDB_PORT, OPTIONAL);
+
+        if (object.get(PUBLIC_GATEWAYS) != null && object.get(PUBLIC_GATEWAYS).isArray()) {
+            for (JsonNode node : object.get(PUBLIC_GATEWAYS)) {
+                ObjectNode gateway = (ObjectNode) node;
+                result = result && isIpAddress(gateway, GATEWAY_IP, MANDATORY);
+                result = result && isMacAddress(gateway, GATEWAY_MAC, MANDATORY);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the set of nodes read from network config.
+     *
+     * @return set of CordVtnNodeConfig or empty set
+     */
+    public Set<CordVtnNode> cordVtnNodes() {
+        Set<CordVtnNode> nodes = Sets.newHashSet();
+        JsonNode sshNode = object.get(SSH);
+        String ovsdbPort = getConfig(object, OVSDB_PORT);
+
+        object.get(CORDVTN_NODES).forEach(vtnNode -> {
+            NetworkAddress localMgmt = NetworkAddress.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
+            NetworkAddress hostsMgmt = NetworkAddress.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
+
+            SshAccessInfo sshInfo = new SshAccessInfo(
+                    hostsMgmt.ip().getIp4Address(),
+                    TpPort.tpPort(Integer.parseInt(getConfig(sshNode, SSH_PORT))),
+                    getConfig(sshNode, SSH_USER),
+                    getConfig(sshNode, SSH_KEY_FILE));
+
+            CordVtnNode.Builder nodeBuilder = CordVtnNode.builder()
+                    .hostname(getConfig(vtnNode, HOSTNAME))
+                    .hostMgmtIp(hostsMgmt)
+                    .localMgmtIp(localMgmt)
+                    .dataIp(getConfig(vtnNode, DATA_IP))
+                    .sshInfo(sshInfo)
+                    .integrationBridgeId(getConfig(vtnNode, INTEGRATION_BRIDGE_ID))
+                    .dataIface(getConfig(vtnNode, DATA_IFACE));
+
+            if (!Strings.isNullOrEmpty(ovsdbPort)) {
+                nodeBuilder.ovsdbPort(Integer.parseInt(ovsdbPort));
+            }
+
+            String hostMgmtIface = getConfig(vtnNode, HOST_MANAGEMENT_IFACE);
+            if (!Strings.isNullOrEmpty(hostMgmtIface)) {
+                nodeBuilder.hostMgmtIface(hostMgmtIface);
+            }
+
+            nodes.add(nodeBuilder.build());
+        });
+
+        return nodes;
+    }
+
+    /**
+     * Gets the specified property as a string.
+     *
+     * @param jsonNode node whose fields to get
+     * @param path property to get
+     * @return value as a string
+     */
+    private String getConfig(JsonNode jsonNode, String path) {
+        jsonNode = jsonNode.path(path);
+        return jsonNode.asText();
+    }
+
+    /**
+     * Returns private network gateway MAC address.
+     *
+     * @return mac address
+     */
+    public MacAddress privateGatewayMac() {
+        JsonNode jsonNode = object.get(PRIVATE_GATEWAY_MAC);
+        return MacAddress.valueOf(jsonNode.asText());
+    }
+
+    /**
+     * Returns public network gateway IP and MAC address pairs.
+     *
+     * @return map of ip and mac address
+     */
+    public Map<IpAddress, MacAddress> publicGateways() {
+        JsonNode jsonNodes = object.get(PUBLIC_GATEWAYS);
+        Map<IpAddress, MacAddress> publicGateways = Maps.newHashMap();
+
+        if (jsonNodes == null) {
+            return publicGateways;
+        }
+
+        jsonNodes.forEach(jsonNode -> publicGateways.put(
+                IpAddress.valueOf(jsonNode.path(GATEWAY_IP).asText()),
+                MacAddress.valueOf(jsonNode.path(GATEWAY_MAC).asText())));
+        return publicGateways;
+    }
+
+    // TODO add methods to get XOS and OpenStack API access
+}