Project

General

Profile

Download (18.8 KB) Statistics
| Branch: | Tag: | Revision:
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.logging.log4j.LogManager;import org.apache.logging.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.TypeDesignationSetException;
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.util.UserHelper;
37
import eu.etaxonomy.cdm.database.PermissionDeniedException;
38
import eu.etaxonomy.cdm.format.reference.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.permission.CRUD;
48
import eu.etaxonomy.cdm.model.reference.Reference;
49
import eu.etaxonomy.cdm.model.reference.ReferenceType;
50
import eu.etaxonomy.cdm.persistence.dao.initializer.EntityInitStrategy;
51
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
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 TYPEDESIGNATION_INIT_STRATEGY = new EntityInitStrategy(
69
            "typeStatus",
70
            "typifiedNames.typeDesignations", // important !!
71
            "typeSpecimen",
72
            "typeName.$",
73
            "designationSource.annotations",
74
            "designationSource.links",
75
            "designationSource.markers",
76
            "annotations",   // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
77
            "markers",       // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
78
            "registrations" // DerivedUnitConverter.copyPropertiesTo(TARGET n));
79
            )
80
            .extend("designationSource.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
81

    
82
    public static final EntityInitStrategy NAME_INIT_STRATEGY = new EntityInitStrategy(
83
                "$",
84
                "nomenclaturalSource.citation.inReference.inReference",
85
                "rank",
86
                "homotypicalGroup.typifiedNames",
87
                "status.type",
88
                "typeDesignations" // important !!!
89
            )
90
            .extend("nomenclaturalSource.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
91

    
92
    public static final EntityInitStrategy REGISTRATION_DTO_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String []{
93
                "blockedBy",
94
                // institution
95
                "institution",
96
                }
97
                )
98
            )
99
            .extend("name", NAME_INIT_STRATEGY, false)
100
            .extend("typeDesignations", TYPEDESIGNATION_INIT_STRATEGY, true);
