Project

General

Profile

Download (37.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.vaadin.view.registration;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.EnumSet;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Objects;
17
import java.util.Set;
18
import java.util.Stack;
19
import java.util.UUID;
20

    
21
import org.apache.log4j.Logger;
22
import org.hibernate.Session;
23
import org.hibernate.Transaction;
24
import org.springframework.beans.factory.annotation.Autowired;
25
import org.springframework.security.core.Authentication;
26
import org.springframework.transaction.TransactionStatus;
27
import org.vaadin.spring.events.EventScope;
28
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
29

    
30
import com.vaadin.server.SystemError;
31
import com.vaadin.spring.annotation.SpringComponent;
32
import com.vaadin.spring.annotation.ViewScope;
33
import com.vaadin.ui.AbstractField;
34
import com.vaadin.ui.Button;
35
import com.vaadin.ui.Label;
36
import com.vaadin.ui.UI;
37
import com.vaadin.ui.VerticalLayout;
38
import com.vaadin.ui.Window;
39

    
40
import eu.etaxonomy.cdm.api.service.INameService;
41
import eu.etaxonomy.cdm.api.service.IRegistrationService;
42
import eu.etaxonomy.cdm.api.service.config.RegistrationStatusTransitions;
43
import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
44
import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
45
import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
46
import eu.etaxonomy.cdm.api.service.idminter.IdentifierMinter.Identifier;
47
import eu.etaxonomy.cdm.api.service.idminter.RegistrationIdentifierMinter;
48
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
49
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
50
import eu.etaxonomy.cdm.api.utility.UserHelper;
51
import eu.etaxonomy.cdm.ext.common.ExternalServiceException;
52
import eu.etaxonomy.cdm.ext.registration.messages.IRegistrationMessageService;
53
import eu.etaxonomy.cdm.model.common.User;
54
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
55
import eu.etaxonomy.cdm.model.name.Rank;
56
import eu.etaxonomy.cdm.model.name.Registration;
57
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
58
import eu.etaxonomy.cdm.model.name.TaxonName;
59
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
60
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
61
import eu.etaxonomy.cdm.model.reference.Reference;
62
import eu.etaxonomy.cdm.model.reference.ReferenceType;
63
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
64
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
65
import eu.etaxonomy.cdm.ref.EntityReference;
66
import eu.etaxonomy.cdm.ref.TypedEntityReference;
67
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
68
import eu.etaxonomy.cdm.service.CdmStore;
69
import eu.etaxonomy.cdm.service.UserHelperAccess;
70
import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
71
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
72
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
73
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
74
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
75
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
76
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
77
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
78
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
79
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
80
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
81
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
82
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
83
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
84
import eu.etaxonomy.cdm.vaadin.permission.RegistrationCuratorRoleProbe;
85
import eu.etaxonomy.cdm.vaadin.theme.EditValoTheme;
86
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
87
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
88
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
89
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
90
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
91
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorMode;
92
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorView;
93
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
94
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
95
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
96
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
97
import eu.etaxonomy.vaadin.mvp.AbstractView;
98
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
99
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
100
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
101
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
102

    
103
/**
104
 * @author a.kohlbecker
105
 * @since Mar 3, 2017
106
 *
107
 */
108
@SpringComponent
109
@ViewScope
110
public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> {
111

    
112
    private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
113

    
114
    private static final List<String> REGISTRATION_INIT_STRATEGY = Arrays.asList(
115
            "$",
116
            "blockedBy",
117
            "name.combinationAuthorship",
118
            "name.exCombinationAuthorship",
119
            "name.basionymAuthorship",
120
            "name.exBasionymAuthorship"
121
            );
122

    
123
    private static final long serialVersionUID = 1L;
124

    
125
    @Autowired
126
    private IRegistrationWorkingSetService regWorkingSetService;
127

    
128
    @Autowired
129
    private RegistrationIdentifierMinter minter;
130

    
131
    @Autowired
132
    private IRegistrationMessageService messageService;
133

    
134
    /**
135
     * @return the regWorkingSetService
136
     */
137
    public IRegistrationWorkingSetService getWorkingSetService() {
138
        return regWorkingSetService;
139
    }
140

    
141
    private RegistrationWorkingSet workingset;
142

    
143
    private TaxonName newTaxonNameForRegistration = null;
144

    
145
    private RegistrationDTO newRegistrationDTOWithExistingName;
146

    
147
    private RegistrationDTO newNameTypeDesignationTarget;
148

    
149

    
150
    /**
151
     *
152
     */
153
    public RegistrationWorkingsetPresenter() {
154
    }
155

    
156
    /**
157
     * Always create a new Store
158
     *
159
     * @return
160
     */
161
    protected CdmStore<Registration, IRegistrationService> getRegistrationStore(){
162
        return new CdmStore<Registration, IRegistrationService>(getRepo(), getRepo().getRegistrationService());
163
    }
164

    
165
    /**
166
     * Always create a new Store
167
     *
168
     * @return
169
     */
170
    protected CdmStore<TaxonName, INameService> getTaxonNameStore(){
171
        return new  CdmStore<TaxonName, INameService>(getRepo(), getRepo().getNameService());
172
    }
173

    
174
    /**
175
     * Checks
176
     * <ol>
177
     * <li>if there is NOT any registration for this name created in the current registration system</li>
178
     * <li>Checks if the name belongs to the current workingset</li>
179
     * </ol>
180
     * If both checks are successful the method returns <code>true</code>.
181
     */
182
    public boolean canCreateNameRegistrationFor(TaxonName name) {
183
        return !checkRegistrationExistsFor(name) && checkWokingsetContainsProtologe(name);
184
    }
185

    
186
    /**
187
     * @param name
188
     * @return
189
     */
190
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
191
        Reference nomRef = name.getNomenclaturalReference();
192
        UUID citationUuid = workingset.getCitationUuid();
193
        // @formatter:off
194
        return nomRef != null && (
195
                // nomref matches
196
                nomRef.getUuid().equals(citationUuid) ||
197
                // nomref.inreference matches
198
                (nomRef.getType() != null && nomRef.getType() == ReferenceType.Section && nomRef.getInReference() != null && nomRef.getInReference().getUuid().equals(citationUuid))
199
                );
200
        // @formatter:on
201
    }
202

    
203
    /**
204
     * @param name
205
     */
206
    public boolean checkRegistrationExistsFor(TaxonName name) {
207

    
208
        for(Registration reg : name.getRegistrations()){
209
            if(minter.isFromOwnRegistration(reg.getIdentifier())){
210
                return true;
211
            }
212
        }
213
        return false;
214
    }
215

    
216

    
217

    
218
    /**
219
     * @param taxonNameId
220
     * @return
221
     */
222
    protected Registration createNewRegistrationForName(UUID taxonNameUuid) {
223
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224
        // move into RegistrationWorkflowStateMachine
225
        TransactionStatus txStatus = getRepo().startTransaction();
226

    
227
        Identifier<String> identifiers = minter.mint();
228
        if(identifiers.getIdentifier() == null){
229
            throw new RuntimeException("RegistrationIdentifierMinter configuration incomplete.");
230
        }
231
        Registration reg = Registration.NewInstance(
232
                identifiers.getIdentifier(),
233
                identifiers.getLocalId(),
234
                taxonNameUuid != null ? getRepo().getNameService().load(taxonNameUuid, Arrays.asList("nomenclaturalReference.inReference")) : null,
235
                null);
236
        Authentication authentication = currentSecurityContext().getAuthentication();
237
        reg.setSubmitter((User)authentication.getPrincipal());
238
        EntityChangeEvent event = getRegistrationStore().saveBean(reg, (AbstractView) getView());
239
        UserHelperAccess.userHelper().createAuthorityForCurrentUser(Registration.class, event.getEntityUuid(), Operation.UPDATE, RegistrationStatus.PREPARATION.name());
240
        getRepo().commitTransaction(txStatus);
241
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
242
        return getRepo().getRegistrationService().load(event.getEntityUuid(), Arrays.asList(new String []{"blockedBy"}));
243
    }
244

    
245
    /**
246
     * @param doReload TODO
247
     *
248
     */
249
    protected void refreshView(boolean doReload) {
250
        if(workingset == null){
251
            return; // nothing to do
252
        }
253
        if(doReload){
254
            loadWorkingSet(workingset.getCitationUuid());
255
        }
256
        applyWorkingset();
257
    }
258

    
259
    /**
260
     * {@inheritDoc}
261
     */
262
    @Override
263
    public void handleViewEntered() {
264
        super.handleViewEntered();
265
        // TODO currently cannot specify type more precisely, see AbstractSelect
266
        // FIXME externalize into class file!!!!!!!!!!!!
267
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
268

    
269
            private static final long serialVersionUID = 7099181280977511048L;
270

    
271
            @Override
272
            public AbstractField<Object> create(RegistrationDTO regDto) {
273

    
274
                CdmBeanItemContainerFactory selectFieldFactory = new CdmBeanItemContainerFactory(getRepo());
275
                // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
276
                UserHelper userHelper = UserHelperAccess.userHelper();
277
                Set<RegistrationStatus> availableStatus = new HashSet<>();
278

    
279
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
280
                availableStatus.add(regDto.getStatus());
281
                if(canChangeStatus){
282
                    if(userHelper.userIsAdmin()){
283
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
284
                    } else {
285
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
286
                    }
287
                }
288

    
289
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
290
                        RegistrationStatus.class,
291
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
292
                        );
293
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
294
                select.setEnabled(canChangeStatus);
295
                select.setNullSelectionAllowed(false);
296
                return select;
297
            }
298

    
299

    
300
        });
