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 */
016package org.kuali.rice.kim.document.rule;
017
018import java.util.List;
019import java.util.Map;
020import java.util.regex.Matcher;
021import java.util.regex.Pattern;
022
023import javax.xml.namespace.QName;
024
025import org.apache.commons.lang.StringUtils;
026import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
027import org.kuali.rice.core.api.uif.RemotableAttributeError;
028import org.kuali.rice.core.api.util.RiceKeyConstants;
029import org.kuali.rice.kim.api.common.template.Template;
030import org.kuali.rice.kim.api.permission.Permission;
031import org.kuali.rice.kim.api.services.KimApiServiceLocator;
032import org.kuali.rice.kim.api.type.KimType;
033import org.kuali.rice.kim.framework.permission.PermissionTypeService;
034import org.kuali.rice.kim.impl.permission.GenericPermissionBo;
035import org.kuali.rice.kns.document.MaintenanceDocument;
036import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
037import org.kuali.rice.krad.util.GlobalVariables;
038
039/**
040 * This is a description of what this class does - kellerj don't forget to fill this in. 
041 * 
042 * @author Kuali Rice Team (rice.collab@kuali.org)
043 *
044 */
045public class GenericPermissionMaintenanceDocumentRule extends MaintenanceDocumentRuleBase {
046    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GenericPermissionMaintenanceDocumentRule.class);    
047    
048        protected static final String DETAIL_VALUES_PROPERTY = "detailValues";
049    protected static final String NAMESPACE_CODE_PROPERTY = "namespaceCode";
050        protected static final String ERROR_MESSAGE_PREFIX = "error.document.kim.genericpermission.";
051        protected static final String ERROR_MISSING_TEMPLATE = ERROR_MESSAGE_PREFIX + "missingtemplate";
052        protected static final String ERROR_UNKNOWN_ATTRIBUTE = ERROR_MESSAGE_PREFIX + "unknownattribute";
053        protected static final String ERROR_ATTRIBUTE_VALIDATION = ERROR_MESSAGE_PREFIX + "attributevalidation";
054    protected static final String ERROR_NAMESPACE_AND_NAME_VALIDATION = ERROR_MESSAGE_PREFIX + "namespaceandnamevalidation";
055
056        
057        @Override
058        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
059                boolean rulesPassed = super.processCustomRouteDocumentBusinessRules( document );
060                try {
061                        GenericPermissionBo newPerm = (GenericPermissionBo)getNewBo();
062            GenericPermissionBo oldPerm = (GenericPermissionBo)getOldBo();
063                        rulesPassed &= validateDetailValuesFormat(newPerm.getDetailValues());
064            if(StringUtils.isNotBlank(newPerm.getNamespaceCode()) && StringUtils.isNotBlank(newPerm.getName()) && StringUtils.isBlank(newPerm.getId())){
065                rulesPassed &= validateNamespaceCodeAndName(newPerm.getNamespaceCode(), newPerm.getName());
066            }
067            // rule case for copy
068            if(StringUtils.isNotBlank(newPerm.getNamespaceCode()) &&
069               StringUtils.isNotBlank(newPerm.getName()) &&
070               StringUtils.isNotBlank(oldPerm.getId()) &&
071               StringUtils.isNotBlank(newPerm.getId()) &&
072               !StringUtils.equals(oldPerm.getId(), newPerm.getId())){
073                  rulesPassed &= validateNamespaceCodeAndName(newPerm.getNamespaceCode(), newPerm.getName());
074            }
075            // rule case for edit
076            if(StringUtils.isNotBlank(newPerm.getNamespaceCode()) &&
077                    StringUtils.isNotBlank(newPerm.getName()) &&
078                    StringUtils.isNotBlank(oldPerm.getId()) &&
079                    StringUtils.isNotBlank(newPerm.getId()) &&
080                    StringUtils.equals(oldPerm.getId(), newPerm.getId()) &&
081                    ( !StringUtils.equals(oldPerm.getNamespaceCode(), newPerm.getNamespaceCode()) ||
082                      !StringUtils.equals(oldPerm.getName(), newPerm.getName())
083                    )
084               ) {
085                rulesPassed &= validateNamespaceCodeAndName(newPerm.getNamespaceCode(), newPerm.getName());
086            }
087                        // detailValues
088                        // get the type from the template for validation
089            if(StringUtils.isNotBlank(newPerm.getTemplateId())){
090                Template template = KimApiServiceLocator.getPermissionService().getPermissionTemplate(newPerm.getTemplateId());
091                if ( template == null ) {
092                    GlobalVariables.getMessageMap().addToErrorPath( MAINTAINABLE_ERROR_PATH );
093                    GlobalVariables.getMessageMap().putError( DETAIL_VALUES_PROPERTY, ERROR_MISSING_TEMPLATE, newPerm.getTemplateId() );
094                    GlobalVariables.getMessageMap().removeFromErrorPath( MAINTAINABLE_ERROR_PATH );
095                    rulesPassed &= false;
096                } else {
097                    KimType kimType = KimApiServiceLocator.getKimTypeInfoService().getKimType(template.getKimTypeId());
098                    Map<String, String> details = newPerm.getDetails();
099                    // check that add passed attributes are defined
100                    for ( String attributeName : details.keySet() ) {
101                        if ( kimType.getAttributeDefinitionByName(attributeName) == null ) {
102                            GlobalVariables.getMessageMap().addToErrorPath( MAINTAINABLE_ERROR_PATH );
103                            GlobalVariables.getMessageMap().putError( DETAIL_VALUES_PROPERTY, ERROR_UNKNOWN_ATTRIBUTE, attributeName, template.getNamespaceCode(), template.getName() );
104                            GlobalVariables.getMessageMap().removeFromErrorPath( MAINTAINABLE_ERROR_PATH );
105                            rulesPassed &= false;
106                        }
107                    }
108                    // if all attributes are known, pass to the service for validation
109                    if ( !GlobalVariables.getMessageMap().hasErrors() ) {
110                        PermissionTypeService service = getPermissionTypeService( kimType.getServiceName() );
111                        if ( service != null ) {
112                            List<RemotableAttributeError> validationErrors = service.validateAttributes( kimType.getId(), details);
113                            if ( validationErrors != null && !validationErrors.isEmpty() ) {
114                                for ( RemotableAttributeError error : validationErrors ) {
115                                    GlobalVariables.getMessageMap().addToErrorPath( MAINTAINABLE_ERROR_PATH );
116                                    for (String errMsg : error.getErrors()) {
117                                        GlobalVariables.getMessageMap().putError( DETAIL_VALUES_PROPERTY, ERROR_ATTRIBUTE_VALIDATION, error.getAttributeName(), errMsg );
118                                    }
119                                    GlobalVariables.getMessageMap().removeFromErrorPath( MAINTAINABLE_ERROR_PATH );
120                                }
121                                rulesPassed &= false;
122                            }
123                        }
124                    }
125
126                }
127
128            }
129                        // check each permission name against the type
130                } catch ( RuntimeException ex ) {
131                        LOG.error( "Error in processCustomRouteDocumentBusinessRules()", ex );
132                        throw ex;
133                }
134                return rulesPassed;
135        }
136
137        protected boolean validateDetailValuesFormat(String permissionDetailValues){
138                if(permissionDetailValues != null){
139                        Pattern pattern = Pattern.compile(".+"+"="+".+");
140                        // ensure that all line delimiters are single linefeeds
141                        permissionDetailValues = permissionDetailValues.replace( "\r\n", "\n" );
142                        permissionDetailValues = permissionDetailValues.replace( '\r', '\n' );
143                        if(StringUtils.isNotBlank(permissionDetailValues)){
144                                String[] values = permissionDetailValues.split( "\n" );
145                                for(String attrib : values){
146                    Matcher matcher = pattern.matcher(attrib);
147                    if (!matcher.matches()) {
148                        GlobalVariables.getMessageMap().putError(
149                                MAINTAINABLE_ERROR_PATH + "." + DETAIL_VALUES_PROPERTY,
150                                RiceKeyConstants.ERROR_INVALID_FORMAT,
151                                new String[]{"Detail Values", permissionDetailValues});
152                        return false;
153                    }
154                                }
155                        }
156                }
157                return true;
158        }
159    protected boolean validateNamespaceCodeAndName(String namespaceCode,String name){
160        Permission permission = KimApiServiceLocator.getPermissionService().findPermByNamespaceCodeAndName(namespaceCode,name);
161        if(null != permission){
162            GlobalVariables.getMessageMap().putError(MAINTAINABLE_ERROR_PATH+"."+NAMESPACE_CODE_PROPERTY,ERROR_NAMESPACE_AND_NAME_VALIDATION,namespaceCode,name);
163            return false;
164        } else{
165            return true;
166        }
167    }
168        
169        protected PermissionTypeService getPermissionTypeService( String serviceName ) {
170        if ( StringUtils.isBlank( serviceName ) ) {
171                return null;
172        }
173        try {
174                Object service = GlobalResourceLoader.getService(QName.valueOf(serviceName));
175                // if we have a service name, it must exist
176                if ( service == null ) {
177                                LOG.warn("null returned for permission type service for service name: " + serviceName);
178                } else {
179                        // whatever we retrieved must be of the correct type
180                        if ( !(service instanceof PermissionTypeService)  ) {
181                                LOG.warn( "Service " + serviceName + " was not a KimPermissionTypeService.  Was: " + service.getClass().getName() );
182                                service = null;
183                        }
184                }
185                return (PermissionTypeService)service;
186        } catch( Exception ex ) {
187                LOG.error( "Error retrieving service: " + serviceName + " from the KimImplServiceLocator.", ex );
188        }
189        return null;
190    }
191
192}