Project

General

Profile

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

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

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

    
110
    private static final long serialVersionUID = 1L;
111

    
112
    @Autowired
113
    private IRegistrationWorkingSetService regWorkingSetService;
114

    
115
    @Autowired
116
    private IRegistrationWorkflowService registrationWorkflowService;
117

    
118
    @Autowired
119
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
120

    
121
    @Autowired
122
    private CdmBeanItemContainerFactory selectFieldFactory;
123

    
124
    @Autowired
125
    private CdmStore cdmStore;
126

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

    
134
    private RegistrationWorkingSet workingset;
135

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

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

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

    
153

    
154
    private ICdmEntityUuidCacher cache;
155

    
156
    private Collection<CdmBase> rootEntities = new HashSet<>();
157

    
158
    /**
159
     *
160
     */
161
    public RegistrationWorkingsetPresenter() {
162
    }
163

    
164
    /**
165

    
166

    
167
    /**
168
     * @param doReload reload the workingset from the persistent storage.
169
     *  Workingsets which are not yet persisted are preserved.
170
     *
171
     */
172
    protected void refreshView(boolean doReload) {
173
        if(workingset == null){
174
            return; // nothing to do
175
        }
176
        if(doReload){
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
        }
195
        applyWorkingset();
196
    }
197

    
198
    /**
199
     * {@inheritDoc}
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.buildBeanItemContainer(
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
        loadWorkingSet(getView().getCitationUuid());
241
        applyWorkingset();
242

    
243
    }
244

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

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

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

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

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

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

    
310

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

    
314
        if(!checkFromOwnView(event)){
315
            return;
316
        }
317

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

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

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

    
335
    @EventBusListenerMethod
336
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
337
        if(event.getPopup() instanceof ReferencePopupEditor){
338
            if(event.getReason().equals(Reason.SAVE)){
339
                refreshView(true);
340
            }
341
        }
342
    }
343

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

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

    
351
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
352
        popup.loadInEditor(event.getEntityUuid());
353
    }
354

    
355
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
356
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
357

    
358
        if(!checkFromOwnView(event)){
359
            return;
360
        }
361

    
362
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
363
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
364
        popup.withDeleteButton(true);
365
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
366
        popup.loadInEditor(event.getEntityUuid());
367
        if(event.hasSource() && event.getSource().isReadOnly()){
368
            // avoid resetting readonly to false
369
            popup.setReadOnly(true);
370
        }
371

    
372
    }
373

    
374

    
375
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
376
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
377

    
378
        if(!checkFromOwnView(event)){
379
            return;
380
        }
381

    
382
        getView().getAddNewNameRegistrationButton().setEnabled(false);
383
        if(newNameForRegistrationPopupEditor == null){
384
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
385
            newNameForRegistrationPopupEditor = popup;
386
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
387
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
388
            popup.withDeleteButton(true);
389
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
390

    
391
                @Override
392
                public TaxonName createNewBean() {
393
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
394
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
395
                    return newTaxonName;
396
                }
397
            });
398
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
399
            popup.loadInEditor(null);
400
        }
401
    }
402

    
403
    /**
404
     * Creates a new <code>Registration</code> for a new name that has just been edited
405
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
406
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
407
     * Any blocking registrations which have been created while editing the new name are
408
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
409
     * for the first name has been created. Additional new names are created for example
410
     * when a new name as basionym, replaced synonym, etc to the new name is created.
411
     * <p>
412
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
413
     *
414
     * @param event
415
     * @throws RegistrationValidationException
416
     */
417
    @EventBusListenerMethod