301
        loadWorkingSet(getView().getCitationUuid());
302
        applyWorkingset();
303

    
304
    }
305

    
306
    private void applyWorkingset(){
307
         getView().setWorkingset(workingset);
308
        // PagingProviders and CacheGenerator for the existingNameCombobox
309
        activateComboboxes();
310
        // update the messages
311
        updateMessages();
312
    }
313

    
314
    /**
315
     *
316
     */
317
    protected void activateComboboxes() {
318
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
319
                getRepo().getNameService());
320
        pagingProvider.setInitStrategy(Arrays.asList("registrations", "nomenclaturalReference"));
321
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
322
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
323
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
324
    }
325

    
326
    /**
327
     *
328
     */
329
    protected void updateMessages() {
330
        User user = UserHelperAccess.userHelper().user();
331
        for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
332
            Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
333

    
334
            RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
335
            try {
336
                int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
337

    
338
                boolean activeMessages = messageCount > 0;
339
                boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
340
                boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RegistrationCuratorRoleProbe());
341
                messageButton.setEnabled(false);
342
                if(currentUserIsCurator){
343
                    if(currentUserIsSubmitter){
344
                        messageButton.setDescription("No point sending messages to your self.");
345
                    } else {
346
                        messageButton.setEnabled(true);
347
                        messageButton.setDescription("Open the messages dialog.");
348
                    }
349
                } else {
350
                    messageButton.setDescription("Sorry, only a curator can start a conversation.");
351
                }
352
                if(activeMessages){
353
                    messageButton.setEnabled(true);
354
                    messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
355
                    String who = currentUserIsSubmitter ? "curator" : "submitter";
356
                    messageButton.setDescription("The " + who + " is looking forward to your reply.");
357

    
358
                }
359
            } catch (ExternalServiceException e) {
360
                messageButton.setComponentError(new SystemError(e.getMessage(), e));
361
            }
