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