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    }