Project

General

Profile

Download (39.2 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.Collection;
14
import java.util.EnumSet;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Objects;
20
import java.util.Set;
21
import java.util.Stack;
22
import java.util.UUID;
23

    
24
import org.apache.log4j.Logger;
25
import org.springframework.beans.factory.annotation.Autowired;
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.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
47
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
48
import eu.etaxonomy.cdm.api.utility.RoleProber;
49
import eu.etaxonomy.cdm.api.utility.UserHelper;
50
import eu.etaxonomy.cdm.cache.CdmTransientEntityAndUuidCacher;
51
import eu.etaxonomy.cdm.ext.common.ExternalServiceException;
52
import eu.etaxonomy.cdm.ext.registration.messages.IRegistrationMessageService;
53
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
54
import eu.etaxonomy.cdm.model.common.CdmBase;
55
import eu.etaxonomy.cdm.model.common.User;
56
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
57
import eu.etaxonomy.cdm.model.name.Rank;
58
import eu.etaxonomy.cdm.model.name.Registration;
59
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
60
import eu.etaxonomy.cdm.model.name.TaxonName;
61
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
62
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
63
import eu.etaxonomy.cdm.model.reference.Reference;
64
import eu.etaxonomy.cdm.model.reference.ReferenceType;
65
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
66
import eu.etaxonomy.cdm.ref.EntityReference;
67
import eu.etaxonomy.cdm.ref.TypedEntityReference;
68
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
69
import eu.etaxonomy.cdm.service.CdmStore;
70
import eu.etaxonomy.cdm.service.UserHelperAccess;
71
import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
72
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
73
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
74
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
75
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
76
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
77
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
78
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
79
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
80
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
81
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
82
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
83
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
84
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
85
import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
86
import eu.etaxonomy.cdm.vaadin.theme.EditValoTheme;
87
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
88
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
89
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
90
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
91
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
92
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
93
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
94
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
95
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
96
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
97
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
98
import eu.etaxonomy.vaadin.mvp.AbstractView;
99
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
100
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
101
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
102
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
103

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

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

    
115
    private static final long serialVersionUID = 1L;
116

    
117
    @Autowired
118
    private IRegistrationWorkingSetService regWorkingSetService;
119

    
120
    @Autowired
121
    private IRegistrationMessageService messageService;
122

    
123
    /**
124
     * @return the regWorkingSetService
125
     */
126
    public IRegistrationWorkingSetService getWorkingSetService() {
127
        return regWorkingSetService;
128
    }
129

    
130
    private RegistrationWorkingSet workingset;
131

    
132
    /**
133
     * Contains the poupeditor which has neen opend to start the registration of a new name as long as it has not been saved or canceled.
134
     * There can always only be one popup editor for this purpose.
135
     */
136
    private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
137

    
138
    /**
139
     * Contains
140
     */
141
    private List<Registration> newNameBlockingRegistrations = new ArrayList<>();
142

    
143
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
144

    
145

    
146
    private ICdmEntityUuidCacher cache;
147

    
148
    private Collection<CdmBase> rootEntities = new HashSet<>();
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 !getRepo().getRegistrationService().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 doReload TODO
205
     *
206
     */
207
    protected void refreshView(boolean doReload) {
208
        if(workingset == null){
209
            return; // nothing to do
210
        }
211
        if(doReload){
212
            loadWorkingSet(workingset.getCitationUuid());
213
        }
214
        applyWorkingset();
215
    }
216

    
217
    /**
218
     * {@inheritDoc}
219
     */
220
    @Override
221
    public void handleViewEntered() {
222
        super.handleViewEntered();
223
        // TODO currently cannot specify type more precisely, see AbstractSelect
224
        // FIXME externalize into class file!!!!!!!!!!!!
225
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
226

    
227
            private static final long serialVersionUID = 7099181280977511048L;
228

    
229
            @Override
230
            public AbstractField<Object> create(RegistrationDTO regDto) {
231

    
232
                CdmBeanItemContainerFactory selectFieldFactory = new CdmBeanItemContainerFactory(getRepo());
233
                // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
234
                UserHelper userHelper = UserHelperAccess.userHelper();
235
                Set<RegistrationStatus> availableStatus = new HashSet<>();
236

    
237
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
238
                availableStatus.add(regDto.getStatus());
239
                if(canChangeStatus){
240
                    if(userHelper.userIsAdmin()){
241
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
242
                    } else {
243
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
244
                    }
245
                }
246

    
247
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
248
                        RegistrationStatus.class,
249
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
250
                        );
251
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
252
                select.setEnabled(canChangeStatus);
253
                select.setNullSelectionAllowed(false);
254
                return select;
255
            }
256

    
257

    
258
        });
