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.kim.rules.ui;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.CoreConstants;
020import org.kuali.rice.core.api.membership.MemberType;
021import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
022import org.kuali.rice.core.api.uif.RemotableAttributeError;
023import org.kuali.rice.core.api.util.RiceKeyConstants;
024import org.kuali.rice.kim.api.KimConstants;
025import org.kuali.rice.kim.api.type.KimType;
026import org.kuali.rice.kim.bo.ui.KimDocumentRoleMember;
027import org.kuali.rice.kim.document.IdentityManagementRoleDocument;
028import org.kuali.rice.kim.document.rule.AttributeValidationHelper;
029import org.kuali.rice.kim.framework.role.RoleTypeService;
030import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator;
031import org.kuali.rice.kim.framework.type.KimTypeService;
032import org.kuali.rice.kim.impl.services.KimImplServiceLocator;
033import org.kuali.rice.kim.rule.event.ui.AddMemberEvent;
034import org.kuali.rice.kim.rule.ui.AddMemberRule;
035import org.kuali.rice.kns.rules.DocumentRuleBase;
036import org.kuali.rice.krad.service.KRADServiceLocator;
037import org.kuali.rice.krad.service.impl.KRADModuleService;
038import org.kuali.rice.core.api.util.VersionHelper;
039import org.kuali.rice.krad.util.GlobalVariables;
040import org.kuali.rice.krad.util.ObjectUtils;
041import org.kuali.rice.ksb.api.KsbApiServiceLocator;
042import org.kuali.rice.ksb.api.bus.Endpoint;
043import org.kuali.rice.ksb.api.bus.ServiceBus;
044
045import javax.xml.namespace.QName;
046import java.util.ArrayList;
047import java.util.HashMap;
048import java.util.List;
049import java.util.Map;
050
051
052/**
053 * This is a description of what this class does - shyu don't forget to fill this in. 
054 * 
055 * @author Kuali Rice Team (rice.collab@kuali.org)
056 *
057 */
058public class KimDocumentMemberRule extends DocumentRuleBase implements AddMemberRule {
059
060        private static final String ERROR_PATH = "member.memberId";
061
062        protected AttributeValidationHelper attributeValidationHelper = new AttributeValidationHelper();
063        
064        public boolean processAddMember(AddMemberEvent addMemberEvent){
065                KimDocumentRoleMember newMember = addMemberEvent.getMember();
066                IdentityManagementRoleDocument document = (IdentityManagementRoleDocument)addMemberEvent.getDocument();
067            boolean rulePassed = true;
068
069        if (newMember == null || StringUtils.isBlank(newMember.getMemberId())){
070            GlobalVariables.getMessageMap().putError(ERROR_PATH, RiceKeyConstants.ERROR_EMPTY_ENTRY, new String[] {"Member"});
071            return false;
072        }
073        if(!validAssignRole(newMember, document)) {
074                return false;
075        }
076                List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>();
077        KimTypeService kimTypeService = KimFrameworkServiceLocator.getKimTypeService(document.getKimType());
078        
079        Long newMemberFromTime = newMember.getActiveFromDate() == null ? 0L : newMember.getActiveFromDate().getTime();
080        Long newMemberToTime = newMember.getActiveToDate() == null ? Long.MAX_VALUE : newMember.getActiveToDate().getTime();
081        
082                List<RemotableAttributeError> errorsAttributesAgainstExisting  = new ArrayList<RemotableAttributeError>();
083        Map<String, String> newMemberQualifiers = attributeValidationHelper.convertQualifiersToMap(newMember.getQualifiers());
084
085            Map<String, String> oldMemberQualifiers;
086            for (KimDocumentRoleMember member: document.getMembers()){
087                Long memberFromTime = member.getActiveFromDate() == null ? 0L : member.getActiveFromDate().getTime();
088            Long memberToTime = member.getActiveToDate() == null ? Long.MAX_VALUE : member.getActiveToDate().getTime();
089                oldMemberQualifiers = attributeValidationHelper.convertQualifiersToMap(member.getQualifiers());
090
091            if ((member.getMemberId().equals(newMember.getMemberId()) &&
092                    member.getMemberTypeCode().equals(newMember.getMemberTypeCode()))
093                    && ((newMemberFromTime >= memberFromTime && newMemberFromTime < memberToTime)
094                    || (newMemberToTime >= memberFromTime && newMemberToTime <= memberToTime)))  {
095
096                errorsAttributesAgainstExisting = kimTypeService.validateAttributesAgainstExisting(
097                                document.getKimType().getId(), newMemberQualifiers, oldMemberQualifiers);
098                            validationErrors.addAll(
099                                        attributeValidationHelper.convertErrorsForMappedFields(ERROR_PATH, errorsAttributesAgainstExisting));
100                    if (!errorsAttributesAgainstExisting.isEmpty()) {
101                        rulePassed = false;
102                        GlobalVariables.getMessageMap().putError(ERROR_PATH, RiceKeyConstants.ERROR_DUPLICATE_ENTRY, new String[] {"Member"});
103                        break;
104                    }
105            }
106            }
107
108        boolean shouldNotValidate = newMember.isRole();
109            if ( kimTypeService != null && ObjectUtils.isNotNull( document.getKimType() ) && StringUtils.isNotBlank(document.getKimType().getServiceName()) ) {
110            VersionedService<RoleTypeService> versionedRoleTypeService = getVersionedRoleTypeService(document.getKimType());
111            if (versionedRoleTypeService != null) {
112                boolean versionOk = VersionHelper.compareVersion(versionedRoleTypeService.getVersion(), CoreConstants.Versions.VERSION_2_1_2)!=-1? true:false;
113                if(versionOk) {
114                    shouldNotValidate = versionedRoleTypeService.getService().shouldValidateQualifiersForMemberType( MemberType.fromCode(newMember.getMemberTypeCode()));
115                } else {
116                    shouldNotValidate = false;
117                }
118            }
119        }
120        if (kimTypeService !=null && !shouldNotValidate) {
121                List<RemotableAttributeError> localErrors = kimTypeService.validateAttributes( document.getKimType().getId(), attributeValidationHelper.convertQualifiersToMap( newMember.getQualifiers() ) );
122                validationErrors.addAll( attributeValidationHelper.convertErrors("member",
123                    attributeValidationHelper.convertQualifiersToAttrIdxMap(newMember.getQualifiers()), localErrors) );
124        }
125        if (!validationErrors.isEmpty()) {
126                attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors);
127                rulePassed = false;
128        }
129
130                return rulePassed;
131        } 
132
133        protected boolean validAssignRole(KimDocumentRoleMember roleMember, IdentityManagementRoleDocument document){
134        boolean rulePassed = true;
135                if(StringUtils.isNotEmpty(document.getRoleNamespace())){
136                        Map<String,String> roleDetails = new HashMap<String,String>();
137                        roleDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, document.getRoleNamespace());
138                        roleDetails.put(KimConstants.AttributeConstants.ROLE_NAME, document.getRoleName());
139                        if (!getDocumentDictionaryService().getDocumentAuthorizer(document).isAuthorizedByTemplate(
140                                        document, 
141                                        KimConstants.NAMESPACE_CODE, 
142                                        KimConstants.PermissionTemplateNames.ASSIGN_ROLE,
143                                        GlobalVariables.getUserSession().getPerson().getPrincipalId(), 
144                                        roleDetails, null)){
145                    GlobalVariables.getMessageMap().putError(ERROR_PATH, RiceKeyConstants.ERROR_ASSIGN_ROLE, 
146                                new String[] {document.getRoleNamespace(), document.getRoleName()});
147                    rulePassed = false;
148                        }
149                }
150                return rulePassed;
151        }
152
153    private static class VersionedService<T> {
154
155        String version;
156        T service;
157
158        VersionedService(String version, T service) {
159            this.version = version;
160            this.service = service;
161        }
162
163        T getService() {
164            return this.service;
165        }
166
167        String getVersion() {
168            return this.version;
169        }
170
171    }
172
173    protected VersionedService<RoleTypeService> getVersionedRoleTypeService(KimType typeInfo) {
174        String serviceName = typeInfo.getServiceName();
175        if (serviceName != null) {
176            String version = "2.0.0"; // default version since the base services have been available since then
177            RoleTypeService roleTypeService = null;
178            try {
179
180                ServiceBus serviceBus = KsbApiServiceLocator.getServiceBus();
181                Endpoint endpoint = serviceBus.getEndpoint(QName.valueOf(serviceName));
182                if (endpoint != null) {
183                    version = endpoint.getServiceConfiguration().getServiceVersion();
184                }
185                KimTypeService service = (KimTypeService) GlobalResourceLoader.getService(QName.valueOf(serviceName));
186                if (service != null && service instanceof RoleTypeService) {
187                    roleTypeService = (RoleTypeService) service;
188                } else {
189                    roleTypeService = (RoleTypeService) KimImplServiceLocator.getService("kimNoMembersRoleTypeService");
190                }
191            } catch (Exception ex) {
192                roleTypeService = (RoleTypeService) KimImplServiceLocator.getService("kimNoMembersRoleTypeService");
193            }
194            return new VersionedService<RoleTypeService>(version, roleTypeService);
195        }
196        return null;
197    }
198
199
200}