http notifier and device providers
diff --git a/apps/fpcagent/BUCK b/apps/fpcagent/BUCK
index 4396a00..effa245 100644
--- a/apps/fpcagent/BUCK
+++ b/apps/fpcagent/BUCK
@@ -2,15 +2,14 @@
     '//lib:CORE_DEPS',
     '//lib:JACKSON',
     '//lib:KRYO',
-    '//models/fpcagent:onos-models-fpcagent',
-    '//models/common:onos-models-common',
     '//lib:onos-yang-model',
-    '//apps/config:onos-apps-config',
-    '//core/api:onos-api',
-    '//lib:javax.ws.rs-api',
-    '//utils/rest:onlab-rest',
+    '//lib:httpclient-osgi',
+    '//lib:httpcore-osgi',
     '//core/store/serializers:onos-core-serializers',
     '//apps/restconf/utils:onos-apps-restconf-utils',
+    '//apps/config:onos-apps-config',
+    '//models/fpcagent:onos-models-fpcagent',
+    '//models/common:onos-models-common',
     ':zeromq',
     ':json',
 ]
@@ -23,6 +22,8 @@
 
 BUNDLES = [
     '//apps/fpcagent:onos-apps-fpcagent',
+    '//lib:httpclient-osgi',
+    '//lib:httpcore-osgi',
 ]
 
 EXCLUDED_BUNDLES = [
@@ -51,6 +52,7 @@
     url = 'http://onosproject.org',
     description = 'FPC Agent YANG Application',
     required_apps = APPS,
+    included_bundles = BUNDLES,
     excluded_bundles = EXCLUDED_BUNDLES,
 )
 
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
index ba2f989..4ae0847 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
@@ -18,12 +18,16 @@
 
 import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.*;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.DynamicConfigListener;
 import org.onosproject.config.DynamicConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
-import org.onosproject.fpcagent.providers.DpnProviderService;
+import org.onosproject.core.IdGenerator;
 import org.onosproject.fpcagent.providers.DpnDeviceListener;
+import org.onosproject.fpcagent.providers.DpnProviderService;
 import org.onosproject.fpcagent.util.ConfigHelper;
+import org.onosproject.fpcagent.workers.HTTPNotifier;
 import org.onosproject.fpcagent.workers.ZMQSBPublisherManager;
 import org.onosproject.fpcagent.workers.ZMQSBSubscriberManager;
 import org.onosproject.net.config.*;
@@ -36,6 +40,7 @@
 import java.util.HashSet;
 import java.util.Optional;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.fpcagent.util.FpcUtil.FPC_APP_ID;
 
 /**
@@ -50,6 +55,9 @@
     private final InternalNetworkConfigListener configListener =
             new InternalNetworkConfigListener();
 
+    private final InternalConfigListener dynListener =
+            new InternalConfigListener();
+
     /* Services */
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private FpcRpcService fpcRpcService;
@@ -76,6 +84,7 @@
     private DpnProviderService dpnProviderService;
 
     /* Variables */
+    private IdGenerator notificationIds;
     private FpcConfig fpcConfig;
     private boolean started = false;
     private HashSet<DpnDeviceListener> listeners = Sets.newHashSet();
@@ -95,6 +104,11 @@
         coreService.registerApplication(FPC_APP_ID);
         configService.addListener(configListener);
         registry.registerConfigFactory(fpcConfigConfigFactory);
+        dynamicConfigService.addListener(dynListener);
+
+        notificationIds = coreService.getIdGenerator("fpc-notification-ids");
+
+        HTTPNotifier.getInstance().open();
 
         log.info("FPC Service Started");
     }
@@ -102,6 +116,7 @@
     @Deactivate
     protected void deactivate() {
         configService.removeListener(configListener);
+        dynamicConfigService.removeListener(dynListener);
         registry.unregisterConfigFactory(fpcConfigConfigFactory);
 
         if (started) {
@@ -110,7 +125,9 @@
             started = false;
         }
 
-        log.info("FPC Servicea Stopped");
+        HTTPNotifier.getInstance().close();
+
+        log.info("FPC Service Stopped");
     }
 
     /**
@@ -184,4 +201,16 @@
         }
 
     }
+
+    /**
+     * Representation of internal listener, listening for dynamic config event.
+     */
+    private class InternalConfigListener implements DynamicConfigListener {
+
+        @Override
+        public void event(DynamicConfigEvent event) {
+            checkNotNull(event, "Event cannot be NULL");
+            log.debug("event {}", event);
+        }
+    }
 }
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
index 61aa4bd..f9b7d36 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
@@ -16,7 +16,11 @@
 
 package org.onosproject.fpcagent;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.felix.scr.annotations.*;
