Project

General

Profile

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

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

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

    
30
import com.vaadin.server.SystemError;
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.Button;
35
import com.vaadin.ui.Label;
36
import com.vaadin.ui.UI;
37
import com.vaadin.ui.VerticalLayout;
38
import com.vaadin.ui.Window;
39

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

    
106
/**
107
 * @author a.kohlbecker
108
 * @since Mar 3, 2017
109
 *
110
 */
111
@SpringComponent
112
@ViewScope
113
public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> implements CachingPresenter {
114

    
115
    private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
116

    
117
    private static final long serialVersionUID = 1L;
118

    
119
    @Autowired
120
    private IRegistrationWorkingSetService regWorkingSetService;
121

    
122
    @Autowired
123
    private IRegistrationMessageService messageService;
124

    
125
    @Autowired
126
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
127

    
128

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

    
136
    private RegistrationWorkingSet workingset;
137

    
138
    /**
139
     * Contains the poupeditor which has neen opend to start the registration of a new name as long as it has not been saved or canceled.
140
     * There can always only be one popup editor for this purpose.
141
     */
142
    private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
143

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

    
149
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
150

    
151

    
152
    private ICdmEntityUuidCacher cache;
153

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

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

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

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

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

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

    
209
    /**
210
     * @param doReload TODO
211
     *
212
     */
213
    protected void refreshView(boolean doReload) {
214
        if(workingset == null){
215
            return; // nothing to do
216
        }
217
        if(doReload){
218
            loadWorkingSet(workingset.getCitationUuid());
219
        }
220
        applyWorkingset();
221
    }
222

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

    
233
            private static final long serialVersionUID = 7099181280977511048L;
234

    
235
            @Override
236
            public AbstractField<Object> create(RegistrationDTO regDto) {
237

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

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

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

    
264

    
265
        });
266
        loadWorkingSet(getView().getCitationUuid());
267
        applyWorkingset();
268

    
269
    }
270

    
271
    private void applyWorkingset(){
272
         getView().setWorkingset(workingset);
273
        // PagingProviders and CacheGenerator for the existingNameCombobox
274
        activateComboboxes();
275
        // update the messages
276
        // updateMessages(); // disabled see  #7908
277
    }
278

    
279
    protected void activateComboboxes() {
280
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
281
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
282
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
283
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
284
    }
285

    
286
    protected void updateMessages() {
287
        User user = UserHelperAccess.userHelper().user();
288
        for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
289
            Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
290

    
291
            RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
292
            try {
293
                int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
294

    
295
                boolean activeMessages = messageCount > 0;
296
                boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
297
                boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RoleProber(RolesAndPermissions.ROLE_CURATION));
298
                messageButton.setEnabled(false);
299
                if(currentUserIsCurator){
300
                    if(currentUserIsSubmitter){
301
                        messageButton.setDescription("No point sending messages to your self.");
302
                    } else {
303
                        messageButton.setEnabled(true);
304
                        messageButton.setDescription("Open the messages dialog.");
305
                    }
306
                } else {
307
                    messageButton.setDescription("Sorry, only a curator can start a conversation.");
308
                }
309
                if(activeMessages){
310
                    messageButton.setEnabled(true);
311
                    messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
312
                    String who = currentUserIsSubmitter ? "curator" : "submitter";
313
                    messageButton.setDescription("The " + who + " is looking forward to your reply.");
314

    
315
                }
316
            } catch (ExternalServiceException e) {
317
                messageButton.setComponentError(new SystemError(e.getMessage(), e));
318
            }
319
        }
320
    }
321

    
322

    
323
    /**
324
     * @param referenceID
325
     */
326
    protected void loadWorkingSet(UUID referenceUuid) {
327

    
328
        try {
329
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
330
        } catch (RegistrationValidationException error) {
331
            logger.error(error);
332
            Window errorDialog = new Window("Validation Error");
333
            errorDialog.setModal(true);
334
            VerticalLayout subContent = new VerticalLayout();
335
            subContent.setMargin(true);
336
            errorDialog.setContent(subContent);
337
            subContent.addComponent(new Label(error.getMessage()));
338
            UI.getCurrent().addWindow(errorDialog);
339
        }
340
        if(workingset == null || workingset.getCitationUuid() == null){
341
            Reference citation = getRepo().getReferenceService().find(referenceUuid);
342
            workingset = new RegistrationWorkingSet(citation);
343
        }
344
        cache = new CdmTransientEntityAndUuidCacher(this);
345
        for(Registration registration : workingset.getRegistrations()) {
346
            addRootEntity(registration);
347
        }
348
    }
349

    
350
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
351
        Registration reg = getRepo().getRegistrationService().load(uuid);
352
        if(reg == null){
353
            // registration was not yet persisted, ignore
354
            return;
355
        }
356
        if(value != null && value instanceof RegistrationStatus){
357
            if(!Objects.equals(value, reg.getStatus())){
358
                reg.setStatus((RegistrationStatus)value);
359
                getRegistrationStore().saveBean(reg, (AbstractView)getView());
360
                refreshView(true);
361
            }
362
        } else {
363
            // only log here as error
364
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
365
        }
