All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.internet2.middleware.grouper.group.GroupSet Maven / Gradle / Ivy

There is a newer version: 5.12.2
Show newest version
/**
 * Copyright 2014 Internet2
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.internet2.middleware.grouper.group;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import edu.internet2.middleware.grouper.FieldFinder;
import edu.internet2.middleware.grouper.Group;
import edu.internet2.middleware.grouper.GroupFinder;
import edu.internet2.middleware.grouper.GrouperAPI;
import edu.internet2.middleware.grouper.GrouperSession;
import edu.internet2.middleware.grouper.cfg.GrouperConfig;
import edu.internet2.middleware.grouper.changeLog.ChangeLogEntry;
import edu.internet2.middleware.grouper.changeLog.ChangeLogLabels;
import edu.internet2.middleware.grouper.changeLog.ChangeLogTypeBuiltin;
import edu.internet2.middleware.grouper.exception.GroupSetNotFoundException;
import edu.internet2.middleware.grouper.exception.GrouperSessionException;
import edu.internet2.middleware.grouper.hibernate.AuditControl;
import edu.internet2.middleware.grouper.hibernate.GrouperTransactionType;
import edu.internet2.middleware.grouper.hibernate.HibernateHandler;
import edu.internet2.middleware.grouper.hibernate.HibernateHandlerBean;
import edu.internet2.middleware.grouper.hibernate.HibernateSession;
import edu.internet2.middleware.grouper.internal.dao.GroupDAO;
import edu.internet2.middleware.grouper.internal.dao.GrouperDAOException;
import edu.internet2.middleware.grouper.internal.dao.StemDAO;
import edu.internet2.middleware.grouper.internal.dao.hib3.Hib3GrouperVersioned;
import edu.internet2.middleware.grouper.internal.util.GrouperUuid;
import edu.internet2.middleware.grouper.membership.MembershipType;
import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
import edu.internet2.middleware.grouper.misc.GrouperHasContext;
import edu.internet2.middleware.grouper.misc.GrouperSessionHandler;
import edu.internet2.middleware.grouper.pit.PITGroupSet;
import edu.internet2.middleware.grouper.util.GrouperUtil;

/**
 * @author shilen $Id: GroupSet.java,v 1.12 2009-12-07 07:31:09 mchyzer Exp $
 *
 */
@SuppressWarnings("serial")
public class GroupSet extends GrouperAPI implements GrouperHasContext, Hib3GrouperVersioned {
  
  /**
   * @see Object#toString()
   */
  @Override
  public String toString() {
    final StringBuilder result = new StringBuilder();
    
    result.append("id: ").append(this.id);
    result.append(", type: ").append(this.type);
    result.append(", depth: ").append(this.depth);
    result.append(", parent: ").append(this.parentId);
    result.append(", field: ").append(FieldFinder.findById(this.fieldId, true).getName());
    result.append(", memberField: ").append(FieldFinder.findById(this.memberFieldId, true).getName());
    result.append(", parent: ").append(this.parentId);
    
    GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() {
 
      /**
       * 
       */
      @Override
      public Object callback(GrouperSession grouperSession) throws GrouperSessionException {
        if (!StringUtils.isBlank(GroupSet.this.ownerGroupId)) {
          Group ownerGroup = GroupFinder.findByUuid(grouperSession, GroupSet.this.ownerGroupId, true);
          result.append(", ownerGroup: ").append(ownerGroup.getName());
          Group memberGroup = GroupFinder.findByUuid(grouperSession, GroupSet.this.memberGroupId, true);
          result.append(", memberGroup: ").append(memberGroup.getName());
        }
        return null;
      }
    });
    