362
        }
363
    }
364

    
365

    
366
    /**
367
     * @param referenceID
368
     */
369
    protected void loadWorkingSet(UUID referenceUuid) {
370
        try {
371
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
372
        } catch (RegistrationValidationException error) {
373
            logger.error(error);
374
            Window errorDialog = new Window("Validation Error");
375
            errorDialog.setModal(true);
376
            VerticalLayout subContent = new VerticalLayout();
377
            subContent.setMargin(true);
378
            errorDialog.setContent(subContent);
379
            subContent.addComponent(new Label(error.getMessage()));
380
            UI.getCurrent().addWindow(errorDialog);
381
        }
382
        if(workingset == null || workingset.getCitationUuid() == null){
383
            Reference citation = getRepo().getReferenceService().find(referenceUuid);
384
            workingset = new RegistrationWorkingSet(citation);
385
        }
386
    }
387

    
388
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
389
        Registration reg = getRepo().getRegistrationService().load(uuid);
390
        if(value != null && value instanceof RegistrationStatus){
391
            if(!Objects.equals(value, reg.getStatus())){
392
                reg.setStatus((RegistrationStatus)value);
393
                getRegistrationStore().saveBean(reg, (AbstractView)getView());
394
                refreshView(true);
395
            }
396
        } else {
397
            // only log here as error
398
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
399
        }