366
    }
367

    
368

    
369
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
370
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
371

    
372
        if(!checkFromOwnView(event)){
373
            return;
374
        }
375

    
376
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
377
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
378
        popup.loadInEditor(null);
379
    }
380

    
381
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
382
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
383

    
384
        if(!checkFromOwnView(event)){
385
            return;
386
        }
387
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
388
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
389
        popup.withDeleteButton(true);
390
        popup.loadInEditor(event.getEntityUuid());
391
    }
392

    
393
    @EventBusListenerMethod
394
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
395
        if(event.getPopup() instanceof ReferencePopupEditor){
396
            if(event.getReason().equals(Reason.SAVE)){
397
                refreshView(true);
398
            }
399
        }
400
    }
401

    
402
    @EventBusListenerMethod
403
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
404
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
405
            if(event.getReason().equals(Reason.SAVE)){
406
                refreshView(true);
407
            }
408
        }
409
    }
410

    
411
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
412
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
413

    
414
        if(!checkFromOwnView(event)){
415
            return;
416
        }
417

    
418
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
419
        popup.loadInEditor(event.getEntityUuid());
420
    }
421

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

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

    
429
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
430
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
431
        popup.withDeleteButton(true);
432
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
433
        popup.loadInEditor(event.getEntityUuid());
434
        if(event.hasSource() && event.getSource().isReadOnly()){
435
            // avoid resetting readonly to false
436
            popup.setReadOnly(true);
437
        }
438

    
439
    }
440

    
441

    
442
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
443
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
444

    
445
        if(!checkFromOwnView(event)){
446
            return;
447
        }
448

    
449
        getView().getAddNewNameRegistrationButton().setEnabled(false);
450
        if(newNameForRegistrationPopupEditor == null){
451
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
452
            newNameForRegistrationPopupEditor = popup;
453
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
454
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
455
            popup.withDeleteButton(true);
456
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
457

    
458
                @Override
459
                public TaxonName createNewBean() {
460
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
461
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
462
                    return newTaxonName;
463
                }
464
            });
465
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
466
            popup.loadInEditor(null);
467
        }
468
    }
469

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

    
523

    
524
    /**
525
     * Creates a new Registration for an exiting (previously published) name.
526
     *
527
     * @param event
528
     * @throws RegistrationValidationException
529
     */
530
    @EventBusListenerMethod
531
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
532

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

    
537
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
538
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
539
        if(typifiedName != null){
540
            boolean doReloadWorkingSet = false;
541
            Reference citation = getRepo().getReferenceService().find(workingset.getCitationUuid());
542
            // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
543
            // to create a typification only registration in the working (publication) set which contains
544
            // the protologe. This is known from the nomenclatural reference.
545
            if(canCreateNameRegistrationFor(typifiedName)){
546
                // the citation which is the base for workingset contains the protologe of the name and the name has not
547
                // been registered before:
548
                // create a registration for the name and the first typifications
549
                Registration newRegistrationWithExistingName = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
550
                workingset.add(new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation));
551
                doReloadWorkingSet = true;
552
            } else {
553
                if(!checkWokingsetContainsProtologe(typifiedName)){
554
                    // create a typification only registration
555
                    Registration typificationOnlyRegistration = getRepo().getRegistrationService().newRegistration();
556
                    if(!getRepo().getRegistrationService().checkRegistrationExistsFor(typifiedName)){
557
                        // oops, yet no registration for this name, so we create it as blocking registration:
558
                        Registration blockingNameRegistration = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
559
                        typificationOnlyRegistration.getBlockedBy().add(blockingNameRegistration);
560
                    }
561
                    RegistrationDTO regDTO = new RegistrationDTO(typificationOnlyRegistration, typifiedName, citation);
562
                    workingset.add(regDTO);
563
                }
564
            }
565
            // tell the view to update the workingset
566
            refreshView(doReloadWorkingSet);
567
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
568
        } else {
569
            logger.error("Seletced name is NULL");
570
        }
571

    
572
    }
573

    
574

    
575
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
576
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
577

    
578
        if(!checkFromOwnView(event)){
579
            return;
580
        }
581

    
582
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
583
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
584
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
585
            popup.withDeleteButton(true);
586
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
587
            if(event.hasSource()){
588
                // propagate readonly state from source button to popup
589
                popup.setReadOnly(event.getSource().isReadOnly());
590
            }
591
        } else {
592
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
593
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
594
            popup.withDeleteButton(true);
595
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
596

    
597
            popup.getCitationCombobox().setEnabled(false);
598
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
599

    
600
            if(event.hasSource()){
601
                // propagate readonly state from source button to popup
602
                popup.setReadOnly(event.getSource().isReadOnly());
603
            }
604
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
605
        }
606
    }
607

    
608
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
609
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
610

    
611
        if(!event.hasSource()){
612
            return;
613
        }
614

    
615
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
616
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
617
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
618
            TypeDesignationWorkingsetEditorIdSet identifierSet;
619
            UUID typifiedNameUuid;
620

    
621
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
622
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
623
            if(typifiedNameRef != null){
624
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
625
                typifiedNameUuid = typifiedNameRef.getUuid();
626
            } else {
627
                // case of registrations with a name in the nomenclatural act.
628
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
629
            }
630

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

    
653
                @Override
654
                public NameTypeDesignation createNewBean() {
655

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

    
673
    /**
674
     * Performs final actions after a TypeDesignationEditor which has been
675
     * opened to add a TypeDesignation to a Registration object which was
676
     * created for an previously published name. Prior adding a typedesignation,
677
     * the according Registration object is dangling, that has no association to
678
     * any entity denoting an nomenclatural act which has a reference to a
679
     * publication. This means that the registration object is not in the
680
     * working set.
681
     *
682
     *
683
     * @param event
684
     * @throws RegistrationValidationException
685
     */
686
    @EventBusListenerMethod
687
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
688
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
689
            if(event.getReason().equals(Reason.SAVE)){
690
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
691
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
692
                refreshView(true);
693
            } else if(event.getReason().equals(Reason.CANCEL)){
694
                // noting to do
695
            }
696
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
697
            if(event.getReason().equals(Reason.SAVE)){
698
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
699
                getRepo().getSession().clear();
700
                UUID regUUID = nameTypeDesignationPopupEditorRegistrationUUIDMap.get(event.getPopup());
701
                getRepo().getRegistrationService().addTypeDesignation(regUUID, typeDesignationUuid);
702
                getRepo().getSession().clear();
703
                nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
704
                refreshView(true);
705
            } else if(event.getReason().equals(Reason.CANCEL)){
706
                // noting to do
707
            }
708

    
709
        }
710
        // ignore other editors
711
    }
712

    
713

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

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

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

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

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

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

    
754
                    try {
755
                        getRepo().getSession().clear();
756
                        TransactionStatus txStatus = getRepo().startTransaction();
757
                        // create a blocking registration, the new Registration will be persisted
758
                        UUID taxonNameUUID = event.getEntityUuid();
759
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
760

    
761
                        if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
762
                            // Oha!! The event came from a popup editor and the
763
                            // first popup in the context is a TaxonNameEditor with un-persisted name
764
                            // This is a name for a new registration which has not yet been created.
765
                            // It is necessary to store blocking registrations in the newNameBlockingRegistrations
766
                            newNameBlockingRegistrations.add(blockingRegistration);
767
                            logger.debug("Blocking registration created and memorized");
768
                        } else {
769
                            // some new name related somehow to an existing registration
770
                            TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
771
                            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
772
                            Registration registration = registrationDTO.registration();
773

    
774
                                registration = getRepo().getRegistrationService().load(registration.getUuid());
775
                                if(registration == null){
776
                                    throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
777
                                }
778
                                registration.getBlockedBy().add(blockingRegistration);
779
                                getRepo().getRegistrationService().saveOrUpdate(registration);
780
                                getRepo().commitTransaction(txStatus);
781
                            logger.debug("Blocking registration created and added to registion");
782
                        }
783
                    } finally {
784
                        getRepo().getSession().clear();
785
                    }
786
                } else {
787
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
788
                    // this is set
789
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
790
                }
791
            }
792
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
793
                reg.getTypifiedNameRef() != null
794
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
795
                    refreshView(true);
796
            }
797
        } else
798
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
799
            if(workingset.getRegistrationDTOs().stream().anyMatch(
800
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
801
                            td -> td.getUuid() == event.getEntityUuid()
802
                            )
803
                        )
804
                    ){
805
                refreshView(true);
806
            }
807
        }
808
    }
809

    
810
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
811
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
812

    
813
        // FIXME check from own view!!!
814
        if(getView() == null){
815
            return;
816
        }
817

    
818
        UUID registrationUuid = event.getIdentifier();
819

    
820
        RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
821
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
822

    
823
            Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
824
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
825
        } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
826

    
827
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
828
            popup.loadMessagesFor(regDto.getUuid());
829

    
830
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
831
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
832
        }
833
    }
834

    
835
    /**
836
     * {@inheritDoc}
837
     */
838
    @Override
839
    public ICdmEntityUuidCacher getCache() {
840
        return cache;
841
    }
842

    
843
    /**
844
     * {@inheritDoc}
845
     */
846
    @Override
847
    public void addRootEntity(CdmBase entity) {
848
        rootEntities.add(entity);
849
        cache.load(entity);
850
    }
851

    
852

    
853
    /**
854
     * {@inheritDoc}
855
     */
856
    @Override
857
    public Collection<CdmBase> getRootEntities() {
858
        return rootEntities;
859
    }
860

    
861
    @Override
862
    public void destroy() throws Exception {
863
        super.destroy();
864
        disposeCache();
865
    }
866

    
867
    /**
868
     * {@inheritDoc}
869
     */
870
    @Override
871
    public void disposeCache() {
872
        cache.dispose();
873
    }
874

    
875
}
(13-13/21)