Add Spring Events to be used when activemq is not available

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

Branch: refs/heads/develop
Commit: 0b0212966cd2af309580587edae6081b8fa1fed7
Parents: 7395d6c
Author: Anh3h <couragean...@gmail.com>
Authored: Tue Dec 12 00:17:24 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   |   1 -
 .../boot/AbstractApplicationConfiguration.java  |   3 +-
 .../TenantAwareBasicAuthenticationFilter.java   |   8 -
 .../api/NotificationApiResource.java            |   2 +-
 .../cache/CacheNotificationResponseHeader.java  |   1 +
 .../config/MessagingConfiguration.java          |  94 +++++++
 .../notification/data/NotificationData.java     |   4 +-
 .../notification/domain/Notification.java       |   8 +-
 .../notification/domain/NotificationMapper.java |   1 +
 .../domain/NotificationRepository.java          |   1 +
 .../eventandlistener/NotificationEvent.java     |  51 ----
 .../eventandlistener/SpringEvent.java           |  38 +++
 .../eventandlistener/SpringEventListener.java   |  92 +++++++
 .../eventandlistener/SpringEventPublisher.java  |  35 +++
 .../service/NotificationDomainServiceImpl.java  |  22 +-
 .../NotificationMapperWritePlatformService.java |   1 +
 .../NotificationReadPlatformServiceImpl.java    |  12 +-
 .../NotificationWritePlatformService.java       |   1 -
 .../service/TopicDomainService.java             |  45 ++++
 .../service/TopicDomainServiceImpl.java         | 249 +++++++++++++++++++
 ...ceWritePlatformServiceJpaRepositoryImpl.java |  54 +---
 .../BusinessEventNotificationConstants.java     |   1 -
 ...esWritePlatformServiceJpaRepositoryImpl.java |   2 -
 ...ctWritePlatformServiceJpaRepositoryImpl.java |   8 +-
 ...erWritePlatformServiceJpaRepositoryImpl.java |  96 ++-----
 ...leWritePlatformServiceJpaRepositoryImpl.java |  61 ++---
 .../resources/META-INF/spring/appContext.xml    |   1 -
 .../META-INF/spring/notificationContext.xml     |  45 ----
 .../core_db/V336__topic_module_table.sql        |  45 ----
 .../core_db/V342__topic_module_table.sql        |  45 ++++
 .../fineract/notification/StorageTest.java      |   2 -
 32 files changed, 678 insertions(+), 352 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/dependencies.gradle
----------------------------------------------------------------------
diff --git a/fineract-provider/dependencies.gradle 
b/fineract-provider/dependencies.gradle
index d157c89..27a256c 100644
--- a/fineract-provider/dependencies.gradle
+++ b/fineract-provider/dependencies.gradle
@@ -93,6 +93,7 @@ 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/0b021296/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 b052649..785dab1 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
@@ -52,5 +52,4 @@ public class NotificationApiTest {
         System.out.println("Response : " + response.toString());
         Assert.assertNotNull(response);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java
index dd8fc20..53bf337 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.infrastructure.core.boot;
 
+import org.apache.fineract.notification.config.MessagingConfiguration;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -41,7 +42,7 @@ import org.springframework.context.annotation.PropertySource;
  */
 @Configuration
 @Import({ WebXmlConfiguration.class, WebXmlOauthConfiguration.class, 
WebFrontEndConfiguration.class,
-               WebTwoFactorXmlConfiguration.class })
+       MessagingConfiguration.class, WebTwoFactorXmlConfiguration.class })
 @ImportResource({ "classpath*:META-INF/spring/appContext.xml" })
 @PropertySource(value="classpath:META-INF/spring/jdbc.properties")
 @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 ccd71cb..a36079d 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,7 +28,6 @@ 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;
@@ -79,7 +78,6 @@ 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;
@@ -179,12 +177,6 @@ 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/0b021296/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 860c74f..065d7cb 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,6 +18,7 @@
  */
 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;
@@ -85,5 +86,4 @@ public class NotificationApiResource {
         this.context.authenticatedUser();
         this.notificationReadPlatformService.updateNotificationReadStatus();
     }
-
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 3b5a6e1..205050b 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,6 +18,7 @@
  */
 package org.apache.fineract.notification.cache;
 