400
    }
401

    
402

    
403
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
404
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
405

    
406
        if(!checkFromOwnView(event)){
407
            return;
408
        }
409

    
410
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
411
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
412
        popup.loadInEditor(null);
413
    }
414

    
415
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
416
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
417

    
418
        if(!checkFromOwnView(event)){
419
            return;
420
        }
421
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
422
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
423
        popup.withDeleteButton(true);
424
        popup.loadInEditor(event.getEntityUuid());
425
    }
426

    
427
    @EventBusListenerMethod
428
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
429
        if(event.getPopup() instanceof ReferencePopupEditor){
430
            if(event.getReason().equals(Reason.SAVE)){
431
                refreshView(true);
432
            }
433
        }
434
    }
435

    
436
    @EventBusListenerMethod
437
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
438
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
439
            if(event.getReason().equals(Reason.SAVE)){
440
                refreshView(true);
441
            }
442
        }
443
    }
444

    
445
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
446
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
447

    
448
        if(!checkFromOwnView(event)){
449
            return;
450
        }
451

    
452
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
453
        popup.loadInEditor(event.getEntityUuid());
454
    }
455

    
456
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
457
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
458

    
459
        if(!checkFromOwnView(event)){
460
            return;
461
        }
462

    
463
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
464
        popup.setParentEditorActionContext(event.getContext());
465
        popup.withDeleteButton(true);
466
        configureTaxonNameEditor(popup);
467
        popup.loadInEditor(event.getEntityUuid());
468
        if(event.hasSource() && event.getSource().isReadOnly()){
469
            // avoid resetting readonly to false
470
            popup.setReadOnly(true);
471
        }
472

    
473
    }
474

    
475

    
476
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
477
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
478

    
479
        if(!checkFromOwnView(event)){
480
            return;
481
        }
482

    
483
        newTaxonNameForRegistration = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
484
        newTaxonNameForRegistration.setNomenclaturalReference(getRepo().getReferenceService().find(workingset.getCitationUuid()));
485
        EntityChangeEvent nameSaveEvent = getTaxonNameStore().saveBean(newTaxonNameForRegistration, (AbstractView) getView());
486
        newTaxonNameForRegistration = getRepo().getNameService().find(nameSaveEvent.getEntityUuid());
487
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
488
        popup.setParentEditorActionContext(event.getContext());
489
        popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
490
        popup.withDeleteButton(true);
491
        configureTaxonNameEditor(popup);
492
        popup.loadInEditor(newTaxonNameForRegistration.getUuid());
493
    }
494

    
495
    /**
496
     * TODO consider putting this into a Configurer Bean per UIScope.
497
     * In the configurator bean this methods popup papamerter should be of the type
498
     * AbstractPopupEditor
499
     *
500
     * @param popup
501
     */