@@ -24,12 +28,20 @@
 import org.onlab.packet.Ip4Prefix;
 import org.onosproject.config.DynamicConfigService;
 import org.onosproject.config.DynamicConfigStore;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
 import org.onosproject.fpcagent.protocols.DpnCommunicationService;
 import org.onosproject.fpcagent.protocols.DpnNgicCommunicator;
 import org.onosproject.fpcagent.protocols.DpnP4Communicator;
+import org.onosproject.fpcagent.providers.CpProviderService;
 import org.onosproject.fpcagent.util.CacheManager;
 import org.onosproject.fpcagent.util.FpcUtil;
+import org.onosproject.fpcagent.workers.HTTPNotifier;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.device.DeviceStore;
+import org.onosproject.restconf.utils.RestconfUtils;
 import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.DefaultConnectionInfo;
 import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.P4DpnControlProtocol;
 import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.ZmqDpnControlProtocol;
@@ -48,6 +60,7 @@
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configurebundles.configurebundlesoutput.DefaultBundles;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configuredpn.DefaultConfigureDpnInput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configuredpn.DefaultConfigureDpnOutput;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.dpnstatusvalue.DpnStatusEnum;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.instructions.Instructions;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.instructions.instructions.instrtype.Instr3GppMob;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.opinput.opbody.CreateOrUpdate;
@@ -66,6 +79,7 @@
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpcmobility.ContextsKeys;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpcmobility.DefaultContexts;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpctopology.DefaultDpns;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.yangautoprefixnotify.value.DefaultDpnAvailability;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcContextId;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcDpnControlProtocol;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcDpnId;
@@ -81,14 +95,14 @@
 import java.math.BigInteger;
 import java.time.Duration;
 import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Optional;
+import java.util.*;
 import java.util.concurrent.*;
 
 import static org.onosproject.fpcagent.util.Converter.convertContext;
 import static org.onosproject.fpcagent.util.FpcUtil.*;
 
+//import org.onosproject.fpcagent.workers.HTTPNotifier;
+
 @Component(immediate = true)
 @Service
 public class FpcRpcManager implements FpcRpcService, IetfDmmFpcagentService, org.onosproject.yang.gen.v1.fpc.rev20150105.FpcService {
@@ -105,29 +119,49 @@
     private DynamicConfigStore dynamicConfigStore;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    private RpcRegistry registry;
+    private RpcRegistry rpcRegistry;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private DeviceStore deviceStore;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private CpProviderService cpProviderService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private DeviceService deviceService;
+
+    private InternalDeviceListener listener = new InternalDeviceListener();
     private ConcurrentMap<ClientIdentifier, DefaultRegisterClientInput> clientInfo = Maps.newConcurrentMap();
+    private ConcurrentMap<FpcIdentity, HashSet<ClientIdentifier>> tenantInfo = Maps.newConcurrentMap();
+    private HashMap<FpcDpnId, org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpctopology.Dpns> dpnInfo = Maps.newHashMap();
+
     // FIXME configurable
     private ExecutorService executorService = Executors.newFixedThreadPool(25);
+    private IdGenerator notificationIds;
 
     @Activate
     protected void activate() {
         init();
-        registry.registerRpcService(this);
+        rpcRegistry.registerRpcService(this);
+        deviceService.addListener(listener);
         log.info("FPC RPC Service Started");
     }
 
     @Deactivate
     protected void deactivate() {
-        registry.unregisterRpcService(this);
+        deviceService.removeListener(listener);
+        rpcRegistry.unregisterRpcService(this);
+        clientInfo.clear();
+        tenantInfo.clear();
+        dpnInfo.clear();
         log.info("FPC RPC Service Stopped");
     }
 
     private void init() {
+        notificationIds = coreService.getIdGenerator("fpc-notification-ids");
         FpcUtil.modelConverter = modelConverter;
         FpcUtil.dynamicConfigService = dynamicConfigService;
         FpcUtil.deviceStore = deviceStore;
@@ -176,7 +210,7 @@
             defaultCommonSuccess.addToContexts(context);
 
             // check if mobility exists and if the context id exists.
-            if (CacheManager.getInstance(tenantId).contextsCache.get(context.contextId()).isPresent()) {
+            if (cacheManager.contextsCache.get(context.contextId()).isPresent()) {
                 // throw exception if trying to create a Context that already exists.
                 throw new RuntimeException("Context tried to create already exists. Please issue update operation..");
             }
@@ -871,6 +905,9 @@
                         throw new RuntimeException("Client already registered.");
                     }
                     clientInfo.put(input.clientId(), input);
+                    HashSet<ClientIdentifier> hashSet = tenantInfo.getOrDefault(input.tenantId(), Sets.newHashSet());
+                    hashSet.add(input.clientId());
+                    tenantInfo.put(input.tenantId(), hashSet);
                     registerClientOutput.clientId(input.clientId());
                     registerClientOutput.supportedFeatures(input.supportedFeatures());
                     registerClientOutput.endpointUri(input.endpointUri());
@@ -879,6 +916,12 @@
 
                     DefaultConnections defaultConnections = new DefaultConnections();
                     defaultConnections.clientId(input.clientId().toString());
+                    // TODO add all fields
+
+                    cpProviderService.getListener().deviceAdded(
+                            input.clientId().toString(),
+                            input.endpointUri().toString()
+                    );
 
                     ModelObjectId modelObjectId = ModelObjectId.builder()
                             .addChild(DefaultConnectionInfo.class)
@@ -917,6 +960,8 @@
                     clientInfo.remove(input.clientId());
                     deregisterClientOutput.clientId(input.clientId());
 
+                    cpProviderService.getListener().deviceRemoved(input.clientId().toString());
+
                     DefaultConnections defaultConnections = new DefaultConnections();
                     defaultConnections.clientId(input.clientId().toString());
 
@@ -946,4 +991,112 @@
         }, executorService).join();
     }
 