101

    
102
    public  EntityInitStrategy DERIVEDUNIT_INIT_STRATEGY = new EntityInitStrategy(Arrays.asList(new String[]{
103
           "*", // initialize all related entities to allow DerivedUnit conversion, see DerivedUnitConverter.copyPropertiesTo()
104
           "derivedFrom.$",
105
           "derivedFrom.type", // TODO remove?
106
           "derivedFrom.originals.derivationEvents", // important!!
107
           "specimenTypeDesignations.typifiedNames.typeDesignations", // important!!
108
           "mediaSpecimen.sources.citation",
109
           "collection.institute"// see CollectionCaptionGenerator
110
   })).extend("mediaSpecimen.sources.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
111

    
112
   public List<String> FIELDUNIT_INIT_STRATEGY = Arrays.asList(new String[]{
113
          "$",
114
          "annotations.*", // * is needed as log as we are using a table in FilterableAnnotationsField
115
          "gatheringEvent.$",
116
          "gatheringEvent.country",
117
          "gatheringEvent.collectingAreas",
118
          "gatheringEvent.actor",
119
          "gatheringEvent.exactLocation.$",
120
          "derivationEvents.derivatives", // important, otherwise the DerivedUnits are not included into the graph of initialized entities!!!
121

    
122
  });
123

    
124
  public static final List<String> BLOCKING_REGISTRATION_INIT_STRATEGY = Arrays.asList(new String []{
125

    
126
          "blockedBy.blockedBy",
127
          // typeDesignation
128
          "blockedBy.typeDesignations.typeStatus",
129
//          "typeDesignations.typifiedNames.typeDesignations", // important !?
130
//          "blockedBy.name.$",
131
          "blockedBy.name.nomenclaturalSource.citation.authorship",
132
          "blockedBy.name.nomenclaturalSource.citation.inReference",
133
          "blockedBy.name.rank",
134
          // institution
135
          "blockedBy.institution",
136
          }
137
  );
138

    
139
    /**
140
     *
141
     */
142
    private static final int PAGE_SIZE = 50;
143

    
144
    private static final Logger logger = LogManager.getLogger(RegistrationWorkingSetService.class);
145

    
146
    @Autowired
147
    @Qualifier("cdmRepository")
148
    private CdmRepository repo;
149

    
150
    @Autowired
151
    private UserHelper userHelper;
152

    
153
    @Autowired
154
    protected IBeanInitializer defaultBeanInitializer;
155

    
156
    public RegistrationWorkingSetService() {
157

    
158
    }
159

    
160

    
161
    /**
162
     * @param id the Registration entity id
163
     * @return
164
     */
165
    @Override
166
    public RegistrationDTO loadDtoById(Integer id) {
167
        Registration reg = repo.getRegistrationService().load(id, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
168
        inititializeSpecimen(reg);
169
        return new RegistrationDTO(reg);
170
    }
171

    
172
    /**
173
     * @param id the Registration entity id
174
     * @return
175
     */
176
    @Override
177
    public RegistrationDTO loadDtoByUuid(UUID uuid) {
178
        Registration reg = repo.getRegistrationService().load(uuid, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
179
        inititializeSpecimen(reg);
180
        return new RegistrationDTO(reg);
181
    }
182

    
183
    @Override
184
    public Pager<RegistrationDTO> pageDTOs(String identifier, Integer pageIndex,  Integer pageSize) throws IOException {
185

    
186
        Pager<Registration> regPager = repo.getRegistrationService().pageByIdentifier(identifier, pageIndex, pageSize, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
187
        return convertToDTOPager(regPager);
188
    }
189

    
190
    @Override
191
    public Pager<RegistrationDTO> convertToDTOPager(Pager<Registration> regPager) {
192
        return new DefaultPagerImpl<>(regPager.getCurrentIndex(), regPager.getCount(),
193
                regPager.getPageSize(), makeDTOs(regPager.getRecords()));
194
    }
195

    
196
    @Override
197
    public Pager<RegistrationDTO> pageDTOs(Integer pageSize, Integer pageIndex) {
198
        return pageDTOs((UUID)null, null, null, null, null, null, pageSize, pageIndex, null);
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 TypeDesignationSetException
266
     */
267
    @Override
268
    public RegistrationWorkingSet loadWorkingSetByReferenceUuid(UUID referenceUuid, boolean resolveSections) throws TypeDesignationSetException, 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
    /**
318
     * @param reference
319
     * @return
320
     */
321
    public boolean checkReferencePublished(Reference reference) {
322

    
323
        if(reference.getDatePublished() == null){
324
            return false;
325
        }
326
        Partial pubPartial = null;
327
        if(reference.getDatePublished().getStart() != null){
328
            pubPartial = reference.getDatePublished().getStart();
329
        } else {
330
            pubPartial = reference.getDatePublished().getEnd();
331
        }
332
        if(pubPartial == null){
333
            return !reference.getDatePublished().getFreeText().isEmpty();
334
        }
335

    
336
        DateTime nowLocal = new DateTime();
337
        //LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
338

    
339
        DateTime pubDateTime = pubPartial.toDateTime(null);
340
        return nowLocal.isAfter(pubDateTime);
341

    
342
    }
343

    
344

    
345
    /**
346
     * @param reference
347
     * @return
348
     */
349
    protected Reference resolveSection(Reference reference) {
350
        repo.getReferenceService().load(reference.getUuid(), Arrays.asList(new String[]{"inReference"})); // needed to avoid the problem described in #7331
351
        if(reference.isOfType(ReferenceType.Section) && reference.getInReference() != null) {
352
            reference = reference.getInReference();
353
        }
354
        return reference;
355
    }
356

    
357
    /**
358
     * {@inheritDoc}
359
     * @throws TypeDesignationSetException
360
     */
361
    @Override
362
    public RegistrationWorkingSet loadWorkingSetByReferenceID(Integer referenceID, boolean resolveSections) throws TypeDesignationSetException, PermissionDeniedException {
363

    
364
        Reference reference = repo.getReferenceService().find(referenceID);
365
        if(resolveSections){
366
            reference = resolveSection(reference);
367
        }
368

    
369
        checkPermissions(reference);
370

    
371
        repo.getReferenceService().load(reference.getUuid()); // needed to avoid the problem described in #7331
372

    
373
        Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
374

    
375
        /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
376
        // debugIssue7331(pager);
377

    
378
        return new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
379
    }
380

    
381
    @Override
382
    public Pager<RegistrationDTO> pageWorkingSetsByNameUUID(Collection<UUID> taxonNameUuids, Integer pageIndex, Integer pageSize, List<OrderHint> orderHints) throws TypeDesignationSetException, PermissionDeniedException {
383

    
384
        if(orderHints == null){
385
            orderHints = Arrays.asList(new OrderHint("identifier", SortOrder.ASCENDING));
386
        }
387

    
388
        Pager<Registration> pager = repo.getRegistrationService().page((UUID)null, null, taxonNameUuids, pageSize, pageIndex, orderHints, REGISTRATION_DTO_INIT_STRATEGY.getPropertyPaths());
389

    
390
        return new DefaultPagerImpl<RegistrationDTO>(pager.getCurrentIndex(), pager.getCount(), pager.getPageSize(), makeDTOs(pager.getRecords()));
391
    }
392

    
393

    
394
    /**
395
     * @param pager
396
     */
397
    @SuppressWarnings("unused")
398
    private void debugIssue7331(Pager<Registration> pager) {
399
        for(Registration reg : pager.getRecords()){
400
            if(reg.getName() != null && reg.getName().getNomenclaturalReference().getAuthorship() != null){
401
                Reference ref = reg.getName().getNomenclaturalReference();
402
                if(!Hibernate.isInitialized(ref.getAuthorship())){
403
                    logger.error("UNINITIALIZED");
404
                }
405
            } else {
406
                logger.debug("NO AUTHORS");
407
            }
408
        }
409
    }
410

    
411
    @Override
412
    public Set<RegistrationDTO> loadBlockingRegistrations(UUID blockedRegistrationUuid){
413

    
414
        Registration registration = repo.getRegistrationService().load(blockedRegistrationUuid, BLOCKING_REGISTRATION_INIT_STRATEGY);
415
        Set<Registration> registrations = registration.getBlockedBy();
416

    
417
        Set<RegistrationDTO> blockingSet = new HashSet<>();
418
        for(Registration reg : registrations){
419
            blockingSet.add(new RegistrationDTO(reg));
420
        }
421
        return blockingSet;
422
    }
423

    
424
    @Override
425
    public List<RegistrationDTO> makeDTOs(Collection<Registration> regs) {
426
        initializeSpecimens(regs);
427
        List<RegistrationDTO> dtos = new ArrayList<>(regs.size());
428
        regs.forEach(reg -> {dtos.add(new RegistrationDTO(reg));});
429
        return dtos;
430
    }
431

    
432
    public void initializeSpecimens(Collection<Registration> regs) {
433
        for(Registration reg : regs){
434
            inititializeSpecimen(reg);
435
        }
436
    }
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
}
(2-2/2)