502
    protected void configureTaxonNameEditor(TaxonNamePopupEditorView popup) {
503
        popup.enableMode(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA);
504
        popup.enableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
505
        popup.enableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
506
        // popup.enableMode(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE);
507
    }
508

    
509
    /**
510
     * Creates a new <code>Registration</code> for a new name that has just been edited
511
     * using the <code>TaxonNamePopupEditor</code>. The new name was previously created
512
     * in this presenter as <code>newTaxonNameForRegistration</code> (see {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)})
513
     * and is either filled with data (<code>Reason.SAVE</code>) or it is still empty
514
     * (<code>Reason.CANCEL</code>).
515
     *
516
     *
517
     * @param event
518
     * @throws RegistrationValidationException
519
     */
520
    @EventBusListenerMethod
521
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
522
        if(event.getPopup() instanceof TaxonNamePopupEditor){
523
            TransactionStatus txStatus = getRepo().startTransaction();
524
            if(event.getReason().equals(Reason.SAVE)){
525
                if(newTaxonNameForRegistration != null){
526
                    UUID taxonNameUuid = newTaxonNameForRegistration.getUuid();
527
                    getRepo().getSession().refresh(newTaxonNameForRegistration);
528
                    Registration reg = createNewRegistrationForName(taxonNameUuid);
529
                    // reload workingset into current session
530
                    loadWorkingSet(workingset.getCitationUuid());
531
                    workingset.add(reg);
532
                }
533
                refreshView(true);
534
            } else if(event.getReason().equals(Reason.CANCEL)){
535
                if(newTaxonNameForRegistration != null){
536
                    // clean up
537
                    getTaxonNameStore().deleteBean(newTaxonNameForRegistration, (AbstractView) getView());
538
                }
539
            }
540
            getRepo().commitTransaction(txStatus);
541
            newTaxonNameForRegistration = null;
542
        }
543
    }
544

    
545

    
546
    /**
547
     * Creates a new Registration for an exiting (previously published name).
548
     *
549
     * @param event
550
     * @throws RegistrationValidationException
551
     */
552
    @EventBusListenerMethod
553
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
554

    
555
        if(!event.isStart()){
556
            return;
557
        }
558

    
559
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
560
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
561
        if(typifiedName != null){
562
            boolean reloadWorkingSet = false;
563
            Reference citation = getRepo().getReferenceService().find(workingset.getCitationUuid());
564
            // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
565
            // to create a typification only registration in the working (publication) set which contains
566
            // the protologe. This is known from the nomenclatural reference.
567
            if(canCreateNameRegistrationFor(typifiedName)){
568
                // the citation which is the base for workingset contains the protologe of the name and the name has not
569
                // been registered before:
570
                // create a registration for the name and the first typifications
571
                Registration newRegistrationWithExistingName = createNewRegistrationForName(typifiedName.getUuid());
572
                newRegistrationDTOWithExistingName = new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation);
573
                reloadWorkingSet = true;
574
            } else {
575
                if(!checkWokingsetContainsProtologe(typifiedName)){
576
                    // create a typification only registration
577
                    Registration typificationOnlyRegistration = createNewRegistrationForName(null);
578
                    if(!checkRegistrationExistsFor(typifiedName)){
579
                        // oops, yet no registration for this name, so we create it as blocking registration:
580
                        Registration blockingNameRegistration = createNewRegistrationForName(typifiedName.getUuid());
581
                        typificationOnlyRegistration.getBlockedBy().add(blockingNameRegistration);
582
                    }
583
                    newRegistrationDTOWithExistingName = new RegistrationDTO(typificationOnlyRegistration, typifiedName, citation);
584
                }
585
            }
586
            workingset.add(newRegistrationDTOWithExistingName);
587
            // tell the view to update the workingset
588
            refreshView(reloadWorkingSet);