418
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) {
419
        if(event.getPopup() instanceof TaxonNamePopupEditor){
420
            Registration registration = null;
421
            boolean doRefreshView = false;
422
            if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
423
                if(event.getReason().equals(Reason.SAVE)){
424
                    try {
425
                        TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
426
                        registration = registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations);
427
                        loadWorkingSet(workingset.getCitationUuid());
428
                    } finally {
429
                        clearSession();
430
                        doRefreshView = true;
431
                        getView().getAddNewNameRegistrationButton().setEnabled(true);
432
                    }
433
                }
434
                // nullify and clear the memory on this popup editor in any case (SAVE, CANCEL, DELETE)
435
                newNameForRegistrationPopupEditor = null;
436
                newNameBlockingRegistrations.clear();
437
                getView().getAddNewNameRegistrationButton().setEnabled(true);
438
            }
439

    
440
            if(registration == null){
441
                // no new registration has been created above, so there must be an existing one.
442
                registration = findRegistrationInContext(event.getPopup());
443
            }
444

    
445
            // Check if the other names used in the context of the name are registered yet.
446
            TaxonNamePopupEditor nameEditor = (TaxonNamePopupEditor)event.getPopup();
447
            Set<TaxonName> namesToCheck = new HashSet<>();
448

    
449
            namesToCheck.addAll(nameEditor.getBasionymComboboxSelect().getValue());
450
            namesToCheck.addAll(nameEditor.getReplacedSynonymsComboboxSelect().getValue());
451
            namesToCheck.add(nameEditor.getValidationField().getRelatedNameComboBox().getValue());
452
            namesToCheck.add(nameEditor.getOrthographicVariantField().getRelatedNameComboBox().getValue());
453

    
454
            for(TaxonName name : namesToCheck){
455
                if(name != null){
456
                    doRefreshView |= registrationWorkflowService.addBlockingRegistration(name.getUuid(), registration) != null;
457
                }
458
            }
459

    
460
            refreshView(doRefreshView);
461
        }
462
    }
463

    
464

    
465

    
466

    
467
    /**
468
     * Creates a new Registration for an exiting (previously published) name.
469
     *
470
     * @param event
471
     * @throws RegistrationValidationException
472
     */
473
    @EventBusListenerMethod
474
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
475

    
476
        if(!event.isStart()){
477
            return;
478
        }
479

    
480
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
481
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
482
        if(typifiedName != null){
483
            boolean doReloadWorkingSet = false;
484
            try {
485
                doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
486
            } finally {
487
                clearSession();
488
                refreshView(doReloadWorkingSet);
489
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
490
            }
491
        } else {
492
            logger.error("Seletced name is NULL");
493
        }
494

    
495
    }
496

    
497
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
498
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
499

    
500
        if(!checkFromOwnView(event)){
501
            return;
502
        }
503

    
504
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
505
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
506
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
507
            popup.withDeleteButton(true);
508
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
509
            if(event.hasSource()){
510
                // propagate readonly state from source button to popup
511
                popup.setReadOnly(event.getSource().isReadOnly());
512
            }
513
        } else {
514
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
515
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
516
            popup.withDeleteButton(true);
517
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
518

    
519
            popup.getCitationCombobox().setEnabled(false);
520
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
521

    
522
            if(event.hasSource()){
523
                // propagate readonly state from source button to popup
524
                popup.setReadOnly(event.getSource().isReadOnly());
525
            }
526
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
527
        }
528
    }
529

    
530
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
531
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
532

    
533
        if(!event.hasSource()){
534
            return;
535
        }
536

    
537
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
538
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
539
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
540
            TypeDesignationWorkingsetEditorIdSet identifierSet;
541
            UUID typifiedNameUuid;
542

    
543
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
544
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
545
            if(typifiedNameRef != null){
546
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
547
                typifiedNameUuid = typifiedNameRef.getUuid();
548
            } else {
549
                // case of registrations with a name in the nomenclatural act.
550
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
551
            }
552

    
553
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
554
                    event.getRegistrationUuid(),
555
                    getView().getCitationUuid(),
556
                    typifiedNameUuid
557
                    );
558
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
559
            popup.loadInEditor(identifierSet);
560
            popup.withDeleteButton(true);
561
            if(event.hasSource()){
562
                // propagate readonly state from source component to popup
563
                popup.setReadOnly(event.getSource().isReadOnly());
564
            }
