Project

General

Profile

Download (39.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.vaadin.view.registration;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.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.vaadin.spring.events.EventScope;
28
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
29

    
30
import com.vaadin.server.ClientConnector.DetachEvent;
31
import com.vaadin.server.ClientConnector.DetachListener;
32
import com.vaadin.spring.annotation.SpringComponent;
33
import com.vaadin.spring.annotation.ViewScope;
34
import com.vaadin.ui.AbstractField;
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.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.TypeDesignationWorkingSet.TypeDesignationWorkingSetType;
45
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
46
import eu.etaxonomy.cdm.api.util.UserHelper;
47
import eu.etaxonomy.cdm.cache.CdmTransientEntityAndUuidCacher;
48
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
49
import eu.etaxonomy.cdm.model.common.CdmBase;
50
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
51
import eu.etaxonomy.cdm.model.name.Rank;
52
import eu.etaxonomy.cdm.model.name.Registration;
53
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
54
import eu.etaxonomy.cdm.model.name.TaxonName;
55
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
56
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
57
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
58
import eu.etaxonomy.cdm.model.permission.CRUD;
59
import eu.etaxonomy.cdm.model.reference.Reference;
60
import eu.etaxonomy.cdm.ref.TypedEntityReference;
61
import eu.etaxonomy.cdm.service.CdmBeanItemContainerFactory;
62
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
63
import eu.etaxonomy.cdm.service.CdmFilterablePagingProviderFactory;
64
import eu.etaxonomy.cdm.service.CdmStore;
65
import eu.etaxonomy.cdm.service.IRegistrationWorkflowService;
66
import eu.etaxonomy.cdm.service.UserHelperAccess;
67
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
68
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
69
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
70
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
71
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
72
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
73
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
74
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
75
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
76
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
77
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
78
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
79
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
80
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
81
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
82
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
83
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
84
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
85
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationWorkingsetIds;
86
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetIds;
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.TaxonNamePopupEditorMode;
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
import eu.etaxonomy.vaadin.ui.view.PopupView;
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 IRegistrationWorkflowService registrationWorkflowService;
119

    
120
    @Autowired
121
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
122

    
123
    @Autowired
124
    private CdmBeanItemContainerFactory selectFieldFactory;
125

    
126
    @Autowired
127
    private CdmStore cdmStore;
128

    
129
    /**
130
     * @return the regWorkingSetService
131
     */
132
    public IRegistrationWorkingSetService getWorkingSetService() {
133
        return regWorkingSetService;
134
    }
135

    
136
    private RegistrationWorkingSet workingset;
137

    
138
    /**
139
     * 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.
140
     * There can always only be one popup editor for this purpose.
141
     */
142
    private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
143

    
144
    /**
145
     * Contains
146
     */
147
    private List<Registration> newNameBlockingRegistrations = new ArrayList<>();
148

    
149
    /**
150
     * TODO is this still needed? The registration UUID should be accessible in the popup editor context,
151
     * see findRegistrationInContext()
152
     */
153
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
154

    
155

    
156
    private ICdmEntityUuidCacher cache;
157

    
158
    private Collection<CdmBase> rootEntities = new HashSet<>();
159

    
160

    
161
    public RegistrationWorkingsetPresenter() {
162
    }
163

    
164
    /**
165
     * @param doReload reload the workingset from the persistent storage.
166
     *  Workingsets which are not yet persisted are preserved.
167
     */
168
    protected void refreshView(boolean doReload) {
169

    
170
        if(workingset == null){
171
            return; // nothing to do
172
        }
173
        if(doReload){
174
            if(logger.isDebugEnabled()){
175
                logger.debug("refreshView() - workingset:\n" + workingset.toString());
176
            }
177
            List<RegistrationDTO> unpersisted = new ArrayList<>();
178
            for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
179
                if(!regDto.registration().isPersited()){
180
                    unpersisted.add(regDto);
181
                }
182
            }
183
            loadWorkingSet(workingset.getCitationUuid());
184
            for(RegistrationDTO regDtoUnpersisted : unpersisted){
185
                if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
186
                    // only add if the regDtoUnpersisted has not been persisted meanwhile
187
                    try {
188
                        workingset.add(regDtoUnpersisted);
189
                    } catch (RegistrationValidationException e) {
190
                        // would never happen here //
191
                    }
192
                }
193
            }
194
            if(logger.isDebugEnabled()){
195
                logger.debug("refreshView() - workingset reloaded:\n" + workingset.toString());
196
            }
197
        }
