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