259
        loadWorkingSet(getView().getCitationUuid());
260
        applyWorkingset();
261

    
262
    }
263

    
264
    private void applyWorkingset(){
265
         getView().setWorkingset(workingset);
266
        // PagingProviders and CacheGenerator for the existingNameCombobox
267
        activateComboboxes();
268
        // update the messages
269
        updateMessages();
270
    }
271

    
272
    /**
273
     *
274
     */
275
    protected void activateComboboxes() {
276
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
277
                getRepo().getNameService());
278
        pagingProvider.setInitStrategy(Arrays.asList("registrations", "nomenclaturalReference", "nomenclaturalReference.inReference"));
279
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
280
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
281
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
282
    }
283

    
284
    /**
285
     *
286
     */
287
    protected void updateMessages() {
288
        User user = UserHelperAccess.userHelper().user();
289
        for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
290
            Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
291

    
292
            RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
293
            try {
294
                int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
295

    
296
                boolean activeMessages = messageCount > 0;
297
                boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
298
                boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RoleProber(RolesAndPermissions.ROLE_CURATION));
299
                messageButton.setEnabled(false);
300
                if(currentUserIsCurator){
301
                    if(currentUserIsSubmitter){
302
                        messageButton.setDescription("No point sending messages to your self.");
303
                    } else {
304
                        messageButton.setEnabled(true);
305
                        messageButton.setDescription("Open the messages dialog.");
306
                    }
307
                } else {
308
                    messageButton.setDescription("Sorry, only a curator can start a conversation.");
309
                }
310
                if(activeMessages){
311
                    messageButton.setEnabled(true);
312
                    messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
313
                    String who = currentUserIsSubmitter ? "curator" : "submitter";
314
                    messageButton.setDescription("The " + who + " is looking forward to your reply.");
315

    
316
                }
317
            } catch (ExternalServiceException e) {
318
                messageButton.setComponentError(new SystemError(e.getMessage(), e));
319
            }
320
        }
321
    }
322

    
323

    
324
    /**
325
     * @param referenceID
326
     */
327
    protected void loadWorkingSet(UUID referenceUuid) {
328
        try {
329
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
330
        } catch (RegistrationValidationException error) {
331
            logger.error(error);
332
            Window errorDialog = new Window("Validation Error");
333
            errorDialog.setModal(true);
334
            VerticalLayout subContent = new VerticalLayout();
335
            subContent.setMargin(true);
336
            errorDialog.setContent(subContent);
337
            subContent.addComponent(new Label(error.getMessage()));
338
            UI.getCurrent().addWindow(errorDialog);
339
        }
340
        if(workingset == null || workingset.getCitationUuid() == null){
341
            Reference citation = getRepo().getReferenceService().find(referenceUuid);
342
            workingset = new RegistrationWorkingSet(citation);
343
        }
344
        cache = new CdmTransientEntityAndUuidCacher(this);
345
        for(Registration registration : workingset.getRegistrations()) {
346
            addRootEntity(registration);
347
        }
348
    }
349

    
350
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
351
        Registration reg = getRepo().getRegistrationService().load(uuid);
352
        if(reg == null){
353
            // registration was not yet persisted, ignore
354
            return;
355
        }
356
        if(value != null && value instanceof RegistrationStatus){
357
            if(!Objects.equals(value, reg.getStatus())){
358
                reg.setStatus((RegistrationStatus)value);
359
                getRegistrationStore().saveBean(reg, (AbstractView)getView());
360
                refreshView(true);
361
            }
362
        } else {
363
            // only log here as error
364
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
365
        }
366
    }
367

    
368

    
369
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
370
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
371

    
372
        if(!checkFromOwnView(event)){
373
            return;
374
        }
375

    
376
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
377
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
378
        popup.loadInEditor(null);
379
    }
380

    
381
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
382
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
383

    
384
        if(!checkFromOwnView(event)){
385
            return;
386
        }
387
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
388
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
389
        popup.withDeleteButton(true);
390
        popup.loadInEditor(event.getEntityUuid());
391
    }
392

    
393
    @EventBusListenerMethod
394
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
395
        if(event.getPopup() instanceof ReferencePopupEditor){
396
            if(event.getReason().equals(Reason.SAVE)){
397
                refreshView(true);
398
            }
399
        }
400
    }
401

    
402
    @EventBusListenerMethod
403
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
404
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
405
            if(event.getReason().equals(Reason.SAVE)){
406
                refreshView(true);
407
            }
