cleanup
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / service / SpecimenTypeDesignationSetServiceImpl.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.service;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.UUID;
18
19 import org.apache.logging.log4j.LogManager;
20 import org.apache.logging.log4j.Logger;
21 import org.hibernate.Session;
22 import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.beans.factory.annotation.Qualifier;
24 import org.springframework.stereotype.Service;
25 import org.springframework.transaction.annotation.Transactional;
26
27 import eu.etaxonomy.cdm.api.application.CdmRepository;
28 import eu.etaxonomy.cdm.api.service.DeleteResult;
29 import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
30 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
31 import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
32 import eu.etaxonomy.cdm.api.service.registration.RegistrationWorkingSetService;
33 import eu.etaxonomy.cdm.compare.name.TypeDesignationComparator;
34 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
35 import eu.etaxonomy.cdm.model.common.VersionableEntity;
36 import eu.etaxonomy.cdm.model.name.Registration;
37 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
38 import eu.etaxonomy.cdm.model.name.TaxonName;
39 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
40 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
41 import eu.etaxonomy.cdm.model.occurrence.DerivationEventType;
42 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
43 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
44 import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
45 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
46 import eu.etaxonomy.cdm.vaadin.model.registration.SpecimenTypeDesignationDTO;
47 import eu.etaxonomy.cdm.vaadin.model.registration.SpecimenTypeDesignationSetDTO;
48
49 /**
50 * @author a.kohlbecker
51 * @since Nov 13, 2017
52 */
53 @Service("specimenTypeDesignationSetService")
54 @Transactional(readOnly=true)
55 public class SpecimenTypeDesignationSetServiceImpl
56 implements ISpecimenTypeDesignationSetService {
57
58 private final Logger logger = LogManager.getLogger();
59
60 static SpecimenDeleteConfigurator specimenDeleteConfigurer = new SpecimenDeleteConfigurator();
61 static {
62 specimenDeleteConfigurer.setDeleteChildren(true);
63 specimenDeleteConfigurer.setDeleteFromDescription(true);
64 specimenDeleteConfigurer.setDeleteFromIndividualsAssociation(true);
65 specimenDeleteConfigurer.setDeleteFromTypeDesignation(true);
66 specimenDeleteConfigurer.setDeleteMolecularData(true);
67 }
68
69 public static final List<String> TAXON_NAME_INIT_STRATEGY = Arrays.asList(new String []{
70 "$",
71 "nomenclaturalSource.citation.authorship.$",
72 "nomenclaturalSource.citation.inReference.authorship.$",
73 "nomenclaturalSource.citation.inReference.inReference.authorship.$",
74 "status.type",
75 "typeDesignations"
76 }
77 );
78
79 @Autowired
80 private IRegistrationWorkingSetService registrationWorkingSetService;
81
82 @Qualifier("cdmRepository")
83 @Autowired
84 private CdmRepository repo;
85
86 @Override
87 public SpecimenTypeDesignationSetDTO<Registration> create(UUID registrationUuid, UUID typifiedNameUuid) {
88 FieldUnit newfieldUnit = FieldUnit.NewInstance();
89 Registration reg = repo.getRegistrationService().load(registrationUuid, RegistrationWorkingSetService.REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
90 if(reg == null){
91 reg = repo.getRegistrationService().newRegistration();
92 reg.setUuid(registrationUuid);
93 }
94 TaxonName typifiedName = repo.getNameService().load(typifiedNameUuid, TAXON_NAME_INIT_STRATEGY);
95 SpecimenTypeDesignationSetDTO<Registration> workingSetDto = new SpecimenTypeDesignationSetDTO<>(reg, newfieldUnit, typifiedName);
96 return workingSetDto;
97 }
98
99 @Override
100 @Transactional(readOnly=true)
101 public SpecimenTypeDesignationSetDTO<Registration> load(UUID registrationUuid, IdentifiableEntity<?> baseEntity) {
102
103 RegistrationDTO regDTO = registrationWorkingSetService.loadDtoByUuid(registrationUuid);
104 // find the working set
105 SpecimenTypeDesignationSetDTO<Registration> workingSetDto = specimenTypeDesignationSetDTO(regDTO, baseEntity);
106 return workingSetDto;
107 }
108
109 protected SpecimenTypeDesignationSetDTO<Registration> specimenTypeDesignationSetDTO(
110 RegistrationDTO regDTO, VersionableEntity baseEntity) {
111
112 @SuppressWarnings("rawtypes")
113 Set<TypeDesignationBase> typeDesignations = regDTO.getTypeDesignationsInWorkingSet(baseEntity);
114 List<SpecimenTypeDesignation> specimenTypeDesignations = new ArrayList<>(typeDesignations.size());
115 typeDesignations.forEach(td -> specimenTypeDesignations.add((SpecimenTypeDesignation)td));
116 specimenTypeDesignations.sort(new TypeDesignationComparator());
117 //TODO is this needed?
118 baseEntity = regDTO.getTypeDesignationSet(baseEntity).getBaseEntity();
119
120 SpecimenTypeDesignationSetDTO<Registration> dto = new SpecimenTypeDesignationSetDTO<>(regDTO.registration(),
121 baseEntity, specimenTypeDesignations, regDTO.typifiedName());
122 return dto;
123 }
124
125 @Override
126 public SpecimenTypeDesignationSetDTO<Registration> fixMissingFieldUnit(SpecimenTypeDesignationSetDTO<Registration> bean) {
127
128 if(bean.getFieldUnit() == null){
129 // in case the base unit of the working set is not a FieldUnit all contained TypeDesignations must be modified
130 // so that they are based on an empty FieldUnit with an associated Gathering Event
131
132 Registration reg = repo.getRegistrationService().find(bean.getOwner().getUuid());
133 RegistrationDTO regDTO = new RegistrationDTO(reg);
134
135 FieldUnit fieldUnit = FieldUnit.NewInstance();
136 GatheringEvent gatheringEvent = GatheringEvent.NewInstance();
137 fieldUnit.setGatheringEvent(gatheringEvent);
138 fieldUnit = repo.getOccurrenceService().save(fieldUnit);
139
140 VersionableEntity baseEntity = bean.getBaseEntity();
141 @SuppressWarnings("rawtypes")
142 Set<TypeDesignationBase> typeDesignations = regDTO.getTypeDesignationsInWorkingSet(baseEntity);
143 for(TypeDesignationBase<?> td : typeDesignations){
144 DerivationEvent de = DerivationEvent.NewInstance(DerivationEventType.GATHERING_IN_SITU());
145 de.addOriginal(fieldUnit);
146 de.addDerivative(((SpecimenTypeDesignation)td).getTypeSpecimen());
147 }
148
149 repo.getRegistrationService().saveOrUpdate(reg);
150 }
151 return bean;
152 }
153
154 @Override
155 @Transactional(readOnly=false)
156 public void save(SpecimenTypeDesignationSetDTO<? extends VersionableEntity> dto) {
157
158 if(dto.getOwner() instanceof Registration){
159 Registration regPremerge = (Registration) dto.getOwner();
160
161 regPremerge = repo.getRegistrationService().assureIsPersisted(regPremerge);
162
163 // find the newly created type designations
164 Set<SpecimenTypeDesignation> newTypeDesignations = findNewTypeDesignations((SpecimenTypeDesignationSetDTO<Registration>) dto);
165
166 FieldUnit fieldUnit = (FieldUnit) dto.getBaseEntity();
167
168 // associate the new typeDesignations with the registration
169 for(SpecimenTypeDesignation std : newTypeDesignations){
170 assureFieldUnit(fieldUnit, std);
171 // here the TypeDesignation.typifiedName is also set internally
172 dto.getTypifiedName().addTypeDesignation(std, false);
173 regPremerge.addTypeDesignation(std);
174 }
175
176 for(SpecimenTypeDesignationDTO stdDTO : dto.getSpecimenTypeDesignationDTOs()){
177 SpecimenTypeDesignation specimenTypeDesignation = stdDTO.asSpecimenTypeDesignation();
178 // associate all type designations with the fieldUnit
179 assureFieldUnit(fieldUnit, specimenTypeDesignation);
180 }
181
182 Session session = repo.getSession();
183
184 session.merge(regPremerge);
185 session.flush();
186
187 // ------------------------ perform delete of removed SpecimenTypeDesignations
188 // this step also includes the deletion of DerivedUnits which have been converted by
189 // the DerivedUnitConverter in turn of a kindOfUnit change
190 for(SpecimenTypeDesignation std : dto.deletedSpecimenTypeDesignations()){
191 deleteSpecimenTypeDesignation(dto, std);
192 }
193 }
194
195
196 }
197
198 protected void deleteSpecimenTypeDesignation(SpecimenTypeDesignationSetDTO<? extends VersionableEntity> dto, SpecimenTypeDesignation std) {
199
200 // if(dto.getOwner() instanceof Registration){
201 // Registration registration = (Registration) dto.getOwner();
202 // registration.getTypeDesignations().clear();
203 // repo.getRegistrationService().save(registration);
204 // } else {
205 // throw new RuntimeException("Unimplemented owner type");
206 // }
207 DerivedUnit du = std.getTypeSpecimen();
208 // DerivationEvent derivationEvent = du.getDerivedFrom();
209
210 //du.removeSpecimenTypeDesignation(std);
211 //derivationEvent.removeDerivative(du);
212 std.setTypeSpecimen(null);
213 repo.getOccurrenceService().delete(du, specimenDeleteConfigurer);
214 repo.getNameService().deleteTypeDesignation(dto.getTypifiedName(), std);
215 // if(derivationEvent.getDerivatives().size() == 0){
216 // getRepo().getEventBaseService().delete(derivationEvent);
217 // }
218 }
219
220 protected void assureFieldUnit(FieldUnit fieldUnit,
221 SpecimenTypeDesignation specimenTypeDesignation) {
222 try {
223 SpecimenOrObservationBase<?> original = findEarliestOriginal(specimenTypeDesignation.getTypeSpecimen());
224 if(original instanceof DerivedUnit){
225 DerivedUnit du = (DerivedUnit)original;
226 du.getDerivedFrom().addOriginal(fieldUnit);
227 }
228 } catch (Exception e) {
229 // has more than one originals !!!
230 logger.error(e);
231 }
232 }
233
234 private SpecimenOrObservationBase<?> findEarliestOriginal(DerivedUnit du) throws Exception {
235
236 SpecimenOrObservationBase<?> original = du;
237
238 while(du != null && du.getDerivedFrom() != null && !du.getDerivedFrom().getOriginals().isEmpty()) {
239 @SuppressWarnings("rawtypes")
240 Iterator<SpecimenOrObservationBase> it = du.getDerivedFrom().getOriginals().iterator();
241 SpecimenOrObservationBase<?> nextOriginal = it.next();
242 if(nextOriginal == null){
243 break;
244 }
245 original = nextOriginal;
246 if(original instanceof DerivedUnit){
247 du = (DerivedUnit)original;
248 } else {
249 // so this must be a FieldUnit,
250 break;
251 }
252 if(it.hasNext()){
253 throw new Exception(String.format("%s has more than one originals", du.toString()));
254 }
255 }
256 return original;
257 }
258
259 private Set<SpecimenTypeDesignation> findNewTypeDesignations(SpecimenTypeDesignationSetDTO<Registration> workingSetDto) {
260
261 Registration reg = workingSetDto.getOwner();
262 Set<SpecimenTypeDesignation> addCandidates = new HashSet<>();
263 for(SpecimenTypeDesignationDTO stdDTO : workingSetDto.getSpecimenTypeDesignationDTOs()){
264 SpecimenTypeDesignation std = stdDTO.asSpecimenTypeDesignation();
265 if(reg.getTypeDesignations().isEmpty() || !reg.getTypeDesignations().stream().filter(td -> td.equals(std)).findFirst().isPresent()){
266 addCandidates.add(std);
267 }
268 }
269 return addCandidates;
270 }
271
272 @Override
273 @Transactional(readOnly=false)
274 public void delete(SpecimenTypeDesignationSetDTO bean, boolean deleteFieldUnit) {
275
276 @SuppressWarnings("unchecked")
277 List<SpecimenTypeDesignationDTO> specimenTypeDesignationDTOs = bean.getSpecimenTypeDesignationDTOs();
278 for(SpecimenTypeDesignationDTO stdDTO : specimenTypeDesignationDTOs){
279 SpecimenTypeDesignation std = stdDTO.asSpecimenTypeDesignation();
280 deleteSpecimenTypeDesignation(bean, std);
281 if(bean.getOwner() instanceof Registration){
282 ((Registration)bean.getOwner()).getTypeDesignations().remove(std);
283 }
284 }
285
286 if(deleteFieldUnit){
287 FieldUnit fu = bean.getFieldUnit();
288 // delete the fieldunit and all derivatives
289 DeleteResult result = repo.getOccurrenceService().delete(fu.getUuid(), specimenDeleteConfigurer);
290 String msg = result.toString();
291 }
292 }
293 }