Project

General

Profile

Download (38.8 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.CdmStore;
70
import eu.etaxonomy.cdm.service.UserHelperAccess;
71
import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
72
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
73
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
74
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
75
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
76
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
77
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
78
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
79
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
80
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
81
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
82
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
83
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
84
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
85
import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
86
import eu.etaxonomy.cdm.vaadin.theme.EditValoTheme;
87
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
88
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
89
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
90
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
91
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
92
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
93
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
94
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
95
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
96
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
97
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
98
import eu.etaxonomy.vaadin.mvp.AbstractView;
99
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
100
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
101
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
102
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
103

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

    
113
    private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
114

    
115
    private static final List<String> REGISTRATION_INIT_STRATEGY = Arrays.asList(
116
            "$",
117
            "blockedBy",
118
            "name.combinationAuthorship",
119
            "name.exCombinationAuthorship",
120
            "name.basionymAuthorship",
121
            "name.exBasionymAuthorship"
122
            );
123

    
124
    private static final long serialVersionUID = 1L;
125

    
126
    @Autowired
127
    private IRegistrationWorkingSetService regWorkingSetService;
128

    
129
    @Autowired
130
    private IRegistrationMessageService messageService;
131

    
132
    /**
133
     * @return the regWorkingSetService
134
     */
135
    public IRegistrationWorkingSetService getWorkingSetService() {
136
        return regWorkingSetService;
137
    }
138

    
139
    private RegistrationWorkingSet workingset;
140

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

    
147
    /**
148
     * Contains
149
     */
150
    private List<Registration> newNameBlockingRegistrations = new ArrayList<>();
151

    
152
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
153

    
154

    
155
    private ICdmEntityUuidCacher cache;
156

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

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

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

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

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

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

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

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

    
236
            private static final long serialVersionUID = 7099181280977511048L;
237

    
238
            @Override
239
            public AbstractField<Object> create(RegistrationDTO regDto) {
240

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

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

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

    
266

    
267
        });
268
        loadWorkingSet(getView().getCitationUuid());
269
        applyWorkingset();
270

    
271
    }
272

    
273
    private void applyWorkingset(){
274
         getView().setWorkingset(workingset);
275
        // PagingProviders and CacheGenerator for the existingNameCombobox
276
        activateComboboxes();
277
        // update the messages
278
        updateMessages();
279
    }
280

    
281
    /**
282
     *
283
     */
284
    protected void activateComboboxes() {
285
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
286
                getRepo().getNameService());
287
        pagingProvider.setInitStrategy(Arrays.asList("registrations", "nomenclaturalReference", "nomenclaturalReference.inReference"));
288
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
289
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
290
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
291
    }
292

    
293
    /**
294
     *
295
     */
296
    protected void updateMessages() {
297
        User user = UserHelperAccess.userHelper().user();
298
        for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
299
            Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
300

    
301
            RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
302
            try {
303
                int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
304

    
305
                boolean activeMessages = messageCount > 0;
306
                boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
307
                boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RoleProber(RolesAndPermissions.ROLE_CURATION));
308
                messageButton.setEnabled(false);
309
                if(currentUserIsCurator){
310
                    if(currentUserIsSubmitter){
311
                        messageButton.setDescription("No point sending messages to your self.");
312
                    } else {
313
                        messageButton.setEnabled(true);
314
                        messageButton.setDescription("Open the messages dialog.");
315
                    }
316
                } else {
317
                    messageButton.setDescription("Sorry, only a curator can start a conversation.");
318
                }
319
                if(activeMessages){
320
                    messageButton.setEnabled(true);
321
                    messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
322
                    String who = currentUserIsSubmitter ? "curator" : "submitter";
323
                    messageButton.setDescription("The " + who + " is looking forward to your reply.");
324

    
325
                }
326
            } catch (ExternalServiceException e) {
327
                messageButton.setComponentError(new SystemError(e.getMessage(), e));
328
            }
329
        }
330
    }
331

    
332

    
333
    /**
334
     * @param referenceID
335
     */
