Java tutorial
/** * The MIT License * Copyright (c) 2016, Population Register Centre (VRK) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package fi.vrk.xroad.catalog.persistence; import fi.vrk.xroad.catalog.persistence.entity.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import java.time.LocalDateTime; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.StreamSupport; /** * Implementation for catalogservice CRUD */ @Slf4j @Component("catalogService") @Transactional public class CatalogServiceImpl implements CatalogService { @Autowired MemberRepository memberRepository; @Autowired SubsystemRepository subsystemRepository; @Autowired ServiceRepository serviceRepository; @Autowired WsdlRepository wsdlRepository; @Override public Iterable<Member> getActiveMembers() { return memberRepository.findAllActive(); } @Override public Iterable<Member> getAllMembers() { return memberRepository.findAll(); } public Iterable<Member> getActiveMembers(LocalDateTime changedAfter) { return memberRepository.findActiveChangedSince(changedAfter); } @Override public Iterable<Member> getAllMembers(LocalDateTime changedAfter) { return memberRepository.findAllChangedSince(changedAfter); } @Override public Wsdl getWsdl(String externalId) { List<Wsdl> matches = wsdlRepository.findAnyByExternalId(externalId); if (matches.size() > 1) { throw new IllegalStateException("multiple matches found to " + externalId + ": " + matches); } else if (matches.size() == 1) { return matches.iterator().next(); } else { return null; } } @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 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); } } } 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); } } } } @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); } } } @Override public void saveWsdl(SubsystemId subsystemId, ServiceId serviceId, String wsdlString) { Assert.notNull(subsystemId); Assert.notNull(serviceId); Service oldService; // bit ugly this one, would be a little cleaner if // https://jira.spring.io/browse/DATAJPA-209 was resolved if (serviceId.getServiceVersion() == null) { oldService = serviceRepository.findActiveNullVersionByNaturalKey(subsystemId.getXRoadInstance(), subsystemId.getMemberClass(), subsystemId.getMemberCode(), subsystemId.getSubsystemCode(), serviceId.getServiceCode()); } else { oldService = serviceRepository.findActiveByNaturalKey(subsystemId.getXRoadInstance(), subsystemId.getMemberClass(), subsystemId.getMemberCode(), subsystemId.getSubsystemCode(), serviceId.getServiceCode(), serviceId.getServiceVersion()); } if (oldService == null) { throw new IllegalStateException("service " + serviceId + " not found!"); } LocalDateTime now = LocalDateTime.now(); Wsdl wsdl = new Wsdl(); wsdl.setData(wsdlString); Wsdl oldWsdl = oldService.getWsdl(); if (oldWsdl == null) { wsdl.initializeExternalId(); wsdl.getStatusInfo().setTimestampsForNew(now); oldService.setWsdl(wsdl); wsdl.setService(oldService); wsdlRepository.save(wsdl); } else { if (oldWsdl.getStatusInfo().isRemoved()) { // resurrect oldWsdl.setData(wsdl.getData()); oldWsdl.getStatusInfo().setChanged(now); oldWsdl.getStatusInfo().setRemoved(null); oldWsdl.getStatusInfo().setFetched(now); } else { // update existing boolean wsdlChanged = !oldWsdl.getData().equals(wsdl.getData()); if (wsdlChanged) { oldWsdl.getStatusInfo().setChanged(now); oldWsdl.setData(wsdl.getData()); } oldWsdl.getStatusInfo().setFetched(now); } } } }