565
        } else {
566
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
567
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
568
            popup.withDeleteButton(true);
569
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
570
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
571
            Reference citation = regDto.getCitation();
572
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
573
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
574

    
575
                @Override
576
                public NameTypeDesignation createNewBean() {
577

    
578
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
579
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
580
                    nameTypeDesignation.setCitation(citation);
581
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
582
                    return nameTypeDesignation;
583
                }
584
            });
585
            popup.loadInEditor(null);
586
            popup.getCitationCombobox().setEnabled(false);
587
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
588
            if(event.hasSource()){
589
                // propagate readonly state from source component to popup
590
                popup.setReadOnly(event.getSource().isReadOnly());
591
            }
592
        }
593
    }
594

    
595
    /**
596
     * Performs final actions after a TypeDesignationEditor which has been
597
     * opened to add a TypeDesignation to a Registration object which was
598
     * created for an previously published name. Prior adding a typedesignation,
599
     * the according Registration object is dangling, that has no association to
600
     * any entity denoting an nomenclatural act which has a reference to a
601
     * publication. This means that the registration object is not in the
602
     * working set.
603
     *
604
     *
605
     * @param event
606
     * @throws RegistrationValidationException
607
     */
608
    @EventBusListenerMethod
609
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) {
610
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
611
            if(event.getReason().equals(Reason.SAVE)){
612
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
613
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
614
                refreshView(true);
615
            } else if(event.getReason().equals(Reason.CANCEL)){
616
                // noting to do
617
            }
618
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
619
            if(event.getReason().equals(Reason.SAVE)){
620

    
621
                Registration registration = null;
622
                boolean doRefreshView = false;
623

    
624
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
625

    
626
                try {
627
                    clearSession();
628
                    getRepo().getSession().clear();
629
                    registrationWorkflowService.addTypeDesignation(typeDesignationUuid, registration);
630
                    nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
631
                } finally {
632
                    clearSession();
633
                    doRefreshView = true;
634
                }
635

    
636
                if(registration == null){
637
                    // no new registration has been created above, so there must be an existing one.
638
                    registration = findRegistrationInContext(event.getPopup());
639
                }
640

    
641
                // Check if the other names used in the context of the name are registered yet.
642
                NameTypeDesignationPopupEditor nameEditor = (NameTypeDesignationPopupEditor)event.getPopup();
643
                Set<TaxonName> namesToCheck = new HashSet<>();
644

    
645
                namesToCheck.add(nameEditor.getTypeNameField().getValue());
646

    
647
                for(TaxonName name : namesToCheck){
648
                    if(name != null){
649
                        doRefreshView |= registrationWorkflowService.addBlockingRegistration(name.getUuid(), registration) != null;
650
                    }
651

    
652
                }
653

    
654
                refreshView(doRefreshView);
655

    
656
            } else if(event.getReason().equals(Reason.CANCEL)){
657
                // noting to do
658
            }
659

    
660
        }
661
        // ignore other editors
662
    }
663

    
664
    /**
665
     *
666
     */
667
    public void clearSession() {
668
        getRepo().clearSession();
669
    }
670

    
671

    
672
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
673
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
674

    
675
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
676
            List<String> messages = new ArrayList<>();
677
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
678
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
679
            }
680
            getView().openDetailsPopup("Validation Problems", messages);
681
        }
682
    }
683

    
684
    @EventBusListenerMethod
685
    public void onEntityChangeEvent(EntityChangeEvent event){
686

    
687
        if(workingset == null){
688
            return;
689
        }
690
        if(Reference.class.isAssignableFrom(event.getEntityType())){
691

    
692
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
693
                if(event.isRemovedType()){
694
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
695
                } else {
696
                    refreshView(true);
697
                }
698
            }
699

    
700
        } else
701
        if(Registration.class.isAssignableFrom(event.getEntityType())){
702
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
703
                refreshView(true);
704
            }
