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 }