198
        applyWorkingset();
199
    }
200

    
201
    @Override
202
    public void handleViewEntered() {
203
        super.handleViewEntered();
204
        // TODO currently cannot specify type more precisely, see AbstractSelect
205
        // FIXME externalize into class file!!!!!!!!!!!!
206
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
207

    
208
            private static final long serialVersionUID = 7099181280977511048L;
209

    
210
            @Override
211
            public AbstractField<Object> create(RegistrationDTO regDto) {
212

    
213
                // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
214
                UserHelper userHelper = UserHelperAccess.userHelper().withCache(getCache());
215
                Set<RegistrationStatus> availableStatus = new HashSet<>();
216

    
217
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
218
                availableStatus.add(regDto.getStatus());
219
                if(canChangeStatus){
220
                    if(userHelper.userIsAdmin()){
221
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
222
                    } else {
223
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
224
                    }
225
                }
226

    
227
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildEnumTermItemContainer(
228
                        RegistrationStatus.class,
229
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
230
                        );
231
                select.setValue(regDto.getStatus());
232
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
233
                select.setEnabled(canChangeStatus);
234
                select.setNullSelectionAllowed(false);
235
                return select;
236
            }
237

    
238

    
239
        });
240

    
241
        loadWorkingSet(getView().getCitationUuid());
242
        applyWorkingset();
243

    
244
    }
245

    
246
    private void applyWorkingset(){
247
         getView().setWorkingset(workingset);
248
        // PagingProviders and CacheGenerator for the existingNameCombobox
249
        activateComboboxes();
250
    }
251

    
252
    protected void activateComboboxes() {
253
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
254
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
255
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
256
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
257
    }
258

    
259
    /**
260
     * @param referenceID
261
     */
262
    protected void loadWorkingSet(UUID referenceUuid) {
263

    
264
        try {
265
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
266
        } catch (RegistrationValidationException error) {
267
            logger.error(error);
268
            showErrorDialog("Validation Error", error.getMessage());
269
        }
270
        cache = new CdmTransientEntityAndUuidCacher(this);
271
        for(Registration registration : workingset.getRegistrations()) {
272
            addRootEntity(registration);
273
        }
274
    }
275

    
276
    /**
277
     * @param errorDialogCaption
278
     * @param errorMessage
279
     */
280
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
281
        Window errorDialog = new Window(errorDialogCaption);
282
        errorDialog.setModal(true);
283
        VerticalLayout subContent = new VerticalLayout();
284
        subContent.setMargin(true);
285
        errorDialog.setContent(subContent);
286
        subContent.addComponent(new Label(errorMessage));
287
        UI.getCurrent().addWindow(errorDialog);
288
    }
289

    
290
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
291
        Registration reg = getRepo().getRegistrationService().load(uuid);
292
        if(reg == null){
293
            // registration was not yet persisted, ignore
294
            return;
295
        }
296
        if(value != null && value instanceof RegistrationStatus){
297
            if(!Objects.equals(value, reg.getStatus())){
298
                reg.updateStatusAndDate((RegistrationStatus)value);
299
                cdmStore.saveBean(reg, (AbstractView)getView());
300
                refreshView(true);
301
            }
302
        } else {
303
            // only log here as error
304
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
305
        }
306
    }
307

    
308

    
309
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
310
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
311

    
312
        if(!checkFromOwnView(event)){
313
            return;
314
        }
315

    
316
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
317
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
318
        popup.loadInEditor(null);
319
    }
320

    
321
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
322
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
323

    
324
        if(!checkFromOwnView(event)){
325
            return;
326
        }
327
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
328
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
329
        popup.withDeleteButton(true);
330
        popup.loadInEditor(event.getEntityUuid());
331
    }
332

    
333
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
334
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
335

    
336
        if(!checkFromOwnView(event)){
337
            return;
338
        }