589
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
590
            if(newRegistrationDTOWithExistingName.registration().getName() == null){
591
                getView().getAddExistingNameCombobox().setEnabled(false);
592
                getView().getAddNewNameRegistrationButton().setEnabled(false);
593
                getView().getAddNewNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
594
                getView().getAddExistingNameCombobox().setDescription("You first need to add a type designation to the previously created registration.");
595
                getView().getAddExistingNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
596
            }
597
        } else {
598
            logger.error("Seletced name is NULL");
599
        }
600

    
601
    }
602

    
603

    
604
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
605
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
606

    
607
        if(!checkFromOwnView(event)){
608
            return;
609
        }
610

    
611
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
612
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
613
            popup.setParentEditorActionContext(event.getContext());
614
            popup.withDeleteButton(true);
615
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
616
            if(event.hasSource()){
617
                // propagate readonly state from source button to popup
618
                popup.setReadOnly(event.getSource().isReadOnly());
619
            }
620
        } else {
621
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
622
            popup.setParentEditorActionContext(event.getContext());
623
            popup.withDeleteButton(true);
624
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
625

    
626
            popup.getCitationCombobox().setEnabled(false);
627
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
628

    
629
            if(event.hasSource()){
630
                // propagate readonly state from source button to popup
631
                popup.setReadOnly(event.getSource().isReadOnly());
632
            }
633
            newNameTypeDesignationTarget = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
634
        }
635
    }
636

    
637
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
638
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
639

    
640
        if(!event.hasSource()){
641
            return;
642
        }
643

    
644
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
645
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
646
            popup.setParentEditorActionContext(event.getContext());
647
            TypeDesignationWorkingsetEditorIdSet identifierSet;
648
            UUID typifiedNameUuid;
649
            if(newRegistrationDTOWithExistingName != null){
650
                typifiedNameUuid = newRegistrationDTOWithExistingName.getTypifiedNameRef().getUuid();
651
            } else {
652
                RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
653
                EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
654
                if(typifiedNameRef != null){
655
                    // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
656
                    typifiedNameUuid = typifiedNameRef.getUuid();
657
                } else {
658
                    // case of registrations with a name in the nomenclatural act.
659
                    typifiedNameUuid = registrationDTO.getNameRef().getUuid();
660
                }
661
            }
662
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
663
                    event.getRegistrationUuid(),
664
                    getView().getCitationUuid(),
665
                    typifiedNameUuid
666
                    );
667
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
668
            popup.loadInEditor(identifierSet);
669
            popup.withDeleteButton(true);
670
            if(event.hasSource()){
671
                // propagate readonly state from source component to popup
672
                popup.setReadOnly(event.getSource().isReadOnly());
673
            }
674
        } else {
675
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
676
            popup.setParentEditorActionContext(event.getContext());
677
            popup.withDeleteButton(true);
678
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
679
            newNameTypeDesignationTarget = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
680
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
681

    
682
                @Override
683
                public NameTypeDesignation createNewBean() {
684

    
685
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
686
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
687
                    nameTypeDesignation.setCitation(newNameTypeDesignationTarget.getCitation());
688
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
689
                    return nameTypeDesignation;
690
                }
691
            });
692
            popup.loadInEditor(null);
693
            popup.getCitationCombobox().setEnabled(false);
694
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
695
            if(event.hasSource()){
696
                // propagate readonly state from source component to popup
697
                popup.setReadOnly(event.getSource().isReadOnly());
698
            }
699
        }
700
    }
701

    
702
    /**
703
     * Performs final actions after a TypeDesignationEditor which has been
704
     * opened to add a TypeDesignation to a Registration object which was
705
     * created for an previously published name. Prior adding a typedesignation,
706
     * the according Registration object is dangling, that has no association to
707
     * any entity denoting an nomenclatural act which has a reference to a
708
     * publication. This means that the registration object is not in the
709
     * working set.
710
     *
711
     *
712
     * @param event
713
     * @throws RegistrationValidationException
714
     */
