Coverage Report - org.kuali.rice.kim.impl.group.GroupServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
GroupServiceImpl
52%
206/390
42%
104/242
4.52
GroupServiceImpl$1
0%
0/3
0%
0/4
4.52
 
 1  
 /*
 2  
  * Copyright 2006-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.kuali.rice.kim.impl.group;
 18  
 
 19  
 import org.apache.commons.collections.CollectionUtils;
 20  
 import org.apache.commons.collections.Predicate;
 21  
 import org.apache.commons.lang.StringUtils;
 22  
 import org.apache.log4j.Logger;
 23  
 import org.kuali.rice.core.api.criteria.CriteriaLookupService;
 24  
 import org.kuali.rice.core.api.criteria.GenericQueryResults;
 25  
 import org.kuali.rice.core.api.criteria.LookupCustomizer;
 26  
 import org.kuali.rice.core.api.criteria.QueryByCriteria;
 27  
 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
 28  
 import org.kuali.rice.core.api.exception.RiceIllegalStateException;
 29  
 import org.kuali.rice.core.api.exception.RiceRuntimeException;
 30  
 import org.kuali.rice.kim.api.group.Group;
 31  
 import org.kuali.rice.kim.api.group.GroupMember;
 32  
 import org.kuali.rice.kim.api.group.GroupMemberQueryResults;
 33  
 import org.kuali.rice.kim.api.group.GroupQueryResults;
 34  
 import org.kuali.rice.kim.api.group.GroupService;
 35  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 36  
 import org.kuali.rice.kim.impl.common.attribute.AttributeTransform;
 37  
 import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo;
 38  
 import org.kuali.rice.kim.service.IdentityManagementNotificationService;
 39  
 import org.kuali.rice.kim.service.KIMServiceLocatorInternal;
 40  
 import org.kuali.rice.kim.util.KIMPropertyConstants;
 41  
 import org.kuali.rice.kim.util.KimConstants;
 42  
 import org.kuali.rice.krad.service.BusinessObjectService;
 43  
 import org.kuali.rice.ksb.api.KsbApiServiceLocator;
 44  
 
 45  
 import javax.xml.namespace.QName;
 46  
 import java.sql.Timestamp;
 47  
 import java.util.ArrayList;
 48  
 import java.util.Collection;
 49  
 import java.util.Collections;
 50  
 import java.util.HashMap;
 51  
 import java.util.HashSet;
 52  
 import java.util.List;
 53  
 import java.util.Map;
 54  
 import java.util.Set;
 55  
 
 56  
 import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
 57  
 import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
 58  
 import static org.kuali.rice.core.api.criteria.PredicateFactory.in;
 59  
 
 60  22
 public class GroupServiceImpl extends GroupServiceBase implements GroupService {
 61  1
     private static final Logger LOG = Logger.getLogger(GroupServiceImpl.class);
 62  
 
 63  
     protected BusinessObjectService businessObjectService;
 64  
     private CriteriaLookupService criteriaLookupService;
 65  
 
 66  
     @Override
 67  
     public Group getGroup(String groupId) {
 68  7
         if ( StringUtils.isEmpty(groupId) ) {
 69  0
                          throw new RiceIllegalArgumentException("groupId is blank");
 70  
                 }
 71  7
                 return GroupBo.to(getGroupBo(groupId));
 72  
     }
 73  
 
 74  
     @Override
 75  
     public List<Group> getGroupsForPrincipal(String principalId) throws RiceIllegalArgumentException {
 76  1
         if ( StringUtils.isEmpty(principalId) ) {
 77  0
                          throw new RiceIllegalArgumentException("principalId is blank");
 78  
                 }
 79  1
         return getGroupsForPrincipalByNamespace( principalId, null );
 80  
     }
 81  
 
 82  
     @Override
 83  
     public List<Group> getGroupsForPrincipalByNamespace(String principalId, String namespaceCode) throws RiceIllegalArgumentException {
 84  4
         if ( StringUtils.isEmpty(principalId) ) {
 85  0
                          throw new RiceIllegalArgumentException("principalId is blank");
 86  
                 }
 87  4
         Collection<Group> directGroups = getDirectGroupsForPrincipal( principalId, namespaceCode );
 88  4
                 Set<Group> groups = new HashSet<Group>();
 89  4
         groups.addAll(directGroups);
 90  4
                 for ( Group group : directGroups ) {
 91  4
                         groups.add( group );
 92  4
                         groups.addAll( getParentGroups( group.getId() ) );
 93  
                 }
 94  4
                 return new ArrayList<Group>( groups );
 95  
     }
 96  
 
 97  
     @Override
 98  
     public List<String> findGroupIds(final QueryByCriteria queryByCriteria) {
 99  1
         GroupQueryResults results = this.findGroups(queryByCriteria);
 100  1
         List<String> result = new ArrayList<String>();
 101  
 
 102  1
         for (Group group : results.getResults()) {
 103  3
             result.add(group.getId());
 104  
         }
 105  
 
 106  1
         return result;
 107  
     }
 108  
 
 109  
     @Override
 110  
     public boolean isDirectMemberOfGroup(String principalId, String groupId) throws RiceIllegalArgumentException {
 111  2
         if ( StringUtils.isEmpty(groupId) ) {
 112  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 113  
                 }
 114  2
         if ( StringUtils.isEmpty(principalId) ) {
 115  0
                         throw new RiceIllegalArgumentException("principalId is blank");
 116  
                 }
 117  2
                 Map<String,String> criteria = new HashMap<String,String>();
 118  2
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_ID, principalId);
 119  2
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_TYPE_CODE, KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
 120  2
                 criteria.put(KIMPropertyConstants.GroupMember.GROUP_ID, groupId);
 121  
 
 122  2
                 Collection<GroupMemberBo> groupMembers = businessObjectService.findMatching(GroupMemberBo.class, criteria);
 123  2
                 for ( GroupMemberBo gm : groupMembers ) {
 124  1
                         if ( gm.isActive(new Timestamp(System.currentTimeMillis())) ) {
 125  1
                                 return true;
 126  
                         }
 127  
                 }
 128  1
                 return false;
 129  
     }
 130  
 
 131  
     @Override
 132  
     public List<String> getGroupIdsForPrincipal(String principalId) throws RiceIllegalArgumentException {
 133  1
         if ( StringUtils.isEmpty(principalId) ) {
 134  0
                         throw new RiceIllegalArgumentException("principalId is blank");
 135  
                 }
 136  1
         return getGroupIdsForPrincipalByNamespace(principalId, null);
 137  
     }
 138  
 
 139  
     @Override
 140  
     public List<String> getGroupIdsForPrincipalByNamespace(String principalId, String namespaceCode) throws RiceIllegalArgumentException {
 141  2
         if ( StringUtils.isEmpty(principalId) ) {
 142  0
                          throw new RiceIllegalArgumentException("principalId is blank");
 143  
                 }
 144  2
         List<String> result = new ArrayList<String>();
 145  
 
 146  2
         if (principalId != null) {
 147  2
             List<Group> groupList = getGroupsForPrincipalByNamespace(principalId, namespaceCode);
 148  
 
 149  2
             for (Group group : groupList) {
 150  2
                 result.add(group.getId());
 151  
             }
 152  
         }
 153  
 
 154  2
         return result;
 155  
     }
 156  
 
 157  
     @Override
 158  
     public List<String> getDirectGroupIdsForPrincipal(String principalId) throws RiceIllegalArgumentException {
 159  1
         if ( StringUtils.isEmpty(principalId) ) {
 160  0
                         throw new RiceIllegalArgumentException("principalId is blank");
 161  
                 }
 162  1
         List<String> result = new ArrayList<String>();
 163  
 
 164  1
         if (principalId != null) {
 165  1
                 Collection<Group> groupList = getDirectGroupsForPrincipal(principalId);
 166  
 
 167  1
             for (Group g : groupList) {
 168  1
                 result.add(g.getId());
 169  
             }
 170  
         }
 171  
 
 172  1
         return result;
 173  
     }
 174  
 
 175  
     @Override
 176  
     public List<String> getMemberPrincipalIds(String groupId) throws RiceIllegalArgumentException {
 177  1
         if ( StringUtils.isEmpty(groupId) ) {
 178  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 179  
                 }
 180  1
                 Set<String> visitedGroupIds = new HashSet<String>();
 181  1
                 return getMemberPrincipalIdsInternal(groupId, visitedGroupIds);
 182  
     }
 183  
 
 184  
     @Override
 185  
     public List<String> getDirectMemberPrincipalIds(String groupId) throws RiceIllegalArgumentException {
 186  1
         if ( StringUtils.isEmpty(groupId) ) {
 187  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 188  
                 }
 189  
         //Group group = getGroup(groupId);
 190  1
         return this.getMemberIdsByType(getMembersOfGroup(groupId), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
 191  
     }
 192  
 
 193  
     @Override
 194  
     public List<String> getMemberGroupIds(String groupId) throws RiceIllegalArgumentException {
 195  
         /*if ( StringUtils.isEmpty(groupId) ) {
 196  
                         throw new RiceIllegalArgumentException("groupId is blank");
 197  
                 }
 198  
                 Set<String> visitedGroupIds = new HashSet<String>();
 199  
                 return getMemberIdsInternalByType(groupId, visitedGroupIds, KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE);
 200  
 */
 201  
 
 202  1
         if ( StringUtils.isEmpty(groupId) ) {
 203  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 204  
                 }
 205  1
                 List<GroupBo> groups = getMemberGroupBos( groupId );
 206  1
                 ArrayList<String> groupIds = new ArrayList<String>( groups.size() );
 207  1
                 for ( GroupBo group : groups ) {
 208  1
                         if ( group.isActive() ) {
 209  1
                                 groupIds.add( group.getId() );
 210  
                         }
 211  
                 }
 212  1
                 return groupIds;
 213  
     }
 214  
 
 215  
 
 216  
         protected List<GroupBo> getMemberGroupBos(String groupId) {
 217  1
                 if ( groupId == null ) {
 218  0
                         return Collections.emptyList();
 219  
                 }
 220  1
                 Set<GroupBo> groups = new HashSet<GroupBo>();
 221  
 
 222  1
                 GroupBo group = getGroupBo(groupId);
 223  1
                 getMemberGroupsInternal(group, groups);
 224  
 
 225  1
                 return new ArrayList<GroupBo>(groups);
 226  
         }
 227  
 
 228  
     protected void getMemberGroupsInternal( GroupBo group, Set<GroupBo> groups ) {
 229  2
                 if ( group == null ) {
 230  0
                         return;
 231  
                 }
 232  2
                 List<String> groupIds = group.getMemberGroupIds();
 233  
 
 234  2
                 for (String id : groupIds) {
 235  1
                         GroupBo memberGroup = getGroupBo(id);
 236  
                         // if we've already seen that group, don't recurse into it
 237  1
                         if ( memberGroup.isActive() && !groups.contains( memberGroup ) ) {
 238  1
                                 groups.add(memberGroup);
 239  1
                                 getMemberGroupsInternal(memberGroup,groups);
 240  
                         }
 241  1
                 }
 242  
 
 243  2
         }
 244  
 
 245  
     @Override
 246  
         public boolean isGroupMemberOfGroup(String groupMemberId, String groupId) {
 247  0
         if ( StringUtils.isEmpty(groupId) || StringUtils.isEmpty(groupMemberId) ) {
 248  0
                          throw new RiceIllegalArgumentException("groupMemberId or groupId is blank");
 249  
                 }
 250  
 
 251  0
         Set<String> visitedGroupIds = new HashSet<String>();
 252  0
                 return isMemberOfGroupInternal(groupMemberId, groupId, visitedGroupIds, KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE);
 253  
         }
 254  
 
 255  
     @Override
 256  
     public boolean isMemberOfGroup(String principalId, String groupId) {
 257  2
         if ( principalId == null || groupId == null ) {
 258  0
                         return false;
 259  
                 }
 260  2
                 Set<String> visitedGroupIds = new HashSet<String>();
 261  2
                 return isMemberOfGroupInternal(principalId, groupId, visitedGroupIds, KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
 262  
     }
 263  
 
 264  
     @Override
 265  
     public List<String> getDirectMemberGroupIds(String groupId) {
 266  1
         if ( groupId == null ) {
 267  0
                         return Collections.emptyList();
 268  
                 }
 269  
         //Group group = getGroup(groupId);
 270  1
         return this.getMemberIdsByType(getMembersOfGroup(groupId), KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE);
 271  
     }
 272  
 
 273  
     @Override
 274  
     public List<String> getParentGroupIds(String groupId) throws RiceIllegalArgumentException {
 275  1
         if ( StringUtils.isEmpty(groupId) ) {
 276  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 277  
                 }
 278  1
         List<String> result = new ArrayList<String>();
 279  1
         if (groupId != null) {
 280  1
             List<Group> groupList = getParentGroups(groupId);
 281  
 
 282  1
             for (Group group : groupList) {
 283  1
                 result.add(group.getId());
 284  
             }
 285  
         }
 286  
 
 287  1
         return result;
 288  
     }
 289  
 
 290  
     @Override
 291  
     public List<String> getDirectParentGroupIds(String groupId) throws RiceIllegalArgumentException {
 292  1
         if ( StringUtils.isEmpty(groupId) ) {
 293  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 294  
                 }
 295  1
         List<String> result = new ArrayList<String>();
 296  1
         if (groupId != null) {
 297  1
             List<Group> groupList = getDirectParentGroups(groupId);
 298  1
             for (Group group : groupList) {
 299  1
                 result.add(group.getId());
 300  
             }
 301  
         }
 302  
 
 303  1
         return result;
 304  
     }
 305  
 
 306  
     @Override
 307  
     public Map<String, String> getAttributes(String groupId) throws RiceIllegalArgumentException {
 308  0
         if ( StringUtils.isEmpty(groupId) ) {
 309  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 310  
                 }
 311  
 
 312  0
         if (groupId == null) {
 313  0
             return Collections.emptyMap();
 314  
         }
 315  
 
 316  0
         Group group = getGroup(groupId);
 317  0
         if (group != null) {
 318  0
             return group.getAttributes();
 319  
         }
 320  0
         return null;
 321  
     }
 322  
 
 323  
     @Override
 324  
     public List<GroupMember> getMembers(List<String> groupIds) {
 325  1
         if (CollectionUtils.isEmpty(groupIds)) {
 326  0
             throw new RiceIllegalArgumentException("groupIds is empty");
 327  
                 }
 328  
 
 329  
         //TODO: PRIME example of something for new Criteria API
 330  1
         List<GroupMember> groupMembers = new ArrayList<GroupMember>();
 331  1
         for (String groupId : groupIds) {
 332  2
               groupMembers.addAll(getMembersOfGroup(groupId));
 333  
         }
 334  1
         return groupMembers;
 335  
     }
 336  
 
 337  
     /**
 338  
      * @see org.kuali.rice.kim.api.group.GroupService#getGroups(java.util.Collection)
 339  
      */
 340  
     //@Override
 341  
     public List<Group> getGroups(Collection<String> groupIds) {
 342  12
         if (CollectionUtils.isEmpty(groupIds)) {
 343  5
             return new ArrayList<Group>();
 344  
         }
 345  7
         final QueryByCriteria.Builder builder = QueryByCriteria.Builder.create();
 346  7
         builder.setPredicates(and(in("id", groupIds.toArray()), equal("active", "Y")));
 347  7
         GroupQueryResults qr = findGroups(builder.build());
 348  
 
 349  7
         return qr.getResults();
 350  
     }
 351  
 
 352  
     //@Override
 353  
     public Group getGroupByName(String namespaceCode, String groupName) {
 354  4
         if ( namespaceCode == null || groupName == null ) {
 355  0
                         return null;
 356  
                 }
 357  4
                 Map<String,String> criteria = new HashMap<String,String>();
 358  4
                 criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode);
 359  4
                 criteria.put(KimConstants.UniqueKeyConstants.GROUP_NAME, groupName);
 360  4
                 Collection<GroupBo> groups = businessObjectService.findMatching(GroupBo.class, criteria);
 361  4
                 if ( groups.size() > 0 ) {
 362  3
                         return GroupBo.to(groups.iterator().next());
 363  
                 }
 364  1
                 return null;
 365  
     }
 366  
 
 367  
     public GroupQueryResults findGroups(final QueryByCriteria queryByCriteria) {
 368  9
         if (queryByCriteria == null) {
 369  0
             throw new RiceIllegalArgumentException("queryByCriteria is null");
 370  
         }
 371  
 
 372  9
         LookupCustomizer.Builder<GroupBo> lc = LookupCustomizer.Builder.create();
 373  9
         lc.setPredicateTransform(AttributeTransform.getInstance());
 374  
 
 375  9
         GenericQueryResults<GroupBo> results = criteriaLookupService.lookup(GroupBo.class, queryByCriteria, lc.build());
 376  
 
 377  9
         GroupQueryResults.Builder builder = GroupQueryResults.Builder.create();
 378  9
         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
 379  9
         builder.setTotalRowCount(results.getTotalRowCount());
 380  
 
 381  9
         final List<Group.Builder> ims = new ArrayList<Group.Builder>();
 382  9
         for (GroupBo bo : results.getResults()) {
 383  13
             ims.add(Group.Builder.create(bo));
 384  
         }
 385  
 
 386  9
         builder.setResults(ims);
 387  9
         return builder.build();
 388  
     }
 389  
 
 390  
     public GroupMemberQueryResults findGroupMembers(final QueryByCriteria queryByCriteria) {
 391  0
         if (queryByCriteria == null) {
 392  0
             throw new RiceIllegalArgumentException("queryByCriteria is null");
 393  
         }
 394  
 
 395  0
         GenericQueryResults<GroupMemberBo> results = criteriaLookupService.lookup(GroupMemberBo.class, queryByCriteria);
 396  
 
 397  0
         GroupMemberQueryResults.Builder builder = GroupMemberQueryResults.Builder.create();
 398  0
         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
 399  0
         builder.setTotalRowCount(results.getTotalRowCount());
 400  
 
 401  0
         final List<GroupMember.Builder> ims = new ArrayList<GroupMember.Builder>();
 402  0
         for (GroupMemberBo bo : results.getResults()) {
 403  0
             ims.add(GroupMember.Builder.create(bo));
 404  
         }
 405  
 
 406  0
         builder.setResults(ims);
 407  0
         return builder.build();
 408  
     }
 409  
 
 410  
 
 411  
     public boolean isMemberOfGroupInternal(String memberId, String groupId, Set<String> visitedGroupIds, String memberType) {
 412  3
                 if ( memberId == null || groupId == null ) {
 413  0
                         return false;
 414  
                 }
 415  
 
 416  
                 // when group traversal is not needed
 417  3
                 Group group = getGroup(groupId);
 418  3
                 if ( group == null || !group.isActive() ) {
 419  0
                         return false;
 420  
                 }
 421  
 
 422  3
         List<GroupMember> members = getMembersOfGroup(group.getId());
 423  
                 // check the immediate group
 424  3
                 for (String groupMemberId : getMemberIdsByType(members, memberType)) {
 425  3
                         if (groupMemberId.equals(memberId)) {
 426  1
                                 return true;
 427  
                         }
 428  
                 }
 429  
 
 430  
                 // check each contained group, returning as soon as a match is found
 431  2
                 for ( String memberGroupId : getMemberIdsByType(members, KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE) ) {
 432  1
                         if (!visitedGroupIds.contains(memberGroupId)){
 433  1
                                 visitedGroupIds.add(memberGroupId);
 434  1
                                 if ( isMemberOfGroupInternal( memberId, memberGroupId, visitedGroupIds, memberType ) ) {
 435  0
                                         return true;
 436  
                                 }
 437  
                         }
 438  
                 }
 439  
 
 440  
                 // no match found, return false
 441  2
                 return false;
 442  
         }
 443  
 
 444  
     protected void getParentGroupsInternal( String groupId, Set<Group> groups ) {
 445  6
                 List<Group> parentGroups = getDirectParentGroups( groupId );
 446  6
                 for ( Group group : parentGroups ) {
 447  1
                         if ( !groups.contains( group ) ) {
 448  1
                                 groups.add( group );
 449  1
                                 getParentGroupsInternal( group.getId(), groups );
 450  
                         }
 451  
                 }
 452  6
         }
 453  
 
 454  
     protected List<Group> getDirectParentGroups(String groupId) {
 455  7
                 if ( groupId == null ) {
 456  0
                         return Collections.emptyList();
 457  
                 }
 458  7
                 Map<String,String> criteria = new HashMap<String,String>();
 459  7
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_ID, groupId);
 460  7
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_TYPE_CODE, KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE);
 461  
 
 462  7
                 List<GroupMemberBo> groupMembers = (List<GroupMemberBo>)businessObjectService.findMatching(GroupMemberBo.class, criteria);
 463  7
                 Set<String> matchingGroupIds = new HashSet<String>();
 464  
                 // filter to active groups
 465  7
                 for ( GroupMemberBo gm : groupMembers ) {
 466  2
                         if ( gm.isActive(new Timestamp(System.currentTimeMillis())) ) {
 467  2
                                 matchingGroupIds.add(gm.getGroupId());
 468  
                         }
 469  
                 }
 470  7
                 return getGroups(matchingGroupIds);
 471  
         }
 472  
 
 473  
     public List<GroupMember> getMembersOfGroup(String groupId) {
 474  7
         if (groupId == null) {
 475  0
             throw new RiceIllegalArgumentException("groupId is blank");
 476  
                 }
 477  7
         Map<String,String> criteria = new HashMap<String,String>();
 478  7
                 criteria.put(KIMPropertyConstants.GroupMember.GROUP_ID, groupId);
 479  
 
 480  7
                 Collection<GroupMemberBo> groupMembersBos = businessObjectService.findMatching(GroupMemberBo.class, criteria);
 481  7
         List<GroupMember> groupMembers = new ArrayList<GroupMember>();
 482  7
         for (GroupMemberBo groupBo : groupMembersBos) {
 483  16
             if (groupBo.isActive(new Timestamp(System.currentTimeMillis()))){
 484  16
                 groupMembers.add(GroupMemberBo.to(groupBo));
 485  
             }
 486  
         }
 487  7
         return groupMembers;
 488  
     }
 489  
 
 490  
 
 491  
 
 492  
     protected List<Group> toGroupList(List<GroupBo> groupBos) {
 493  0
         if (groupBos == null) {
 494  0
             return null;
 495  
         }
 496  0
         List<Group> groups = new ArrayList<Group>();
 497  0
         for (GroupBo bo : groupBos) {
 498  0
             groups.add(GroupBo.to(bo));
 499  
         }
 500  0
         return groups;
 501  
     }
 502  
 
 503  
     /*protected List<String> getMemberIdsByType(Group group, String memberType) {
 504  
         List<String> principalIds = new ArrayList<String>();
 505  
         if (group != null) {
 506  
             for (GroupMember member : getMembersOfGroup(group.getId())) {
 507  
                 if (member.getTypeCode().equals(memberType)) {
 508  
                     principalIds.add(member.getMemberId());
 509  
                 }
 510  
             }
 511  
         }
 512  
         return principalIds;
 513  
     }*/
 514  
 
 515  
     protected List<GroupMember> getMembersByType(Collection<GroupMember> members, String memberType) {
 516  0
         List<GroupMember> membersByType = new ArrayList<GroupMember>();
 517  0
         if (members != null) {
 518  0
             for (GroupMember member : members) {
 519  0
                 if (member.getTypeCode().equals(memberType)) {
 520  0
                     membersByType.add(member);
 521  
                 }
 522  
             }
 523  
         }
 524  0
         return membersByType;
 525  
     }
 526  
 
 527  
     protected List<String> getMemberIdsByType(Collection<GroupMember> members, String memberType) {
 528  7
         List<String> membersIds = new ArrayList<String>();
 529  7
         if (members != null) {
 530  7
             for (GroupMember member : members) {
 531  13
                 if (member.getTypeCode().equals(memberType)) {
 532  7
                     membersIds.add(member.getMemberId());
 533  
                 }
 534  
             }
 535  
         }
 536  7
         return membersIds;
 537  
     }
 538  
 
 539  
     protected GroupBo getGroupBo(String groupId) {
 540  11
         if ( StringUtils.isEmpty(groupId) ) {
 541  0
                          throw new RiceIllegalArgumentException("groupId is blank");
 542  
                 }
 543  11
         return (GroupBo)businessObjectService.findBySinglePrimaryKey(GroupBo.class, groupId);
 544  
 
 545  
     }
 546  
 
 547  
 
 548  
         protected List<Group> getParentGroups(String groupId) throws RiceIllegalArgumentException {
 549  5
                 if ( StringUtils.isEmpty(groupId) ) {
 550  0
                         throw new RiceIllegalArgumentException("groupId is blank");
 551  
                 }
 552  5
                 Set<Group> groups = new HashSet<Group>();
 553  5
                 getParentGroupsInternal( groupId, groups );
 554  5
                 return new ArrayList<Group>( groups );
 555  
         }
 556  
 
 557  
     protected List<String> getMemberPrincipalIdsInternal(String groupId, Set<String> visitedGroupIds) {
 558  2
                 if ( groupId == null ) {
 559  0
                         return Collections.emptyList();
 560  
                 }
 561  2
                 Set<String> ids = new HashSet<String>();
 562  2
                 GroupBo group = getGroupBo(groupId);
 563  2
                 if ( group == null || !group.isActive()) {
 564  0
                         return Collections.emptyList();
 565  
                 }
 566  
 
 567  
         //List<String> memberIds = getMemberIdsByType(group, memberType);
 568  
         //List<GroupMember> members = new ArrayList<GroupMember>(getMembersOfGroup(group.getId()));
 569  2
                 ids.addAll( group.getMemberPrincipalIds());
 570  2
                 visitedGroupIds.add(group.getId());
 571  
 
 572  2
                 for (String memberGroupId : group.getMemberGroupIds()) {
 573  1
                         if (!visitedGroupIds.contains(memberGroupId)){
 574  1
                                 ids.addAll(getMemberPrincipalIdsInternal(memberGroupId, visitedGroupIds));
 575  
                         }
 576  
                 }
 577  
 
 578  2
                 return new ArrayList<String>(ids);
 579  
         }
 580  
 
 581  
     protected Collection<Group> getDirectGroupsForPrincipal( String principalId ) {
 582  1
                 return getDirectGroupsForPrincipal( principalId, null );
 583  
         }
 584  
 
 585  
     @SuppressWarnings("unchecked")
 586  
         protected Collection<Group> getDirectGroupsForPrincipal( String principalId, String namespaceCode ) {
 587  5
                 if ( principalId == null ) {
 588  0
                         return Collections.emptyList();
 589  
                 }
 590  5
                 Map<String,Object> criteria = new HashMap<String,Object>();
 591  5
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_ID, principalId);
 592  5
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_TYPE_CODE, KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
 593  5
                 Collection<GroupMemberBo> groupMembers = businessObjectService.findMatching(GroupMemberBo.class, criteria);
 594  5
                 Set<String> groupIds = new HashSet<String>( groupMembers.size() );
 595  
                 // only return the active members
 596  5
                 for ( GroupMemberBo gm : groupMembers ) {
 597  5
                         if ( gm.isActive(new Timestamp(System.currentTimeMillis())) ) {
 598  5
                                 groupIds.add( gm.getGroupId() );
 599  
                         }
 600  
                 }
 601  
                 // pull all the group information for the matching members
 602  5
                 List<Group> groups = getGroups(groupIds);
 603  5
                 List<Group> result = new ArrayList<Group>( groups.size() );
 604  
                 // filter by namespace if necessary
 605  5
                 for ( Group group : groups ) {
 606  5
                         if ( group.isActive() ) {
 607  5
                                 if ( StringUtils.isBlank(namespaceCode) || StringUtils.equals(namespaceCode, group.getNamespaceCode() ) ) {
 608  5
                                         result.add(group);
 609  
                                 }
 610  
                         }
 611  
                 }
 612  5
                 return result;
 613  
         }
 614  
 
 615  
             /**
 616  
      * @see org.kuali.rice.kim.api.group.GroupService#addGroupToGroup(java.lang.String, java.lang.String)
 617  
      */
 618  
     public boolean addGroupToGroup(String childId, String parentId) {
 619  0
         if(childId.equals(parentId)) {
 620  0
             throw new RiceIllegalArgumentException("Can't add group to itself.");
 621  
         }
 622  
 
 623  0
         if(isGroupMemberOfGroup(parentId, childId)) {
 624  0
             throw new RiceIllegalArgumentException("Circular group reference.");
 625  
         }
 626  
 
 627  0
         GroupMemberBo groupMember = new GroupMemberBo();
 628  0
         groupMember.setGroupId(parentId);
 629  0
         groupMember.setTypeCode(KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE);
 630  0
         groupMember.setMemberId(childId);
 631  
 
 632  0
         this.businessObjectService.save(groupMember);
 633  0
         getIdentityManagementNotificationService().groupUpdated();
 634  
 
 635  0
         return true;
 636  
     }
 637  
 
 638  
     /**
 639  
      * @see org.kuali.rice.kim.api.group.GroupService#addPrincipalToGroup(java.lang.String, java.lang.String)
 640  
      */
 641  
     public boolean addPrincipalToGroup(String principalId, String groupId) {
 642  0
         GroupMemberBo groupMember = new GroupMemberBo();
 643  0
         groupMember.setGroupId(groupId);
 644  0
         groupMember.setTypeCode(KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
 645  0
         groupMember.setMemberId(principalId);
 646  
 
 647  0
         groupMember = (GroupMemberBo)this.businessObjectService.save(groupMember);
 648  0
         KIMServiceLocatorInternal.getGroupInternalService().updateForUserAddedToGroup(groupMember.getMemberId(), groupMember.getGroupId());
 649  0
         getIdentityManagementNotificationService().groupUpdated();
 650  0
         return true;
 651  
     }
 652  
 
 653  
     public Group createGroup(Group group) {
 654  1
         if (group == null) {
 655  1
             throw new RiceIllegalArgumentException(("group is null"));
 656  
         }
 657  0
         if (StringUtils.isNotBlank(group.getId()) && getGroup(group.getId()) != null) {
 658  0
             throw new RiceIllegalStateException("the group to create already exists: " + group);
 659  
         }
 660  0
         List<GroupAttributeBo> attrBos = KimAttributeDataBo
 661  
                 .createFrom(GroupAttributeBo.class, group.getAttributes(), group.getKimTypeId());
 662  0
         if (StringUtils.isNotEmpty(group.getId())) {
 663  0
             for (GroupAttributeBo attr : attrBos) {
 664  0
                 attr.setAssignedToId(group.getId());
 665  
             }
 666  
         }
 667  0
         GroupBo bo = GroupBo.from(group);
 668  0
         bo.setAttributeDetails(attrBos);
 669  
 
 670  0
         bo = saveGroup(bo);
 671  
 
 672  0
         return GroupBo.to(bo);
 673  
     }
 674  
 
 675  
     public Group updateGroup(Group group) {
 676  0
         if (group == null) {
 677  0
             throw new RiceIllegalArgumentException(("group is null"));
 678  
         }
 679  0
         GroupBo origGroup = getGroupBo(group.getId());
 680  0
         if (StringUtils.isBlank(group.getId()) || origGroup == null) {
 681  0
             throw new RiceIllegalStateException("the group does not exist: " + group);
 682  
         }
 683  0
         List<GroupAttributeBo> attrBos = KimAttributeDataBo.createFrom(GroupAttributeBo.class, group.getAttributes(), group.getKimTypeId());
 684  0
         GroupBo bo = GroupBo.from(group);
 685  0
         bo.setMembers(origGroup.getMembers());
 686  0
         bo.setAttributeDetails(attrBos);
 687  
 
 688  0
         bo = saveGroup(bo);
 689  
 
 690  0
         return GroupBo.to(bo);
 691  
     }
 692  
 
 693  
             /**
 694  
          *
 695  
          * @see org.kuali.rice.kim.api.group.GroupService#updateGroup(java.lang.String, org.kuali.rice.kim.api.group.Group)
 696  
          */
 697  
         public Group updateGroup(String groupId, Group group) {
 698  1
         if (group == null) {
 699  1
             throw new RiceIllegalArgumentException(("group is null"));
 700  
         }
 701  0
         if (StringUtils.isEmpty(groupId)) {
 702  0
             throw new RiceIllegalArgumentException(("groupId is empty"));
 703  
         }
 704  
 
 705  0
         if (StringUtils.equals(groupId, group.getId())) {
 706  0
             return updateGroup(group);
 707  
         }
 708  
 
 709  
         //if group Ids are different, inactivate old group, and create new with new id based off old
 710  0
         GroupBo groupBo = getGroupBo(groupId);
 711  
 
 712  0
         if (StringUtils.isBlank(group.getId()) || groupBo == null) {
 713  0
             throw new RiceIllegalStateException("the group does not exist: " + group);
 714  
         }
 715  
 
 716  
         //create and save new group
 717  0
         GroupBo newGroup = GroupBo.from(group);
 718  0
         newGroup.setMembers(groupBo.getMembers());
 719  0
         List<GroupAttributeBo> attrBos = KimAttributeDataBo.createFrom(GroupAttributeBo.class, group.getAttributes(), group.getKimTypeId());
 720  0
         newGroup.setAttributeDetails(attrBos);
 721  0
         newGroup = saveGroup(newGroup);
 722  
 
 723  
         //inactivate and save old group
 724  0
         groupBo.setActive(false);
 725  0
         saveGroup(groupBo);
 726  
 
 727  0
         return GroupBo.to(newGroup);
 728  
     }
 729  
 
 730  
     /**
 731  
     *
 732  
     * @see org.kuali.rice.kim.api.group.GroupService#removeAllMembers(java.lang.String)
 733  
     */
 734  
    public void removeAllMembers(String groupId) {
 735  0
            GroupService groupService = KimApiServiceLocator.getGroupService();
 736  0
        List<String> memberPrincipalsBefore = groupService.getMemberPrincipalIds(groupId);
 737  
 
 738  0
        Collection<GroupMemberBo> toDeactivate = getActiveGroupMembers(groupId, null, null);
 739  0
        java.sql.Timestamp today = new java.sql.Timestamp(System.currentTimeMillis());
 740  
 
 741  
        // Set principals as inactive
 742  0
         for (GroupMemberBo aToDeactivate : toDeactivate) {
 743  0
             aToDeactivate.setActiveToDateValue(today);
 744  
         }
 745  
 
 746  
        // Save
 747  0
        this.businessObjectService.save(new ArrayList<GroupMemberBo>(toDeactivate));
 748  0
        List<String> memberPrincipalsAfter = groupService.getMemberPrincipalIds(groupId);
 749  
 
 750  0
        if (!CollectionUtils.isEmpty(memberPrincipalsAfter)) {
 751  
                // should never happen!
 752  0
                LOG.warn("after attempting removal of all members, group with id '" + groupId + "' still has principal members");
 753  
        }
 754  
 
 755  
        // do updates
 756  0
        KIMServiceLocatorInternal.getGroupInternalService().updateForWorkgroupChange(groupId, memberPrincipalsBefore, memberPrincipalsAfter);
 757  0
        getIdentityManagementNotificationService().groupUpdated();
 758  0
    }
 759  
 
 760  
         /**
 761  
      * @see org.kuali.rice.kim.api.group.GroupService#removeGroupFromGroup(java.lang.String, java.lang.String)
 762  
      */
 763  
     public boolean removeGroupFromGroup(String childId, String parentId) {
 764  0
             java.sql.Timestamp today = new java.sql.Timestamp(System.currentTimeMillis());
 765  
 
 766  0
             List<GroupMemberBo> groupMembers =
 767  
                     getActiveGroupMembers(parentId, childId, KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE);
 768  
 
 769  0
         if(groupMembers.size() == 1) {
 770  0
                 GroupMemberBo groupMember = groupMembers.get(0);
 771  0
                 groupMember.setActiveToDateValue(today);
 772  0
             this.businessObjectService.save(groupMember);
 773  0
             getIdentityManagementNotificationService().groupUpdated();
 774  0
             return true;
 775  
         }
 776  
 
 777  0
         return false;
 778  
     }
 779  
 
 780  
         /**
 781  
      * @see org.kuali.rice.kim.api.group.GroupService#removePrincipalFromGroup(java.lang.String, java.lang.String)
 782  
      */
 783  
     @SuppressWarnings("unchecked")
 784  
     public boolean removePrincipalFromGroup(String principalId, String groupId) {
 785  0
             List<GroupMemberBo> groupMembers =
 786  
                     getActiveGroupMembers(groupId, principalId, KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
 787  
 
 788  0
         if(groupMembers.size() == 1) {
 789  0
                 GroupMemberBo member = groupMembers.iterator().next();
 790  0
                 member.setActiveToDateValue(new java.sql.Timestamp(System.currentTimeMillis()));
 791  0
                 this.businessObjectService.save(member);
 792  0
             KIMServiceLocatorInternal.getGroupInternalService().updateForUserRemovedFromGroup(member.getMemberId(), member.getGroupId());
 793  0
             getIdentityManagementNotificationService().groupUpdated();
 794  0
             return true;
 795  
         }
 796  
 
 797  0
         return false;
 798  
     }
 799  
 
 800  
         protected GroupBo saveGroup(GroupBo group) {
 801  0
                 if ( group == null ) {
 802  0
                         return null;
 803  0
                 } else if (group.getId() != null) {
 804  
                         // Get the version of the group that is in the DB
 805  0
                         GroupBo oldGroup = getGroupBo(group.getId());
 806  
 
 807  0
                         if (oldGroup != null) {
 808  
                                 // Inactivate and re-add members no longer in the group (in order to preserve history).
 809  0
                                 java.sql.Timestamp activeTo = new java.sql.Timestamp(System.currentTimeMillis());
 810  0
                                 List<GroupMemberBo> toReAdd = null;
 811  
 
 812  0
                                 if (oldGroup.getMembers() != null) {
 813  0
                     for (GroupMemberBo member : oldGroup.getMembers()) {
 814  
                         // if the old member isn't in the new group
 815  0
                         if (group.getMembers() == null || !group.getMembers().contains(member)) {
 816  
                             // inactivate the member
 817  0
                             member.setActiveToDateValue(activeTo);
 818  0
                             if (toReAdd == null) {
 819  0
                                 toReAdd = new ArrayList<GroupMemberBo>();
 820  
                             }
 821  
                             // queue it up for re-adding
 822  0
                             toReAdd.add(member);
 823  
                         }
 824  
                     }
 825  
                                 }
 826  
 
 827  
                                 // do the re-adding
 828  0
                                 if (toReAdd != null) {
 829  0
                                         List<GroupMemberBo> groupMembers = group.getMembers();
 830  0
                                         if (groupMembers == null) {
 831  0
                         groupMembers = new ArrayList<GroupMemberBo>(toReAdd.size());
 832  
                     }
 833  0
                                         group.setMembers(groupMembers);
 834  
                                 }
 835  
                         }
 836  
                 }
 837  
 
 838  0
                 GroupBo savedGroup = KIMServiceLocatorInternal.getGroupInternalService().saveWorkgroup(group);
 839  0
                 getIdentityManagementNotificationService().groupUpdated();
 840  0
                 return savedGroup;
 841  
         }
 842  
 
 843  
 
 844  
         /**
 845  
          * This helper method gets the active group members of the specified type (see {@link org.kuali.rice.kim.util.KimConstants.KimGroupMemberTypes}).
 846  
          * If the optional params are null, it will return all active members for the specified group regardless
 847  
          * of type.
 848  
          *
 849  
          * @param parentId
 850  
          * @param childId optional, but if provided then memberType must be too
 851  
          * @param memberType optional, but must be provided if childId is
 852  
      * @return a list of group members
 853  
          */
 854  
         private List<GroupMemberBo> getActiveGroupMembers(String parentId,
 855  
                         String childId, String memberType) {
 856  0
             final java.sql.Date today = new java.sql.Date(System.currentTimeMillis());
 857  
 
 858  0
             if (childId != null && memberType == null) throw new RiceRuntimeException("memberType must be non-null if childId is non-null");
 859  
 
 860  0
                 Map<String,Object> criteria = new HashMap<String,Object>(4);
 861  0
         criteria.put(KIMPropertyConstants.GroupMember.GROUP_ID, parentId);
 862  
 
 863  0
         if (childId != null) {
 864  0
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_ID, childId);
 865  0
                 criteria.put(KIMPropertyConstants.GroupMember.MEMBER_TYPE_CODE, memberType);
 866  
         }
 867  
 
 868  0
         Collection<GroupMemberBo> groupMembers = this.businessObjectService.findMatching(GroupMemberBo.class, criteria);
 869  
 
 870  0
         CollectionUtils.filter(groupMembers, new Predicate() {
 871  
                         public boolean evaluate(Object object) {
 872  0
                                 GroupMemberBo member = (GroupMemberBo) object;
 873  
                                 // keep in the collection (return true) if the activeToDate is null, or if it is set to a future date
 874  0
                                 return member.getActiveToDate() == null || today.before(member.getActiveToDate().toDate());
 875  
                         }
 876  
                 });
 877  
 
 878  0
         return new ArrayList<GroupMemberBo>(groupMembers);
 879  
         }
 880  
 
 881  
     protected IdentityManagementNotificationService getIdentityManagementNotificationService() {
 882  0
         return (IdentityManagementNotificationService) KsbApiServiceLocator
 883  
                 .getMessageHelper().getServiceAsynchronously(new QName("KIM", "kimIdentityManagementNotificationService"));
 884  
     }
 885  
 
 886  
     /**
 887  
      * Sets the businessObjectService attribute value.
 888  
      *
 889  
      * @param businessObjectService The businessObjectService to set.
 890  
      */
 891  
     public void setBusinessObjectService(final BusinessObjectService businessObjectService) {
 892  20
         this.businessObjectService = businessObjectService;
 893  20
     }
 894  
 
 895  
     /**
 896  
      * Sets the criteriaLookupService attribute value.
 897  
      *
 898  
      * @param criteriaLookupService The criteriaLookupService to set.
 899  
      */
 900  
     public void setCriteriaLookupService(final CriteriaLookupService criteriaLookupService) {
 901  11
         this.criteriaLookupService = criteriaLookupService;
 902  11
     }
 903  
 }