001/**
002 * Copyright 2005-2015 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.service.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.ken.bo.NotificationMessageDelivery;
020import org.kuali.rice.ken.document.kew.NotificationWorkflowDocument;
021import org.kuali.rice.ken.service.NotificationMessageContentService;
022import org.kuali.rice.ken.service.NotificationWorkflowDocumentService;
023import org.kuali.rice.ken.util.NotificationConstants;
024import org.kuali.rice.kew.api.WorkflowDocument;
025import org.kuali.rice.kew.api.WorkflowRuntimeException;
026import org.kuali.rice.kew.api.action.ActionRequest;
027import org.kuali.rice.kew.api.action.ActionRequestType;
028import org.kuali.rice.kim.api.identity.principal.Principal;
029import org.kuali.rice.kim.api.services.KimApiServiceLocator;
030
031import java.util.List;
032
033/**
034 * This class is responsible for interacting with KEW - this is the default implementation that
035 * leverages the KEW client API.
036 * @author Kuali Rice Team (rice.collab@kuali.org)
037 */
038public class NotificationWorkflowDocumentServiceImpl implements NotificationWorkflowDocumentService {
039    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
040            .getLogger(NotificationWorkflowDocumentServiceImpl.class);
041
042    private NotificationMessageContentService messageContentService;
043
044    /**
045     * Constructs a NotificationWorkflowDocumentServiceImpl instance.
046     * @param messageContentService
047     */
048    public NotificationWorkflowDocumentServiceImpl(NotificationMessageContentService messageContentService) {
049        this.messageContentService = messageContentService;
050    }
051
052    /**
053     * Implements by instantiating a NotificationWorkflowDocument, which in turn interacts with
054     * Workflow to set it up with an initiator of the passed in user id.
055     * @see org.kuali.rice.ken.service.NotificationWorkflowDocumentService#createAndAdHocRouteNotificationWorkflowDocument(org.kuali.rice.ken.bo.NotificationMessageDelivery,
056     *      java.lang.String, java.lang.String, java.lang.String)
057     */
058    public String createAndAdHocRouteNotificationWorkflowDocument(NotificationMessageDelivery messageDelivery,
059            String initiatorUserId,
060            String recipientUserId, String annotation) {
061        // obtain a workflow user object first
062        //WorkflowIdDTO initiator = new WorkflowIdDTO(initiatorUserId);
063
064        // now construct the workflow document, which will interact with workflow
065        WorkflowDocument document;
066        if (StringUtils.isNotBlank(messageDelivery.getNotification().getDocTypeName())) {
067            document = NotificationWorkflowDocument.createNotificationDocument(initiatorUserId,
068                    messageDelivery.getNotification().getDocTypeName());
069        } else {
070            document = NotificationWorkflowDocument.createNotificationDocument(initiatorUserId);
071        }
072
073        // this is our loose foreign key to our message delivery record in notification
074        document.setApplicationDocumentId(messageDelivery.getId().toString());
075        //document.setAppDocId(messageDelivery.getId().toString());
076
077        // now add the content of the notification as XML to the document
078        document.setApplicationContent(messageContentService.generateNotificationMessage(
079                messageDelivery.getNotification(), messageDelivery.getUserRecipientId()));
080
081        if (!StringUtils.isBlank(messageDelivery.getNotification().getTitle())) {
082            document.setTitle(messageDelivery.getNotification().getTitle());
083        } else {
084            LOG.error("Encountered notification with no title set: Message Delivery #" + messageDelivery.getId()
085                    + ", Notification #" + messageDelivery.getNotification().getId());
086        }
087
088        // now set up the ad hoc route
089        String actionRequested;
090        if (NotificationConstants.DELIVERY_TYPES.ACK.equals(messageDelivery.getNotification().getDeliveryType())) {
091            actionRequested = NotificationConstants.KEW_CONSTANTS.ACK_AD_HOC_ROUTE;
092        } else {
093            actionRequested = NotificationConstants.KEW_CONSTANTS.FYI_AD_HOC_ROUTE;
094        }
095
096        // Clarification of ad hoc route call
097        // param 1 - actionRequested will be either ACK or FYI
098        // param 2 - annotation is whatever text we pass in to describe the transaction - this will be system generated
099        // param 3 - recipient is the person who will receive this request
100        // param 4 - this is the responsibilityParty (a.k.a the system that produced this request), so we'll put the producer name in there
101        // param 5 - this is the "force action" requests - if set to true, this will be delivered to the recipients list regardless of
102        //           whether the recipient has already taken action on this request; in our case, this doesn't really apply at this point in time,
103        //           so we'll set to true just to be safe
104        
105        // recipientUserId will always be a principal ID due to code changes in NotificationMessageDeliveryResolverServiceImpl.buildCompleteRecipientList()
106        Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(recipientUserId);
107        
108        document.adHocToPrincipal(ActionRequestType.fromCode(actionRequested), annotation, principal.getPrincipalId(),
109                messageDelivery.getNotification().getProducer().getName(), true);
110
111        // now actually route it along its way
112        document.route(annotation);
113
114        return document.getDocumentId();
115    }
116
117    /**
118     * This service method is implemented by constructing a NotificationWorkflowDocument using the
119     * pre-existing document Id that is passed in.
120     * @see org.kuali.rice.ken.service.NotificationWorkflowDocumentService#findNotificationWorkflowDocumentByDocumentId(java.lang.String,
121     *      java.lang.String)
122     */
123    public WorkflowDocument getNotificationWorkflowDocumentByDocumentId(String initiatorUserId,
124            String workflowDocumentId) {
125        // construct the workflow id value object
126        //WorkflowIdDTO initiator = new WorkflowIdDTO(initiatorUserId);
127
128        // now return the actual document instance
129        // this handles going out and getting the workflow document
130        return NotificationWorkflowDocument.loadNotificationDocument(initiatorUserId, workflowDocumentId);
131    }
132
133    /**
134     * @see org.kuali.rice.ken.service.NotificationWorkflowDocumentService#clearAllFyisAndAcknowledgeNotificationWorkflowDocument(java.lang.String,
135     *      org.kuali.rice.ken.document.kew.NotificationWorkflowDocument, java.lang.String)
136     */
137    public void clearAllFyisAndAcknowledgeNotificationWorkflowDocument(String initiatorUserId,
138            WorkflowDocument workflowDocument, String annotation) {
139        List<ActionRequest> reqs = workflowDocument.getRootActionRequests();
140        for (int i = 0; i < reqs.size(); i++) {
141            LOG.info("Action Request[" + i + "] = " + reqs.get(i).getActionRequested());
142            if (reqs.get(i).getActionRequested().equals(ActionRequestType.ACKNOWLEDGE)) {
143                workflowDocument.acknowledge(annotation);
144            } else if (reqs.get(i).getActionRequested().equals(ActionRequestType.FYI)) {
145                workflowDocument.logAnnotation(annotation);
146                workflowDocument.fyi();
147            } else {
148                throw new WorkflowRuntimeException("Invalid notification action request in workflow document ("
149                        + workflowDocument.getDocumentId()
150                        + ") was encountered.  Should be either an acknowledge or fyi and was not.");
151            }
152        }
153    }
154
155    /** 
156     * @see org.kuali.rice.ken.service.NotificationWorkflowDocumentService#terminateWorkflowDocument(org.kuali.rice.kew.api.WorkflowDocument)
157     */
158    public void terminateWorkflowDocument(WorkflowDocument document) {
159        document.superUserCancel("terminating document: documentId=" + document.getDocumentId() + ", appDocId="
160                + document.getApplicationDocumentId());
161    }
162}