Project

General

Profile

Download (17.6 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
        return new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
295
    }
296

    
297

    
298
    /**
299
     * @param reference
300
     */
301
    private void checkPermissions(Reference reference) throws PermissionDeniedException {
302

    
303
        boolean permissionDenied = isPermissionDenied(reference);
304
        if(permissionDenied) {
305
            throw new PermissionDeniedException("Access to the workingset is denied for the current user.");
306
        }
307
    }
308

    
309

    
310
    /**
311
     * @param reference
312
     * @return
313
     */
314
    public boolean isPermissionDenied(Reference reference) {
315
        boolean permissionDenied = false;
316
        if(!checkReferencePublished(reference)){
317
            permissionDenied = !userHelper.userHasPermission(reference, CRUD.UPDATE);
318
        }
319
        return permissionDenied;
320
    }
321

    
322

    
323
    /**
324
     * @param reference
325
     * @return
326
     */
327
    public boolean checkReferencePublished(Reference reference) {
328

    
329
        if(reference.getDatePublished() == null){
330
            return false;
331
        }
332
        Partial pubPartial = null;
333
        if(reference.getDatePublished().getStart() != null){
334
            pubPartial = reference.getDatePublished().getStart();
335
        } else {
336
            pubPartial = reference.getDatePublished().getEnd();
337
        }
338
        if(pubPartial == null){
339
            return !reference.getDatePublished().getFreeText().isEmpty();
340
        }
341

    
342
        DateTime nowLocal = new DateTime();
343
        //LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
344

    
345
        DateTime pubDateTime = pubPartial.toDateTime(null);
346
        return nowLocal.isAfter(pubDateTime);
347

    
348
    }
349

    
350

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

    
363
    /**
364
     * {@inheritDoc}
365
     * @throws RegistrationValidationException
366
     */
367
    @Override
368
    public RegistrationWorkingSet loadWorkingSetByReferenceID(Integer referenceID, boolean resolveSections) throws RegistrationValidationException, PermissionDeniedException {
369

    
370
        Reference reference = repo.getReferenceService().find(referenceID);
371
        if(resolveSections){
372
            reference = resolveSection(reference);
373
        }
374

    
375
        checkPermissions(reference);
376

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

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

    
381
        /* for debugging https://dev.e-taxonomy.eu/redmine/issues/7331 */
382
        // debugIssue7331(pager);
383

    
384
        return new RegistrationWorkingSet(makeDTOs(pager.getRecords()));
385
    }
386

    
387

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

    
405
    @Override
406
    public Set<RegistrationDTO> loadBlockingRegistrations(UUID blockedRegistrationUuid){
407

    
408
        Registration registration = repo.getRegistrationService().load(blockedRegistrationUuid, BLOCKING_REGISTRATION_INIT_STRATEGY);
409
        Set<Registration> registrations = registration.getBlockedBy();
410

    
411
        Set<RegistrationDTO> blockingSet = new HashSet<>();
412
        for(Registration reg : registrations){
413
            blockingSet.add(new RegistrationDTO(reg));
414
        }
415
        return blockingSet;
416
    }
417

    
418
    /**
419
     * @param regs
420
     * @return
421
     */
422
    private List<RegistrationDTO> makeDTOs(List<Registration> regs) {
423
        initializeSpecimens(regs);
424
        List<RegistrationDTO> dtos = new ArrayList<>(regs.size());
425
        regs.forEach(reg -> {dtos.add(new RegistrationDTO(reg));});
426
        return dtos;
427
    }
428

    
429

    
430
    /**
431
     * @param regs
432
     */
433
    public void initializeSpecimens(List<Registration> regs) {
434
        for(Registration reg : regs){
435
            inititializeSpecimen(reg);
436
        }
437

    
438
    }
439

    
440

    
441
    /**
442
     * @param reg
443
     */
444
    public void inititializeSpecimen(Registration reg) {
445

    
446
        for(TypeDesignationBase<?> td : reg.getTypeDesignations()){
447
            if(td instanceof SpecimenTypeDesignation){
448

    
449
                DerivedUnit derivedUnit = ((SpecimenTypeDesignation) td).getTypeSpecimen();
450
                @SuppressWarnings("rawtypes")
451
                Set<SpecimenOrObservationBase> sobs = new HashSet<>();
452
                sobs.add(HibernateProxyHelper.deproxy(derivedUnit));
453

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

    
476

    
477

    
478

    
479

    
480

    
481
}
(2-2/2)