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

edu.internet2.middleware.changelogconsumer.googleapps.GoogleAppsChangeLogConsumer Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright 2015 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.changelogconsumer.googleapps;

import com.google.api.services.directory.model.Group;
import com.google.api.services.directory.model.User;
import edu.internet2.middleware.changelogconsumer.googleapps.cache.GoogleCacheManager;
import edu.internet2.middleware.changelogconsumer.googleapps.utils.GoogleAppsSyncProperties;
import edu.internet2.middleware.grouper.*;
import edu.internet2.middleware.grouper.Stem.Scope;
import edu.internet2.middleware.grouper.attr.AttributeDefName;
import edu.internet2.middleware.grouper.attr.assign.AttributeAssignType;
import edu.internet2.middleware.grouper.changeLog.*;
import edu.internet2.middleware.grouper.pit.PITGroup;
import edu.internet2.middleware.grouper.pit.finder.PITGroupFinder;
import edu.internet2.middleware.subject.Subject;
import edu.internet2.middleware.subject.SubjectType;
import edu.internet2.middleware.subject.provider.SubjectTypeEnum;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


/**
 * A {@link ChangeLogConsumer} which provisions via Google Apps API.
 *
 * @author John Gasper, Unicon
 **/
public class GoogleAppsChangeLogConsumer extends ChangeLogConsumerBase {

    /** Maps change log entry category and action (change log type) to methods. */
    enum EventType {

        /** Process the add attribute assign value change log entry type. */
        attributeAssign__addAttributeAssign {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processAttributeAssignAdd(consumer, changeLogEntry);
            }
        },

