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}