2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.api
.service
;
11 import java
.io
.IOException
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Arrays
;
14 import java
.util
.Collection
;
15 import java
.util
.HashMap
;
16 import java
.util
.List
;
18 import java
.util
.Optional
;
20 import java
.util
.UUID
;
21 import java
.util
.stream
.Collectors
;
23 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
24 import org
.springframework
.security
.core
.Authentication
;
25 import org
.springframework
.stereotype
.Service
;
26 import org
.springframework
.transaction
.annotation
.Transactional
;
28 import eu
.etaxonomy
.cdm
.api
.service
.idminter
.IdentifierMinter
.Identifier
;
29 import eu
.etaxonomy
.cdm
.api
.service
.idminter
.RegistrationIdentifierMinter
;
30 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
31 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.AbstractPagerImpl
;
32 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
33 import eu
.etaxonomy
.cdm
.api
.service
.taxonGraph
.ITaxonGraphService
;
34 import eu
.etaxonomy
.cdm
.api
.utility
.UserHelper
;
35 import eu
.etaxonomy
.cdm
.model
.common
.User
;
36 import eu
.etaxonomy
.cdm
.model
.name
.Registration
;
37 import eu
.etaxonomy
.cdm
.model
.name
.RegistrationStatus
;
38 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
39 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
40 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationStatusBase
;
41 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
42 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.Restriction
;
43 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.IRegistrationDao
;
44 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.Operation
;
45 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
46 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
49 * @author a.kohlbecker
54 @Transactional(readOnly
= true)
55 public class RegistrationServiceImpl
extends AnnotatableServiceBase
<Registration
, IRegistrationDao
>
56 implements IRegistrationService
{
63 protected void setDao(IRegistrationDao dao
) {
67 @Autowired(required
=false)
68 private RegistrationIdentifierMinter minter
;
71 private UserHelper userHelper
;
74 private INameService nameService
;
77 private ITaxonGraphService taxonGraphService
;
86 @Transactional(readOnly
= true)
87 public Pager
<Registration
> page(Optional
<Reference
> reference
, Collection
<RegistrationStatus
> includedStatus
,
88 Integer pageSize
, Integer pageIndex
, List
<String
> propertyPaths
) {
90 if( !userHelper
.userIsAutheticated() || userHelper
.userIsAnnonymous() ) {
91 includedStatus
= Arrays
.asList(RegistrationStatus
.PUBLISHED
);
94 long numberOfResults
= dao
.count(reference
, includedStatus
);
96 List
<Registration
> results
= new ArrayList
<>();
97 Integer
[] limitStart
= AbstractPagerImpl
.limitStartforRange(numberOfResults
, pageIndex
, pageSize
);
98 if(limitStart
!= null) {
99 results
= dao
.list(reference
, includedStatus
, limitStart
[0], limitStart
[1], propertyPaths
);
102 return new DefaultPagerImpl
<>(pageIndex
, numberOfResults
, pageSize
, results
);
109 @Transactional(readOnly
= true)
110 public Pager
<Registration
> page(User submitter
, Collection
<RegistrationStatus
> includedStatus
,
111 String identifierFilterPattern
, String taxonNameFilterPattern
, Set
<TypeDesignationStatusBase
> typeDesignationStatus
,
112 Integer pageSize
, Integer pageIndex
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
114 List
<Restriction
<?
extends Object
>> restrictions
= new ArrayList
<>();
116 if( !userHelper
.userIsAutheticated() || userHelper
.userIsAnnonymous() ) {
117 includedStatus
= Arrays
.asList(RegistrationStatus
.PUBLISHED
);
120 if(submitter
!= null){
121 restrictions
.add(new Restriction
<>("submitter", MatchMode
.EXACT
, submitter
));
123 if(includedStatus
!= null && !includedStatus
.isEmpty()){
124 restrictions
.add(new Restriction
<>("status", MatchMode
.EXACT
, includedStatus
.toArray(new RegistrationStatus
[includedStatus
.size()])));
126 if(identifierFilterPattern
!= null){
127 restrictions
.add(new Restriction
<>("identifier", MatchMode
.LIKE
, identifierFilterPattern
));
129 if(taxonNameFilterPattern
!= null){
130 restrictions
.add(new Restriction
<>("name.titleCache", MatchMode
.LIKE
, taxonNameFilterPattern
));
132 if(typeDesignationStatus
!= null){
133 restrictions
.add(new Restriction
<>("typeDesignations.typeStatus", null, typeDesignationStatus
.toArray(new TypeDesignationStatusBase
[typeDesignationStatus
.size()])));
136 long numberOfResults
= dao
.count(Registration
.class, restrictions
);
138 List
<Registration
> results
= new ArrayList
<>();
139 Integer
[] limitStart
= AbstractPagerImpl
.limitStartforRange(numberOfResults
, pageIndex
, pageSize
);
140 if(limitStart
!= null) {
141 results
= dao
.list(Registration
.class, restrictions
, limitStart
[0], limitStart
[1], orderHints
, propertyPaths
);
144 return new DefaultPagerImpl
<>(pageIndex
, numberOfResults
, pageSize
, results
);
148 @Transactional(readOnly
= true)
149 public Pager
<Registration
> page(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
,
150 String identifierFilterPattern
, String taxonNameFilterPattern
, Collection
<UUID
> typeDesignationStatusUuids
,
151 Integer pageSize
, Integer pageIndex
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
153 List
<Restriction
<?
extends Object
>> restrictions
= new ArrayList
<>();
155 if( !userHelper
.userIsAutheticated() || userHelper
.userIsAnnonymous() ) {
156 includedStatus
= Arrays
.asList(RegistrationStatus
.PUBLISHED
);
159 if(submitterUuid
!= null){
160 restrictions
.add(new Restriction
<>("submitter.uuid", null, submitterUuid
));
162 if(includedStatus
!= null && !includedStatus
.isEmpty()){
163 restrictions
.add(new Restriction
<>("status", null, includedStatus
.toArray(new RegistrationStatus
[includedStatus
.size()])));
165 if(identifierFilterPattern
!= null){
166 restrictions
.add(new Restriction
<>("identifier", MatchMode
.LIKE
, identifierFilterPattern
));
168 if(taxonNameFilterPattern
!= null){
169 restrictions
.add(new Restriction
<>("name.titleCache", MatchMode
.LIKE
, taxonNameFilterPattern
));
171 if(typeDesignationStatusUuids
!= null){
172 restrictions
.add(new Restriction
<>("typeDesignations.typeStatus.uuid", null, typeDesignationStatusUuids
.toArray(new UUID
[typeDesignationStatusUuids
.size()])));
175 long numberOfResults
= dao
.count(Registration
.class, restrictions
);
177 List
<Registration
> results
= new ArrayList
<>();
178 if(pageIndex
== null){
181 Integer
[] limitStart
= AbstractPagerImpl
.limitStartforRange(numberOfResults
, pageIndex
, pageSize
);
182 if(limitStart
!= null) {
183 results
= dao
.list(Registration
.class, restrictions
, limitStart
[0], limitStart
[1], orderHints
, propertyPaths
);
186 return new DefaultPagerImpl
<>(pageIndex
, numberOfResults
, pageSize
, results
);
190 @Transactional(readOnly
= true)
191 public Pager
<Registration
> pageTaxomicInclusion(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
,
192 String taxonNameFilterPattern
, MatchMode matchMode
,
193 Integer pageSize
, Integer pageIndex
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
195 List
<TaxonName
> includedNames
= taxonGraphService
.listIncludedNames(taxonNameFilterPattern
, matchMode
);
196 Set
<UUID
> includedNamesUuids
= includedNames
.stream().map(TaxonName
::getUuid
).collect(Collectors
.toSet());
198 if(includedNames
.size() > 0){
199 return page(submitterUuid
, includedStatus
, includedNamesUuids
, pageSize
, pageIndex
, orderHints
, propertyPaths
);
201 return new DefaultPagerImpl
<>(pageIndex
, 0l, pageSize
, new ArrayList
<Registration
>());
206 @Transactional(readOnly
= true)
207 public Pager
<Registration
> page(UUID submitterUuid
, Collection
<RegistrationStatus
> includedStatus
,
208 Collection
<UUID
> taxonNameUUIDs
,
209 Integer pageSize
, Integer pageIndex
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
211 List
<Restriction
<?
extends Object
>> restrictions
= new ArrayList
<>();
213 if( !userHelper
.userIsAutheticated() || userHelper
.userIsAnnonymous() ) {
214 includedStatus
= Arrays
.asList(RegistrationStatus
.PUBLISHED
);
217 if(submitterUuid
!= null){
218 restrictions
.add(new Restriction
<>("submitter.uuid", null, submitterUuid
));
220 if(includedStatus
!= null && !includedStatus
.isEmpty()){
221 restrictions
.add(new Restriction
<>("status", null, includedStatus
.toArray(new RegistrationStatus
[includedStatus
.size()])));
224 if(taxonNameUUIDs
!= null){
225 restrictions
.add(new Restriction
<>("name.uuid", null , taxonNameUUIDs
.toArray(new UUID
[taxonNameUUIDs
.size()])));
228 long numberOfResults
= dao
.count(Registration
.class, restrictions
);
230 List
<Registration
> results
= new ArrayList
<>();
231 if(pageIndex
== null){
234 Integer
[] limitStart
= AbstractPagerImpl
.limitStartforRange(numberOfResults
, pageIndex
, pageSize
);
235 if(limitStart
!= null) {
236 results
= dao
.list(Registration
.class, restrictions
, limitStart
[0], limitStart
[1], orderHints
, propertyPaths
);
239 return new DefaultPagerImpl
<>(pageIndex
, numberOfResults
, pageSize
, results
);
244 * @param validateUniqueness
247 * @throws IOException
250 @Transactional(readOnly
= true)
251 public Pager
<Registration
> pageByIdentifier(String identifier
, Integer pageIndex
, Integer pageSize
, List
<String
> propertyPaths
) throws IOException
{
253 List
<Restriction
<?
>> restrictions
= new ArrayList
<>();
254 if( !userHelper
.userIsAutheticated() || userHelper
.userIsAnnonymous() ) {
255 restrictions
.add(new Restriction
<>("status", null, RegistrationStatus
.PUBLISHED
));
258 Pager
<Registration
> regPager
= pageByRestrictions(Registration
.class, "identifier", identifier
, MatchMode
.EXACT
,
259 restrictions
, pageSize
, pageIndex
, null, propertyPaths
);
266 @Transactional(readOnly
= true)
267 public Map
<UUID
, RegistrationStatus
> statusByIdentifier(String identifier
) throws IOException
{
269 Pager
<Registration
> regPager
= pageByRestrictions(Registration
.class, "identifier", identifier
, MatchMode
.EXACT
,
270 null, null, null, null, Arrays
.asList("status"));
272 Map
<UUID
, RegistrationStatus
> map
= new HashMap
<>();
273 for(Registration reg
: regPager
.getRecords()){
274 map
.put(reg
.getUuid(), reg
.getStatus());
284 public Registration
save(Registration newInstance
) {
285 return assureIsPersisted(newInstance
);
292 public UUID
saveOrUpdate(Registration transientObject
) {
293 transientObject
= assureIsPersisted(transientObject
);
294 return super.saveOrUpdate(transientObject
);
302 public Map
<UUID
, Registration
> save(Collection
<Registration
> newInstances
) {
303 Map
<UUID
, Registration
> regs
= new HashMap
<>();
304 for(Registration newInstance
: newInstances
) {
305 Registration reg
= save(newInstance
);
306 regs
.put(reg
.getUuid(), reg
);
315 public Map
<UUID
, Registration
> saveOrUpdate(Collection
<Registration
> transientInstances
) {
316 Map
<UUID
, Registration
> regs
= new HashMap
<>();
317 for(Registration transientInstance
: transientInstances
) {
318 UUID uuid
= saveOrUpdate(transientInstance
);
319 regs
.put(uuid
, transientInstance
);
324 // ============= functionality to be moved into a "RegistrationManagerBean" ==================
329 * TODO move into RegistrationFactory
331 * @return a new Registration instance with submitter set to the current authentications principal
334 public Registration
newRegistration() {
336 Registration reg
= Registration
.NewInstance(
341 Authentication authentication
= userHelper
.getAuthentication();
342 reg
.setSubmitter((User
)authentication
.getPrincipal());
351 @Transactional(readOnly
=false)
352 public Registration
createRegistrationForName(UUID taxonNameUuid
) {
354 Registration reg
= Registration
.NewInstance(
357 taxonNameUuid
!= null ? nameService
.load(taxonNameUuid
, Arrays
.asList("nomenclaturalReference.inReference")) : null,
360 reg
= assureIsPersisted(reg
);
362 return load(reg
.getUuid(), Arrays
.asList(new String
[]{"blockedBy"}));
366 * @param typeDesignationTarget
369 @Transactional(readOnly
=false)
370 public Registration
assureIsPersisted(Registration reg
) {
372 if(reg
.isPersited()){
377 reg
= super.save(reg
);
378 userHelper
.createAuthorityForCurrentUser(reg
, Operation
.UPDATE
, RegistrationStatus
.PREPARATION
.name());
384 @Transactional(readOnly
=false)
385 public void addTypeDesignation(UUID registrationUUID
, UUID typeDesignationUuid
){
387 // load the typeDesignations with the registration so that typified names can not be twice in detached sessions
388 // otherwise multiple representation problems might occur
389 Registration registration
= load(registrationUUID
, Arrays
.asList("typeDesignations"));
390 if(registration
== null){
391 registration
= newRegistration();
392 registration
= assureIsPersisted(registration
);
394 TypeDesignationBase
<?
> nameTypeDesignation
= nameService
.loadTypeDesignation(typeDesignationUuid
, Arrays
.asList(""));
395 registration
.getTypeDesignations().add(nameTypeDesignation
);
399 @Transactional(readOnly
=false)
400 public void addTypeDesignation(Registration registration
, UUID typeDesignationUuid
){
402 if(registration
== null){
403 registration
= newRegistration();
404 registration
= assureIsPersisted(registration
);
406 if(registration
.isPersited()){
407 // make sure the the typeDesignations are loaded with the registration so that typified names can not be twice in detached sessions
408 // otherwise multiple representation problems might occur
409 registration
.getTypeDesignations();
412 TypeDesignationBase
<?
> nameTypeDesignation
= nameService
.loadTypeDesignation(typeDesignationUuid
, Arrays
.asList(""));
413 registration
.getTypeDesignations().add(nameTypeDesignation
);
417 * Sets the registration identifier and submitter in case the registration is not yet persisted.
420 * The Registration to prepare for saving.
422 private void prepareForSave(Registration reg
) {
424 if(!reg
.isPersited()){
426 Identifier
<String
> identifiers
= minter
.mint();
427 if(identifiers
.getIdentifier() == null){
428 throw new RuntimeException("RegistrationIdentifierMinter configuration incomplete.");
430 reg
.setIdentifier(identifiers
.getIdentifier());
431 reg
.setSpecificIdentifier(identifiers
.getLocalId());
433 Authentication authentication
= userHelper
.getAuthentication();
434 reg
.setSubmitter((User
)authentication
.getPrincipal());
442 public boolean checkRegistrationExistsFor(TaxonName name
) {
444 for(Registration reg
: name
.getRegistrations()){
446 if(minter
.isFromOwnRegistration(reg
.getIdentifier())){
450 return true; // first registrations wins as we can't distinguish them without a minter.
458 // =============================================================================================