Adding EVPN App code

Change-Id: Id3b2192f56f054cadcd8384092245b8757a781a9
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigEvent.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigEvent.java
new file mode 100755
index 0000000..944698c
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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.vpnafconfig;
+
+import org.onosproject.event.AbstractEvent;
+import org.onosproject.evpnopenflow.rsc.VpnAfConfig;
+
+/**
+ * Describes network VPN af config event.
+ */
+public class VpnAfConfigEvent extends AbstractEvent<VpnAfConfigEvent.Type, VpnAfConfig> {
+
+    /**
+     * Type of VPN port events.
+     */
+    public enum Type {
+        /**
+         * Signifies that VPN af config has been set.
+         */
+        VPN_AF_CONFIG_SET,
+        /**
+         * Signifies that VPN af config has been deleted.
+         */
+        VPN_AF_CONFIG_DELETE,
+        /**
+         * Signifies that VPN af config has been updated.
+         */
+        VPN_AF_CONFIG_UPDATE
+    }
+
+    /**
+     * Creates an event of a given type and for the specified VPN af config.
+     *
+     * @param type        VPN af config type
+     * @param vpnAfConfig VPN af config subject
+     */
+    public VpnAfConfigEvent(Type type, VpnAfConfig vpnAfConfig) {
+        super(type, vpnAfConfig);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified VPN af config.
+     *
+     * @param type        VPN af config type
+     * @param vpnAfConfig VPN af config subject
+     * @param time        occurrence time
+     */
+    public VpnAfConfigEvent(Type type, VpnAfConfig vpnAfConfig, long time) {
+        super(type, vpnAfConfig, time);
+    }
+}
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigListener.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigListener.java
new file mode 100755
index 0000000..42db841
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.vpnafconfig;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Entity capable of VPN af config related events.
+ */
+public interface VpnAfConfigListener extends EventListener<VpnAfConfigEvent> {
+}
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java
new file mode 100755
index 0000000..31714ad
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java
@@ -0,0 +1,100 @@
+/*
+ * 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.vpnafconfig;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.onosproject.evpnopenflow.rsc.VpnAfConfig;
+import org.onosproject.incubator.net.routing.VpnRouteTarget;
+
+import java.util.Collection;
+
+/**
+ * Service for interacting with the inventory of VPN af config instance.
+ */
+public interface VpnAfConfigService {
+    /**
+     * Returns if the route target is existed.
+     *
+     * @param routeTarget route target
+     * @return true or false if one with the given route target is not existed.
+     */
+    boolean exists(VpnRouteTarget routeTarget);
+
+    /**
+     * Returns the VPN af config with the route target.
+     *
+     * @param routeTarget route target
+     * @return VPN af config or null if one with the given route target is not
+     * know.
+     */
+    VpnAfConfig getVpnAfConfig(VpnRouteTarget routeTarget);
+
+    /**
+     * Returns the collection of the currently known VPN af configurations.
+     *
+     * @return collection of VPN af configurations.
+     */
+    Collection<VpnAfConfig> getVpnAfConfigs();
+
+    /**
+     * Creates VPN af configurations by vpnAfConfigs.
+     *
+     * @param vpnAfConfigs the iterable collection of vpnAfConfigs
+     * @return true if all given VPN af configs created successfully
+     */
+    boolean createVpnAfConfigs(Iterable<VpnAfConfig> vpnAfConfigs);
+
+    /**
+     * Updates VPN af configurations by vpnAfConfigs.
+     *
+     * @param vpnAfConfigs the iterable collection of vpnAfConfigs
+     * @return true if all given VPN af configs created successfully.
+     */
+    boolean updateVpnAfConfigs(Iterable<VpnAfConfig> vpnAfConfigs);
+
+    /**
+     * Deletes vpnAfConfigs by route target.
+     *
+     * @param routeTarget the iterable collection of vpnAFConfigs
+     * @return true or false if one with the given route target to delete is
+     * successfully
+     */
+    boolean removeVpnAfConfigs(Iterable<VpnRouteTarget> routeTarget);
+
+    /**
+     * process gluon config for vpn af configuration.
+     *
+     * @param action can be either update or delete
+     * @param key    can contain the id and also target information
+     * @param value  content of the route targets configuration
+     */
+    void processGluonConfig(String action, String key, JsonNode value);
+
+    /**
+     * Adds the specified listener to Vpn Port manager.
+     *
+     * @param listener vpn af config listener
+     */
+    void addListener(VpnAfConfigListener listener);
+
+    /**
+     * Removes the specified listener to vpn af config manager.
+     *
+     * @param listener vpn af config listener
+     */
+    void removeListener(VpnAfConfigListener listener);
+}
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java
new file mode 100755
index 0000000..fafd5d8
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java
@@ -0,0 +1,268 @@
+/*
+ * 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.vpnafconfig.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.CoreService;
+import org.onosproject.evpnopenflow.rsc.DefaultVpnAfConfig;
+import org.onosproject.evpnopenflow.rsc.VpnAfConfig;
+import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigEvent;
+import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigListener;
+import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService;
+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.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.DELETE;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVENT_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_AF_CONFIG_START;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_VPN_AF_CONFIG_STOP;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EXPORT_ROUTE_POLICY;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IMPORT_ROUTE_POLICY;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_ACTION_VPN_AF_CONFIG;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.JSON_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.LISTENER_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RESPONSE_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_TARGET_CANNOT_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_TARGET_DELETE_FAILED;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_TARGET_VALUE;
+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_AF_CONFIG_CREATION_FAILED;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_IS_NOT_EXIST;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_STORE;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_CONFIG_UPDATE_FAILED;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_ID_NOT_NULL;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VRF_RT_TYPE;
+import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VRF_RT_VALUE;
+
+/**
+ * Provides implementation of the VPN af config APIs.
+ */
+@Component(immediate = true)
+@Service
+public class VpnAfConfigManager implements VpnAfConfigService {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final Set<VpnAfConfigListener> listeners = Sets
+            .newCopyOnWriteArraySet();
+
+    protected EventuallyConsistentMap<VpnRouteTarget, VpnAfConfig>
+            vpnAfConfigStore;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Activate
+    public void activate() {
+        coreService.registerApplication(APP_ID);
+        KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+                .register(KryoNamespaces.API).register(VpnAfConfig.class)
+                .register(VpnRouteTarget.class);
+        vpnAfConfigStore = storageService
+                .<VpnRouteTarget, VpnAfConfig>eventuallyConsistentMapBuilder()
+                .withName(VPN_AF_CONFIG_STORE).withSerializer(serializer)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .build();
+        log.info(EVPN_VPN_AF_CONFIG_START);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        vpnAfConfigStore.destroy();
+        log.info(EVPN_VPN_AF_CONFIG_STOP);
+    }
+
+    @Override
+    public boolean exists(VpnRouteTarget routeTarget) {
+        checkNotNull(routeTarget, ROUTE_TARGET_CANNOT_NOT_NULL);
+        return vpnAfConfigStore.containsKey(routeTarget);
+    }
+
+    @Override
+    public VpnAfConfig getVpnAfConfig(VpnRouteTarget routeTarget) {
+        checkNotNull(routeTarget, ROUTE_TARGET_CANNOT_NOT_NULL);
+        return vpnAfConfigStore.get(routeTarget);
+    }
+
+    @Override
+    public Collection<VpnAfConfig> getVpnAfConfigs() {
+        return Collections.unmodifiableCollection(vpnAfConfigStore.values());
+    }
+
+    @Override
+    public boolean createVpnAfConfigs(Iterable<VpnAfConfig> vpnAfConfigs) {
+        checkNotNull(vpnAfConfigs, VPN_AF_CONFIG_NOT_NULL);
+        for (VpnAfConfig vpnAfConfig : vpnAfConfigs) {
+            log.info(ROUTE_TARGET_VALUE, vpnAfConfig
+                    .routeTarget().getRouteTarget());
+            vpnAfConfigStore.put(vpnAfConfig.routeTarget(), vpnAfConfig);
+            if (!vpnAfConfigStore.containsKey(vpnAfConfig.routeTarget())) {
+                log.info(VPN_AF_CONFIG_CREATION_FAILED,
+                         vpnAfConfig.routeTarget().getRouteTarget());
+                return false;
+            }
+            notifyListeners(new VpnAfConfigEvent(VpnAfConfigEvent
+                                                         .Type
+                                                         .VPN_AF_CONFIG_SET,
+                                                 vpnAfConfig));
+        }
+        return true;
+    }
+
+    @Override
+    public boolean updateVpnAfConfigs(Iterable<VpnAfConfig> vpnAfConfigs) {
+        checkNotNull(vpnAfConfigs, VPN_AF_CONFIG_NOT_NULL);
+        for (VpnAfConfig vpnAfConfig : vpnAfConfigs) {
+            if (!vpnAfConfigStore.containsKey(vpnAfConfig.routeTarget())) {
+                log.info(VPN_AF_CONFIG_IS_NOT_EXIST,
+                         vpnAfConfig.routeTarget().getRouteTarget());
+                return false;
+            }
+            vpnAfConfigStore.put(vpnAfConfig.routeTarget(), vpnAfConfig);
+            if (!vpnAfConfig.equals(vpnAfConfigStore
+                                            .get(vpnAfConfig.routeTarget()))) {
+                log.info(VPN_AF_CONFIG_UPDATE_FAILED,
+                         vpnAfConfig.routeTarget().getRouteTarget());
+                return false;
+            }
+            notifyListeners(new VpnAfConfigEvent(VpnAfConfigEvent
+                                                         .Type
+                                                         .VPN_AF_CONFIG_UPDATE,
+                                                 vpnAfConfig));
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeVpnAfConfigs(Iterable<VpnRouteTarget> routeTargets) {
+        checkNotNull(routeTargets, VPN_INSTANCE_ID_NOT_NULL);
+        for (VpnRouteTarget routeTarget : routeTargets) {
+            VpnAfConfig vpnAfConfig = vpnAfConfigStore.get(routeTarget);
+            vpnAfConfigStore.remove(routeTarget);
+            if (vpnAfConfigStore.containsKey(routeTarget)) {
+                log.info(ROUTE_TARGET_DELETE_FAILED,
+                         routeTarget.getRouteTarget());
+                return false;
+            }
+            notifyListeners(new VpnAfConfigEvent(VpnAfConfigEvent
+                                                         .Type
+                                                         .VPN_AF_CONFIG_DELETE,
+                                                 vpnAfConfig));
+        }
+        return true;
+    }
+
+    @Override
+    public void processGluonConfig(String action, String key, JsonNode value) {
+        Collection<VpnAfConfig> vpnAfConfigs;
+        switch (action) {
+            case DELETE:
+                String[] list = key.split(SLASH);
+                VpnRouteTarget routeTarget = VpnRouteTarget
+                        .routeTarget(list[list.length - 1]);
+                Set<VpnRouteTarget> routeTargets
+                        = Sets.newHashSet(routeTarget);
+                removeVpnAfConfigs(routeTargets);
+                break;
+            case SET:
+                checkNotNull(value, RESPONSE_NOT_NULL);
+                vpnAfConfigs = changeJsonToSub(value);
+                createVpnAfConfigs(vpnAfConfigs);
+                break;
+            case UPDATE:
+                checkNotNull(value, RESPONSE_NOT_NULL);
+                vpnAfConfigs = changeJsonToSub(value);
+                updateVpnAfConfigs(vpnAfConfigs);
+                break;
+            default:
+                log.info(INVALID_ACTION_VPN_AF_CONFIG);
+                break;
+        }
+    }
+
+    /**
+     * Returns a collection of vpn af configuration.
+     *
+     * @param vpnAfConfigNode the vpn af configuration json node
+     * @return returns the collection of vpn af configuration
+     */
+    private Collection<VpnAfConfig> changeJsonToSub(JsonNode vpnAfConfigNode) {
+        checkNotNull(vpnAfConfigNode, JSON_NOT_NULL);
+        Map<VpnRouteTarget, VpnAfConfig> vpnAfConfigMap = new HashMap<>();
+        String exportRoutePolicy
+                = vpnAfConfigNode.get(EXPORT_ROUTE_POLICY).asText();
+        String importRoutePolicy
+                = vpnAfConfigNode.get(IMPORT_ROUTE_POLICY).asText();
+        String routeTargetType = vpnAfConfigNode.get(VRF_RT_TYPE).asText();
+        VpnRouteTarget routeTarget = VpnRouteTarget
+                .routeTarget(vpnAfConfigNode.get(VRF_RT_VALUE).asText());
+
+        VpnAfConfig vpnAfConfig = new DefaultVpnAfConfig(exportRoutePolicy,
+                                                         importRoutePolicy,
+                                                         routeTarget,
+                                                         routeTargetType);
+        vpnAfConfigMap.put(routeTarget, vpnAfConfig);
+
+        return Collections.unmodifiableCollection(vpnAfConfigMap.values());
+    }
+
+    @Override
+    public void addListener(VpnAfConfigListener listener) {
+        checkNotNull(listener, LISTENER_NOT_NULL);
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeListener(VpnAfConfigListener listener) {
+        checkNotNull(listener, LISTENER_NOT_NULL);
+        listeners.remove(listener);
+    }
+
+    /**
+     * Notifies specify event to all listeners.
+     *
+     * @param event vpn af config event
+     */
+    private void notifyListeners(VpnAfConfigEvent event) {
+        checkNotNull(event, EVENT_NOT_NULL);
+        listeners.forEach(listener -> listener.event(event));
+    }
+}
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/package-info.java
new file mode 100755
index 0000000..f2dd128
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * VPN af configuration that used by l3vpn.
+ */
+package org.onosproject.evpnopenflow.rsc.vpnafconfig.impl;
\ No newline at end of file
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/package-info.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/package-info.java
new file mode 100755
index 0000000..7c2e4f4
--- /dev/null
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * VPN resources that used by Evpn.
+ */
+package org.onosproject.evpnopenflow.rsc.vpnafconfig;