Notification sub-system

Project: http://git-wip-us.apache.org/repos/asf/fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/fineract/commit/7395d6c5
Tree: http://git-wip-us.apache.org/repos/asf/fineract/tree/7395d6c5
Diff: http://git-wip-us.apache.org/repos/asf/fineract/diff/7395d6c5

Branch: refs/heads/develop
Commit: 7395d6c5439ffb6e7b375c4a74b78d453a3a2693
Parents: 58184a5
Author: Anh3h <couragean...@gmail.com>
Authored: Wed Aug 23 07:27:57 2017 +0100
Committer: Avik Ganguly <av...@apache.org>
Committed: Wed Dec 13 18:04:36 2017 +0530

----------------------------------------------------------------------
 fineract-provider/dependencies.gradle           |    1 -
 .../integrationtests/NotificationApiTest.java   |    5 +-
 .../common/NotificationHelper.java              |    3 +-
 .../TenantAwareBasicAuthenticationFilter.java   |    8 +
 .../api/NotificationApiResource.java            |    2 +-
 .../cache/CacheNotificationResponseHeader.java  |    1 -
 .../notification/data/NotificationData.java     |   12 +-
 .../fineract/notification/data/TopicData.java   |   76 ++
 .../notification/data/TopicSubscriberData.java  |   60 +
 .../notification/domain/Notification.java       |    6 +-
 .../notification/domain/NotificationMapper.java |    1 -
 .../domain/NotificationMapperRepository.java    |    1 -
 .../domain/NotificationRepository.java          |    1 -
 .../fineract/notification/domain/Topic.java     |  122 ++
 .../notification/domain/TopicRepository.java    |   29 +
 .../notification/domain/TopicSubscriber.java    |   80 ++
 .../domain/TopicSubscriberRepository.java       |   29 +
 .../eventandlistener/NotificationEvent.java     |   51 +
 .../exception/TopicNotFoundException.java       |   32 +
 .../service/NotificationDomainServiceImpl.java  | 1085 +++++++++---------
 .../NotificationMapperWritePlatformService.java |    1 -
 .../NotificationReadPlatformServiceImpl.java    |   10 +-
 .../NotificationWritePlatformService.java       |    1 +
 .../service/TopicReadPlatformService.java       |   32 +
 .../service/TopicReadPlatformServiceImpl.java   |   98 ++
 .../TopicSubscriberReadPlatformService.java     |   29 +
 .../TopicSubscriberReadPlatformServiceImpl.java |   78 ++
 .../TopicSubscriberWritePlatformService.java    |   27 +
 ...erWritePlatformServiceJpaRepositoryImpl.java |   42 +
 .../service/TopicWritePlatformService.java      |   27 +
 ...icWritePlatformServiceJpaRepositoryImpl.java |   42 +
 .../organisation/office/domain/Office.java      |    4 +
 ...ceWritePlatformServiceJpaRepositoryImpl.java |   49 +-
 .../BusinessEventNotificationConstants.java     |    1 +
 ...esWritePlatformServiceJpaRepositoryImpl.java |    2 +
 ...ctWritePlatformServiceJpaRepositoryImpl.java |    5 +
 ...ssWritePlatformServiceJpaRepositoryImpl.java |    6 +
 ...ctWritePlatformServiceJpaRepositoryImpl.java |    8 +-
 .../useradministration/domain/Role.java         |    4 +
 ...erWritePlatformServiceJpaRepositoryImpl.java |   91 +-
 ...leWritePlatformServiceJpaRepositoryImpl.java |   50 +-
 .../resources/META-INF/spring/appContext.xml    |    1 -
 .../META-INF/spring/notificationContext.xml     |    1 +
 .../core_db/V336__topic_module_table.sql        |   45 +
 .../apache/fineract/notification/Listener.java  |    3 +-
 .../fineract/notification/ListenerTest.java     |    3 +-
 .../fineract/notification/SenderTest.java       |    4 +-
 .../fineract/notification/StorageTest.java      |    6 +-
 .../apache/fineract/notification/TopicTest.java |  109 ++
 49 files changed, 1795 insertions(+), 589 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/dependencies.gradle
----------------------------------------------------------------------
diff --git a/fineract-provider/dependencies.gradle 
b/fineract-provider/dependencies.gradle
index 27a256c..d157c89 100644
--- a/fineract-provider/dependencies.gradle
+++ b/fineract-provider/dependencies.gradle
@@ -93,7 +93,6 @@ dependencies {
                 //[group: 'com.google.code.findbugs', name: 'jsr305', version: 
'3.0.0']
                 [group: 'org.springframework', name:'spring-jms'],
                 [group: 'org.apache.activemq', name: 'activemq-broker']
-
      )
      testCompile 'junit:junit:4.11',
                  'junit:junit-dep:4.11',

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java
 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java
index c516502..b052649 100644
--- 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java
+++ 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/NotificationApiTest.java
@@ -1,5 +1,3 @@
-package org.apache.fineract.integrationtests;
-
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements. See the NOTICE file
@@ -18,7 +16,7 @@ package org.apache.fineract.integrationtests;
  * specific language governing permissions and limitations
  * under the License.
  */
-
+package org.apache.fineract.integrationtests;
 
 import com.jayway.restassured.builder.RequestSpecBuilder;
 import com.jayway.restassured.builder.ResponseSpecBuilder;
@@ -54,4 +52,5 @@ public class NotificationApiTest {
         System.out.println("Response : " + response.toString());
         Assert.assertNotNull(response);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java
 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java
index efac104..a2674ba 100644
--- 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java
+++ 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/NotificationHelper.java
@@ -1,5 +1,3 @@
-package org.apache.fineract.integrationtests.common;
-
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements. See the NOTICE file
@@ -18,6 +16,7 @@ package org.apache.fineract.integrationtests.common;
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.fineract.integrationtests.common;
 
 import com.jayway.restassured.specification.RequestSpecification;
 import com.jayway.restassured.specification.ResponseSpecification;

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
index a36079d..ccd71cb 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
@@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.lang.time.StopWatch;
+import 
org.apache.fineract.notification.service.NotificationReadPlatformService;
 import org.apache.fineract.infrastructure.cache.domain.CacheType;
 import 
org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService;
 import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -78,6 +79,7 @@ public class TenantAwareBasicAuthenticationFilter extends 
BasicAuthenticationFil
     private final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
     private final ConfigurationDomainService configurationDomainService;
     private final CacheWritePlatformService cacheWritePlatformService;
+
     private final NotificationReadPlatformService 
notificationReadPlatformService;
     private final String tenantRequestHeader = "Fineract-Platform-TenantId";
     private final boolean exceptionIfHeaderMissing = true;
@@ -177,6 +179,12 @@ public class TenantAwareBasicAuthenticationFilter extends 
BasicAuthenticationFil
             response.addHeader("X-Notification-Refresh", "false");
         }
                
