Package org.jasig.portal.groups.grouper

Source Code of org.jasig.portal.groups.grouper.GrouperEntityGroupStore

/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you 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 org.jasig.portal.groups.grouper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portal.EntityIdentifier;
import org.jasig.portal.EntityTypes;
import org.jasig.portal.groups.EntityGroupImpl;
import org.jasig.portal.groups.EntityImpl;
import org.jasig.portal.groups.GroupsException;
import org.jasig.portal.groups.IEntity;
import org.jasig.portal.groups.IEntityGroup;
import org.jasig.portal.groups.IEntityGroupStore;
import org.jasig.portal.groups.IEntitySearcher;
import org.jasig.portal.groups.IEntityStore;
import org.jasig.portal.groups.IGroupConstants;
import org.jasig.portal.groups.IGroupMember;
import org.jasig.portal.groups.ILockableEntityGroup;
import org.jasig.portal.security.IPerson;

import edu.internet2.middleware.grouperClient.api.GcAddMember;
import edu.internet2.middleware.grouperClient.api.GcFindGroups;
import edu.internet2.middleware.grouperClient.api.GcGetGroups;
import edu.internet2.middleware.grouperClient.api.GcGetMembers;
import edu.internet2.middleware.grouperClient.api.GcGetSubjects;
import edu.internet2.middleware.grouperClient.api.GcGroupDelete;
import edu.internet2.middleware.grouperClient.api.GcGroupSave;
import edu.internet2.middleware.grouperClient.api.GcHasMember;
import edu.internet2.middleware.grouperClient.util.GrouperClientUtils;
import edu.internet2.middleware.grouperClient.ws.StemScope;
import edu.internet2.middleware.grouperClient.ws.beans.WsFindGroupsResults;
import edu.internet2.middleware.grouperClient.ws.beans.WsGetGroupsResult;
import edu.internet2.middleware.grouperClient.ws.beans.WsGetGroupsResults;
import edu.internet2.middleware.grouperClient.ws.beans.WsGetMembersResults;
import edu.internet2.middleware.grouperClient.ws.beans.WsGetSubjectsResults;
import edu.internet2.middleware.grouperClient.ws.beans.WsGroup;
import edu.internet2.middleware.grouperClient.ws.beans.WsGroupLookup;
import edu.internet2.middleware.grouperClient.ws.beans.WsGroupToSave;
import edu.internet2.middleware.grouperClient.ws.beans.WsHasMemberResult;
import edu.internet2.middleware.grouperClient.ws.beans.WsHasMemberResults;
import edu.internet2.middleware.grouperClient.ws.beans.WsQueryFilter;
import edu.internet2.middleware.grouperClient.ws.beans.WsStemLookup;
import edu.internet2.middleware.grouperClient.ws.beans.WsSubject;
import edu.internet2.middleware.grouperClient.ws.beans.WsSubjectLookup;

