Project

General

Profile

Download (40.3 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.Optional;
21
import java.util.Set;
22
import java.util.Stack;
23
import java.util.UUID;
24

    
25
import org.apache.log4j.Logger;
26
import org.springframework.beans.factory.annotation.Autowired;
27
import org.springframework.transaction.TransactionStatus;
28
import org.vaadin.spring.events.EventScope;
29
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
30

    
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.Label;
35
import com.vaadin.ui.UI;
36
import com.vaadin.ui.VerticalLayout;
37
import com.vaadin.ui.Window;
38

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

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

    
110
    private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
111

    
112
    private static final long serialVersionUID = 1L;
113

    
114
    @Autowired
115
    private IRegistrationWorkingSetService regWorkingSetService;
116

    
117
    @Autowired
118
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
119

    
120

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

    
128
    private RegistrationWorkingSet workingset;
129

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

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

    
141
    /**
142
     * TODO is this still needed? The regitration UUID should be accessible in the popup editor context,
143
     * see findRegistrationInContext()
144
     */
145
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
146

    
147

    
148
    private ICdmEntityUuidCacher cache;
149

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

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

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

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

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

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

    
205
    /**
206
     * @param doReload reload the workingset from the persistent storage.
207
     *  Workingsets which are not yet persisted are preserved.
208
     *
209
     */
210
    protected void refreshView(boolean doReload) {
211
        if(workingset == null){
212
            return; // nothing to do
213
        }
214
        if(doReload){
215
            List<RegistrationDTO> unpersisted = new ArrayList<>();
216
            for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
217
                if(!regDto.registration().isPersited()){
218
                    unpersisted.add(regDto);
219
                }
220
            }
221
            loadWorkingSet(workingset.getCitationUuid());
222
            for(RegistrationDTO regDtoUnpersisted : unpersisted){
223
                if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
224
                    // only add if the regDtoUnpersisted has not been persisted meanwhile
225
                    try {
226
                        workingset.add(regDtoUnpersisted);
227
                    } catch (RegistrationValidationException e) {
228
                        // would never happen here //
229
                    }
230
                }
231
            }
232
        }
233
        applyWorkingset();
234
    }
235

    
236
    /**
237
     * {@inheritDoc}
238
     */
239
    @Override
240
    public void handleViewEntered() {
241
        super.handleViewEntered();
242
        // TODO currently cannot specify type more precisely, see AbstractSelect
243
        // FIXME externalize into class file!!!!!!!!!!!!
244
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
245

    
246
            private static final long serialVersionUID = 7099181280977511048L;
247

    
248
            @Override
249
            public AbstractField<Object> create(RegistrationDTO regDto) {
250

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

    
256
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
257
                availableStatus.add(regDto.getStatus());
258
                if(canChangeStatus){
259
                    if(userHelper.userIsAdmin()){
260
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
261
                    } else {
262
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
263
                    }
264
                }
265

    
266
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
267
                        RegistrationStatus.class,
268
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
269
                        );
270
                select.setValue(regDto.getStatus());
271
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
272
                select.setEnabled(canChangeStatus);
273
                select.setNullSelectionAllowed(false);
274
                return select;
275
            }
276

    
277

    
278
        });
279
        loadWorkingSet(getView().getCitationUuid());
280
        applyWorkingset();
281

    
282
    }
283

    
284
    private void applyWorkingset(){
285
         getView().setWorkingset(workingset);
286
        // PagingProviders and CacheGenerator for the existingNameCombobox
287
        activateComboboxes();
288
    }
289

    
290
    protected void activateComboboxes() {
291
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
292
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
293
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
294
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
295
    }
296

    
297
    /**
298
     * @param referenceID
299
     */
