Project

General

Profile

Download (40.1 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.spring.annotation.SpringComponent;
31
import com.vaadin.spring.annotation.ViewScope;
32
import com.vaadin.ui.AbstractField;
33
import com.vaadin.ui.Label;
34
import com.vaadin.ui.UI;
35
import com.vaadin.ui.VerticalLayout;
36
import com.vaadin.ui.Window;
37

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

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

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

    
111
    private static final long serialVersionUID = 1L;
112

    
113
    @Autowired
114
    private IRegistrationWorkingSetService regWorkingSetService;
115

    
116
    @Autowired
117
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
118

    
119

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

    
127
    private RegistrationWorkingSet workingset;
128

    
129
    /**
130
     * 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.
131
     * There can always only be one popup editor for this purpose.
132
     */
133
    private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
134

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

    
140
    /**
141
     * TODO is this still needed? The regitration UUID should be accessible in the popup editor context,
142
     * see findRegistrationInContext()
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 reload the workingset from the persistent storage.
206
     *  Workingsets which are not yet persisted are preserved.
207
     *
208
     */
209
    protected void refreshView(boolean doReload) {
210
        if(workingset == null){
211
            return; // nothing to do
212
        }
213
        if(doReload){
214
            List<RegistrationDTO> unpersisted = new ArrayList<>();
215
            for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
216
                if(!regDto.registration().isPersited()){
217
                    unpersisted.add(regDto);
218
                }
219
            }
220
            loadWorkingSet(workingset.getCitationUuid());
221
            for(RegistrationDTO regDtoUnpersisted : unpersisted){
222
                if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
223
                    // only add if the regDtoUnpersisted has not been persisted meanwhile
224
                    try {
225
                        workingset.add(regDtoUnpersisted);
226
                    } catch (RegistrationValidationException e) {
227
                        // would never happen here //
228
                    }
229
                }
230
            }
231
        }
232
        applyWorkingset();
233
    }
234

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

    
245
            private static final long serialVersionUID = 7099181280977511048L;
246

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

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

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

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

    
276

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

    
281
    }
282

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

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

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

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

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

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

    
348

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

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

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

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

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

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

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

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

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

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

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

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

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

    
419
    }
420

    
421

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

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

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

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

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

    
505

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

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

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

    
562
    }
563

    
564

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

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

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

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

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

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

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

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

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

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

    
643
                @Override
644
                public NameTypeDesignation createNewBean() {
645

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

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

    
690
                try {
691
                    getRepo().getSession().clear();
692
                    // TODO move into a service class --------------
693
                    TransactionStatus txStatus = getRepo().startTransaction();
694
                    UUID regUUID = nameTypeDesignationPopupEditorRegistrationUUIDMap.get(event.getPopup());
695
                    Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getPopup()).getEditorActionContext();
696
                    Registration registration = findRegistrationInContext(context);
697
                    getRepo().getRegistrationService().addTypeDesignation(registration, typeDesignationUuid);
698
                    getRepo().getRegistrationService().saveOrUpdate(registration);
699
                    nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
700
                    getRepo().commitTransaction(txStatus);
701
                    // TODO move into a service class --------------
702
                } finally {
703
                    getRepo().getSession().clear();
704
                    refreshView(true);
705
                }
706
            } else if(event.getReason().equals(Reason.CANCEL)){
707
                // noting to do
708
            }
709

    
710
        }
711
        // ignore other editors
712
    }
713

    
714

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

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

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

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

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

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

    
755
                    try {
756
                        getRepo().getSession().clear();
757
                        // TODO move into a service class --------------
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 somehow related to an existing registration
772
                            Registration registration = findRegistrationInContext(context);
773
                            registration.getBlockedBy().add(blockingRegistration);
774

    
775
                            if(registration.isPersited()){
776
                                getRepo().getRegistrationService().saveOrUpdate(registration);
777
                                logger.debug("Blocking registration created, added to registion and persited");
778
                            }
779
                            getRepo().commitTransaction(txStatus);
780
                            // TODO move into a service class --------------
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
    /**
810
     * @param context
811
     * @return
812
     */
813
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
814
        EditorActionContext rootCtx = context.get(0);
815
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
816
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
817
        Registration registration = registrationDTO.registration();
818

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

    
830
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
831
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
832

    
833
        // FIXME check from own view!!!
834
        if(getView() == null){
835
            return;
836
        }
837

    
838
        UUID registrationUuid = event.getIdentifier();
839

    
840
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
841
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
842

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

    
855
    /**
856
     * {@inheritDoc}
857
     */
858
    @Override
859
    public ICdmEntityUuidCacher getCache() {
860
        return cache;
861
    }
862

    
863
    /**
864
     * {@inheritDoc}
865
     */
866
    @Override
867
    public void addRootEntity(CdmBase entity) {
868
        rootEntities.add(entity);
869
        cache.load(entity);
870
    }
871

    
872

    
873
    /**
874
     * {@inheritDoc}
875
     */
876
    @Override
877
    public Collection<CdmBase> getRootEntities() {
878
        return rootEntities;
879
    }
880

    
881
    @Override
882
    public void destroy() throws Exception {
883
        super.destroy();
884
        disposeCache();
885
    }
886

    
887
    /**
888
     * {@inheritDoc}
889
     */
890
    @Override
891
    public void disposeCache() {
892
        cache.dispose();
893
    }
894

    
895
}
(10-10/18)