Merge branch 'release/5.2.0'
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / registration / RegistrationWorkingSetService.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.api.service.registration;
10
11 import java.io.IOException;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Optional;
18 import java.util.Set;
19 import java.util.UUID;
20
21 import org.apache.log4j.Logger;
22 import org.hibernate.Hibernate;
23 import org.springframework.beans.factory.annotation.Autowired;
24 import org.springframework.beans.factory.annotation.Qualifier;
25 import org.springframework.stereotype.Service;
26 import org.springframework.transaction.annotation.Transactional;
27
28 import eu.etaxonomy.cdm.api.application.CdmRepository;
29 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
30 import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
31 import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
32 import eu.etaxonomy.cdm.api.service.pager.Pager;
33 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
34 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
35 import eu.etaxonomy.cdm.model.common.User;
36 import eu.etaxonomy.cdm.model.name.Registration;
37 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
38 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
39 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
40 import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
41 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
42 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
43 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
44 import eu.etaxonomy.cdm.model.reference.Reference;
45 import eu.etaxonomy.cdm.model.reference.ReferenceType;
46 import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
47 import eu.etaxonomy.cdm.persistence.query.OrderHint;
48 import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder;
49
50 /**
51 * Provides RegistrationDTOs and RegistrationWorkingsets for Registrations in the database.
52 *
53 *
54 * @author a.kohlbecker
55 * @since Mar 10, 2017
56 *
57 */
58 @Service("registrationWorkingSetService")
59 @Transactional(readOnly=true)
60 public class RegistrationWorkingSetService implements IRegistrationWorkingSetService {
61
62 public static final List<String> REGISTRATION_DTO_INIT_STRATEGY = Arrays.asList(new String []{
63 "blockedBy",
64 // typeDesignation
65 "typeDesignations.typeStatus",
66 "typeDesignations.typifiedNames.typeDesignations", // important !!
67 "typeDesignations.typeSpecimen",
68 "typeDesignations.typeName.$",
69 "typeDesignations.citation",
70 "typeDesignations.citation.authorship.$",
71 "typeDesignations.annotations", // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
72 "typeDesignations.markers", // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
73 "typeDesignations.registrations", // DerivedUnitConverter.copyPropertiesTo(TARGET n)
74
75 // name
76 "name.$",
77 "name.nomenclaturalReference.authorship.$",
78 "name.nomenclaturalReference.inReference",
79 "name.rank",
80 "name.homotypicalGroup.typifiedNames",
81 "name.status.type",
82 "name.typeDesignations", // important !!"
83 // institution
84 "institution",
85 }
86 );
87
88 /**
89 *
90 */
91 public List<String> DERIVEDUNIT_INIT_STRATEGY = Arrays.asList(new String[]{
92 "*", // initialize all related entities to allow DerivedUnit conversion, see DerivedUnitConverter.copyPropertiesTo()
93 "derivedFrom.$",
94 "derivedFrom.type", // TODO remove?
95 "derivedFrom.originals.derivationEvents", // important!!
96 "specimenTypeDesignations.typifiedNames.typeDesignations", // important!!
97 "mediaSpecimen.sources"
98 });
99
100 /**
101 *
102 */
103 public List<String> FIELDUNIT_INIT_STRATEGY = Arrays.asList(new String[]{
104 "$",
105 "annotations.*", // * is needed as log as we are using a table in FilterableAnnotationsField
106 "gatheringEvent.$",
107 "gatheringEvent.country",
108 "gatheringEvent.collectingAreas",
109 "gatheringEvent.actor",
110 "derivationEvents.derivatives" // important, otherwise the DerivedUnits are not included into the graph of initialized entities!!!
111 });
112
113 public static final List<String> BLOCKING_REGISTRATION_INIT_STRATEGY = Arrays.asList(new String []{
114
115 "blockedBy.blockedBy",
116 // typeDesignation
117 "blockedBy.typeDesignations.typeStatus",
118 // "typeDesignations.typifiedNames.typeDesignations", // important !!
119 // "typeDesignations.typeSpecimen",
120 // "typeDesignations.typeName.$",
121 // "typeDesignations.citation",
122 // "typeDesignations.citation.authorship.$",
123 // name
124 // "blockedBy.name.$",
125 "blockedBy.name.nomenclaturalReference.authorship",
126 "blockedBy.name.nomenclaturalReference.inReference",
127 "blockedBy.name.rank",
128 // "name.homotypicalGroup.typifiedNames",
129 // "name.status.type",
130 // "name.typeDesignations",
131 // institution
132 "blockedBy.institution",
133 }
134 );
135
136 /**
137 *
138 */
139 private static final int PAGE_SIZE = 50;
140
141 private static final Logger logger = Logger.getLogger(RegistrationWorkingSetService.class);
142
143 @Autowired
144 @Qualifier("cdmRepository")
145 private CdmRepository repo;
146
147 @Autowired
148 protected IBeanInitializer defaultBeanInitializer;
149
150 public RegistrationWorkingSetService() {
151
152 }
153
154
155 /**
156 * @param id the Registration entity id
157 * @return
158 */
159 @Override
160 public RegistrationDTO loadDtoById(Integer id) {
161 Registration reg = repo.getRegistrationService().load(id, REGISTRATION_DTO_INIT_STRATEGY);
162 inititializeSpecimen(reg);
163 return new RegistrationDTO(reg);
164 }
165
166
167 /**
168 * @param id the Registration entity id
169 * @return
170 */
171 @Override
172 @Transactional(readOnly=true)
173 public RegistrationDTO loadDtoByUuid(UUID uuid) {
174 Registration reg = repo.getRegistrationService().load(uuid, REGISTRATION_DTO_INIT_STRATEGY);
175 inititializeSpecimen(reg);
176 return new RegistrationDTO(reg);
177 }
178
179 @Override
180 @Transactional(readOnly=true)
181 public Pager<RegistrationDTO> pageDTOs(String identifier, Integer pageIndex, Integer pageSize) throws IOException {
182
183 Pager<Registration> regPager = repo.getRegistrationService().pageByIdentifier(identifier, pageIndex, pageSize, REGISTRATION_DTO_INIT_STRATEGY);
184 return convertToDTOPager(regPager);
185 }
186
187
188 /**
189 * @param regPager
190 * @return
191 */
192 @Override
193 public Pager<RegistrationDTO> convertToDTOPager(Pager<Registration> regPager) {
194 return new DefaultPagerImpl<RegistrationDTO>(regPager.getCurrentIndex(), regPager.getCount(), regPager.getPageSize(), makeDTOs(regPager.getRecords()));
195 }
196
197
198 @Override
199 public Pager<RegistrationDTO> pageDTOs(Integer pageSize, Integer pageIndex) {
200
201 return pageDTOs((User)null, null, null, null, null, pageSize, pageIndex, null);
202 }
203
204 /**
205 * {@inheritDoc}
206 */
207 @Override
208 public Pager<RegistrationDTO> pageDTOs(User submitter, Collection<RegistrationStatus> includedStatus,
209 String identifierFilterPattern, String taxonNameFilterPattern, Set<TypeDesignationStatusBase> typeStatusFilter,
210 Integer pageSize, Integer pageIndex, List<OrderHint> orderHints) {
211
212 if(pageSize == null){
213 pageSize = PAGE_SIZE;
214 }
215
216 if(orderHints == null){
217 orderHints = Arrays.asList(new OrderHint("identifier", SortOrder.ASCENDING));
218 }
219
220 Pager<Registration> pager = repo.getRegistrationService().page(submitter, includedStatus, identifierFilterPattern, taxonNameFilterPattern,
221 typeStatusFilter, PAGE_SIZE, pageIndex , orderHints, REGISTRATION_DTO_INIT_STRATEGY);
222
223 Pager<RegistrationDTO> dtoPager = convertToDTOPager(pager);
224 if(logger.isDebugEnabled()){
225 logger.debug(String.format("pageDTOs() pageIndex: $1%d, pageSize: $2%d, includedStatus: $3%s, identifierFilterPattern: $4%s, taxonNameFilterPattern: $5%s, submitter: $6%s",
226 pageIndex, pageSize, includedStatus, identifierFilterPattern, taxonNameFilterPattern, submitter));
227 logger.debug("pageDTOs() result: " + pager.toString());
228 }
229 return dtoPager;
230 }
231
232 @Override
233 public Pager<RegistrationDTO> pageDTOs(UUID submitterUuid, Collection<RegistrationStatus> includedStatus, String identifierFilterPattern,
234 String taxonNameFilterPattern, Collection<UUID> typeDesignationStatusUuids, Integer pageSize,
235 Integer pageIndex, List<OrderHint> orderHints){
236
237 if(pageSize == null){
238 pageSize = PAGE_SIZE;
239 }
240
241 if(orderHints == null){
242 orderHints = Arrays.asList(new OrderHint("identifier", SortOrder.ASCENDING));
243 }
244
245 Pager<Registration> pager = repo.getRegistrationService().page(submitterUuid, includedStatus,
246 identifierFilterPattern, taxonNameFilterPattern,
247 typeDesignationStatusUuids, PAGE_SIZE, pageIndex , orderHints, REGISTRATION_DTO_INIT_STRATEGY);
248
249 Pager<RegistrationDTO> dtoPager = convertToDTOPager(pager);
250 if(logger.isDebugEnabled()){
251 logger.debug(String.format("pageDTOs() pageIndex: $1%d, pageSize: $2%d, includedStatusUuids: $3%s, typeDesignationStatusUuids: $4%s, taxonNameFilterPattern: $5%s, submitterUuid: $6%s",
252 pageIndex, pageSize, includedStatus, identifierFilterPattern, taxonNameFilterPattern, submitterUuid));
253 logger.debug("pageDTOs() result: " + pager.toString());
254 }
255 return dtoPager;
256
257 }
258
259
260 /**
261 * {@inheritDoc}
262 * @throws RegistrationValidationException
263 */
264 @Override
265 public RegistrationWorkingSet loadWorkingSetByReferenceUuid(UUID referenceUuid, boolean resolveSections) throws RegistrationValidationException {
266
267 Reference reference = repo.getReferenceService().load(referenceUuid); // needed to use load to avoid the problem described in #7331
268 if(resolveSections){
269 reference = resolveSection(reference);
270 }
271
272 Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY);
273
274 /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
275 // debugIssue7331(pager);
276 return new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
277 }
278
279
280 /**
281 * @param reference
282 * @return
283 */
284 protected Reference resolveSection(Reference reference) {
285 repo.getReferenceService().load(reference.getUuid(), Arrays.asList(new String[]{"inReference"})); // needed to avoid the problem described in #7331
286 if(reference.isOfType(ReferenceType.Section) && reference.getInReference() != null) {
287 reference = reference.getInReference();
288 }
289 return reference;
290 }
291
292 /**
293 * {@inheritDoc}
294 * @throws RegistrationValidationException
295 */
296 @Override
297 public RegistrationWorkingSet loadWorkingSetByReferenceID(Integer referenceID, boolean resolveSections) throws RegistrationValidationException {
298
299 Reference reference = repo.getReferenceService().find(referenceID);
300 if(resolveSections){
301 reference = resolveSection(reference);
302 }
303 repo.getReferenceService().load(reference.getUuid()); // needed to avoid the problem described in #7331
304
305 Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY);
306
307 /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
308 // debugIssue7331(pager);
309
310 return new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
311 }
312
313
314 /**
315 * @param pager
316 */
317 @SuppressWarnings("unused")
318 private void debugIssue7331(Pager<Registration> pager) {
319 for(Registration reg : pager.getRecords()){
320 if(reg.getName() != null && reg.getName().getNomenclaturalReference().getAuthorship() != null){
321 Reference ref = reg.getName().getNomenclaturalReference();
322 if(!Hibernate.isInitialized(ref.getAuthorship())){
323 logger.error("UNINITIALIZED");
324 }
325 } else {
326 logger.debug("NO AUTHORS");
327 }
328 }
329 }
330
331 @Override
332 public Set<RegistrationDTO> loadBlockingRegistrations(UUID blockedRegistrationUuid){
333
334 Registration registration = repo.getRegistrationService().load(blockedRegistrationUuid, BLOCKING_REGISTRATION_INIT_STRATEGY);
335 Set<Registration> registrations = registration.getBlockedBy();
336
337 Set<RegistrationDTO> blockingSet = new HashSet<>();
338 for(Registration reg : registrations){
339 blockingSet.add(new RegistrationDTO(reg));
340 }
341 return blockingSet;
342 }
343
344 /**
345 * @param regs
346 * @return
347 */
348 private List<RegistrationDTO> makeDTOs(List<Registration> regs) {
349 initializeSpecimens(regs);
350 List<RegistrationDTO> dtos = new ArrayList<>(regs.size());
351 regs.forEach(reg -> {dtos.add(new RegistrationDTO(reg));});
352 return dtos;
353 }
354
355
356 /**
357 * @param regs
358 */
359 public void initializeSpecimens(List<Registration> regs) {
360 for(Registration reg : regs){
361 inititializeSpecimen(reg);
362 }
363
364 }
365
366
367 /**
368 * @param reg
369 */
370 public void inititializeSpecimen(Registration reg) {
371
372 for(TypeDesignationBase<?> td : reg.getTypeDesignations()){
373 if(td instanceof SpecimenTypeDesignation){
374
375 DerivedUnit derivedUnit = ((SpecimenTypeDesignation) td).getTypeSpecimen();
376 @SuppressWarnings("rawtypes")
377 Set<SpecimenOrObservationBase> sobs = new HashSet<>();
378 sobs.add(HibernateProxyHelper.deproxy(derivedUnit));
379
380 while(sobs != null && !sobs.isEmpty()){
381 @SuppressWarnings("rawtypes")
382 Set<SpecimenOrObservationBase> nextSobs = null;
383 for(@SuppressWarnings("rawtypes") SpecimenOrObservationBase sob : sobs){
384 sob = HibernateProxyHelper.deproxy(sob);
385 if(sob == null){
386 continue;
387 }
388 if(DerivedUnit.class.isAssignableFrom(sob.getClass())) {
389 defaultBeanInitializer.initialize(sob, DERIVEDUNIT_INIT_STRATEGY);
390 nextSobs = ((DerivedUnit)sob).getOriginals();
391 }
392 if(sob instanceof FieldUnit){
393 defaultBeanInitializer.initialize(sob, FIELDUNIT_INIT_STRATEGY);
394 }
395 }
396 sobs = nextSobs;
397 }
398 }
399 }
400 }
401
402
403
404
405
406
407 }