From 44b7bc59b24471d2fdf5426b59556fb9813a60ee Mon Sep 17 00:00:00 2001 From: mchyzer Date: Sat, 5 Nov 2022 15:11:41 -0400 Subject: [PATCH] GRP-4465: Subject identifier shouldn't be cleared from member sync table until member isn't in target --- .../ProvisioningSyncIntegration.class | Bin 0 -> 28851 bytes .../ProvisioningSyncIntegration.java | 846 ++++++++++++++++++ 2 files changed, 846 insertions(+) create mode 100644 container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.class create mode 100644 container_files/api/edu/internet2/middleware/grouper/app/tableSync/ProvisioningSyncIntegration.java 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 0000000000000000000000000000000000000000..ad9971a55c6cfd10d99a286448e11e66505d070a GIT binary patch literal 28851 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 P1_(xFwH2mKsVn~ 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); + } + + } + + } + + } + +}