Completed Deactivation method and implemented Session Deletion on CP reconnect
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 3a8c2f9..f29b1a2 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
@@ -175,8 +175,16 @@
     protected void deactivate() {
         deviceService.removeListener(listener);
         rpcRegistry.unregisterRpcService(this);
+
+        CLIENT_INFO.keySet().forEach(this::deleteSessions);
         CLIENT_INFO.clear();
+        CLIENT_CONTEXTS_INFO.clear();
         TENANT_INFO.clear();
+
+        deleteNode(connections);
+        deleteNode(fpcAgents);
+        deleteNode(tenants);
+
         log.info("FPC RPC Service Stopped");
     }
 
@@ -299,7 +307,7 @@
 
                 Ip4Address s1USgwIpv4Dl = Ip4Address.valueOf(context.dl().tunnelLocalAddress().toString()),
                         s1UEnodebIpv4Dl = Ip4Address.valueOf(context.dl().tunnelRemoteAddress().toString()),
-			s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
+                        s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
                         s1USgwIpv4Ul = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
 
                 long clientId = clientInfo.clientId().fpcIdentity().union().int64(),
@@ -339,6 +347,11 @@
                                 .build();
                         createNode(convertContext, modelObjectId);
                         cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+                        HashSet<FpcContextId> contexts = CLIENT_CONTEXTS_INFO.getOrDefault(
+                                clientInfo.clientId(),
+                                Sets.newHashSet()
+                        );
+                        contexts.add(context.contextId());
                     }));
 
                     // FIXME why downlink is in session while uplink is not?
@@ -359,6 +372,11 @@
                                     .build();
                             createNode(convertContext, modelObjectId);
                             cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+                            HashSet<FpcContextId> contexts = CLIENT_CONTEXTS_INFO.getOrDefault(
+                                    clientInfo.clientId(),
+                                    Sets.newHashSet()
+                            );
+                            contexts.add(context.contextId());
                         }));
                     }
                 } else if (commands.contains("indirect-forward")) {
@@ -468,13 +486,13 @@
 
                 Ip4Address s1USgwIpv4Dl = Ip4Address.valueOf(context.dl().tunnelLocalAddress().toString()),
                         s1UEnodebIpv4Dl = Ip4Address.valueOf(context.dl().tunnelRemoteAddress().toString()),
-			s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
+                        s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
                         s1USgwIpv4Ul = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
 
                 long s1UEnbGtpuTeidDl = ((ThreegppTunnel) context.dl().mobilityTunnelParameters()
                         .mobprofileParameters()).tunnelIdentifier(),
-			s1UEnbGtpuTeidUl = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
-                        .mobprofileParameters()).tunnelIdentifier(),
+                        s1UEnbGtpuTeidUl = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+                                .mobprofileParameters()).tunnelIdentifier(),
                         cId = clientInfo.clientId().fpcIdentity().union().int64(),
                         contextId = context.contextId().fpcIdentity().union().int64();
 
@@ -549,86 +567,67 @@
         return configureOutput;
     }
 