        /** Process the delete attribute assign value change log entry type. */
        attributeAssign__deleteAttributeAssign {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processAttributeAssignDelete(consumer, changeLogEntry);
            }
        },

        /** Process the add group change log entry type. */
        group__addGroup {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processGroupAdd(consumer, changeLogEntry);
            }
        },

        /** Process the delete group change log entry type. */
        group__deleteGroup {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processGroupDelete(consumer, changeLogEntry);
            }
        },

        /** Process the update group change log entry type. */
        group__updateGroup {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processGroupUpdate(consumer, changeLogEntry);
            }
        },

        /** Process the add membership change log entry type. */
        membership__addMembership {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processMembershipAdd(consumer, changeLogEntry);
            }
        },

        /** Process the delete membership change log entry type. */
        membership__deleteMembership {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processMembershipDelete(consumer, changeLogEntry);
            }
        },

        privilege__addPrivilege {
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processPrivilegeAdd(consumer, changeLogEntry);
            }
        },

        privilege__deletePrivilege {
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processPrivilegeDelete(consumer, changeLogEntry);
            }
        },

        privilege__updatePrivilege {
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processPrivilegeUpdate(consumer, changeLogEntry);
            }
        },

        /** Process the delete stem change log entry type. */
        stem__deleteStem {
            /** {@inheritDoc} */
            public void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception {
                consumer.processStemDelete(consumer, changeLogEntry);
            }
        },
        ;

        /**
         * Process the change log entry.
         *
         * @param consumer the google change log consumer
         * @param changeLogEntry the change log entry
         * @throws Exception if any error occurs
         */
        public abstract void process(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) throws Exception;
    }

    private static final Logger LOG = LoggerFactory.getLogger(GoogleAppsChangeLogConsumer.class);

    /** The change log consumer name from the processor metadata. */
    private String consumerName;
    private AttributeDefName syncAttribute;
    private GoogleGrouperConnector connector;


    public GoogleAppsChangeLogConsumer() {
        LOG.trace("Google Apps Consumer - new instances starting up");

        connector = new GoogleGrouperConnector();
    }

    /** {@inheritDoc} */
    @Override
    public long processChangeLogEntries(final List changeLogEntryList,
                                        ChangeLogProcessorMetadata changeLogProcessorMetadata) {

        LOG.debug("Google Apps Consumer - waking up");

        // the change log sequence number to return
        long sequenceNumber = -1;

        // initialize this consumer's consumerName from the change log metadata
        if (consumerName == null) {
            consumerName = changeLogProcessorMetadata.getConsumerName();
            LOG.trace("Google Apps Consumer '{}' - Setting name.", consumerName);
        }

        GoogleAppsSyncProperties properties = new GoogleAppsSyncProperties(consumerName);

        try {
            connector.initialize(consumerName, properties);

            if (properties.getprefillGoogleCachesForConsumer()) {
                connector.populateGoogleCache();
            }

        } catch (Exception e) {
            LOG.error("Google Apps Consumer '{}' - This consumer failed to initialize: {}", consumerName, e.getMessage());
            return changeLogEntryList.get(0).getSequenceNumber() - 1;
        }

        GrouperSession grouperSession = null;
        try {

            grouperSession = GrouperSession.startRootSession();
            syncAttribute = connector.getGoogleSyncAttribute();
            connector.cacheSyncedGroupsAndStems();

            // time context processing
            final StopWatch stopWatch = new StopWatch();

            // the last change log sequence number processed
            String lastContextId = null;

            LOG.debug("Google Apps Consumer '{}' - Processing change log entry list size '{}'", consumerName, changeLogEntryList.size());

            boolean first = true;

            // process each change log entry
            for (ChangeLogEntry changeLogEntry : changeLogEntryList) {

                // return the current change log sequence number
                sequenceNumber = changeLogEntry.getSequenceNumber();

                // if full sync is running, return the previous sequence number to process this entry on the next run
                boolean isFullSyncRunning = GoogleAppsFullSync.isFullSyncRunning(consumerName);

                if (isFullSyncRunning) {
                    LOG.info("Google Apps Consumer '{}' - Full sync is running, returning sequence number '{}'", consumerName,
                            sequenceNumber - 1);
                    return sequenceNumber - 1;
                }

                // if first run, start the stop watch and store the last sequence number
                if (first) {
                    first = false;
                    stopWatch.start();
                    lastContextId = changeLogEntry.getContextId();
                }

                // whether or not an exception was thrown during processing of the change log entry
                boolean errorOccurred = false;

                try {
                    // process the change log entry
                    processChangeLogEntry(changeLogEntry);

                } catch (Exception e) {
                    errorOccurred = true;
                    String message =
                            "Google Apps Consumer '" + consumerName + "' - An error occurred processing sequence number " + sequenceNumber;
                    LOG.error(message, e);
                    changeLogProcessorMetadata.registerProblem(e, message, sequenceNumber);
                    changeLogProcessorMetadata.setHadProblem(true);
                    changeLogProcessorMetadata.setRecordException(e);
                    changeLogProcessorMetadata.setRecordExceptionSequence(sequenceNumber);
                }

                // if the change log context id has changed, log and restart stop watch
                if (lastContextId == null || changeLogEntry.getContextId() == null || !StringUtils.equals(lastContextId, changeLogEntry.getContextId())) {
                    stopWatch.stop();
                    LOG.debug("Google Apps Consumer '{}' - Processed change log context '{}' Elapsed time {}", new Object[] {consumerName,
                            lastContextId, stopWatch,});
                    stopWatch.reset();
                    stopWatch.start();
                }

                lastContextId = changeLogEntry.getContextId();

                // if an error occurs and retry on error is true, return the current sequence number minus 1
                /* Whether or not to retry a change log entry if an error occurs. */
                boolean retryOnError = properties.isRetryOnError();
                if (errorOccurred && retryOnError) {
                    sequenceNumber--;
                    break;
                }
            }

            // stop the timer and log
            stopWatch.stop();
            LOG.debug("Google Apps Consumer '{}' - Processed change log context '{}' Elapsed time {}", new Object[] {consumerName,
                    lastContextId, stopWatch,});

        } finally {
            GrouperSession.stopQuietly(grouperSession);
        }

        if (sequenceNumber == -1) {
            LOG.error("Google Apps Consumer '" + consumerName + "' - Unable to process any records.");
            throw new RuntimeException("Google Apps Consumer '" + consumerName + "' - Unable to process any records.");
        }

        LOG.debug("Google Apps Consumer '{}' - Finished processing change log entries. Last sequence number '{}'", consumerName,
                sequenceNumber);

        // return the sequence number
        return sequenceNumber;
    }

    /**
     * Call the method of the {@link EventType} enum which matches the {@link ChangeLogEntry} category and action (the
     * change log type).
     *
     * @param changeLogEntry the change log entry
     * @throws Exception if an error occurs processing the change log entry
     */
    protected void processChangeLogEntry(ChangeLogEntry changeLogEntry) throws Exception {
        try {
            // find the method to run via the enum
            final String enumKey = changeLogEntry.getChangeLogType().getChangeLogCategory() + "__"
                    + changeLogEntry.getChangeLogType().getActionName();

            final EventType eventType = EventType.valueOf(enumKey);

            if (eventType == null) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Unsupported category and action.", consumerName,
                        toString(changeLogEntry));
            } else {
                // process the change log event
                LOG.info("Google Apps Consumer '{}' - Change log entry '{}'", consumerName, toStringDeep(changeLogEntry));
                StopWatch stopWatch = new StopWatch();
                stopWatch.start();

                eventType.process(this, changeLogEntry);

                stopWatch.stop();
                LOG.info("Google Apps Consumer '{}' - Change log entry '{}' Finished processing. Elapsed time {}",
                        new Object[] {consumerName, toString(changeLogEntry), stopWatch,});

            }

        } catch (IllegalArgumentException e) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Unsupported category and action.", consumerName,
                    toString(changeLogEntry));
        }
    }

    /**
     * Add an attribute.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processAttributeAssignAdd(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing add attribute assign value.", consumerName,
                toString(changeLogEntry));

        final String attributeDefNameId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.ATTRIBUTE_ASSIGN_ADD.attributeDefNameId);
        final String assignType = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.ATTRIBUTE_ASSIGN_ADD.assignType);
        final String ownerId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.ATTRIBUTE_ASSIGN_ADD.ownerId1);

        if (syncAttribute.getId().equalsIgnoreCase(attributeDefNameId)) {

            if (AttributeAssignType.valueOf(assignType) == AttributeAssignType.group) {
                final edu.internet2.middleware.grouper.Group group = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), ownerId, false);
                if (group == null) {
                  return;  // group was deleted
                }

                try {
                    connector.createGooGroupIfNecessary(group);
                } catch (IOException e) {
                    LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group add: {}", new Object[] {consumerName, toString(changeLogEntry), e});
                }

            } else if (AttributeAssignType.valueOf(assignType) == AttributeAssignType.stem) {
                final Stem stem = StemFinder.findByUuid(GrouperSession.staticGrouperSession(), ownerId, false);
                if (stem == null) {
                  return;  // stem was deleted
                }
                final Set groups = stem.getChildGroups(Scope.SUB);

                for (edu.internet2.middleware.grouper.Group group : groups) {
                    try {
                        connector.createGooGroupIfNecessary(group);
                    } catch (IOException e) {
                        LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group add, continuing: {}", new Object[] {consumerName, toString(changeLogEntry), e});
                    }
                }
            }
        }
    }

    /**
     * Delete an attribute.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processAttributeAssignDelete(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry)  {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing delete attribute assign value.", consumerName,
                toString(changeLogEntry));

        final String attributeDefNameId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.ATTRIBUTE_ASSIGN_DELETE.attributeDefNameId);
        final String assignType = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.ATTRIBUTE_ASSIGN_DELETE.assignType);
        final String ownerId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.ATTRIBUTE_ASSIGN_DELETE.ownerId1);

        if (syncAttribute.getId().equalsIgnoreCase(attributeDefNameId)) {

            if (AttributeAssignType.valueOf(assignType) == AttributeAssignType.group) {
                String groupName = null;
                final edu.internet2.middleware.grouper.Group group = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), ownerId, false);
                if (group != null) {
                    groupName = group.getName();
                } else {
                    groupName = PITGroupFinder.findBySourceId(ownerId, true).iterator().next().getName();
                }
                try {
                    connector.deleteGooGroupByName(groupName, ownerId);
                } catch (IOException e) {
                    LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group add: {}", new Object[] {consumerName, toString(changeLogEntry), e});
                }

            } else if (AttributeAssignType.valueOf(assignType) == AttributeAssignType.stem) {
                final Stem stem = StemFinder.findByUuid(GrouperSession.staticGrouperSession(), ownerId, false);
                if (stem != null){
                    final Set groups = stem.getChildGroups(Scope.SUB);
                    
                    for (edu.internet2.middleware.grouper.Group group : groups) {
                        try {
                            connector.deleteGooGroup(group);
                        } catch (IOException e) {
                            LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group add, continuing: {}", new Object[] {consumerName, toString(changeLogEntry), e});
                        }
                    }
                }
            }
        }
    }

    /**
     * Add a group.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processGroupAdd(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing group add.", consumerName, toString(changeLogEntry));

        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_ADD.name);
        final edu.internet2.middleware.grouper.Group group = connector.fetchGrouperGroup(groupName);

        if (!connector.shouldSyncGroup(group)) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping group add, nothing to do cause the group is not flagged or is gone.", consumerName,
                    toString(changeLogEntry));
            return;
        }

        try {
            connector.createGooGroupIfNecessary(group);
        } catch (IOException e) {
            LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group add: {}",  new Object[] {consumerName, toString(changeLogEntry), e});
        }

    }

    /**
     * Delete a group.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processGroupDelete(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing group delete.", consumerName, toString(changeLogEntry));

        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_DELETE.name);

        //For PIT testing, uncomment the following line and wait a couple of minutes after testing and the cache will clear forcing the PIT to be used.
        //connector.getSyncedGroupsAndStems().clear();

        final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' The group object is null: {} (if true, then the PIT info will be used.)", new Object[]{consumerName, toString(changeLogEntry), grouperGroup == null});

        if (grouperGroup != null) {
            if (!connector.shouldSyncStem(grouperGroup.getParentStem())) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping group delete, nothing to do cause the group is not flagged or is gone.", consumerName,
                        toString(changeLogEntry));
                return;
            }

            try {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Trying to delete via Grouper Group data", consumerName, toString(changeLogEntry));

                connector.deleteGooGroup(grouperGroup);
                return;
            } catch (IOException e) {
                LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group delete: {}", new Object[]{consumerName, toString(changeLogEntry), e.getMessage()});
            }
        } else {
            PITGroup group = PITGroupFinder.findByName(groupName, false, true).iterator().next();

            if (!connector.shouldSyncStem(group.getPITStem().getName())) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping PIT-based group delete, nothing to do cause the group is not flagged or is gone.", consumerName,
                        toString(changeLogEntry));
                return;
            }

            try {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Trying to delete via Grouper PITGroup data", consumerName, toString(changeLogEntry));

                connector.deleteGooGroup(group);
                return;
            } catch (IOException e) {
                LOG.error("Google Apps Consumer '{}' - Change log entry '{}' Error processing group delete: {}", new Object[]{consumerName, toString(changeLogEntry), e.getMessage()});
            }
        }
    }

    /**
     * Update a group.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processGroupUpdate(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing group update.", consumerName, toString(changeLogEntry));

        final String groupId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.id);
        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.name);
        final String propertyChanged = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyChanged);
        final String propertyOldValue = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyOldValue);
        final String propertyNewValue = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyNewValue);

        Group group;
        edu.internet2.middleware.grouper.Group grouperGroup;

        try {
            grouperGroup = connector.fetchGrouperGroup(groupName);
            if (!connector.shouldSyncGroup(grouperGroup)) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping group update, nothing to do cause the group is not flagged or is gone.", consumerName,
                        toString(changeLogEntry));
                return;
            }

            //Group moves are a bit different than just a property change, let's take care of it now.
            if (propertyChanged.equalsIgnoreCase("name")) {
                String oldAddress = connector.getAddressFormatter().qualifyGroupAddress(propertyOldValue, groupId);
                String newAddress = connector.getAddressFormatter().qualifyGroupAddress(propertyNewValue, groupId);

                group = connector.fetchGooGroup(oldAddress);

                if (group != null) {
                    group.setEmail(newAddress);

                    if (group.getAliases() == null) {
                        group.setAliases(new ArrayList(1));
                    }

                    group.getAliases().add(oldAddress);

                    connector.getSyncedGroupsAndStems().remove(groupName);
                    GoogleCacheManager.googleGroups().remove(oldAddress);
                    GoogleCacheManager.googleGroups().put(connector.updateGooGroup(oldAddress, group));
                }

                return;
            }

            group = connector.fetchGooGroup(connector.getAddressFormatter().qualifyGroupAddress(groupName, groupId));

            if (propertyChanged.equalsIgnoreCase("displayExtension")) {
                group.setName(propertyNewValue);

            } else if (propertyChanged.equalsIgnoreCase("description")) {
                group.setDescription(propertyNewValue);

            } else {
                LOG.warn("Google Apps Consumer '{}' - Change log entry '{}' Unmapped group property updated {}.",
                        new Object[] {consumerName, toString(changeLogEntry), propertyChanged});
            }

            GoogleCacheManager.googleGroups().put(connector.updateGooGroup(connector.getAddressFormatter().qualifyGroupAddress(groupName, groupId), group));

        } catch (IOException e) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Error processing group update.", consumerName, toString(changeLogEntry));
        }
    }

    /**
     * Add a membership.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processMembershipAdd(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing membership add.", consumerName,
                toString(changeLogEntry));

        final String groupId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.groupId);
        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.groupName);
        final String memberId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.memberId);
        final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);
        final Member member = MemberFinder.findByUuid(GrouperSession.staticGrouperSession(), memberId, false);

        if (!connector.shouldSyncGroup(grouperGroup)) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping membership add, nothing to do cause the group is not flagged or is gone.", consumerName,
                    toString(changeLogEntry));
            return;
        }

        final String subjectId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.subjectId);
        final String sourceId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.sourceId);
        final Subject lookupSubject = connector.fetchGrouperSubject(sourceId, subjectId);
        final SubjectType subjectType = lookupSubject.getType();

        try {
            Group group = connector.fetchGooGroup(connector.getAddressFormatter().qualifyGroupAddress(groupName, groupId));
            if (group == null) {
                connector.createGooGroupIfNecessary(grouperGroup);
                group = connector.fetchGooGroup(connector.getAddressFormatter().qualifyGroupAddress(groupName, groupId));
            }

            //For nested groups, ChangeLogEvents fire when the group is added, and also for each indirect user added,
            //so we only need to handle PERSON events.
            if (subjectType == SubjectTypeEnum.PERSON) {
                User user = connector.fetchGooUser(connector.getAddressFormatter().qualifySubjectAddress(lookupSubject));
                if (user == null) {
                    user = connector.createGooUser(lookupSubject);
                }

                if (user != null) {
                    String role = connector.determineRole(member, grouperGroup);
                    if (role != null && !role.equalsIgnoreCase("NONE")) {
                      connector.createGooMember(group, user, role);
                    }
                }
            }

        } catch (IOException e) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Error processing membership add failed: {}", new Object[] {consumerName,
                    toString(changeLogEntry), e});
        }
    }

    /**
     * Delete a membership entry.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processMembershipDelete(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing membership delete.", consumerName,
                toString(changeLogEntry));

        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.groupName);
        final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);

        if (!connector.shouldSyncGroup(grouperGroup)) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping membership delete, nothing to do cause the group is not flagged or is gone.", consumerName,
                    toString(changeLogEntry));
            return;
        }

        final String memberId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.memberId);
        final String subjectId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.subjectId);
        final String sourceId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.sourceId);
        final Subject lookupSubject = connector.fetchGrouperSubject(sourceId, subjectId);
        final SubjectType subjectType = lookupSubject.getType();
        final Member member = MemberFinder.findByUuid(GrouperSession.staticGrouperSession(), memberId, false);

        //For nested groups, ChangeLogEvents fire when the group is removed, and also for each indirect user added,
        //so we only need to handle PERSON events.
        if (member.getSubjectType() == SubjectTypeEnum.PERSON) {
            try {
                String role = connector.determineRole(member, grouperGroup);
                if (role != null && !role.equalsIgnoreCase("NONE")) {
                    connector.updateGooMember(grouperGroup, member.getSubject(), role);
                } else {
                    connector.removeGooMembership(grouperGroup.getName(), grouperGroup.getId(), member.getSubject());
                }
            } catch (IOException e) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Error processing membership delete: {}", new Object[]{consumerName,
                        toString(changeLogEntry), e});
            }
        }
    }

    protected void processPrivilegeAdd(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {
        final String ROLE = "MEMBER"; //Other types are ADMIN and OWNER. Neither makes sense for managed groups.

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing privilege add.", consumerName,
                toString(changeLogEntry));

        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_ADD.ownerName);
        final String privilegeName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_ADD.privilegeName);
        final String memberId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_ADD.memberId);

        final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);
        final Member member = MemberFinder.findByUuid(GrouperSession.staticGrouperSession(), memberId, false);

        if (!connector.shouldSyncGroup(grouperGroup)) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping privilege add, nothing to do cause the group is not flagged or is gone.", consumerName,
                    toString(changeLogEntry));

            return;
        }

        if (member.getSubjectType() == SubjectTypeEnum.PERSON) {
            try {
                String role = connector.determineRole(member, grouperGroup);
                if (role != null && !role.equalsIgnoreCase("NONE")) {
                    connector.updateGooMember(grouperGroup, member.getSubject(), role);
                } else {
                    connector.removeGooMembership(grouperGroup.getName(), grouperGroup.getId(), member.getSubject());
                }
            } catch (IOException e) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Error processing privilege add: {}", new Object[]{consumerName,
                        toString(changeLogEntry), e});
            }
        }

    }

    /**
     * Update a privilege entry.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processPrivilegeUpdate(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing privilege update.", consumerName,
                toString(changeLogEntry));

        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_UPDATE.ownerName);
        final String privilegeName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_UPDATE.privilegeName);
        final String memberId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_UPDATE.id);

        final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);
        final Member member = MemberFinder.findByUuid(GrouperSession.staticGrouperSession(), memberId, false);

        if (!connector.shouldSyncGroup(grouperGroup)) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping privilege update, nothing to do cause the group is not flagged or is gone.", consumerName,
                    toString(changeLogEntry));

            return;
        }

        if (member.getSubjectType() == SubjectTypeEnum.PERSON) {
            try {
                String role = connector.determineRole(member, grouperGroup);
                if (role != null && !role.equalsIgnoreCase("NONE")) {
                    connector.updateGooMember(grouperGroup, member.getSubject(), role);
                } else {
                    connector.removeGooMembership(grouperGroup.getName(), grouperGroup.getId(), member.getSubject());
                }
            } catch (IOException e) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Error processing privilege update: {}", new Object[]{consumerName,
                        toString(changeLogEntry), e});
            }
        }

    }

    /**
     * Delete a privilege entry.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processPrivilegeDelete(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing privilege delete.", consumerName,
                toString(changeLogEntry));

        final String groupName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_DELETE.ownerName);
        final String privilegeName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_DELETE.privilegeName);
        final String memberId = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.PRIVILEGE_DELETE.memberId);

        final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);
        final Member member = MemberFinder.findByUuid(GrouperSession.staticGrouperSession(), memberId, false);

        if (!connector.shouldSyncGroup(grouperGroup)) {
            LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Skipping privilege delete, nothing to do cause the group is not flagged or is gone", consumerName,
                    toString(changeLogEntry));

            return;
        }

        if (member.getSubjectType() == SubjectTypeEnum.PERSON) {
            try {
                String role = connector.determineRole(member, grouperGroup);
                if (role != null && !role.equalsIgnoreCase("NONE")) {
                    connector.updateGooMember(grouperGroup, member.getSubject(), role);
                } else {
                    connector.removeGooMembership(grouperGroup.getName(), grouperGroup.getId(), member.getSubject());
                }

            } catch (IOException e) {
                LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Error processing privilege delete: {}",
                        new Object[]{consumerName, toString(changeLogEntry), e});
            }
        }

    }

    /**
     * Delete a stem, but we generally don't care since the stem has to be empty before it can be deleted.
     *
     * @param consumer the change log consumer
     * @param changeLogEntry the change log entry
     */
    protected void processStemDelete(GoogleAppsChangeLogConsumer consumer, ChangeLogEntry changeLogEntry) {

        LOG.debug("Google Apps Consumer '{}' - Change log entry '{}' Processing stem delete.", consumerName, toString(changeLogEntry));

        final String stemName = changeLogEntry.retrieveValueForLabel(ChangeLogLabels.STEM_DELETE.name);

        connector.getSyncedGroupsAndStems().remove(stemName);
    }

    /**
     * Gets a simple string representation of the change log entry.
     *
     * @param changeLogEntry the change log entry
     * @return the simple string representation of the change log entry
     */
    private static String toString(ChangeLogEntry changeLogEntry) {
        final ToStringBuilder toStringBuilder = new ToStringBuilder(changeLogEntry, ToStringStyle.SHORT_PREFIX_STYLE);
        toStringBuilder.append("timestamp", changeLogEntry.getCreatedOn())
                .append("sequence", changeLogEntry.getSequenceNumber())
                .append("category", changeLogEntry.getChangeLogType().getChangeLogCategory())
                .append("actionName", changeLogEntry.getChangeLogType().getActionName())
                .append("contextId", changeLogEntry.getContextId());
        return toStringBuilder.toString();
    }

    /**
     * Gets a deep string representation of the change log entry.
     *
     * @param changeLogEntry the change log entry
     * @return the deep string representation of the change log entry
     */
    private static String toStringDeep(ChangeLogEntry changeLogEntry) {
        final ToStringBuilder toStringBuilder = new ToStringBuilder(changeLogEntry, ToStringStyle.SHORT_PREFIX_STYLE);
        toStringBuilder.append("timestamp", changeLogEntry.getCreatedOn())
                .append("sequence", changeLogEntry.getSequenceNumber())
                .append("category", changeLogEntry.getChangeLogType().getChangeLogCategory())
                .append("actionName", changeLogEntry.getChangeLogType().getActionName())
                .append("contextId", changeLogEntry.getContextId());

        final ChangeLogType changeLogType = changeLogEntry.getChangeLogType();

        for (String label : changeLogType.labels()) {
            toStringBuilder.append(label, changeLogEntry.retrieveValueForLabel(label));
        }

        return toStringBuilder.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy