Project

General

Profile

Download (39.6 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.config.RegistrationStatusTransitions;
40
import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
41
import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
42
import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
43
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
44
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
45
import eu.etaxonomy.cdm.api.utility.UserHelper;
46
import eu.etaxonomy.cdm.cache.CdmTransientEntityAndUuidCacher;
47
import eu.etaxonomy.cdm.database.PermissionDeniedException;
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.reference.Reference;
58
import eu.etaxonomy.cdm.model.reference.ReferenceType;
59
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
60
import eu.etaxonomy.cdm.ref.EntityReference;
61
import eu.etaxonomy.cdm.ref.TypedEntityReference;
62
import eu.etaxonomy.cdm.service.CdmBeanItemContainerFactory;
63
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
64
import eu.etaxonomy.cdm.service.CdmFilterablePagingProviderFactory;
65
import eu.etaxonomy.cdm.service.CdmStore;
66
import eu.etaxonomy.cdm.service.UserHelperAccess;
67
import eu.etaxonomy.cdm.vaadin.component.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.permission.AccessRestrictedView;
81
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
82
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
83
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
84
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
85
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
86
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
87
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNameEditorPresenter;
88
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
89
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
90
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
91
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
92
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
93
import eu.etaxonomy.vaadin.mvp.AbstractView;
94
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
95
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
96
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
97
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
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 CdmFilterablePagingProviderFactory pagingProviderFactory;
117

    
118
    @Autowired
119
    private CdmBeanItemContainerFactory selectFieldFactory;
120

    
121
    @Autowired
122
    private CdmStore cdmStore;
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
     * Checks
163
     * <ol>
164
     * <li>if there is NOT any registration for this name created in the current registration system</li>
165
     * <li>Checks if the name belongs to the current workingset</li>
166
     * </ol>
167
     * If both checks are successful the method returns <code>true</code>.
168
     */
169
    public boolean canCreateNameRegistrationFor(TaxonName name) {
170
        return !getRepo().getRegistrationService().checkRegistrationExistsFor(name) && checkWokingsetContainsProtologe(name);
171
    }
172

    
173
    /**
174
     * @param name
175
     * @return
176
     */
177
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
178
        Reference nomRef = name.getNomenclaturalReference();
179
        UUID citationUuid = workingset.getCitationUuid();
180
        // @formatter:off
181
        return nomRef != null && (
182
                // nomref matches
183
                nomRef.getUuid().equals(citationUuid) ||
184
                // nomref.inreference matches
185
                (nomRef.getType() != null && nomRef.getType() == ReferenceType.Section && nomRef.getInReference() != null && nomRef.getInReference().getUuid().equals(citationUuid))
186
                );
187
        // @formatter:on
188
    }
189

    
190
    /**
191
     * @param doReload reload the workingset from the persistent storage.
192
     *  Workingsets which are not yet persisted are preserved.
193
     *
194
     */
195
    protected void refreshView(boolean doReload) {
196
        if(workingset == null){
197
            return; // nothing to do
198
        }
199
        if(doReload){
200
            List<RegistrationDTO> unpersisted = new ArrayList<>();
201
            for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
202
                if(!regDto.registration().isPersited()){
203
                    unpersisted.add(regDto);
204
                }
205
            }
206
            loadWorkingSet(workingset.getCitationUuid());
207
            for(RegistrationDTO regDtoUnpersisted : unpersisted){
208
                if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
209
                    // only add if the regDtoUnpersisted has not been persisted meanwhile
210
                    try {
211
                        workingset.add(regDtoUnpersisted);
212
                    } catch (RegistrationValidationException e) {
213
                        // would never happen here //
214
                    }
215
                }
216
            }
217
        }
218
        applyWorkingset();
219
    }
220

    
221
    /**
222
     * {@inheritDoc}
223
     */
224
    @Override
225
    public void handleViewEntered() {
226
        super.handleViewEntered();
227
        // TODO currently cannot specify type more precisely, see AbstractSelect
228
        // FIXME externalize into class file!!!!!!!!!!!!
229
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
230

    
231
            private static final long serialVersionUID = 7099181280977511048L;
232

    
233
            @Override
234
            public AbstractField<Object> create(RegistrationDTO regDto) {
235

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

    
240
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
241
                availableStatus.add(regDto.getStatus());
242
                if(canChangeStatus){
243
                    if(userHelper.userIsAdmin()){
244
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
245
                    } else {
246
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
247
                    }
248
                }
249

    
250
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
251
                        RegistrationStatus.class,
252
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
253
                        );
254
                select.setValue(regDto.getStatus());
255
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
256
                select.setEnabled(canChangeStatus);
257
                select.setNullSelectionAllowed(false);
258
                return select;
259
            }
260

    
261

    
262
        });
263
        loadWorkingSet(getView().getCitationUuid());
264
        applyWorkingset();
265

    
266
    }
267

    
268
    private void applyWorkingset(){
269
         getView().setWorkingset(workingset);
270
        // PagingProviders and CacheGenerator for the existingNameCombobox
271
        activateComboboxes();
272
    }
273

    
274
    protected void activateComboboxes() {
275
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
276
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
277
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
278
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
279
    }
280

    
281
    /**
282
     * @param referenceID
283
     */
284
    protected void loadWorkingSet(UUID referenceUuid) {
285

    
286
        try {
287
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
288
        } catch (RegistrationValidationException error) {
289
            logger.error(error);
290
            showErrorDialog("Validation Error", error.getMessage());
291
        } catch(PermissionDeniedException e){
292
            logger.info(e);
293
            ((AccessRestrictedView)getView()).setAccessDeniedMessage(e.getMessage());
294
        }
295
        cache = new CdmTransientEntityAndUuidCacher(this);
296
        for(Registration registration : workingset.getRegistrations()) {
297
            addRootEntity(registration);
298
        }
299
    }
300

    
301
    /**
302
     * @param errorDialogCaption
303
     * @param errorMessage
304
     */
305
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
306
        Window errorDialog = new Window(errorDialogCaption);
307
        errorDialog.setModal(true);
308
        VerticalLayout subContent = new VerticalLayout();
309
        subContent.setMargin(true);
310
        errorDialog.setContent(subContent);
311
        subContent.addComponent(new Label(errorMessage));
312
        UI.getCurrent().addWindow(errorDialog);
313
    }
314

    
315
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
316
        Registration reg = getRepo().getRegistrationService().load(uuid);
317
        if(reg == null){
318
            // registration was not yet persisted, ignore
319
            return;
320
        }
321
        if(value != null && value instanceof RegistrationStatus){
322
            if(!Objects.equals(value, reg.getStatus())){
323
                reg.updateStatusAndDate((RegistrationStatus)value);
324
                cdmStore.saveBean(reg, (AbstractView)getView());
325
                refreshView(true);
326
            }
327
        } else {
328
            // only log here as error
329
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
330
        }
331
    }
332

    
333

    
334
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
335
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
336

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

    
341
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
342
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
343
        popup.loadInEditor(null);
344
    }
345

    
346
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
347
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
348

    
349
        if(!checkFromOwnView(event)){
350
            return;
351
        }
352
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
353
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
354
        popup.withDeleteButton(true);
355
        popup.loadInEditor(event.getEntityUuid());
356
    }
357

    
358
    @EventBusListenerMethod
359
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
360
        if(event.getPopup() instanceof ReferencePopupEditor){
361
            if(event.getReason().equals(Reason.SAVE)){
362
                refreshView(true);
363
            }
364
        }
365
    }
366

    
367
    @EventBusListenerMethod
368
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
369
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
370
            if(event.getReason().equals(Reason.SAVE)){
371
                refreshView(true);
372
            }
373
        }
374
    }
375

    
376
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
377
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
378

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

    
383
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
384
        popup.loadInEditor(event.getEntityUuid());
385
    }
386

    
387
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
388
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
389

    
390
        if(!checkFromOwnView(event)){
391
            return;
392
        }
393

    
394
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
395
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
396
        popup.withDeleteButton(true);
397
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
398
        popup.loadInEditor(event.getEntityUuid());
399
        if(event.hasSource() && event.getSource().isReadOnly()){
400
            // avoid resetting readonly to false
401
            popup.setReadOnly(true);
402
        }
403

    
404
    }
405

    
406

    
407
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
408
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
409

    
410
        if(!checkFromOwnView(event)){
411
            return;
412
        }
413

    
414
        getView().getAddNewNameRegistrationButton().setEnabled(false);
415
        if(newNameForRegistrationPopupEditor == null){
416
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
417
            newNameForRegistrationPopupEditor = popup;
418
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
419
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
420
            popup.withDeleteButton(true);
421
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
422

    
423
                @Override
424
                public TaxonName createNewBean() {
425
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
426
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
427
                    return newTaxonName;
428
                }
429
            });
430
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
431
            popup.loadInEditor(null);
432
        }
433
    }
434

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

    
490

    
491
    /**
492
     * Creates a new Registration for an exiting (previously published) name.
493
     *
494
     * @param event
495
     * @throws RegistrationValidationException
496
     */
497
    @EventBusListenerMethod
498
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
499

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

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

    
547
    }
548

    
549

    
550
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
551
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
552

    
553
        if(!checkFromOwnView(event)){
554
            return;
555
        }
556

    
557
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
558
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
559
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
560
            popup.withDeleteButton(true);
561
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
562
            if(event.hasSource()){
563
                // propagate readonly state from source button to popup
564
                popup.setReadOnly(event.getSource().isReadOnly());
565
            }
566
        } else {
567
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
568
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
569
            popup.withDeleteButton(true);
570
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
571

    
572
            popup.getCitationCombobox().setEnabled(false);
573
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
574

    
575
            if(event.hasSource()){
576
                // propagate readonly state from source button to popup
577
                popup.setReadOnly(event.getSource().isReadOnly());
578
            }
579
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
580
        }
581
    }
582

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

    
586
        if(!event.hasSource()){
587
            return;
588
        }
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
            TypeDesignationWorkingsetEditorIdSet identifierSet;
594
            UUID typifiedNameUuid;
595

    
596
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
597
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
598
            if(typifiedNameRef != null){
599
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
600
                typifiedNameUuid = typifiedNameRef.getUuid();
601
            } else {
602
                // case of registrations with a name in the nomenclatural act.
603
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
604
            }
605

    
606
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
607
                    event.getRegistrationUuid(),
608
                    getView().getCitationUuid(),
609
                    typifiedNameUuid
610
                    );
611
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
612
            popup.loadInEditor(identifierSet);
613
            popup.withDeleteButton(true);
614
            if(event.hasSource()){
615
                // propagate readonly state from source component to popup
616
                popup.setReadOnly(event.getSource().isReadOnly());
617
            }
