diff --git a/container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.class b/container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.class new file mode 100644 index 00000000..ad9971a5 Binary files /dev/null and b/container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.class differ diff --git a/container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.java b/container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.java new file mode 100644 index 00000000..2fe7d6f1 --- /dev/null +++ b/container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.java @@ -0,0 +1,846 @@ +package edu.internet2.middleware.grouper.app.tableSync; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; + +import edu.internet2.middleware.grouper.GrouperSession; +import edu.internet2.middleware.grouper.Member; +import edu.internet2.middleware.grouper.MemberFinder; +import edu.internet2.middleware.grouper.app.loader.GrouperLoaderConfig; +import edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioner; +import edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningObjectAttributes; +import edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningSettings; +import edu.internet2.middleware.grouper.app.provisioning.ProvisioningEntity; +import edu.internet2.middleware.grouper.app.provisioning.ProvisioningEntityWrapper; +import edu.internet2.middleware.grouper.app.provisioning.ProvisioningMembership; +import edu.internet2.middleware.grouper.app.provisioning.ProvisioningMembershipWrapper; +import edu.internet2.middleware.grouper.util.GrouperUtil; +import edu.internet2.middleware.grouperClient.collections.MultiKey; +import edu.internet2.middleware.grouperClient.jdbc.tableSync.GcGrouperSync; +import edu.internet2.middleware.grouperClient.jdbc.tableSync.GcGrouperSyncGroup; +import edu.internet2.middleware.grouperClient.jdbc.tableSync.GcGrouperSyncMember; +import edu.internet2.middleware.grouperClient.jdbc.tableSync.GcGrouperSyncMembership; +import edu.internet2.middleware.grouperClient.util.GrouperClientUtils; + +/** + * Sync up provisioning attributes with grouper group sync provisionable attributes + */ +public class ProvisioningSyncIntegration { + + public ProvisioningSyncIntegration() { + + } + + public static void fullSyncGroups(ProvisioningSyncResult provisioningSyncGroupResult, GcGrouperSync gcGrouperSync, + List initialGcGrouperSyncGroups, Map groupUuidToProvisioningObjectAttributes) { + + if (gcGrouperSync == null || StringUtils.isBlank(gcGrouperSync.getProvisionerName())) { + throw new RuntimeException("provisioner name is required"); + } + + if (!GrouperProvisioningSettings.getTargets(true).containsKey(gcGrouperSync.getProvisionerName())) { + throw new RuntimeException("Target '" + gcGrouperSync.getProvisionerName() + + "' is not configured. Go to Miscellaneous -> Provisioning to configure a new target."); + } + + Map groupUuidToSyncGroup = new HashMap(); + + initialGcGrouperSyncGroups = GrouperUtil.nonNull(initialGcGrouperSyncGroups); + + for (GcGrouperSyncGroup gcGrouperSyncGroup : initialGcGrouperSyncGroups) { + groupUuidToSyncGroup.put(gcGrouperSyncGroup.getGroupId(), gcGrouperSyncGroup); + } + + int removeSyncRowsAfterSecondsOutOfTarget = GrouperLoaderConfig.retrieveConfig().propertyValueInt( + "grouper.provisioning.removeSyncRowsAfterSecondsOutOfTarget", 60*60*24*7); + + provisioningSyncGroupResult.setGcGrouperSync(gcGrouperSync); + + // start group ids to insert with all group ids minus those which have sync group objects already + Set groupIdsToInsert = new HashSet(groupUuidToProvisioningObjectAttributes.keySet()); + provisioningSyncGroupResult.setGroupIdsToInsert(groupIdsToInsert); + groupIdsToInsert.removeAll(groupUuidToSyncGroup.keySet()); + + Set groupIdsToUpdate = new HashSet(); + provisioningSyncGroupResult.setGroupIdsToUpdate(groupIdsToUpdate); + + List gcGrouperSyncRowsToDeleteFromDatabase = new ArrayList(); + + Set groupIdsWithChangedIdIndexes = new HashSet(); + provisioningSyncGroupResult.setGroupIdsWithChangedIdIndexes(groupIdsWithChangedIdIndexes); + + Set groupIdsWithChangedNames = new HashSet(); + provisioningSyncGroupResult.setGroupIdsWithChangedNames(groupIdsWithChangedNames); + + + // lets remove ones that dont need to be there + if (GrouperUtil.length(groupUuidToSyncGroup) > 0) { + + // make an array list so we can remove from the map without exception + List gcGrouperSyncGroups = new ArrayList(groupUuidToSyncGroup.values()); + + for (GcGrouperSyncGroup gcGrouperSyncGroup : gcGrouperSyncGroups) { + + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes = groupUuidToProvisioningObjectAttributes.get(gcGrouperSyncGroup.getGroupId()); + + String newGroupName = grouperProvisioningObjectAttributes == null ? null : grouperProvisioningObjectAttributes.getName(); + Long newGroupIdIndex = grouperProvisioningObjectAttributes == null ? null : grouperProvisioningObjectAttributes.getIdIndex(); + String newMetadataJson = grouperProvisioningObjectAttributes == null ? null : grouperProvisioningObjectAttributes.getProvisioningMetadataJson(); + boolean groupIsProvisionable = grouperProvisioningObjectAttributes != null; + + gcGrouperSyncGroup.setMetadataJson(newMetadataJson); + + processSyncGroup(groupUuidToSyncGroup, + removeSyncRowsAfterSecondsOutOfTarget, groupIdsToInsert, groupIdsToUpdate, + gcGrouperSyncRowsToDeleteFromDatabase, groupIdsWithChangedIdIndexes, + groupIdsWithChangedNames, gcGrouperSyncGroup, grouperProvisioningObjectAttributes, + newGroupName, newGroupIdIndex, newMetadataJson, groupIsProvisionable); + } + + gcGrouperSync.getGcGrouperSyncGroupDao().groupDelete(gcGrouperSyncRowsToDeleteFromDatabase, true, true); + } + + if (GrouperUtil.length(groupIdsToInsert) > 0) { + + Map mapGroupIdToSyncGroupInsert = gcGrouperSync.getGcGrouperSyncGroupDao().groupRetrieveOrCreateByGroupIds(groupIdsToInsert); + + for (String groupIdToInsert : mapGroupIdToSyncGroupInsert.keySet()) { + + GcGrouperSyncGroup gcGrouperSyncGroup = mapGroupIdToSyncGroupInsert.get(groupIdToInsert); + initialGcGrouperSyncGroups.add(gcGrouperSyncGroup); + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes = groupUuidToProvisioningObjectAttributes.get(groupIdToInsert); + + if (grouperProvisioningObjectAttributes == null) { + continue; + } + String groupName = grouperProvisioningObjectAttributes.getName(); + Long groupIdIndex = grouperProvisioningObjectAttributes.getIdIndex(); + String groupMetadataJson = grouperProvisioningObjectAttributes.getProvisioningMetadataJson(); + + processSyncGroupInsert(gcGrouperSync, groupUuidToSyncGroup, groupIdToInsert, + gcGrouperSyncGroup, groupName, groupIdIndex, groupMetadataJson); + } + + } + + Set groupIdsToDelete = new HashSet(groupUuidToSyncGroup.keySet()); + + provisioningSyncGroupResult.setGroupIdsToDelete(groupIdsToDelete); + + groupIdsToDelete.removeAll(groupUuidToProvisioningObjectAttributes.keySet()); + + processSyncGroupDelete(groupUuidToSyncGroup, groupIdsToDelete); + + } + + public static void processSyncGroupDelete( + Map groupUuidToSyncGroup, + Set groupIdsToDelete) { + if (GrouperUtil.length(groupIdsToDelete) > 0) { + + Iterator groupIdToDeleteIterator = groupIdsToDelete.iterator(); + + while (groupIdToDeleteIterator.hasNext()) { + + String groupIdToDelete = groupIdToDeleteIterator.next(); + + GcGrouperSyncGroup gcGrouperSyncGroup = groupUuidToSyncGroup.get(groupIdToDelete); + + if (gcGrouperSyncGroup == null) { + throw new RuntimeException("why is gcGrouperSyncGroup null???"); + } + + if (gcGrouperSyncGroup.isProvisionable() || gcGrouperSyncGroup.getProvisionableEnd() == null) { + gcGrouperSyncGroup.setProvisionable(false); + gcGrouperSyncGroup.setProvisionableEnd(new Timestamp(System.currentTimeMillis())); + } + + // if we arent in target, dont worry about it + if (!gcGrouperSyncGroup.isInTarget() ) { + groupIdToDeleteIterator.remove(); + groupUuidToSyncGroup.remove(gcGrouperSyncGroup.getGroupId()); + } + + } + + } + } + + public static void processSyncMemberDelete( + Map memberUuidToSyncMember, + Set memberIdsToDelete) { + + if (GrouperUtil.length(memberIdsToDelete) > 0) { + + Iterator memberIdToDeleteIterator = memberIdsToDelete.iterator(); + + while (memberIdToDeleteIterator.hasNext()) { + + String memberIdToDelete = memberIdToDeleteIterator.next(); + + GcGrouperSyncMember gcGrouperSyncMember = memberUuidToSyncMember.get(memberIdToDelete); + + if (gcGrouperSyncMember == null) { + throw new RuntimeException("why is gcGrouperSyncMember null???"); + } + + if (gcGrouperSyncMember.isProvisionable() || gcGrouperSyncMember.getProvisionableEnd() == null) { + gcGrouperSyncMember.setProvisionable(false); + gcGrouperSyncMember.setProvisionableEnd(new Timestamp(System.currentTimeMillis())); + } + + // if we arent in target, dont worry about it + if (!gcGrouperSyncMember.isInTarget() ) { + memberIdToDeleteIterator.remove(); + memberUuidToSyncMember.remove(gcGrouperSyncMember.getMemberId()); + } + + } + + } + } + + public static void processSyncGroupInsert(GcGrouperSync gcGrouperSync, + Map groupUuidToSyncGroup, String groupIdToInsert, + GcGrouperSyncGroup gcGrouperSyncGroup, String groupName, + Long groupIdIndex, String metadataJson) { + if (gcGrouperSyncGroup == null) { + gcGrouperSyncGroup = gcGrouperSync.getGcGrouperSyncGroupDao().groupCreateByGroupId(groupIdToInsert); + } + gcGrouperSyncGroup.setGroupName(groupName); + gcGrouperSyncGroup.setGroupIdIndex(groupIdIndex); + gcGrouperSyncGroup.setMetadataJson(metadataJson); + gcGrouperSyncGroup.setProvisionable(true); + gcGrouperSyncGroup.setProvisionableStart(new Timestamp(System.currentTimeMillis())); + groupUuidToSyncGroup.put(groupIdToInsert, gcGrouperSyncGroup); + } + + public static void processSyncGroup( + Map groupUuidToSyncGroup, + int removeSyncRowsAfterSecondsOutOfTarget, Set groupIdsToInsert, + Set groupIdsToUpdate, + List gcGrouperSyncRowsToDeleteFromDatabase, + Set groupIdsWithChangedIdIndexes, Set groupIdsWithChangedNames, + GcGrouperSyncGroup gcGrouperSyncGroup, + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes, String newGroupName, + Long newGroupIdIndex, String newMetadataJson, boolean groupIsProvisionable) { + +// { +// // is in grouper? +// Boolean inGrouper = null; +// if (inGrouper == null && provisioningGroupWrapper != null && provisioningGroupWrapper.isDelete()) { +// inGrouper = false; +// } +// if (inGrouper == null && provisioningGroupWrapper.getGrouperProvisioningGroup() != null) { +// inGrouper = true; +// } +// if (inGrouper == null && groupIsProvisionable) { +// inGrouper = true; +// } +// if (inGrouper == null) { +// inGrouper = false; +// } +// if (gcGrouperSyncGroup.getInGrouper() != inGrouper) { +// if (gcGrouperSyncGroup.getInGrouperInsertOrExistsDb() == null) { +// gcGrouperSyncGroup.setInTargetInsertOrExists(false); +// } +// gcGrouperSyncGroup.setInGrouper(inGrouper); +// if (inGrouper) { +// gcGrouperSyncGroup.setInGrouperStart(new Timestamp(System.currentTimeMillis())); +// } else { +// gcGrouperSyncGroup.setInGrouperEnd(new Timestamp(System.currentTimeMillis())); +// } +// } +// } +// + // keep it + if (groupIsProvisionable || gcGrouperSyncGroup.isProvisionable() || gcGrouperSyncGroup.isInTarget()) { + + // see if needs to update + { + if (!StringUtils.equals(newGroupName, gcGrouperSyncGroup.getGroupName())) { + groupIdsWithChangedNames.add(gcGrouperSyncGroup.getGroupId()); + if (newGroupName != null) { + gcGrouperSyncGroup.setGroupName(newGroupName); + } + } + } + + { + if (!GrouperUtil.equals(newGroupIdIndex, gcGrouperSyncGroup.getGroupIdIndex())) { + groupIdsWithChangedIdIndexes.add(gcGrouperSyncGroup.getGroupId()); + if (newGroupIdIndex != null) { + gcGrouperSyncGroup.setGroupIdIndex(newGroupIdIndex); + } + } + } + + // see if not provisionable + if (!gcGrouperSyncGroup.isProvisionable() && groupIsProvisionable) { + gcGrouperSyncGroup.setProvisionableStart(new Timestamp(System.currentTimeMillis())); + gcGrouperSyncGroup.setProvisionableEnd(null); + gcGrouperSyncGroup.setProvisionable(true); + } + if (gcGrouperSyncGroup.isProvisionable() && !groupIsProvisionable) { + gcGrouperSyncGroup.setProvisionableEnd(new Timestamp(System.currentTimeMillis())); + gcGrouperSyncGroup.setProvisionable(false); + } + + // see if not provisionable + if (!gcGrouperSyncGroup.isInTarget() && groupIsProvisionable) { + groupIdsToInsert.add(gcGrouperSyncGroup.getGroupId()); + } + + if (gcGrouperSyncGroup.dbVersionDifferent()) { + groupIdsToUpdate.add(gcGrouperSyncGroup.getGroupId()); + } + + } + + groupUuidToSyncGroup.remove(gcGrouperSyncGroup.getGroupId()); + + //if we arent provisionable, and the group has not been in the target for a week, then we done with that one + if (!gcGrouperSyncGroup.isInTarget() && !gcGrouperSyncGroup.isProvisionable() && gcGrouperSyncGroup.getInTargetEnd() != null) { + long targetEndMillis = gcGrouperSyncGroup.getInTargetEnd() == null ? 0 : gcGrouperSyncGroup.getInTargetEnd().getTime(); + targetEndMillis = Math.max(targetEndMillis, gcGrouperSyncGroup.getProvisionableEnd() == null ? 0 : gcGrouperSyncGroup.getProvisionableEnd().getTime()); + targetEndMillis = Math.max(targetEndMillis, gcGrouperSyncGroup.getLastUpdated() == null ? 0 : gcGrouperSyncGroup.getLastUpdated().getTime()); + if (targetEndMillis != 0 &&( (System.currentTimeMillis() - targetEndMillis) / 1000 > removeSyncRowsAfterSecondsOutOfTarget)) { + gcGrouperSyncRowsToDeleteFromDatabase.add(gcGrouperSyncGroup); + } + } + } + + public static void fullSyncMembers(GrouperProvisioner grouperProvisioner, ProvisioningSyncResult provisioningSyncResult, GcGrouperSync gcGrouperSync, + List initialGcGrouperSyncMembers, + Map memberUuidToProvisioningObjectAttributes) { + + if (gcGrouperSync == null || StringUtils.isBlank(gcGrouperSync.getProvisionerName())) { + throw new RuntimeException("provisioner name is required"); + } + + if (!GrouperProvisioningSettings.getTargets(true).containsKey(gcGrouperSync.getProvisionerName())) { + throw new RuntimeException("Target '" + gcGrouperSync.getProvisionerName() + + "' is not configured. Go to Miscellaneous -> Provisioning to configure a new target."); + } + + Map memberUuidToSyncMember = new HashMap(); + + initialGcGrouperSyncMembers = GrouperUtil.nonNull(initialGcGrouperSyncMembers); + + for (GcGrouperSyncMember gcGrouperSyncMember : initialGcGrouperSyncMembers) { + memberUuidToSyncMember.put(gcGrouperSyncMember.getMemberId(), gcGrouperSyncMember); + } + + int removeSyncRowsAfterSecondsOutOfTarget = GrouperLoaderConfig.retrieveConfig().propertyValueInt( + "grouper.provisioning.removeSyncRowsAfterSecondsOutOfTarget", 60*60*24*7); + + provisioningSyncResult.setGcGrouperSync(gcGrouperSync); + + // start member ids to insert with all member ids minus those which have sync member objects already + Set memberIdsToInsert = new HashSet(memberUuidToProvisioningObjectAttributes.keySet()); + provisioningSyncResult.setMemberIdsToInsert(memberIdsToInsert); + memberIdsToInsert.removeAll(memberUuidToSyncMember.keySet()); + + Set memberIdsToUpdate = new HashSet(); + provisioningSyncResult.setMemberIdsToUpdate(memberIdsToUpdate); + + Set gcGrouperSyncRowsToDeleteFromDatabase = new HashSet(); + + Set memberIdsWithChangedSubjectIds = new HashSet(); + provisioningSyncResult.setMemberIdsWithChangedSubjectIds(memberIdsWithChangedSubjectIds); + + // lets remove ones that dont need to be there + if (GrouperUtil.length(memberUuidToSyncMember) > 0) { + + // make an array list so we can remove from the map without exception + List gcGrouperSyncMembers = new ArrayList(memberUuidToSyncMember.values()); + + for (GcGrouperSyncMember gcGrouperSyncMember: gcGrouperSyncMembers) { + + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes = memberUuidToProvisioningObjectAttributes.get(gcGrouperSyncMember.getMemberId()); + + String newMetadataJson = grouperProvisioningObjectAttributes == null ? null : grouperProvisioningObjectAttributes.getProvisioningMetadataJson(); + gcGrouperSyncMember.setMetadataJson(newMetadataJson); + + //if we arent provisionable, and the member has not been in the target for a week, then we done with that one + if (!gcGrouperSyncMember.isInTarget() && !gcGrouperSyncMember.isProvisionable() && gcGrouperSyncMember.getInTargetEnd() != null) { + long targetEndMillis = gcGrouperSyncMember.getInTargetEnd() == null ? 0 : gcGrouperSyncMember.getInTargetEnd().getTime(); + targetEndMillis = Math.max(targetEndMillis, gcGrouperSyncMember.getProvisionableEnd() == null ? 0 : gcGrouperSyncMember.getProvisionableEnd().getTime()); + targetEndMillis = Math.max(targetEndMillis, gcGrouperSyncMember.getLastUpdated() == null ? 0 : gcGrouperSyncMember.getLastUpdated().getTime()); + if (targetEndMillis != 0 &&( (System.currentTimeMillis() - targetEndMillis) / 1000 > removeSyncRowsAfterSecondsOutOfTarget)) { + gcGrouperSyncRowsToDeleteFromDatabase.add(gcGrouperSyncMember); + } + } + + } + + gcGrouperSync.getGcGrouperSyncMemberDao().memberDelete(gcGrouperSyncRowsToDeleteFromDatabase, true, true); + } + + // fix missing subject id or source id + Set gcGrouperSyncRowsToFixSubjectIdOrSourceId = new HashSet(); + for (GcGrouperSyncMember gcGrouperSyncMember : GrouperUtil.nonNull(memberUuidToSyncMember).values()) { + if (gcGrouperSyncRowsToDeleteFromDatabase.contains(gcGrouperSyncMember)) { + continue; + } + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSourceId()) || GrouperClientUtils.isBlank(gcGrouperSyncMember.getSubjectId())) { + gcGrouperSyncRowsToFixSubjectIdOrSourceId.add(gcGrouperSyncMember); + } + } + + // null subject id issue + // GRP-4137: error resolving subject attributes. has null subject id and subject identifier + for (GcGrouperSyncMember gcGrouperSyncMember : gcGrouperSyncRowsToFixSubjectIdOrSourceId) { + + // try by query + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes = memberUuidToProvisioningObjectAttributes.get(gcGrouperSyncMember.getMemberId()); + + decorateSyncMemberSubjectInformationIfNull(grouperProvisioner, gcGrouperSyncMember, + grouperProvisioningObjectAttributes); + } + + if (GrouperUtil.length(memberIdsToInsert) > 0) { + + Map mapMemberIdToSyncMemberInsert = gcGrouperSync.getGcGrouperSyncMemberDao().memberRetrieveOrCreateByMemberIds(memberIdsToInsert); + + for (String memberIdToInsert : mapMemberIdToSyncMemberInsert.keySet()) { + + GcGrouperSyncMember gcGrouperSyncMember = mapMemberIdToSyncMemberInsert.get(memberIdToInsert); + initialGcGrouperSyncMembers.add(gcGrouperSyncMember); + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes = memberUuidToProvisioningObjectAttributes.get(memberIdToInsert); + + if (grouperProvisioningObjectAttributes == null) { + continue; + } + String sourceId = grouperProvisioningObjectAttributes.getSourceId(); + String subjectId = grouperProvisioningObjectAttributes.getSubjectId(); + String subjectIdentifier = grouperProvisioningObjectAttributes.getSubjectIdentifier0(); + if ("subjectIdentifier1".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + subjectIdentifier = grouperProvisioningObjectAttributes.getSubjectIdentifier1(); + } else if ("subjectIdentifier2".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + subjectIdentifier = grouperProvisioningObjectAttributes.getSubjectIdentifier2(); + } + String metadataJson = grouperProvisioningObjectAttributes.getProvisioningMetadataJson(); + + if (gcGrouperSyncMember == null) { + gcGrouperSyncMember = gcGrouperSync.getGcGrouperSyncMemberDao().memberCreateByMemberId(memberIdToInsert); + } + + gcGrouperSyncMember.setSourceId(sourceId); + gcGrouperSyncMember.setSubjectId(subjectId); + gcGrouperSyncMember.setSubjectIdentifier(subjectIdentifier); +// gcGrouperSyncMember.setProvisionable(true); +// gcGrouperSyncMember.setProvisionableStart(new Timestamp(System.currentTimeMillis())); + gcGrouperSyncMember.setMetadataJson(metadataJson); + memberUuidToSyncMember.put(memberIdToInsert, gcGrouperSyncMember); + + } + + } + +// Set memberIdsToDelete = new HashSet(memberUuidToSyncMember.keySet()); +// +// provisioningSyncResult.setMemberIdsToDelete(memberIdsToDelete); +// +// memberIdsToDelete.removeAll(memberUuidToProvisioningObjectAttributes.keySet()); +// +// processSyncMemberDelete(memberUuidToSyncMember, memberIdsToDelete); + + } + + public static void decorateSyncMemberSubjectInformationIfNull(GrouperProvisioner grouperProvisioner, + GcGrouperSyncMember gcGrouperSyncMember, + GrouperProvisioningObjectAttributes grouperProvisioningObjectAttributes) { + if (grouperProvisioningObjectAttributes != null) { + String sourceId = grouperProvisioningObjectAttributes.getSourceId(); + String subjectId = grouperProvisioningObjectAttributes.getSubjectId(); + String subjectIdentifier = grouperProvisioningObjectAttributes.getSubjectIdentifier0(); + if ("subjectIdentifier1".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + subjectIdentifier = grouperProvisioningObjectAttributes.getSubjectIdentifier1(); + } else if ("subjectIdentifier2".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + subjectIdentifier = grouperProvisioningObjectAttributes.getSubjectIdentifier2(); + } + + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSourceId())) { + gcGrouperSyncMember.setSourceId(sourceId); + } + + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSubjectId())) { + gcGrouperSyncMember.setSubjectId(subjectId); + } + + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSubjectIdentifier())) { + gcGrouperSyncMember.setSubjectIdentifier(subjectIdentifier); + } + } + + // TODO batch this when the API is available + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSourceId()) || GrouperClientUtils.isBlank(gcGrouperSyncMember.getSubjectId())) { + Member member = MemberFinder.findByUuid(GrouperSession.staticGrouperSession(), gcGrouperSyncMember.getMemberId(), false); + if (member != null) { + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSourceId())) { + gcGrouperSyncMember.setSourceId(member.getSubjectSourceId()); + } + if (GrouperClientUtils.isBlank(gcGrouperSyncMember.getSubjectId())) { + gcGrouperSyncMember.setSubjectId(member.getSubjectId()); + } + } + } + } + + + public static void fullSyncMembersForInitialize(GrouperProvisioner grouperProvisioner, ProvisioningSyncResult provisioningSyncResult, GcGrouperSync gcGrouperSync, + List initialGcGrouperSyncMembers, + Map memberUuidToProvisioningEntityWrapper) { + + initialGcGrouperSyncMembers = GrouperUtil.nonNull(initialGcGrouperSyncMembers); + + Map memberUuidToSyncMember = new HashMap(); + + for (GcGrouperSyncMember gcGrouperSyncMember : initialGcGrouperSyncMembers) { + memberUuidToSyncMember.put(gcGrouperSyncMember.getMemberId(), gcGrouperSyncMember); + } + + provisioningSyncResult.setGcGrouperSync(gcGrouperSync); + + // start group ids to insert with all group ids minus those which have sync group objects already + Set memberIdsToInsert = new HashSet(memberUuidToProvisioningEntityWrapper.keySet()); + provisioningSyncResult.setMemberIdsToInsert(memberIdsToInsert); + memberIdsToInsert.removeAll(memberUuidToSyncMember.keySet()); + + Set memberIdsToUpdate = new HashSet(); + provisioningSyncResult.setMemberIdsToUpdate(memberIdsToUpdate); + + Set memberIdsWithChangedSubjectIds = new HashSet(); + provisioningSyncResult.setMemberIdsWithChangedSubjectIds(memberIdsWithChangedSubjectIds); + + // lets remove ones that dont need to be there + if (GrouperUtil.length(memberUuidToSyncMember) > 0) { + + // make an array list so we can remove from the map without exception + List gcGrouperSyncMembers = new ArrayList(memberUuidToSyncMember.values()); + + for (GcGrouperSyncMember gcGrouperSyncMember : gcGrouperSyncMembers) { + + ProvisioningEntityWrapper provisioningEntityWrapper = memberUuidToProvisioningEntityWrapper.get(gcGrouperSyncMember.getMemberId()); + + ProvisioningEntity grouperProvisioningEntity = provisioningEntityWrapper == null ? null : provisioningEntityWrapper.getGrouperProvisioningEntity(); + + // keep it + if (grouperProvisioningEntity != null || gcGrouperSyncMember.isProvisionable() || gcGrouperSyncMember.isInTarget()) { + + if (grouperProvisioningEntity != null && StringUtils.isBlank(gcGrouperSyncMember.getSubjectId())) { + gcGrouperSyncMember.setSubjectId(grouperProvisioningEntity.getSubjectId()); + } + if (grouperProvisioningEntity != null && StringUtils.isBlank(gcGrouperSyncMember.getSourceId())) { + gcGrouperSyncMember.setSourceId(grouperProvisioningEntity.getSubjectSourceId()); + } + + // see if needs to update + { + String newSubjectId = grouperProvisioningEntity == null ? null : grouperProvisioningEntity.retrieveAttributeValueString("subjectId"); + if (!StringUtils.equals(newSubjectId, gcGrouperSyncMember.getSubjectId())) { + memberIdsWithChangedSubjectIds.add(gcGrouperSyncMember.getMemberId()); + } + } + + { + String newSubjectIdentifier = grouperProvisioningEntity == null ? null : grouperProvisioningEntity.retrieveAttributeValueString("subjectIdentifier0"); + if ("subjectIdentifier1".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + newSubjectIdentifier = grouperProvisioningEntity == null ? null : grouperProvisioningEntity.retrieveAttributeValueString("subjectIdentifier1"); + } else if ("subjectIdentifier2".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + newSubjectIdentifier = grouperProvisioningEntity == null ? null : grouperProvisioningEntity.retrieveAttributeValueString("subjectIdentifier2"); + } + + if (!StringUtils.equals(newSubjectIdentifier, gcGrouperSyncMember.getSubjectIdentifier())) { + if (grouperProvisioningEntity == null && gcGrouperSyncMember.isInTarget() && newSubjectIdentifier == null) { + // don't remove the identifier if not provisionable but still in target + } else { + gcGrouperSyncMember.setSubjectIdentifier(newSubjectIdentifier); + } + } + } + + // see if not provisionable + if (!gcGrouperSyncMember.isProvisionable() && grouperProvisioningEntity != null + && (provisioningEntityWrapper == null || !provisioningEntityWrapper.isDelete())) { + gcGrouperSyncMember.setProvisionableStart(new Timestamp(System.currentTimeMillis())); + gcGrouperSyncMember.setProvisionableEnd(null); + gcGrouperSyncMember.setProvisionable(true); + } + if (gcGrouperSyncMember.isProvisionable() && grouperProvisioningEntity == null) { + gcGrouperSyncMember.setProvisionableEnd(new Timestamp(System.currentTimeMillis())); + gcGrouperSyncMember.setProvisionable(false); + } + + // see if not provisionable + if (!gcGrouperSyncMember.isInTarget() && grouperProvisioningEntity != null + && (provisioningEntityWrapper == null || !provisioningEntityWrapper.isDelete())) { + memberIdsToInsert.add(gcGrouperSyncMember.getMemberId()); + } + + if (gcGrouperSyncMember.dbVersionDifferent()) { + memberIdsToUpdate.add(gcGrouperSyncMember.getMemberId()); + } + + continue; + } + + if (grouperProvisioningEntity == null && !gcGrouperSyncMember.isProvisionable() && !gcGrouperSyncMember.isInTarget() && gcGrouperSyncMember.getSubjectIdentifier() != null) { + gcGrouperSyncMember.setSubjectIdentifier(null); + } + + memberUuidToSyncMember.remove(gcGrouperSyncMember.getMemberId()); + + } + + } + + if (GrouperUtil.length(memberIdsToInsert) > 0) { + + Map mapMemberIdToSyncMemberInsert = gcGrouperSync.getGcGrouperSyncMemberDao().memberRetrieveOrCreateByMemberIds(memberIdsToInsert); + + for (String memberIdToInsert : mapMemberIdToSyncMemberInsert.keySet()) { + + GcGrouperSyncMember gcGrouperSyncMember = mapMemberIdToSyncMemberInsert.get(memberIdToInsert); + ProvisioningEntityWrapper provisioningEntityWrapper = memberUuidToProvisioningEntityWrapper.get(memberIdToInsert); + ProvisioningEntity grouperProvisioningEntity = provisioningEntityWrapper == null ? null : provisioningEntityWrapper.getGrouperProvisioningEntity(); + + if (grouperProvisioningEntity == null) { + continue; + } + if (gcGrouperSyncMember == null) { + gcGrouperSyncMember = gcGrouperSync.getGcGrouperSyncMemberDao().memberCreateByMemberId(memberIdToInsert); + } + + gcGrouperSyncMember.setSourceId(grouperProvisioningEntity.retrieveAttributeValueString("subjectSourceId")); + gcGrouperSyncMember.setSubjectId(grouperProvisioningEntity.getSubjectId()); + + String subjectIdentifier = grouperProvisioningEntity.retrieveAttributeValueString("subjectIdentifier0"); + if ("subjectIdentifier1".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + subjectIdentifier = grouperProvisioningEntity.retrieveAttributeValueString("subjectIdentifier1"); + } else if ("subjectIdentifier2".equals(grouperProvisioner.retrieveGrouperProvisioningBehavior().getSubjectIdentifierForMemberSyncTable())) { + subjectIdentifier = grouperProvisioningEntity.retrieveAttributeValueString("subjectIdentifier2"); + } + + gcGrouperSyncMember.setSubjectIdentifier(subjectIdentifier); + gcGrouperSyncMember.setProvisionable(true); + gcGrouperSyncMember.setProvisionableStart(new Timestamp(System.currentTimeMillis())); + memberUuidToSyncMember.put(memberIdToInsert, gcGrouperSyncMember); + provisioningEntityWrapper.setGcGrouperSyncMember(gcGrouperSyncMember); + + } + + } + + Set memberIdsToDelete = new HashSet(memberUuidToSyncMember.keySet()); + + provisioningSyncResult.setMemberIdsToDelete(memberIdsToDelete); + + memberIdsToDelete.removeAll(memberUuidToProvisioningEntityWrapper.keySet()); + + if (GrouperUtil.length(memberIdsToDelete) > 0) { + + Iterator memberIdToDeleteIterator = memberIdsToDelete.iterator(); + + while (memberIdToDeleteIterator.hasNext()) { + + String memberIdToDelete = memberIdToDeleteIterator.next(); + + GcGrouperSyncMember gcGrouperSyncMember = memberUuidToSyncMember.get(memberIdToDelete); + + if (gcGrouperSyncMember == null) { + throw new RuntimeException("why is gcGrouperSyncMember null???"); + } + + if (gcGrouperSyncMember.isProvisionable() || gcGrouperSyncMember.getProvisionableEnd() == null) { + gcGrouperSyncMember.setProvisionable(false); + gcGrouperSyncMember.setProvisionableEnd(new Timestamp(System.currentTimeMillis())); + } + + // if we arent in target, dont worry about it + if (!gcGrouperSyncMember.isInTarget() ) { + memberIdToDeleteIterator.remove(); + memberUuidToSyncMember.remove(gcGrouperSyncMember.getMemberId()); + } + + } + + } + + } + + + public static void fullSyncMemberships(ProvisioningSyncResult provisioningSyncResult, GcGrouperSync gcGrouperSync, + List initialGcGrouperSyncGroups, List initialGcGrouperSyncMembers, + List initialGcGrouperSyncMemberships, Map groupIdMemberIdToProvisioningMembershipWrapper) { + + if (gcGrouperSync == null || StringUtils.isBlank(gcGrouperSync.getProvisionerName())) { + throw new RuntimeException("provisioner name is required"); + } + + if (!GrouperProvisioningSettings.getTargets(true).containsKey(gcGrouperSync.getProvisionerName())) { + throw new RuntimeException("Target '" + gcGrouperSync.getProvisionerName() + + "' is not configured. Go to Miscellaneous -> Provisioning to configure a new target."); + } + + initialGcGrouperSyncMemberships = GrouperUtil.nonNull(initialGcGrouperSyncMemberships); + + Map groupSyncIdToSyncGroup = new HashMap(); + for (GcGrouperSyncGroup gcGrouperSyncGroup : GrouperUtil.nonNull(initialGcGrouperSyncGroups)) { + groupSyncIdToSyncGroup.put(gcGrouperSyncGroup.getId(), gcGrouperSyncGroup); + } + Map memberSyncIdToSyncMember = new HashMap(); + for (GcGrouperSyncMember gcGrouperSyncMember : GrouperUtil.nonNull(initialGcGrouperSyncMembers)) { + memberSyncIdToSyncMember.put(gcGrouperSyncMember.getId(), gcGrouperSyncMember); + } + + Map groupIdMemberIdToSyncMembership = new HashMap(); + + for (GcGrouperSyncMembership gcGrouperSyncMembership : initialGcGrouperSyncMemberships) { + + GcGrouperSyncGroup gcGrouperSyncGroup = groupSyncIdToSyncGroup.get(gcGrouperSyncMembership.getGrouperSyncGroupId()); + GcGrouperSyncMember gcGrouperSyncMember = memberSyncIdToSyncMember.get(gcGrouperSyncMembership.getGrouperSyncMemberId()); + if (gcGrouperSyncGroup != null && gcGrouperSyncMember != null) { + groupIdMemberIdToSyncMembership.put( + new MultiKey(gcGrouperSyncGroup.getGroupId(), gcGrouperSyncMember.getMemberId()), gcGrouperSyncMembership); + } + } + + int removeSyncRowsAfterSecondsOutOfTarget = GrouperLoaderConfig.retrieveConfig().propertyValueInt( + "grouper.provisioning.removeSyncRowsAfterSecondsOutOfTarget", 60*60*24*7); + + provisioningSyncResult.setGcGrouperSync(gcGrouperSync); + + // start group ids to insert with all group ids minus those which have sync group objects already + Set groupIdMemberIdsToInsert = new HashSet(groupIdMemberIdToProvisioningMembershipWrapper.keySet()); + provisioningSyncResult.setMembershipGroupIdMemberIdsToInsert(groupIdMemberIdsToInsert); + groupIdMemberIdsToInsert.removeAll(groupIdMemberIdToSyncMembership.keySet()); + + Set groupIdMemberIdsToUpdate = new HashSet(); + provisioningSyncResult.setMembershipGroupIdMemberIdsToUpdate(groupIdMemberIdsToUpdate); + + List gcGrouperSyncRowsToDeleteFromDatabase = new ArrayList(); + + // lets remove ones that dont need to be there + if (GrouperUtil.length(groupIdMemberIdToSyncMembership) > 0) { + Set groupIdMemberIds = new HashSet(groupIdMemberIdToSyncMembership.keySet()); + for (MultiKey groupIdMemberId : groupIdMemberIds) { + + GcGrouperSyncMembership gcGrouperSyncMembership = groupIdMemberIdToSyncMembership.get(groupIdMemberId); + + GcGrouperSyncGroup gcGrouperSyncGroup = groupSyncIdToSyncGroup.get(gcGrouperSyncMembership.getGrouperSyncGroupId()); + + GcGrouperSyncMember gcGrouperSyncMember = memberSyncIdToSyncMember.get(gcGrouperSyncMembership.getGrouperSyncMemberId()); + + // not sure why this would happen, i guess if a group aged out and this is already removed???? + if (gcGrouperSyncGroup == null || gcGrouperSyncMember == null) { + continue; + } + + ProvisioningMembershipWrapper provisioningMembershipWrapper = groupIdMemberIdToProvisioningMembershipWrapper.get(groupIdMemberId); + + ProvisioningMembership grouperProvisioningMembership = provisioningMembershipWrapper == null ? null : provisioningMembershipWrapper.getGrouperProvisioningMembership(); + + // keep it + boolean membershipProvisionable = gcGrouperSyncGroup.isProvisionable() && gcGrouperSyncMember.isProvisionable(); + + if (grouperProvisioningMembership != null || membershipProvisionable || gcGrouperSyncMembership.isInTarget()) { + + // see if not provisionable + if (!gcGrouperSyncMembership.isInTarget() && grouperProvisioningMembership != null + && (provisioningMembershipWrapper == null || provisioningMembershipWrapper.isDelete())) { + groupIdMemberIdsToInsert.add(groupIdMemberId); + } + + if (gcGrouperSyncMembership.dbVersionDifferent()) { + groupIdMemberIdsToUpdate.add(groupIdMemberId); + } + + continue; + } + + groupIdMemberIdToSyncMembership.remove(groupIdMemberId); + + + if (!gcGrouperSyncMembership.isInTarget() && gcGrouperSyncMembership.getInTargetEnd() != null) { + //if we arent provisionable, and the group has not been in the target for a week, then we done with that one + long targetEndMillis = gcGrouperSyncMembership.getInTargetEnd() == null ? 0 : gcGrouperSyncMembership.getInTargetEnd().getTime(); + targetEndMillis = Math.max(targetEndMillis, gcGrouperSyncMembership.getLastUpdated() == null ? 0 : gcGrouperSyncMembership.getLastUpdated().getTime()); + //if we arent provisionable, and the group has not been in the target for a week, then we done with that one + if (targetEndMillis != 0 &&( (System.currentTimeMillis() - targetEndMillis) / 1000 > removeSyncRowsAfterSecondsOutOfTarget)) { + gcGrouperSyncRowsToDeleteFromDatabase.add(gcGrouperSyncMembership); + } + } + } + + gcGrouperSync.getGcGrouperSyncMembershipDao().membershipDelete(gcGrouperSyncRowsToDeleteFromDatabase, true); + } + + if (GrouperUtil.length(groupIdMemberIdsToInsert) > 0) { + + Map mapGroupIdMemberIdToSyncMembershipInsert = gcGrouperSync.getGcGrouperSyncMembershipDao() + .membershipRetrieveOrCreateByGroupIdsAndMemberIds(gcGrouperSync.getId(), groupIdMemberIdsToInsert); + + for (MultiKey groupIdMemberIdToInsert : mapGroupIdMemberIdToSyncMembershipInsert.keySet()) { + + GcGrouperSyncMembership gcGrouperSyncMembership = mapGroupIdMemberIdToSyncMembershipInsert.get(groupIdMemberIdToInsert); + ProvisioningMembershipWrapper provisioningMembershipWrapper = groupIdMemberIdToProvisioningMembershipWrapper.get(groupIdMemberIdToInsert); + ProvisioningMembership grouperProvisioningMembership = provisioningMembershipWrapper == null ? null : provisioningMembershipWrapper.getGrouperProvisioningMembership(); + + if (grouperProvisioningMembership == null) { + continue; + } + if (gcGrouperSyncMembership == null) { + gcGrouperSyncMembership = gcGrouperSync.getGcGrouperSyncMembershipDao().membershipCreateBySyncGroupIdAndSyncMemberId((String)groupIdMemberIdToInsert.getKey(0), + (String)groupIdMemberIdToInsert.getKey(1)); + } + groupIdMemberIdToSyncMembership.put(groupIdMemberIdToInsert, gcGrouperSyncMembership); + provisioningMembershipWrapper.setGcGrouperSyncMembership(gcGrouperSyncMembership); + + } + + } + + Set groupIdMemberIdsToDelete = new HashSet(groupIdMemberIdToSyncMembership.keySet()); + + provisioningSyncResult.setMembershipGroupIdMemberIdsToDelete(groupIdMemberIdsToDelete); + + groupIdMemberIdsToDelete.removeAll(groupIdMemberIdToProvisioningMembershipWrapper.keySet()); + + if (GrouperUtil.length(groupIdMemberIdsToDelete) > 0) { + + Iterator groupIdMemberIdToDeleteIterator = groupIdMemberIdsToDelete.iterator(); + + while (groupIdMemberIdToDeleteIterator.hasNext()) { + + MultiKey groupIdMemberIdToDelete = groupIdMemberIdToDeleteIterator.next(); + + GcGrouperSyncMembership gcGrouperSyncMembership = groupIdMemberIdToSyncMembership.get(groupIdMemberIdToDelete); + + if (gcGrouperSyncMembership == null) { + throw new RuntimeException("why is gcGrouperSyncMembership null???"); + } + + // if we arent in target, dont worry about it + if (!gcGrouperSyncMembership.isInTarget() ) { + groupIdMemberIdToDeleteIterator.remove(); + groupIdMemberIdToSyncMembership.remove(groupIdMemberIdToDelete); + } + + } + + } + + } + +}