ref #8330 removing unused and obsolete service methods which are replaces by the...
[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.joda.time.DateTime;
24 import org.joda.time.Partial;
25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.beans.factory.annotation.Qualifier;
27 import org.springframework.stereotype.Service;
28 import org.springframework.transaction.annotation.Transactional;
29
30 import eu.etaxonomy.cdm.api.application.CdmRepository;
31 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
32 import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
33 import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
34 import eu.etaxonomy.cdm.api.service.pager.Pager;
35 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
36 import eu.etaxonomy.cdm.api.utility.UserHelper;
37 import eu.etaxonomy.cdm.database.PermissionDeniedException;
38 import eu.etaxonomy.cdm.format.ReferenceEllypsisFormatter;
39 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
40 import eu.etaxonomy.cdm.model.name.Registration;
41 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
42 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
43 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
44 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
45 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
46 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
47 import eu.etaxonomy.cdm.model.reference.Reference;
48 import eu.etaxonomy.cdm.model.reference.ReferenceType;
49 import eu.etaxonomy.cdm.persistence.dao.initializer.EntityInitStrategy;
50 import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
51 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
52 import eu.etaxonomy.cdm.persistence.query.MatchMode;
53 import eu.etaxonomy.cdm.persistence.query.OrderHint;
54 import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder;
55
56 /**
57 * Provides RegistrationDTOs and RegistrationWorkingsets for Registrations in the database.
58 *
59 *
60 * @author a.kohlbecker
61 * @since Mar 10, 2017
62 *
63 */
64 @Service("registrationWorkingSetService")
65 @Transactional(readOnly=true)
66 public class RegistrationWorkingSetService implements IRegistrationWorkingSetService {
67
68 public static final EntityInitStrategy REGISTRATION_DTO_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
69 "blockedBy",
70 // typeDesignation
71 "typeDesignations.typeStatus",
72 "typeDesignations.typifiedNames.typeDesignations", // important !!
73 "typeDesignations.typeSpecimen",
74 "typeDesignations.typeName.$",
75 "typeDesignations.citation",
76 "typeDesignations.annotations", // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
77 "typeDesignations.markers", // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
78 "typeDesignations.registrations", // DerivedUnitConverter.copyPropertiesTo(TARGET n)
79
80 // name
81 "name.$",
82 "name.nomenclaturalReference",
83 "name.rank",
84 "name.homotypicalGroup.typifiedNames",
85 "name.status.type",
86 "name.typeDesignations", // important !!"
87 // institution
88 "institution",
89 }
90 ))
91 .extend("typeDesignations.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false)
92 .extend("name.nomenclaturalReference", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
93
94 public EntityInitStrategy DERIVEDUNIT_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String[]{
95 "*", // initialize all related entities to allow DerivedUnit conversion, see DerivedUnitConverter.copyPropertiesTo()
96 "derivedFrom.$",
97 "derivedFrom.type", // TODO remove?
98 "derivedFrom.originals.derivationEvents", // important!!
99 "specimenTypeDesignations.typifiedNames.typeDesignations", // important!!
100 "mediaSpecimen.sources.citation",
101 "collection.institute"// see CollectionCaptionGenerator
102 })).extend("mediaSpecimen.sources.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
103
104 public List<String> FIELDUNIT_INIT_STRATEGY = Arrays.asList(new String[]{
105 "$",
106 "annotations.*", // * is needed as log as we are using a table in FilterableAnnotationsField
107 "gatheringEvent.$",
108 "gatheringEvent.country",
109 "gatheringEvent.collectingAreas",
110 "gatheringEvent.actor",
111 "gatheringEvent.exactLocation.$",
112 "derivationEvents.derivatives", // important, otherwise the DerivedUnits are not included into the graph of initialized entities!!!
113
114 });
115
116 public static final List<String> BLOCKING_REGISTRATION_INIT_STRATEGY = Arrays.asList(new String []{
117
118 "blockedBy.blockedBy",
119 // typeDesignation
120 "blockedBy.typeDesignations.typeStatus",
121 // "typeDesignations.typifiedNames.typeDesignations", // important !?
122 // "blockedBy.name.$",
123 "blockedBy.name.nomenclaturalReference.authorship",
124 "blockedBy.name.nomenclaturalReference.inReference",
125 "blockedBy.name.rank",
126 // institution
127 "blockedBy.institution",
128 }
129 );
130
131 /**
132 *
133 */
134 private static final int PAGE_SIZE = 50;
135
136 private static final Logger logger = Logger.getLogger(RegistrationWorkingSetService.class);
137
138 @Autowired
139 @Qualifier("cdmRepository")
140 private CdmRepository repo;
141
142 @Autowired
143 private UserHelper userHelper;
144
145 @Autowired
146 protected IBeanInitializer defaultBeanInitializer;
147
148 public RegistrationWorkingSetService() {
149
150 }
151
152
153 /**
154 * @param id the Registration entity id
155 * @return
156 */
157 @Override
158 public RegistrationDTO loadDtoById(Integer id) {
159 Registration reg = repo.getRegistrationService().load(id, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
160 inititializeSpecimen(reg);
161 return new RegistrationDTO(reg);
162 }
163
164
165 /**
166 * @param id the Registration entity id
167 * @return
168 */
169 @Override
170 public RegistrationDTO loadDtoByUuid(UUID uuid) {
171 Registration reg = repo.getRegistrationService().load(uuid, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
172 inititializeSpecimen(reg);
173 return new RegistrationDTO(reg);
174 }
175
176 @Override
177 public Pager<RegistrationDTO> pageDTOs(String identifier, Integer pageIndex, Integer pageSize) throws IOException {
178
179 Pager<Registration> regPager = repo.getRegistrationService().pageByIdentifier(identifier, pageIndex, pageSize, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
180 return convertToDTOPager(regPager);
181 }
182
183
184 /**
185 * @param regPager
186 * @return
187 */
188 @Override
189 public Pager<RegistrationDTO> convertToDTOPager(Pager<Registration> regPager) {
190 return new DefaultPagerImpl<RegistrationDTO>(regPager.getCurrentIndex(), regPager.getCount(), regPager.getPageSize(), makeDTOs(regPager.getRecords()));
191 }
192
193
194 @Override
195 public Pager<RegistrationDTO> pageDTOs(Integer pageSize, Integer pageIndex) {
196
197 return pageDTOs((UUID)null, null, null, null, null, null, pageSize, pageIndex, null);
198
199 }
200
201 /**
202 * @param submitterUuid
203 * Filter by the uuid of the {@link User} associated with the Registration as <code>Registration.submitter</code>
204 * @param includedStatus
205 * Filter by one or more {@link RegistrationStatus}. Multiple status will be combined with OR. In case the current user
206 * is not authenticated (i.e. the authentication is anonymous) the includedStatus will be set to {@link RegistrationStatus#PUBLISHED}
207 * to protect all other Registrations from being undisclosed.
208 * @param identifierFilterPattern
209 * Filter by the {@link Registration#getIdentifier() Registration.identifier}.
210 * The method matches Registrations which contain the the passed pattern in the identifier.
211 * @param taxonNameFilterPattern
212 * The method matches Registrations which contain the the passed pattern in the
213 * {@link Registration#getName() Registration.name}
214 * @param typeDesignationStatusUuids
215 * Filter by one or more {@link eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus} or {@link eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus}.
216 * Multiple status will be combined with OR.
217 * @param pageSize
218 * @param pageIndex
219 * @param orderHints
220 * @return
221 */
222
223 @Override
224 public Pager<RegistrationDTO> pageDTOs(UUID submitterUuid, Collection<RegistrationStatus> includedStatus, String identifierFilterPattern,
225 String taxonNameFilterPattern, String referenceFilterPattern, Collection<UUID> typeDesignationStatusUuids,
226 Integer pageSize, Integer pageIndex, List<OrderHint> orderHints){
227
228 if(pageSize == null){
229 pageSize = PAGE_SIZE;
230 }
231
232 if(orderHints == null){
233 orderHints = Arrays.asList(new OrderHint("identifier", SortOrder.ASCENDING));
234 }
235
236 Pager<Registration> pager = repo.getRegistrationService().page(submitterUuid, includedStatus,
237 identifierFilterPattern, taxonNameFilterPattern,
238 referenceFilterPattern, typeDesignationStatusUuids, PAGE_SIZE , pageIndex, orderHints, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
239
240 Pager<RegistrationDTO> dtoPager = convertToDTOPager(pager);
241 if(logger.isDebugEnabled()){
242 logger.debug(String.format("pageDTOs() pageIndex: $1%d, pageSize: $2%d, includedStatusUuids: $3%s, typeDesignationStatusUuids: $4%s, taxonNameFilterPattern: $5%s, submitterUuid: $6%s",
243 pageIndex, pageSize, includedStatus, identifierFilterPattern, taxonNameFilterPattern, submitterUuid));
244 logger.debug("pageDTOs() result: " + pager.toString());
245 }
246 return dtoPager;
247
248 }
249
250 @Override
251 public Pager<RegistrationDTO> findInTaxonGraph(UUID submitterUuid, Collection<RegistrationStatus> includedStatus,
252 String taxonNameFilterPattern, MatchMode matchMode,
253 Integer pageSize, Integer pageIndex, List<OrderHint> orderHints) {
254
255 Pager<Registration> regPager = repo.getRegistrationService().pageTaxomicInclusion(null, includedStatus,
256 taxonNameFilterPattern, matchMode,
257 pageSize, pageIndex, orderHints, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
258
259 return convertToDTOPager(regPager);
260 }
261
262
263 /**
264 * {@inheritDoc}
265 * @throws RegistrationValidationException
266 */
267 @Override
268 public RegistrationWorkingSet loadWorkingSetByReferenceUuid(UUID referenceUuid, boolean resolveSections) throws RegistrationValidationException, PermissionDeniedException {
269
270 Reference reference = repo.getReferenceService().load(referenceUuid); // needed to use load to avoid the problem described in #7331
271 if(resolveSections){
272 reference = resolveSection(reference);
273 }
274
275 checkPermissions(reference);
276
277 Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
278
279 /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
280 // debugIssue7331(pager);
281 RegistrationWorkingSet registrationWorkingSet;
282 if(pager.getCount() > 0) {
283 registrationWorkingSet = new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
284 } else {
285 registrationWorkingSet = new RegistrationWorkingSet(reference);
286 }
287 return registrationWorkingSet;
288 }
289
290
291 /**
292 * @param reference
293 */
294 private void checkPermissions(Reference reference) throws PermissionDeniedException {
295
296 boolean permissionDenied = isPermissionDenied(reference);
297 if(permissionDenied) {
298 throw new PermissionDeniedException("Access to the workingset is denied for the current user.");
299 }
300 }
301
302
303 /**
304 * @param reference
305 * @return
306 */
307 public boolean isPermissionDenied(Reference reference) {
308 boolean permissionDenied = false;
309 if(!checkReferencePublished(reference)){
310 permissionDenied = !userHelper.userHasPermission(reference, CRUD.UPDATE);
311 }
312 return permissionDenied;
313 }
314
315
316 /**
317 * @param reference
318 * @return
319 */
320 public boolean checkReferencePublished(Reference reference) {
321
322 if(reference.getDatePublished() == null){
323 return false;
324 }
325 Partial pubPartial = null;
326 if(reference.getDatePublished().getStart() != null){
327 pubPartial = reference.getDatePublished().getStart();
328 } else {
329 pubPartial = reference.getDatePublished().getEnd();
330 }
331 if(pubPartial == null){
332 return !reference.getDatePublished().getFreeText().isEmpty();
333 }
334
335 DateTime nowLocal = new DateTime();
336 //LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
337
338 DateTime pubDateTime = pubPartial.toDateTime(null);
339 return nowLocal.isAfter(pubDateTime);
340
341 }
342
343
344 /**
345 * @param reference
346 * @return
347 */
348 protected Reference resolveSection(Reference reference) {
349 repo.getReferenceService().load(reference.getUuid(), Arrays.asList(new String[]{"inReference"})); // needed to avoid the problem described in #7331
350 if(reference.isOfType(ReferenceType.Section) && reference.getInReference() != null) {
351 reference = reference.getInReference();
352 }
353 return reference;
354 }
355
356 /**
357 * {@inheritDoc}
358 * @throws RegistrationValidationException
359 */
360 @Override
361 public RegistrationWorkingSet loadWorkingSetByReferenceID(Integer referenceID, boolean resolveSections) throws RegistrationValidationException, PermissionDeniedException {
362
363 Reference reference = repo.getReferenceService().find(referenceID);
364 if(resolveSections){
365 reference = resolveSection(reference);
366 }
367
368 checkPermissions(reference);
369
370 repo.getReferenceService().load(reference.getUuid()); // needed to avoid the problem described in #7331
371
372 Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
373
374 /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
375 // debugIssue7331(pager);
376
377 return new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
378 }
379
380
381 /**
382 * @param pager
383 */
384 @SuppressWarnings("unused")
385 private void debugIssue7331(Pager<Registration> pager) {
386 for(Registration reg : pager.getRecords()){
387 if(reg.getName() != null && reg.getName().getNomenclaturalReference().getAuthorship() != null){
388 Reference ref = reg.getName().getNomenclaturalReference();
389 if(!Hibernate.isInitialized(ref.getAuthorship())){
390 logger.error("UNINITIALIZED");
391 }
392 } else {
393 logger.debug("NO AUTHORS");
394 }
395 }
396 }
397
398 @Override
399 public Set<RegistrationDTO> loadBlockingRegistrations(UUID blockedRegistrationUuid){
400
401 Registration registration = repo.getRegistrationService().load(blockedRegistrationUuid, BLOCKING_REGISTRATION_INIT_STRATEGY);
402 Set<Registration> registrations = registration.getBlockedBy();
403
404 Set<RegistrationDTO> blockingSet = new HashSet<>();
405 for(Registration reg : registrations){
406 blockingSet.add(new RegistrationDTO(reg));
407 }
408 return blockingSet;
409 }
410
411 /**
412 * @param regs
413 * @return
414 */
415 @Override
416 public List<RegistrationDTO> makeDTOs(Collection<Registration> regs) {
417 initializeSpecimens(regs);
418 List<RegistrationDTO> dtos = new ArrayList<>(regs.size());
419 regs.forEach(reg -> {dtos.add(new RegistrationDTO(reg));});
420 return dtos;
421 }
422
423
424 /**
425 * @param regs
426 */
427 public void initializeSpecimens(Collection<Registration> regs) {
428 for(Registration reg : regs){
429 inititializeSpecimen(reg);
430 }
431
432 }
433
434
435 /**
436 * @param reg
437 */
438 public void inititializeSpecimen(Registration reg) {
439
440 for(TypeDesignationBase<?> td : reg.getTypeDesignations()){
441 if(td instanceof SpecimenTypeDesignation){
442
443 DerivedUnit derivedUnit = ((SpecimenTypeDesignation) td).getTypeSpecimen();
444 @SuppressWarnings("rawtypes")
445 Set<SpecimenOrObservationBase> sobs = new HashSet<>();
446 sobs.add(HibernateProxyHelper.deproxy(derivedUnit));
447
448 while(sobs != null && !sobs.isEmpty()){
449 @SuppressWarnings("rawtypes")
450 Set<SpecimenOrObservationBase> nextSobs = null;
451 for(@SuppressWarnings("rawtypes") SpecimenOrObservationBase sob : sobs){
452 sob = HibernateProxyHelper.deproxy(sob);
453 if(sob == null){
454 continue;
455 }
456 if(DerivedUnit.class.isAssignableFrom(sob.getClass())) {
457 defaultBeanInitializer.initialize(sob, DERIVEDUNIT_INIT_STRATEGY.getPropertyPaths());
458 nextSobs = ((DerivedUnit)sob).getOriginals();
459 }
460 if(sob instanceof FieldUnit){
461 defaultBeanInitializer.initialize(sob, FIELDUNIT_INIT_STRATEGY);
462 }
463 }
464 sobs = nextSobs;
465 }
466 }
467 }
468 }
469
470
471
472
473
474
475 }