408
        }
409
    }
410

    
411
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
412
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
413

    
414
        if(!checkFromOwnView(event)){
415
            return;
416
        }
417

    
418
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
419
        popup.loadInEditor(event.getEntityUuid());
420
    }
421

    
422
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
423
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
424

    
425
        if(!checkFromOwnView(event)){
426
            return;
427
        }
428

    
429
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
430
        popup.setParentEditorActionContext(event.getContext());
431
        popup.withDeleteButton(true);
432
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
433
        popup.loadInEditor(event.getEntityUuid());
434
        if(event.hasSource() && event.getSource().isReadOnly()){
435
            // avoid resetting readonly to false
436
            popup.setReadOnly(true);
437
        }
438

    
439
    }
440

    
441

    
442
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
443
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
444

    
445
        if(!checkFromOwnView(event)){
446
            return;
447
        }
448

    
449
        getView().getAddNewNameRegistrationButton().setEnabled(false);
450
        if(newNameForRegistrationPopupEditor == null){
451
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
452
            newNameForRegistrationPopupEditor = popup;
453
            popup.setParentEditorActionContext(event.getContext());
454
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
455
            popup.withDeleteButton(true);
456
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
457

    
458
                @Override
459
                public TaxonName createNewBean() {
460
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
461
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid()));
462
                    return newTaxonName;
463
                }
464
            });
465
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
466
            popup.loadInEditor(null);
467
        }
468
    }
469

    
470
    /**
471
     * Creates a new <code>Registration</code> for a new name that has just been edited
472
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
473
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
474
     * Any blocking registrations which have been created while editing the new name are
475
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
476
     * for the first name has been created. Additional new names are created for example
477
     * when a new name as basionym, replaced synonym, etc to the new name is created.
478
     * <p>
479
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
480
     *
481
     * @param event
482
     * @throws RegistrationValidationException
483
     */
484
    @EventBusListenerMethod
485
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
486
        if(event.getPopup() instanceof TaxonNamePopupEditor){
487
                    if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
488
                        if(event.getReason().equals(Reason.SAVE)){
489
                        try {
490
                            TransactionStatus txStatus = getRepo().startTransaction();
491
                            UUID taxonNameUuid = newNameForRegistrationPopupEditor.getBean().getUuid();
492
                            if(newNameForRegistrationPopupEditor.getBean().cdmEntity().isPersited()){
493
                                getRepo().getSession().refresh(newNameForRegistrationPopupEditor.getBean().cdmEntity());
494
                            }
495
                            Registration reg = getRepo().getRegistrationService().createRegistrationForName(taxonNameUuid);
496
                            if(!newNameBlockingRegistrations.isEmpty()){
497
                                for(Registration blockingReg : newNameBlockingRegistrations){
498
                                    blockingReg = getRepo().getRegistrationService().load(blockingReg.getUuid());
499
                                    reg.getBlockedBy().add(blockingReg);
500
                                }
501
                                getRepo().getRegistrationService().saveOrUpdate(reg);
502
                                newNameBlockingRegistrations.clear();
503
                            }
504
                            // reload workingset into current session
505
                            loadWorkingSet(workingset.getCitationUuid());
506
                            workingset.add(reg);
507
                            getRepo().commitTransaction(txStatus);
508
                        } finally {
509
                            getRepo().getSession().clear(); // #7702
510
                            refreshView(true);
511
                            getView().getAddNewNameRegistrationButton().setEnabled(true);
512
                        }
513
                        // nullify and clear the memory on this popup editor in any case (SAVE, CANCEL, DELETE)
514
                        newNameForRegistrationPopupEditor = null;
515
                        newNameBlockingRegistrations.clear();
516
                    }
517
                }
518

    
519
        }
520
    }
521

    
522

    
523
    /**
524
     * Creates a new Registration for an exiting (previously published) name.
525
     *
526
     * @param event
527
     * @throws RegistrationValidationException
528
     */
529
    @EventBusListenerMethod
530
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
531

    
532
        if(!event.isStart()){
533
            return;
534
        }
