001 /* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.kfs.module.endow.batch.service.impl; 017 018 import java.sql.Date; 019 import java.util.ArrayList; 020 import java.util.Collection; 021 import java.util.HashMap; 022 import java.util.List; 023 import java.util.Map; 024 025 import org.kuali.kfs.module.endow.EndowPropertyConstants; 026 import org.kuali.kfs.module.endow.batch.service.TicklerDeliveryService; 027 import org.kuali.kfs.module.endow.businessobject.GLInterfaceBatchStatisticsReportDetailTableRow; 028 import org.kuali.kfs.module.endow.businessobject.Tickler; 029 import org.kuali.kfs.module.endow.businessobject.TicklerDeliveryStatisticsReportDetailTableRow; 030 import org.kuali.kfs.module.endow.businessobject.TicklerRecipientGroup; 031 import org.kuali.kfs.module.endow.businessobject.TicklerRecipientPrincipal; 032 import org.kuali.kfs.module.endow.document.service.KEMService; 033 import org.kuali.kfs.sys.KFSConstants; 034 import org.kuali.kfs.sys.context.SpringContext; 035 import org.kuali.kfs.sys.service.ReportWriterService; 036 import org.kuali.kfs.sys.service.UniversityDateService; 037 import org.kuali.rice.kew.exception.WorkflowException; 038 import org.kuali.rice.kew.util.KEWConstants; 039 import org.kuali.rice.kns.bo.AdHocRoutePerson; 040 import org.kuali.rice.kns.bo.AdHocRouteRecipient; 041 import org.kuali.rice.kns.bo.AdHocRouteWorkgroup; 042 import org.kuali.rice.kns.document.MaintenanceDocument; 043 import org.kuali.rice.kns.maintenance.KualiMaintainableImpl; 044 import org.kuali.rice.kns.rule.event.SendAdHocRequestsEvent; 045 import org.kuali.rice.kns.service.BusinessObjectService; 046 import org.kuali.rice.kns.service.DocumentService; 047 import org.kuali.rice.kns.service.KualiRuleService; 048 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 049 import org.kuali.rice.kns.util.KNSConstants; 050 import org.kuali.rice.kns.util.ObjectUtils; 051 import org.springframework.transaction.annotation.Transactional; 052 053 @Transactional 054 public class TicklerDeliveryServiceImpl implements TicklerDeliveryService { 055 056 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(TicklerDeliveryServiceImpl.class); 057 058 private BusinessObjectService businessObjectService; 059 private KEMService kemService; 060 private UniversityDateService universityDateService; 061 private KualiRuleService kualiRuleService; 062 private DocumentService documentService; 063 private Date currentDate; 064 private ReportWriterService ticklerDeliveryStatisticsReportsWriterService; 065 066 private TicklerDeliveryStatisticsReportDetailTableRow ticklerDeliveryStatisticsReportDetailTableRow; 067 068 public TicklerDeliveryServiceImpl(){ 069 //statistics report... 070 ticklerDeliveryStatisticsReportDetailTableRow = new TicklerDeliveryStatisticsReportDetailTableRow(); 071 } 072 073 public boolean generateTicklerNotices() { 074 075 //set current date 076 currentDate = kemService.getCurrentDate(); 077 078 LOG.info("Begin generateTicklerNotices() with notification date of " + currentDate); 079 080 //get tickler documents 081 ArrayList<Tickler>ticklerBOs = new ArrayList<Tickler>(getTicklerBusinessObjects()); 082 083 //route tickler delivery notice 084 routeTicklerDeliveryNotice(ticklerBOs); 085 086 writeStatisticsReport(); 087 088 LOG.info("End generateTicklerNotices() with notification date of " + currentDate); 089 090 return false; 091 } 092 093 /** 094 * Retrieves a list of tickler BOs where the next review date is 095 * equal to today, the term date is null or greater than today, and the record is active. 096 * 097 * @param currentDate 098 * @return 099 */ 100 protected List<Tickler> getTicklerBusinessObjects(){ 101 Map<String, Object> queryCriteria = new HashMap<String, Object>(); 102 queryCriteria.put(EndowPropertyConstants.TICKLER_NEXT_DUE_DATE, currentDate); 103 queryCriteria.put(EndowPropertyConstants.TICKLER_ACTIVE_INDICATOR, KFSConstants.ParameterValues.YES); 104 105 ArrayList<Tickler> ticklerBOs = null; 106 ticklerBOs = new ArrayList<Tickler>(businessObjectService.findMatching(Tickler.class, queryCriteria)); 107 108 //Go through and remove tickler docs where the term date has expired 109 if(ObjectUtils.isNotNull(ticklerBOs)){ 110 111 for(int i = ticklerBOs.size()-1; i > -1; i--){ 112 113 if(ObjectUtils.isNotNull(ticklerBOs.get(i).getTerminationDate()) && ticklerBOs.get(i).getTerminationDate().before(currentDate)){ 114 ticklerBOs.remove(i); 115 } 116 } 117 } 118 119 return ticklerBOs; 120 } 121 122 /** 123 * Routes FYI tickler documents to Tickler persons and groups 124 * 125 * @param ticklerDocs 126 * @return 127 */ 128 protected boolean routeTicklerDeliveryNotice(List<Tickler> ticklerBOs){ 129 boolean success = false; 130 boolean rulePassed = false; 131 MaintenanceDocument ticklerDocument = null; 132 133 if(ObjectUtils.isNotNull(ticklerBOs)){ 134 135 for(Tickler ticklerBO : ticklerBOs){ 136 137 //create a maintenance document from the 138 ticklerDocument = createTicklerDocument(ticklerBO); 139 140 //add principals and groups 141 ticklerDocument.setAdHocRoutePersons(convertTicklerPrincipalToAdhocRoutePerson(ticklerBO.getRecipientPrincipals())); 142 ticklerDocument.setAdHocRouteWorkgroups(convertTicklerGroupsToAdhocRouteGroup(ticklerBO.getRecipientGroups())); 143 144 //check rules to ensure valid recipients 145 rulePassed = kualiRuleService.applyRules(new SendAdHocRequestsEvent(ticklerDocument)); 146 147 if (rulePassed) { 148 try{ 149 //rule passed to send adhoc requests 150 documentService.routeDocument(ticklerDocument, "Tickler Notification - " + currentDate, combineAdHocRecipients(ticklerDocument)); 151 ticklerDeliveryStatisticsReportDetailTableRow.increaseTicklerDeliveryNotificationsCount(); 152 success = true; 153 }catch(WorkflowException wfe){ 154 ticklerDeliveryStatisticsReportDetailTableRow.increaseNumberOfExceptionsCount(); 155 //just warn, but continue routing with other tickler BOs 156 LOG.warn("Failed to route Tickler Delivery notices for Tickler Number " + ticklerBO.getNumber() + " with notification date of " + currentDate); 157 } 158 }else{ 159 ticklerDeliveryStatisticsReportDetailTableRow.increaseNumberOfExceptionsCount(); 160 LOG.warn("Invalid recipients for Tickler Delivery notices for Tickler Number " + ticklerBO.getNumber() + " with notification date of " + currentDate); 161 } 162 163 164 } 165 }else{ 166 //nothing to process 167 success = true; 168 } 169 170 return success; 171 } 172 173 /** 174 * Creates a Tickler Maintenance Document based on a Tickler BO 175 * 176 * @param ticklerBo 177 * @return 178 */ 179 protected MaintenanceDocument createTicklerDocument(Tickler ticklerBo){ 180 181 MaintenanceDocument document = null; 182 183 try{ 184 document = (MaintenanceDocument) documentService.getNewDocument(SpringContext.getBean(MaintenanceDocumentDictionaryService.class).getDocumentTypeName(ticklerBo.getClass())); 185 } 186 catch (WorkflowException e) { 187 throw new RuntimeException(e); 188 } 189 190 // add all the pieces 191 document.getDocumentHeader().setDocumentDescription("Tickler Notification - " + currentDate); 192 document.setOldMaintainableObject(new KualiMaintainableImpl(ticklerBo)); 193 document.getOldMaintainableObject().setBoClass(ticklerBo.getClass()); 194 document.setNewMaintainableObject(new KualiMaintainableImpl(ticklerBo)); 195 document.getNewMaintainableObject().setBoClass(ticklerBo.getClass()); 196 document.getNewMaintainableObject().setMaintenanceAction(KNSConstants.MAINTENANCE_EDIT_ACTION); 197 document.getNewMaintainableObject().setDocumentNumber(document.getDocumentNumber()); 198 199 return document; 200 } 201 202 /** 203 * Converts tickler principals into normal AdHocRoutePerson list 204 * 205 * @param principals 206 * @return 207 */ 208 protected List<AdHocRoutePerson> convertTicklerPrincipalToAdhocRoutePerson(List<TicklerRecipientPrincipal> principals){ 209 List<AdHocRoutePerson> personList = new ArrayList<AdHocRoutePerson>(); 210 AdHocRoutePerson person = null; 211 212 if(ObjectUtils.isNotNull(principals)){ 213 //for each principal, make an AdHocRoutePerson 214 for(TicklerRecipientPrincipal principal : principals){ 215 if(principal.isActive()){ 216 person = new AdHocRoutePerson(); 217 person.setId(principal.getContact().getPrincipalName()); 218 person.setActionRequested(KEWConstants.ACTION_REQUEST_FYI_REQ); 219 personList.add(person); 220 } 221 } 222 } 223 224 return personList; 225 } 226 227 /** 228 * Converts tickler groups into normal AdHocRouteWorkgroup list 229 * 230 * @param groups 231 * @return 232 */ 233 protected List<AdHocRouteWorkgroup> convertTicklerGroupsToAdhocRouteGroup(List<TicklerRecipientGroup> groups){ 234 List<AdHocRouteWorkgroup> groupList = new ArrayList<AdHocRouteWorkgroup>(); 235 AdHocRouteWorkgroup workgroup = null; 236 237 if(ObjectUtils.isNotNull(groups)){ 238 //for each group, make an AdHocWorkgroup 239 for(TicklerRecipientGroup group : groups){ 240 if(group.isActive()){ 241 workgroup = new AdHocRouteWorkgroup(); 242 workgroup.setId(group.getGroupId()); 243 workgroup.setRecipientName(group.getAssignedToGroup().getGroupName()); 244 workgroup.setRecipientNamespaceCode(group.getAssignedToGroup().getNamespaceCode()); 245 workgroup.setActionRequested(KEWConstants.ACTION_REQUEST_FYI_REQ); 246 247 groupList.add(workgroup); 248 } 249 } 250 } 251 252 return groupList; 253 } 254 255 /** 256 * Combines persons and workgroups from document into one list. 257 * 258 * @param ticklerDocument 259 * @return 260 */ 261 protected List<AdHocRouteRecipient> combineAdHocRecipients(MaintenanceDocument ticklerDocument) { 262 List<AdHocRouteRecipient> adHocRecipients = new ArrayList<AdHocRouteRecipient>(); 263 adHocRecipients.addAll(ticklerDocument.getAdHocRoutePersons()); 264 adHocRecipients.addAll(ticklerDocument.getAdHocRouteWorkgroups()); 265 return adHocRecipients; 266 } 267 268 protected void writeStatisticsReport() { 269 //now print the statistics report..... 270 long totalTicklerDeliveryNotifications = 0; 271 long totalNumberOfExceptions = 0; 272 273 //write the header line.... 274 ticklerDeliveryStatisticsReportsWriterService.writeStatisticLine("Number of Tickler Notifications\t\tNumber of Exceptions"); 275 ticklerDeliveryStatisticsReportsWriterService.writeStatisticLine("-------------------------------\t\t--------------------"); 276 277 ticklerDeliveryStatisticsReportsWriterService.writeStatisticLine("%31d\t\t%20d", ticklerDeliveryStatisticsReportDetailTableRow.getTicklerDeliveryNotifications(), ticklerDeliveryStatisticsReportDetailTableRow.getNumberOfExceptions()); 278 } 279 280 protected TicklerDeliveryStatisticsReportDetailTableRow getTicklerDeliveryStatisticsReportDetailTableRow() { 281 return ticklerDeliveryStatisticsReportDetailTableRow; 282 } 283 284 public void setTicklerDeliveryStatisticsReportDetailTableRow(TicklerDeliveryStatisticsReportDetailTableRow ticklerDeliveryStatisticsReportDetailTableRow) { 285 this.ticklerDeliveryStatisticsReportDetailTableRow = ticklerDeliveryStatisticsReportDetailTableRow; 286 } 287 288 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 289 this.businessObjectService = businessObjectService; 290 } 291 292 public void setKemService(KEMService kemService) { 293 this.kemService = kemService; 294 } 295 296 public void setUniversityDateService(UniversityDateService universityDateService) { 297 this.universityDateService = universityDateService; 298 } 299 300 public void setKualiRuleService(KualiRuleService kualiRuleService) { 301 this.kualiRuleService = kualiRuleService; 302 } 303 304 public void setDocumentService(DocumentService documentService) { 305 this.documentService = documentService; 306 } 307 308 public void setTicklerDeliveryStatisticsReportsWriterService(ReportWriterService ticklerDeliveryStatisticsReportsWriterService) { 309 this.ticklerDeliveryStatisticsReportsWriterService = ticklerDeliveryStatisticsReportsWriterService; 310 } 311 312 }