336
    protected void loadWorkingSet(UUID referenceUuid) {
337
        try {
338
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
339
        } catch (RegistrationValidationException error) {
340
            logger.error(error);
341
            Window errorDialog = new Window("Validation Error");
342
            errorDialog.setModal(true);
343
            VerticalLayout subContent = new VerticalLayout();
344
            subContent.setMargin(true);
345
            errorDialog.setContent(subContent);
346
            subContent.addComponent(new Label(error.getMessage()));
347
            UI.getCurrent().addWindow(errorDialog);
348
        }
349
        if(workingset == null || workingset.getCitationUuid() == null){
350
            Reference citation = getRepo().getReferenceService().find(referenceUuid);
351
            workingset = new RegistrationWorkingSet(citation);
352
        }
353
        cache = new CdmTransientEntityAndUuidCacher(this);
354
        for(Registration registration : workingset.getRegistrations()) {
355
            addRootEntity(registration);
356
        }
357
    }
358

    
359
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
360
        Registration reg = getRepo().getRegistrationService().load(uuid);
361
        if(reg == null){
362
            // registration was not yet persisted, ignore
363
            return;
364
        }
365
        if(value != null && value instanceof RegistrationStatus){
366
            if(!Objects.equals(value, reg.getStatus())){
367
                reg.setStatus((RegistrationStatus)value);
368
                getRegistrationStore().saveBean(reg, (AbstractView)getView());
369
                refreshView(true);
370
            }
371
        } else {
372
            // only log here as error
373
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
374
        }
375
    }
376

    
377

    
378
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
379
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
380

    
381
        if(!checkFromOwnView(event)){
382
            return;
383
        }
384

    
385
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
386
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
387
        popup.loadInEditor(null);
388
    }
389

    
390
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
391
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
392

    
393
        if(!checkFromOwnView(event)){
394
            return;
395
        }
396
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
397
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
398
        popup.withDeleteButton(true);
399
        popup.loadInEditor(event.getEntityUuid());
400
    }
401

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

    
411
    @EventBusListenerMethod
412
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
413
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
414
            if(event.getReason().equals(Reason.SAVE)){
415
                refreshView(true);
416
            }
417
        }
418
    }
419

    
420
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
421
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
422

    
423
        if(!checkFromOwnView(event)){
424
            return;
425
        }
426

    
427
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
428
        popup.loadInEditor(event.getEntityUuid());
429
    }
430

    
431
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
432
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
433

    
434
        if(!checkFromOwnView(event)){
435
            return;
436
        }
437

    
438
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
439
        popup.setParentEditorActionContext(event.getContext());
440
        popup.withDeleteButton(true);
441
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
442
        popup.loadInEditor(event.getEntityUuid());
443
        if(event.hasSource() && event.getSource().isReadOnly()){
444
            // avoid resetting readonly to false
445
            popup.setReadOnly(true);
446
        }
447

    
448
    }
449

    
450

    
451
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
452
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
453

    
454
        if(!checkFromOwnView(event)){
455
            return;
456
        }
457

    
458
        getView().getAddNewNameRegistrationButton().setEnabled(false);
459
        if(newNameForRegistrationPopupEditor == null){
460
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
461
            newNameForRegistrationPopupEditor = popup;
462
            popup.setParentEditorActionContext(event.getContext());
463
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
464
            popup.withDeleteButton(true);
465
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
466

    
467
                @Override
468
                public TaxonName createNewBean() {
469
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
470
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid()));
471
                    return newTaxonName;
472
                }
473
            });
474
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
475
            popup.loadInEditor(null);
476
        }
477
    }
478

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

    
528
        }
529
    }
530

    
531

    
532
    /**
533
     * Creates a new Registration for an exiting (previously published) name.
534
     *
535
     * @param event
536
     * @throws RegistrationValidationException
537
     */
538
    @EventBusListenerMethod
539
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
540

    
541
        if(!event.isStart()){
542
            return;
543
        }
544

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

    
580
    }