535

    
536
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
537
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
538
        if(typifiedName != null){
539
            boolean doReloadWorkingSet = false;
540
            Reference citation = getRepo().getReferenceService().find(workingset.getCitationUuid());
541
            // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
542
            // to create a typification only registration in the working (publication) set which contains
543
            // the protologe. This is known from the nomenclatural reference.
544
            if(canCreateNameRegistrationFor(typifiedName)){
545
                // the citation which is the base for workingset contains the protologe of the name and the name has not
546
                // been registered before:
547
                // create a registration for the name and the first typifications
548
                Registration newRegistrationWithExistingName = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
549
                workingset.add(new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation));
550
                doReloadWorkingSet = true;
551
            } else {
552
                if(!checkWokingsetContainsProtologe(typifiedName)){
553
                    // create a typification only registration
554
                    Registration typificationOnlyRegistration = getRepo().getRegistrationService().newRegistration();
555
                    if(!getRepo().getRegistrationService().checkRegistrationExistsFor(typifiedName)){
556
                        // oops, yet no registration for this name, so we create it as blocking registration:
557
                        Registration blockingNameRegistration = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
558
                        typificationOnlyRegistration.getBlockedBy().add(blockingNameRegistration);
559
                    }
560
                    RegistrationDTO regDTO = new RegistrationDTO(typificationOnlyRegistration, typifiedName, citation);
561
                    workingset.add(regDTO);
562
                }
563
            }
564
            // tell the view to update the workingset
565
            refreshView(doReloadWorkingSet);
566
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
567
        } else {
568
            logger.error("Seletced name is NULL");
569
        }
570

    
571
    }
572

    
573

    
574
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
575
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
576

    
577
        if(!checkFromOwnView(event)){
578
            return;
579
        }
580

    
581
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
582
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
583
            popup.setParentEditorActionContext(event.getContext());
584
            popup.withDeleteButton(true);
585
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
586
            if(event.hasSource()){
587
                // propagate readonly state from source button to popup
588
                popup.setReadOnly(event.getSource().isReadOnly());
589
            }
590
        } else {
591
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
592
            popup.setParentEditorActionContext(event.getContext());
593
            popup.withDeleteButton(true);
594
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
595

    
596
            popup.getCitationCombobox().setEnabled(false);
597
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
598

    
599
            if(event.hasSource()){
600
                // propagate readonly state from source button to popup
601
                popup.setReadOnly(event.getSource().isReadOnly());
602
            }
603
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
604
        }
605
    }
606

    
607
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
608
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
609

    
610
        if(!event.hasSource()){
611
            return;
612
        }
613

    
614
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
615
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
616
            popup.setParentEditorActionContext(event.getContext());
617
            TypeDesignationWorkingsetEditorIdSet identifierSet;
618
            UUID typifiedNameUuid;
619

    
620
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
621
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
622
            if(typifiedNameRef != null){
623
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
624
                typifiedNameUuid = typifiedNameRef.getUuid();
625
            } else {
626
                // case of registrations with a name in the nomenclatural act.
627
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
628
            }
629

    
630
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
631
                    event.getRegistrationUuid(),
632
                    getView().getCitationUuid(),
633
                    typifiedNameUuid
634
                    );
635
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
636
            popup.loadInEditor(identifierSet);
637
            popup.withDeleteButton(true);
638
            if(event.hasSource()){
639
                // propagate readonly state from source component to popup
640
                popup.setReadOnly(event.getSource().isReadOnly());
641
            }
642
        } else {
643
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
644
            popup.setParentEditorActionContext(event.getContext());
645
            popup.withDeleteButton(true);
646
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
647
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
648
            Reference citation = regDto.getCitation();
649
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
650
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
651

    
652
                @Override
653
                public NameTypeDesignation createNewBean() {
654

    
655
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
656
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
657
                    nameTypeDesignation.setCitation(citation);
658
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
659
                    return nameTypeDesignation;
660
                }
661
            });
662
            popup.loadInEditor(null);
663
            popup.getCitationCombobox().setEnabled(false);
664
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
665
            if(event.hasSource()){
666
                // propagate readonly state from source component to popup
667
                popup.setReadOnly(event.getSource().isReadOnly());
668
            }
669
        }
670
    }
671

    
672
    /**
673
     * Performs final actions after a TypeDesignationEditor which has been
674
     * opened to add a TypeDesignation to a Registration object which was
675
     * created for an previously published name. Prior adding a typedesignation,
676
     * the according Registration object is dangling, that has no association to
677
     * any entity denoting an nomenclatural act which has a reference to a
678
     * publication. This means that the registration object is not in the
679
     * working set.
680
     *
681
     *
682
     * @param event
683
     * @throws RegistrationValidationException
684
     */
685
    @EventBusListenerMethod
686
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
687
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
688
            if(event.getReason().equals(Reason.SAVE)){
689
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
690
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
691
                refreshView(true);
692
            } else if(event.getReason().equals(Reason.CANCEL)){
693
                // noting to do
694
            }
