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.krad.kim;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator;
020import org.kuali.rice.coreservice.api.namespace.Namespace;
021import org.kuali.rice.core.api.uif.RemotableAttributeError;
022import org.kuali.rice.kim.api.KimConstants;
023import org.kuali.rice.kim.api.permission.Permission;
024import org.kuali.rice.kim.api.type.KimType;
025import org.kuali.rice.kim.impl.permission.PermissionBo;
026import org.kuali.rice.krad.kim.NamespacePermissionTypeServiceImpl;
027
028import java.util.ArrayList;
029import java.util.Collections;
030import java.util.HashMap;
031import java.util.List;
032import java.util.Map;
033
034/**
035 * @author Kuali Rice Team (rice.collab@kuali.org)
036 */
037public class NamespaceWildcardAllowedAndOrStringExactMatchPermissionTypeServiceImpl
038                extends NamespacePermissionTypeServiceImpl {
039        protected static final String NAMESPACE_CODE = KimConstants.UniqueKeyConstants.NAMESPACE_CODE;
040        
041        protected String exactMatchStringAttributeName;
042        protected boolean namespaceRequiredOnStoredMap;
043    private List<String> requiredAttributes = new ArrayList<String>();
044
045    @Override
046    protected List<String> getRequiredAttributes() {
047        return Collections.unmodifiableList(requiredAttributes);
048    }
049
050        @Override
051        protected List<Permission> performPermissionMatches(Map<String, String> requestedDetails, List<Permission> permissionsList) {
052            List<Permission> matchingPermissions = new ArrayList<Permission>();
053        List<Permission> matchingBlankPermissions = new ArrayList<Permission>();
054            String requestedAttributeValue = requestedDetails.get(exactMatchStringAttributeName);
055            for ( Permission kpi : permissionsList ) {
056            PermissionBo bo = PermissionBo.from(kpi);
057                String permissionAttributeValue = bo.getDetails().get(exactMatchStringAttributeName);
058                if ( StringUtils.equals(requestedAttributeValue, permissionAttributeValue) ) {
059                    matchingPermissions.add(kpi);
060                } else if ( StringUtils.isBlank(permissionAttributeValue) ) {
061                    matchingBlankPermissions.add(kpi);
062                }
063            }
064            // if the exact match worked, use those when checking the namespace
065            // otherwise, use those with a blank additional property value
066            if ( !matchingPermissions.isEmpty() ) {
067            List<Permission> matchingWithNamespace = super.performPermissionMatches(requestedDetails, matchingPermissions);
068                if ( !namespaceRequiredOnStoredMap ) {
069                    // if the namespace is not required and the namespace match would have excluded
070                    // the results, return the original set of matches
071                    if ( matchingWithNamespace.isEmpty() ) {
072                        return matchingPermissions;
073                    }
074                }
075            return matchingWithNamespace;
076            } else if ( !matchingBlankPermissions.isEmpty() ) {
077            List<Permission> matchingWithNamespace = super.performPermissionMatches(requestedDetails, matchingBlankPermissions);
078            if ( !namespaceRequiredOnStoredMap ) {
079                // if the namespace is not required and the namespace match would have excluded
080                // the results, return the original set of matches
081                if ( matchingWithNamespace.isEmpty() ) {
082                    return matchingBlankPermissions;
083                }
084            }
085            return matchingWithNamespace;
086            }
087            return matchingPermissions; // will be empty if drops to here
088        }
089        
090        public void setExactMatchStringAttributeName(
091                        String exactMatchStringAttributeName) {
092                this.exactMatchStringAttributeName = exactMatchStringAttributeName;
093                requiredAttributes.add(exactMatchStringAttributeName);
094        }
095
096        public void setNamespaceRequiredOnStoredMap(
097                        boolean namespaceRequiredOnStoredMap) {
098                this.namespaceRequiredOnStoredMap = namespaceRequiredOnStoredMap;
099        }
100
101        /**
102         * Overrides the superclass's version of this method in order to account for "namespaceCode" permission detail values containing wildcards.
103         */
104        @Override
105        protected List<RemotableAttributeError> validateReferencesExistAndActive(KimType kimType, Map<String, String> attributes, List<RemotableAttributeError> previousValidationErrors) {
106                List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>();
107                Map<String, String> nonNamespaceCodeAttributes = new HashMap<String, String>(attributes);
108                // Check if "namespaceCode" is one of the permission detail values.
109                if (attributes.containsKey(NAMESPACE_CODE)) {
110                        nonNamespaceCodeAttributes.remove(NAMESPACE_CODE);
111
112            final Namespace namespace =
113                    StringUtils.isBlank(attributes.get(NAMESPACE_CODE)) ?
114                            null : CoreServiceApiServiceLocator.getNamespaceService().getNamespace(attributes.get(NAMESPACE_CODE));
115
116            if (namespace != null) {
117                            errors.addAll(super.validateReferencesExistAndActive(kimType, Collections.singletonMap(NAMESPACE_CODE,
118                        namespace.getCode()), previousValidationErrors));
119                        } else {
120                                // If no namespaces were found, let the superclass generate an appropriate error.
121                                errors.addAll(super.validateReferencesExistAndActive(kimType, Collections.singletonMap(NAMESPACE_CODE,
122                        attributes.get(NAMESPACE_CODE)), previousValidationErrors));
123                        }
124                }
125                // Validate all non-namespaceCode attributes.
126                errors.addAll(super.validateReferencesExistAndActive(kimType, nonNamespaceCodeAttributes, previousValidationErrors));
127                return errors;
128        }
129}