public void postProcess(ProcessorState state) throws Exception {
    Map<String, List<String[]>> sectionMembers = getSectionMembers(state);
    for (String sectionEid : sectionMembers.keySet()) {
      if (!cmService.isSectionDefined(sectionEid)) {
        log.error("can't sync section memberships, no section with eid of {} found", sectionEid);
        continue;
      }

      Set<Membership> existingMembers = cmService.getSectionMemberships(sectionEid);

      // Build a map of existing member userEids to Memberships
      Map<String, Membership> existingMemberMap = new HashMap(existingMembers.size());
      for (Membership member : existingMembers) {
        existingMemberMap.put(member.getUserId(), member);
      }

      List<String[]> memberElements = sectionMembers.get(sectionEid);

      // Keep track of the new members userEids, and add/update them
      Set<Membership> newMembers = new HashSet<>();
      for (String[] memberElement : memberElements) {
        newMembers.add(
            cmAdmin.addOrUpdateSectionMembership(
                memberElement[1], memberElement[2], sectionEid, memberElement[3]));
      }

      // For everybody not in the newMembers set, remove their memberships
      existingMembers.removeAll(newMembers);
      for (Membership member : existingMembers) {
        cmAdmin.removeSectionMembership(member.getUserId(), sectionEid);
      }
    }
  }
  private Collection<SyncableGroup> readSakaiGroups() throws IdUnusedException {
    Collection<SyncableGroup> result = new ArrayList<SyncableGroup>();

    Collection<AuthzGroup> sakaiGroups = new ArrayList<AuthzGroup>();
    Site site = SiteService.getSite(siteId);
    sakaiGroups.add(site);
    sakaiGroups.addAll(site.getGroups());

    for (AuthzGroup sakaiGroup : sakaiGroups) {
      List<UserWithRole> members = new ArrayList<UserWithRole>();
      HashSet<String> inactiveUsers = new HashSet<String>();

      // Load direct members of this group
      for (Member m : sakaiGroup.getMembers()) {
        if (!m.isActive()) {
          inactiveUsers.add(m.getUserEid());
          continue;
        }

        if (!m.isProvided()) {
          // Provided users will be handled separately below.
          members.add(new UserWithRole(m.getUserEid(), m.getRole().getId()));
        }
      }

      String provider = sakaiGroup.getProviderGroupId();

      // Plus those provided by sections
      if (provider != null) {
        HashSet<String> seenUsers = new HashSet<String>();

        for (String providerId : provider.split("\\+")) {
          for (org.sakaiproject.coursemanagement.api.Membership m :
              cms.getSectionMemberships(providerId)) {
            if (seenUsers.contains(m.getUserId()) || inactiveUsers.contains(m.getUserId())) {
              continue;
            }

            members.add(new UserWithRole(m.getUserId(), m.getRole()));
            seenUsers.add(m.getUserId());
          }
        }
      }

      result.add(new SyncableGroup(sakaiGroup.getId(), sakaiGroup.getDescription(), members));
    }

    return result;
  }