Adding EVPN App code

Change-Id: Id3b2192f56f054cadcd8384092245b8757a781a9
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java
new file mode 100755
index 0000000..361bad4
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java
@@ -0,0 +1,290 @@
+/*
+ * 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.onosproject.evpnopenflow.rsc.vpninstance.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Sets;
+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.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.evpnopenflow.rsc.DefaultVpnInstance;
+import org.onosproject.evpnopenflow.rsc.VpnAfConfig;
+import org.onosproject.evpnopenflow.rsc.VpnInstance;
+import org.onosproject.evpnopenflow.rsc.VpnInstanceId;
+import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService;
+import org.onosproject.evpnopenflow.rsc.vpninstance.VpnInstanceService;
+import org.onosproject.incubator.net.routing.EvpnInstanceName;
+import org.onosproject.incubator.net.routing.RouteAdminService;
+import org.onosproject.incubator.net.routing.RouteDistinguisher;
+import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.COMMA;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DESCRIPTION;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_INSTANCE_START;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_INSTANCE_STOP;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ID;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INSTANCE_ID;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IPV4_FAMILY;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.JSON_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_DISTINGUISHERS;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_CREATION_FAILED;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_DELETE_FAILED;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_ID_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_IS_NOT_EXIST;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_NAME;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_STORE;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_UPDATE_FAILED;
+
+
+/**
+ * Provides implementation of the VpnInstance APIs.
+ */
+@Component(immediate = true)
+@Service
+public class VpnInstanceManager implements VpnInstanceService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    protected EventuallyConsistentMap<VpnInstanceId, VpnInstance> vpnInstanceStore;
+    protected ApplicationId appId;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected RouteAdminService routeService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VpnAfConfigService vpnAfConfigService;
+
+    @Activate
+    public void activate() {
+        appId = coreService.registerApplication(APP_ID);
+        KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+                .register(KryoNamespaces.API).register(VpnInstance.class)
+                .register(VpnInstanceId.class);
+        vpnInstanceStore = storageService
+                .<VpnInstanceId, VpnInstance>eventuallyConsistentMapBuilder()
+                .withName(VPN_INSTANCE_STORE).withSerializer(serializer)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .build();
+        log.info(EVPN_VPN_INSTANCE_START);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        vpnInstanceStore.destroy();
+        log.info(EVPN_VPN_INSTANCE_STOP);
+    }
+
+    @Override
+    public boolean exists(VpnInstanceId vpnInstanceId) {
+        checkNotNull(vpnInstanceId, VPN_INSTANCE_ID_NOT_NULL);
+        return vpnInstanceStore.containsKey(vpnInstanceId);
+    }
+
+    @Override
+    public VpnInstance getInstance(VpnInstanceId vpnInstanceId) {
+        checkNotNull(vpnInstanceId, VPN_INSTANCE_ID_NOT_NULL);
+        return vpnInstanceStore.get(vpnInstanceId);
+    }
+
+    @Override
+    public Collection<VpnInstance> getInstances() {
+        return Collections.unmodifiableCollection(vpnInstanceStore.values());
+    }
+
+    @Override
+    public boolean createInstances(Iterable<VpnInstance> vpnInstances) {
+        checkNotNull(vpnInstances, VPN_INSTANCE_NOT_NULL);
+        for (VpnInstance vpnInstance : vpnInstances) {
+            log.info(INSTANCE_ID, vpnInstance.id().toString());
+            vpnInstanceStore.put(vpnInstance.id(), vpnInstance);
+            if (!vpnInstanceStore.containsKey(vpnInstance.id())) {
+                log.info(VPN_INSTANCE_CREATION_FAILED,
+                         vpnInstance.id().toString());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean updateInstances(Iterable<VpnInstance> vpnInstances) {
+        checkNotNull(vpnInstances, VPN_INSTANCE_NOT_NULL);
+        for (VpnInstance vpnInstance : vpnInstances) {
+            if (!vpnInstanceStore.containsKey(vpnInstance.id())) {
+                log.info(VPN_INSTANCE_IS_NOT_EXIST,
+                         vpnInstance.id().toString());
+                return false;
+            }
+            vpnInstanceStore.put(vpnInstance.id(), vpnInstance);
+            if (!vpnInstance.equals(vpnInstanceStore.get(vpnInstance.id()))) {
+                log.info(VPN_INSTANCE_UPDATE_FAILED,
+                         vpnInstance.id().toString());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeInstances(Iterable<VpnInstanceId> vpnInstanceIds) {
+        checkNotNull(vpnInstanceIds, VPN_INSTANCE_ID_NOT_NULL);
+        for (VpnInstanceId vpnInstanceId : vpnInstanceIds) {
+            vpnInstanceStore.remove(vpnInstanceId);
+            if (vpnInstanceStore.containsKey(vpnInstanceId)) {
+                log.info(VPN_INSTANCE_DELETE_FAILED, vpnInstanceId.toString());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void processGluonConfig(String action, String key, JsonNode value) {
+        Collection<VpnInstance> vpnInstances;
+        switch (action) {
+            case DELETE:
+                String[] list = key.split(SLASH);
+                VpnInstanceId vpnInstanceId = VpnInstanceId
+                        .vpnInstanceId(list[list.length - 1]);
+                Set<VpnInstanceId> vpnInstanceIds
+                        = Sets.newHashSet(vpnInstanceId);
+                removeInstances(vpnInstanceIds);
+                break;
+            case SET:
+                checkNotNull(value, RESPONSE_NOT_NULL);
+                vpnInstances = changeJsonToSub(value);
+                createInstances(vpnInstances);
+                break;
+            case UPDATE:
+                checkNotNull(value, RESPONSE_NOT_NULL);
+                vpnInstances = changeJsonToSub(value);
+                updateInstances(vpnInstances);
+                break;
+            default:
+                log.info("Invalid action is received while processing VPN " +
+                                 "instance configuration");
+        }
+    }
+
+    @Override
+    public void updateImpExpRouteTargets(String routeTargetType,
+                                         Set<VpnRouteTarget> exportRouteTargets,
+                                         Set<VpnRouteTarget> importRouteTargets,
+                                         VpnRouteTarget vpnRouteTarget) {
+        switch (routeTargetType) {
+            case "export_extcommunity":
+                exportRouteTargets.add(vpnRouteTarget);
+                break;
+            case "import_extcommunity":
+                importRouteTargets.add(vpnRouteTarget);
+                break;
+            case "both":
+                exportRouteTargets.add(vpnRouteTarget);
+                importRouteTargets.add(vpnRouteTarget);
+                break;
+            default:
+                log.info("Invalid route target type has received");
+                break;
+        }
+    }
+
+    /**
+     * Returns a collection of vpnInstances from subnetNodes.
+     *
+     * @param vpnInstanceNodes the vpnInstance json node
+     * @return returns the collection of vpn instances
+     */
+    private Collection<VpnInstance> changeJsonToSub(JsonNode vpnInstanceNodes) {
+        checkNotNull(vpnInstanceNodes, JSON_NOT_NULL);
+
+        Set<VpnRouteTarget> exportRouteTargets = new HashSet<>();
+        Set<VpnRouteTarget> importRouteTargets = new HashSet<>();
+        Set<VpnRouteTarget> configRouteTargets = new HashSet<>();
+
+        Map<VpnInstanceId, VpnInstance> vpnInstanceMap = new HashMap<>();
+        VpnInstanceId id = VpnInstanceId
+                .vpnInstanceId(vpnInstanceNodes.get(ID).asText());
+        EvpnInstanceName name = EvpnInstanceName
+                .evpnName(vpnInstanceNodes.get(VPN_INSTANCE_NAME).asText());
+        String description = vpnInstanceNodes.get(DESCRIPTION).asText();
+        RouteDistinguisher routeDistinguisher = RouteDistinguisher
+                .routeDistinguisher(vpnInstanceNodes.get(ROUTE_DISTINGUISHERS)
+                                            .asText());
+        String routeTargets = vpnInstanceNodes.get(IPV4_FAMILY).asText();
+        String[] list = routeTargets.split(COMMA);
+
+        for (String routeTarget : list) {
+            // Converting route target string into route target object and
+            // then storing into configuration route target set.
+            VpnRouteTarget vpnRouteTarget
+                    = VpnRouteTarget.routeTarget(routeTarget);
+            configRouteTargets.add(vpnRouteTarget);
+            VpnAfConfig vpnAfConfig
+                    = vpnAfConfigService.getVpnAfConfig(vpnRouteTarget);
+            if (vpnAfConfig == null) {
+                log.info("Not able to find vpn af config for the give vpn " +
+                                 "route target");
+                break;
+            }
+            updateImpExpRouteTargets(vpnAfConfig.routeTargetType(),
+                                     exportRouteTargets,
+                                     importRouteTargets,
+                                     vpnRouteTarget);
+        }
+
+        VpnInstance vpnInstance = new DefaultVpnInstance(id, name, description,
+                                                         routeDistinguisher,
+                                                         exportRouteTargets,
+                                                         importRouteTargets,
+                                                         configRouteTargets);
+        vpnInstanceMap.put(id, vpnInstance);
+        return Collections.unmodifiableCollection(vpnInstanceMap.values());
+    }
+}
\ No newline at end of file