705
        } else
706
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
707
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
708
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
709
                EditorActionContext rootContext = context.get(0);
710
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
711
                    try {
712
                        clearSession();
713
                        // create a blocking registration, the new Registration will be persisted
714
                        UUID taxonNameUUID = event.getEntityUuid();
715

    
716
                        if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
717
                            // Oha!! The event came from a popup editor and the
718
                            // first popup in the context is a TaxonNameEditor with un-persisted name
719
                            // This is a name for a new registration which has not yet been created.
720
                            // It is necessary to store blocking registrations in the newNameBlockingRegistrations
721
                            Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
722
                            newNameBlockingRegistrations.add(blockingRegistration);
723
                            logger.debug("Blocking registration created and memorized");
724
                        } else {
725
                            Registration registration = findRegistrationInContext(context);
726
                            // some new name somehow related to an existing registration
727
                            registrationWorkflowService.addBlockingRegistration(taxonNameUUID, registration);
728
                        }
729
                    } finally {
730
                        clearSession();
731
                    }
732

    
733
                } else {
734
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
735
                    // this is set
736
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
737
                }
738
            }
739
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
740
                reg.getTypifiedNameRef() != null
741
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
742
                    refreshView(true);
743
            }
744
        } else
745
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
746
            if(workingset.getRegistrationDTOs().stream().anyMatch(
747
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
748
                            td -> td.getUuid() == event.getEntityUuid()
749
                            )
750
                        )
751
                    ){
752
                refreshView(true);
753
            }
754
        }
755
    }
756

    
757
    public Registration findRegistrationInContext(PopupView popupView) {
758
        Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
759
        return findRegistrationInContext(context);
760
    }
761
    /**
762
     * Finds the Registration in the EditorContext stack
763
     *
764
     * @param context
765
     * @return
766
     */
767
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
768
        EditorActionContext rootCtx = context.get(0);
769
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
770
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
771
        if(!registrationDTOOptional.isPresent()){
772
            logger.error("RegistrationDTO missing in rootCtx.");
773
        }
774
        Registration registration = registrationDTOOptional.get().registration();
775

    
776
        // registration = reloadRegistration(registration);
777
        return registration;
778
    }
779

    
780

    
781

    
782
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
783
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
784

    
785
        // FIXME check from own view!!!
786
        if(getView() == null){
787
            return;
788
        }
789

    
790
        UUID registrationUuid = event.getIdentifier();
791

    
792
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
793
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
794

    
795
            Set<RegistrationDTO> blockingRegs;
796
            if(regDto.registration().isPersited()){
797
                blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
798
            } else {
799
                blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
800
            }
801
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
802
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
803
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
804
        }
805
    }
806

    
807
    /**
808
     * {@inheritDoc}
809
     */
810
    @Override
811
    public ICdmEntityUuidCacher getCache() {
812
        return cache;
813
    }
814

    
815
    /**
816
     * {@inheritDoc}
817
     */
818
    @Override
819
    public void addRootEntity(CdmBase entity) {
820
        rootEntities.add(entity);
821
        cache.load(entity);
822
    }
823

    
824

    
825
    /**
826
     * {@inheritDoc}
827
     */
828
    @Override
829
    public Collection<CdmBase> getRootEntities() {
830
        return rootEntities;
831
    }
832

    
833
    @Override
834
    public void destroy() throws Exception {
835
        super.destroy();
836
        disposeCache();
837
    }
838

    
839
    /**
840
     * {@inheritDoc}
841
     */
842
    @Override
843
    public void disposeCache() {
844
        cache.dispose();
845
    }
846

    
847
    /**
848
     * @param name
849
     * @return
850
     */
851
    public boolean canCreateNameRegistrationFor(TaxonName name) {
852
        return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
853
    }
854

    
855
    /**
856
     * @param name
857
     * @return
858
     */
859
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
860
        return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
861
    }
862

    
863
}
(10-10/18)