Project

General

Profile

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

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.EnumSet;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Objects;
20
import java.util.Optional;
21
import java.util.Set;
22
import java.util.Stack;
23
import java.util.UUID;
24

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

    
31
import com.vaadin.spring.annotation.SpringComponent;
32
import com.vaadin.spring.annotation.ViewScope;
33
import com.vaadin.ui.AbstractField;
34
import com.vaadin.ui.Label;
35
import com.vaadin.ui.UI;
36
import com.vaadin.ui.VerticalLayout;
37
import com.vaadin.ui.Window;
38

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

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

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

    
112
    private static final long serialVersionUID = 1L;
113

    
114
    @Autowired
115
    private IRegistrationWorkingSetService regWorkingSetService;
116

    
117
    @Autowired
118
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
119

    
120
    @Autowired
121
    private CdmBeanItemContainerFactory selectFieldFactory;
122

    
123

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

    
131
    private RegistrationWorkingSet workingset;
132

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

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

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

    
150

    
151
    private ICdmEntityUuidCacher cache;
152

    
153
    private Collection<CdmBase> rootEntities = new HashSet<>();
154

    
155
    /**
156
     *
157
     */
158
    public RegistrationWorkingsetPresenter() {
159
    }
160

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

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

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

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

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

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

    
249
            private static final long serialVersionUID = 7099181280977511048L;
250

    
251
            @Override
252
            public AbstractField<Object> create(RegistrationDTO regDto) {
253

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

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

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

    
279

    
280
        });
281
        loadWorkingSet(getView().getCitationUuid());
282
        applyWorkingset();
283

    
284
    }
285

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

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

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

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

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

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

    
351

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

    
355
        if(!checkFromOwnView(event)){
356
            return;
357
        }
358

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

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

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

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

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

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

    
397
        if(!checkFromOwnView(event)){
398
            return;
399
        }
400

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

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

    
408
        if(!checkFromOwnView(event)){
409
            return;
410
        }
411

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

    
422
    }
423

    
424

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

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

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

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

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

    
508

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

    
518
        if(!event.isStart()){
519
            return;
520
        }
521

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

    
565
    }
566

    
567

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

    
571
        if(!checkFromOwnView(event)){
572
            return;
573
        }
574

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

    
590
            popup.getCitationCombobox().setEnabled(false);
591
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
592

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

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

    
604
        if(!event.hasSource()){
605
            return;
606
        }
607

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

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

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

    
646
                @Override
647
                public NameTypeDesignation createNewBean() {
648

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

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

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

    
713
        }
714
        // ignore other editors
715
    }
716

    
717
    /**
718
     *
719
     */
720
    public void clearSession() {
721
        getRepo().clearSession();
722
    }
723

    
724

    
725
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
726
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
727

    
728
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
729
            List<String> messages = new ArrayList<>();
730
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
731
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
732
            }
733
            getView().openDetailsPopup("Validation Problems", messages);
734
        }
735
    }
736

    
737
    @EventBusListenerMethod
738
    public void onEntityChangeEvent(EntityChangeEvent event){
739

    
740
        if(workingset == null){
741
            return;
742
        }
743
        if(Reference.class.isAssignableFrom(event.getEntityType())){
744

    
745
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
746
                if(event.isRemovedType()){
747
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
748
                } else {
749
                    refreshView(true);
750
                }
751
            }
752

    
753
        } else
754
        if(Registration.class.isAssignableFrom(event.getEntityType())){
755
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
756
                refreshView(true);
757
            }
758
        } else
759
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
760
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
761
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
762
                EditorActionContext rootContext = context.get(0);
763
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
764

    
765
                    try {
766
                        clearSession();
767
                        // TODO move into a service class --------------
768
                        TransactionStatus txStatus = getRepo().startTransaction();
769
                        // create a blocking registration, the new Registration will be persisted
770
                        UUID taxonNameUUID = event.getEntityUuid();
771
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
772

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

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

    
819
    /**
820
     * @param context
821
     * @return
822
     */
823
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
824
        EditorActionContext rootCtx = context.get(0);
825
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
826
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
827
        if(!registrationDTOOptional.isPresent()){
828
            logger.error("RegistrationDTO missing in rootCtx.");
829
        }
830
        Registration registration = registrationDTOOptional.get().registration();
831

    
832
        if(registration.isPersited()){
833
             registration = getRepo().getRegistrationService().load(registration.getUuid());
834
             if(registration == null){
835
                 throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
836
             }
837
         } else {
838
             logger.trace("Registration is not yet persisted.");
839
         }
840
        return registration;
841
    }
842

    
843
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
844
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
845

    
846
        // FIXME check from own view!!!
847
        if(getView() == null){
848
            return;
849
        }
850

    
851
        UUID registrationUuid = event.getIdentifier();
852

    
853
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
854
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
855

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

    
868
    /**
869
     * {@inheritDoc}
870
     */
871
    @Override
872
    public ICdmEntityUuidCacher getCache() {
873
        return cache;
874
    }
875

    
876
    /**
877
     * {@inheritDoc}
878
     */
879
    @Override
880
    public void addRootEntity(CdmBase entity) {
881
        rootEntities.add(entity);
882
        cache.load(entity);
883
    }
884

    
885

    
886
    /**
887
     * {@inheritDoc}
888
     */
889
    @Override
890
    public Collection<CdmBase> getRootEntities() {
891
        return rootEntities;
892
    }
893

    
894
    @Override
895
    public void destroy() throws Exception {
896
        super.destroy();
897
        disposeCache();
898
    }
899

    
900
    /**
901
     * {@inheritDoc}
902
     */
903
    @Override
904
    public void disposeCache() {
905
        cache.dispose();
906
    }
907

    
908
}
(10-10/18)