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.impl.type; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020import org.kuali.rice.kew.engine.RouteContext; 021import org.kuali.rice.kim.api.KimConstants; 022import org.kuali.rice.kim.api.group.Group; 023import org.kuali.rice.kim.api.group.GroupService; 024import org.kuali.rice.kim.api.role.RoleMembership; 025import org.kuali.rice.kim.api.role.RoleService; 026import org.kuali.rice.kim.api.services.KimApiServiceLocator; 027import org.kuali.rice.kim.api.type.KimType; 028import org.kuali.rice.kim.api.type.KimTypeInfoService; 029import org.kuali.rice.kim.bo.ui.KimDocumentRoleMember; 030import org.kuali.rice.kim.bo.ui.PersonDocumentGroup; 031import org.kuali.rice.kim.bo.ui.PersonDocumentRole; 032import org.kuali.rice.kim.document.IdentityManagementGroupDocument; 033import org.kuali.rice.kim.document.IdentityManagementPersonDocument; 034import org.kuali.rice.kim.document.IdentityManagementRoleDocument; 035import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator; 036import org.kuali.rice.kim.framework.type.KimTypeService; 037import org.kuali.rice.kns.workflow.attribute.QualifierResolverBase; 038import org.kuali.rice.krad.document.Document; 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.HashMap; 043import java.util.List; 044import java.util.Map; 045 046/** 047 * This is a description of what this class does - kellerj don't forget to fill this in. 048 * 049 * @author Kuali Rice Team (rice.collab@kuali.org) 050 * 051 */ 052public class KimTypeQualifierResolver extends QualifierResolverBase { 053 private static final Logger LOG = Logger.getLogger(KimTypeQualifierResolver.class); 054 055 protected static final String GROUP_ROUTE_LEVEL = "GroupType"; 056 protected static final String ROLE_ROUTE_LEVEL = "RoleType"; 057 058 private static KimTypeInfoService kimTypeInfoService; 059 private static GroupService groupService; 060 private static RoleService roleService; 061 062 protected static Map<String,KimTypeService> typeServices = new HashMap<String, KimTypeService>(); 063 064 /** 065 * This overridden method ... 066 * 067 * @see org.kuali.rice.kew.role.QualifierResolver#resolve(org.kuali.rice.kew.engine.RouteContext) 068 */ 069 public List<Map<String, String>> resolve(RouteContext context) { 070 String routeLevel = context.getNodeInstance().getName(); 071 Document document = getDocument(context); 072 List<Map<String, String>> qualifiers = new ArrayList<Map<String, String>>(); 073 String customDocTypeName = null; 074 075 if ( document instanceof IdentityManagementGroupDocument ) { 076 customDocTypeName = handleGroupDocument(qualifiers, (IdentityManagementGroupDocument)document, routeLevel); 077 } else if ( document instanceof IdentityManagementRoleDocument ) { 078 customDocTypeName = handleRoleDocument(qualifiers, (IdentityManagementRoleDocument)document, routeLevel); 079 } else if ( document instanceof IdentityManagementPersonDocument ) { 080 customDocTypeName = handlePersonDocument(qualifiers, (IdentityManagementPersonDocument)document, routeLevel); 081 } 082 // add standard components 083 decorateWithCommonQualifiers(qualifiers, context, customDocTypeName); 084 // return the resulting list of Map<String, String>s 085 return qualifiers; 086 } 087 088 protected KimTypeService getTypeService( String typeId ) { 089 KimTypeService typeService = typeServices.get(typeId); 090 if ( typeService == null ) { 091 KimType typeInfo = getKimTypeInfoService().getKimType(typeId); 092 if ( typeInfo != null ) { 093 typeService = KimFrameworkServiceLocator.getKimTypeService(typeInfo); 094 typeServices.put(typeId, typeService); 095 } else { 096 LOG.warn( "Unable to retrieve KIM Type Info object for id: " + typeId ); 097 } 098 } 099 return typeService; 100 } 101 102 protected void putMatchingAttributesIntoQualifier( Map<String, String> qualifier, Map<String, String> itemAttributes, List<String> routingAttributes ) { 103 if ( routingAttributes != null && !routingAttributes.isEmpty() ) { 104 // pull the qualifiers off the document object (group or role member) 105 for ( String attribName : routingAttributes ) { 106 qualifier.put( attribName, itemAttributes.get(attribName)); 107 } 108 } 109 } 110 111 protected String handleGroupDocument( List<Map<String, String>> qualifiers, IdentityManagementGroupDocument groupDoc, String routeLevel ) { 112 // get the appropriate type service for the group being edited 113 String typeId = groupDoc.getGroupTypeId(); 114 qualifiers.add( getGroupQualifier(groupDoc.getGroupId(), typeId, groupDoc.getQualifiersAsAttributes(), routeLevel) ); 115 String customDocTypeName = null; 116 KimTypeService typeService = getTypeService(typeId); 117 customDocTypeName = typeService.getWorkflowDocumentTypeName(); 118 return customDocTypeName; 119 } 120 121 protected String handleRoleDocument( List<Map<String, String>> qualifiers, IdentityManagementRoleDocument roleDoc, String routeLevel ) { 122 String customDocTypeName = null; 123 124// LOG.warn( "Role member data routing not implemented for the Role document yet!" ); 125 // get the appropriate type service for the group being edited 126 String typeId = roleDoc.getRoleTypeId(); 127 KimTypeService typeService = getTypeService(typeId); 128 if ( typeService != null ) { 129 // QUESTION: can roles be modified in a way which requires routing? 130 // get the existing role members 131 List<RoleMembership> currentRoleMembers = KimApiServiceLocator.getRoleService().getRoleMembers( Collections.singletonList( roleDoc.getRoleId() ), Collections.<String, String>emptyMap() ); 132 // loop over the role members on the document, check if added or removed 133 for ( KimDocumentRoleMember rm : roleDoc.getMembers() ) { 134 boolean foundMember = false; 135 for ( RoleMembership rmi : currentRoleMembers ) { 136 if ( rmi.getId().equals( rm.getRoleMemberId() ) ) { 137 foundMember = true; 138 if ( !rm.isActive() ) { // don't need to check the role member information 139 // - only active members are returned 140 // inactivated member, add a qualifier 141 qualifiers.add( getRoleQualifier(rm.getRoleId(), typeId, typeService, rm.getQualifierAsMap(), routeLevel) ); 142 } 143 break; 144 } 145 } 146 if ( !foundMember ) { 147 qualifiers.add( getRoleQualifier(rm.getRoleId(), typeId, typeService, rm.getQualifierAsMap(), routeLevel) ); 148 } 149 } 150 151 customDocTypeName = typeService.getWorkflowDocumentTypeName(); 152 } 153 return customDocTypeName; 154 } 155 156 protected String handlePersonDocument( List<Map<String, String>> qualifiers, IdentityManagementPersonDocument personDoc, String routeLevel ) { 157 // check the route level - see if we are doing groups or roles at the moment 158 String principalId = personDoc.getPrincipalId(); 159 if ( GROUP_ROUTE_LEVEL.equals(routeLevel) ) { 160 // if groups, find any groups to which the user was added or removed 161 // get the type and service for each group 162 // handle as per the group document, a qualifier for each group 163 List<String> currentGroups = getGroupService().getDirectGroupIdsByPrincipalId(principalId); 164 List<PersonDocumentGroup> groups = personDoc.getGroups(); 165 for ( PersonDocumentGroup group : groups ) { 166 // if they are being added to the group, add a qualifier set 167 if ( group.isActive() && !currentGroups.contains( group.getGroupId() ) ) { 168 // pull the group to get its attributes for adding to the qualifier 169 Group kimGroup = getGroupService().getGroup(group.getGroupId()); 170 qualifiers.add( getGroupQualifier( group.getGroupId(), kimGroup.getKimTypeId(), kimGroup.getAttributes(), routeLevel ) ); 171 } 172 } 173 // detect removed groups 174 // get the existing directly assigned groups for the person 175 for ( String groupId : currentGroups ) { 176 for ( PersonDocumentGroup group : groups ) { 177 if ( !group.isActive() ) { 178 Group kimGroup = getGroupService().getGroup(groupId); 179 qualifiers.add( getGroupQualifier( groupId, kimGroup.getKimTypeId(), kimGroup.getAttributes(), routeLevel ) ); 180 } 181 } 182 } 183 } else if ( ROLE_ROUTE_LEVEL.equals(routeLevel) ) { 184// getRoleService().get 185 for ( PersonDocumentRole pdr : personDoc.getRoles() ) { 186 KimTypeService typeService = getTypeService(pdr.getKimTypeId()); 187 for ( KimDocumentRoleMember rm : pdr.getRolePrncpls() ) { 188 boolean foundMember = false; 189 for ( RoleMembership rmi : getRoleService().getRoleMembers( Collections.singletonList( rm.getRoleId() ), Collections.<String, String>emptyMap() ) ) { 190 if ( StringUtils.equals( rmi.getId(), rm.getRoleMemberId() ) ) { 191 foundMember = true; 192 if ( !rm.isActive() ) { // don't need to check the role member information 193 // - only active members are returned 194 // inactivated member, add a qualifier 195 qualifiers.add( getRoleQualifier(rm.getRoleId(), pdr.getKimRoleType().getId(), typeService, rm.getQualifierAsMap(), routeLevel) ); 196 } 197 break; 198 } 199 } 200 if ( !foundMember ) { 201 qualifiers.add( getRoleQualifier(rm.getRoleId(), pdr.getKimRoleType().getId(), typeService, rm.getQualifierAsMap(), routeLevel) ); 202 } 203 } 204 } 205 // if roles, check the role member data for any roles added 206 // get the type and service for each role 207 // handle as for the role document, a qualifier for each role membership added 208// LOG.warn( "Role-based data routing on the person document not implemented!" ); 209 } 210 211 return null; 212 } 213 214 protected Map<String, String> getGroupQualifier( String groupId, String kimTypeId, Map<String, String> groupAttributes, String routeLevel ) { 215 Map<String, String> qualifier = new HashMap<String, String>(); 216 // pull the group to get its attributes for adding to the qualifier 217 qualifier.put(KimConstants.PrimaryKeyConstants.KIM_TYPE_ID, kimTypeId); 218 qualifier.put(KimConstants.AttributeConstants.QUALIFIER_RESOLVER_PROVIDED_IDENTIFIER, kimTypeId); 219 qualifier.put(KimConstants.PrimaryKeyConstants.GROUP_ID, groupId); 220 KimTypeService typeService = getTypeService(kimTypeId); 221 if ( typeService != null ) { 222 // check for the custom document type for the group 223 String customDocTypeName = typeService.getWorkflowDocumentTypeName(); 224 if ( StringUtils.isNotBlank(customDocTypeName)) { 225 qualifier.put(KIM_ATTRIBUTE_DOCUMENT_TYPE_NAME, customDocTypeName ); 226 } 227 putMatchingAttributesIntoQualifier(qualifier, groupAttributes, typeService.getWorkflowRoutingAttributes(routeLevel) ); 228 } 229 return qualifier; 230 } 231 232 protected Map<String, String> getRoleQualifier( String roleId, String kimTypeId, KimTypeService typeService, Map<String, String> roleAttributes, String routeLevel ) { 233 Map<String, String> qualifier = new HashMap<String, String>(); 234 // pull the group to get its attributes for adding to the qualifier 235 qualifier.put(KimConstants.PrimaryKeyConstants.KIM_TYPE_ID, kimTypeId); 236 qualifier.put(KimConstants.AttributeConstants.QUALIFIER_RESOLVER_PROVIDED_IDENTIFIER, kimTypeId); 237 qualifier.put("roleId", roleId); 238 // check for the custom document type for the group 239 String customDocTypeName = typeService.getWorkflowDocumentTypeName(); 240 if ( StringUtils.isNotBlank(customDocTypeName)) { 241 qualifier.put(KIM_ATTRIBUTE_DOCUMENT_TYPE_NAME, customDocTypeName ); 242 } 243 putMatchingAttributesIntoQualifier(qualifier, roleAttributes, typeService.getWorkflowRoutingAttributes(routeLevel) ); 244 return qualifier; 245 } 246 247 public KimTypeInfoService getKimTypeInfoService() { 248 if ( kimTypeInfoService == null ) { 249 kimTypeInfoService = KimApiServiceLocator.getKimTypeInfoService(); 250 } 251 return kimTypeInfoService; 252 } 253 254 public static GroupService getGroupService() { 255 if ( groupService == null ) { 256 groupService = KimApiServiceLocator.getGroupService(); 257 } 258 return groupService; 259 } 260 261 public static RoleService getRoleService() { 262 if ( roleService == null ) { 263 roleService = KimApiServiceLocator.getRoleService(); 264 } 265 return roleService; 266 } 267}