@Override
  public void saveAllMembersAndSubsystems(Collection<Member> members) {
    LocalDateTime now = LocalDateTime.now();
    // process members
    Map<MemberId, Member> unprocessedOldMembers = new HashMap<>();
    StreamSupport.stream(memberRepository.findAll().spliterator(), false)
        .forEach(member -> unprocessedOldMembers.put(member.createKey(), member));

    for (Member member : members) {
      Member oldMember = unprocessedOldMembers.get(member.createKey());
      if (oldMember == null) {
        // brand new item
        member.getStatusInfo().setTimestampsForNew(now);
        for (Subsystem subsystem : member.getAllSubsystems()) {
          subsystem.getStatusInfo().setTimestampsForNew(now);
          subsystem.setMember(member);
        }
        member = memberRepository.save(member);
      } else {
        handleOldMember(now, member, oldMember);

        member = memberRepository.save(oldMember);
      }
      unprocessedOldMembers.remove(member.createKey());
    }
    // now unprocessedOldMembers should all be removed (either already removed, or will be now)
    removeUnprocessedOldMembers(now, unprocessedOldMembers);
  }
 private void removeUnprocessedOldMembers(
     LocalDateTime now, Map<MemberId, Member> unprocessedOldMembers) {
   for (Member oldToRemove : unprocessedOldMembers.values()) {
     StatusInfo status = oldToRemove.getStatusInfo();
     if (!status.isRemoved()) {
       status.setTimestampsForRemoved(now);
     }
     for (Subsystem subsystem : oldToRemove.getAllSubsystems()) {
       if (!subsystem.getStatusInfo().isRemoved()) {
         subsystem.getStatusInfo().setTimestampsForRemoved(now);
       }
     }
   }
 }
 /**
  * Returns the hash code value for this object.
  *
  * @return Hash code value for this object.
  */
 public int hashCode() {
   int h = 31 * 17 + getName().hashCode();
   h = 31 * h + getActions().hashCode();
   if (subsystem != null) {
     h = 31 * h + subsystem.hashCode();
   }
   return h;
 }
 /**
  * Create a permission name from a Subsystem
  *
  * @param subsystem Subsystem to use to create permission name.
  * @return permission name.
  */
 private static String createName(Subsystem subsystem) {
   if (subsystem == null) {
     throw new IllegalArgumentException("subsystem must not be null");
   }
   StringBuffer sb = new StringBuffer("(id=");
   sb.append(subsystem.getSubsystemId());
   sb.append(")");
   return sb.toString();
 }
  @Override
  public void saveServices(SubsystemId subsystemId, Collection<Service> services) {
    assert subsystemId != null;
    Subsystem oldSubsystem =
        subsystemRepository.findActiveByNaturalKey(
            subsystemId.getXRoadInstance(),
            subsystemId.getMemberClass(),
            subsystemId.getMemberCode(),
            subsystemId.getSubsystemCode());
    if (oldSubsystem == null) {
      throw new IllegalStateException("subsystem " + subsystemId + " not found!");
    }

    LocalDateTime now = LocalDateTime.now();

    Map<ServiceId, Service> unprocessedOldServices = new HashMap<>();
    oldSubsystem
        .getAllServices()
        .stream()
        .forEach(s -> unprocessedOldServices.put(s.createKey(), s));

    for (Service service : services) {
      Service oldService = unprocessedOldServices.get(service.createKey());
      if (oldService == null) {
        // brand new item, add it
        service.getStatusInfo().setTimestampsForNew(now);
        service.setSubsystem(oldSubsystem);
        oldSubsystem.getAllServices().add(service);
      } else {
        oldService.getStatusInfo().setTimestampsForFetched(now);
      }
      unprocessedOldServices.remove(service.createKey());
    }

    // now unprocessedOldServices should all be removed (either already removed, or will be now)
    for (Service oldToRemove : unprocessedOldServices.values()) {
      StatusInfo status = oldToRemove.getStatusInfo();
      if (!status.isRemoved()) {
        status.setTimestampsForRemoved(now);
      }
    }
  }
  /**
   * Determines the equality of two {@code SubsystemPermission} objects.
   *
   * @param obj The object being compared for equality with this object.
   * @return {@code true} if {@code obj} is equivalent to this {@code SubsystemPermission}; {@code
   *     false} otherwise.
   */
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }

    if (!(obj instanceof SubsystemPermission)) {
      return false;
    }

    SubsystemPermission sp = (SubsystemPermission) obj;

    return (action_mask == sp.action_mask)
        && ((subsystem == sp.subsystem) || ((subsystem != null) && subsystem.equals(sp.subsystem)))
        && (filter == null ? sp.filter == null : filter.equals(sp.filter));
  }
 private void handleOldMember(LocalDateTime now, Member member, Member oldMember) {
   oldMember.updateWithDataFrom(member, now);
   // process subsystems for the old member
   Map<SubsystemId, Subsystem> unprocessedOldSubsystems = new HashMap<>();
   for (Subsystem subsystem : oldMember.getAllSubsystems()) {
     unprocessedOldSubsystems.put(subsystem.createKey(), subsystem);
   }
   for (Subsystem subsystem : member.getAllSubsystems()) {
     Subsystem oldSubsystem = unprocessedOldSubsystems.get(subsystem.createKey());
     if (oldSubsystem == null) {
       // brand new item, add it
       subsystem.getStatusInfo().setTimestampsForNew(now);
       subsystem.setMember(oldMember);
       oldMember.getAllSubsystems().add(subsystem);
     } else {
       oldSubsystem.getStatusInfo().setTimestampsForFetched(now);
     }
     unprocessedOldSubsystems.remove(subsystem.createKey());
   }
   // remaining old subsystems - that were not included in member.subsystems -
   // are removed (if not already)
   for (Subsystem oldToRemove : unprocessedOldSubsystems.values()) {
     StatusInfo status = oldToRemove.getStatusInfo();
     if (!status.isRemoved()) {
       status.setTimestampsForRemoved(now);
     }
   }
 }