581

    
582

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

    
586
        if(!checkFromOwnView(event)){
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());
593
            popup.withDeleteButton(true);
594
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
595
            if(event.hasSource()){
596
                // propagate readonly state from source button to popup
597
                popup.setReadOnly(event.getSource().isReadOnly());
598
            }
599
        } else {
600
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
601
            popup.setParentEditorActionContext(event.getContext());
602
            popup.withDeleteButton(true);
603
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
604

    
605
            popup.getCitationCombobox().setEnabled(false);
606
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
607

    
608
            if(event.hasSource()){
609
                // propagate readonly state from source button to popup
610
                popup.setReadOnly(event.getSource().isReadOnly());
611
            }
612
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
613
        }
614
    }
615

    
616
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
617
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
618

    
619
        if(!event.hasSource()){
620
            return;
621
        }
622

    
623
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
624
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
625
            popup.setParentEditorActionContext(event.getContext());
626
            TypeDesignationWorkingsetEditorIdSet identifierSet;
627
            UUID typifiedNameUuid;
628

    
629
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
630
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
631
            if(typifiedNameRef != null){
632
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
633
                typifiedNameUuid = typifiedNameRef.getUuid();
634
            } else {
635
                // case of registrations with a name in the nomenclatural act.
636
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
637
            }
638

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

    
661
                @Override
662
                public NameTypeDesignation createNewBean() {
663

    
664
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
665
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
666
                    nameTypeDesignation.setCitation(citation);
667
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
668
                    return nameTypeDesignation;
669
                }
670
            });
671
            popup.loadInEditor(null);
672
            popup.getCitationCombobox().setEnabled(false);
673
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
674
            if(event.hasSource()){
675
                // propagate readonly state from source component to popup
676
                popup.setReadOnly(event.getSource().isReadOnly());
677
            }
678
        }
679
    }
680

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

    
717
        }
718
        // ignore other editors
719
    }
720

    
721

    
722
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
723
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
724

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

    
734
    @EventBusListenerMethod
735
    public void onEntityChangeEvent(EntityChangeEvent event){
736

    
737
        if(workingset == null){
738
            return;
739
        }
740
        if(Reference.class.isAssignableFrom(event.getEntityType())){
741

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

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

    
762
                    // create a blocking registration, the new Registration will be persisted
763
                    UUID taxonNameUUID = event.getEntityUuid();
764
                    Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
765

    
766
                    if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
767
                        // Oha!! The event came from a popup editor and the
768
                        // first popup in the context is a TaxonNameEditor with un-persisted name
769
                        // This is a name for a new registration which has not yet been created.
770
                        // It is necessary to store blocking registrations in the newNameBlockingRegistrations
771
                        newNameBlockingRegistrations.add(blockingRegistration);
772
                        logger.debug("Blocking registration created and memorized");
773
                    } else {
774
                        // some new name related somehow to an existing registration
775
                        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
776
                        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
777
                        Registration registration = registrationDTO.registration();
778
                        if(registration == null){
779
                            throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
780
                        }
781
                        registration.getBlockedBy().add(blockingRegistration);
782
                        getRepo().getRegistrationService().saveOrUpdate(registration);
783
                        logger.debug("Blocking registration created and added to registion");
784
                    }
785
                } else {
786
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
787
                    // this is set
788
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
789
                }
790
            }
791
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
792
                reg.getTypifiedNameRef() != null
793
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
794
                    refreshView(true);
795
            }
796
        } else
797
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
798
            if(workingset.getRegistrationDTOs().stream().anyMatch(
799
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
800
                            td -> td.getUuid() == event.getEntityUuid()
801
                            )
802
                        )
803
                    ){
804
                refreshView(true);
805
            }
806
        }
807
    }
808

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

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

    
817
        UUID registrationUuid = event.getIdentifier();
818

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

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

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

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

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

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

    
851

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

    
860

    
861
    /**
862
     * {@inheritDoc}
863
     */
864
    @Override
865
    public void disposeCache() {
866
        cache.dispose();
867
    }
868

    
869
}
(13-13/20)