edu.internet2.middleware.changelogconsumer.googleapps.GoogleAppsChangeLogConsumer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of google-apps-provisioner Show documentation
Show all versions of google-apps-provisioner Show documentation
Google Apps Integration Library
/*******************************************************************************
* 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();
}
}