@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);
  }
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    Option<OpenIDMember> openIDMemberOption = repository.getOpenIdMember(username);

    return openIDMemberOption.mapValueOrThrowException(
        new Option.Mapper<OpenIDMember, Member>() {
          @Override
          public Member map(OpenIDMember openIDMember) {
            return new Member(openIDMember, String.valueOf(random.nextInt()));
          }
        },
        UsernameNotFoundException.class,
        "Invalid username/password");
  }
  @Override
  public UserDetails loadUserDetails(final OpenIDAuthenticationToken token)
      throws UsernameNotFoundException {
    final String identityUrl = token.getIdentityUrl();
    Option<OpenIDMember> openIDMemberOption = repository.getOpenIdMember(identityUrl);
    OpenIDMember openIDMember =
        openIDMemberOption.getValueOr(
            OpenIDMember.class,
            new Option.DefaultCreator<OpenIDMember>() {
              @Override
              public void init(OpenIDMember openIDMember) {
                openIDMember.identityUrl(identityUrl);
                openIDMember.addRoles("ROLE_MEMBER");
                List<OpenIDAttribute> attributes = token.getAttributes();
                boolean fullnameHasBeenSet = false;
                for (OpenIDAttribute attribute : attributes) {
                  switch (attribute.getName()) {
                    case "email":
                      openIDMember.email(attribute.getValues().get(0));
                      break;
                    case "fullname":
                      openIDMember.displayName(attribute.getValues().get(0));
                      fullnameHasBeenSet = true;
                      break;
                    case "firstname":
                      if (!fullnameHasBeenSet)
                        openIDMember.displayName(attribute.getValues().get(0));
                      break;
                  }
                }
                repository.add(openIDMember);
              }
            });

    return new Member(openIDMember, String.valueOf(random.nextInt()));
  }
 @PostConstruct
 public void retrieveAllMembersOrderedByName() {
   members = memberRepository.findAllOrderedByName();
 }
 @Override
 public Iterable<Member> getAllMembers(LocalDateTime changedAfter) {
   return memberRepository.findAllChangedSince(changedAfter);
 }
 public Iterable<Member> getActiveMembers(LocalDateTime changedAfter) {
   return memberRepository.findActiveChangedSince(changedAfter);
 }
 @Override
 public Iterable<Member> getAllMembers() {
   return memberRepository.findAll();
 }