+
 public class CacheNotificationResponseHeader {
 
     private boolean hasNotifications;

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/notification/config/MessagingConfiguration.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/config/MessagingConfiguration.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/config/MessagingConfiguration.java
new file mode 100644
index 0000000..88713d0
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/config/MessagingConfiguration.java
@@ -0,0 +1,94 @@
+/**
+ * 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.config;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import 
org.apache.fineract.infrastructure.core.boot.db.TenantDataSourcePortFixService;
+import 
org.apache.fineract.notification.eventandlistener.NotificationEventListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jms.connection.CachingConnectionFactory;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.jms.listener.DefaultMessageListenerContainer;
+
+@Configuration
+public class MessagingConfiguration {
+       
+       @Autowired
+       private Environment env;
+       
+       @Autowired
+       private NotificationEventListener notificationEventListener;
+
+       @Bean
+         public Logger loggerBean() { return 
LoggerFactory.getLogger(TenantDataSourcePortFixService.class); }
+
+       private static final String DEFAULT_BROKER_URL = 
"tcp://localhost:61616";
+       
+    @Bean
+    public ActiveMQConnectionFactory amqConnectionFactory(){
+        ActiveMQConnectionFactory amqConnectionFactory = new 
ActiveMQConnectionFactory();
+        try {
+               amqConnectionFactory.setBrokerURL(DEFAULT_BROKER_URL);
+        } catch(Exception e) {
+               
amqConnectionFactory.setBrokerURL(this.env.getProperty("brokerUrl"));
+        }
+        return amqConnectionFactory;
+    }
+    
+    @Bean
+    public CachingConnectionFactory connectionFactory() {
+       CachingConnectionFactory connectionFactory = new 
CachingConnectionFactory(amqConnectionFactory());
+       return connectionFactory;
+    }
+    
+    @Bean
+    public JmsTemplate jmsTemplate(){
+       JmsTemplate jmsTemplate ;
+               jmsTemplate = new JmsTemplate(connectionFactory());
+               jmsTemplate.setConnectionFactory(connectionFactory());
+               return jmsTemplate;
+    }
+    
+    @Bean
+    public DefaultMessageListenerContainer messageListenerContainer() { 
+       
+       DefaultMessageListenerContainer messageListenerContainer = new 
DefaultMessageListenerContainer();
+       messageListenerContainer.setConnectionFactory(connectionFactory());
+       messageListenerContainer.setDestinationName("NotificationQueue");
+       messageListenerContainer.setMessageListener(notificationEventListener);
+       messageListenerContainer.setExceptionListener(new ExceptionListener() {
+               @Override
+            public void onException(JMSException jmse)
+            {
+                       loggerBean().error("Network Error: ActiveMQ Broker 
Unavailable.");
+                       messageListenerContainer.shutdown();
+            } 
+       });
+       return messageListenerContainer;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 865447c..b4937ab 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,7 +29,7 @@ public class NotificationData implements Serializable {
     private String action;
     private Long actorId;
     private String content;
-       private boolean isRead;
+    private boolean isRead;
     private boolean isSystemGenerated;
     private String tenantIdentifier;
     private String createdAt;
@@ -47,7 +47,7 @@ public class NotificationData implements Serializable {
         this.action = action;
         this.actorId = actorId;
         this.content = content;
-               this.isRead = isRead;
+        this.isRead = isRead;
         this.isSystemGenerated = isSystemGenerated;
         this.tenantIdentifier = tenantIdentifier;
         this.officeId = officeId;

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 4985f25..42a3575 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,7 +20,9 @@ package org.apache.fineract.notification.domain;
 
 import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
 
-import javax.persistence.*;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
 
 @Entity
 @Table(name = "notification_generator")
@@ -88,7 +90,7 @@ public class Notification extends 
AbstractPersistableCustom<Long> {
         return actorId;
     }
 
-    public void setActor(Long actorId) {
+    public void setActor(Long actor) {
         this.actorId = actorId;
     }
 
@@ -107,4 +109,4 @@ public class Notification extends 
AbstractPersistableCustom<Long> {
     public void setNotificationContent(String notificationContent) {
         this.notificationContent = notificationContent;
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 970b447..5297d23 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,6 +18,7 @@
  */
 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/0b021296/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 6b9160f..ed0675d 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,4 +20,5 @@ 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/0b021296/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
deleted file mode 100644
index 9df5215..0000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/NotificationEvent.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * 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/0b021296/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEvent.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEvent.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEvent.java
new file mode 100644
index 0000000..0a27cd5
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEvent.java
@@ -0,0 +1,38 @@
+/**
+ * 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 org.apache.fineract.notification.data.NotificationData;
+import org.springframework.context.ApplicationEvent;
+
+@SuppressWarnings("serial")
+public class SpringEvent extends ApplicationEvent {
+
+       private NotificationData notificationData;
+        
+    public SpringEvent(Object source, NotificationData notificationData) {
+        super(source);
+        this.notificationData = notificationData;
+    }
+    
+    public NotificationData getNotificationData() {
+        return notificationData;
+    }
+       
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventListener.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventListener.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventListener.java
new file mode 100644
index 0000000..bf4e0ce
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventListener.java
@@ -0,0 +1,92 @@
+/**
+ * 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 java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import 
org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
+import org.apache.fineract.notification.data.NotificationData;
+import 
org.apache.fineract.notification.service.NotificationWritePlatformService;
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.apache.fineract.useradministration.domain.AppUserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringEventListener implements ApplicationListener<SpringEvent> {
+       
+       private final BasicAuthTenantDetailsService 
basicAuthTenantDetailsService;
+
+    private final NotificationWritePlatformService 
notificationWritePlatformService;
+
+    private final AppUserRepository appUserRepository;
+    
+    @Autowired
+    public SpringEventListener(BasicAuthTenantDetailsService 
basicAuthTenantDetailsService,
+                                     NotificationWritePlatformService 
notificationWritePlatformService,
+                                     AppUserRepository appUserRepository) {
+        this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
+        this.notificationWritePlatformService = 
notificationWritePlatformService;
+        this.appUserRepository = appUserRepository;
+    }
+
+       @Override
+       public void onApplicationEvent(SpringEvent event) {
+               NotificationData notificationData = event.getNotificationData();
+               
+               final FineractPlatformTenant tenant = 
this.basicAuthTenantDetailsService
+                .loadTenantById(notificationData.getTenantIdentifier(), false);
+        ThreadLocalContextUtil.setTenant(tenant);
+
+        Long appUserId = notificationData.getActor();
+
+        List<Long> userIds = notificationData.getUserIds();
+
+        if (notificationData.getOfficeId() != null) {
+            List<Long> tempUserIds = new ArrayList<>(userIds);
+            for (Long userId : tempUserIds) {
+                AppUser appUser = appUserRepository.findOne(userId);
+                if (!Objects.equals(appUser.getOffice().getId(), 
notificationData.getOfficeId())) {
+                    userIds.remove(userId);
+                }
+            }
+        }
+
+        if (userIds.contains(appUserId)) {
+            userIds.remove(appUserId);
+        }
+
+        notificationWritePlatformService.notify(
+                userIds,
+                notificationData.getObjectType(),
+                notificationData.getObjectIdentfier(),
+                notificationData.getAction(),
+                notificationData.getActor(),
+                notificationData.getContent(),
+                notificationData.isSystemGenerated()
+        );
+               
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventPublisher.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventPublisher.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventPublisher.java
new file mode 100644
index 0000000..1e7ed06
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/eventandlistener/SpringEventPublisher.java
@@ -0,0 +1,35 @@
+/**
+ * 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 org.apache.fineract.notification.data.NotificationData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SpringEventPublisher {
+       @Autowired
+       private ApplicationEventPublisher applicationEventPublisher;
+       
+       public void broadcastNotification(final NotificationData 
notificationData) {
+        SpringEvent event = new SpringEvent(this, notificationData);
+        applicationEventPublisher.publishEvent(event);
+    }
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 1744bd3..6617cbd 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
@@ -24,7 +24,8 @@ 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.data.TopicSubscriberData;
-import org.apache.fineract.notification.eventandlistener.NotificationEvent;
+import 
org.apache.fineract.notification.eventandlistener.NotificationEventService;
+import org.apache.fineract.notification.eventandlistener.SpringEventPublisher;
 import org.apache.fineract.organisation.office.domain.OfficeRepository;
 import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants;
@@ -47,6 +48,7 @@ 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;
@@ -56,25 +58,27 @@ import java.util.Map;
 public class NotificationDomainServiceImpl implements 
NotificationDomainService {
 
        private final BusinessEventNotifierService businessEventNotifierService;
-       private final NotificationEvent notificationEvent;
-       private final PlatformSecurityContext context;
+       final PlatformSecurityContext context;
        private final RoleRepository roleRepository;
        private final OfficeRepository officeRepository;
        private final TopicSubscriberReadPlatformService 
topicSubscriberReadPlatformService;
+       private final NotificationEventService notificationEvent;
+       private final SpringEventPublisher springEventPublisher;
        
        @Autowired
        public NotificationDomainServiceImpl(final BusinessEventNotifierService 
businessEventNotifierService,
-                       final NotificationEvent notificationEvent,
                        final PlatformSecurityContext context, final 
RoleRepository roleRepository,
                        final TopicSubscriberReadPlatformService 
topicSubscriberReadPlatformService,
-                       final OfficeRepository officeRepository) {
+                       final OfficeRepository officeRepository, final 
NotificationEventService notificationEvent,
+                       final SpringEventPublisher springEventPublisher) {
                
                this.businessEventNotifierService = 
businessEventNotifierService;
-               this.notificationEvent = notificationEvent;
                this.context = context;
                this.roleRepository = roleRepository;
                this.topicSubscriberReadPlatformService = 
topicSubscriberReadPlatformService;
                this.officeRepository = officeRepository;
+               this.notificationEvent = notificationEvent;
+               this.springEventPublisher = springEventPublisher;
        }
        
        @PostConstruct
@@ -570,7 +574,11 @@ public class NotificationDomainServiceImpl implements 
NotificationDomainService
                                officeId,
                                userIds
                );
-               notificationEvent.broadcastNotification(queue, 
notificationData);
+               try {
+                       this.notificationEvent.broadcastNotification(queue, 
notificationData);
+               } catch(Exception e) {
+                       
this.springEventPublisher.broadcastNotification(notificationData);
+               }
        }
        
        private List<Long> retrieveSubscribers(Long officeId, String 
permission) {

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 fe8b13a..72c2ded 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,6 +20,7 @@ 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/0b021296/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 1c53d4e..799fddf 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,12 +61,16 @@ 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();
                 }
-                               return 
notificationResponseHeaderCache.get(appUserId).hasNotifications();
+            } else {
+                return this.createUpdateCacheValue(appUserId, now, 
notificationResponseHeaderCache);
             }
-                       return this.createUpdateCacheValue(appUserId, now, 
notificationResponseHeaderCache);
+        } else {
+            return 
this.initializeTenantNotificationResponseHeaderCache(tenantId, now, appUserId);
+
         }
-               return 
this.initializeTenantNotificationResponseHeaderCache(tenantId, now, appUserId);
     }
 
     private boolean initializeTenantNotificationResponseHeaderCache(Long 
tenantId, Long now, Long appUserId) {
@@ -212,4 +216,4 @@ public class NotificationReadPlatformServiceImpl implements 
NotificationReadPlat
             return notificationData;
         }
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/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 cb76070..703cf8e 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,5 +26,4 @@ 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/0b021296/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainService.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainService.java
new file mode 100644
index 0000000..f96befd
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainService.java
@@ -0,0 +1,45 @@
+/**
+ * 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.Map;
+
+import org.apache.fineract.organisation.office.domain.Office;
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.apache.fineract.useradministration.domain.Role;
+
+public interface TopicDomainService {
+       
+       public void createTopic( Office newOffice );
+       
+       public void createTopic( Role newRole );
+       
+       public void updateTopic( Office updatedOffice, Map<String, Object> 
changes );
+       
+       public void updateTopic( String previousRolename, Role updatedRole, 
Map<String, Object> changes );
+       
+       public void deleteTopic( Role role );
+       
+       public void subscribeUserToTopic( AppUser newUser );
+       
+       public void updateUserSubscription( AppUser userToUpdate, Map<String, 
Object> changes );
+       
+       public void unsubcribeUserFromTopic( AppUser user );
+       
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainServiceImpl.java
new file mode 100644
index 0000000..fe1bb6c
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/notification/service/TopicDomainServiceImpl.java
@@ -0,0 +1,249 @@
+/**
+ * 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.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.fineract.notification.domain.Topic;
+import org.apache.fineract.notification.domain.TopicRepository;
+import org.apache.fineract.notification.domain.TopicSubscriber;
+import org.apache.fineract.notification.domain.TopicSubscriberRepository;
+import org.apache.fineract.organisation.office.domain.Office;
+import org.apache.fineract.organisation.office.domain.OfficeRepository;
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.apache.fineract.useradministration.domain.Role;
+import org.apache.fineract.useradministration.domain.RoleRepository;
+import org.apache.fineract.useradministration.exception.RoleNotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+
+@Service
+public class TopicDomainServiceImpl implements TopicDomainService {
+
+       private final RoleRepository roleRepository;
+       private final TopicRepository topicRepository;
+    private final OfficeRepository officeRepository;
+    private final TopicSubscriberRepository topicSubscriberRepository;
+       
+       @Autowired
+       public TopicDomainServiceImpl(RoleRepository roleRepository, 
TopicRepository topicRepository,
+                       OfficeRepository officeRepository, 
TopicSubscriberRepository topicSubscriberRepository) {
+               
+               this.roleRepository = roleRepository;
+               this.topicRepository = topicRepository;
+               this.officeRepository = officeRepository;
+               this.topicSubscriberRepository = topicSubscriberRepository;
+       }
+       
+       @Override
+       public void createTopic( Office newOffice ) {
+               
+               Long entityId = newOffice.getId();
+        String entityType = this.getEntityType(newOffice);
+        
+        List<Role> allRoles = roleRepository.findAll();
+        for(Role role : allRoles) {
+               String memberType = role.getName().toUpperCase();
+               String title = role.getName() + " of " + newOffice.getName();
+               Topic newTopic = new Topic(title, true, entityId, entityType, 
memberType);
+               topicRepository.save(newTopic);
+        }
+       }
+       
+       @Override
+       public void createTopic( Role newRole ) {
+               
+               List<Office> offices = officeRepository.findAll();
+               
+        for (Office office : offices){
+               String entityType = this.getEntityType(office);
+               String title = newRole.getName() + " of " + office.getName();
+               Topic newTopic = new Topic(title, true, office.getId(), 
entityType, newRole.getName().toUpperCase());
+               topicRepository.save(newTopic);
+        }
+       }
+       
+       @Override
+       public void updateTopic( Office updatedOffice, Map<String, Object> 
changes ) {
+               
+               List<Topic> entityTopics = 
topicRepository.findByEntityId(updatedOffice.getId());
+               
+               if (changes.containsKey("parentId")) {
+                       
+            String entityType = this.getEntityType(updatedOffice);
+            for (Topic topic : entityTopics) {
+               topic.setEntityType(entityType);
+               topicRepository.save(topic);
+            }
+               }
+               if (changes.containsKey("name")) {
+                       
+               for (Topic topic: entityTopics) {
+                       Role role = 
roleRepository.getRoleByName(topic.getMemberType());
+                String title = role.getName() + " of " + 
updatedOffice.getName();
+                topic.setTitle(title);
+                topicRepository.save(topic);
+               }
+        }
+       }
+       
+       @Override
+       public void updateTopic( String previousRolename, Role updatedRole, 
Map<String, Object> changes ) {
+
+        if (changes.containsKey("name")) {
+               List<Topic> entityTopics = 
topicRepository.findByMemberType(previousRolename);
+               for (Topic topic : entityTopics) {
+                       Office office = 
officeRepository.findOne(topic.getEntityId());
+                       String title = updatedRole.getName() + " of " + 
office.getName();
+                       topic.setTitle(title);
+               topic.setMemberType(updatedRole.getName().toUpperCase());
+               topicRepository.save(topic);
+               }
+        }
+       }
+       
+       @Override
+       public void deleteTopic( Role role ) {
+               
+               List<Topic> topics = 
topicRepository.findByMemberType(role.getName().toUpperCase());
+        for (Topic topic : topics) {
+               topicRepository.delete(topic);
+        }
+       }
+       
+       @Override
+       public void subscribeUserToTopic( AppUser newUser ) {
+               
+               List<Topic> possibleTopics = 
topicRepository.findByEntityId(newUser.getOffice().getId());
+        
+        if (!possibleTopics.isEmpty()) {
+               Set<Role> userRoles = newUser.getRoles();
+               for (Role role : userRoles) {
+                       for (Topic topic : possibleTopics) {
+                               
if(role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
+                                       TopicSubscriber topicSubscriber = new 
TopicSubscriber(topic, newUser, new Date());
+                                       
topicSubscriberRepository.save(topicSubscriber);
+                               }
+                       }
+               }
+        }
+       }
+       
+       @Override
+       public void updateUserSubscription( AppUser userToUpdate, Map<String, 
Object> changes ) {
+               
+               List<TopicSubscriber> oldSubscriptions = 
topicSubscriberRepository.findBySubscriber(userToUpdate);
+               if (changes.containsKey("officeId")) {
+                       final Long oldOfficeId = 
userToUpdate.getOffice().getId();
+               final Long newOfficeId = (Long) changes.get("officeId");
+               List<Topic> oldTopics = 
topicRepository.findByEntityId(oldOfficeId);
+            List<Topic> newTopics = 
topicRepository.findByEntityId(newOfficeId);
+            
+            for (TopicSubscriber subscriber : oldSubscriptions) {
+               for (Topic topic : oldTopics) {
+                       if (subscriber.getTopic().getId() == topic.getId()) {
+                               topicSubscriberRepository.delete(subscriber);
+                       }
+               }
+            }
+            
+            Set<Role> userRoles = userToUpdate.getRoles();
+               for (Role role : userRoles) {
+                       for (Topic topic : newTopics) {
+                               if 
(role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
+                                       TopicSubscriber newSubscription = new 
TopicSubscriber(topic, userToUpdate, new Date());
+                                       
topicSubscriberRepository.save(newSubscription);
+                               }
+                       }
+               }
+               }
+               
+               if (changes.containsKey("roles")) {
+                       
+                       final Set<Role> oldRoles = userToUpdate.getRoles() ;
+            final Set<Role> tempOldRoles = new HashSet<>(oldRoles);
+            
+            final String[] roleIds = (String[]) changes.get("roles");
+            final Set<Role> updatedRoles = assembleSetOfRoles(roleIds);
+            final Set<Role> tempUpdatedRoles = new HashSet<>(updatedRoles);
+            
+            tempOldRoles.removeAll(updatedRoles);
+            for (TopicSubscriber subscriber : oldSubscriptions) {
+               Topic topic = subscriber.getTopic();
+               for (Role role : tempOldRoles) {
+                       if 
(role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
+                               topicSubscriberRepository.delete(subscriber);
+                       }
+               }
+            }
+            
+            tempUpdatedRoles.removeAll(oldRoles);
+            List<Topic> newTopics = 
topicRepository.findByEntityId(userToUpdate.getOffice().getId());
+            for (Topic topic : newTopics) {
+               for (Role role : tempUpdatedRoles) {
+                       if 
(role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
+                               TopicSubscriber topicSubscriber = new 
TopicSubscriber(topic, userToUpdate, new Date());
+                                       
topicSubscriberRepository.save(topicSubscriber);
+                       }
+               }
+            }
+               }
+       }
+       
+       @Override
+       public void unsubcribeUserFromTopic( AppUser user ) {
+               
+               List<TopicSubscriber> subscriptions = 
topicSubscriberRepository.findBySubscriber(user);
+        for (TopicSubscriber subscription : subscriptions) {
+               topicSubscriberRepository.delete(subscription);
+        }
+       }
+       
+
+       private String getEntityType( Office office ) {
+               
+        if (office.getParent() == null) {
+               return "OFFICE";
+        } else {
+               return "BRANCH";
+        }
+       }
+       
+       private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
+
+        final Set<Role> allRoles = new HashSet<>();
+
+        if (!ObjectUtils.isEmpty(rolesArray)) {
+            for (final String roleId : rolesArray) {
+                final Long id = Long.valueOf(roleId);
+                final Role role = this.roleRepository.findOne(id);
+                if (role == null) { throw new RoleNotFoundException(id); }
+                allRoles.add(role);
+            }
+        }
+
+        return allRoles;
+    }
+       
+}

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java
index 9da65f6..d56c0cc 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java
@@ -18,7 +18,6 @@
  */
 package org.apache.fineract.organisation.office.service;
 
-import java.util.List;
 import java.util.Map;
 
 import javax.persistence.PersistenceException;
@@ -30,8 +29,7 @@ import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import 
org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.notification.domain.Topic;
-import org.apache.fineract.notification.domain.TopicRepository;
+import org.apache.fineract.notification.service.TopicDomainService;
 import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
@@ -43,8 +41,6 @@ import 
org.apache.fineract.organisation.office.domain.OfficeTransactionRepositor
 import 
org.apache.fineract.organisation.office.serialization.OfficeCommandFromApiJsonDeserializer;
 import 
org.apache.fineract.organisation.office.serialization.OfficeTransactionCommandFromApiJsonDeserializer;
 import org.apache.fineract.useradministration.domain.AppUser;
-import org.apache.fineract.useradministration.domain.Role;
-import org.apache.fineract.useradministration.domain.RoleRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -65,23 +61,21 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl 
implements OfficeWriteP
     private final OfficeRepositoryWrapper officeRepositoryWrapper;
     private final OfficeTransactionRepository officeTransactionRepository;
     private final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository;
-    private final RoleRepository roleRepository;
-    private final TopicRepository topicRepository;
+    private final TopicDomainService topicDomainService;
 
     @Autowired
     public OfficeWritePlatformServiceJpaRepositoryImpl(final 
PlatformSecurityContext context,
             final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer,
             final OfficeTransactionCommandFromApiJsonDeserializer 
moneyTransferCommandFromApiJsonDeserializer,
             final OfficeRepositoryWrapper officeRepositoryWrapper, final 
OfficeTransactionRepository officeMonetaryTransferRepository,
-            final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository, RoleRepository roleRepository, TopicRepository 
topicRepository) {
+            final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository, final TopicDomainService topicDomainService) {
         this.context = context;
         this.fromApiJsonDeserializer = fromApiJsonDeserializer;
         this.moneyTransferCommandFromApiJsonDeserializer = 
moneyTransferCommandFromApiJsonDeserializer;
         this.officeRepositoryWrapper = officeRepositoryWrapper;
         this.officeTransactionRepository = officeMonetaryTransferRepository;
         this.applicationCurrencyRepository = applicationCurrencyRepository;
-        this.roleRepository = roleRepository;
-        this.topicRepository = topicRepository;
+        this.topicDomainService = topicDomainService;
     }
 
     @Transactional
@@ -111,22 +105,7 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl 
implements OfficeWriteP
 
             this.officeRepositoryWrapper.save(office);
             
-            Long entityId = office.getId();
-            String entityType = "";
-            if (office.getParent() == null) {
-               entityType = "OFFICE";
-            } else {
-               entityType = "BRANCH";
-            }
-            
-            List<Role> allRoles = roleRepository.findAll();
-            for(Role curRole : allRoles) {
-               String memberType = curRole.getName().toUpperCase();
-               String title = curRole.getName() + " of " + office.getName();
-               Topic newTopic = new Topic(title, true, entityId, entityType, 
memberType);
-               topicRepository.save(newTopic);
-            }
-            
+            this.topicDomainService.createTopic(office);
 
             return new CommandProcessingResultBuilder() //
                     .withCommandId(command.commandId()) //
@@ -168,31 +147,12 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl 
implements OfficeWriteP
             if (changes.containsKey("parentId")) {
                 final Office parent = 
validateUserPriviledgeOnOfficeAndRetrieve(currentUser, parentId);
                 office.update(parent);
-                String entityType = "";
-                if (office.getParent() == null) {
-                       entityType = "OFFICE";
-                } else {
-                       entityType = "BRANCH";
-                }
-                List<Topic> entityTopics = 
topicRepository.findByEntityId(office.getId());
-                for (Topic topic : entityTopics) {
-                       topic.setEntityType(entityType);
-                       topicRepository.save(topic);
-                }
-            }
-            
-            if (changes.containsKey("name")) {
-               List<Topic> entityTopics = 
topicRepository.findByEntityId(office.getId());
-               for (Topic topic: entityTopics) {
-                       Role role = 
roleRepository.getRoleByName(topic.getMemberType());
-                       String title = role.getName() + " of " + 
office.getName();
-                       topic.setTitle(title);
-                       topicRepository.save(topic);
-               }
             }
 
             if (!changes.isEmpty()) {
                 this.officeRepositoryWrapper.saveAndFlush(office);
+                
+                this.topicDomainService.updateTopic(office, changes);
             }
 
             return new CommandProcessingResultBuilder() //

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
index 4e8966a..4a11d02 100755
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
@@ -67,7 +67,6 @@ public class BusinessEventNotificationConstants {
         "loan_adjusted_transaction"), SAVING("saving"), CLIENT("client"), 
SAVINGS_TRANSACTION("Savings Transaction"), GROUP("group"),
         SHARE_ACCOUNT("share_account"), SHARE_PRODUCT("share_product"), 
DEPOSIT_ACCOUNT("deposit_account"), LOAN_PRODUCT("loan_product");
 
-
         private final String value;
 
         private BUSINESS_ENTITY(final String value) {

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
index 55cfce6..2616c27 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
@@ -53,8 +53,6 @@ import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
 import org.apache.fineract.portfolio.client.service.LoanStatusMapper;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants;
-import 
org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
-import 
org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
 import 
org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
 import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants;
 import org.apache.fineract.portfolio.group.domain.*;

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
index 463ec62..1a4ff23 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
@@ -215,11 +215,11 @@ public class 
ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareP
         throw new 
PlatformDataIntegrityException("error.msg.shareproduct.unknown.data.integrity.issue",
                 "Unknown data integrity issue with resource.");
     }
-    
+
     private Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> 
constructEntityMap(final BusinessEventNotificationConstants.BUSINESS_ENTITY 
entityEvent, Object entity) {
-       Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> map = 
new HashMap<>(1);
-       map.put(entityEvent, entity);
-       return map;
+        Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> map = 
new HashMap<>(1);
+        map.put(entityEvent, entity);
+        return map;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java
index 7fefedc..ad96bc4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java
@@ -20,12 +20,12 @@ package org.apache.fineract.useradministration.service;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.persistence.EntityExistsException;
 import javax.persistence.PersistenceException;
 
 import org.apache.commons.lang.exception.ExceptionUtils;
@@ -39,10 +39,7 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityEx
 import 
org.apache.fineract.infrastructure.core.service.PlatformEmailSendException;
 import 
org.apache.fineract.infrastructure.security.service.PlatformPasswordEncoder;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.notification.domain.Topic;
-import org.apache.fineract.notification.domain.TopicRepository;
-import org.apache.fineract.notification.domain.TopicSubscriber;
-import org.apache.fineract.notification.domain.TopicSubscriberRepository;
+import org.apache.fineract.notification.service.TopicDomainService;
 import org.apache.fineract.organisation.office.domain.Office;
 import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
 import org.apache.fineract.organisation.staff.domain.Staff;
@@ -91,16 +88,14 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
     private final AppUserPreviousPasswordRepository 
appUserPreviewPasswordRepository;
     private final StaffRepositoryWrapper staffRepositoryWrapper;
     private final ClientRepositoryWrapper clientRepositoryWrapper;
-    private final TopicRepository topicRepository;
-    private final TopicSubscriberRepository topicSubscriberRepository;
+    private final TopicDomainService topicDomainService;
 
     @Autowired
     public AppUserWritePlatformServiceJpaRepositoryImpl(final 
PlatformSecurityContext context, final AppUserRepository appUserRepository,
             final UserDomainService userDomainService, final 
OfficeRepositoryWrapper officeRepositoryWrapper, final RoleRepository 
roleRepository,
             final PlatformPasswordEncoder platformPasswordEncoder, final 
UserDataValidator fromApiJsonDeserializer,
             final AppUserPreviousPasswordRepository 
appUserPreviewPasswordRepository, final StaffRepositoryWrapper 
staffRepositoryWrapper,
-            final ClientRepositoryWrapper clientRepositoryWrapper, final 
TopicRepository topicRepository,
-            final TopicSubscriberRepository topicSubscriberRepository) {
+            final ClientRepositoryWrapper clientRepositoryWrapper, final 
TopicDomainService topicDomainService) {
         this.context = context;
         this.appUserRepository = appUserRepository;
         this.userDomainService = userDomainService;
@@ -111,8 +106,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
         this.appUserPreviewPasswordRepository = 
appUserPreviewPasswordRepository;
         this.staffRepositoryWrapper = staffRepositoryWrapper;
         this.clientRepositoryWrapper = clientRepositoryWrapper;
-        this.topicRepository = topicRepository;
-        this.topicSubscriberRepository = topicSubscriberRepository;
+        this.topicDomainService = topicDomainService;
     }
 
     @Transactional
@@ -159,19 +153,8 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
 
             final Boolean sendPasswordToEmail = 
command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
             this.userDomainService.create(appUser, sendPasswordToEmail);
-            List<Topic> possibleTopics = 
topicRepository.findByEntityId(appUser.getOffice().getId());
             
-            if (!possibleTopics.isEmpty()) {
-               Set<Role> userRoles = appUser.getRoles();
-               for (Role curRole : userRoles) {
-                       for (Topic curTopic : possibleTopics) {
-                               
if(curRole.getName().compareToIgnoreCase(curTopic.getMemberType()) == 0) {
-                                       TopicSubscriber topicSubscriber = new 
TopicSubscriber(curTopic, appUser, new Date());
-                                       
topicSubscriberRepository.save(topicSubscriber);
-                               }
-                       }
-               }
-            }
+            this.topicDomainService.subscribeUserToTopic(appUser);
 
             return new CommandProcessingResultBuilder() //
                     .withCommandId(command.commandId()) //
@@ -223,7 +206,8 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
                isSelfServiceUser = 
command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER);
 
             }
             
