001/**
002 * Copyright 2005-2017 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 */
016package org.kuali.rice.ken.deliverer.impl;
017
018import java.io.ByteArrayOutputStream;
019import java.io.IOException;
020import java.util.Properties;
021
022import org.kuali.rice.ken.bo.NotificationMessageDelivery;
023import org.kuali.rice.ken.core.GlobalNotificationServiceLocator;
024import org.kuali.rice.ken.deliverer.NotificationMessageDeliverer;
025import org.kuali.rice.ken.exception.NotificationAutoRemoveException;
026import org.kuali.rice.ken.exception.NotificationMessageDeliveryException;
027import org.kuali.rice.ken.service.NotificationWorkflowDocumentService;
028import org.kuali.rice.ken.util.NotificationConstants;
029import org.kuali.rice.ken.util.Util;
030import org.kuali.rice.kew.api.WorkflowDocument;
031
032/**
033 * This class is responsible for describing the default delivery mechanism for the system - the KEW
034 * Action List.
035 * @author Kuali Rice Team (rice.collab@kuali.org)
036 */
037public class KEWActionListMessageDeliverer implements NotificationMessageDeliverer {
038    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KEWActionListMessageDeliverer.class);
039
040    /**
041     * Property set in the attribute content that indicates the action received by workflow was
042     * initiated by the Notification System itself (and not an end user)
043     */
044    public static final String INTERNAL_COMMAND_FLAG = "internal_command";
045
046    private NotificationWorkflowDocumentService notificationWorkflowDocumentService;
047
048    /**
049     * Constructs a KEWActionListMessageDeliverer.java.
050     */
051    public KEWActionListMessageDeliverer() {
052        this.notificationWorkflowDocumentService = GlobalNotificationServiceLocator.getInstance()
053                .getNotificationWorkflowDocumentService();
054    }
055
056    /**
057     * This implementation leverages the workflow integration services to push this notification
058     * into the KEW action list.
059     * @see org.kuali.rice.ken.deliverer.NotificationMessageDeliverer#deliverMessage(org.kuali.rice.ken.bo.NotificationMessageDelivery)
060     */
061    public void deliverMessage(NotificationMessageDelivery messageDelivery) throws NotificationMessageDeliveryException {
062        // make the call to actually generate and ad-hoc route a workflow document
063        String documentId = notificationWorkflowDocumentService.createAndAdHocRouteNotificationWorkflowDocument(
064                messageDelivery,
065                Util.getNotificationSystemUser(),
066                messageDelivery.getUserRecipientId(),
067                NotificationConstants.KEW_CONSTANTS.GENERIC_DELIVERY_ANNOTATION);
068
069        // now set the workflow doc id into the message delivery's delivery system id
070        messageDelivery.setDeliverySystemId(documentId);
071        LOG.debug("Message Delivery: " + messageDelivery.toString());
072    }
073
074    /**
075     * This implementation does an auto-remove by "canceling" the workflow document associated with
076     * the message delivery record. This prevents the user from seeing the item in their list
077     * anymore.
078     * @see org.kuali.rice.ken.deliverer.NotificationMessageDeliverer#autoRemoveMessageDelivery(org.kuali.rice.ken.bo.NotificationMessageDelivery)
079     */
080    public void autoRemoveMessageDelivery(NotificationMessageDelivery messageDelivery)
081            throws NotificationAutoRemoveException {
082        // first retrieve the appropriate notification workflow document to "auto-remove" and proxy as the recipient
083        WorkflowDocument workflowDoc = null;
084        String sysId = messageDelivery.getDeliverySystemId();
085        if (sysId == null) {
086            LOG.error("NotificationMessageDelivery " + messageDelivery.getId()
087                    + " is missing delivery system id (workflow document id");
088            // there is no possibility for recovery, so since there is no id, we'll just log an error and return successfully instead
089            // of throwing an exception
090            return;
091        }
092
093        workflowDoc = notificationWorkflowDocumentService.getNotificationWorkflowDocumentByDocumentId(
094                messageDelivery.getUserRecipientId(), sysId);
095
096        flagWorkflowDocument(workflowDoc);
097
098        notificationWorkflowDocumentService.clearAllFyisAndAcknowledgeNotificationWorkflowDocument(
099                messageDelivery.getUserRecipientId(), workflowDoc,
100                NotificationConstants.KEW_CONSTANTS.GENERIC_AUTO_REMOVE_ANNOTATION);
101    }
102
103    /**
104     * @see org.kuali.rice.ken.deliverer.NotificationMessageDeliverer#dismissMessageDelivery(org.kuali.rice.ken.bo.NotificationMessageDelivery,
105     *      java.lang.String, java.lang.String)
106     */
107    public void dismissMessageDelivery(NotificationMessageDelivery messageDelivery, String user, String cause) {
108        // TODO: move hardcoded web controller actions here...
109        LOG.info("Dismissing as user '" + user + "' workflow document '" + messageDelivery.getDeliverySystemId()
110                + "' corresponding to message delivery #" + messageDelivery.getId() + " due to cause: " + cause);
111        if (NotificationConstants.AUTO_REMOVE_CAUSE.equals(cause)) {
112            // perform an auto-remove
113            // XXX: currently auto-removes are going through autoremove method
114        } else {
115            WorkflowDocument nwd;
116            nwd = notificationWorkflowDocumentService.getNotificationWorkflowDocumentByDocumentId(user,
117                    messageDelivery.getDeliverySystemId());
118
119            flagWorkflowDocument(nwd);
120
121            if (NotificationConstants.ACK_CAUSE.equals(cause)) {
122                // moved from NotificationController, ack command
123                /*
124                 * acknowledge using workflow docId
125                 */
126                if (nwd.isAcknowledgeRequested()) {
127                    nwd.acknowledge("This notification has been acknowledged.");
128                    LOG.debug("acknowledged " + nwd.getTitle());
129                    LOG.debug("status display value: " + nwd.getStatus().getLabel());
130                } else {
131                    LOG.debug("Acknowledgement was not needed for document " + nwd.getDocumentId());
132                }
133            } else if (NotificationConstants.FYI_CAUSE.equals(cause)) {
134                // moved from NotificationController, fyi command
135                /*
136                 * FYI using workflow docId
137                 */
138                if (nwd.isFYIRequested()) {
139                    nwd.fyi();
140                    LOG.debug("fyi " + nwd.getTitle());
141                    LOG.debug("status display value: " + nwd.getStatus().getLabel());
142                } else {
143                    LOG.debug("FYI was not needed for document " + nwd.getDocumentId());
144                }
145            }
146        }
147    }
148
149    /**
150     * Marks the workflow document as originating from the Notification System, so that the
151     * Notification post-processor does not route the action back through the Notification System.
152     * @param doc the doc to monogram
153     */
154    protected void flagWorkflowDocument(WorkflowDocument doc) {
155        Properties p = new Properties();
156        p.setProperty(INTERNAL_COMMAND_FLAG, "true");
157        ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
158        try {
159            p.store(baos, null);
160        } catch (IOException ioe) {
161            throw new RuntimeException("Could not store properties", ioe);
162        }
163        doc.setAttributeContent("<whatever>" + new String(baos.toByteArray()) + "</whatever>");
164    }
165}