+    private void sendNotification(DefaultYangAutoPrefixNotify notify, ClientIdentifier client) {
+        ResourceData dataNode = modelConverter.createDataNode(
+                DefaultModelObjectData.builder()
+                        .addModelObject(notify)
+                        .build()
+        );
+        ObjectNode jsonNodes = RestconfUtils.convertDataNodeToJson(notification, dataNode.dataNodes().get(0));
+        ObjectMapper mapper = new ObjectMapper();
+
+        try {
+            log.info("Sending HTTP notification {} to {}", notify, client);
+            HTTPNotifier.getInstance().send(
+                    new AbstractMap.SimpleEntry<>(
+                            clientInfo.get(client).endpointUri().toString(),
+                            mapper.writeValueAsString(jsonNodes)
+                    )
+            );
+        } catch (JsonProcessingException e) {
+            log.error(ExceptionUtils.getFullStackTrace(e));
+        }
+    }
+
+    public class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            if (event.subject().manufacturer().equals("fpc")) {
+                switch (event.type()) {
+                    case DEVICE_UPDATED:
+                    case DEVICE_ADDED: {
+                        tenantInfo.forEach(
+                                (tenantId, clients) -> {
+                                    Optional<DefaultTenant> defaultTenant = getTenant(tenantId);
+                                    if (defaultTenant.isPresent()) {
+                                        DefaultTenant tenant = defaultTenant.get();
+                                        if (tenant.fpcTopology().dpns() != null) {
+                                            tenant.fpcTopology().dpns().forEach(dpn -> {
+                                                        if (!dpnInfo.containsKey(dpn.dpnId())) {
+                                                            DefaultYangAutoPrefixNotify notify = new DefaultYangAutoPrefixNotify();
+                                                            notify.notificationId(NotificationId.of(notificationIds.getNewId()));
+
+                                                            notify.timestamp(BigInteger.valueOf(System.currentTimeMillis()));
+                                                            DefaultDpnAvailability availability = new DefaultDpnAvailability();
+                                                            availability.availabilityMessageType("Dpn-Availability");
+                                                            availability.dpnId(dpn.dpnId());
+                                                            availability.dpnGroups(dpn.dpnGroups());
+                                                            availability.controlProtocol(dpn.controlProtocol());
+                                                            availability.networkId(dpn.networkId());
+                                                            availability.nodeId(dpn.nodeId());
+                                                            availability.dpnName(dpn.dpnName());
+                                                            availability.dpnStatus(DpnStatusEnum.AVAILABLE);
+
+                                                            notify.value(availability);
+
+                                                            clients.forEach(client -> sendNotification(notify, client));
+                                                            dpnInfo.put(dpn.dpnId(), dpn);
+                                                        }
+                                                    }
+                                            );
+                                        }
+                                    }
+                                }
+                        );
+                        break;
+                    }
+                    case DEVICE_AVAILABILITY_CHANGED:
+                    case DEVICE_REMOVED: {
+                        String[] s = event.subject().id().toString().split(":")[1].split("/");
+                        tenantInfo.forEach(
+                                (tenantId, clients) -> {
+                                    Optional<DefaultTenant> defaultTenant = getTenant(tenantId);
+                                    if (defaultTenant.isPresent()) {
+                                        DefaultTenant tenant = defaultTenant.get();
+                                        if (tenant.fpcTopology().dpns() != null) {
+                                            tenant.fpcTopology().dpns().forEach(dpn -> {
+                                                        if (dpn.networkId().equals(s[1]) && dpn.nodeId().equals(s[0]) &&
+                                                                dpnInfo.containsKey(dpn.dpnId())) {
+                                                            DefaultYangAutoPrefixNotify notify = new DefaultYangAutoPrefixNotify();
+                                                            notify.notificationId(NotificationId.of(notificationIds.getNewId()));
+
+                                                            notify.timestamp(BigInteger.valueOf(System.currentTimeMillis()));
+                                                            DefaultDpnAvailability availability = new DefaultDpnAvailability();
+                                                            availability.availabilityMessageType("Dpn-Availability");
+                                                            availability.dpnId(dpn.dpnId());
+                                                            availability.dpnGroups(dpn.dpnGroups());
+                                                            availability.controlProtocol(dpn.controlProtocol());
+                                                            availability.networkId(dpn.networkId());
+                                                            availability.nodeId(dpn.nodeId());
+                                                            availability.dpnName(dpn.dpnName());
+                                                            availability.dpnStatus(DpnStatusEnum.UNAVAILABLE);
+
+                                                            notify.value(availability);
+
+                                                            clients.forEach(client -> sendNotification(notify, client));
+                                                            dpnInfo.remove(dpn.dpnId());
+                                                        }
+                                                    }
+                                            );
+                                        }
+                                    }
+                                }
+                        );
+                        break;
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpDeviceListener.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpDeviceListener.java
new file mode 100644
index 0000000..d9bc09d
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpDeviceListener.java
@@ -0,0 +1,23 @@
+/*
+ * 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.fpcagent.providers;
+
+public interface CpDeviceListener {
+    void deviceAdded(String id, String address);
+
+    void deviceRemoved(String id);
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpProvider.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpProvider.java
new file mode 100644
index 0000000..c26e787
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpProvider.java
@@ -0,0 +1,113 @@
+/*
+ * 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.fpcagent.providers;
+
+import org.apache.felix.scr.annotations.*;
+import org.onlab.packet.ChassisId;
+import org.onosproject.net.*;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceProviderRegistry;
+import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.slf4j.Logger;
+
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ *
+ */
+@Component(immediate = true)
+@Service
+public class CpProvider extends AbstractProvider implements CpProviderService {
+
+    private static final Logger log = getLogger(CpProvider.class);
+    private final InternalDeviceListener listener = new InternalDeviceListener();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceProviderRegistry providerRegistry;
+
+    private DeviceProviderService providerService;
+
+    public CpProvider() {
+        super(new ProviderId("cp", "org.onosproject.providers.cp"));
+    }
+
+    @Activate
+    public void activate() {
+        providerService = providerRegistry.register(this);
+        log.info("FPC Device Provider Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        providerRegistry.unregister(this);
+        providerService = null;
+        log.info("FPC Device Provider Stopped");
+    }
+
+    public InternalDeviceListener getListener() {
+        return listener;
+    }
+
+    @Override
+    public void triggerProbe(DeviceId deviceId) {
+
+    }
+
+    @Override
+    public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
+
+    }
+
+    @Override
+    public boolean isReachable(DeviceId deviceId) {
+        return true;
+    }
+
+    @Override
+    public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) {
+
+    }
+
+    public class InternalDeviceListener implements CpDeviceListener {
+
+        @Override
+        public void deviceAdded(String id, String address) {
+            DeviceId deviceId = deviceId("cp:" + id);
+            ChassisId chassisId = new ChassisId(deviceId.hashCode());
+
+            Device.Type type = Device.Type.OTHER;
+            SparseAnnotations annotations = DefaultAnnotations.builder()
+                    .set(AnnotationKeys.NAME, id)
+                    .set(AnnotationKeys.PROTOCOL, "RESTCONF")
+                    .set(AnnotationKeys.MANAGEMENT_ADDRESS, address)
+                    .build();
+            DeviceDescription descriptionBase = new DefaultDeviceDescription(deviceId.uri(), type, "cp", "0.1", "0.1", id, chassisId),
+                    description = new DefaultDeviceDescription(descriptionBase, annotations);
+
+            providerService.deviceConnected(deviceId, description);
+        }
+
+        @Override
+        public void deviceRemoved(String id) {
+            providerService.deviceDisconnected(deviceId("cp:" + id));
+        }
+    }
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpProviderService.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpProviderService.java
new file mode 100644
index 0000000..67c2a35
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/providers/CpProviderService.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.fpcagent.providers;
+
+import org.onosproject.net.device.DeviceProvider;
+
+public interface CpProviderService extends DeviceProvider {
+
+    CpDeviceListener getListener();
+
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
index c3fa25a..25c0312 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
@@ -51,8 +51,9 @@
     public static ResourceId tenants;
     public static ResourceId configureBundles;
     public static ResourceId registerClient;
-    public static ResourceId deregisterClinet;
+    public static ResourceId deregisterClient;
     public static ResourceId module;
+    public static ResourceId notification;
 
     /**
      * Returns resource id from model converter.
@@ -88,12 +89,12 @@
 
         configureDpn = ResourceId.builder()
                 .addBranchPointSchema("/", null)
-                .addBranchPointSchema("Configure-dpn", "urn:ietf:params:xml:ns:yang:fpcagent")
+                .addBranchPointSchema("configure-dpn", "urn:ietf:params:xml:ns:yang:fpcagent")
                 .build();
 
         configureBundles = ResourceId.builder()
                 .addBranchPointSchema("/", null)
-                .addBranchPointSchema("Configure-bundles", "urn:ietf:params:xml:ns:yang:fpcagent")
+                .addBranchPointSchema("configure-bundles", "urn:ietf:params:xml:ns:yang:fpcagent")
                 .build();
 
         registerClient = ResourceId.builder()
@@ -101,10 +102,15 @@
                 .addBranchPointSchema("register-client", "urn:onos:params:xml:ns:yang:fpc")
                 .build();
 
-        deregisterClinet = ResourceId.builder()
+        deregisterClient = ResourceId.builder()
                 .addBranchPointSchema("/", null)
                 .addBranchPointSchema("deregister-client", "urn:onos:params:xml:ns:yang:fpc")
                 .build();
+
+        notification = ResourceId.builder()
+                .addBranchPointSchema("/", null)
+                .addBranchPointSchema("notify", "urn:onos:params:xml:ns:yang:fpcagent")
+                .build();
     }
 
     /**
@@ -171,7 +177,7 @@
      * Gets the mapping for node id / network id to ZMQ Topic
      *
      * @param key - Concatenation of node id + / + network id
-     * @return - ZMQ Topic
+     * @return ZMQ Topic
      */
     public static byte getTopicFromNode(String key) {
         // TODO add cache
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/HTTPNotifier.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/HTTPNotifier.java
new file mode 100644
index 0000000..995d6f3
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/HTTPNotifier.java
@@ -0,0 +1,88 @@
+/*
+ * 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.fpcagent.workers;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class HTTPNotifier implements AutoCloseable {
+    private static final Logger log = LoggerFactory.getLogger(HTTPNotifier.class);
+    private static HTTPNotifier _instance = null;
+    private final BlockingQueue<Map.Entry<String, String>> blockingQueue;
+    private boolean run;
+
+    protected HTTPNotifier() {
+        this.run = true;
+        this.blockingQueue = new LinkedBlockingQueue<>();
+    }
+
+    public static HTTPNotifier getInstance() {
+        if (_instance == null) {
+            _instance = new HTTPNotifier();
+        }
+        return _instance;
+    }
+
+    public void send(Map.Entry<String, String> buf) {
+        try {
+            blockingQueue.put(buf);
+        } catch (InterruptedException e) {
+            log.error(ExceptionUtils.getFullStackTrace(e));
+        }
+    }
+
+    public void open() {
+        ExecutorService executorService = Executors.newSingleThreadExecutor();
+        executorService.submit(() -> {
+            while ((!Thread.currentThread().isInterrupted()) && run) {
+                try {
+                    Map.Entry<String, String> entry = blockingQueue.take();
+
+                    CloseableHttpClient client = HttpClients.createDefault();
+                    HttpPost httpPost = new HttpPost(entry.getKey());
+                    httpPost.addHeader("User-Agent", "ONOS Notification Agent");
+                    httpPost.addHeader("Charset", "utf-8");
+                    httpPost.addHeader("Content-type", "application/json");
+                    StringEntity params = new StringEntity(entry.getValue());
+                    httpPost.setEntity(params);
+                    HttpResponse response = client.execute(httpPost);
+
+                    log.info("Response {}", response);
+                } catch (Exception e) {
+                    log.error(ExceptionUtils.getFullStackTrace(e));
+                }
+            }
+        });
+    }
+
+    @Override
+    public void close() {
+        run = false;
+    }
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/ZMQSBSubscriberManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/ZMQSBSubscriberManager.java
index 5cd5028..a8e93e4 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/ZMQSBSubscriberManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/workers/ZMQSBSubscriberManager.java
@@ -160,6 +160,7 @@
                 short nodeIdLen = buf[18];
                 short networkIdLen = buf[19 + nodeIdLen];
                 String key = new String(Arrays.copyOfRange(buf, 19, 19 + nodeIdLen)) + "/" + new String(Arrays.copyOfRange(buf, 20 + nodeIdLen, 20 + nodeIdLen + networkIdLen));
+
 //                return uplinkDpnMap.get(key) == null ? null : new AbstractMap.SimpleEntry<>(uplinkDpnMap.get(key), processDDN(buf, key));
             } else if (type.equals(s11MsgType.DPN_STATUS_INDICATION)) {
                 DpnStatusIndication status;
@@ -171,7 +172,6 @@
                 status = DpnStatusIndication.getEnum(buf[3]);
                 if (status.equals(DpnStatusIndication.HELLO)) {
                     log.info("Hello {} on topic {}", deviceId, buf[2]);
-
                     dpnDeviceListener.deviceAdded(deviceId, buf[2]);
                 } else if (status.equals(DpnStatusIndication.GOODBYE)) {
                     log.info("Bye {}", deviceId);
diff --git a/ng40-license b/ng40-license
new file mode 100644
index 0000000..426627a
--- /dev/null
+++ b/ng40-license
Binary files differ
diff --git a/scripts/httpserver.py b/scripts/httpserver.py
new file mode 100755
index 0000000..9dd33d8
--- /dev/null
+++ b/scripts/httpserver.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# Reflects the requests from HTTP methods GET, POST, PUT, and DELETE
+# Written by Nathan Hamiel (2010)
+
+from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from optparse import OptionParser
+
+class RequestHandler(BaseHTTPRequestHandler):
+    
+    def do_GET(self):
+        
+        request_path = self.path
+        
+        print("\n----- Request Start ----->\n")
+        print(request_path)
+        print(self.headers)
+        print("<----- Request End -----\n")
+        
+        self.send_response(200)
+        self.send_header("Set-Cookie", "foo=bar")
+        
+    def do_POST(self):
+        
+        request_path = self.path
+        
+        print("\n----- Request Start ----->\n")
+        print(request_path)
+        
+        request_headers = self.headers
+        content_length = request_headers.getheaders('content-length')
+        length = int(content_length[0]) if content_length else 0
+        
+        print(request_headers)
+        print(self.rfile.read(length))
+        print("<----- Request End -----\n")
+        
+        self.send_response(200)
+    
+    do_PUT = do_POST
+    do_DELETE = do_GET
+        
+def main():
+    port = 9997
+    print('Listening on localhost:%s' % port)
+    server = HTTPServer(('', port), RequestHandler)
+    server.serve_forever()
+
+        
+if __name__ == "__main__":
+    parser = OptionParser()
+    parser.usage = ("Creates an http-server that will echo out any GET or POST parameters\n"
+                    "Run:\n\n"
+                    "   reflect")
+    (options, args) = parser.parse_args()
+    
+    main()
\ No newline at end of file