695
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
696
            if(event.getReason().equals(Reason.SAVE)){
697
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
698
                getRepo().getSession().clear();
699
                UUID regUUID = nameTypeDesignationPopupEditorRegistrationUUIDMap.get(event.getPopup());
700
                getRepo().getRegistrationService().addTypeDesignation(regUUID, typeDesignationUuid);
701
                getRepo().getSession().clear();
702
                nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
703
                refreshView(true);
704
            } else if(event.getReason().equals(Reason.CANCEL)){
705
                // noting to do
706
            }
707

    
708
        }
709
        // ignore other editors
710
    }
711

    
712

    
713
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
714
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
715

    
716
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
717
            List<String> messages = new ArrayList<>();
718
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
719
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
720
            }
721
            getView().openDetailsPopup("Validation Problems", messages);
722
        }
723
    }
724

    
725
    @EventBusListenerMethod
726
    public void onEntityChangeEvent(EntityChangeEvent event){
727

    
728
        if(workingset == null){
729
            return;
730
        }
731
        if(Reference.class.isAssignableFrom(event.getEntityType())){
732

    
733
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
734
                if(event.isRemovedType()){
735
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
736
                } else {
737
                    refreshView(true);
738
                }
739
            }
740

    
741
        } else
742
        if(Registration.class.isAssignableFrom(event.getEntityType())){
743
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
744
                refreshView(true);
745
            }
746
        } else
747
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
748
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
749
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
750
                EditorActionContext rootContext = context.get(0);
751
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
752

    
753
                    try {
754
                        getRepo().getSession().clear();
755
                        TransactionStatus txStatus = getRepo().startTransaction();
756
                        // create a blocking registration, the new Registration will be persisted
757
                        UUID taxonNameUUID = event.getEntityUuid();
758
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
759

    
760
                        if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
761
                            // Oha!! The event came from a popup editor and the
762
                            // first popup in the context is a TaxonNameEditor with un-persisted name
763
                            // This is a name for a new registration which has not yet been created.
764
                            // It is necessary to store blocking registrations in the newNameBlockingRegistrations
765
                            newNameBlockingRegistrations.add(blockingRegistration);
766
                            logger.debug("Blocking registration created and memorized");
767
                        } else {
768
                            // some new name related somehow to an existing registration
769
                            TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
770
                            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
771
                            Registration registration = registrationDTO.registration();
772

    
773
                                registration = getRepo().getRegistrationService().load(registration.getUuid());
774
                                if(registration == null){
775
                                    throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
776
                                }
777
                                registration.getBlockedBy().add(blockingRegistration);
778
                                getRepo().getRegistrationService().saveOrUpdate(registration);
779
                                getRepo().commitTransaction(txStatus);
780
                            logger.debug("Blocking registration created and added to registion");
781
                        }
782
                    } finally {
783
                        getRepo().getSession().clear();
784
                    }
785
                } else {
786
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
787
                    // this is set
788
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
789
                }
790
            }
791
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
792
                reg.getTypifiedNameRef() != null
793
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
794
                    refreshView(true);
795
            }
796
        } else
797
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
798
            if(workingset.getRegistrationDTOs().stream().anyMatch(
799
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
800
                            td -> td.getUuid() == event.getEntityUuid()
801
                            )
802
                        )
803
                    ){
804
                refreshView(true);
805
            }
806
        }
807
    }
808

    
809
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
810
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
811

    
812
        // FIXME check from own view!!!
813
        if(getView() == null){
814
            return;
815
        }
816

    
817
        UUID registrationUuid = event.getIdentifier();
818

    
819
        RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
820
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
821

    
822
            Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
823
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
824
        } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
825

    
826
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
827
            popup.loadMessagesFor(regDto.getUuid());
828

    
829
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
830
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
831
        }
832
    }
833

    
834
    /**
835
     * {@inheritDoc}
836
     */
837
    @Override
838
    public ICdmEntityUuidCacher getCache() {
839
        return cache;
840
    }
841

    
842
    /**
843
     * {@inheritDoc}
844
     */
845
    @Override
846
    public void addRootEntity(CdmBase entity) {
847
        rootEntities.add(entity);
848
        cache.put(entity);
849
    }
850

    
851

    
852
    /**
853
     * {@inheritDoc}
854
     */
855
    @Override
856
    public Collection<CdmBase> getRootEntities() {
857
        return rootEntities;
858
    }
859

    
860
    @Override
861
    public void destroy() throws Exception {
862
        super.destroy();
863
        disposeCache();
864
    }
865

    
866
    /**
867
     * {@inheritDoc}
868
     */
869
    @Override
870
    public void disposeCache() {
871
        cache.dispose();
872
    }
873

    
874
}
(13-13/20)