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
.vaadin
.view
.registration
;
11 import java
.util
.ArrayList
;
12 import java
.util
.EnumSet
;
13 import java
.util
.List
;
15 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
16 import org
.springframework
.context
.event
.EventListener
;
17 import org
.springframework
.security
.core
.Authentication
;
18 import org
.springframework
.transaction
.TransactionStatus
;
20 import com
.vaadin
.spring
.annotation
.SpringComponent
;
21 import com
.vaadin
.spring
.annotation
.ViewScope
;
22 import com
.vaadin
.ui
.Label
;
23 import com
.vaadin
.ui
.UI
;
24 import com
.vaadin
.ui
.VerticalLayout
;
25 import com
.vaadin
.ui
.Window
;
27 import eu
.etaxonomy
.cdm
.api
.service
.INameService
;
28 import eu
.etaxonomy
.cdm
.api
.service
.IRegistrationService
;
29 import eu
.etaxonomy
.cdm
.api
.service
.idminter
.IdentifierMinter
.Identifier
;
30 import eu
.etaxonomy
.cdm
.api
.service
.idminter
.RegistrationIdentifierMinter
;
31 import eu
.etaxonomy
.cdm
.model
.common
.User
;
32 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
33 import eu
.etaxonomy
.cdm
.model
.name
.Registration
;
34 import eu
.etaxonomy
.cdm
.model
.name
.RegistrationStatus
;
35 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
36 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
37 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
38 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
39 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.CRUD
;
40 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.Operation
;
41 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProvider
;
42 import eu
.etaxonomy
.cdm
.service
.CdmStore
;
43 import eu
.etaxonomy
.cdm
.service
.IRegistrationWorkingSetService
;
44 import eu
.etaxonomy
.cdm
.vaadin
.event
.EntityChangeEvent
;
45 import eu
.etaxonomy
.cdm
.vaadin
.event
.ReferenceEditorAction
;
46 import eu
.etaxonomy
.cdm
.vaadin
.event
.RegistrationEditorAction
;
47 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEvent
;
48 import eu
.etaxonomy
.cdm
.vaadin
.event
.TaxonNameEditorAction
;
49 import eu
.etaxonomy
.cdm
.vaadin
.event
.TypeDesignationWorkingsetEditorAction
;
50 import eu
.etaxonomy
.cdm
.vaadin
.event
.registration
.RegistrationWorkingsetAction
;
51 import eu
.etaxonomy
.cdm
.vaadin
.model
.EntityReference
;
52 import eu
.etaxonomy
.cdm
.vaadin
.model
.registration
.RegistrationWorkingSet
;
53 import eu
.etaxonomy
.cdm
.vaadin
.security
.UserHelper
;
54 import eu
.etaxonomy
.cdm
.vaadin
.ui
.RegistrationUIDefaults
;
55 import eu
.etaxonomy
.cdm
.vaadin
.util
.CdmTitleCacheCaptionGenerator
;
56 import eu
.etaxonomy
.cdm
.vaadin
.util
.converter
.TypeDesignationSetManager
.TypeDesignationWorkingSetType
;
57 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationWorkingsetPopupEditor
;
58 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNamePopupEditor
;
59 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNamePopupEditorMode
;
60 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TypeDesignationWorkingsetEditorIdSet
;
61 import eu
.etaxonomy
.cdm
.vaadin
.view
.reference
.ReferencePopupEditor
;
62 import eu
.etaxonomy
.vaadin
.mvp
.AbstractPresenter
;
63 import eu
.etaxonomy
.vaadin
.ui
.view
.DoneWithPopupEvent
;
64 import eu
.etaxonomy
.vaadin
.ui
.view
.DoneWithPopupEvent
.Reason
;
67 * @author a.kohlbecker
73 public class RegistrationWorkingsetPresenter
extends AbstractPresenter
<RegistrationWorkingsetView
> {
75 private static final long serialVersionUID
= 1L;
78 private IRegistrationWorkingSetService workingSetService
;
81 private RegistrationIdentifierMinter minter
;
84 * @return the workingSetService
86 public IRegistrationWorkingSetService
getWorkingSetService() {
87 return workingSetService
;
90 private RegistrationWorkingSet workingset
;
92 private TaxonName newTaxonNameForRegistration
= null;
94 private RegistrationDTO newRegistrationDTOWithExistingName
;
100 public RegistrationWorkingsetPresenter() {
105 * Always create a new Store
109 protected CdmStore
<Registration
, IRegistrationService
> getRegistrationStore(){
110 return new CdmStore
<Registration
, IRegistrationService
>(getRepo(), getRepo().getRegistrationService());
114 * Always create a new Store
118 protected CdmStore
<TaxonName
, INameService
> getTaxonNameStore(){
119 return new CdmStore
<TaxonName
, INameService
>(getRepo(), getRepo().getNameService());
127 protected Registration
createNewRegistrationForName(Integer taxonNameId
) {
128 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129 // move into RegistrationWorkflowStateMachine
130 TransactionStatus txStatus
= getRepo().startTransaction();
131 long identifier
= System
.currentTimeMillis();
133 Identifier
<String
> identifiers
= minter
.mint();
134 if(identifiers
.getIdentifier() == null){
135 throw new RuntimeException("RegistrationIdentifierMinter configuration incomplete.");
137 Registration reg
= Registration
.NewInstance(
138 identifiers
.getIdentifier(),
139 identifiers
.getLocalId(),
140 taxonNameId
!= null ?
getRepo().getNameService().find(taxonNameId
) : null,
142 Authentication authentication
= currentSecurityContext().getAuthentication();
143 reg
.setSubmitter((User
)authentication
.getPrincipal());
144 EntityChangeEvent event
= getRegistrationStore().saveBean(reg
);
145 UserHelper
.fromSession().createAuthorityForCurrentUser(Registration
.class, event
.getEntityId(), Operation
.UPDATE
, RegistrationStatus
.PREPARATION
.name());
146 getRepo().commitTransaction(txStatus
);
147 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 return getRepo().getRegistrationService().find(event
.getEntityId());
153 * @param doReload TODO
156 protected void refreshView(boolean doReload
) {
158 loadWorkingSet(workingset
.getCitationId());
160 getView().setWorkingset(workingset
);
168 public void handleViewEntered() {
170 super.handleViewEntered();
172 loadWorkingSet(getView().getCitationID());
173 getView().setWorkingset(workingset
);
175 CdmFilterablePagingProvider
<TaxonName
, TaxonName
> pagingProvider
= new CdmFilterablePagingProvider
<TaxonName
, TaxonName
>(
176 getRepo().getNameService());
177 CdmTitleCacheCaptionGenerator
<TaxonName
> titleCacheGenrator
= new CdmTitleCacheCaptionGenerator
<TaxonName
>();
178 getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenrator
);
179 getView().getAddExistingNameCombobox().loadFrom(pagingProvider
, pagingProvider
, pagingProvider
.getPageSize());
186 protected void loadWorkingSet(Integer referenceID
) {
188 workingset
= getWorkingSetService().loadWorkingSetByReferenceID(referenceID
);
189 } catch (RegistrationValidationException error
) {
191 Window errorDialog
= new Window("Validation Error");
192 errorDialog
.setModal(true);
193 VerticalLayout subContent
= new VerticalLayout();
194 subContent
.setMargin(true);
195 errorDialog
.setContent(subContent
);
196 subContent
.addComponent(new Label(error
.getMessage()));
197 UI
.getCurrent().addWindow(errorDialog
);
199 if(workingset
== null || workingset
.getCitationId() == null){
200 Reference citation
= getRepo().getReferenceService().find(referenceID
);
201 workingset
= new RegistrationWorkingSet(citation
);
205 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).ADD")
206 public void onReferenceEditorActionAdd(ReferenceEditorAction event
) {
208 if(!checkFromOwnView(event
)){
212 ReferencePopupEditor popup
= getNavigationManager().showInPopup(ReferencePopupEditor
.class);
213 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
214 popup
.loadInEditor(null);
217 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).EDIT")
218 public void onReferenceEditorActionEdit(ReferenceEditorAction event
) {
220 if(!checkFromOwnView(event
)){
223 ReferencePopupEditor popup
= getNavigationManager().showInPopup(ReferencePopupEditor
.class);
224 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
225 popup
.withDeleteButton(true);
226 popup
.loadInEditor(event
.getEntityId());
229 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).EDIT")
230 public void onRegistrationEditorAction(RegistrationEditorAction event
) {
232 if(!checkFromOwnView(event
)){
236 RegistrationPopupEditor popup
= getNavigationManager().showInPopup(RegistrationPopupEditor
.class);
237 popup
.loadInEditor(event
.getEntityId());
240 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).EDIT")
241 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event
) {
243 if(!checkFromOwnView(event
)){
247 TaxonNamePopupEditor popup
= getNavigationManager().showInPopup(TaxonNamePopupEditor
.class);
248 popup
.withDeleteButton(true);
249 configureTaxonNameEditor(popup
);
250 popup
.loadInEditor(event
.getEntityId());
251 if(event
.getSourceComponent() != null){
252 popup
.setReadOnly(event
.getSourceComponent().isReadOnly());
258 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).ADD")
259 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event
) {
261 if(!checkFromOwnView(event
)){
265 newTaxonNameForRegistration
= TaxonNameFactory
.NewNameInstance(RegistrationUIDefaults
.NOMENCLATURAL_CODE
, Rank
.SPECIES());
266 newTaxonNameForRegistration
.setNomenclaturalReference(getRepo().getReferenceService().find(workingset
.getCitationId()));
267 EntityChangeEvent nameSaveEvent
= getTaxonNameStore().saveBean(newTaxonNameForRegistration
);
268 newTaxonNameForRegistration
= getRepo().getNameService().find(nameSaveEvent
.getEntityId());
269 TaxonNamePopupEditor popup
= getNavigationManager().showInPopup(TaxonNamePopupEditor
.class);
270 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
,CRUD
.DELETE
));
271 popup
.withDeleteButton(true);
272 configureTaxonNameEditor(popup
);
273 popup
.loadInEditor(newTaxonNameForRegistration
.getId());
277 * TODO consider putting this into a Configurer Bean per UIScope.
278 * In the configurator bean this methods popup papamerter should be of the type
279 * AbstractPopupEditor
283 protected void configureTaxonNameEditor(TaxonNamePopupEditor popup
) {
284 popup
.enableMode(TaxonNamePopupEditorMode
.suppressReplacementAuthorshipData
);
285 popup
.enableMode(TaxonNamePopupEditorMode
.nomenclaturalReferenceSectionEditingOnly
);
289 * Creates a new <code>Registration</code> for a new name that has just been edited
290 * using the <code>TaxonNamePopupEditor</code>. The new name was previously created
291 * in this presenter as <code>newTaxonNameForRegistration</code> (see {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)})
292 * and is either filled with data (<code>Reason.SAVE</code>) or it is still empty
293 * (<code>Reason.CANCEL</code>).
297 * @throws RegistrationValidationException
300 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event
) throws RegistrationValidationException
{
301 if(event
.getPopup() instanceof TaxonNamePopupEditor
){
302 TransactionStatus txStatus
= getRepo().startTransaction();
303 if(event
.getReason().equals(Reason
.SAVE
)){
304 if(newTaxonNameForRegistration
!= null){
305 int taxonNameId
= newTaxonNameForRegistration
.getId();
306 getRepo().getSession().refresh(newTaxonNameForRegistration
);
307 Registration reg
= createNewRegistrationForName(taxonNameId
);
308 // reload workingset into current session
309 loadWorkingSet(workingset
.getCitationId());
313 } else if(event
.getReason().equals(Reason
.CANCEL
)){
314 if(newTaxonNameForRegistration
!= null){
316 getTaxonNameStore().deleteBean(newTaxonNameForRegistration
);
319 getRepo().commitTransaction(txStatus
);
320 newTaxonNameForRegistration
= null;
326 * Creates a new Registration for an exiting (previously published name).
329 * @throws RegistrationValidationException
331 @EventListener(condition
= "#event.action == T(eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction.Action).start")
332 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event
) throws RegistrationValidationException
{
334 getView().getAddExistingNameCombobox().commit();
335 TaxonName typifiedName
= getView().getAddExistingNameCombobox().getValue();
336 if(typifiedName
!= null){
337 Registration newRegistrationWithExistingName
= createNewRegistrationForName(null);
338 Reference citation
= getRepo().getReferenceService().find(workingset
.getCitationId());
339 newRegistrationDTOWithExistingName
= new RegistrationDTO(newRegistrationWithExistingName
, typifiedName
, citation
);
340 workingset
.add(newRegistrationDTOWithExistingName
);
341 // tell the view to update the workingset
342 getView().setWorkingset(workingset
);
343 getView().getAddExistingNameRegistrationButton().setEnabled(false);
344 getView().getAddExistingNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
346 logger
.error("Seletced name is NULL");
351 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).EDIT")
352 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event
) {
354 if(!checkFromOwnView(event
)){
358 if(event
.getWorkingSetType() == TypeDesignationWorkingSetType
.SPECIMEN_TYPE_DESIGNATION_WORKINGSET
){
359 SpecimenTypeDesignationWorkingsetPopupEditor popup
= getNavigationManager().showInPopup(SpecimenTypeDesignationWorkingsetPopupEditor
.class);
360 popup
.withDeleteButton(true);
361 popup
.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event
.getRegistrationId(), event
.getEntityId()));
362 if(event
.getSourceComponent() != null){
363 popup
.setReadOnly(event
.getSourceComponent().isReadOnly());
366 // TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET
367 // FIXME implement NameTypeDesignationWorkingsetPopupEditor
371 @EventListener(condition
= "#event.type == T(eu.etaxonomy.vaadin.event.EditorActionType).ADD && #event.sourceComponent == null")
372 public void onAddNewTypeDesignationWorkingset(TypeDesignationWorkingsetEditorAction event
) {
374 if(event
.getWorkingSetType() == TypeDesignationWorkingSetType
.SPECIMEN_TYPE_DESIGNATION_WORKINGSET
){
375 SpecimenTypeDesignationWorkingsetPopupEditor popup
= getNavigationManager().showInPopup(SpecimenTypeDesignationWorkingsetPopupEditor
.class);
376 TypeDesignationWorkingsetEditorIdSet identifierSet
;
377 Integer typifiedNameId
;
378 if(newRegistrationDTOWithExistingName
!= null){
379 typifiedNameId
= newRegistrationDTOWithExistingName
.getTypifiedNameRef().getId();
381 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationId()).get();
382 EntityReference typifiedNameRef
= registrationDTO
.getTypifiedNameRef();
383 if(typifiedNameRef
!= null){
384 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
385 typifiedNameId
= typifiedNameRef
.getId();
387 // case of registrations with a name in the nomenclatural act.
388 typifiedNameId
= registrationDTO
.getNameRef().getId();
391 identifierSet
= new TypeDesignationWorkingsetEditorIdSet(
392 event
.getRegistrationId(),
393 getView().getCitationID(),
396 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
397 popup
.loadInEditor(identifierSet
);
398 popup
.withDeleteButton(true);
400 // TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET
401 // FIXME implement NameTypeDesignationWorkingsetPopupEditor
406 * Performs final actions after a TypeDesignationEditor which has been
407 * opened to add a TypeDesignation to a Registration object which was
408 * created for an previously published name. Prior adding a typedesignation,
409 * the according Registration object is dangling, that has no association to
410 * any entity denoting an nomenclatural act which has a reference to a
411 * publication. This means that the registration object is not in the
416 * @throws RegistrationValidationException
419 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event
) throws RegistrationValidationException
{
420 if(event
.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor
){
421 if(event
.getReason().equals(Reason
.SAVE
)){
423 } else if(event
.getReason().equals(Reason
.CANCEL
)){
425 if(newRegistrationDTOWithExistingName
!= null){
426 getRegistrationStore().deleteBean(newRegistrationDTOWithExistingName
.registration());
429 // set newRegistrationDTOWithExistingName NULL in any case
430 newRegistrationDTOWithExistingName
= null;
435 @EventListener(classes
=ShowDetailsEvent
.class, condition
= "#event.type == T(eu.etaxonomy.cdm.vaadin.model.registration.RegistrationWorkingSet)")
436 public void onShowRegistrationWorkingSetMessages(ShowDetailsEvent
<?
,?
> event
) { // WARNING don't use more specific generic type arguments
437 List
<String
> messages
= new ArrayList
<>();
438 for(RegistrationDTO dto
: workingset
.getRegistrationDTOs()){
439 dto
.getMessages().forEach(m
-> messages
.add(dto
.getSummary() + ": " + m
));
441 if(event
.getProperty().equals("messages")){
442 getView().openDetailsPopup("Messages", messages
);
446 @EventListener(classes
=ShowDetailsEvent
.class, condition
= "#event.type == T(eu.etaxonomy.cdm.vaadin.view.registration.RegistrationDTO)")
447 public void onShowRegistrationMessages(ShowDetailsEvent
<?
,?
> event
) { // WARNING don't use more specific generic type arguments
448 RegistrationDTO regDto
= workingSetService
.loadDtoById((Integer
)event
.getIdentifier());
449 if(event
.getProperty().equals("messages")){
450 if(getView() != null){
451 getView().openDetailsPopup("Messages", regDto
.getMessages());
457 public void onEntityChangeEvent(EntityChangeEvent event
){
458 if(workingset
== null){
461 if(Reference
.class.isAssignableFrom(event
.getEntityType())){
462 if(workingset
.getCitationId().equals(event
.getEntityId())){
466 if(Registration
.class.isAssignableFrom(event
.getEntityType())){
467 if(workingset
.getRegistrations().stream().anyMatch(reg
-> reg
.getId() == event
.getEntityId())){
471 if(TaxonName
.class.isAssignableFrom(event
.getEntityType())){
472 if(workingset
.getRegistrationDTOs().stream().anyMatch(reg
->
473 reg
.getTypifiedNameRef() != null
474 && reg
.getTypifiedNameRef().getId() == event
.getEntityId())){
478 if(TypeDesignationBase
.class.isAssignableFrom(event
.getEntityType())){
479 if(workingset
.getRegistrationDTOs().stream().anyMatch(
480 reg
-> reg
.getTypeDesignations().stream().anyMatch(
481 td
-> td
.getId() == event
.getEntityId()