001/**
002 * Copyright 2005-2016 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.kew.doctype.service.impl;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.collections.Transformer;
020import org.apache.commons.lang.StringUtils;
021import org.kuali.rice.kew.api.KewApiConstants;
022import org.kuali.rice.kew.doctype.bo.DocumentType;
023import org.kuali.rice.kew.doctype.service.DocumentTypePermissionService;
024import org.kuali.rice.kew.engine.node.RouteNodeInstance;
025import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
026import org.kuali.rice.kim.api.group.GroupService;
027import org.kuali.rice.kim.api.services.KimApiServiceLocator;
028
029import java.util.*;
030
031/**
032 * Implementation of the DocumentTypePermissionService. 
033 * 
034 * @author Kuali Rice Team (rice.collab@kuali.org)
035 */
036public class DocumentTypePermissionServiceImpl extends DocumentActionsPermissionBase implements DocumentTypePermissionService {
037        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentTypePermissionServiceImpl.class);
038
039    @Override
040    public boolean canReceiveAdHocRequest(String principalId, DocumentRouteHeaderValue document, String actionRequestType) {
041        validatePrincipalId(principalId);
042        validateDocument(document);
043        DocumentType documentType = document.getDocumentType();
044        validateDocumentType(documentType);
045        validateActionRequestType(actionRequestType);
046        final Boolean result;
047
048        Map<String, String> permissionDetails = buildDocumentTypePermissionDetails(documentType, null, actionRequestType, null);
049        if (useKimPermission(KewApiConstants.KEW_NAMESPACE, KewApiConstants.AD_HOC_REVIEW_PERMISSION, permissionDetails, true)) {
050            result = getPermissionService().isAuthorizedByTemplate(principalId, KewApiConstants.KEW_NAMESPACE,
051                    KewApiConstants.AD_HOC_REVIEW_PERMISSION, permissionDetails, new HashMap<String, String>());
052        } else {
053            result = Boolean.TRUE;
054        }
055        return result;
056    }
057
058    @Override
059    public boolean canGroupReceiveAdHocRequest(String groupId, DocumentRouteHeaderValue document, String actionRequestType) {
060        validateGroupId(groupId);
061        validateDocument(document);
062        DocumentType documentType = document.getDocumentType();
063        validateDocumentType(documentType);
064        validateActionRequestType(actionRequestType);
065
066        Boolean result = Boolean.TRUE;
067        Map<String, String> permissionDetails = buildDocumentTypePermissionDetails(documentType, null, actionRequestType, null);
068        if (useKimPermission(KewApiConstants.KEW_NAMESPACE, KewApiConstants.AD_HOC_REVIEW_PERMISSION, permissionDetails, true)) {
069            List<String> principalIds = getGroupService().getMemberPrincipalIds(groupId);
070            // if any member of the group is not allowed to receive the request, then the group may not receive it
071            for (String principalId : principalIds) {
072                if (!getPermissionService().isAuthorizedByTemplate(principalId, KewApiConstants.KEW_NAMESPACE,
073                        KewApiConstants.AD_HOC_REVIEW_PERMISSION, permissionDetails, new HashMap<String, String>())) {
074                    result = Boolean.FALSE;
075                    break;
076                }
077            }
078        }
079        return result;
080    }
081
082    @Override
083    public boolean canAdministerRouting(String principalId, DocumentType documentType) {
084        validatePrincipalId(principalId);
085        validateDocumentType(documentType);
086
087        final Boolean result;
088        if (documentType.isSuperUserGroupDefined()) {
089            result = documentType.isSuperUser(principalId);
090        } else {
091            Map<String, String> permissionDetails = buildDocumentTypePermissionDetails(documentType, null, null, null);
092            result = getPermissionService().isAuthorizedByTemplate(principalId, KewApiConstants.KEW_NAMESPACE,
093                    KewApiConstants.ADMINISTER_ROUTING_PERMISSION, permissionDetails, new HashMap<String, String>());
094        }
095        return result;
096    }
097
098    @Override
099    public boolean canSuperUserApproveSingleActionRequest(String principalId, DocumentType documentType,
100                                                          List<RouteNodeInstance> routeNodeInstances, String routeStatusCode) {
101        return canSuperUserApproveSingleActionRequest(principalId, documentType, toRouteNodeNames(routeNodeInstances), routeStatusCode);
102    }
103
104    @Override
105    public boolean canSuperUserApproveDocument(String principalId, DocumentType documentType,
106                                               List<RouteNodeInstance> routeNodeInstances, String routeStatusCode) {
107        return canSuperUserApproveDocument(principalId, documentType, toRouteNodeNames(routeNodeInstances), routeStatusCode);
108    }
109
110    @Override
111    public boolean canSuperUserDisapproveDocument(String principalId, DocumentType documentType,
112                                                  List<RouteNodeInstance> routeNodeInstances,String routeStatusCode) {
113        return canSuperUserDisapproveDocument(principalId, documentType, toRouteNodeNames(routeNodeInstances), routeStatusCode);
114    }
115
116    @Override
117    public boolean canAddRouteLogMessage(String principalId, DocumentRouteHeaderValue document) {
118        validatePrincipalId(principalId);
119        validateDocument(document);
120        String documentId = document.getDocumentId();
121        DocumentType documentType = document.getDocumentType();
122        String documentStatus = document.getDocRouteStatus();
123        String initiatorPrincipalId = document.getInitiatorWorkflowId();
124        validateDocumentType(documentType);
125        validateDocumentStatus(documentStatus);
126        validatePrincipalId(initiatorPrincipalId);
127
128        Map<String, String> permissionDetails = buildDocumentTypePermissionDetails(documentType, documentStatus, null, null);
129        Map<String, String> roleQualifiers = buildDocumentRoleQualifiers(document, permissionDetails.get(KewApiConstants.ROUTE_NODE_NAME_DETAIL));
130
131        if (LOG.isDebugEnabled()) {
132            LOG.debug("Permission details values: " + permissionDetails);
133            LOG.debug("Role qualifiers values: " + roleQualifiers);
134        }
135
136        if (useKimPermission(KewApiConstants.KEW_NAMESPACE, KewApiConstants.ADD_MESSAGE_TO_ROUTE_LOG, permissionDetails, false)) {
137            return getPermissionService().isAuthorizedByTemplate(principalId, KewApiConstants.KEW_NAMESPACE,
138                    KewApiConstants.ADD_MESSAGE_TO_ROUTE_LOG, permissionDetails, roleQualifiers);
139        }
140
141        return false;
142    }
143
144    /**
145     * Converts list of RouteNodeInstance objects to a list of the route node names
146     * @param routeNodeInstances the list RouteNodeInstance objects, may be null
147     * @return non-null, possibly empty, Collection of routenode names
148     */
149    protected Collection<String> toRouteNodeNames(Collection<RouteNodeInstance> routeNodeInstances) {
150        if (routeNodeInstances != null) {
151            return CollectionUtils.collect(routeNodeInstances, new Transformer() {
152                @Override
153                public Object transform(Object input) {
154                    return ((RouteNodeInstance) input).getName();
155                }
156            });
157        } else {
158            return Collections.EMPTY_LIST;
159        }
160    }
161
162    /**
163     * Validates groupId parameter
164     * @param groupId the group id
165     * @throw IllegalArgumentException if groupId is empty or null
166     */
167    private void validateGroupId(String groupId) {
168        if (StringUtils.isBlank(groupId)) {
169            throw new IllegalArgumentException("Invalid group ID, value was empty");
170        }
171    }
172
173    /**
174     * Validates actionRequestType parameter
175     * @param actionRequestType the actionRequest type
176     * @throw IllegalArgumentException if the actionRequest type is empty or null, or an invalid value
177     */
178    private void validateActionRequestType(String actionRequestType) {
179        if (StringUtils.isBlank(actionRequestType)) {
180            throw new IllegalArgumentException("Invalid action request type, value was empty");
181        }
182        if (!KewApiConstants.ACTION_REQUEST_CODES.containsKey(actionRequestType)) {
183            throw new IllegalArgumentException("Invalid action request type was given, value was: " + actionRequestType);
184        }
185    }
186
187    // convenience method to look up KIM GroupService
188    protected GroupService getGroupService() {
189        return KimApiServiceLocator.getGroupService();
190    }
191}