339

    
340
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
341
        popup.loadInEditor(event.getEntityUuid());
342
    }
343

    
344
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
345
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
346

    
347
        if(!checkFromOwnView(event)){
348
            return;
349
        }
350

    
351
        boolean isAddExistingNameRegistration = event.getTarget() != null && event.getTarget().equals(getView().getAddExistingNameCombobox());
352

    
353
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
354

    
355
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
356
        popup.withDeleteButton(!isAddExistingNameRegistration);
357
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
358
        if(isAddExistingNameRegistration){
359
            // allow saving even if the name parts are not valid
360
            // the user will need to fix this in a later step
361
            popup.disableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
362
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
363
            popup.addDetachListener(new DetachListener() {
364

    
365
                @Override
366
                public void detach(DetachEvent event) {
367
                    getView().getAddExistingNameRegistrationButton().setEnabled(true);
368

    
369
                }
370
            });
371
        }
372
        popup.loadInEditor(event.getEntityUuid());
373
        if(event.hasSource() && event.getSource().isReadOnly()){
374
            // avoid resetting readonly to false
375
            popup.setReadOnly(true);
376
        }
377

    
378
        boolean hasNomRef = popup.getBean().getNomenclaturalReference() != null;
379
        if(isAddExistingNameRegistration){
380
            popup.setAllFieldsReadOnly(true);
381
            if(!hasNomRef){
382
                // only allow editing the nomenclatural reference, all other
383
                // editing need to be done another way.
384
                // Otherwise we would need to be prepared for creating blocking registrations
385
                // in turn of creation, modification of related taxon names.
386
                popup.disableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
387
                popup.getNomReferenceCombobox().setReadOnly(false);
388
                popup.getNomenclaturalReferenceDetail().setReadOnly(false);
389
                popup.addStatusMessage("The chosen name needs to be completed before it can be used. "
390
                        + "Please add the nomenclatural reference and click on \"Save\" to proceed with entering the type of this name.");
391
            } else {
392
                popup.addStatusMessage("You are about to create a registration for this name. "
393
                        + "This editor is for reviewing the name only. Therefore, all fields have been switched to readonly state. "
394
                        + "Click on \"Save\" to proceed with entering the type of this name.");
395
            }
396
        }
397
    }
398

    
399

    
400
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
401
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
402

    
403
        if(!checkFromOwnView(event)){
404
            return;
405
        }
406

    
407
        getView().getAddNewNameRegistrationButton().setEnabled(false);
408
        if(newNameForRegistrationPopupEditor == null){
409
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
410
            newNameForRegistrationPopupEditor = popup;
411
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
412
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
413
            popup.withDeleteButton(true);
414
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
415

    
416
                @Override
417
                public TaxonName createNewBean() {
418
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
419
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
420
                    return newTaxonName;
421
                }
422
            });
423
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
424
            popup.loadInEditor(null);
425
        }
426
    }
427

    
428
    /**
429
     * Creates a new <code>Registration</code> for a new name that has just been edited
430
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
431
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
432
     * Any blocking registrations which have been created while editing the new name are
433
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
434
     * for the first name has been created. Additional new names are created for example
435
     * when a new name as basionym, replaced synonym, etc to the new name is created.
436
     * <p>
437
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
438
     *
439
     * @param event
440
     * @throws RegistrationValidationException
441
     *      passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
442
     */
443
    @EventBusListenerMethod
444
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException {
445

    
446
        if(!isFromOwnView(event)){
447
            return;
448
        }
449

    
450
        if(event.getPopup() instanceof TaxonNamePopupEditor){
451

    
452
                EditorActionContext rootContext = editorActionContextRoot(event.getPopup());
453
                boolean isAddExistingNameRegistration = rootContext.getTargetField() != null && rootContext.getTargetField().equals(getView().getAddExistingNameCombobox());
454

    
455
                if(isAddExistingNameRegistration){
456
                    if(event.getReason().equals(Reason.SAVE)){
457
                    onRegistrationWorkflowEventActionStart(new RegistrationWorkingsetAction(workingset.getCitationUuid(),
458
                            RegistrationWorkingsetAction.Action.start));
459
                    }
460
                    // just ignore on CANCEL
461
                } else {
462
                    Optional<Registration> registrationOpt = Optional.ofNullable(null);
463
                    if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
464
                        if(event.getReason().equals(Reason.SAVE)){
465
                            try {
466
                                TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
467
                                registrationOpt = Optional.of(registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations));
468
                                loadWorkingSet(workingset.getCitationUuid());
469
                            } finally {
470
                                clearSession();
471
                                getView().getAddNewNameRegistrationButton().setEnabled(true);
472
                            }
473
                        }
474
                        // nullify and clear the memory on this popup editor in any case (SAVE, DELETE, CANCEL)
475
                        newNameForRegistrationPopupEditor = null;
476
                        newNameBlockingRegistrations.clear();
477
                        getView().getAddNewNameRegistrationButton().setEnabled(true);
478
                    }
479

    
480
                    if(event.getReason().equals(Reason.SAVE)){
481
                        if(!registrationOpt.isPresent()){
482
                            // no new registration has been created above, so there must be an existing one.
483
                            registrationOpt = findRegistrationInContext(event.getPopup());
484
                        }
485

    
486
                        // Check if the other names used in the context of the name are registered yet.
487
                        TaxonNamePopupEditor nameEditor = (TaxonNamePopupEditor)event.getPopup();
488
                        Set<TaxonName> namesToCheck = new HashSet<>();
489

    
490
                        namesToCheck.addAll(nameEditor.getBasionymComboboxSelect().getValue());
491
                        namesToCheck.addAll(nameEditor.getReplacedSynonymsComboboxSelect().getValue());
492
                        namesToCheck.add(nameEditor.getValidationField().getRelatedNameComboBox().getValue());
493
                        namesToCheck.add(nameEditor.getOrthographicVariantField().getRelatedNameComboBox().getValue());
494
                        // NOTE: according to https://dev.e-taxonomy.eu/redmine/issues/8049#note-2 we will not create blocking
495
                        // registrations for names in WeaklyRelatedEntityFields
496

    
497
                        for(TaxonName name : namesToCheck){
498
                            if(name != null){
499
                                clearSession();
500
                                assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
501
                            }
502
                        }
503
                    } else if (event.getReason().equals(Reason.DELETE)){
504
                        //FIXME handle delete: need to remove blocking registrations?
505
                    }
506
                    // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
507
                    refreshView(isAtContextRoot(event.getPopup()));
508
                }
509
        }
510
    }
511

    
512

    
513
    /**
514
     * Creates a new Registration for an exiting (previously published) name.
515
     *
516
     * @param event
517
     * @throws RegistrationValidationException
518
     */
519
    @EventBusListenerMethod
520
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
521

    
522
        if(!event.isStart()){
523
            return;
524
        }
525

    
526
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
527
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
528
        if(typifiedName != null){
529
            boolean doReloadWorkingSet = false;
530
            try {
531
                doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
532
            } finally {
533
                clearSession();
534
                refreshView(doReloadWorkingSet);
535
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
536
            }
537
        } else {
538
            logger.error("Seletced name is NULL");
539
        }
540

    
541
    }
542

    
543
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
544
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
545

    
546
        if(!checkFromOwnView(event)){
547
            return;
548
        }
549

    
550
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
551

    
552
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
553
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
554
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
555
            popup.withDeleteButton(true);
556
            popup.loadInEditor(new SpecimenTypeDesignationWorkingsetIds(
557
                    workingset.getCitationUuid(),
558
                    event.getRegistrationUuid(),
559
                    event.getBaseEntityRef().castTo(FieldUnit.class), null));
560
            if(event.hasSource()){
561
                // propagate readonly state from source button to popup
562
                popup.setReadOnly(event.getSource().isReadOnly());
563
            }
564
        } else {
565
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
566
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
567
            popup.withDeleteButton(true);
568
            popup.loadInEditor(NameTypeDesignationWorkingsetIds.forExistingTypeDesignation(
569
                    registrationDTO.getCitationUuid(),
570
                    event.getBaseEntityRef().castTo(NameTypeDesignation.class))
571
                    );
572
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
573
            if(event.hasSource()){
574
                // propagate readonly state from source button to popup
575
                popup.setReadOnly(event.getSource().isReadOnly());
576
            }
577
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
578
        }
579
    }
580

    
581
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
582
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
583

    
584
        if(!event.hasSource()){
585
            return;
586
        }
587

    
588
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
589

    
590
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
591
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
592
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
593
            TypedEntityReference<TaxonName> typifiedNameRef;
594
            if(registrationDTO.getTypifiedNameRef() != null){
595
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
596
                typifiedNameRef = new TypedEntityReference(TaxonName.class, registrationDTO.getTypifiedNameRef().getUuid());
597
            } else {
598
                // case of registrations with a name in the nomenclatural act.
599
                typifiedNameRef = new TypedEntityReference(TaxonName.class, registrationDTO.getNameRef().getUuid());
600
            }
601

    
602
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
603
            popup.withDeleteButton(false);
604
            popup.loadInEditor(new SpecimenTypeDesignationWorkingsetIds(
605
                        workingset.getCitationUuid(),
606
                        event.getRegistrationUuid(),
607
                        null,
608
                        typifiedNameRef.getUuid()
609
                        )
610
                    );
611
            if(event.hasSource()){
612
                // propagate readonly state from source component to popup
613
                popup.setReadOnly(event.getSource().isReadOnly());
614
            }
615
        } else {
616
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
617
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
618
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
619
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
620
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
621

    
622
                @Override
623
                public NameTypeDesignation createNewBean() {
624

    
625
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{
626
                            "typeDesignations",
627
                            "homotypicalGroup",
628
                            "nomenclaturalSource.citation"
629
                            }));
630
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
631
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
632
                    return nameTypeDesignation;
633
                }
634
            });
635
            popup.withDeleteButton(false);
636
            popup.loadInEditor(NameTypeDesignationWorkingsetIds.forNewTypeDesignation(
637
                    registrationDTO.getCitationUuid(),
638
                    event.getTypifiedNameUuid()
639
                    )
640
                );
641
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
642
            if(event.hasSource()){
643
                // propagate readonly state from source component to popup
644
                popup.setReadOnly(event.getSource().isReadOnly());
645
            }
646
        }
647
    }
648

    
649
    /**
650
     * Performs final actions after a TypeDesignationEditor which has been
651
     * opened to add a TypeDesignation to a Registration object which was
652
     * created for an previously published name. Prior adding a typedesignation,
653
     * the according Registration object is dangling, that has no association to
654
     * any entity denoting an nomenclatural act which has a reference to a
655
     * publication. This means that the registration object is not in the
656
     * working set.
657
     *
658
     *
659
     * @param event
660
     * @throws RegistrationValidationException
661
     */
662
    @EventBusListenerMethod
663
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) {
664

    
665
        if(!isFromOwnView(event)){
666
            return;
667
        }
668

    
669
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
670
            if(event.getReason().equals(Reason.SAVE)){
671
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
672
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
673
            }
674
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
675
            refreshView(isAtContextRoot(event.getPopup()));
676
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
677
            if(event.getReason().equals(Reason.SAVE)){
678

    
679
                Optional<Registration> registrationOpt = Optional.ofNullable(null);
680
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
681
                try {
682
                    clearSession();
683
                    registrationOpt = findRegistrationInContext(event.getPopup());
684
                    registrationOpt.ifPresent(reg -> {
685
                        registrationWorkflowService.addTypeDesignation(typeDesignationUuid, reg);
686
                        nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
687
                        });
688

    
689
                } finally {
690
                    clearSession();
691
                }
692

    
693
                // Check if other names used in the context of the name are registered yet.
694
                NameTypeDesignationPopupEditor nameTypeDesignationEditor = (NameTypeDesignationPopupEditor)event.getPopup();
695
                Set<TaxonName> namesToCheck = new HashSet<>();
696

    
697
                namesToCheck.add(nameTypeDesignationEditor.getTypeNameField().getValue());
698

    
699
                for(TaxonName name : namesToCheck){
700
                    if(name != null){
701
                        assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
702
                    }
703

    
704
                }
705

    
706
            } else if(event.getReason().equals(Reason.CANCEL)){
707
                // noting to do
708
            }
709
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
710
            refreshView(isAtContextRoot(event.getPopup()));
711

    
712
        }