+               
if(notificationReadPlatformService.hasUnreadNotifications(user.getId())) {
+                       response.addHeader("X-Notification-Refresh", "true");
+               } else {
+                       response.addHeader("X-Notification-Refresh", "false");
+               }
+               
                String pathURL = request.getRequestURI();
                boolean isSelfServiceRequest = (pathURL != null && 
pathURL.contains("/self/"));
 

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
index 065d7cb..860c74f 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
@@ -18,7 +18,6 @@
  */
 package org.apache.fineract.notification.api;
 
-
 import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
 import 
org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
 import 
org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
@@ -86,4 +85,5 @@ public class NotificationApiResource {
         this.context.authenticatedUser();
         this.notificationReadPlatformService.updateNotificationReadStatus();
     }
+
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java
index 205050b..3b5a6e1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/cache/CacheNotificationResponseHeader.java
@@ -18,7 +18,6 @@
  */
 package org.apache.fineract.notification.cache;
 
-
 public class CacheNotificationResponseHeader {
 
     private boolean hasNotifications;

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java
index 63dab1a..865447c 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/data/NotificationData.java
@@ -29,6 +29,7 @@ public class NotificationData implements Serializable {
     private String action;
     private Long actorId;
     private String content;
+       private boolean isRead;
     private boolean isSystemGenerated;
     private String tenantIdentifier;
     private String createdAt;
@@ -40,12 +41,13 @@ public class NotificationData implements Serializable {
     }
 
     public NotificationData(String objectType, Long objectId, String action, 
Long actorId, String content, boolean isSystemGenerated,
-                            String tenantIdentifier, Long officeId, List<Long> 
userIds) {
+               boolean isRead, String tenantIdentifier, Long officeId, 
List<Long> userIds) {
         this.objectType = objectType;
         this.objectId = objectId;
         this.action = action;
         this.actorId = actorId;
         this.content = content;
+               this.isRead = isRead;
         this.isSystemGenerated = isSystemGenerated;
         this.tenantIdentifier = tenantIdentifier;
         this.officeId = officeId;
@@ -123,6 +125,14 @@ public class NotificationData implements Serializable {
     public void setContent(String content) {
         this.content = content;
     }
+    
+       public boolean isRead() {
+               return this.isRead;
+       }
+
+       public void setRead(boolean isRead) {
+               this.isRead = isRead;
+       }
 
     public boolean isSystemGenerated() {
         return isSystemGenerated;

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java
new file mode 100644
index 0000000..9e070fb
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicData.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.data;
+
+import java.io.Serializable;
+
+public class TopicData implements Serializable {
+
+       private final Long id;
+       private final String title;
+       private final boolean enabled;
+       private final Long entityId;
+       private final String entityType;
+       private final String memberType;
+
+       public TopicData(Long id, String title, boolean enabled, Long entityId, 
String entityType,
+                       String memberType) {
+               this.id = id;
+               this.title = title;
+               this.enabled = enabled;
+               this.entityId = entityId;
+               this.entityType = entityType;
+               this.memberType = memberType;
+       }
+
+       public TopicData(Long id, String title, Long entityId, String 
entityType,
+                       String memberType) {
+               this.id = id;
+               this.title = title;
+               this.enabled = true;
+               this.entityId = entityId;
+               this.entityType = entityType;
+               this.memberType = memberType;
+       }
+
+       public Long getId() {
+               return this.id;
+       }
+
+       public String getTitle() {
+               return this.title;
+       }
+
+       public boolean isEnabled() {
+               return this.enabled;
+       }
+
+       public Long getEntityId() {
+               return this.entityId;
+       }
+
+       public String getEntityType() {
+               return this.entityType;
+       }
+
+       public String getMemberType() {
+               return this.memberType;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java
new file mode 100644
index 0000000..7691694
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/data/TopicSubscriberData.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.data;
+
+import org.joda.time.LocalDate;
+
+public class TopicSubscriberData {
+       
+       private final Long id;
+       private final Long topicId;
+       private final Long userId;
+       private final LocalDate subscriptionDate;
+       
+       public TopicSubscriberData(Long id, Long topicId, Long userId, 
LocalDate subscriptionDate) {
+               this.id = id;
+               this.topicId = topicId;
+               this.userId = userId;
+               this.subscriptionDate = subscriptionDate;
+       }
+
+       public TopicSubscriberData(Long id, Long topicId, Long userId) {
+               this.id = id;
+               this.topicId = topicId;
+               this.userId = userId;
+               this.subscriptionDate = new LocalDate();
+       }
+
+       public Long getId() {
+               return this.id;
+       }
+
+       public Long getTopicId() {
+               return this.topicId;
+       }
+
+       public Long getUserId() {
+               return this.userId;
+       }
+
+       public LocalDate getSubscriptionDate() {
+               return this.subscriptionDate;
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java
index cf7d41e..4985f25 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Notification.java
@@ -20,9 +20,7 @@ package org.apache.fineract.notification.domain;
 
 import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
 
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Table;
+import javax.persistence.*;
 
 @Entity
 @Table(name = "notification_generator")
@@ -90,7 +88,7 @@ public class Notification extends 
AbstractPersistableCustom<Long> {
         return actorId;
     }
 
-    public void setActor(Long actor) {
+    public void setActor(Long actorId) {
         this.actorId = actorId;
     }
 

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java
index 5297d23..970b447 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapper.java
@@ -18,7 +18,6 @@
  */
 package org.apache.fineract.notification.domain;
 
-
 import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
 import org.apache.fineract.useradministration.domain.AppUser;
 

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java
index fb88509..5caabf1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationMapperRepository.java
@@ -20,5 +20,4 @@ package org.apache.fineract.notification.domain;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 
-
 public interface NotificationMapperRepository extends 
JpaRepository<NotificationMapper, Long> {}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java
index ed0675d..6b9160f 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/NotificationRepository.java
@@ -20,5 +20,4 @@ package org.apache.fineract.notification.domain;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 
-
 public interface NotificationRepository extends JpaRepository<Notification, 
Long> {}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java
new file mode 100644
index 0000000..62f1a56
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/Topic.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+
+@Entity
+@Table(name = "topic")
+public class Topic extends AbstractPersistableCustom<Long> {
+
+       @Column(name = "title", unique = true, nullable = false, length = 100)
+       private String title;
+       
+       @Column(name = "enabled", nullable = false)
+       private Boolean enabled;
+       
+       @Column(name = "entity_id", nullable = false)
+       private Long entityId;
+       
+       @Column(name = "entity_type")
+       private String entityType;
+       
+       @Column(name = "member_type")
+       private String memberType;
+       
+       public Topic() {
+       }
+       
+       public Topic(String title, Boolean enabled, Long entityId, String 
entityType, String memberType) {
+               this.title = title.trim();
+               this.enabled = enabled;
+               this.entityId = entityId;
+               this.entityType = entityType.trim();
+               this.memberType = memberType.trim();
+       }
+
+       public static Topic fromJson(final JsonCommand command) {
+               String title = "";
+               Boolean enabled = null;
+               Long entityId = 0L;
+               String entityType = "";
+               String memberType = "";
+               
+               if (command.hasParameter("title")) {
+                       title = command.stringValueOfParameterNamed("title");
+               }
+               if (command.hasParameter("enabled")) {
+                       enabled = 
command.booleanPrimitiveValueOfParameterNamed("enabled");
+               }
+               if (command.hasParameter("entityId")) {
+                       entityId = 
command.longValueOfParameterNamed("entityId");
+               }
+               if (command.hasParameter("entityType")) {
+                       entityType = 
command.stringValueOfParameterNamed("entityType");
+               }
+               if (command.hasParameter("memberType")) {
+                       memberType = 
command.stringValueOfParameterNamed("memberType");
+               }
+               return new Topic(title, enabled, entityId, entityType, 
memberType);
+       }
+
+       public String getTitle() {
+               return this.title;
+       }
+
+       public void setTitle(String title) {
+               this.title = title;
+       }
+
+       public Boolean getEnabled() {
+               return this.enabled;
+       }
+
+       public void setEnabled(Boolean enabled) {
+               this.enabled = enabled;
+       }
+
+       public Long getEntityId() {
+               return this.entityId;
+       }
+
+       public void setEntityId(Long entityId) {
+               this.entityId = entityId;
+       }
+
+       public String getEntityType() {
+               return this.entityType;
+       }
+
+       public void setEntityType(String entityType) {
+               this.entityType = entityType;
+       }
+
+       public String getMemberType() {
+               return this.memberType;
+       }
+
+       public void setMemberType(String memberType) {
+               this.memberType = memberType;
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java
new file mode 100644
index 0000000..c01bb7b
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicRepository.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.domain;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface TopicRepository extends JpaRepository<Topic, Long>, 
JpaSpecificationExecutor<Topic> {
+       List<Topic> findByEntityId(Long entityId);
+       List<Topic> findByMemberType(String memberType);
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java
new file mode 100644
index 0000000..74ef960
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriber.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.domain;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.useradministration.domain.AppUser;
+
+@Entity
+@Table(name = "topic_subscriber")
+public class TopicSubscriber extends AbstractPersistableCustom<Long> {
+
+       @ManyToOne
+       @JoinColumn(name = "topic_id")
+       private Topic topic;
+       
+       @ManyToOne
+       @JoinColumn(name = "user_id")
+       private AppUser subscriber;
+       
+       @Column(name = "subscription_date")
+       private Date subscriptionDate;
+
+       public TopicSubscriber() {
+       }
+
+       public TopicSubscriber(Topic topic, AppUser subscriber, Date 
subscriptionDate) {
+               this.topic = topic;
+               this.subscriber = subscriber;
+               this.subscriptionDate = subscriptionDate;
+       }
+
+       public Topic getTopic() {
+               return this.topic;
+       }
+
+       public void setTopic(Topic topic) {
+               this.topic = topic;
+       }
+
+       public AppUser getSubscriber() {
+               return this.subscriber;
+       }
+
+       public void setSubscriber(AppUser subscriber) {
+               this.subscriber = subscriber;
+       }
+
+       public Date getSubscriptionDate() {
+               return this.subscriptionDate;
+       }
+
+       public void setSubscriptionDate(Date subscriptionDate) {
+               this.subscriptionDate = subscriptionDate;
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java
new file mode 100644
index 0000000..cd67fb9
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/domain/TopicSubscriberRepository.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.domain;
+
+import java.util.List;
+
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface TopicSubscriberRepository extends 
JpaRepository<TopicSubscriber, Long>, JpaSpecificationExecutor<TopicSubscriber> 
{
+       List<TopicSubscriber> findBySubscriber(AppUser subscriber);
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java
new file mode 100644
index 0000000..9df5215
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.eventandlistener;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.apache.fineract.notification.data.NotificationData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.jms.core.MessageCreator;
+import org.springframework.stereotype.Service;
+
+@Service
+public class NotificationEvent {
+       
+       private final JmsTemplate jmsTemplate;
+       
+       @Autowired
+       public NotificationEvent(JmsTemplate jmsTemplate) {
+               this.jmsTemplate = jmsTemplate;
+       }
+       
+       public void broadcastNotification(final Destination destination, final 
NotificationData notificationData) {
+               this.jmsTemplate.send(destination, new MessageCreator() {
+                       @Override
+                       public Message createMessage(Session session) throws 
JMSException {
+                               return 
session.createObjectMessage(notificationData);
+                       }
+               });
+       }
+       
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java
new file mode 100644
index 0000000..857ef4c
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/exception/TopicNotFoundException.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.exception;
+
+import 
org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+
+/**
+ * A {@link RuntimeException} thrown when topic resources are not found.
+ */
+public class TopicNotFoundException extends 
AbstractPlatformResourceNotFoundException {
+
+       public TopicNotFoundException(final Long id) {
+               super("error.msg.topic.id.invalid", "Topic with identifier " + 
id + " does not exist", id);
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java
index e8becbe..1744bd3 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationDomainServiceImpl.java
@@ -18,13 +18,14 @@
  */
 package org.apache.fineract.notification.service;
 
-
 import org.apache.activemq.command.ActiveMQQueue;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.notification.data.NotificationData;
-import 
org.apache.fineract.notification.eventandlistener.NotificationEventService;
+import org.apache.fineract.notification.data.TopicSubscriberData;
+import org.apache.fineract.notification.eventandlistener.NotificationEvent;
+import org.apache.fineract.organisation.office.domain.OfficeRepository;
 import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants;
 import 
org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
@@ -39,552 +40,562 @@ import 
org.apache.fineract.portfolio.savings.domain.RecurringDepositAccount;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
 import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
-import org.apache.fineract.useradministration.domain.AppUser;
-import org.apache.fineract.useradministration.domain.AppUserRepository;
 import org.apache.fineract.useradministration.domain.Role;
+import org.apache.fineract.useradministration.domain.RoleRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
 import javax.jms.Queue;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 @Service
 public class NotificationDomainServiceImpl implements 
NotificationDomainService {
 
-    private final BusinessEventNotifierService businessEventNotifierService;
-    private final NotificationEventService notificationEventService;
-    private final AppUserRepository appUserRepository;
-    private final PlatformSecurityContext context;
-
-
-    @Autowired
-    public NotificationDomainServiceImpl(final BusinessEventNotifierService 
businessEventNotifierService,
-                                         final NotificationEventService 
notificationEventService,
-                                         final AppUserRepository 
appUserRepository,
-                                         final PlatformSecurityContext 
context) {
-        this.businessEventNotifierService = businessEventNotifierService;
-        this.notificationEventService = notificationEventService;
-        this.appUserRepository = appUserRepository;
-        this.context = context;
-    }
-
-    @PostConstruct
-    public void addListeners() {
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_CREATE,
-                new ClientCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_APPROVE,
-                new SavingsAccountApprovedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CENTERS_CREATE,
-                new CenterCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.GROUPS_CREATE,
-                new GroupCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_DEPOSIT,
-                new SavingsAccountDepositListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_PRODUCT_DIVIDENDS_CREATE,
-                new ShareProductDividendCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.FIXED_DEPOSIT_ACCOUNT_CREATE,
-                new FixedDepositAccountCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.RECURRING_DEPOSIT_ACCOUNT_CREATE,
-                new RecurringDepositAccountCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_POST_INTEREST,
-                new SavingsPostInterestListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CREATE,
-                new LoanCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_APPROVED,
-                new LoanApprovedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE,
-                new LoanClosedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE_AS_RESCHEDULE,
-                new LoanCloseAsRescheduledListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT,
-                new LoanMakeRepaymentListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_PRODUCT_CREATE,
-                new LoanProductCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CREATE,
-                new SavingsAccountCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CLOSE,
-                new SavingsAccountClosedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_CREATE,
-                new ShareAccountCreatedListener());
-        
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_APPROVE,
-                new ShareAccountApprovedListener());
-    }
-
-    private abstract class NotificationBusinessEventAdapter implements 
BusinessEventListner {
-
-        @Override
-        public void 
businessEventToBeExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
-            //Nothing to do
-        }
-    }
-
-    private class ClientCreatedListener extends  
NotificationBusinessEventAdapter {
-
-        @Override
-        public void 
businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
-            Client client;
-            Object entity = 
businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT);
-            if (entity != null) {
-                client = (Client) entity;
-                buildNotification(
-                        "ACTIVATE_CLIENT",
-                        "client",
-                        client.getId(),
-                        "New client created",
-                        "created",
-                        context.authenticatedUser().getId(),
-                        client.getOffice().getId()
-                );
-            }
-        }
-    }
-
-    private class CenterCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void 
businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
-            CommandProcessingResult commandProcessingResult;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.GROUP);
-            if (entity != null) {
-                commandProcessingResult = (CommandProcessingResult) entity;
-                buildNotification(
-                        "ACTIVATE_CENTER",
-                        "center",
-                        commandProcessingResult.getGroupId(),
-                        "New center created",
-                        "created",
-                        context.authenticatedUser().getId(),
-                        commandProcessingResult.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class GroupCreatedListener extends  
NotificationBusinessEventAdapter {
-
-        @Override
-        public void 
businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
-            CommandProcessingResult commandProcessingResult;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.GROUP);
-            if (entity != null) {
-                commandProcessingResult = (CommandProcessingResult) entity;
-                buildNotification(
-                        "ACTIVATE_GROUP",
-                        "group",
-                        commandProcessingResult.getGroupId(),
-                        "New group created",
-                        "created",
-                        context.authenticatedUser().getId(),
-                        commandProcessingResult.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class SavingsAccountDepositListener extends  
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            SavingsAccountTransaction savingsAccountTransaction;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SAVINGS_TRANSACTION);
-            if (entity != null) {
-                savingsAccountTransaction = (SavingsAccountTransaction) entity;
-                buildNotification(
-                        "READ_SAVINGSACCOUNT",
-                        "savingsAccount",
-                        savingsAccountTransaction.getSavingsAccount().getId(),
-                        "Deposit made",
-                        "depositMade",
-                        context.authenticatedUser().getId(),
-                        
savingsAccountTransaction.getSavingsAccount().officeId()
-                );
-            }
-        }
-    }
-
-    private class ShareProductDividendCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            Long shareProductId;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SHARE_PRODUCT);
-            if (entity != null) {
-                shareProductId = (Long) entity;
-                buildNotification(
-                        "READ_DIVIDEND_SHAREPRODUCT",
-                        "shareProduct",
-                        shareProductId,
-                        "Dividend posted to account",
-                        "dividendPosted",
-                        context.authenticatedUser().getId(),
-                        context.authenticatedUser().getOffice().getId()
-                );
-            }
-        }
-    }
-
-    private class FixedDepositAccountCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            FixedDepositAccount fixedDepositAccount;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT);
-            if (entity != null) {
-                fixedDepositAccount = (FixedDepositAccount) entity;
-                buildNotification(
-                        "APPROVE_FIXEDDEPOSITACCOUNT",
-                        "fixedDeposit",
-                        fixedDepositAccount.getId(),
-                        "New fixed deposit account created",
-                        "created",
-                        context.authenticatedUser().getId(),
-                        fixedDepositAccount.officeId()
-                );
-            }
-        }
-    }
-
-    private class RecurringDepositAccountCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            RecurringDepositAccount recurringDepositAccount;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT);
-            if (entity != null) {
-                recurringDepositAccount = (RecurringDepositAccount) entity;
-                buildNotification(
-                        "APPROVE_RECURRINGDEPOSITACCOUNT",
-                        "recurringDepositAccount",
-                        recurringDepositAccount.getId(),
-                        "New recurring deposit account created",
-                        "created",
-                        context.authenticatedUser().getId(),
-                        recurringDepositAccount.officeId()
-                );
-            }
-        }
-    }
-
-
-    private class SavingsAccountApprovedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            SavingsAccount  savingsAccount;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING);
-            if (entity != null) {
-                savingsAccount = (SavingsAccount) entity;
-                if 
(savingsAccount.depositAccountType().equals(DepositAccountType.FIXED_DEPOSIT)) {
-
-                    buildNotification(
-                        "ACTIVATE_FIXEDDEPOSITACCOUNT",
-                        "fixedDeposit",
-                        savingsAccount.getId(),
-                        "Fixed deposit account approved",
-                        "approved",
-                        context.authenticatedUser().getId(),
-                        savingsAccount.officeId()
-                    );
-
-                } else if 
(savingsAccount.depositAccountType().equals(DepositAccountType.RECURRING_DEPOSIT))
 {
-
-                    buildNotification(
-                        "ACTIVATE_RECURRINGDEPOSITACCOUNT",
-                        "recurringDepositAccount",
-                        savingsAccount.getId(),
-                        "Recurring deposit account approved",
-                        "approved",
-                        context.authenticatedUser().getId(),
-                        savingsAccount.officeId()
-                    );
-
-                } else if 
(savingsAccount.depositAccountType().equals(DepositAccountType.SAVINGS_DEPOSIT))
 {
-
-                    buildNotification(
-                        "ACTIVATE_SAVINGSACCOUNT",
-                        "savingsAccount",
-                        savingsAccount.getId(),
-                        "Savings account approved",
-                        "approved",
-                        context.authenticatedUser().getId(),
-                        savingsAccount.officeId()
-                    );
-                }
-            }
-        }
-    }
-
-    private class SavingsPostInterestListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            SavingsAccount savingsAccount;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING);
-            if (entity != null) {
-                savingsAccount = (SavingsAccount) entity;
-                buildNotification(
-                    "READ_SAVINGSACCOUNT",
-                    "savingsAccount",
-                    savingsAccount.getId(),
-                    "Interest posted to account",
-                    "interestPosted",
-                    context.authenticatedUser().getId(),
-                    savingsAccount.officeId()
-                );
-            }
-        }
-    }
-
-    private class LoanCreatedListener extends NotificationBusinessEventAdapter 
{
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            Loan loan;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN);
-            if (entity != null) {
-                loan = (Loan) entity;
-                buildNotification(
-                    "APPROVE_LOAN",
-                    "loan",
-                    loan.getId(),
-                    "New loan created",
-                    "created",
-                    context.authenticatedUser().getId(),
-                    loan.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class LoanApprovedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            Loan loan;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN);
-            if (entity != null) {
-                loan = (Loan) entity;
-                buildNotification(
-                    "DISBURSE_LOAN",
-                    "loan",
-                    loan.getId(),
-                    "New loan approved",
-                    "approved",
-                    context.authenticatedUser().getId(),
-                    loan.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class LoanClosedListener extends NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            Loan loan;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN);
-            if (entity != null) {
-                loan = (Loan) entity;
-                buildNotification(
-                    "READ_LOAN",
-                    "loan",
-                    loan.getId(),
-                    "Loan closed",
-                    "loanClosed",
-                    context.authenticatedUser().getId(),
-                    loan.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class LoanCloseAsRescheduledListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            Loan loan;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN);
-            if (entity != null) {
-                loan = (Loan) entity;
-                buildNotification(
-                    "READ_Rescheduled Loans",
-                    "loan",
-                    loan.getId(),
-                    "Loan has been rescheduled",
-                    "loanRescheduled",
-                    context.authenticatedUser().getId(),
-                    loan.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class LoanMakeRepaymentListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            Loan loan;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.LOAN);
-            if (entity != null) {
-                loan = (Loan) entity;
-                buildNotification(
-                    "READ_LOAN",
-                    "loan",
-                    loan.getId(),
-                    "Repayment made",
-                    "repaymentMade",
-                    context.authenticatedUser().getId(),
-                    loan.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class LoanProductCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-
-            LoanProduct loanProduct;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN_PRODUCT);
-            if (entity != null) {
-                loanProduct = (LoanProduct) entity;
-                buildNotification(
-                    "READ_LOANPRODUCT",
-                    "loanProduct",
-                    loanProduct.getId(),
-                    "New loan product created",
-                    "created",
-                    context.authenticatedUser().getId(),
-                    context.authenticatedUser().getOffice().getId()
-                );
-            }
-        }
-    }
-
-    private class SavingsAccountCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            SavingsAccount  savingsAccount;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING);
-            if (entity != null) {
-                savingsAccount = (SavingsAccount) entity;
-                buildNotification(
-                    "APPROVE_SAVINGSACCOUNT",
-                    "savingsAccount",
-                    savingsAccount.getId(),
-                    "New savings account created",
-                    "created",
-                    context.authenticatedUser().getId(),
-                    savingsAccount.officeId()
-                );
-            }
-        }
-    }
-
-    private class SavingsAccountClosedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            SavingsAccount  savingsAccount;
-            Object entity = businessEventEntity.get(BUSINESS_ENTITY.SAVING);
-            if (entity != null) {
-                savingsAccount = (SavingsAccount) entity;
-                buildNotification(
-                    "READ_SAVINGSACCOUNT",
-                    "savingsAccount",
-                    savingsAccount.getId(),
-                    "Savings has gone into dormant",
-                    "closed",
-                    context.authenticatedUser().getId(),
-                    savingsAccount.officeId()
-                );
-            }
-        }
-    }
-
-    private class ShareAccountCreatedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            ShareAccount shareAccount;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT);
-            if (entity != null) {
-                shareAccount = (ShareAccount) entity;
-                buildNotification(
-                    "APPROVE_SHAREACCOUNT",
-                    "shareAccount",
-                    shareAccount.getId(),
-                    "New share account created",
-                    "created",
-                    context.authenticatedUser().getId(),
-                    shareAccount.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private class ShareAccountApprovedListener extends 
NotificationBusinessEventAdapter {
-
-        @Override
-        public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> 
businessEventEntity) {
-            ShareAccount shareAccount;
-            Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT);
-            if (entity != null) {
-                shareAccount = (ShareAccount) entity;
-                buildNotification(
-                    "ACTIVATE_SHAREACCOUNT",
-                    "shareAccount",
-                    shareAccount.getId(),
-                    "Share account approved",
-                    "approved",
-                    context.authenticatedUser().getId(),
-                    shareAccount.getOfficeId()
-                );
-            }
-        }
-    }
-
-    private void buildNotification(String permission, String objectType,
-                                   Long objectIdentifier, String 
notificationContent, String eventType,
-                                   Long appUserId, Long officeId) {
-
-        String tenantIdentifier = 
ThreadLocalContextUtil.getTenant().getTenantIdentifier();
-        Queue queue = new ActiveMQQueue("NotificationQueue");
-        List<Long> userIds = retrieveUsersWithSpecificPermission(permission);
-        NotificationData notificationData = new NotificationData(
-                objectType,
-                objectIdentifier,
-                eventType,
-                appUserId,
-                notificationContent,
-                false,
-                tenantIdentifier,
-                officeId,
-                userIds
-        );
-        notificationEventService.broadcastNotification(queue, 
notificationData);
-
-    }
-
-    private List<Long> retrieveUsersWithSpecificPermission(String permission) {
-        List<AppUser> appUsers = appUserRepository.findAll();
-        List<Long> userIds = new ArrayList<>();
-        for (AppUser appUser : appUsers) {
-            Set<Role> roles = appUser.getRoles();
-            for (Role role : roles) {
-                if (role.hasPermissionTo(permission)) {
-                    if (!(userIds.contains(appUser.getId()))) {
-                        userIds.add(appUser.getId());
-                    }
-                }
-            }
-        }
-        return userIds;
-    }
+       private final BusinessEventNotifierService businessEventNotifierService;
+       private final NotificationEvent notificationEvent;
+       private final PlatformSecurityContext context;
+       private final RoleRepository roleRepository;
+       private final OfficeRepository officeRepository;
+       private final TopicSubscriberReadPlatformService 
topicSubscriberReadPlatformService;
+       
+       @Autowired
+       public NotificationDomainServiceImpl(final BusinessEventNotifierService 
businessEventNotifierService,
+                       final NotificationEvent notificationEvent,
+                       final PlatformSecurityContext context, final 
RoleRepository roleRepository,
+                       final TopicSubscriberReadPlatformService 
topicSubscriberReadPlatformService,
+                       final OfficeRepository officeRepository) {
+               
+               this.businessEventNotifierService = 
businessEventNotifierService;
+               this.notificationEvent = notificationEvent;
+               this.context = context;
+               this.roleRepository = roleRepository;
+               this.topicSubscriberReadPlatformService = 
topicSubscriberReadPlatformService;
+               this.officeRepository = officeRepository;
+       }
+       
+       @PostConstruct
+       public void addListeners() {
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_CREATE,
+                               new ClientCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_APPROVE,
+                               new SavingsAccountApprovedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CENTERS_CREATE,
+                               new CenterCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.GROUPS_CREATE,
+                               new GroupCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_DEPOSIT,
+                               new SavingsAccountDepositListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_PRODUCT_DIVIDENDS_CREATE,
+                               new ShareProductDividendCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.FIXED_DEPOSIT_ACCOUNT_CREATE,
+                               new FixedDepositAccountCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.RECURRING_DEPOSIT_ACCOUNT_CREATE,
+                               new RecurringDepositAccountCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_POST_INTEREST,
+                               new SavingsPostInterestListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CREATE,
+                               new LoanCreatedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_APPROVED,
+                               new LoanApprovedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE,
+                               new LoanClosedListener());
+               
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_CLOSE_AS_RESCHEDULE,
+                               new LoanCloseAsRescheduledListener());
+                
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT,
+                                new LoanMakeRepaymentListener());
+                
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_PRODUCT_CREATE,
+                                new LoanProductCreatedListener());
+                
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CREATE,
+                                new SavingsAccountCreatedListener());
+                
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_CLOSE,
+                                new SavingsAccountClosedListener());
+                
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_CREATE,
+                                new ShareAccountCreatedListener());
+                
businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SHARE_ACCOUNT_APPROVE,
+                                new ShareAccountApprovedListener());
+       }
+       
+       private abstract class NotificationBusinessEventAdapter implements 
BusinessEventListner {
+               @Override
+               public void 
businessEventToBeExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
+               }
+       }
+       
+       private class ClientCreatedListener extends  
NotificationBusinessEventAdapter {
+
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       Client client;
+                       Object entity = 
businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT);
+                       if (entity != null) {
+                               client = (Client) entity;
+                               buildNotification(
+                                               "ACTIVATE_CLIENT",
+                                               "client",
+                                               client.getId(),
+                                               "New client created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               client.getOffice().getId()
+                               );
+                       }
+               }       
+       }
+       
+       private class CenterCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void 
businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
+                       CommandProcessingResult commandProcessingResult;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.GROUP);
+                       if (entity != null) {
+                               commandProcessingResult = 
(CommandProcessingResult) entity;
+                               buildNotification(
+                                               "ACTIVATE_CENTER",
+                                               "center",
+                                               
commandProcessingResult.getGroupId(),
+                                               "New center created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               
commandProcessingResult.getOfficeId()
+                               );
+                       }
+               }
+       }
+       
+       private class GroupCreatedListener extends  
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void 
businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY,
 Object> businessEventEntity) {
+                       CommandProcessingResult commandProcessingResult;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.GROUP);
+                       if (entity != null) {
+                               commandProcessingResult = 
(CommandProcessingResult) entity;
+                               buildNotification(
+                                               "ACTIVATE_GROUP",
+                                               "group",
+                                               
commandProcessingResult.getGroupId(),
+                                               "New group created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               
commandProcessingResult.getOfficeId()
+                               );
+                       }
+               }
+       }
+       
+       private class SavingsAccountDepositListener extends  
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       SavingsAccountTransaction savingsAccountTransaction;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SAVINGS_TRANSACTION);
+                       if (entity != null) {
+                               savingsAccountTransaction = 
(SavingsAccountTransaction) entity;
+                               buildNotification(
+                                               "READ_SAVINGSACCOUNT",
+                                               "savingsAccount",
+                                               
savingsAccountTransaction.getSavingsAccount().getId(),
+                                               "Deposit made",
+                                               "depositMade",
+                                               
context.authenticatedUser().getId(),
+                                               
savingsAccountTransaction.getSavingsAccount().officeId()
+                               );
+                       }
+               }
+       }
+       
+       private class ShareProductDividendCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       Long shareProductId;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SHARE_PRODUCT);
+                       if (entity != null) {
+                               shareProductId = (Long) entity;
+                               buildNotification(
+                                               "READ_DIVIDEND_SHAREPRODUCT",
+                                               "shareProduct",
+                                               shareProductId,
+                                               "Dividend posted to account",
+                                               "dividendPosted",
+                                               
context.authenticatedUser().getId(),
+                                               
context.authenticatedUser().getOffice().getId()
+                               );
+                       }
+               }
+       }
+       
+       private class FixedDepositAccountCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       FixedDepositAccount fixedDepositAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT);
+                       if (entity != null) {
+                               fixedDepositAccount = (FixedDepositAccount) 
entity;
+                               buildNotification(
+                                               "APPROVE_FIXEDDEPOSITACCOUNT",
+                                               "fixedDeposit",
+                                               fixedDepositAccount.getId(),
+                                               "New fixed deposit account 
created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               fixedDepositAccount.officeId()
+                               );
+                       }
+               }
+       }
+       
+       private class RecurringDepositAccountCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       RecurringDepositAccount recurringDepositAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.DEPOSIT_ACCOUNT);
+                       if (entity != null) {
+                               recurringDepositAccount = 
(RecurringDepositAccount) entity;
+                               buildNotification(
+                                               
"APPROVE_RECURRINGDEPOSITACCOUNT",
+                                               "recurringDepositAccount",
+                                               recurringDepositAccount.getId(),
+                                               "New recurring deposit account 
created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               
recurringDepositAccount.officeId()
+                               );
+                       }
+               }
+       }
+       
+       private class SavingsAccountApprovedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       SavingsAccount  savingsAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SAVING);
+                       if (entity != null) {
+                               savingsAccount = (SavingsAccount) entity;
+                               if 
(savingsAccount.depositAccountType().equals(DepositAccountType.FIXED_DEPOSIT)) {
+                                       
+                                       buildNotification(
+                                                       
"ACTIVATE_FIXEDDEPOSITACCOUNT",
+                                                       "fixedDeposit",
+                                                       savingsAccount.getId(),
+                                                       "Fixed deposit account 
approved",
+                                                       "approved",
+                                                       
context.authenticatedUser().getId(),
+                                                       
savingsAccount.officeId()
+                                       );                                      
+                               } else if 
(savingsAccount.depositAccountType().equals(DepositAccountType.RECURRING_DEPOSIT))
 {
+                                       
+                                       buildNotification(
+                                                       
"ACTIVATE_RECURRINGDEPOSITACCOUNT",
+                                                       
"recurringDepositAccount",
+                                                       savingsAccount.getId(),
+                                                       "Recurring deposit 
account approved",
+                                                       "approved",
+                                                       
context.authenticatedUser().getId(),
+                                                       
savingsAccount.officeId()
+                                       );
+                               } else if 
(savingsAccount.depositAccountType().equals(DepositAccountType.SAVINGS_DEPOSIT))
 {
+                                       
+                                       buildNotification(
+                                                       
"ACTIVATE_SAVINGSACCOUNT",
+                                                       "savingsAccount",
+                                                       savingsAccount.getId(),
+                                                       "Savings account 
approved",
+                                                       "approved",
+                                                       
context.authenticatedUser().getId(),
+                                                       
savingsAccount.officeId()
+                                       );
+                               }
+                       }
+               }
+       }
+       
+       private class SavingsPostInterestListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       SavingsAccount savingsAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SAVING);
+                       if (entity != null) {
+                               savingsAccount = (SavingsAccount) entity;
+                               buildNotification(
+                                               "READ_SAVINGSACCOUNT",
+                                               "savingsAccount",
+                                               savingsAccount.getId(),
+                                               "Interest posted to account",
+                                               "interestPosted",
+                                               
context.authenticatedUser().getId(),
+                                               savingsAccount.officeId()
+                               );
+                       }
+               }
+       }
+       
+       private class LoanCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       Loan loan;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN);
+                       if (entity != null) {
+                               loan = (Loan) entity;
+                               buildNotification(
+                                               "APPROVE_LOAN",
+                                               "loan",
+                                               loan.getId(),
+                                               "New loan created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               loan.getOfficeId()
+                               );
+                       }
+                       
+               }
+       }
+       
+       private class LoanApprovedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       Loan loan;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN);
+                       if (entity != null) {
+                               loan = (Loan) entity;
+                               buildNotification(
+                                               "DISBURSE_LOAN",
+                                               "loan",
+                                               loan.getId(),
+                                               "New loan approved",
+                                               "approved",
+                                               
context.authenticatedUser().getId(),
+                                               loan.getOfficeId()
+                               );
+                       }
+               }
+       }
+       
+       private class LoanClosedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       
+                       Loan loan;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN);
+                       if (entity != null) {
+                               loan = (Loan) entity;
+                               buildNotification(
+                                               "READ_LOAN",
+                                               "loan",
+                                               loan.getId(),
+                                               "Loan closed",
+                                               "loanClosed",
+                                               
context.authenticatedUser().getId(),
+                                               loan.getOfficeId()
+                               );
+                       }
+               }
+       }
+               
+       private class LoanCloseAsRescheduledListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       Loan loan;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN);
+                       if (entity != null) {
+                               loan = (Loan) entity;
+                               buildNotification(
+                                               "READ_Rescheduled Loans",
+                                               "loan",
+                                               loan.getId(),
+                                               "Loan has been rescheduled",
+                                               "loanRescheduled",
+                                                
context.authenticatedUser().getId(),
+                                                loan.getOfficeId()
+                               );
+                       }
+               }
+       }
+               
+       private class LoanMakeRepaymentListener extends 
NotificationBusinessEventAdapter {
+                       
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       Loan loan;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN);
+                       if (entity != null) {
+                               loan = (Loan) entity;
+                               buildNotification(
+                                               "READ_LOAN",
+                                               "loan",
+                                               loan.getId(),
+                                               "Repayment made",
+                                               "repaymentMade",
+                                               
context.authenticatedUser().getId(),
+                                               loan.getOfficeId()
+                               );
+                       }
+               }
+       }
+       
+       private class LoanProductCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       
+                       LoanProduct loanProduct;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.LOAN_PRODUCT);
+                       if (entity != null) {
+                               loanProduct = (LoanProduct) entity;
+                               buildNotification(
+                                               "READ_LOANPRODUCT",
+                                               "loanProduct",
+                                               loanProduct.getId(),
+                                               "New loan product created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               
context.authenticatedUser().getOffice().getId()
+                               );
+                       }
+               }
+       }
+       
+       private class SavingsAccountCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       SavingsAccount  savingsAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SAVING);
+                       if (entity != null) {
+                               savingsAccount = (SavingsAccount) entity;
+                               buildNotification(
+                                               "APPROVE_SAVINGSACCOUNT",
+                                               "savingsAccount",
+                                               savingsAccount.getId(),
+                                               "New savings account created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               savingsAccount.officeId()
+                               );
+                       }
+               }
+       }
+       
+       private class SavingsAccountClosedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       SavingsAccount  savingsAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SAVING);
+                       if (entity != null) {
+                               savingsAccount = (SavingsAccount) entity;
+                               buildNotification(
+                                               "READ_SAVINGSACCOUNT",
+                                               "savingsAccount",
+                                               savingsAccount.getId(),
+                                               "Savings has gone into dormant",
+                                               "closed",
+                                               
context.authenticatedUser().getId(),
+                                               savingsAccount.officeId()
+                               );
+                       }
+               }
+       }
+       
+       private class ShareAccountCreatedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       ShareAccount shareAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT);
+                       if (entity != null) {
+                               shareAccount = (ShareAccount) entity;
+                               buildNotification(
+                                               "APPROVE_SHAREACCOUNT",
+                                               "shareAccount",
+                                               shareAccount.getId(),
+                                               "New share account created",
+                                               "created",
+                                               
context.authenticatedUser().getId(),
+                                               shareAccount.getOfficeId()
+                               );
+                       }
+               }
+       }
+       
+       private class ShareAccountApprovedListener extends 
NotificationBusinessEventAdapter {
+               
+               @Override
+               public void businessEventWasExecuted(Map<BUSINESS_ENTITY, 
Object> businessEventEntity) {
+                       ShareAccount shareAccount;
+                       Object entity = 
businessEventEntity.get(BUSINESS_ENTITY.SHARE_ACCOUNT);
+                       if (entity != null) {
+                               shareAccount = (ShareAccount) entity;
+                               buildNotification(
+                                               "ACTIVATE_SHAREACCOUNT",
+                                               "shareAccount",
+                                               shareAccount.getId(),
+                                               "Share account approved",
+                                               "approved",
+                                               
context.authenticatedUser().getId(),
+                                               shareAccount.getOfficeId()
+                               );
+                       }
+               }
+       }
+       
+       private void buildNotification(String permission, String objectType, 
Long objectIdentifier, 
+                       String notificationContent, String eventType,  Long 
appUserId, Long officeId) {
+               
+               String tenantIdentifier = 
ThreadLocalContextUtil.getTenant().getTenantIdentifier();
+               Queue queue = new ActiveMQQueue("NotificationQueue");
+               List<Long> userIds = retrieveSubscribers(officeId, permission);
+               NotificationData notificationData = new NotificationData(
+                               objectType,
+                               objectIdentifier,
+                               eventType,
+                               appUserId,
+                               notificationContent,
+                               false,
+                               false,
+                               tenantIdentifier,
+                               officeId,
+                               userIds
+               );
+               notificationEvent.broadcastNotification(queue, 
notificationData);
+       }
+       
+       private List<Long> retrieveSubscribers(Long officeId, String 
permission) {
+               
+               Collection<TopicSubscriberData> topicSubscribers = new 
ArrayList<>();
+               List<Long> subscriberIds = new ArrayList<>();
+               Long entityId = officeId;
+               String entityType= "";
+               if (officeRepository.findOne(entityId).getParent() == null) {
+                       entityType = "OFFICE";
+               } else {
+                       entityType = "BRANCH";
+               }
+               List<Role> allRoles = roleRepository.findAll();
+               for (Role curRole : allRoles) {
+                       if (curRole.hasPermissionTo(permission) || 
curRole.hasPermissionTo("ALL_FUNCTIONS")) {
+                               System.out.println(curRole + " Role has 
permission");
+                               String memberType = curRole.getName();
+                               topicSubscribers = 
topicSubscriberReadPlatformService.getSubscribers(entityId, entityType, 
memberType);
+                       }
+               }
+               
+               for (TopicSubscriberData topicSubscriber : topicSubscribers) {
+                       subscriberIds.add(topicSubscriber.getUserId());
+                }
+                return subscriberIds;
+       }
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java
index 72c2ded..fe8b13a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationMapperWritePlatformService.java
@@ -20,7 +20,6 @@ package org.apache.fineract.notification.service;
 
 import org.apache.fineract.notification.domain.NotificationMapper;
 
-
 public interface NotificationMapperWritePlatformService {
 
     Long create(NotificationMapper notificationMapper);

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
index c701be2..1c53d4e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
@@ -61,16 +61,12 @@ public class NotificationReadPlatformServiceImpl implements 
NotificationReadPlat
                 Long lastFetch = 
notificationResponseHeaderCache.get(appUserId).getLastFetch();
                 if ((now - lastFetch) > 1) {
                     return this.createUpdateCacheValue(appUserId, now, 
notificationResponseHeaderCache);
-                } else {
-                    return 
notificationResponseHeaderCache.get(appUserId).hasNotifications();
                 }
-            } else {
-                return this.createUpdateCacheValue(appUserId, now, 
notificationResponseHeaderCache);
+                               return 
notificationResponseHeaderCache.get(appUserId).hasNotifications();
             }
-        } else {
-            return 
this.initializeTenantNotificationResponseHeaderCache(tenantId, now, appUserId);
-
+                       return this.createUpdateCacheValue(appUserId, now, 
notificationResponseHeaderCache);
         }
+               return 
this.initializeTenantNotificationResponseHeaderCache(tenantId, now, appUserId);
     }
 
     private boolean initializeTenantNotificationResponseHeaderCache(Long 
tenantId, Long now, Long appUserId) {

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java
index 703cf8e..cb76070 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationWritePlatformService.java
@@ -26,4 +26,5 @@ public interface NotificationWritePlatformService {
 
     Long notify(List<Long> userIds, String objectType, Long objectId, String 
action,
                 Long actorId, String notificationContent, boolean 
isSystemGenerated);
+
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/7395d6c5/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java
new file mode 100644
index 0000000..e6c9ea5
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicReadPlatformService.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.notification.service;
+
+import java.util.Collection;
+import org.apache.fineract.notification.data.TopicData;
+
+public interface TopicReadPlatformService {
+       
+       Collection<TopicData> getAllTopics();
+       
+       Collection<TopicData> getAllEnabledTopics();
+
+       TopicData findById(Long id);
+       
+}

Reply via email to