001 /** 002 * Copyright 2005-2014 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.rice.ken.postprocessor.kew; 017 018 import org.apache.log4j.Logger; 019 import org.kuali.rice.ken.bo.NotificationMessageDelivery; 020 import org.kuali.rice.ken.core.GlobalNotificationServiceLocator; 021 import org.kuali.rice.ken.deliverer.impl.KEWActionListMessageDeliverer; 022 import org.kuali.rice.ken.service.NotificationMessageDeliveryService; 023 import org.kuali.rice.ken.service.NotificationService; 024 import org.kuali.rice.ken.util.NotificationConstants; 025 import org.kuali.rice.ken.util.Util; 026 import org.kuali.rice.kew.api.KewApiConstants; 027 import org.kuali.rice.kew.api.WorkflowDocument; 028 import org.kuali.rice.kew.api.WorkflowDocumentFactory; 029 import org.kuali.rice.kew.api.action.ActionType; 030 import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent; 031 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent; 032 import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent; 033 import org.kuali.rice.kew.framework.postprocessor.DeleteEvent; 034 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent; 035 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange; 036 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange; 037 import org.kuali.rice.kew.framework.postprocessor.PostProcessor; 038 import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport; 039 040 import java.io.ByteArrayInputStream; 041 import java.io.IOException; 042 import java.util.List; 043 import java.util.Properties; 044 045 046 /** 047 * This class is the post processor that gets run when workflow state changes occur for the 048 * underlying core NotificationDocumentType that all notifications go into KEW as. This class is responsible for changing 049 * the state of the associated notification message delivery record after someone FYIs or ACKs their notification 050 * in the KEW Action List. 051 * @author Kuali Rice Team (rice.collab@kuali.org) 052 */ 053 public class NotificationPostProcessor implements PostProcessor { 054 private static final Logger LOG = Logger.getLogger(NotificationPostProcessor.class); 055 056 NotificationService notificationService; 057 NotificationMessageDeliveryService msgDeliverySvc; 058 059 /** 060 * Constructs a NotificationPostProcessor instance. 061 */ 062 public NotificationPostProcessor() { 063 this.msgDeliverySvc = GlobalNotificationServiceLocator.getInstance().getNotificationMessageDeliveryService(); 064 this.notificationService = GlobalNotificationServiceLocator.getInstance().getNotificationService(); 065 } 066 067 /** 068 * Need to intercept ACKNOWLEDGE or FYI actions taken on notification workflow documents and set the local state of the 069 * Notification to REMOVED as well. 070 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doActionTaken(org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent) 071 */ 072 public ProcessDocReport doActionTaken(ActionTakenEvent event) throws Exception { 073 LOG.debug("ENTERING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId()); 074 075 // NOTE: this action could be happening because the user initiated it via KEW, OR because a dismiss or autoremove action 076 // has been invoked programmatically and the KEWActionListMessageDeliverer is taking an action...so there is a risk of being 077 // invoked recursively (which will lead to locking issues and other problems). We therefore mark the document in the KEWActionList 078 // MessageDeliverer before performing an action, so that we can detect this scenario here, and avoid invoking KEN again. 079 080 LOG.debug("ACTION TAKEN=" + event.getActionTaken().getActionTaken()); 081 082 String actionTakenCode = event.getActionTaken().getActionTaken().getCode(); 083 084 Properties p = new Properties(); 085 WorkflowDocument doc = WorkflowDocumentFactory.loadDocument(event.getActionTaken().getPrincipalId(), event.getDocumentId()); 086 try { 087 p.load(new ByteArrayInputStream(doc.getAttributeContent().getBytes())); 088 } catch (IOException ioe) { 089 throw new RuntimeException(ioe); 090 } 091 String internalCommand = p.getProperty(KEWActionListMessageDeliverer.INTERNAL_COMMAND_FLAG); 092 093 if (Boolean.valueOf(internalCommand).booleanValue()) { 094 LOG.info("Internal command detected by NotificationPostProcessor - will not invoke KEN"); 095 return new ProcessDocReport(true, ""); 096 } 097 098 LOG.info("NotificationPostProcessor detected end-user action " + event.getActionTaken().getActionTaken() + " on document " + event.getActionTaken().getDocumentId()); 099 100 if(actionTakenCode.equals(KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD) || actionTakenCode.equals(KewApiConstants.ACTION_TAKEN_FYI_CD)) { 101 LOG.debug("User has taken either acknowledge or fy action (action code=" + actionTakenCode + 102 ") for Notification action item with document ID: " + event.getDocumentId() + 103 ". We are now changing the status of the associated NotificationMessageDelivery to REMOVED."); 104 105 try { 106 NotificationMessageDelivery nmd = msgDeliverySvc.getNotificationMessageDeliveryByDelivererId(event.getDocumentId()); 107 108 if (nmd == null) { 109 throw new RuntimeException("Could not find message delivery from workflow document " + event.getDocumentId() + " to dismiss"); 110 } 111 112 //get the id of the associated notification message delivery record 113 String cause; 114 if (KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD.equals(actionTakenCode)) { 115 cause = NotificationConstants.ACK_CAUSE; 116 } else if (KewApiConstants.ACTION_TAKEN_FYI_CD.equals(actionTakenCode)) { 117 cause = NotificationConstants.FYI_CAUSE; 118 } else { 119 cause = "unknown"; 120 } 121 122 LOG.info("Dismissing message id " + nmd.getId() + " due to cause: " + cause); 123 notificationService.dismissNotificationMessageDelivery(nmd.getId(), 124 Util.getNotificationSystemUser(), 125 cause); 126 } catch(Exception e) { 127 throw new RuntimeException("Error dismissing message", e); 128 } 129 } 130 131 LOG.debug("LEAVING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId()); 132 return new ProcessDocReport(true); 133 } 134 135 /** 136 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#afterActionTaken(org.kuali.rice.kew.api.action.ActionType, org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent) 137 */ 138 @Override 139 public ProcessDocReport afterActionTaken(ActionType performed, ActionTakenEvent event) throws Exception { 140 return new ProcessDocReport(true, ""); 141 } 142 143 /** 144 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doDeleteRouteHeader(org.kuali.rice.kew.framework.postprocessor.DeleteEvent) 145 */ 146 public ProcessDocReport doDeleteRouteHeader(DeleteEvent arg0) throws Exception { 147 return new ProcessDocReport(true, ""); 148 } 149 150 /** 151 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doRouteLevelChange(org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange) 152 */ 153 public ProcessDocReport doRouteLevelChange(DocumentRouteLevelChange arg0) throws Exception { 154 return new ProcessDocReport(true, ""); 155 } 156 157 /** 158 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doRouteStatusChange(org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange) 159 */ 160 public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange arg0) throws Exception { 161 return new ProcessDocReport(true, ""); 162 } 163 164 /** 165 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#beforeProcess(org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent) 166 */ 167 public ProcessDocReport beforeProcess(BeforeProcessEvent beforeProcessEvent) throws Exception { 168 return new ProcessDocReport(true, ""); 169 } 170 171 /** 172 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#afterProcess(org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent) 173 */ 174 public ProcessDocReport afterProcess(AfterProcessEvent afterProcessEvent) throws Exception { 175 return new ProcessDocReport(true, ""); 176 } 177 178 /** 179 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#getDocumentIdsToLock(org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent) 180 */ 181 public List<String> getDocumentIdsToLock(DocumentLockingEvent documentLockingEvent) throws Exception { 182 return null; 183 } 184 185 186 187 188 }