Project

General

Profile

Download (18.7 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.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 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.nomenclaturalSource.citation",
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.nomenclaturalSource.citation", 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.nomenclaturalSource.citation.authorship",
124
          "blockedBy.name.nomenclaturalSource.citation.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
    /**
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 RegistrationValidationException
360
     */
361
    @Override
362
    public RegistrationWorkingSet loadWorkingSetByReferenceID(Integer referenceID, boolean resolveSections) throws RegistrationValidationException, 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 RegistrationValidationException, 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
    /**
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.getPropertyPaths());
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)