715
    @EventBusListenerMethod
716
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
717
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
718
            if(event.getReason().equals(Reason.SAVE)){
719
                refreshView(true);
720
            } else if(event.getReason().equals(Reason.CANCEL)){
721
                // noting to do
722
            }
723
            newRegistrationDTOWithExistingName = null;
724
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
725
            if(event.getReason().equals(Reason.SAVE)){
726
                UUID uuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
727

    
728
                Session session = getRepo().getSessionFactory().openSession();
729
                Transaction txstate = session.beginTransaction();
730
                TypeDesignationBase<?> nameTypeDesignation = getRepo().getNameService().loadTypeDesignation(uuid, Arrays.asList(""));
731
                // only load the typeDesignations with the registration so that the typified name can  not be twice in the session
732
                // otherwise multiple representation problems might occur
733
                Registration registration = getRepo().getRegistrationService().load(newNameTypeDesignationTarget.getUuid(), Arrays.asList("typeDesignations"));
734
                registration.getTypeDesignations().add(nameTypeDesignation);
735
                session.merge(registration);
736
                txstate.commit();
737
                session.close();
738

    
739
                refreshView(true);
740
            } else if(event.getReason().equals(Reason.CANCEL)){
741
                // noting to do
742
            }
743
            newNameTypeDesignationTarget = null;
744
        }
745
        // ignore other editors
746
    }
747

    
748

    
749
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
750
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
751

    
752
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
753
            List<String> messages = new ArrayList<>();
754
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
755
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
756
            }
757
            getView().openDetailsPopup("Validation Problems", messages);
758
        }
759
    }
760

    
761
    @EventBusListenerMethod
762
    public void onEntityChangeEvent(EntityChangeEvent event){
763

    
764
        if(workingset == null){
765
            return;
766
        }
767
        if(Reference.class.isAssignableFrom(event.getEntityType())){
768

    
769
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
770
                if(event.isRemovedType()){
771
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
772
                } else {
773
                    refreshView(true);
774
                }
775
            }
776

    
777
        } else
778
        if(Registration.class.isAssignableFrom(event.getEntityType())){
779
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
780
                refreshView(true);
781
            }
782
        } else
783
        if(TaxonName.class.isAssignableFrom(event.getEntityType()) && isFromOwnView(event)){
784
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
785
                // new name! create a blocking registration
786
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
787
                EditorActionContext rootContext = context.get(0);
788
                if(rootContext.getParentView().equals(getView())){
789
                    Registration blockingRegistration = createNewRegistrationForName(event.getEntityUuid());
790
                    TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
791
                    Registration registration = getRepo().getRegistrationService().load(regReference.getUuid(), REGISTRATION_INIT_STRATEGY);
792
                    registration.getBlockedBy().add(blockingRegistration);
793
                    getRepo().getRegistrationService().saveOrUpdate(registration);
794
                    logger.debug("Blocking registration created");
795
                } else {
796
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
797
                }
798
            }
799
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
800
                reg.getTypifiedNameRef() != null
801
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
802
                    refreshView(true);
803
            }
804
        } else
805
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
806
            if(workingset.getRegistrationDTOs().stream().anyMatch(
807
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
808
                            td -> td.getUuid() == event.getEntityUuid()
809
                            )
810
                        )
811
                    ){
812
                refreshView(true);
813
            }
814
        }
815
    }
816

    
817

    
818
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
819
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
820

    
821
        // FIXME check from own view!!!
822
        if(getView() == null){
823
            return;
824
        }
825

    
826
        UUID registrationUuid = event.getIdentifier();
827

    
828
        RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
829
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
830

    
831
            Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
832
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
833
        } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
834

    
835
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
836
            popup.loadMessagesFor(regDto.getUuid());
837

    
838
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
839
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
840
        }
841

    
842

    
843
    }
844

    
845
}
(12-12/19)