    return result.toString();
  }
  
  /** db id for this row */
  public static final String COLUMN_ID = "id";
  
  /** Context id links together multiple operations into one high level action */
  public static final String COLUMN_CONTEXT_ID = "context_id";

  /** field represented by this group set */
  public static final String COLUMN_FIELD_ID = "field_id";
  
  /** type of membership represented by this group set, immediate or composite or effective */
  public static final String COLUMN_MSHIP_TYPE = "mship_type";
  
  /** same as member_group_id if depth is greater than 0, otherwise null. */
  public static final String COLUMN_VIA_GROUP_ID = "via_group_id";
  
  /** number of hops in directed graph */
  public static final String COLUMN_DEPTH = "depth";
  
  /** parent group set */
  public static final String COLUMN_PARENT_ID = "parent_id";
  
  /** member uuid of the creator of this record */
  public static final String COLUMN_CREATOR_ID = "creator_id";
  
  /** number of millis since 1970 that this record was created */
  public static final String COLUMN_CREATE_TIME = "create_time";

  /** owner id */
  public static final String COLUMN_OWNER_ID = "owner_id";
  
  /** owner group if applicable */
  public static final String COLUMN_OWNER_GROUP_ID = "owner_group_id";
  
  /** same as owner_group_id except nulls are replaced with the string '' */
  public static final String COLUMN_OWNER_GROUP_ID_NULL = "owner_group_id_null";
  
  /** owner attribute def if applicable */
  public static final String COLUMN_OWNER_ATTR_DEF_ID = "owner_attr_def_id";
  
  /** same as owner_attr_def_id except nulls are replaced with the string '' */
  public static final String COLUMN_OWNER_ATTR_DEF_ID_NULL = "owner_attr_def_id_null";
  
  /** owner stem if applicable */
  public static final String COLUMN_OWNER_STEM_ID = "owner_stem_id";
  
  /** same as owner_stem_id except nulls are replaced with the string '' */
  public static final String COLUMN_OWNER_STEM_ID_NULL = "owner_stem_id_null";
  
  /** member group if applicable */
  public static final String COLUMN_MEMBER_GROUP_ID = "member_group_id";
  
  /** member attr def if applicable */
  public static final String COLUMN_MEMBER_ATTR_DEF_ID = "member_attr_def_id";
  
  /** member stem if applicable */
  public static final String COLUMN_MEMBER_STEM_ID = "member_stem_id";
  
  /** member id */
  public static final String COLUMN_MEMBER_ID = "member_id";
  
  /** field id used in joining this record with entries in grouper_memberships */
  public static final String COLUMN_MEMBER_FIELD_ID = "member_field_id";
  
  
  //*****  START GENERATED WITH GenerateFieldConstants.java *****//

  /** constant for field name for: contextId */
  public static final String FIELD_CONTEXT_ID = "contextId";

  /** constant for field name for: createTime */
  public static final String FIELD_CREATE_TIME = "createTime";

  /** constant for field name for: creatorId */
  public static final String FIELD_CREATOR_ID = "creatorId";

  /** constant for field name for: depth */
  public static final String FIELD_DEPTH = "depth";
  
  /** constant for field name for: viaGroupId */
  public static final String FIELD_VIA_GROUP_ID = "viaGroupId";

  /** constant for field name for: fieldId */
  public static final String FIELD_FIELD_ID = "fieldId";

  /** constant for field name for: type */
  public static final String FIELD_MSHIP_TYPE = "type";
  
  /** constant for field name for: id */
  public static final String FIELD_ID = "id";

  /** constant for field name for: memberGroupId */
  public static final String FIELD_MEMBER_GROUP_ID = "memberGroupId";

  /** constant for field name for: memberStemId */
  public static final String FIELD_MEMBER_STEM_ID = "memberStemId";

  /** constant for field name for: ownerId */
  public static final String FIELD_OWNER_ID = "ownerId";
  
  /** constant for field name for: ownerGroupId */
  public static final String FIELD_OWNER_GROUP_ID = "ownerGroupId";

  /** constant for field name for: ownerGroupIdNull */
  public static final String FIELD_OWNER_GROUP_ID_NULL = "ownerGroupIdNull";

  /** constant for field name for: ownerStemId */
  public static final String FIELD_OWNER_STEM_ID = "ownerStemId";

  /** constant for field name for: ownerStemIdNull */
  public static final String FIELD_OWNER_STEM_ID_NULL = "ownerStemIdNull";

  /** constant for field name for: parentId */
  public static final String FIELD_PARENT_ID = "parentId";
  
  /** constant for field name for: memberFieldId */
  public static final String FIELD_MEMBER_FIELD_ID = "memberFieldId";

  /**
   * fields which are included in db version
   */
  /*
  private static final Set DB_VERSION_FIELDS = GrouperUtil.toSet(
      FIELD_CONTEXT_ID, FIELD_CREATE_TIME, FIELD_CREATOR_ID, FIELD_DEPTH, FIELD_VIA_GROUP_ID, 
      FIELD_FIELD_ID, FIELD_MSHIP_TYPE, FIELD_ID, FIELD_MEMBER_GROUP_ID, FIELD_MEMBER_GROUP_ID_NULL, 
      FIELD_MEMBER_STEM_ID, FIELD_MEMBER_STEM_ID_NULL, FIELD_OWNER_GROUP_ID, FIELD_OWNER_GROUP_ID_NULL, 
      FIELD_OWNER_STEM_ID, FIELD_OWNER_STEM_ID_NULL, FIELD_PARENT_ID);
  */

  /**
   * fields which are included in clone method
   */
  private static final Set CLONE_FIELDS = GrouperUtil.toSet(
      FIELD_CONTEXT_ID, FIELD_CREATE_TIME, FIELD_CREATOR_ID, FIELD_DEPTH, FIELD_VIA_GROUP_ID,
      FIELD_FIELD_ID, FIELD_MSHIP_TYPE, FIELD_HIBERNATE_VERSION_NUMBER, FIELD_ID, FIELD_MEMBER_GROUP_ID, 
      FIELD_MEMBER_STEM_ID, FIELD_OWNER_GROUP_ID, FIELD_MEMBER_FIELD_ID, FIELD_OWNER_ID,
      FIELD_OWNER_GROUP_ID_NULL, FIELD_OWNER_STEM_ID, FIELD_OWNER_STEM_ID_NULL, FIELD_PARENT_ID);

  //*****  END GENERATED WITH GenerateFieldConstants.java *****//


  /**
   * name of the group set table in the database.
   */
  public static final String TABLE_GROUPER_GROUP_SET = "grouper_group_set";

  /** id of this type */
  private String id;
  
  /** context id ties multiple db changes */
  private String contextId;
  
  /** field associated with this record */
  private String fieldId;
  
  /** membership type -- immediate, effective, or composite */
  private String type = MembershipType.IMMEDIATE.getTypeString();

  /** depth - 0 for self records, 1 for immediate memberships, > 1 for effective */
  private int depth;
  
  /** parent record */
  private String parentId;
  
  /** creator */
  private String creatorId;
  
  /** create time */
  private Long createTime = new Date().getTime();
  
  /** owner id */
  private String ownerId;
  
  /** group id for group memberships.  this is the owner. */
  private String ownerGroupId;
  
  /** ownerGroupId except nulls are replaced with a string so we can use this in a unique constraint */
  private String ownerGroupIdNull = GroupSet.nullColumnValue;

  /** stem id for stem memberships.  this is the owner. */
  private String ownerStemId;
  
  /** ownerStemId except nulls are replaced with a string so we can use this in a unique constraint */
  private String ownerStemIdNull = GroupSet.nullColumnValue;
  
  /** group id for group memberships.  this is the member. */
  private String memberGroupId;

  /** stem id for stem memberships.  this is the member. */
  private String memberStemId;
  
  /** member field id */
  private String memberFieldId;

  /**
   * the value we're storing in the db for nulls that need a value so that we can add a unique constraint.
   */
  public static final String nullColumnValue = "";

  /**
   * 
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    }
    
    if (!(other instanceof GroupSet)) {
      return false;
    }
    
    GroupSet that = (GroupSet) other;
    return new EqualsBuilder()
      .append(this.fieldId, that.fieldId)
      .append(this.type, that.type)
      .append(this.depth, that.depth)
      .append(this.parentId, that.parentId)
      .append(this.ownerAttrDefId, that.ownerAttrDefId)
      .append(this.ownerGroupId, that.ownerGroupId)
      .append(this.ownerStemId, that.ownerStemId)
      .append(this.memberAttrDefId, that.memberAttrDefId)
      .append(this.memberGroupId, that.memberGroupId)
      .append(this.memberStemId, that.memberStemId)
      .isEquals();
  } 

  /**
   * 
   * @see java.lang.Object#hashCode()
   */
  public int hashCode() {
    return new HashCodeBuilder()
      .append(this.fieldId)
      .append(this.type)
      .append(this.depth)
      .append(this.parentId)
      .append(this.ownerAttrDefId)
      .append(this.ownerGroupId)
      .append(this.ownerStemId)
      .append(this.memberAttrDefId)
      .append(this.memberGroupId)
      .append(this.memberStemId)
      .toHashCode();
  }
  
  /**
   * 
   * @see edu.internet2.middleware.grouper.GrouperAPI#clone()
   */
  @Override
  public GrouperAPI clone() {
    return GrouperUtil.clone(this, CLONE_FIELDS);
  }

  /** attr def id for attr def memberships.  this is the member. */
  private String memberAttrDefId;

  /** attr def id for attr def memberships.  this is the owner. */
  private String ownerAttrDefId;

  /** ownerAttrDefId except nulls are replaced with a string so we can use this in a unique constraint */
  private String ownerAttrDefIdNull = GroupSet.nullColumnValue;

  /**
   * 
   * @see edu.internet2.middleware.grouper.GrouperAPI#onPreSave(edu.internet2.middleware.grouper.hibernate.HibernateSession)
   */
  @Override
  public void onPreSave(HibernateSession hibernateSession) {
    super.onPreSave(hibernateSession);

    if (this.createTime == null) {
      this.createTime = System.currentTimeMillis();
    }
    
    if (this.creatorId == null) {
      this.creatorId = GrouperSession.staticGrouperSession().getMember().getUuid();
    }
    
    if (this.depth == 0) {
      this.memberFieldId = new String(this.fieldId);
    } else {
      this.memberFieldId = Group.getDefaultList().getUuid();
    }
    
    //change log into temp table
    new ChangeLogEntry(true, ChangeLogTypeBuiltin.GROUP_SET_ADD, 
        ChangeLogLabels.GROUP_SET_ADD.id.name(), this.getId(), 
        ChangeLogLabels.GROUP_SET_ADD.ownerGroupId.name(), this.getOwnerGroupId(), 
        ChangeLogLabels.GROUP_SET_ADD.ownerStemId.name(), this.getOwnerStemId(), 
        ChangeLogLabels.GROUP_SET_ADD.ownerAttributeDefId.name(), this.getOwnerAttrDefId(), 
        ChangeLogLabels.GROUP_SET_ADD.memberGroupId.name(), this.getMemberGroupId(), 
        ChangeLogLabels.GROUP_SET_ADD.memberStemId.name(), this.getMemberStemId(), 
        ChangeLogLabels.GROUP_SET_ADD.memberAttributeDefId.name(), this.getMemberAttrDefId(), 
        ChangeLogLabels.GROUP_SET_ADD.fieldId.name(), this.getFieldId(), 
        ChangeLogLabels.GROUP_SET_ADD.memberFieldId.name(), this.getMemberFieldId(), 
        ChangeLogLabels.GROUP_SET_ADD.parentGroupSetId.name(), this.getParentId(), 
        ChangeLogLabels.GROUP_SET_ADD.depth.name(), "" + this.getDepth()).save();
  }
  
  /**
   * 
   * @see edu.internet2.middleware.grouper.GrouperAPI#onPostSave(edu.internet2.middleware.grouper.hibernate.HibernateSession)
   */
  @Override
  public void onPostSave(HibernateSession hibernateSession) {
    
    // take care of effective group sets
    if (this.getDepth() == 1 && this.getMemberGroupId() != null) {
      Set results = new LinkedHashSet();
      Set groupSetHasMembers = GrouperDAOFactory.getFactory().getGroupSet().findAllByGroupOwnerAndField(
          this.getMemberGroupId(), Group.getDefaultList());
      
      // Add members of member to owner group set
      results.addAll(addHasMembersToOwner(this, groupSetHasMembers));
  
      // If we are working on a group, where is it a member and field is the default list
      if (this.getOwnerGroupId() != null && this.getFieldId().equals(Group.getDefaultList().getUuid())) {
        Set groupSetIsMember = GrouperDAOFactory.getFactory().getGroupSet().findAllByMemberGroup(this.getOwnerGroupId());
  
        // Add member and members of member to where owner is member
        results.addAll(addHasMembersToWhereGroupIsMember(this.getMemberGroupId(), groupSetIsMember, groupSetHasMembers));
      }
      
      GrouperDAOFactory.getFactory().getGroupSet().save(results);
      
      // update last membership change time
      this.updateLastMembershipChange(this, results);
    }
    
    super.onPostSave(hibernateSession);
  }

  
  /**
   * @see edu.internet2.middleware.grouper.GrouperAPI#onPreDelete(edu.internet2.middleware.grouper.hibernate.HibernateSession)
   */
  @Override
  public void onPreDelete(HibernateSession hibernateSession) {
    super.onPreDelete(hibernateSession);

    // take care of effective group sets
    if (this.getDepth() == 1) {
      Set groupSetsToDelete = new LinkedHashSet();
      
      // Get all children of this group set
      Set childResults = GrouperDAOFactory.getFactory().getGroupSet().findAllChildren(this);
  
      groupSetsToDelete.addAll(childResults);
  
      // Find all effective group sets that need deletion
      if (this.getOwnerGroupId() != null && this.getFieldId().equals(Group.getDefaultList().getUuid())) {
        Set groupSetIsMember = GrouperDAOFactory.getFactory().getGroupSet().findAllByMemberGroup(this.getOwnerGroupId());
        
        Iterator groupSetIsMemberIter = groupSetIsMember.iterator();
        while (groupSetIsMemberIter.hasNext()) {
          GroupSet currGroupSet = groupSetIsMemberIter.next();
          GroupSet childToDelete = GrouperDAOFactory.getFactory().getGroupSet().findImmediateChildByParentAndMemberGroup(currGroupSet, this.getMemberGroupId());
  
          if (childToDelete != null) {
            Set childrenOfChildResults = GrouperDAOFactory.getFactory().getGroupSet().findAllChildren(childToDelete);
    
            groupSetsToDelete.addAll(childrenOfChildResults);
            groupSetsToDelete.add(childToDelete);
          }
        }
      }
      
      GrouperDAOFactory.getFactory().getGroupSet().delete(groupSetsToDelete);
      
      // update last membership change time
      this.updateLastMembershipChange(this, groupSetsToDelete);
    }
    
    //change log into temp table
    new ChangeLogEntry(true, ChangeLogTypeBuiltin.GROUP_SET_DELETE, 
        ChangeLogLabels.GROUP_SET_DELETE.id.name(), this.getId(), 
        ChangeLogLabels.GROUP_SET_DELETE.ownerGroupId.name(), this.getOwnerGroupId(), 
        ChangeLogLabels.GROUP_SET_DELETE.ownerStemId.name(), this.getOwnerStemId(), 
        ChangeLogLabels.GROUP_SET_DELETE.ownerAttributeDefId.name(), this.getOwnerAttrDefId(), 
        ChangeLogLabels.GROUP_SET_DELETE.memberGroupId.name(), this.getMemberGroupId(), 
        ChangeLogLabels.GROUP_SET_DELETE.memberStemId.name(), this.getMemberStemId(), 
        ChangeLogLabels.GROUP_SET_DELETE.memberAttributeDefId.name(), this.getMemberAttrDefId(), 
        ChangeLogLabels.GROUP_SET_DELETE.fieldId.name(), this.getFieldId(), 
        ChangeLogLabels.GROUP_SET_DELETE.memberFieldId.name(), this.getMemberFieldId(), 
        ChangeLogLabels.GROUP_SET_DELETE.parentGroupSetId.name(), this.getParentId(), 
        ChangeLogLabels.GROUP_SET_DELETE.depth.name(), "" + this.getDepth()).save();
  }
  
  /**
   * If enabled, update last_membership_change for groups and stems
   * @param immediateGroupSet
   * @param effectiveGroupSets
   */
  private void updateLastMembershipChange(GroupSet immediateGroupSet, Set effectiveGroupSets) {
    Set groupIds = new LinkedHashSet();
    Set stemIds = new LinkedHashSet();
    Set attrDefIds = new LinkedHashSet();
    
    if (immediateGroupSet.getOwnerGroupId() != null) {
      groupIds.add(immediateGroupSet.getOwnerGroupId());
    } else if (immediateGroupSet.getOwnerStemId() != null) {
      stemIds.add(immediateGroupSet.getOwnerStemId());
    } else if (immediateGroupSet.getOwnerAttrDefId() != null) {
      attrDefIds.add(immediateGroupSet.getOwnerAttrDefId());
    } else {
      throw new RuntimeException("Cant find owner! " + immediateGroupSet);
    }
    
    Iterator iter = effectiveGroupSets.iterator();
    while (iter.hasNext()) {
      GroupSet effectiveGroupSet = iter.next();
      if (effectiveGroupSet.getOwnerGroupId() != null) {
        groupIds.add(effectiveGroupSet.getOwnerGroupId());
      } else if (effectiveGroupSet.getOwnerStemId() != null) {
        stemIds.add(effectiveGroupSet.getOwnerStemId());
      } else if (effectiveGroupSet.getOwnerAttrDefId() != null) {
        attrDefIds.add(effectiveGroupSet.getOwnerAttrDefId());
      } else {
        throw new RuntimeException("Cant find owner! " + effectiveGroupSet);
      }
    }
    
    if (GrouperConfig.retrieveConfig().propertyValueBoolean("stems.updateLastMembershipTime", false)) {
      StemDAO dao = GrouperDAOFactory.getFactory().getStem();
      Iterator stemIdsIter = stemIds.iterator();
      while (stemIdsIter.hasNext()) {
        dao.updateLastMembershipChange(stemIdsIter.next());
      }
    }
    
    if (GrouperConfig.retrieveConfig().propertyValueBoolean("groups.updateLastMembershipTime", false)) {
      GroupDAO dao = GrouperDAOFactory.getFactory().getGroup();
      Iterator groupIdsIter = groupIds.iterator();
      while (groupIdsIter.hasNext()) {
        dao.updateLastMembershipChange(groupIdsIter.next());
      }
    }
  }

  /**
   * @param memberGroupId
   * @param groupSetIsMember
   * @param groupSetHasMembers
   * @return group set
   * @throws IllegalStateException
   */
  private Set addHasMembersToWhereGroupIsMember(String memberGroupId,
      Set groupSetIsMember, Set groupSetHasMembers)
      throws IllegalStateException {
    Set groupSets = new LinkedHashSet();

    Iterator isMembersIter = groupSetIsMember.iterator();
    Map> parentToChildrenMap = getParentToChildrenMap(groupSetHasMembers);

    // lets get all the hasMembers with a depth of 1 before the while loop
    Set hasMembersOneDepth = new LinkedHashSet();
    Iterator hasMembersIter = groupSetHasMembers.iterator();
    while (hasMembersIter.hasNext()) {
      GroupSet gs = hasMembersIter.next();
      if (gs.getDepth() == 1) {
        hasMembersOneDepth.add(gs);
      }
    }

    while (isMembersIter.hasNext()) {
      GroupSet isGS = isMembersIter.next();

      String ownerGroupId = isGS.getOwnerGroupId();
      String ownerStemId = isGS.getOwnerStemId();
      String ownerAttrDefId = isGS.getOwnerAttrDefId();
      String fieldId = isGS.getFieldId();
      String id = isGS.getId();
      int depth = isGS.getDepth();

      // If the isMember's owner is the same as the immediate member's owner and this is for a default member, 
      // then we can skip this isMember.
      if (fieldId.equals(Group.getDefaultList().getUuid())
          && StringUtils.equals(isGS.getOwnerGroupId(), this.getOwnerGroupId())) {
        continue;
      }

      GroupSet groupSet = new GroupSet();
      groupSet.setId(GrouperUuid.getUuid());
      groupSet.setCreatorId(this.getCreatorId());
      groupSet.setCreateTime(this.getCreateTime());
      groupSet.setDepth(depth + 1);
      groupSet.setParentId(id);
      groupSet.setFieldId(fieldId);
      groupSet.setMemberGroupId(memberGroupId);
      groupSet.setOwnerGroupId(ownerGroupId);
      groupSet.setOwnerAttrDefId(ownerAttrDefId);
      groupSet.setOwnerStemId(ownerStemId);
      groupSet.setType(MembershipType.EFFECTIVE.getTypeString());

      // if we're forming a circular path, skip this isMember
      if (internal_isCircular(groupSet, isGS)) {
        continue;
      }

      groupSets.add(groupSet);

      Iterator itHM = hasMembersOneDepth.iterator();
      while (itHM.hasNext()) {
        GroupSet hasGS = itHM.next();
        Set newAdditions = addHasMembersRecursively(isGS, hasGS, groupSet,
            parentToChildrenMap, ownerAttrDefId, ownerGroupId, ownerStemId, this.getCreatorId(), fieldId);
        groupSets.addAll(newAdditions);
      }
    }

    return groupSets;
  } 

  
  /**
   * @param immediateGroupSet
   * @param hasMembers
   * @return set
   * @throws IllegalStateException
   */
  private Set addHasMembersToOwner(GroupSet immediateGroupSet, Set hasMembers) 
    throws  IllegalStateException
  {
    Set groupSets = new LinkedHashSet();
    Iterator it = hasMembers.iterator();

    // cache values outside of iterator
    String ownerAttrDefId = immediateGroupSet.getOwnerAttrDefId();
    String ownerGroupId = immediateGroupSet.getOwnerGroupId();
    String ownerStemId = immediateGroupSet.getOwnerStemId();
    String fieldId = immediateGroupSet.getFieldId();

    Map> parentToChildrenMap = getParentToChildrenMap(hasMembers);
   
    while (it.hasNext()) {
      GroupSet gs = it.next();
      if (gs.getDepth() == 1) {
        Set newAdditions = addHasMembersRecursively(immediateGroupSet, gs, 
            immediateGroupSet, parentToChildrenMap, ownerAttrDefId, ownerGroupId, ownerStemId, this.getCreatorId(), fieldId);
        groupSets.addAll(newAdditions);
      }
    }

    return groupSets;
  }
  
  /**
   * Given a set of group sets, return a map that will allow retrieval of 
   * the children of a parent group set.
   * @param members
   * @return the map
   */
  private Map> getParentToChildrenMap(Set members) {
    Map> parentToChildrenMap = new HashMap>();

    Iterator iterator = members.iterator();
    while (iterator.hasNext()) {
      GroupSet gs = iterator.next();
      String parentId = gs.getParentId();

      if (parentId != null && !parentId.equals("")) {
        Set children = parentToChildrenMap.get(parentId);
        if (children == null) {
          children = new LinkedHashSet();
        }

        children.add(gs);
        parentToChildrenMap.put(parentId, children);
      }
    }

    return parentToChildrenMap;
  }
  
  /**
   * @param startGroupSet
   * @param gs
   * @param parentGroupSet
   * @param parentToChildrenMap
   * @param ownerGroupId1
   * @param ownerStemId1
   * @param ownerAttrDefId1 
   * @param creatorUUID
   * @param fieldId1
   * @return set of group sets
   */
  private Set addHasMembersRecursively(GroupSet startGroupSet, 
      GroupSet gs, GroupSet parentGroupSet, Map> parentToChildrenMap, 
      String ownerAttrDefId1,
      String ownerGroupId1, String ownerStemId1, String creatorUUID, String fieldId1) {

      GroupSet newGroupSet = new GroupSet();
      newGroupSet.setId(GrouperUuid.getUuid());
      newGroupSet.setCreatorId(creatorUUID);
      newGroupSet.setCreateTime(this.getCreateTime());
      newGroupSet.setFieldId(fieldId1);
      newGroupSet.setOwnerAttrDefId(ownerAttrDefId1);
      newGroupSet.setOwnerGroupId(ownerGroupId1);
      newGroupSet.setOwnerStemId(ownerStemId1);
      newGroupSet.setMemberGroupId(gs.getMemberGroupId());
      newGroupSet.setDepth(parentGroupSet.getDepth() + 1);
      newGroupSet.setParentId(parentGroupSet.getId());
      newGroupSet.setType(MembershipType.EFFECTIVE.getTypeString());

      // if we're forming a circular path, return an empty Set.
      if (internal_isCircular(newGroupSet, startGroupSet)) {
        return new LinkedHashSet();
      }

      Set newGroupSets = new LinkedHashSet();
      newGroupSets.add(newGroupSet);

      Set children = parentToChildrenMap.get(gs.getId());
      if (children != null) {
        Iterator it = children.iterator();
        while (it.hasNext()) {
          GroupSet nextGroupSet = it.next();
          Set newAdditions = addHasMembersRecursively(startGroupSet, nextGroupSet, newGroupSet, 
            parentToChildrenMap, ownerAttrDefId1, ownerGroupId1, ownerStemId1, creatorUUID, fieldId1);
          newGroupSets.addAll(newAdditions);
        }
      }
      
      return newGroupSets;
    }
  
  /**
   * Check if the new group set being added will cause a circular group set.
   *
   * @param newGroupSet group set being added
   * @param startGroupSet group set that's a parent of newGroupSet which will be used
   *                        as a starting point to check if we're forming a circular group set
   * @return true if the new group set will cause a circular group set.
   */
  public boolean internal_isCircular(GroupSet newGroupSet, GroupSet startGroupSet) {

    // for the default list, a group should not be an indirect member of itself ....
    if (newGroupSet.getFieldId().equals(Group.getDefaultList().getUuid()) && 
        newGroupSet.getMemberGroupId().equals(newGroupSet.getOwnerGroupId())) {
      return true;
    }

    // now let's go through the parents... 
    // if the member of a parent is equal to the member of the new group set,
    // then we have a circular group set.
    if (newGroupSet.getDepth() < 3) {
      return false;
    }

    GroupSet currentGroupSet = startGroupSet;
    while (true) {
      if (currentGroupSet.getMemberGroupId().equals(newGroupSet.getMemberGroupId())) {
        return true;
      }
      if (currentGroupSet.getDepth() > 1) {
        currentGroupSet = currentGroupSet.getParentGroupSet();
      } else {
        break;
      }
    }

    return false;
  }

  
  /**
   * @return the parent group set
   */
  public GroupSet getParentGroupSet() {
    if (depth == 0) {
      throw new GroupSetNotFoundException("no parent");
    }
    
    GroupSet parent = GrouperDAOFactory.getFactory().getGroupSet().findParentGroupSet(this) ;
    return parent;
  }
  
  
  /**
   * @return id
   */
  public String getId() {
    return id;
  }

  
  /**
   * set id
   * @param id
   */
  public void setId(String id) {
    this.id = id;
  }

  /**
   * @return context id
   */
  public String getContextId() {
    return contextId;
  }

  
  /**
   * set context id
   * @param contextId
   */
  public void setContextId(String contextId) {
    this.contextId = contextId;
  }

  /**
   * @return field id
   */
  public String getFieldId() {
    return fieldId;
  }

  /**
   * @param fieldId
   */
  public void setFieldId(String fieldId) {
    this.fieldId = fieldId;
  }
  
  /**
   * @return field id used in joining with grouper_memberships table
   */
  public String getMemberFieldId() {    
    return memberFieldId;
  }

  /**
   * Internal use only.
   * @param memberFieldId
   */
  public void setMemberFieldId(String memberFieldId) {
    this.memberFieldId = memberFieldId;
  }

  
  /**
   * This is 0 for self memberships (where the owner and member are the same).
   * Otherwise, it's the number of hops in a directed graph from the member to the group.
   * @return depth
   */
  public int getDepth() {
    return depth;
  }

  
  /**
   * set depth
   * @param depth
   */
  public void setDepth(int depth) {
    this.depth = depth;
  }

  /**
   * @return via group id
   */
  public String getViaGroupId() {
    if (depth == 0) {
      return null;
    }
    
    return memberGroupId;
  }

  
  /**
   * Set via group id.  This is for internal use only.
   * @param viaGroupId
   */
  public void setViaGroupId(@SuppressWarnings("unused") String viaGroupId) {
    // not used
  }
  
  /**
   * @return parent id
   */
  public String getParentId() {
    return parentId;
  }

  
  /**
   * set parent id
   * @param parentId
   */
  public void setParentId(String parentId) {
    this.parentId = parentId;
  }

  
  /**
   * @return creator
   */
  public String getCreatorId() {
    return creatorId;
  }

  
  /**
   * set creator
   * @param creatorId
   */
  public void setCreatorId(String creatorId) {
    this.creatorId = creatorId;
  }


  /**
   * @return create time
   */
  public Long getCreateTime() {
    return createTime;
  }

  
  /**
   * set create time
   * @param createTime
   */
  public void setCreateTime(Long createTime) {
    this.createTime = createTime;
  }

  /**
   * @return owner id
   */
  public String getOwnerId() {
    return ownerId;
  }
  
  /**
   * Set owner id.  This is for internal use only.
   * @param ownerId
   */
  public void setOwnerId(String ownerId) {
    this.ownerId = ownerId;
  }
  
  /**
   * @return group id for the owner if this is a group membership
   */
  public String getOwnerGroupId() {
    return ownerGroupId;
  }

  /**
   * Set group id for the owner if this is a group membership
   * @param ownerGroupId
   */
  public void setOwnerGroupId(String ownerGroupId) {
    this.ownerGroupId = ownerGroupId;
    setOwnerGroupIdNull(ownerGroupId);
    if (ownerGroupId == null) {
      setOwnerGroupIdNull(GroupSet.nullColumnValue);
    } else {
      setOwnerId(ownerGroupId);
    }
  }

  /**
   * This is for internal use only.  This is the same as getOwnerGroupId() except nulls are replaced with
   * a constant string.
   * @return group id for the owner if this is a group membership
   */
  public String getOwnerGroupIdNull() {
    return ownerGroupIdNull;
  }

  
  /**
   * Set group id for the owner if this is a group membership.  This is for internal use only.
   * @param ownerGroupIdNull
   */
  public void setOwnerGroupIdNull(String ownerGroupIdNull) {
    this.ownerGroupIdNull = ownerGroupIdNull;
  }

  /**
   * @return stem id for the owner if this is a stem membership
   */
  public String getOwnerStemId() {
    return ownerStemId;
  }

  
  /**
   * Set stem id for the owner if this is a stem membership
   * @param ownerStemId
   */
  public void setOwnerStemId(String ownerStemId) {
    this.ownerStemId = ownerStemId;
    setOwnerStemIdNull(ownerStemId);
    if (ownerStemId == null) {
      setOwnerStemIdNull(GroupSet.nullColumnValue);
    } else {
      setOwnerId(ownerStemId);
    }
  }

  
  /**
   * This is for internal use only.  This is the same as getOwnerStemId() except nulls are replaced with
   * a constant string.
   * @return stem id for the owner if this is a stem membership
   */
  public String getOwnerStemIdNull() {
    return ownerStemIdNull;
  }

  /**
   * Set stem id for the owner if this is a stem membership.  This is for internal use only.
   * @param ownerStemIdNull
   */
  public void setOwnerStemIdNull(String ownerStemIdNull) {
    this.ownerStemIdNull = ownerStemIdNull;
  }

  /**
   * @return group id for the member if the member is a group
   */
  public String getMemberGroupId() {
    return memberGroupId;
  }

  
  /**
   * Set group id for the member if the member is a group
   * @param memberGroupId
   */
  public void setMemberGroupId(String memberGroupId) {
    this.memberGroupId = memberGroupId;
  }
  
  /**
   * @return stem id for the member if the member is a stem
   */
  public String getMemberStemId() {
    return memberStemId;
  }

  
  /**
   * Set stem id for the member if the member is a stem
   * @param memberStemId
   */
  public void setMemberStemId(String memberStemId) {
    this.memberStemId = memberStemId;
  }

  
  /**
   * This is 'immediate' for self memberships (owner and member are the same) except if the group is a composite in which case this will be 'composite'.
   * For non-self memberships, this is 'effective'.
   * @return membership type (immediate, effective, or composite)
   */
  public String getType() {
    return type;
  }

  
  /**
   * set membership type
   * @param type
   */
  public void setType(String type) {
    this.type = type;
  }

  
  /**
   * Since pre hooks on effective memberships have to fire before the membership can be queried,
   * I have this method to manually combine a GroupSet and ImmediateMembershipEntry.
   * @param immediateOrCompositeMembership
   * @return membership
   */
  /*
  public Membership internal_createEffectiveMembershipObject(Membership immediateOrCompositeMembership) {
    Membership effectiveMembership = immediateOrCompositeMembership.clone();
    effectiveMembership.setUuid(immediateOrCompositeMembership.getImmediateMembershipId() + ":" + this.getId());
    effectiveMembership.setGroupSetId(this.getId());
    effectiveMembership.setFieldId(this.getFieldId());
    effectiveMembership.setOwnerAttrDefId(this.getOwnerAttrDefId());
    effectiveMembership.setOwnerGroupId(this.getOwnerGroupId());
    effectiveMembership.setOwnerStemId(this.getOwnerStemId());
    effectiveMembership.setViaGroupId(this.getViaGroupId());
    effectiveMembership.setViaCompositeId(null);
    effectiveMembership.setDepth(this.getDepth());
    effectiveMembership.setType(MembershipType.EFFECTIVE.getTypeString());
    effectiveMembership.setGroupSetParentId(this.getParentId());
    effectiveMembership.setGroupSetCreatorUuid(this.getCreatorId());
    effectiveMembership.setGroupSetCreateTimeLong(this.getCreateTime());
    
    return effectiveMembership;
  }
  */

  /**
   * @return group id for the member if the member is a group
   */
  public String getMemberAttrDefId() {
    return this.memberAttrDefId;
  }

  /**
   * @return attrdef id for the owner if this is a attrdef membership
   */
  public String getOwnerAttrDefId() {
    return this.ownerAttrDefId;
  }

  /**
   * This is for internal use only.  This is the same as getOwnerAttrDefId() except nulls are replaced with
   * a constant string.
   * @return attr def id for the owner if this is a attrdef membership
   */
  public String getOwnerAttrDefIdNull() {
    return this.ownerAttrDefIdNull;
  }

  /**
   * Set attr def id for the member if the member is a attrdef
   * @param memberAttrDefId1
   */
  public void setMemberAttrDefId(String memberAttrDefId1) {
    this.memberAttrDefId = memberAttrDefId1;
  }

  /**
   * Set attrdef id for the owner if this is a attrdef membership
   * @param ownerAttrDefId1
   */
  public void setOwnerAttrDefId(String ownerAttrDefId1) {
    this.ownerAttrDefId = ownerAttrDefId1;
    this.setOwnerAttrDefIdNull(ownerAttrDefId1);
    if (ownerAttrDefId1 == null) {
      this.setOwnerAttrDefIdNull(GroupSet.nullColumnValue);
    } else {
      setOwnerId(ownerAttrDefId1);
    }
  }

  /**
   * Set attrdef id for the owner if this is a attrdef membership.  This is for internal use only.
   * @param ownerAttrDefIdNull1
   */
  public void setOwnerAttrDefIdNull(String ownerAttrDefIdNull1) {
    this.ownerAttrDefIdNull = ownerAttrDefIdNull1;
  }
  
  /**
   * get the member id
   * @return the member id
   */
  public String getMemberId() {
    if (this.memberAttrDefId != null) {
      return this.memberAttrDefId;
    }
    
    if (this.memberGroupId != null) {
      return this.memberGroupId;
    }
    
    if (this.memberStemId != null) {
      return this.memberStemId;
    }
    
    throw new RuntimeException("No value for member.");
  }
  
  /**
   * This is for internal use only.
   * @param member
   */
  public void setMemberId(String member) {
    // not used
  }
  
  /**
   * @see edu.internet2.middleware.grouper.GrouperAPI#onPreUpdate(edu.internet2.middleware.grouper.hibernate.HibernateSession)
   */
  @Override
  public void onPreUpdate(HibernateSession hibernateSession) {
    super.onPreUpdate(hibernateSession);
    
    if (this.depth == 0) {
      this.memberFieldId = new String(this.fieldId);
    } else {
      this.memberFieldId = Group.getDefaultList().getUuid();
    }
  }
  
  /**
   * @param forceDisablePITEntry should only be used if we're removing a corrupt group set
   */
  public void delete(final boolean forceDisablePITEntry) {
    
    HibernateSession.callbackHibernateSession(
        GrouperTransactionType.READ_WRITE_OR_USE_EXISTING, AuditControl.WILL_NOT_AUDIT,
        new HibernateHandler() {

          public Object callback(HibernateHandlerBean hibernateHandlerBean)
              throws GrouperDAOException {

            hibernateHandlerBean.getHibernateSession().setCachingEnabled(false);

            GrouperDAOFactory.getFactory().getGroupSet().delete(GroupSet.this);
            
            if (forceDisablePITEntry) {
              PITGroupSet pit = GrouperDAOFactory.getFactory().getPITGroupSet().findBySourceIdActive(GroupSet.this.getId(), false);
              if (pit != null) {
                pit.internal_disable();
              }
            }
            
            return null;
          }
        });
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy