Project

General

Profile

Download (17.9 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.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.hibernate.HibernateProxyHelper;
39
import eu.etaxonomy.cdm.model.common.User;
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.name.TypeDesignationStatusBase;
45
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
46
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
47
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
48
import eu.etaxonomy.cdm.model.reference.Reference;
49
import eu.etaxonomy.cdm.model.reference.ReferenceType;
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 List<String> REGISTRATION_DTO_INIT_STRATEGY = 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.citation.authorship.$",
77
            "typeDesignations.annotations", // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
78
            "typeDesignations.markers", // needed for AnnotatableEntity.clone() in DerivedUnitConverter.copyPropertiesTo
79
            "typeDesignations.registrations", // DerivedUnitConverter.copyPropertiesTo(TARGET n)
80

    
81
            // name
82
            "name.$",
83
            "name.nomenclaturalReference.authorship.$",
84
            "name.nomenclaturalReference.inReference.authorship.$",
85
            "name.rank",
86
            "name.homotypicalGroup.typifiedNames",
87
            "name.status.type",
88
            "name.typeDesignations", // important !!"
89
            // institution
90
            "institution",
91
            }
92
    );
93

    
94
    public  List<String> DERIVEDUNIT_INIT_STRATEGY = 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
   });
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
//          "typeDesignations.typeSpecimen",
123
//          "typeDesignations.typeName.$",
124
//          "typeDesignations.citation",
125
//          "typeDesignations.citation.authorship.$",
126
          // name
127
//          "blockedBy.name.$",
128
          "blockedBy.name.nomenclaturalReference.authorship",
129
          "blockedBy.name.nomenclaturalReference.inReference",
130
          "blockedBy.name.rank",
131
//          "name.homotypicalGroup.typifiedNames",
132
//          "name.status.type",
133
//          "name.typeDesignations",
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 = Logger.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);
168
        inititializeSpecimen(reg);
169
        return new RegistrationDTO(reg);
170
    }
171

    
172

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

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

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

    
191

    
192
    /**
193
     * @param regPager
194
     * @return
195
     */
196
    @Override
197
    public Pager<RegistrationDTO> convertToDTOPager(Pager<Registration> regPager) {
198
        return new DefaultPagerImpl<RegistrationDTO>(regPager.getCurrentIndex(), regPager.getCount(), regPager.getPageSize(), makeDTOs(regPager.getRecords()));
199
    }
200

    
201

    
202
    @Override
203
    public Pager<RegistrationDTO> pageDTOs(Integer pageSize, Integer pageIndex) {
204

    
205
        return pageDTOs((User)null, null, null, null, null, pageSize, pageIndex, null);
206
    }
207

    
208
    /**
209
     * {@inheritDoc}
210
     */
211
    @Override
212
    public Pager<RegistrationDTO> pageDTOs(User submitter, Collection<RegistrationStatus> includedStatus,
213
            String identifierFilterPattern, String taxonNameFilterPattern, Set<TypeDesignationStatusBase> typeStatusFilter,
214
            Integer pageSize, Integer pageIndex, List<OrderHint> orderHints) {
215

    
216
        if(pageSize == null){
217
            pageSize = PAGE_SIZE;
218
        }
219

    
220
        if(orderHints == null){
221
            orderHints = Arrays.asList(new OrderHint("identifier", SortOrder.ASCENDING));
222
        }
223

    
224
        Pager<Registration> pager = repo.getRegistrationService().page(submitter, includedStatus, identifierFilterPattern, taxonNameFilterPattern,
225
                typeStatusFilter, PAGE_SIZE, pageIndex , orderHints, REGISTRATION_DTO_INIT_STRATEGY);
226

    
227
        Pager<RegistrationDTO> dtoPager = convertToDTOPager(pager);
228
        if(logger.isDebugEnabled()){
229
            logger.debug(String.format("pageDTOs() pageIndex: $1%d, pageSize: $2%d, includedStatus: $3%s, identifierFilterPattern: $4%s, taxonNameFilterPattern: $5%s, submitter: $6%s",
230
                    pageIndex, pageSize, includedStatus, identifierFilterPattern, taxonNameFilterPattern, submitter));
231
            logger.debug("pageDTOs() result: " + pager.toString());
232
        }
233
        return dtoPager;
234
    }
235

    
236
    @Override
237
    public Pager<RegistrationDTO> pageDTOs(UUID submitterUuid, Collection<RegistrationStatus> includedStatus, String identifierFilterPattern,
238
            String taxonNameFilterPattern, Collection<UUID> typeDesignationStatusUuids, Integer pageSize,
239
            Integer pageIndex, List<OrderHint> orderHints){
240

    
241
            if(pageSize == null){
242
                pageSize = PAGE_SIZE;
243
            }
244

    
245
            if(orderHints == null){
246
                orderHints = Arrays.asList(new OrderHint("identifier", SortOrder.ASCENDING));
247
            }
248

    
249
            Pager<Registration> pager = repo.getRegistrationService().page(submitterUuid, includedStatus,
250
                    identifierFilterPattern, taxonNameFilterPattern,
251
                    typeDesignationStatusUuids, PAGE_SIZE, pageIndex , orderHints, REGISTRATION_DTO_INIT_STRATEGY);
252

    
253
            Pager<RegistrationDTO> dtoPager = convertToDTOPager(pager);
254
            if(logger.isDebugEnabled()){
255
                logger.debug(String.format("pageDTOs() pageIndex: $1%d, pageSize: $2%d, includedStatusUuids: $3%s, typeDesignationStatusUuids: $4%s, taxonNameFilterPattern: $5%s, submitterUuid: $6%s",
256
                        pageIndex, pageSize, includedStatus, identifierFilterPattern, taxonNameFilterPattern, submitterUuid));
257
                logger.debug("pageDTOs() result: " + pager.toString());
258
            }
259
            return dtoPager;
260

    
261
    }
262

    
263
    @Override
264
    public Pager<RegistrationDTO> findInTaxonGraph(UUID submitterUuid, Collection<RegistrationStatus> includedStatus,
265
            String taxonNameFilterPattern, MatchMode matchMode,
266
            Integer pageSize, Integer pageIndex, List<OrderHint> orderHints) {
267

    
268
        Pager<Registration> regPager = repo.getRegistrationService().pageTaxomicInclusion(null, includedStatus,
269
            taxonNameFilterPattern, matchMode,
270
            pageSize, pageIndex, orderHints, REGISTRATION_DTO_INIT_STRATEGY);
271

    
272
        return convertToDTOPager(regPager);
273
    }
274

    
275

    
276
    /**
277
     * {@inheritDoc}
278
     * @throws RegistrationValidationException
279
     */
280
    @Override
281
    public RegistrationWorkingSet loadWorkingSetByReferenceUuid(UUID referenceUuid, boolean resolveSections) throws RegistrationValidationException, PermissionDeniedException {
282

    
283
        Reference reference = repo.getReferenceService().load(referenceUuid); // needed to use load to avoid the problem described in #7331
284
        if(resolveSections){
285
            reference = resolveSection(reference);
286
        }
287

    
288
        checkPermissions(reference);
289

    
290
        Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY);
291

    
292
        /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
293
        // debugIssue7331(pager);
294
        RegistrationWorkingSet registrationWorkingSet;
295
        if(pager.getCount() > 0) {
296
            registrationWorkingSet = new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
297
        } else {
298
            registrationWorkingSet = new RegistrationWorkingSet(reference);
299
        }
300
        return registrationWorkingSet;
301
    }
302

    
303

    
304
    /**
305
     * @param reference
306
     */
307
    private void checkPermissions(Reference reference) throws PermissionDeniedException {
308

    
309
        boolean permissionDenied = isPermissionDenied(reference);
310
        if(permissionDenied) {
311
            throw new PermissionDeniedException("Access to the workingset is denied for the current user.");
312
        }
313
    }
314

    
315

    
316
    /**
317
     * @param reference
318
     * @return
319
     */
320
    public boolean isPermissionDenied(Reference reference) {
321
        boolean permissionDenied = false;
322
        if(!checkReferencePublished(reference)){
323
            permissionDenied = !userHelper.userHasPermission(reference, CRUD.UPDATE);
324
        }
325
        return permissionDenied;
326
    }
327

    
328

    
329
    /**
330
     * @param reference
331
     * @return
332
     */
333
    public boolean checkReferencePublished(Reference reference) {
334

    
335
        if(reference.getDatePublished() == null){
336
            return false;
337
        }
338
        Partial pubPartial = null;
339
        if(reference.getDatePublished().getStart() != null){
340
            pubPartial = reference.getDatePublished().getStart();
341
        } else {
342
            pubPartial = reference.getDatePublished().getEnd();
343
        }
344
        if(pubPartial == null){
345
            return !reference.getDatePublished().getFreeText().isEmpty();
346
        }
347

    
348
        DateTime nowLocal = new DateTime();
349
        //LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
350

    
351
        DateTime pubDateTime = pubPartial.toDateTime(null);
352
        return nowLocal.isAfter(pubDateTime);
353

    
354
    }
355

    
356

    
357
    /**
358
     * @param reference
359
     * @return
360
     */
361
    protected Reference resolveSection(Reference reference) {
362
        repo.getReferenceService().load(reference.getUuid(), Arrays.asList(new String[]{"inReference"})); // needed to avoid the problem described in #7331
363
        if(reference.isOfType(ReferenceType.Section) && reference.getInReference() != null) {
364
            reference = reference.getInReference();
365
        }
366
        return reference;
367
    }
368

    
369
    /**
370
     * {@inheritDoc}
371
     * @throws RegistrationValidationException
372
     */
373
    @Override
374
    public RegistrationWorkingSet loadWorkingSetByReferenceID(Integer referenceID, boolean resolveSections) throws RegistrationValidationException, PermissionDeniedException {
375

    
376
        Reference reference = repo.getReferenceService().find(referenceID);
377
        if(resolveSections){
378
            reference = resolveSection(reference);
379
        }
380

    
381
        checkPermissions(reference);
382

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

    
385
        Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_DTO_INIT_STRATEGY);
386

    
387
        /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
388
        // debugIssue7331(pager);
389

    
390
        return new RegistrationWorkingSet(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
    /**
425
     * @param regs
426
     * @return
427
     */
428
    @Override
429
    public List<RegistrationDTO> makeDTOs(Collection<Registration> regs) {
430
        initializeSpecimens(regs);
431
        List<RegistrationDTO> dtos = new ArrayList<>(regs.size());
432
        regs.forEach(reg -> {dtos.add(new RegistrationDTO(reg));});
433
        return dtos;
434
    }
435

    
436

    
437
    /**
438
     * @param regs
439
     */
440
    public void initializeSpecimens(Collection<Registration> regs) {
441
        for(Registration reg : regs){
442
            inititializeSpecimen(reg);
443
        }
444

    
445
    }
446

    
447

    
448
    /**
449
     * @param reg
450
     */
451
    public void inititializeSpecimen(Registration reg) {
452

    
453
        for(TypeDesignationBase<?> td : reg.getTypeDesignations()){
454
            if(td instanceof SpecimenTypeDesignation){
455

    
456
                DerivedUnit derivedUnit = ((SpecimenTypeDesignation) td).getTypeSpecimen();
457
                @SuppressWarnings("rawtypes")
458
                Set<SpecimenOrObservationBase> sobs = new HashSet<>();
459
                sobs.add(HibernateProxyHelper.deproxy(derivedUnit));
460

    
461
                while(sobs != null && !sobs.isEmpty()){
462
                    @SuppressWarnings("rawtypes")
463
                    Set<SpecimenOrObservationBase> nextSobs = null;
464
                    for(@SuppressWarnings("rawtypes") SpecimenOrObservationBase sob : sobs){
465
                        sob = HibernateProxyHelper.deproxy(sob);
466
                        if(sob == null){
467
                            continue;
468
                        }
469
                        if(DerivedUnit.class.isAssignableFrom(sob.getClass())) {
470
                            defaultBeanInitializer.initialize(sob, DERIVEDUNIT_INIT_STRATEGY);
471
                            nextSobs = ((DerivedUnit)sob).getOriginals();
472
                        }
473
                        if(sob instanceof FieldUnit){
474
                            defaultBeanInitializer.initialize(sob, FIELDUNIT_INIT_STRATEGY);
475
                        }
476
                    }
477
                    sobs = nextSobs;
478
                }
479
            }
480
        }
481
    }
482

    
483

    
484

    
485

    
486

    
487

    
488
}
(2-2/2)