713
        // ignore other editors
714
    }
715

    
716
    private void assocciateOrQueueBlockingRegistration(Optional<Registration> registrationOpt, UUID nameUuid) {
717
        registrationOpt.ifPresent(reg -> registrationWorkflowService.addBlockingRegistration(nameUuid, reg));
718
        if(!registrationOpt.isPresent()){
719
            // not present!
720
            Registration blockingRegistration = registrationWorkflowService.prepareBlockingRegistration(nameUuid);
721
            if(blockingRegistration != null){
722
                newNameBlockingRegistrations.add(blockingRegistration);
723
                logger.debug("Blocking registration created and queued for later association with the main registration.");
724
            }
725
        }
726
    }
727

    
728

    
729
    public void clearSession() {
730
        getRepo().clearSession();
731
    }
732

    
733
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
734
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
735

    
736
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
737
            List<String> messages = new ArrayList<>();
738
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
739
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
740
            }
741
            getView().openDetailsPopup("Validation Problems", messages);
742
        }
743
    }
744

    
745
    @EventBusListenerMethod
746
    public void onEntityChangeEvent(EntityChangeEvent event){
747

    
748
        if(!isFromOwnView(event)){
749
            return;
750
        }
751

    
752
        if(workingset == null){
753
            return;
754
        }
755
        if(Reference.class.isAssignableFrom(event.getEntityType())){
756

    
757
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
758
                if(event.isRemovedType()){
759
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
760
                } else {
761
                    refreshView(true);
762
                }
763
            }
764

    
765
        } else
766
        if(Registration.class.isAssignableFrom(event.getEntityType())){
767
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
768
                refreshView(true);
769
            }
770
        } else
771
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
772
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
773
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
774
                EditorActionContext rootContext = context.get(0);
775
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
776
                    try {
777
                        clearSession();
778
                        // create a blocking registration
779
                        UUID taxonNameUUID = event.getEntityUuid();
780
                        Optional<Registration> registrationOpt = findRegistrationInContext(context);
781
                        assocciateOrQueueBlockingRegistration(registrationOpt, taxonNameUUID);
782
                    } finally {
783
                        clearSession();
784
                    }
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
    public Optional<Registration> findRegistrationInContext(PopupView popupView) {
811
        Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
812
        return findRegistrationInContext(context);
813
    }
814

    
815
    /**
816
     * Finds the Registration in the EditorContext stack
817
     */
818
    public Optional<Registration> findRegistrationInContext(Stack<EditorActionContext> context) {
819
        EditorActionContext rootCtx = context.get(0);
820
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
821
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
822
        Optional<Registration> registrationOptional;
823
        if(!registrationDTOOptional.isPresent()){
824
            logger.debug("No RegistrationDTO in found rootCtx -> user is about to create a registration for a new name.");
825
            registrationOptional = Optional.ofNullable(null);
826
        }
827

    
828
        Optional<Registration> regOpt;
829
        if(registrationDTOOptional.isPresent()){
830
            regOpt = Optional.of(registrationDTOOptional.get().registration());
831
        } else {
832
            regOpt = Optional.ofNullable(null);
833
        }
834

    
835
        return regOpt;
836
    }
837

    
838
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
839
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
840

    
841
        // FIXME check from own view!!!
842
        if(getView() == null){
843
            return;
844
        }
845

    
846
        UUID registrationUuid = event.getIdentifier();
847

    
848
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
849
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
850

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

    
863
    @Override
864
    public ICdmEntityUuidCacher getCache() {
865
        return cache;
866
    }
867

    
868
    @Override
869
    public void addRootEntity(CdmBase entity) {
870
        rootEntities.add(entity);
871
        cache.load(entity);
872
    }
873

    
874
    @Override
875
    public Collection<CdmBase> getRootEntities() {
876
        return rootEntities;
877
    }
878

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

    
885
    @Override
886
    public void disposeCache() {
887
        cache.dispose();
888
    }
889

    
890
    public boolean canCreateNameRegistrationFor(TaxonName name) {
891
        return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
892
    }
893

    
894
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
895
        return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
896
    }
897
}
(10-10/18)