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.kew.role.service.impl;
017    
018    import org.apache.commons.collections.CollectionUtils;
019    import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
020    import org.kuali.rice.kew.actionrequest.ActionRequestValue;
021    import org.kuali.rice.kew.api.KewApiServiceLocator;
022    import org.kuali.rice.kew.api.action.RolePokerQueue;
023    import org.kuali.rice.kew.api.document.DocumentProcessingQueue;
024    import org.kuali.rice.kew.api.rule.RoleName;
025    import org.kuali.rice.kew.doctype.bo.DocumentType;
026    import org.kuali.rice.kew.engine.RouteContext;
027    import org.kuali.rice.kew.engine.node.RouteNodeInstance;
028    import org.kuali.rice.kew.role.service.RoleService;
029    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
030    import org.kuali.rice.kew.rule.FlexRM;
031    import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
032    import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
033    import org.kuali.rice.kew.service.KEWServiceLocator;
034    
035    import java.util.ArrayList;
036    import java.util.Collection;
037    import java.util.HashSet;
038    import java.util.List;
039    import java.util.Set;
040    
041    
042    /**
043     *
044     * @author Kuali Rice Team (rice.collab@kuali.org)
045     */
046    public class RoleServiceImpl implements RoleService {
047    
048            private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoleServiceImpl.class);
049    
050        public void reResolveRole(DocumentType documentType, String roleName) {
051            String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName;
052            if (documentType == null ||
053                    org.apache.commons.lang.StringUtils.isEmpty(roleName)) {
054                throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
055            }
056            LOG.debug("Re-resolving role asynchronously for "+infoString);
057            Set<String> documentIds = new HashSet<String>();
058            findAffectedDocuments(documentType, roleName, null, documentIds);
059            LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
060            for (String documentId : documentIds) {
061                String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId);
062                RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId);
063                    rolePokerQueue.reResolveRole(documentId, roleName);
064                    }
065        }
066    
067        public void reResolveQualifiedRole(DocumentType documentType, String roleName, String qualifiedRoleNameLabel) {
068            String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
069            if (documentType == null ||
070                    org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
071                    org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
072                throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
073            }
074            LOG.debug("Re-resolving qualified role asynchronously for "+infoString);
075            Set<String> documentIds = new HashSet<String>();
076            findAffectedDocuments(documentType, roleName, qualifiedRoleNameLabel, documentIds);
077            LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
078            for (String documentId : documentIds) {
079                String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId);
080                RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId);
081                    rolePokerQueue.reResolveQualifiedRole(documentId, roleName, qualifiedRoleNameLabel);
082                    }
083        }
084    
085        /**
086         *
087         * route level and then filters in the approriate ones.
088         */
089        public void reResolveQualifiedRole(DocumentRouteHeaderValue routeHeader, String roleName, String qualifiedRoleNameLabel) {
090            String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
091            if (routeHeader == null ||
092                    org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
093                    org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
094                throw new IllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
095            }
096            LOG.debug("Re-resolving qualified role synchronously for "+infoString);
097            List<RouteNodeInstance> nodeInstances = findNodeInstances(routeHeader, roleName);
098            int requestsGenerated = 0;
099            if (!nodeInstances.isEmpty()) {
100                deletePendingRoleRequests(routeHeader.getDocumentId(), roleName, qualifiedRoleNameLabel);
101                for (RouteNodeInstance nodeInstance : nodeInstances) {
102                    RuleTemplateBo ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate();
103                    FlexRM flexRM = new FlexRM();
104                            RouteContext context = RouteContext.getCurrentRouteContext();
105                            context.setDocument(routeHeader);
106                            context.setNodeInstance(nodeInstance);
107                            try {
108                                    List<ActionRequestValue> actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName());
109                        for (ActionRequestValue actionRequest : actionRequests) {
110                                            if (roleName.equals(actionRequest.getRoleName()) && qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel())) {
111                                                    actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance);
112                                                    KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest);
113                                                    requestsGenerated++;
114                                            }
115                                    }
116                            } catch (Exception e) {
117                                    RouteContext.clearCurrentRouteContext();
118                            }
119    
120                }
121            }
122            LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString);
123            requeueDocument(routeHeader);
124        }
125    
126        public void reResolveRole(DocumentRouteHeaderValue routeHeader, String roleName) {
127            String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName;
128            if (routeHeader == null ||
129                    org.apache.commons.lang.StringUtils.isEmpty(roleName)) {
130                throw new RiceIllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
131            }
132            LOG.debug("Re-resolving role synchronously for "+infoString);
133            List<RouteNodeInstance> nodeInstances = findNodeInstances(routeHeader, roleName);
134            int requestsGenerated = 0;
135            if (!nodeInstances.isEmpty()) {
136                deletePendingRoleRequests(routeHeader.getDocumentId(), roleName, null);
137                for (RouteNodeInstance nodeInstance : nodeInstances) {
138                    RuleTemplateBo ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate();
139                    FlexRM flexRM = new FlexRM();
140                            RouteContext context = RouteContext.getCurrentRouteContext();
141                            context.setDocument(routeHeader);
142                            context.setNodeInstance(nodeInstance);
143                            try {
144                                    List<ActionRequestValue> actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName());
145                        for (ActionRequestValue actionRequest : actionRequests) {
146                                            if (roleName.equals(actionRequest.getRoleName())) {
147                                                    actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance);
148                                                    KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest);
149                                                    requestsGenerated++;
150                                            }
151                                    }
152                            } finally {
153                                    RouteContext.clearCurrentRouteContext();
154                            }
155                }
156            }
157            LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString);
158            requeueDocument(routeHeader);
159        }
160    
161        // search the document type and all its children
162        private void findAffectedDocuments(DocumentType documentType, String roleName, String qualifiedRoleNameLabel, Set<String> documentIds) {
163            List<ActionRequestValue> pendingRequests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocumentType(documentType.getDocumentTypeId());
164            for (ActionRequestValue actionRequest : pendingRequests) {
165                            if (roleName.equals(actionRequest.getRoleName()) &&
166                                            (qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) {
167                                    documentIds.add(actionRequest.getDocumentId());
168                            }
169                    }
170            for (DocumentType childDocumentType : documentType.getChildrenDocTypes()) {
171                            findAffectedDocuments(childDocumentType, roleName, qualifiedRoleNameLabel, documentIds);
172                    }
173        }
174    
175        private void deletePendingRoleRequests(String documentId, String roleName, String qualifiedRoleNameLabel) {
176            List<ActionRequestValue> pendingRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
177            pendingRequests = KEWServiceLocator.getActionRequestService().getRootRequests(pendingRequests);
178            List<ActionRequestValue> requestsToDelete = new ArrayList<ActionRequestValue>();
179            for (ActionRequestValue actionRequest : pendingRequests) {
180                if (roleName.equals(actionRequest.getRoleName()) &&
181                            (qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) {
182                    requestsToDelete.add(actionRequest);
183                }
184            }
185            LOG.debug("Deleting "+requestsToDelete.size()+" action requests for roleName="+roleName+", qualifiedRoleNameLabel="+qualifiedRoleNameLabel);
186            for (ActionRequestValue actionRequest : requestsToDelete) {
187                KEWServiceLocator.getActionRequestService().deleteActionRequestGraphNoOutbox(actionRequest);
188            }
189        }
190    
191        private List<RouteNodeInstance> findNodeInstances(DocumentRouteHeaderValue routeHeader, String roleName) {
192            List<RouteNodeInstance> nodeInstances = new ArrayList<RouteNodeInstance>();
193            Collection<RouteNodeInstance> activeNodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(routeHeader.getDocumentId());
194            if (CollectionUtils.isEmpty(activeNodeInstances)) {
195                throw new IllegalStateException("Document does not currently have any active nodes so re-resolving is not legal.");
196            }
197            for (RouteNodeInstance activeNodeInstance : activeNodeInstances) {
198                RuleTemplateBo template = activeNodeInstance.getRouteNode().getRuleTemplate();
199                if (templateHasRole(template, roleName)) {
200                    nodeInstances.add(activeNodeInstance);
201                }
202            }
203            if (nodeInstances.isEmpty()) {
204                throw new IllegalStateException("Could not locate given role to re-resolve: " + roleName);
205            }
206            return nodeInstances;
207        }
208    
209        private boolean templateHasRole(RuleTemplateBo template, String roleName) {
210            List<RuleTemplateAttributeBo> templateAttributes = template.getRuleTemplateAttributes();
211            for (RuleTemplateAttributeBo templateAttribute : templateAttributes) {
212                List<RoleName> roleNames = KEWServiceLocator.getWorkflowRuleAttributeMediator().getRoleNames(templateAttribute);
213                for (RoleName role : roleNames) {
214                    if (role.getLabel().equals(roleName)) {
215                        return true;
216                    }
217                }
218            }
219            return false;
220        }
221    
222        protected void requeueDocument(DocumentRouteHeaderValue document) {
223            String applicationId = document.getDocumentType().getApplicationId();
224            DocumentProcessingQueue documentProcessingQueue = KewApiServiceLocator.getDocumentProcessingQueue(document.getDocumentId(), applicationId);
225            documentProcessingQueue.process(document.getDocumentId());
226        }
227    
228    }