618
        } else {
619
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
620
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
621
            popup.withDeleteButton(true);
622
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
623
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
624
            Reference citation = regDto.getCitation();
625
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
626
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
627

    
628
                @Override
629
                public NameTypeDesignation createNewBean() {
630

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

    
648
    /**
649
     * Performs final actions after a TypeDesignationEditor which has been
650
     * opened to add a TypeDesignation to a Registration object which was
651
     * created for an previously published name. Prior adding a typedesignation,
652
     * the according Registration object is dangling, that has no association to
653
     * any entity denoting an nomenclatural act which has a reference to a
654
     * publication. This means that the registration object is not in the
655
     * working set.
656
     *
657
     *
658
     * @param event
659
     * @throws RegistrationValidationException
660
     */
661
    @EventBusListenerMethod
662
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
663
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
664
            if(event.getReason().equals(Reason.SAVE)){
665
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
666
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
667
                refreshView(true);
668
            } else if(event.getReason().equals(Reason.CANCEL)){
669
                // noting to do
670
            }
671
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
672
            if(event.getReason().equals(Reason.SAVE)){
673
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
674

    
675
                try {
676
                    clearSession();
677
                    // TODO move into a service class --------------
678
                    TransactionStatus txStatus = getRepo().startTransaction();
679
                    UUID regUUID = nameTypeDesignationPopupEditorRegistrationUUIDMap.get(event.getPopup());
680
                    Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getPopup()).getEditorActionContext();
681
                    Registration registration = findRegistrationInContext(context);
682
                    getRepo().getRegistrationService().addTypeDesignation(registration, typeDesignationUuid);
683
                    getRepo().getRegistrationService().saveOrUpdate(registration);
684
                    nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
685
                    getRepo().commitTransaction(txStatus);
686
                    // TODO move into a service class --------------
687
                } finally {
688
                    clearSession();
689
                    refreshView(true);
690
                }
691
            } else if(event.getReason().equals(Reason.CANCEL)){
692
                // noting to do
693
            }
694

    
695
        }
696
        // ignore other editors
697
    }
698

    
699
    /**
700
     *
701
     */
702
    public void clearSession() {
703
        getRepo().clearSession();
704
    }
705

    
706

    
707
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
708
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
709

    
710
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
711
            List<String> messages = new ArrayList<>();
712
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
713
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
714
            }
715
            getView().openDetailsPopup("Validation Problems", messages);
716
        }
717
    }
718

    
719
    @EventBusListenerMethod
720
    public void onEntityChangeEvent(EntityChangeEvent event){
721

    
722
        if(workingset == null){
723
            return;
724
        }
725
        if(Reference.class.isAssignableFrom(event.getEntityType())){
726

    
727
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
728
                if(event.isRemovedType()){
729
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
730
                } else {
731
                    refreshView(true);
732
                }
733
            }
734

    
735
        } else
736
        if(Registration.class.isAssignableFrom(event.getEntityType())){
737
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
738
                refreshView(true);
739
            }
740
        } else
741
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
742
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
743
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
744
                EditorActionContext rootContext = context.get(0);
745
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
746

    
747
                    try {
748
                        clearSession();
749
                        // TODO move into a service class --------------
750
                        TransactionStatus txStatus = getRepo().startTransaction();
751
                        // create a blocking registration, the new Registration will be persisted
752
                        UUID taxonNameUUID = event.getEntityUuid();
753
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
754

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

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

    
801
    /**
802
     * @param context
803
     * @return
804
     */
805
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
806
        EditorActionContext rootCtx = context.get(0);
807
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
808
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
809
        if(!registrationDTOOptional.isPresent()){
810
            logger.error("RegistrationDTO missing in rootCtx.");
811
        }
812
        Registration registration = registrationDTOOptional.get().registration();
813

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

    
825
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
826
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
827

    
828
        // FIXME check from own view!!!
829
        if(getView() == null){
830
            return;
831
        }
832

    
833
        UUID registrationUuid = event.getIdentifier();
834

    
835
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
836
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
837

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

    
850
    /**
851
     * {@inheritDoc}
852
     */
853
    @Override
854
    public ICdmEntityUuidCacher getCache() {
855
        return cache;
856
    }
857

    
858
    /**
859
     * {@inheritDoc}
860
     */
861
    @Override
862
    public void addRootEntity(CdmBase entity) {
863
        rootEntities.add(entity);
864
        cache.load(entity);
865
    }
866

    
867

    
868
    /**
869
     * {@inheritDoc}
870
     */
871
    @Override
872
    public Collection<CdmBase> getRootEntities() {
873
        return rootEntities;
874
    }
875

    
876
    @Override
877
    public void destroy() throws Exception {
878
        super.destroy();
879
        disposeCache();
880
    }
881

    
882
    /**
883
     * {@inheritDoc}
884
     */
885
    @Override
886
    public void disposeCache() {
887
        cache.dispose();
888
    }
889

    
890
}
(10-10/18)