Coverage Report - org.kuali.rice.ken.service.impl.NotificationMessageDeliveryResolverServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
NotificationMessageDeliveryResolverServiceImpl
0%
0/64
0%
0/18
2.833
 
 1  
 /*
 2  
  * Copyright 2006-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.kuali.rice.ken.service.impl;
 18  
 
 19  
 import org.kuali.rice.core.framework.persistence.dao.GenericDao;
 20  
 import org.kuali.rice.ken.bo.Notification;
 21  
 import org.kuali.rice.ken.bo.NotificationMessageDelivery;
 22  
 import org.kuali.rice.ken.bo.NotificationRecipient;
 23  
 import org.kuali.rice.ken.bo.NotificationRecipientList;
 24  
 import org.kuali.rice.ken.bo.UserChannelSubscription;
 25  
 import org.kuali.rice.ken.deliverer.impl.KEWActionListMessageDeliverer;
 26  
 import org.kuali.rice.ken.exception.NotificationMessageDeliveryException;
 27  
 import org.kuali.rice.ken.service.NotificationMessageDeliveryResolverService;
 28  
 import org.kuali.rice.ken.service.NotificationRecipientService;
 29  
 import org.kuali.rice.ken.service.NotificationService;
 30  
 import org.kuali.rice.ken.service.ProcessingResult;
 31  
 import org.kuali.rice.ken.service.UserPreferenceService;
 32  
 import org.kuali.rice.ken.util.NotificationConstants;
 33  
 import org.kuali.rice.kim.util.KimConstants.KimGroupMemberTypes;
 34  
 import org.springframework.transaction.PlatformTransactionManager;
 35  
 
 36  
 import java.sql.Timestamp;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Collection;
 39  
 import java.util.HashSet;
 40  
 import java.util.Iterator;
 41  
 import java.util.List;
 42  
 import java.util.concurrent.ExecutorService;
 43  
 
 44  
 /**
 45  
  * This is the default out-of-the-box implementation that leverages the status flag on a notification (RESOLVED versus UNRESOLVED) to determine whether
 46  
  * the notification's message deliveries need to be resolved or not.  This also looks at the start and auto remove
 47  
  * dates and times.
 48  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 49  
  */
 50  0
 public class NotificationMessageDeliveryResolverServiceImpl extends ConcurrentJob<Notification> implements NotificationMessageDeliveryResolverService {
 51  0
     private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
 52  
         .getLogger(NotificationMessageDeliveryResolverServiceImpl.class);
 53  
 
 54  
     private NotificationRecipientService notificationRecipientService;
 55  
     private GenericDao businessObjectDao;
 56  
     private UserPreferenceService userPreferenceService;
 57  
     private NotificationService notificationService;
 58  
 
 59  
     /**
 60  
      * Constructs a NotificationMessageDeliveryDispatchServiceImpl instance.
 61  
      * @param notificationRecipientService
 62  
      * @param businessObjectDao
 63  
      * @param txManager
 64  
      * @param executor
 65  
      * @param userPreferenceService
 66  
      */
 67  
     public NotificationMessageDeliveryResolverServiceImpl(NotificationService notificationService, NotificationRecipientService notificationRecipientService,
 68  
             GenericDao businessObjectDao, PlatformTransactionManager txManager, ExecutorService executor,
 69  
             UserPreferenceService userPreferenceService) {
 70  0
         super(txManager, executor);
 71  0
         this.notificationService = notificationService;
 72  0
         this.notificationRecipientService = notificationRecipientService;
 73  0
         this.businessObjectDao = businessObjectDao;
 74  0
         this.userPreferenceService = userPreferenceService;
 75  0
     }
 76  
 
 77  
     /**
 78  
      * Obtains and marks as taken all unresolved (and untaken) notifications
 79  
      * @return a collection of available Notifications to process
 80  
      */
 81  
     @Override
 82  
     protected Collection<Notification> takeAvailableWorkItems() {
 83  0
         Collection<Notification> nots = notificationService.takeNotificationsForResolution();
 84  
         //LOG.debug("Took " + nots.size() + " notifications");
 85  
         
 86  
         //for (Notification not: nots) {
 87  
         //   LOG.debug("Took notification: " + not.getId() + " " + not.getTitle());
 88  
         //}
 89  0
         return nots;
 90  
     }
 91  
 
 92  
 
 93  
     /**
 94  
      * This method is responsible for building out the complete recipient list, which will resolve all members for groups, and add
 95  
      * them to the official list only if they are not already in the list.
 96  
      * @param notification
 97  
      * @return HashSet<String>
 98  
      */
 99  
     private HashSet<String> buildCompleteRecipientList(Notification notification) {
 100  0
         HashSet<String> completeRecipientList = new HashSet<String>(notification.getRecipients().size());
 101  
 
 102  
         // process the list that came in with the notification request
 103  0
            for (int i = 0; i < notification.getRecipients().size(); i++) {
 104  0
                NotificationRecipient recipient = notification.getRecipient(i);
 105  0
                if (KimGroupMemberTypes.GROUP_MEMBER_TYPE.equals(recipient.getRecipientType())) {
 106  
                    // resolve group's users
 107  0
                    String[] groupMembers = notificationRecipientService.getGroupMembers(recipient.getRecipientId());
 108  0
                    for(int j = 0; j < groupMembers.length; j++) {
 109  0
                        completeRecipientList.add(groupMembers[j]);
 110  
                    }
 111  0
                } else {  // just a user, so add to the list
 112  0
                    completeRecipientList.add(recipient.getRecipientId());
 113  
                }
 114  
            }
 115  
 
 116  
            // now process the default recipient lists that are associated with the channel
 117  0
            Iterator<NotificationRecipientList> i = notification.getChannel().getRecipientLists().iterator();
 118  0
            while (i.hasNext()) {
 119  0
                NotificationRecipientList listRecipient  = i.next();
 120  0
                if (KimGroupMemberTypes.GROUP_MEMBER_TYPE.equals(listRecipient.getRecipientType())) {
 121  
                    // resolve group's users
 122  0
                    String[] groupMembers = notificationRecipientService.getGroupMembers(listRecipient.getRecipientId());
 123  0
                    for (int j = 0; j < groupMembers.length; j++) {
 124  0
                        completeRecipientList.add(groupMembers[j]);
 125  
                    }
 126  0
                } else {  // just a user, so add to the list
 127  0
                    completeRecipientList.add(listRecipient.getRecipientId());
 128  
                }
 129  0
            }
 130  
 
 131  
            // now process the subscribers that are associated with the channel
 132  0
            List<UserChannelSubscription> subscriptions = notification.getChannel().getSubscriptions();
 133  0
            for (UserChannelSubscription subscription: subscriptions) {
 134  
                // NOTE: at this time channel subscriptions are USER-only - GROUP is not supported
 135  
                // this could be implemented by adding a recipientType/userType column as we do in
 136  
                // other recipient/user-related tables/BOs
 137  0
                completeRecipientList.add(subscription.getUserId());
 138  
            }
 139  
 
 140  0
            return completeRecipientList;
 141  
     }
 142  
 
 143  
     /**
 144  
      * Generates all message deliveries for a given notification and save thems to the database.
 145  
      * Updates each Notification record to indicate it has been resolved.
 146  
      * Should be performed within a separate transaction
 147  
      * @param notification the Notification for which to generate message deliveries
 148  
      * @return a count of the number of message deliveries generated
 149  
      */
 150  
     /* Perform within transaction */
 151  
     @Override
 152  
     protected Collection<Object> processWorkItems(Collection<Notification> notifications) {
 153  0
         List<Object> successes = new ArrayList<Object>();
 154  
 
 155  
         // because this concurrent job does not performed grouping of work items, there should only
 156  
         // ever be one notification object per work unit anyway...
 157  0
         for (Notification notification: notifications) {
 158  
             // now figure out each unique recipient for this notification
 159  0
             HashSet<String> uniqueRecipients = buildCompleteRecipientList(notification);
 160  
 
 161  
             // now for each unique recipient, figure out each delivery end point and create a NotificationMessageDelivery record
 162  0
             Iterator<String> j = uniqueRecipients.iterator();
 163  0
             while(j.hasNext()) {
 164  0
                 String userRecipientId = j.next();
 165  
 
 166  0
                 NotificationMessageDelivery defaultMessageDelivery = new NotificationMessageDelivery();
 167  0
                 defaultMessageDelivery.setMessageDeliveryStatus(NotificationConstants.MESSAGE_DELIVERY_STATUS.UNDELIVERED);
 168  0
                 defaultMessageDelivery.setNotification(notification);
 169  0
                 defaultMessageDelivery.setUserRecipientId(userRecipientId);
 170  
 
 171  
                 //now save that delivery end point; this record will be later processed by the dispatch service which will actually deliver it
 172  0
                 businessObjectDao.save(defaultMessageDelivery);
 173  
 
 174  
                 try {
 175  0
                     new KEWActionListMessageDeliverer().deliverMessage(defaultMessageDelivery);
 176  0
                 } catch (NotificationMessageDeliveryException e) {
 177  0
                     throw new RuntimeException(e);
 178  0
                 }
 179  
 
 180  
                 // we have no delivery stage any more, anything we send to KCB needs to be considered "delivered" from
 181  
                 // the perspective of KEN
 182  0
                 defaultMessageDelivery.setMessageDeliveryStatus(NotificationConstants.MESSAGE_DELIVERY_STATUS.DELIVERED);
 183  0
                 businessObjectDao.save(defaultMessageDelivery);
 184  
 
 185  0
                 successes.add(defaultMessageDelivery);
 186  
 
 187  
                 // also, update the status of the notification so that it's message deliveries are not resolved again
 188  0
                 notification.setProcessingFlag(NotificationConstants.PROCESSING_FLAGS.RESOLVED);
 189  
                 // unlock the record now
 190  0
                 notification.setLockedDate(null);
 191  0
                 businessObjectDao.save(notification);
 192  0
             }
 193  
 
 194  0
         }
 195  
 
 196  0
         return successes;
 197  
     }
 198  
 
 199  
     /**
 200  
      * @see org.kuali.rice.ken.service.impl.ConcurrentJob#unlockWorkItem(java.lang.Object)
 201  
      */
 202  
     @Override
 203  
     protected void unlockWorkItem(Notification notification) {
 204  0
         LOG.debug("Unlocking notification: " + notification.getId() + " " + notification.getTitle());
 205  0
         notificationService.unlockNotification(notification);
 206  0
     }
 207  
 
 208  
     /**
 209  
      * This method is responsible for resolving the list of NotificationMessageDelivery records for a given notification.  This service will look
 210  
      * at all notifications that are ready to be delivered and will "explode" out specific message delivery records for given delivery end points.
 211  
      * @see org.kuali.rice.ken.service.NotificationMessageDeliveryResolverService#resolveNotificationMessageDeliveries()
 212  
      */
 213  
     public ProcessingResult resolveNotificationMessageDeliveries() {
 214  0
         LOG.debug("[" + new Timestamp(System.currentTimeMillis()).toString() + "] STARTING RESOLUTION OF NOTIFICATION MESSAGE DELIVERIES");
 215  
 
 216  0
         ProcessingResult result = run();
 217  
 
 218  0
         LOG.debug("[" + new Timestamp(System.currentTimeMillis()).toString() + "] FINISHED RESOLUTION OF NOTIFICATION MESSAGE DELIVERIES - " +
 219  
                   "Message Delivery End Points Resolved = " + result.getSuccesses().size());
 220  
 
 221  0
         return result;
 222  
     }
 223  
 }