300
    protected void loadWorkingSet(UUID referenceUuid) {
301

    
302
        try {
303
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
304
        } catch (RegistrationValidationException error) {
305
            logger.error(error);
306
            showErrorDialog("Validation Error", error.getMessage());
307
        } catch(PermissionDeniedException e){
308
            logger.info(e);
309
            ((AccessRestrictedView)getView()).setAccessDeniedMessage(e.getMessage());
310
        }
311
        cache = new CdmTransientEntityAndUuidCacher(this);
312
        for(Registration registration : workingset.getRegistrations()) {
313
            addRootEntity(registration);
314
        }
315
    }
316

    
317
    /**
318
     * @param errorDialogCaption
319
     * @param errorMessage
320
     */
321
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
322
        Window errorDialog = new Window(errorDialogCaption);
323
        errorDialog.setModal(true);
324
        VerticalLayout subContent = new VerticalLayout();
325
        subContent.setMargin(true);
326
        errorDialog.setContent(subContent);
327
        subContent.addComponent(new Label(errorMessage));
328
        UI.getCurrent().addWindow(errorDialog);
329
    }
330

    
331
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
332
        Registration reg = getRepo().getRegistrationService().load(uuid);
333
        if(reg == null){
334
            // registration was not yet persisted, ignore
335
            return;
336
        }
337
        if(value != null && value instanceof RegistrationStatus){
338
            if(!Objects.equals(value, reg.getStatus())){
339
                reg.updateStatusAndDate((RegistrationStatus)value);
340
                getRegistrationStore().saveBean(reg, (AbstractView)getView());
341
                refreshView(true);
342
            }
343
        } else {
344
            // only log here as error
345
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
346
        }
347
    }
348

    
349

    
350
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
351
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
352

    
353
        if(!checkFromOwnView(event)){
354
            return;
355
        }
356

    
357
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
358
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
359
        popup.loadInEditor(null);
360
    }
361

    
362
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
363
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
364

    
365
        if(!checkFromOwnView(event)){
366
            return;
367
        }
368
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
369
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
370
        popup.withDeleteButton(true);
371
        popup.loadInEditor(event.getEntityUuid());
372
    }
373

    
374
    @EventBusListenerMethod
375
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
376
        if(event.getPopup() instanceof ReferencePopupEditor){
377
            if(event.getReason().equals(Reason.SAVE)){
378
                refreshView(true);
379
            }
380
        }
381
    }
382

    
383
    @EventBusListenerMethod
384
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
385
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
386
            if(event.getReason().equals(Reason.SAVE)){
387
                refreshView(true);
388
            }
389
        }
390
    }
391

    
392
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
393
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
394

    
395
        if(!checkFromOwnView(event)){
396
            return;
397
        }
398

    
399
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
400
        popup.loadInEditor(event.getEntityUuid());
401
    }
402

    
403
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
404
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
405

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

    
410
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
411
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
412
        popup.withDeleteButton(true);
413
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
414
        popup.loadInEditor(event.getEntityUuid());
415
        if(event.hasSource() && event.getSource().isReadOnly()){
416
            // avoid resetting readonly to false
417
            popup.setReadOnly(true);
418
        }
419

    
420
    }
421

    
422

    
423
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
424
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
425

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

    
430
        getView().getAddNewNameRegistrationButton().setEnabled(false);
431
        if(newNameForRegistrationPopupEditor == null){
432
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
433
            newNameForRegistrationPopupEditor = popup;
434
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
435
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
436
            popup.withDeleteButton(true);
437
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
438

    
439
                @Override
440
                public TaxonName createNewBean() {
441
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
442
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
443
                    return newTaxonName;
444
                }
445
            });
446
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
447
            popup.loadInEditor(null);
448
        }
449
    }
450

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

    
506

    
507
    /**
508
     * Creates a new Registration for an exiting (previously published) name.
509
     *
510
     * @param event
511
     * @throws RegistrationValidationException
512
     */
513
    @EventBusListenerMethod
514
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
515

    
516
        if(!event.isStart()){
517
            return;
518
        }
