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