@Override
  public Iterator<IEntityGroup> findParentGroups(IGroupMember member) throws GroupsException {

    /*
     * This method has the potential to be called A LOT, especially if
     * there's a lot of portal data (portlets & groups).  It's important
     * not to waste time on nonsensical checks.
     */

    if (!IPERSON_CLASS.equals(member.getLeafType())) {
      // This is going to happen;  GaP code is not responsible for
      // knowing that PAGS only supports groups of IPerson (we are).
      return Collections.emptyIterator();
    }

    logger.debug("finding containing groups for member key {}", member.getKey());

    final Set<IEntityGroup> set = Collections.emptySet();
    Iterator<IEntityGroup> rslt = set.iterator(); // default

    if (member.isGroup()) {
      // PAGS groups may only contain other PAGS groups (and people, of course)
      final IEntityGroup ieg = (IEntityGroup) member;
      if (PagsService.SERVICE_NAME_PAGS.equals(ieg.getServiceName().toString())) {
        rslt = findParentGroupsForGroup((IEntityGroup) member);
      }
    } else {
      rslt = findParentGroupsForEntity((IEntity) member);
    }

    return rslt;
  }
  /* (non-Javadoc)
   * @see org.jasig.portal.groups.IEntityGroupStore#contains(org.jasig.portal.groups.IEntityGroup, org.jasig.portal.groups.IGroupMember)
   */
  public boolean contains(IEntityGroup group, IGroupMember member) throws GroupsException {

    String groupContainerName = group.getLocalKey();
    String groupMemberName = member.getKey();

    if (!validKey(groupContainerName) || !validKey(groupMemberName)) {
      return false;
    }

    GcHasMember gcHasMember = new GcHasMember();
    gcHasMember.assignGroupName(groupContainerName);
    gcHasMember.addSubjectLookup(new WsSubjectLookup(null, "g:gsa", groupMemberName));
    WsHasMemberResults wsHasMemberResults = gcHasMember.execute();
    if (GrouperClientUtils.length(wsHasMemberResults.getResults()) == 1) {
      WsHasMemberResult wsHasMemberResult = wsHasMemberResults.getResults()[0];
      return StringUtils.equals("IS_MEMBER", wsHasMemberResult.getResultMetadata().getResultCode());
    }
    return false;
  }
  @Override
  public boolean contains(IEntityGroup group, IGroupMember member) {

    /*
     * This method has the potential to be called A LOT, especially if
     * there's a lot of portal data (portlets & groups).  It's important
     * not to waste time on nonsensical checks.
     */

    if (!IPERSON_CLASS.equals(member.getLeafType())) {
      // Maybe this call to contains() shouldn't even happen, since
      // group.getLeafType() is (presumably) IPerson.class.
      return false;
    }

    if (member.isGroup()) {
      // PAGS groups may only contain other PAGS groups (and people, of course)
      final IEntityGroup ieg = (IEntityGroup) member;
      if (!PagsService.SERVICE_NAME_PAGS.equals(ieg.getServiceName().toString())) {
        return false;
      }
    }

    final MembershipCacheKey cacheKey =
        new MembershipCacheKey(group.getEntityIdentifier(), member.getEntityIdentifier());
    Element element = membershipCache.get(cacheKey);
    if (element == null) {

      logger.debug(
          "Checking if group {} contains member {}/{}",
          group.getName(),
          member.getKey(),
          member.getLeafType().getSimpleName());

      boolean answer = false; // default
      final PagsGroup groupDef = convertEntityToGroupDef(group);
      if (member.isGroup()) {
        final String key = ((IEntityGroup) member).getLocalKey();
        answer = groupDef.hasMember(key);
      } else {
        try {
          final IPersonAttributeDao pa = PersonAttributeDaoLocator.getPersonAttributeDao();
          final IPersonAttributes personAttributes = pa.getPerson(member.getKey());

          if (personAttributes != null) {
            final RestrictedPerson rp = PersonFactory.createRestrictedPerson();
            rp.setAttributes(personAttributes.getAttributes());
            answer = groupDef.contains(rp);
          }
        } catch (Exception ex) {
          logger.error(
              "Exception acquiring attributes for member "
                  + member
                  + " while checking if group "
                  + group
                  + " contains this member.",
              ex);
          return false;
        }
      }

      element = new Element(cacheKey, answer);
      membershipCache.put(element);
    }

    return (Boolean) element.getObjectValue();
  }
  /* (non-Javadoc)
   * @see org.jasig.portal.groups.IEntityGroupStore#findParentGroups(org.jasig.portal.groups.IGroupMember)
   */
  @SuppressWarnings("unchecked")
  public Iterator findParentGroups(IGroupMember gm) throws GroupsException {

    final List<IEntityGroup> parents = new LinkedList<IEntityGroup>();

    GcGetGroups getGroups = new GcGetGroups();

    String uportalStem = getStemPrefix();

    // if only searching in a specific stem
    if (!StringUtils.isBlank(uportalStem)) {
      getGroups.assignStemScope(StemScope.ALL_IN_SUBTREE);
      getGroups.assignWsStemLookup(new WsStemLookup(uportalStem, null));
    }

    String key = null;
    String subjectSourceId = null;
    if (gm.isGroup()) {

      key = ((IEntityGroup) gm).getLocalKey();

      if (!validKey(key)) {
        return parents.iterator();
      }
      subjectSourceId = "g:gsa";
    } else {

      // Determine the key to use for this entity. If the entity is a
      // group, we should use the group's local key (excluding the
      // "grouper." portion of the full key. If the entity is not a
      // group type, just use the key.
      key = gm.getKey();
    }
    getGroups.addSubjectLookup(new WsSubjectLookup(null, subjectSourceId, key));

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Searching Grouper for parent groups of the entity with key: " + key);
    }

    try {

      WsGetGroupsResults results = getGroups.execute();

      if (results == null || results.getResults() == null || results.getResults().length != 1) {
        LOGGER.debug("Grouper service returned no matches for key " + key);
        return parents.iterator();
      }
      WsGetGroupsResult wsg = results.getResults()[0];
      if (wsg.getWsGroups() != null) {
        for (WsGroup g : wsg.getWsGroups()) {
          if (LOGGER.isDebugEnabled()) {
            LOGGER.trace("Retrieved group: " + g.getName());
          }
          IEntityGroup parent = createUportalGroupFromGrouperGroup(g);
          parents.add(parent);
        }
      }

      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Retrieved " + parents.size() + " parent groups of entity with key " + key);
      }

    } catch (Exception e) {
      LOGGER.warn(
          "Exception while attempting to retrieve "
              + "parents for entity with key "
              + key
              + " from Grouper web services: "
              + e.getMessage());
      return Collections.<IEntityGroup>emptyList().iterator();
    }

    return parents.iterator();
  }