519

    
520
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
521
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
522
        if(typifiedName != null){
523
            boolean doReloadWorkingSet = false;
524
            try {
525
                // TODO move into a service class --------------
526
                TransactionStatus txStatus = getRepo().startTransaction(true);
527
                Reference citation = getRepo().getReferenceService().load(workingset.getCitationUuid(), Arrays.asList("authorship.$", "inReference.authorship.$"));
528
                // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
529
                // to create a typification only registration in the working (publication) set which contains
530
                // the protologe. This is known from the nomenclatural reference.
531
                if(canCreateNameRegistrationFor(typifiedName)){
532
                    // the citation which is the base for workingset contains the protologe of the name and the name has not
533
                    // been registered before:
534
                    // create a registration for the name and the first typifications
535
                    Registration newRegistrationWithExistingName = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
536
                    workingset.add(new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation));
537
                    doReloadWorkingSet = true;
538
                } else {
539
                    if(!checkWokingsetContainsProtologe(typifiedName)){
540
                        // create a typification only registration
541
                        Registration typificationOnlyRegistration = getRepo().getRegistrationService().newRegistration();
542
                        if(!getRepo().getRegistrationService().checkRegistrationExistsFor(typifiedName)){
543
                            // oops, yet no registration for this name, so we create it as blocking registration:
544
                            Registration blockingNameRegistration = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
545
                            typificationOnlyRegistration.getBlockedBy().add(blockingNameRegistration);
546
                        }
547
                        RegistrationDTO regDTO = new RegistrationDTO(typificationOnlyRegistration, typifiedName, citation);
548
                        workingset.add(regDTO);
549
                    }
550
                }
551
                getRepo().commitTransaction(txStatus);
552
                // --------------------------------------------------
553
                // tell the view to update the workingset
554
            } finally {
555
                getRepo().getSession().clear(); // #7702;
556
                refreshView(doReloadWorkingSet);
557
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
558
            }
559
        } else {
560
            logger.error("Seletced name is NULL");
561
        }
562

    
563
    }
564

    
565

    
566
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
567
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
568

    
569
        if(!checkFromOwnView(event)){
570
            return;
571
        }
572

    
573
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
574
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
575
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
576
            popup.withDeleteButton(true);
577
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
578
            if(event.hasSource()){
579
                // propagate readonly state from source button to popup
580
                popup.setReadOnly(event.getSource().isReadOnly());
581
            }
582
        } else {
583
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
584
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
585
            popup.withDeleteButton(true);
586
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
587

    
588
            popup.getCitationCombobox().setEnabled(false);
589
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
590

    
591
            if(event.hasSource()){
592
                // propagate readonly state from source button to popup
593
                popup.setReadOnly(event.getSource().isReadOnly());
594
            }
595
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
596
        }
597
    }
598

    
599
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
600
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
601

    
602
        if(!event.hasSource()){
603
            return;
604
        }
605

    
606
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
607
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
608
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
609
            TypeDesignationWorkingsetEditorIdSet identifierSet;
610
            UUID typifiedNameUuid;
611

    
612
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
613
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
614
            if(typifiedNameRef != null){
615
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
616
                typifiedNameUuid = typifiedNameRef.getUuid();
617
            } else {
618
                // case of registrations with a name in the nomenclatural act.
619
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
620
            }
621

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

    
644
                @Override
645
                public NameTypeDesignation createNewBean() {
646

    
647
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
648
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
649
                    nameTypeDesignation.setCitation(citation);
650
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
651
                    return nameTypeDesignation;
652
                }
653
            });
654
            popup.loadInEditor(null);
655
            popup.getCitationCombobox().setEnabled(false);
656
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
657
            if(event.hasSource()){
658
                // propagate readonly state from source component to popup
659
                popup.setReadOnly(event.getSource().isReadOnly());
660
            }
661
        }
662
    }
