/*
* Licensed to the University Corporation for Advanced Internet Development,
* Inc. (UCAID) under one or more contributor license agreements. See the
* NOTICE file distributed with this work for additional information regarding
* copyright ownership. The UCAID 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 edu.internet2.middleware.changelogconsumer.googleapps;
import com.google.api.services.admin.directory.model.Group;
import com.google.api.services.admin.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.attr.AttributeDefName;
import edu.internet2.middleware.grouper.attr.assign.AttributeAssignType;
import edu.internet2.middleware.grouper.changeLog.*;
import edu.internet2.middleware.grouper.Stem.Scope;
import edu.internet2.middleware.grouper.privs.Privilege;
import edu.internet2.middleware.subject.Subject;
import edu.internet2.middleware.subject.SubjectType;
import edu.internet2.middleware.subject.provider.SubjectTypeEnum;
import java.io.IOException;
import java.util.*;
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;
/**
* 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(GoogleAppsFullSync.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<ChangeLogEntry> 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());
// 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 (lastContextId == null) {
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.equals(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);
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);
final Set<edu.internet2.middleware.grouper.Group> 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) {
final edu.internet2.middleware.grouper.Group group = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), ownerId, false);
try {
connector.deleteGooGroup(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);
final Set<edu.internet2.middleware.grouper.Group> 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);
final edu.internet2.middleware.grouper.Group grouperGroup = connector.fetchGrouperGroup(groupName);
if (!connector.shouldSyncGroup(grouperGroup)) {
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 {
connector.deleteGooGroup(grouperGroup);
} 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 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);
String newAddress = connector.getAddressFormatter().qualifyGroupAddress(propertyNewValue);
group = connector.fetchGooGroup(oldAddress);
if (group != null) {
group.setEmail(newAddress);
if (group.getAliases() == null) {
group.setAliases(new ArrayList<String>(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));
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), 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 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));
if (group == null) {
connector.createGooGroupIfNecessary(grouperGroup);
group = connector.fetchGooGroup(connector.getAddressFormatter().qualifyGroupAddress(groupName));
}
//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(subjectId));
if (user == null) {
user = connector.createGooUser(lookupSubject);
}
if (user != null) {
connector.createGooMember(group, user, connector.determineRole(member, grouperGroup));
}
}
} 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 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();
//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 (subjectType == SubjectTypeEnum.PERSON) {
try {
connector.removeGooMembership(groupName, lookupSubject);
} 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 {
connector.createGooMember(grouperGroup, member.getSubject(), connector.determineRole(member, grouperGroup));
} 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 {
connector.updateGooMember(grouperGroup, member.getSubject(), connector.determineRole(member, grouperGroup));
} 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 {
if (grouperGroup.hasMember(member.getSubject())) {
connector.updateGooMember(grouperGroup, member.getSubject(), connector.determineRole(member, grouperGroup));
} else {
connector.removeGooMembership(grouperGroup.getName(), 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();
}
}