Project

General

Profile

Download (39.5 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.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.TaxonNameEditorPresenter;
94
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
95
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
96
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
97
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
98
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
99
import eu.etaxonomy.vaadin.mvp.AbstractView;
100
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
101
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
102
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
103
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
104

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

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

    
116
    private static final long serialVersionUID = 1L;
117

    
118
    @Autowired
119
    private IRegistrationWorkingSetService regWorkingSetService;
120

    
121
    @Autowired
122
    private IRegistrationMessageService messageService;
123

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

    
131
    private RegistrationWorkingSet workingset;
132

    
133
    /**
134
     * 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.
135
     * There can always only be one popup editor for this purpose.
136
     */
137
    private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
138

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

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

    
146

    
147
    private ICdmEntityUuidCacher cache;
148

    
149
    private Collection<CdmBase> rootEntities = new HashSet<>();
150

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

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

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

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

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

    
204
    /**
205
     * @param doReload TODO
206
     *
207
     */
208
    protected void refreshView(boolean doReload) {
209
        if(workingset == null){
210
            return; // nothing to do
211
        }
212
        if(doReload){
213
            loadWorkingSet(workingset.getCitationUuid());
214
        }
215
        applyWorkingset();
216
    }
217

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

    
228
            private static final long serialVersionUID = 7099181280977511048L;
229

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

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

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

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

    
258

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

    
263
    }
264

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

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

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

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

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

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

    
324

    
325
    /**
326
     * @param referenceID
327
     */
328
    protected void loadWorkingSet(UUID referenceUuid) {
329

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

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

    
370

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

    
374
        if(!checkFromOwnView(event)){
375
            return;
376
        }
377

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

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

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

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

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

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

    
416
        if(!checkFromOwnView(event)){
417
            return;
418
        }
419

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

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

    
427
        if(!checkFromOwnView(event)){
428
            return;
429
        }
430

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

    
441
    }
442

    
443

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

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

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

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

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

    
525

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

    
535
        if(!event.isStart()){
536
            return;
537
        }
538

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

    
574
    }
575

    
576

    
577
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
578
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
579

    
580
        if(!checkFromOwnView(event)){
581
            return;
582
        }
583

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

    
599
            popup.getCitationCombobox().setEnabled(false);
600
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
601

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

    
610
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
611
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
612

    
613
        if(!event.hasSource()){
614
            return;
615
        }
616

    
617
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
618
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
619
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
620
            TypeDesignationWorkingsetEditorIdSet identifierSet;
621
            UUID typifiedNameUuid;
622

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

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

    
655
                @Override
656
                public NameTypeDesignation createNewBean() {
657

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

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

    
711
        }
712
        // ignore other editors
713
    }
714

    
715

    
716
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
717
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
718

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

    
728
    @EventBusListenerMethod
729
    public void onEntityChangeEvent(EntityChangeEvent event){
730

    
731
        if(workingset == null){
732
            return;
733
        }
734
        if(Reference.class.isAssignableFrom(event.getEntityType())){
735

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

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

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

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

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

    
812
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
813
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
814

    
815
        // FIXME check from own view!!!
816
        if(getView() == null){
817
            return;
818
        }
819

    
820
        UUID registrationUuid = event.getIdentifier();
821

    
822
        RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
823
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
824

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

    
829
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
830
            popup.loadMessagesFor(regDto.getUuid());
831

    
832
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
833
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
834
        }
835
    }
836

    
837
    /**
838
     * {@inheritDoc}
839
     */
840
    @Override
841
    public ICdmEntityUuidCacher getCache() {
842
        return cache;
843
    }
844

    
845
    /**
846
     * {@inheritDoc}
847
     */
848
    @Override
849
    public void addRootEntity(CdmBase entity) {
850
        rootEntities.add(entity);
851
        cache.load(entity);
852
    }
853

    
854

    
855
    /**
856
     * {@inheritDoc}
857
     */
858
    @Override
859
    public Collection<CdmBase> getRootEntities() {
860
        return rootEntities;
861
    }
862

    
863
    @Override
864
    public void destroy() throws Exception {
865
        super.destroy();
866
        disposeCache();
867
    }
868

    
869
    /**
870
     * {@inheritDoc}
871
     */
872
    @Override
873
    public void disposeCache() {
874
        cache.dispose();
875
    }
876

    
877
}
(13-13/20)