663

    
664
    /**
665
     * Performs final actions after a TypeDesignationEditor which has been
666
     * opened to add a TypeDesignation to a Registration object which was
667
     * created for an previously published name. Prior adding a typedesignation,
668
     * the according Registration object is dangling, that has no association to
669
     * any entity denoting an nomenclatural act which has a reference to a
670
     * publication. This means that the registration object is not in the
671
     * working set.
672
     *
673
     *
674
     * @param event
675
     * @throws RegistrationValidationException
676
     */
677
    @EventBusListenerMethod
678
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
679
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
680
            if(event.getReason().equals(Reason.SAVE)){
681
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
682
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
683
                refreshView(true);
684
            } else if(event.getReason().equals(Reason.CANCEL)){
685
                // noting to do
686
            }
687
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
688
            if(event.getReason().equals(Reason.SAVE)){
689
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
690

    
691
                try {
692
                    getRepo().getSession().clear();
693
                    // TODO move into a service class --------------
694
                    TransactionStatus txStatus = getRepo().startTransaction();
695
                    UUID regUUID = nameTypeDesignationPopupEditorRegistrationUUIDMap.get(event.getPopup());
696
                    Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getPopup()).getEditorActionContext();
697
                    Registration registration = findRegistrationInContext(context);
698
                    getRepo().getRegistrationService().addTypeDesignation(registration, typeDesignationUuid);
699
                    getRepo().getRegistrationService().saveOrUpdate(registration);
700
                    nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
701
                    getRepo().commitTransaction(txStatus);
702
                    // TODO move into a service class --------------
703
                } finally {
704
                    getRepo().getSession().clear();
705
                    refreshView(true);
706
                }
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
                        // TODO move into a service class --------------
759
                        TransactionStatus txStatus = getRepo().startTransaction();
760
                        // create a blocking registration, the new Registration will be persisted
761
                        UUID taxonNameUUID = event.getEntityUuid();
762
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
763

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

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

    
810
    /**
811
     * @param context
812
     * @return
813
     */
814
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
815
        EditorActionContext rootCtx = context.get(0);
816
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
817
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
818
        if(!registrationDTOOptional.isPresent()){
819
            logger.error("RegistrationDTO missing in rootCtx.");
820
        }
821
        Registration registration = registrationDTOOptional.get().registration();
822

    
823
        if(registration.isPersited()){
824
             registration = getRepo().getRegistrationService().load(registration.getUuid());
825
             if(registration == null){
826
                 throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
827
             }
828
         } else {
829
             logger.trace("Registration is not yet persisted.");
830
         }
831
        return registration;
832
    }
833

    
834
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
835
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
836

    
837
        // FIXME check from own view!!!
838
        if(getView() == null){
839
            return;
840
        }
841

    
842
        UUID registrationUuid = event.getIdentifier();
843

    
844
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
845
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
846

    
847
            Set<RegistrationDTO> blockingRegs;
848
            if(regDto.registration().isPersited()){
849
                blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
850
            } else {
851
                blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
852
            }
853
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
854
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
855
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
856
        }
857
    }
858

    
859
    /**
860
     * {@inheritDoc}
861
     */
862
    @Override
863
    public ICdmEntityUuidCacher getCache() {
864
        return cache;
865
    }
866

    
867
    /**
868
     * {@inheritDoc}
869
     */
870
    @Override
871
    public void addRootEntity(CdmBase entity) {
872
        rootEntities.add(entity);
873
        cache.load(entity);
874
    }
875

    
876

    
877
    /**
878
     * {@inheritDoc}
879
     */
880
    @Override
881
    public Collection<CdmBase> getRootEntities() {
882
        return rootEntities;
883
    }
884

    
885
    @Override
886
    public void destroy() throws Exception {
887
        super.destroy();
888
        disposeCache();
889
    }
890

    
891
    /**
892
     * {@inheritDoc}
893
     */
894
    @Override
895
    public void disposeCache() {
896
        cache.dispose();
897
    }
898

    
899
}
(10-10/18)