-            if(isSelfServiceUser && 
command.hasParameter(AppUserConstants.CLIENTS)){
+            if(isSelfServiceUser
+                       && command.hasParameter(AppUserConstants.CLIENTS)){
                JsonArray clientsArray = 
command.arrayOfParameterNamed(AppUserConstants.CLIENTS);
                Collection<Long> clientIds = new HashSet<>();
                for(JsonElement clientElement : clientsArray){
@@ -234,33 +218,11 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
 
             final Map<String, Object> changes = userToUpdate.update(command, 
this.platformPasswordEncoder, clients);
 
+            this.topicDomainService.updateUserSubscription(userToUpdate, 
changes);
             if (changes.containsKey("officeId")) {
-                final Long oldOfficeId = userToUpdate.getOffice().getId();
-                final Long newOfficeId = (Long) changes.get("officeId");
-                final Office office = 
this.officeRepositoryWrapper.findOneWithNotFoundDetection(newOfficeId);
+                final Long officeId = (Long) changes.get("officeId");
+                final Office office = 
this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
                 userToUpdate.changeOffice(office);
-
-                List<Topic> oldTopics = 
topicRepository.findByEntityId(oldOfficeId);
-                List<Topic> newTopics = 
topicRepository.findByEntityId(newOfficeId);
-                
-                List<TopicSubscriber> oldSubscriptions = 
topicSubscriberRepository.findBySubscriber(userToUpdate);
-                for (TopicSubscriber subscriber : oldSubscriptions) {
-                       for (Topic topic : oldTopics) {
-                               if (subscriber.getTopic().getId() == 
topic.getId()) {
-                                       
topicSubscriberRepository.delete(subscriber);
-                               }
-                       }
-                }
-                
-                Set<Role> userRoles = userToUpdate.getRoles();
-               for (Role curRole : userRoles) {
-                       for (Topic curTopic : newTopics) {
-                               if 
(curRole.getName().compareToIgnoreCase(curTopic.getMemberType()) == 0) {
-                                       TopicSubscriber newSubscription = new 
TopicSubscriber(curTopic, userToUpdate, new Date());
-                                       
topicSubscriberRepository.save(newSubscription);
-                               }
-                       }
-               }
             }
 
             if (changes.containsKey("staffId")) {
@@ -274,34 +236,9 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
 
             if (changes.containsKey("roles")) {
                 final String[] roleIds = (String[]) changes.get("roles");
-                final Set<Role> oldRoles = userToUpdate.getRoles() ;
-                final Set<Role> tempOldRoles = new HashSet<>(oldRoles);
-                final Set<Role> updatedRoles = assembleSetOfRoles(roleIds);
-                final Set<Role> tempUpdatedRoles = new HashSet<>(updatedRoles);
-                
-                tempOldRoles.removeAll(updatedRoles);
-                List<TopicSubscriber> oldSubscriptions = 
topicSubscriberRepository.findBySubscriber(userToUpdate);
-                for (TopicSubscriber subscriber : oldSubscriptions) {
-                       Topic topic = subscriber.getTopic();
-                       for (Role role : tempOldRoles) {
-                               if 
(role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
-                                       
topicSubscriberRepository.delete(subscriber);
-                               }
-                       }
-                }
-                
-                tempUpdatedRoles.removeAll(oldRoles);
-                List<Topic> newTopics = 
topicRepository.findByEntityId(userToUpdate.getOffice().getId());
-                for (Topic topic : newTopics) {
-                       for (Role role : tempUpdatedRoles) {
-                               if 
(role.getName().compareToIgnoreCase(topic.getMemberType()) == 0) {
-                                       TopicSubscriber topicSubscriber = new 
TopicSubscriber(topic, userToUpdate, new Date());
-                                       
topicSubscriberRepository.save(topicSubscriber);
-                               }
-                       }
-                }
-                
-                userToUpdate.updateRoles(updatedRoles);
+                final Set<Role> allRoles = assembleSetOfRoles(roleIds);
+
+                userToUpdate.updateRoles(allRoles);
             }
 
             if (!changes.isEmpty()) {
@@ -393,10 +330,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl 
implements AppUserWrit
         if (user == null || user.isDeleted()) { throw new 
UserNotFoundException(userId); }
 
         user.delete();
-        List<TopicSubscriber> subscriptions = 
topicSubscriberRepository.findBySubscriber(user);
-        for (TopicSubscriber subscription : subscriptions) {
-               topicSubscriberRepository.delete(subscription);
-        }
+        this.topicDomainService.unsubcribeUserFromTopic(user);
         this.appUserRepository.save(user);
 
         return new 
CommandProcessingResultBuilder().withEntityId(userId).withOfficeId(user.getOffice().getId()).build();

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java
index 83f30af..0ae012d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java
@@ -20,7 +20,6 @@ package org.apache.fineract.useradministration.service;
 
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.persistence.PersistenceException;
@@ -31,10 +30,7 @@ import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.notification.domain.Topic;
-import org.apache.fineract.notification.domain.TopicRepository;
-import org.apache.fineract.organisation.office.domain.Office;
-import org.apache.fineract.organisation.office.domain.OfficeRepository;
+import org.apache.fineract.notification.service.TopicDomainService;
 import org.apache.fineract.useradministration.command.PermissionsCommand;
 import org.apache.fineract.useradministration.domain.Permission;
 import org.apache.fineract.useradministration.domain.PermissionRepository;
@@ -60,23 +56,20 @@ public class RoleWritePlatformServiceJpaRepositoryImpl 
implements RoleWritePlatf
     private final PlatformSecurityContext context;
     private final RoleRepository roleRepository;
     private final PermissionRepository permissionRepository;
-    private final TopicRepository topicRepository;
-    private final OfficeRepository officeRepository;
     private final RoleDataValidator roleCommandFromApiJsonDeserializer;
     private final PermissionsCommandFromApiJsonDeserializer 
permissionsFromApiJsonDeserializer;
+    private final TopicDomainService topicDomainService;
 
     @Autowired
     public RoleWritePlatformServiceJpaRepositoryImpl(final 
PlatformSecurityContext context, final RoleRepository roleRepository,
             final PermissionRepository permissionRepository, final 
RoleDataValidator roleCommandFromApiJsonDeserializer,
-            final PermissionsCommandFromApiJsonDeserializer 
fromApiJsonDeserializer, TopicRepository topicRepository,
-            final OfficeRepository officeRepository) {
+            final PermissionsCommandFromApiJsonDeserializer 
fromApiJsonDeserializer, final TopicDomainService topicDomainService) {
         this.context = context;
         this.roleRepository = roleRepository;
         this.permissionRepository = permissionRepository;
         this.roleCommandFromApiJsonDeserializer = 
roleCommandFromApiJsonDeserializer;
         this.permissionsFromApiJsonDeserializer = fromApiJsonDeserializer;
-        this.topicRepository = topicRepository;
-        this.officeRepository = officeRepository;
+        this.topicDomainService = topicDomainService;
     }
 
     @Transactional
@@ -88,22 +81,12 @@ public class RoleWritePlatformServiceJpaRepositoryImpl 
implements RoleWritePlatf
 
             
this.roleCommandFromApiJsonDeserializer.validateForCreate(command.json());
 
-            final Role role = Role.fromJson(command);
-            List<Office> offices = officeRepository.findAll();
-            for (Office office : offices) {
-               String entityType = "";
-               if (office.getParent() == null) {
-                       entityType = "OFFICE";
-               } else {
-                       entityType = "BRANCH";
-               }
-               String title = role.getName() + " of " + office.getName();
-               Topic newTopic = new Topic(title, true, office.getId(), 
entityType, role.getName().toUpperCase());
-               topicRepository.save(newTopic);
-            }
-            this.roleRepository.save(role);
+            final Role entity = Role.fromJson(command);
+            this.roleRepository.save(entity);
+            
+            this.topicDomainService.createTopic(entity);
 
-            return new 
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(role.getId()).build();
+            return new 
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(entity.getId()).build();
         } catch (final DataIntegrityViolationException dve) {
             handleDataIntegrityIssues(command, dve.getMostSpecificCause(), 
dve);
             return new CommandProcessingResultBuilder() //
@@ -151,24 +134,14 @@ public class RoleWritePlatformServiceJpaRepositoryImpl 
implements RoleWritePlatf
 
             final Role role = this.roleRepository.findOne(roleId);
             if (role == null) { throw new RoleNotFoundException(roleId); }
-            
-            String oldMemberType = role.getName().toUpperCase();
+
+            String previousRoleName = role.getName();
             final Map<String, Object> changes = role.update(command);
-            
-            if (changes.containsKey("name")) {
-               String newMemberType = (String) changes.get("name");
-               List<Topic> entityTopics = 
topicRepository.findByMemberType(oldMemberType);
-               for (Topic topic : entityTopics) {
-                       Office office = 
officeRepository.findOne(topic.getEntityId());
-                       String title = role.getName() + " of " + 
office.getName();
-                       topic.setTitle(title);
-                       topic.setMemberType(newMemberType.toUpperCase());
-                       topicRepository.save(topic);
-               }
-            }
-            
             if (!changes.isEmpty()) {
                 this.roleRepository.saveAndFlush(role);
+                if (changes.containsKey("name")) {
+                       this.topicDomainService.updateTopic( previousRoleName, 
role, changes);
+                }
             }
 
             return new CommandProcessingResultBuilder() //
@@ -258,10 +231,8 @@ public class RoleWritePlatformServiceJpaRepositoryImpl 
implements RoleWritePlatf
             final Integer count = 
this.roleRepository.getCountOfRolesAssociatedWithUsers(roleId);
             if (count > 0) { throw new 
RoleAssociatedException("error.msg.role.associated.with.users.deleted", 
roleId); }
             
-            List<Topic> topics = 
topicRepository.findByMemberType(role.getName().toUpperCase());
-            for (Topic topic : topics) {
-               topicRepository.delete(topic);
-            }
+            this.topicDomainService.deleteTopic(role);
+            
             this.roleRepository.delete(role);
             return new 
CommandProcessingResultBuilder().withEntityId(roleId).build();
         } catch (final DataIntegrityViolationException e) {

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/resources/META-INF/spring/appContext.xml
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/resources/META-INF/spring/appContext.xml 
b/fineract-provider/src/main/resources/META-INF/spring/appContext.xml
index 3d84a07..586dcda 100644
--- a/fineract-provider/src/main/resources/META-INF/spring/appContext.xml
+++ b/fineract-provider/src/main/resources/META-INF/spring/appContext.xml
@@ -101,5 +101,4 @@
        </bean>
 
        <import resource="spmContext.xml"/>
-       <import resource="notificationContext.xml"/>
 </beans>

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml 
b/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml
deleted file mode 100644
index 2883481..0000000
--- 
a/fineract-provider/src/main/resources/META-INF/spring/notificationContext.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<beans xmlns="http://www.springframework.org/schema/beans";
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd";>
-
-    <bean id="amqConnectionFactory" 
class="org.apache.activemq.ActiveMQConnectionFactory">
-        <constructor-arg index="0" value="tcp://localhost:61616" />
-    </bean>
-
-    <bean id="connectionFactory" 
class="org.springframework.jms.connection.CachingConnectionFactory">
-        <constructor-arg ref="amqConnectionFactory"/>
-    </bean>
-
-    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
-        <property name="connectionFactory" ref="connectionFactory"/>
-    </bean>
-
-    <bean id="messageListenerContainer" 
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
-        <property name="connectionFactory" ref="connectionFactory" />
-        <property name="destinationName" value="NotificationQueue"/>
-        <property name="messageListener" ref="notificationEventListener" />
-    </bean>
-
-</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql
 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql
deleted file mode 100644
index 92562ef..0000000
--- 
a/fineract-provider/src/main/resources/sql/migrations/core_db/V336__topic_module_table.sql
+++ /dev/null
@@ -1,45 +0,0 @@
---
--- 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.
---
-
-CREATE TABLE IF NOT EXISTS `topic` (
-  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
-  `title` VARCHAR(100) NOT NULL,
-  `enabled` TINYINT(1) NULL,
-  `entity_id` BIGINT(20) NOT NULL,
-  `entity_type` TEXT NOT NULL,
-  `member_type` TEXT NOT NULL,
-  PRIMARY KEY (`id`),
-  UNIQUE INDEX `title_UNIQUE` (`title` ASC)
-)ENGINE = InnoDB;
-
-CREATE TABLE IF NOT EXISTS `topic_subscriber` (
-  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
-  `topic_id` BIGINT(20) NOT NULL,
-  `user_id` BIGINT(20) NOT NULL,
-  `subscription_date` DATE NOT NULL,
-  PRIMARY KEY (`id`),
-  CONSTRAINT `fk_topic_has_m_appuser_topic` FOREIGN KEY (`topic_id`) 
REFERENCES `topic` (`id`),
-  CONSTRAINT `fk_topic_has_m_appuser_m_appuser1` FOREIGN KEY (`user_id`) 
REFERENCES `m_appuser` (`id`)
-) ENGINE = InnoDB;
-
-INSERT INTO topic (enabled, entity_type, entity_id, member_type, title) SELECT 
true, 'OFFICE', o.id as entity_id, UPPER(r.name) as member_type, CONCAT(r.name, 
' of ', o.name) as title FROM m_office o, m_role r WHERE o.parent_id IS NULL 
AND CONCAT(r.name, ' of ', o.name) NOT IN (SELECT title FROM topic);
-
-INSERT INTO topic (enabled, entity_type, entity_id, member_type, title) SELECT 
true, 'BRANCH', o.id as entity_id, UPPER(r.name) as member_type, CONCAT(r.name, 
' of ', o.name) as title FROM m_office o, m_role r WHERE o.parent_id IS NOT 
NULL AND CONCAT(r.name, ' of ', o.name) NOT IN (SELECT title FROM topic);
-
-INSERT INTO topic_subscriber( user_id, topic_id, subscription_date ) SELECT 
u.id AS user_id, t.id AS topic_id, NOW() FROM topic t, m_appuser u, 
m_appuser_role ur, m_role r WHERE u.office_id = t.entity_id AND u.id = 
ur.appuser_id AND ur.role_id = r.id AND r.name = t.member_type AND NOT EXISTS 
(SELECT user_id, topic_id FROM topic_subscriber WHERE user_id = u.id AND 
topic_id = t.id);

http://git-wip-us.apache.org/repos/asf/fineract/blob/0b021296/fineract-provider/src/main/resources/sql/migrations/core_db/V342__topic_module_table.sql
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/resources/sql/migrations/core_db/V342__topic_module_table.sql
 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V342__topic_module_table.sql
new file mode 100644
index 0000000..92562ef
--- /dev/null
+++ 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V342__topic_module_table.sql
@@ -0,0 +1,45 @@
+--
+-- 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.
+--
+
+CREATE TABLE IF NOT EXISTS `topic` (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+  `title` VARCHAR(100) NOT NULL,
+  `enabled` TINYINT(1) NULL,
+  `entity_id` BIGINT(20) NOT NULL,
+  `entity_type` TEXT NOT NULL,
+  `member_type` TEXT NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE INDEX `title_UNIQUE` (`title` ASC)
+)ENGINE = InnoDB;
+
+CREATE TABLE IF NOT EXISTS `topic_subscriber` (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+  `topic_id` BIGINT(20) NOT NULL,
+  `user_id` BIGINT(20) NOT NULL,
+  `subscription_date` DATE NOT NULL,
+  PRIMARY KEY (`id`),
+  CONSTRAINT `fk_topic_has_m_appuser_topic` FOREIGN KEY (`topic_id`) 
REFERENCES `topic` (`id`),
+  CONSTRAINT `fk_topic_has_m_appuser_m_appuser1` FOREIGN KEY (`user_id`) 
REFERENCES `m_appuser` (`id`)
+) ENGINE = InnoDB;
+
+INSERT INTO topic (enabled, entity_type, entity_id, member_type, title) SELECT 
true, 'OFFICE', o.id as entity_id, UPPER(r.name) as member_type, CONCAT(r.name, 
' of ', o.name) as title FROM m_office o, m_role r WHERE o.parent_id IS NULL 
AND CONCAT(r.name, ' of ', o.name) NOT IN (SELECT title FROM topic);
+
+INSERT INTO topic (enabled, entity_type, entity_id, member_type, title) SELECT 
true, 'BRANCH', o.id as entity_id, UPPER(r.name) as member_type, CONCAT(r.name, 
' of ', o.name) as title FROM m_office o, m_role r WHERE o.parent_id IS NOT 
NULL AND CONCAT(r.name, ' of ', o.name) NOT IN (SELECT title FROM topic);
+
+INSERT INTO topic_subscriber( user_id, topic_id, subscription_date ) SELECT 
u.id AS user_id, t.id AS topic_id, NOW() FROM topic t, m_appuser u, 
m_appuser_role ur, m_role r WHERE u.office_id = t.entity_id AND u.id = 
ur.appuser_id AND ur.role_id = r.id AND r.name = t.member_type AND NOT EXISTS 
(SELECT user_id, topic_id FROM topic_subscriber WHERE user_id = u.id AND 
topic_id = t.id);

Reply via email to