/**
* GrouperEntityGroupStore provides an implementation of the group store
* interface capable of retrieving groups information from Grouper web services.
* This implementation uses the standard Grouper client jar to search for group
* information.  It does not currently support write access or group locking.
*
* @author Bill Brown
* @author Jen Bourey, jbourey@unicon.net
* @version $Revision$
*/
public class GrouperEntityGroupStore implements IEntityGroupStore,
        IEntityStore, IEntitySearcher {

    private final static String STEM_PREFIX = "uportal.stem";
   
    /** Logger. */
    protected final static Log LOGGER = LogFactory
            .getLog(GrouperEntityGroupStoreFactory.class);

    /**
     * Package protected constructor used by the factory method.
     */
    GrouperEntityGroupStore() { /* Package protected. */
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(this + " created");
        }
    }

    /* (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;
    }

    /* (non-Javadoc)
     * @see org.jasig.portal.groups.IEntityGroupStore#find(java.lang.String)
     */
    public IEntityGroup find(String key) throws GroupsException {


        try {

            // Search the Grouper server for groups with the specified local
            // key
          if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Searching Grouper for a direct match for key: " + key);
          }
            WsGroup wsGroup = findGroupFromKey(key);
            if (wsGroup == null) {
              return null;
            }
            IEntityGroup group = createUportalGroupFromGrouperGroup(wsGroup);
           
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Retrieved group from the Grouper server matching key "
                        + key + ": " + group.toString());
            }
           
            // return the group
            return group;
           

        } catch (Exception e) {
            LOGGER.warn("Exception while attempting to retrieve "
                    + "group with key " + key + " from Grouper web services: " + e.getMessage());
            return null;
        }

    }

    /* (non-Javadoc)
     * @see org.jasig.portal.groups.IEntityGroupStore#findContainingGroups(org.jasig.portal.groups.IGroupMember)
     */
    @SuppressWarnings("unchecked")
    public Iterator findContainingGroups(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();
    }

    /* (non-Javadoc)
     * @see org.jasig.portal.groups.IEntityGroupStore#findEntitiesForGroup(org.jasig.portal.groups.IEntityGroup)
     */
    @SuppressWarnings("unchecked")
    public Iterator findEntitiesForGroup(IEntityGroup group)
            throws GroupsException {
       
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Searching Grouper for members of the group with key: "
                    + group.getKey());
        }

        try {
           
            // execute a search for members of the specified group
            GcGetMembers getGroupsMembers = new GcGetMembers();
            getGroupsMembers.addGroupName(group.getLocalKey());
            getGroupsMembers.assignIncludeSubjectDetail(true);
            WsGetMembersResults results = getGroupsMembers.execute();
           
            if (results == null || results.getResults() == null
                    || results.getResults().length == 0
                    || results.getResults()[0].getWsSubjects() == null) {
                LOGGER.debug("No members found for Grouper group with key "
                        + group.getLocalKey());
                return Collections.<IGroupMember>emptyList().iterator();
            }

            WsSubject[] gInfos = results.getResults()[0].getWsSubjects();
            final List<IGroupMember> members = new ArrayList<IGroupMember>(
                    gInfos.length);
           
            // add each result to the member list
            for (WsSubject gInfo : gInfos) {
               
                // if the member is not a group (aka person)
              if (!StringUtils.equals(gInfo.getSourceId(), "g:gsa")) {

          if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("creating leaf member:" + gInfo.getId()
                + " and name: " + gInfo.getName()
                + " from group: " + group.getLocalKey());
          }
          //use the name instead of id as it shows better in the display
          IGroupMember member = new EntityImpl(gInfo.getName(),
              IPerson.class);
          members.add(member);
        }

            }

            // return an iterator for the assembled group
            return members.iterator();
           
        } catch (Exception e) {
            LOGGER.warn("Exception while attempting to retrieve "
                    + "member entities of group with key " + group.getKey()
                    + " from Grouper web services: " + e.getMessage());
            return Collections.<IGroupMember>emptyList().iterator();
        }

    }

    /* (non-Javadoc)
     * @see org.jasig.portal.groups.IEntityGroupStore#findMemberGroupKeys(org.jasig.portal.groups.IEntityGroup)
     */
    @SuppressWarnings("unchecked")
    public String[] findMemberGroupKeys(IEntityGroup group)
            throws GroupsException {
       
        // first the get an iterator for the member groups
        final Iterator<IEntityGroup> it = findMemberGroups(group);
       
        // construct a list of group keys from this iterator
        List<String> keys = new ArrayList<String>();
        while (it.hasNext()) {
            IEntityGroup eg = it.next();
            keys.add(eg.getKey());
        }
       
        // return an iterator over the assembled list
        return keys.toArray(new String[keys.size()]);
    }

    @SuppressWarnings("unchecked")
    public Iterator findMemberGroups(IEntityGroup group) throws GroupsException {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Searching for group-type members of group with key: "
                    + group.getKey());
        }

        try {
           
            if (!validKey(group.getLocalKey())) {
                return Collections.<IEntityGroup> emptyList().iterator();
            }

            GcGetMembers gcGetMembers = new GcGetMembers();
            gcGetMembers.addGroupName(group.getLocalKey());
            gcGetMembers.assignIncludeSubjectDetail(true);
            gcGetMembers.addSourceId("g:gsa");

            WsGetMembersResults results = gcGetMembers.execute();

            if (results == null || results.getResults() == null
          || results.getResults().length == 0
          || results.getResults()[0].getWsSubjects() == null) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER
                            .debug("No group-type members found for group with key "
                                    + group.getKey());
                }
                return Collections.<IEntityGroup> emptyList().iterator();
            }

            final List<IEntityGroup> members = new ArrayList<IEntityGroup>();
            WsSubject[] subjects = results.getResults()[0].getWsSubjects();

      for (WsSubject wsSubject : subjects) {
                if (validKey(wsSubject.getName())) {
                    WsGroup wsGroup = findGroupFromKey(wsSubject
                            .getName());
                    if (wsGroup != null) {
                        IEntityGroup member = createUportalGroupFromGrouperGroup(wsGroup);
                        members.add(member);
                        if (LOGGER.isTraceEnabled()) {
                            LOGGER.trace("found IEntityGroup member: "
                                    + member);
                        }
                    }
                }
            }

           
            return members.iterator();
           
        } catch (Exception e) {
            LOGGER.warn("Exception while attempting to retrieve "
                    + "member groups of group with key " + group.getKey()
                    + " from Grouper web services: " + e.getMessage());
            return Collections.<IGroupMember>emptyList().iterator();
        }

    }

    /* (non-Javadoc)
     * @see org.jasig.portal.groups.IEntityGroupStore#searchForGroups(java.lang.String, int, java.lang.Class)
     */
    public EntityIdentifier[] searchForGroups(final String query,
            final int method,
            @SuppressWarnings("unchecked") final Class leaftype) {
     
      //only search for groups
        if ( leaftype != IPerson.class )
          { return new EntityIdentifier[] {}; }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Searching Grouper for groups matching query: " + query);
        }

        // result groups.
        List<EntityIdentifier> groups = new ArrayList<EntityIdentifier>();

        try {
           
            // TODO: searches need to be performed against the group display
            // name rather than the group key
           
            GcFindGroups groupSearch = new GcFindGroups();
            WsQueryFilter filter = new WsQueryFilter();
            //is this an exact search or fuzzy
            if(method == IGroupConstants.IS){
              filter.setQueryFilterType("FIND_BY_GROUP_NAME_EXACT");
            }else{
              filter.setQueryFilterType("FIND_BY_GROUP_NAME_APPROXIMATE");
            }
            filter.setGroupName(query);
            groupSearch.assignQueryFilter(filter);
            WsFindGroupsResults results = groupSearch.execute();
           
            if (results != null && results.getGroupResults() != null) {
                for (WsGroup g : results.getGroupResults()) {
                  if (validKey(g.getName())) {
                    if (LOGGER.isTraceEnabled()) {
                      LOGGER.trace("Retrieved group: " + g.getName());
                    }
                    groups.add(new EntityIdentifier(g.getName(),
                            IEntityGroup.class));
                }
            }
            }

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Returning " + groups.size()
                        + " results for query " + query);
            }

            return groups.toArray(new EntityIdentifier[groups.size()]);

        } catch (Exception e) {
            LOGGER.warn("Exception while attempting to retrieve "
                    + "search results for query " + query + " and entity type "
                    + leaftype.getCanonicalName() + " : " + e.getMessage());
            return new EntityIdentifier[] {};
        }

    }
   
    /**
     * @see org.jasig.portal.groups.IEntitySearcher#searchForEntities(java.lang.String,
     *      int, java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    public EntityIdentifier[] searchForEntities(String query, int method,
            Class type) throws GroupsException {
     
      // only search for groups
    if (type != IPerson.class) {
      return new EntityIdentifier[] {};
    }

    List<EntityIdentifier> entityIdentifiers = new ArrayList<EntityIdentifier>();

    try {

      GcGetSubjects subjects = new GcGetSubjects();
      subjects.assignIncludeSubjectDetail(true);
      WsGetSubjectsResults results = subjects.assignSearchString(query)
          .execute();

      if (results != null && results.getWsSubjects() != null) {

        for (WsSubject wsSubject : results.getWsSubjects()) {
          entityIdentifiers.add(new EntityIdentifier(wsSubject
              .getName(), EntityTypes.LEAF_ENTITY_TYPE));
        }
      }
      return entityIdentifiers.toArray(new EntityIdentifier[entityIdentifiers.size()]);

    } catch (Exception e) {
      LOGGER.warn("Exception while attempting to retrieve "
          + "search results for query " + query + " and entity type "
          + type.getCanonicalName() + " : " + e.getMessage());
      return new EntityIdentifier[] {};
    }
   
    }
   
    /**
     * @see org.jasig.portal.groups.IEntityStore#newInstance(java.lang.String)
     */
    public IEntity newInstance(String key) throws GroupsException {
        return new EntityImpl(key, null);
    }

    /**
     * @see org.jasig.portal.groups.IEntityStore#newInstance(java.lang.String, java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    public IEntity newInstance(String key, Class type) throws GroupsException {
        if (org.jasig.portal.EntityTypes.getEntityTypeID(type) == null) {
            throw new GroupsException("Invalid group type: " + type);
        }
        return new EntityImpl(key, type);
    }

    /**
     * Test a Grouper {WsGroup} against a query string according to the specified
     * method and determine if it matches the query.
     *
     * @param group  WsGroup to be tested
     * @param query  Query string
     * @param method int-based method matching one of the standard search methods
     *               defined in {IGroupConstants}
     * @return       <code>true</code> if the group matches, <code>false</code>
     *               otherwise
     */
    protected boolean groupMatches(WsGroup group, String query, int method) {
       
        // Ensure that this group has a name defined before performing
        // comparisons.
        if (group == null || group.getName() == null) {
            return false;
        }
       
        switch (method) {
            case IGroupConstants.IS:
                return group.getName().equals(query);
            case IGroupConstants.STARTS_WITH:
                return group.getName().startsWith(query);
            case IGroupConstants.ENDS_WITH:
                return group.getName().endsWith(query);
            case IGroupConstants.CONTAINS:
                return group.getName().contains(query);
            default:
                return false;
        }
    }
   
    /**
     * Construct an IEntityGroup from a Grouper WsGroup.
     *
     * @param wsGroup
     * @return the group
     */
    protected IEntityGroup createUportalGroupFromGrouperGroup(WsGroup wsGroup) {
        IEntityGroup iEntityGroup = new EntityGroupImpl(wsGroup.getName(),
                IPerson.class);

        // need to set the group name and description to the actual
        // display name and description
        iEntityGroup.setName(wsGroup.getDisplayName());
        iEntityGroup.setDescription(wsGroup.getDescription());
        return iEntityGroup;
    }

    /**
     * Find the Grouper group matching the specified key.
     *
     * @param key
     * @return the group or null
     */
    protected WsGroup findGroupFromKey(String key) {
      WsGroup wsGroup = null;

    if (key != null) {

      GcFindGroups gcFindGroups = new GcFindGroups();
      gcFindGroups.addGroupName(key);
      WsFindGroupsResults results = gcFindGroups.execute();

      // if no results were returned, return null
      if (results != null && results.getGroupResults() != null
          && results.getGroupResults().length > 0) {

        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("found group from key " + key + ": "
              + results.getGroupResults()[0]);
        }

        wsGroup = results.getGroupResults()[0];
      }
    }

    return wsGroup;
    }

    /**
     * Get the prefix for the stem containing uPortal groups.  If this value
     * is non-empty, all groups will be required to be prefixed with the
     * specified stem name.
     *
     * @return the uportal stem in the registry, without trailing colon
     */
    protected static String getStemPrefix() {
       
        String uportalStem = GrouperClientUtils.propertiesValue(STEM_PREFIX,
                false);

        // make sure it ends in colon
        if (!StringUtils.isBlank(uportalStem)) {
            if (uportalStem.endsWith(":")) {
                uportalStem = uportalStem
                        .substring(0, uportalStem.length() - 1);
            }
        }

        return uportalStem;
    }

    /**
     *
     * @param key
     * @return true if ok key (group name) false if not
     */
    protected static boolean validKey(String key) {
        String uportalStem = getStemPrefix();
       
        if (!StringUtils.isBlank(uportalStem)
                && (StringUtils.isBlank(key) || !key.startsWith(uportalStem.concat(":")))) {
            // if the uPortal stem prefix is specified and the key is blank
            // or does not contain the stem prefix, return false
            return false;
        } else {
            // otherwise, indicate that the key is valid
            return true;
        }
    }

    /**
     * @see org.jasig.portal.groups.IEntityGroupStore#update(org.jasig.portal.groups.IEntityGroup)
     */
    public void update(IEntityGroup group) throws GroupsException {

        // assume key is fully qualified group name
        String groupName = group.getLocalKey();

        String description = group.getDescription();

        // the name is the displayExtension
        String displayExtension = group.getName();

        WsGroupToSave wsGroupToSave = new WsGroupToSave();
        wsGroupToSave.setCreateParentStemsIfNotExist("T");
        wsGroupToSave.setWsGroupLookup(new WsGroupLookup(groupName, null));
        WsGroup wsGroup = new WsGroup();
        wsGroup.setName(groupName);
        wsGroup.setDisplayExtension(displayExtension);
        wsGroup.setDescription(description);
        wsGroupToSave.setWsGroup(wsGroup);

        new GcGroupSave().addGroupToSave(wsGroupToSave).execute();

        updateMembers(group);
    }

    /**
     * @see org.jasig.portal.groups.IEntityGroupStore#updateMembers(org.jasig.portal.groups.IEntityGroup)
     */
    public void updateMembers(IEntityGroup group) throws GroupsException {

        // assume key is fully qualified group name
        String groupName = group.getLocalKey();

        GcAddMember gcAddMember = new GcAddMember().assignGroupName(groupName);

        Iterator<IGroupMember> membersIterator = group.getMembers();

        while (membersIterator != null && membersIterator.hasNext()) {
            IGroupMember iGroupMember = membersIterator.next();
            EntityIdentifier entityIdentifier = iGroupMember
                    .getEntityIdentifier();

            String identifier = entityIdentifier.getKey();

            gcAddMember.addSubjectIdentifier(identifier);
        }
        gcAddMember.execute();

    }

    /**
     * @see org.jasig.portal.groups.IEntityGroupStore#delete(org.jasig.portal.groups.IEntityGroup)
     */
    public void delete(IEntityGroup group) throws GroupsException {

        String groupName = group.getLocalKey();
        new GcGroupDelete().addGroupLookup(new WsGroupLookup(groupName, null))
                .execute();
    }

    /**
     * @see org.jasig.portal.groups.IEntityGroupStore#findLockable(java.lang.String)
     */
    public ILockableEntityGroup findLockable(String key) throws GroupsException {
        throw new UnsupportedOperationException(
            "Group locking is not supported by the Grouper groups service");
    }

    /*
     * @see
     * org.jasig.portal.groups.IEntityGroupStore#newInstance(java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    public IEntityGroup newInstance(Class entityType) throws GroupsException {
        throw new UnsupportedOperationException(
            "Group updates are not supported by the Grouper groups service");
    }

}
TOP

Related Classes of org.jasig.portal.groups.grouper.GrouperEntityGroupStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.