-    @Override
-    public DefaultConfigureOutput configureDelete(
-            DeleteOrQuery delete,
-            DefaultRegisterClientInput clientInfo,
-            OpIdentifier operationId
-    ) throws Exception {
-        DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
+    public Collection<Callable<Object>> deleteSessions(ClientIdentifier clientIdentifier) {
         Collection<Callable<Object>> tasks = new ArrayList<>();
-        // get client's tenant.
-        FpcIdentity tenantId = clientInfo.tenantId();
-        // get cache for specific tenant.
-        CacheManager cacheManager = CacheManager.getInstance(tenantId);
-        DefaultDeleteSuccess defaultDeleteSuccess = new DefaultDeleteSuccess();
-        for (Targets target : delete.targets()) {
-            defaultDeleteSuccess.addToTargets(target);
-            // parse context id.
-            String targetStr = target.target().toString(),
-                    s = StringUtils.substringBetween(targetStr, "contexts=", "/"),
-                    trgt = s != null ? s : StringUtils.substringAfter(targetStr, "contexts=");
+        try {
+            FpcIdentity tenantId = CLIENT_INFO.get(clientIdentifier).tenantId();
+            CacheManager cacheManager = CacheManager.getInstance(tenantId);
 
-            // find context that this target is about.
-            FpcContextId fpcContextId = FpcContextId.of(FpcIdentity.fromString(trgt));
-            Optional<DefaultContexts> defaultContexts = CacheManager.getInstance(tenantId)
-                    .contextsCache.get(fpcContextId);
-            if (!defaultContexts.isPresent()) {
-                throw new RuntimeException("Context doesn't exist. Please issue create operation..");
-            }
+            for (FpcContextId fpcContextId : CLIENT_CONTEXTS_INFO.get(clientIdentifier)) {
+                Optional<DefaultContexts> defaultContexts = null;
 
-            log.debug("handling configure-delete {}", targetStr);
+                defaultContexts = CacheManager.getInstance(tenantId).contextsCache.get(fpcContextId);
 
-            DefaultContexts context = defaultContexts.get();
-            for (Dpns dpn : context.dpns()) {
-                Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(dpn.dpnId());
-                // check if dpns exists and if there is a DPN registered for the wanted identifier.
-                if (!optionalDpn.isPresent()) {
-                    // throw exception if DPN ID is not registered.
-                    throw new RuntimeException("DPN ID is not registered to the topology.");
+                if (!defaultContexts.isPresent()) {
+                    throw new RuntimeException("Context doesn't exist. Please issue create operation..");
                 }
 
-                final DpnCommunicationService dpnCommunicationService;
-                Class<? extends FpcDpnControlProtocol> controlProtocol = optionalDpn.get().controlProtocol();
-                if (controlProtocol.isAssignableFrom(ZmqDpnControlProtocol.class)) {
-                    dpnCommunicationService = DpnNgicCommunicator.getInstance();
-                } else if (controlProtocol.isAssignableFrom(P4DpnControlProtocol.class)) {
-                    DpnP4Communicator instance = DpnP4Communicator.getInstance();
-                    dpnCommunicationService = instance;
-                    instance.setDeviceId(
-                            DeviceId.deviceId(optionalDpn.get().dpnId().toString())
-                    );
-                    instance.setClientId(clientInfo.clientId());
-                } else {
-                    throw new RuntimeException("Control Protocol is not supported.");
-                }
+                DefaultContexts context = defaultContexts.get();
+                for (Dpns dpn : context.dpns()) {
+                    Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(dpn.dpnId());
+                    // check if dpns exists and if there is a DPN registered for the wanted identifier.
+                    if (!optionalDpn.isPresent()) {
+                        // throw exception if DPN ID is not registered.
+                        throw new RuntimeException("DPN ID is not registered to the topology.");
+                    }
 
-                // from DPN ID find the Network and Node Identifiers
-                Optional<String> key = optionalDpn
-                        .map(node -> node.nodeId() + "/" + node.networkId());
-                if (!key.isPresent()) {
-                    throw new RuntimeException("DPN does not have node and network ID defined.");
-                }
+                    final DpnCommunicationService dpnCommunicationService;
+                    Class<? extends FpcDpnControlProtocol> controlProtocol = optionalDpn.get().controlProtocol();
+                    if (controlProtocol.isAssignableFrom(ZmqDpnControlProtocol.class)) {
+                        dpnCommunicationService = DpnNgicCommunicator.getInstance();
+                    } else if (controlProtocol.isAssignableFrom(P4DpnControlProtocol.class)) {
+                        DpnP4Communicator instance = DpnP4Communicator.getInstance();
+                        dpnCommunicationService = instance;
+                        instance.setDeviceId(
+                                DeviceId.deviceId(optionalDpn.get().dpnId().toString())
+                        );
+                        instance.setClientId(clientIdentifier);
+                    } else {
+                        throw new RuntimeException("Control Protocol is not supported.");
+                    }
 
-                // find DPN Topic from Node/Network ID pair.
-                byte topicId = getTopicFromNode(key.get());
-                if (topicId == -1 && dpnCommunicationService instanceof ZmqDpnControlProtocol) {
-                    throw new RuntimeException("Could not find Topic ID");
-                }
+                    // from DPN ID find the Network and Node Identifiers
+                    Optional<String> key = optionalDpn
+                            .map(node -> node.nodeId() + "/" + node.networkId());
+                    if (!key.isPresent()) {
+                        throw new RuntimeException("DPN does not have node and network ID defined.");
+                    }
 
-                if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
-                    throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
-                }
+                    // find DPN Topic from Node/Network ID pair.
+                    byte topicId = getTopicFromNode(key.get());
+                    if (topicId == -1 && dpnCommunicationService instanceof ZmqDpnControlProtocol) {
+                        throw new RuntimeException("Could not find Topic ID");
+                    }
 
-                Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
-                        .mobprofileParameters()).tunnelIdentifier();
-                long clientId = clientInfo.clientId().fpcIdentity().union().int64();
-                BigInteger opId = operationId.uint64();
+                    if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+                        throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+                    }
 
-                // TODO figure out what is going on.
-                if (targetStr.endsWith("ul") || targetStr.endsWith("dl")) {
-                    // TODO delete bearer
-                } else {
+                    Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+                            .mobprofileParameters()).tunnelIdentifier();
+                    long clientId = clientIdentifier.fpcIdentity().union().int64();
+                    BigInteger opId = BigInteger.valueOf(-1);
+
                     tasks.add(Executors.callable(() -> {
                         dpnCommunicationService.deleteSession(
                                 topicId,
@@ -647,9 +646,132 @@
 
                         dynamicConfigService.deleteNode(resourceVal);
                         cacheManager.contextsCache.put(context.contextId(), Optional.empty());
+                        CLIENT_CONTEXTS_INFO.get(clientIdentifier).remove(fpcContextId);
                     }));
                 }
             }
+        } catch (Exception e) {
+            log.error(ExceptionUtils.getFullStackTrace(e));
+        }
+        return tasks;
+    }
+
+    public Collection<Callable<Object>> deleteSession(
+            ClientIdentifier clientIdentifier,
+            FpcContextId fpcContextId,
+            OpIdentifier operationId
+    ) throws ExecutionException {
+        Collection<Callable<Object>> tasks = new ArrayList<>();
+
+        FpcIdentity tenantId = CLIENT_INFO.get(clientIdentifier).tenantId();
+        CacheManager cacheManager = CacheManager.getInstance(tenantId);
+
+        Optional<DefaultContexts> defaultContexts = null;
+
+        defaultContexts = CacheManager.getInstance(tenantId)
+                .contextsCache.get(fpcContextId);
+
+        if (!defaultContexts.isPresent()) {
+            throw new RuntimeException("Context doesn't exist. Please issue create operation..");
+        }
+
+        DefaultContexts context = defaultContexts.get();
+        for (Dpns dpn : context.dpns()) {
+            Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(dpn.dpnId());
+            // check if dpns exists and if there is a DPN registered for the wanted identifier.
+            if (!optionalDpn.isPresent()) {
+                // throw exception if DPN ID is not registered.
+                throw new RuntimeException("DPN ID is not registered to the topology.");
+            }
+
+            final DpnCommunicationService dpnCommunicationService;
+            Class<? extends FpcDpnControlProtocol> controlProtocol = optionalDpn.get().controlProtocol();
+            if (controlProtocol.isAssignableFrom(ZmqDpnControlProtocol.class)) {
+                dpnCommunicationService = DpnNgicCommunicator.getInstance();
+            } else if (controlProtocol.isAssignableFrom(P4DpnControlProtocol.class)) {
+                DpnP4Communicator instance = DpnP4Communicator.getInstance();
+                dpnCommunicationService = instance;
+                instance.setDeviceId(
+                        DeviceId.deviceId(optionalDpn.get().dpnId().toString())
+                );
+                instance.setClientId(clientIdentifier);
+            } else {
+                throw new RuntimeException("Control Protocol is not supported.");
+            }
+
+            // from DPN ID find the Network and Node Identifiers
+            Optional<String> key = optionalDpn
+                    .map(node -> node.nodeId() + "/" + node.networkId());
+            if (!key.isPresent()) {
+                throw new RuntimeException("DPN does not have node and network ID defined.");
+            }
+
+            // find DPN Topic from Node/Network ID pair.
+            byte topicId = getTopicFromNode(key.get());
+            if (topicId == -1 && dpnCommunicationService instanceof ZmqDpnControlProtocol) {
+                throw new RuntimeException("Could not find Topic ID");
+            }
+
+            if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+                throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+            }
+
+            Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+                    .mobprofileParameters()).tunnelIdentifier();
+            long clientId = clientIdentifier.fpcIdentity().union().int64();
+            BigInteger opId = operationId.uint64();
+
+            tasks.add(Executors.callable(() -> {
+                dpnCommunicationService.deleteSession(
+                        topicId,
+                        context.contextId().fpcIdentity().union().int64(),
+                        clientId,
+                        opId
+                );
+
+                ContextsKeys contextsKeys = new ContextsKeys();
+                contextsKeys.contextId(context.contextId());
+
+                ResourceId resourceVal = getResourceVal(tenantBuilder(tenantId)
+                        .addChild(DefaultFpcMobility.class)
+                        .addChild(DefaultContexts.class, contextsKeys)
+                        .build());
+
+                dynamicConfigService.deleteNode(resourceVal);
+                cacheManager.contextsCache.put(context.contextId(), Optional.empty());
+                CLIENT_CONTEXTS_INFO.get(clientIdentifier).remove(fpcContextId);
+            }));
+        }
+
+        return tasks;
+    }
+
+    @Override
+    public DefaultConfigureOutput configureDelete(
+            DeleteOrQuery delete,
+            DefaultRegisterClientInput clientInfo,
+            OpIdentifier operationId
+    ) throws Exception {
+        Collection<Callable<Object>> tasks = new ArrayList<>();
+        DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
+        // get cache for specific tenant.
+        DefaultDeleteSuccess defaultDeleteSuccess = new DefaultDeleteSuccess();
+        for (Targets target : delete.targets()) {
+            defaultDeleteSuccess.addToTargets(target);
+            // parse context id.
+            String targetStr = target.target().toString(),
+                    s = StringUtils.substringBetween(targetStr, "contexts=", "/"),
+                    trgt = s != null ? s : StringUtils.substringAfter(targetStr, "contexts=");
+
+            log.debug("handling configure-delete {}", targetStr);
+
+            // TODO figure out what is going on.
+            if (targetStr.endsWith("ul") || targetStr.endsWith("dl")) {
+                // TODO delete bearer
+            } else {
+                FpcContextId fpcContextId = FpcContextId.of(FpcIdentity.fromString(trgt));
+                tasks = deleteSession(clientInfo.clientId(), fpcContextId, operationId);
+            }
         }
 
         // execute all tasks
@@ -984,7 +1106,11 @@
                 for (ModelObject modelObject : getModelObjects(rpcInput.data(), registerClient)) {
                     DefaultRegisterClientInput input = (DefaultRegisterClientInput) modelObject;
                     if (CLIENT_INFO.containsKey(input.clientId())) {
-                        throw new RuntimeException("Client already registered.");
+//                        throw new RuntimeException("Client already registered.");
+                        log.error("Client already registered. Deleting previous contexts...");
+                        deleteSessions(input.clientId());
+                        CLIENT_INFO.remove(input.clientId());
+                        CLIENT_CONTEXTS_INFO.remove(input.clientId());
                     }
                     // keep information for each client. this can be moved to the DC Store and use Cache.
                     CLIENT_INFO.put(input.clientId(), input);
@@ -1041,6 +1167,13 @@
                     if (!CLIENT_INFO.containsKey(input.clientId())) {
                         throw new RuntimeException("Client does not exist.");
                     }
+
+                    for (HashSet<ClientIdentifier> clientIdentifiers : TENANT_INFO.values()) {
+                       if (clientIdentifiers.remove(input.clientId())) {
+                           break;
+                       }
+                    }
+
                     CLIENT_INFO.remove(input.clientId());
                     deregisterClientOutput.clientId(input.clientId());
 
@@ -1052,6 +1185,9 @@
                     ConnectionsKeys connectionsKeys = new ConnectionsKeys();
                     connectionsKeys.clientId(input.clientId().toString());
 
+                    // delete all sessions associated with this client.
+                    deleteSessions(input.clientId());
+
                     ResourceId resourceVal = getResourceVal(ModelObjectId.builder()
                             .addChild(DefaultConnectionInfo.class)
                             .addChild(DefaultConnections.class, connectionsKeys)
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 bccc8e8..23934b7 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
@@ -28,9 +28,11 @@
 import org.onosproject.net.device.DeviceStore;
 import org.onosproject.restconf.api.RestconfService;
 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.registerclient.DefaultRegisterClientInput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.ClientIdentifier;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultConfigResultNotification;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultFpcAgentInfo;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultTenants;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.NotificationId;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.OpIdentifier;
@@ -42,6 +44,7 @@
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbody.resulttype.DefaultEmptyCase;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.DefaultTenant;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.TenantKeys;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcContextId;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcIdentity;
 import org.onosproject.yang.model.DataNode;
 import org.onosproject.yang.model.DefaultModelObjectData;
@@ -74,6 +77,7 @@
     public static final FpcIdentity DEFAULT_IDENTITY;
     public static final ConcurrentMap<ClientIdentifier, DefaultRegisterClientInput> CLIENT_INFO;
     public static final ConcurrentMap<FpcIdentity, HashSet<ClientIdentifier>> TENANT_INFO;
+    public static final ConcurrentMap<ClientIdentifier, HashSet<FpcContextId>> CLIENT_CONTEXTS_INFO;
     private static final Logger log = LoggerFactory.getLogger(FpcUtil.class);
     // Services
     public static DynamicConfigService dynamicConfigService;
@@ -84,6 +88,8 @@
     public static ResourceId configureDpn;
     public static ResourceId configure;
     public static ResourceId tenants;
+    public static ResourceId fpcAgents;
+    public static ResourceId connections;
     public static ResourceId configureBundles;
     public static ResourceId registerClient;
     public static ResourceId deregisterClient;
@@ -96,6 +102,7 @@
         DEFAULT_IDENTITY = FpcIdentity.fromString("default");
         CLIENT_INFO = Maps.newConcurrentMap();
         TENANT_INFO = Maps.newConcurrentMap();
+        CLIENT_CONTEXTS_INFO = Maps.newConcurrentMap();
     }
 
     private FpcUtil() {
@@ -127,6 +134,18 @@
 
         tenants = getResourceVal(tenantsId);
 
+        ModelObjectId fpcAgentInfo = ModelObjectId.builder()
+                .addChild(DefaultFpcAgentInfo.class)
+                .build();
+
+        fpcAgents = getResourceVal(fpcAgentInfo);
+
+        ModelObjectId connectionInfo = ModelObjectId.builder()
+                .addChild(DefaultConnectionInfo.class)
+                .build();
+
+        connections = getResourceVal(connectionInfo);
+
         configure = ResourceId.builder()
                 .addBranchPointSchema("/", null)
                 .addBranchPointSchema("configure", "urn:ietf:params:xml:ns:yang:fpcagent")
@@ -305,7 +324,11 @@
                         .build()
         );
         dataNode.dataNodes().forEach(
-                node -> dynamicConfigService.createNode(dataNode.resourceId(), node)
+                node -> {
+                    if (!dynamicConfigService.nodeExist(dataNode.resourceId())) {
+                        dynamicConfigService.createNode(dataNode.resourceId(), node);
+                    }
+                }
         );
     }
 
@@ -323,14 +346,29 @@
                         .build()
         );
         dataNode.dataNodes().forEach(
-                node -> dynamicConfigService.updateNode(dataNode.resourceId(), node)
+                node -> {
+                    if (!dynamicConfigService.nodeExist(dataNode.resourceId())) {
+                        dynamicConfigService.updateNode(dataNode.resourceId(), node);
+                    }
+                }
         );
     }
 
     /**
+     * Deletes a Node based on provided resource Id.
+     *
+     * @param resourceId Resource Id
+     */
+    public static void deleteNode(ResourceId resourceId) {
+        if (dynamicConfigService.nodeExist(resourceId)) {
+            dynamicConfigService.deleteNode(resourceId);
+        }
+    }
+
+    /**
      * Creates a Config Result Notification for SPGW-C.
      *
-     * @param opId operation identifier
+     * @param opId  operation identifier
      * @param cause cause id
      * @return config result notification model
      */
@@ -354,7 +392,7 @@
      * Sends to specified CP the notification object.
      *
      * @param clientId client identifier (CP)
-     * @param notify notification object
+     * @param notify   notification object
      */
     public static void sendNotification(String clientId, ModelObject notify) {
         try {