Project

General

Profile

Download (42.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.database.PermissionDeniedException;
52
import eu.etaxonomy.cdm.ext.common.ExternalServiceException;
53
import eu.etaxonomy.cdm.ext.registration.messages.IRegistrationMessageService;
54
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
55
import eu.etaxonomy.cdm.model.common.CdmBase;
56
import eu.etaxonomy.cdm.model.common.User;
57
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
58
import eu.etaxonomy.cdm.model.name.Rank;
59
import eu.etaxonomy.cdm.model.name.Registration;
60
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
61
import eu.etaxonomy.cdm.model.name.TaxonName;
62
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
63
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
64
import eu.etaxonomy.cdm.model.reference.Reference;
65
import eu.etaxonomy.cdm.model.reference.ReferenceType;
66
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
67
import eu.etaxonomy.cdm.ref.EntityReference;
68
import eu.etaxonomy.cdm.ref.TypedEntityReference;
69
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
70
import eu.etaxonomy.cdm.service.CdmFilterablePagingProviderFactory;
71
import eu.etaxonomy.cdm.service.CdmStore;
72
import eu.etaxonomy.cdm.service.UserHelperAccess;
73
import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
74
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
75
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
76
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
77
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
78
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
79
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
80
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
81
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
82
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
83
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
84
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
85
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
86
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
87
import eu.etaxonomy.cdm.vaadin.permission.AccessRestrictedView;
88
import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
89
import eu.etaxonomy.cdm.vaadin.theme.EditValoTheme;
90
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
91
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
92
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
93
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
94
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
95
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
96
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNameEditorPresenter;
97
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
98
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
99
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
100
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
101
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
102
import eu.etaxonomy.vaadin.mvp.AbstractView;
103
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
104
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
105
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
106
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
107

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

    
117
    private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
118

    
119
    private static final long serialVersionUID = 1L;
120

    
121
    @Autowired
122
    private IRegistrationWorkingSetService regWorkingSetService;
123

    
124
    @Autowired
125
    private IRegistrationMessageService messageService;
126

    
127
    @Autowired
128
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
129

    
130

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

    
138
    private RegistrationWorkingSet workingset;
139

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

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

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

    
157

    
158
    private ICdmEntityUuidCacher cache;
159

    
160
    private Collection<CdmBase> rootEntities = new HashSet<>();
161

    
162
    /**
163
     *
164
     */
165
    public RegistrationWorkingsetPresenter() {
166
    }
167

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

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

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

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

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

    
246
    /**
247
     * {@inheritDoc}
248
     */
249
    @Override
250
    public void handleViewEntered() {
251
        super.handleViewEntered();
252
        // TODO currently cannot specify type more precisely, see AbstractSelect
253
        // FIXME externalize into class file!!!!!!!!!!!!
254
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
255

    
256
            private static final long serialVersionUID = 7099181280977511048L;
257

    
258
            @Override
259
            public AbstractField<Object> create(RegistrationDTO regDto) {
260

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

    
266
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
267
                availableStatus.add(regDto.getStatus());
268
                if(canChangeStatus){
269
                    if(userHelper.userIsAdmin()){
270
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
271
                    } else {
272
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
273
                    }
274
                }
275

    
276
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
277
                        RegistrationStatus.class,
278
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
279
                        );
280
                select.setValue(regDto.getStatus());
281
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
282
                select.setEnabled(canChangeStatus);
283
                select.setNullSelectionAllowed(false);
284
                return select;
285
            }
286

    
287

    
288
        });
289
        loadWorkingSet(getView().getCitationUuid());
290
        applyWorkingset();
291

    
292
    }
293

    
294
    private void applyWorkingset(){
295
         getView().setWorkingset(workingset);
296
        // PagingProviders and CacheGenerator for the existingNameCombobox
297
        activateComboboxes();
298
        // update the messages
299
        // updateMessages(); // disabled see  #7908
300
    }
301

    
302
    protected void activateComboboxes() {
303
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
304
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
305
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
306
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
307
    }
308

    
309
    protected void updateMessages() {
310
        User user = UserHelperAccess.userHelper().user();
311
        for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
312
            Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
313

    
314
            RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
315
            try {
316
                int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
317

    
318
                boolean activeMessages = messageCount > 0;
319
                boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
320
                boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RoleProber(RolesAndPermissions.ROLE_CURATION));
321
                messageButton.setEnabled(false);
322
                if(currentUserIsCurator){
323
                    if(currentUserIsSubmitter){
324
                        messageButton.setDescription("No point sending messages to your self.");
325
                    } else {
326
                        messageButton.setEnabled(true);
327
                        messageButton.setDescription("Open the messages dialog.");
328
                    }
329
                } else {
330
                    messageButton.setDescription("Sorry, only a curator can start a conversation.");
331
                }
332
                if(activeMessages){
333
                    messageButton.setEnabled(true);
334
                    messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
335
                    String who = currentUserIsSubmitter ? "curator" : "submitter";
336
                    messageButton.setDescription("The " + who + " is looking forward to your reply.");
337

    
338
                }
339
            } catch (ExternalServiceException e) {
340
                messageButton.setComponentError(new SystemError(e.getMessage(), e));
341
            }
342
        }
343
    }
344

    
345

    
346
    /**
347
     * @param referenceID
348
     */
349
    protected void loadWorkingSet(UUID referenceUuid) {
350

    
351
        try {
352
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
353
        } catch (RegistrationValidationException error) {
354
            logger.error(error);
355
            showErrorDialog("Validation Error", error.getMessage());
356
        } catch(PermissionDeniedException e){
357
            logger.info(e);
358
            ((AccessRestrictedView)getView()).setAccessDeniedMessage(e.getMessage());
359
        }
360
        cache = new CdmTransientEntityAndUuidCacher(this);
361
        for(Registration registration : workingset.getRegistrations()) {
362
            addRootEntity(registration);
363
        }
364
    }
365

    
366
    /**
367
     * @param errorDialogCaption
368
     * @param errorMessage
369
     */
370
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
371
        Window errorDialog = new Window(errorDialogCaption);
372
        errorDialog.setModal(true);
373
        VerticalLayout subContent = new VerticalLayout();
374
        subContent.setMargin(true);
375
        errorDialog.setContent(subContent);
376
        subContent.addComponent(new Label(errorMessage));
377
        UI.getCurrent().addWindow(errorDialog);
378
    }
379

    
380
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
381
        Registration reg = getRepo().getRegistrationService().load(uuid);
382
        if(reg == null){
383
            // registration was not yet persisted, ignore
384
            return;
385
        }
386
        if(value != null && value instanceof RegistrationStatus){
387
            if(!Objects.equals(value, reg.getStatus())){
388
                reg.updateStatusAndDate((RegistrationStatus)value);
389
                getRegistrationStore().saveBean(reg, (AbstractView)getView());
390
                refreshView(true);
391
            }
392
        } else {
393
            // only log here as error
394
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
395
        }
396
    }
397

    
398

    
399
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
400
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
401

    
402
        if(!checkFromOwnView(event)){
403
            return;
404
        }
405

    
406
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
407
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
408
        popup.loadInEditor(null);
409
    }
410

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

    
414
        if(!checkFromOwnView(event)){
415
            return;
416
        }
417
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
418
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
419
        popup.withDeleteButton(true);
420
        popup.loadInEditor(event.getEntityUuid());
421
    }
422

    
423
    @EventBusListenerMethod
424
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
425
        if(event.getPopup() instanceof ReferencePopupEditor){
426
            if(event.getReason().equals(Reason.SAVE)){
427
                refreshView(true);
428
            }
429
        }
430
    }
431

    
432
    @EventBusListenerMethod
433
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
434
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
435
            if(event.getReason().equals(Reason.SAVE)){
436
                refreshView(true);
437
            }
438
        }
439
    }
440

    
441
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
442
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
443

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

    
448
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
449
        popup.loadInEditor(event.getEntityUuid());
450
    }
451

    
452
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
453
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
454

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

    
459
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
460
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
461
        popup.withDeleteButton(true);
462
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
463
        popup.loadInEditor(event.getEntityUuid());
464
        if(event.hasSource() && event.getSource().isReadOnly()){
465
            // avoid resetting readonly to false
466
            popup.setReadOnly(true);
467
        }
468

    
469
    }
470

    
471

    
472
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
473
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
474

    
475
        if(!checkFromOwnView(event)){
476
            return;
477
        }
478

    
479
        getView().getAddNewNameRegistrationButton().setEnabled(false);
480
        if(newNameForRegistrationPopupEditor == null){
481
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
482
            newNameForRegistrationPopupEditor = popup;
483
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
484
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
485
            popup.withDeleteButton(true);
486
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
487

    
488
                @Override
489
                public TaxonName createNewBean() {
490
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
491
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
492
                    return newTaxonName;
493
                }
494
            });
495
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
496
            popup.loadInEditor(null);
497
        }
498
    }
499

    
500
    /**
501
     * Creates a new <code>Registration</code> for a new name that has just been edited
502
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
503
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
504
     * Any blocking registrations which have been created while editing the new name are
505
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
506
     * for the first name has been created. Additional new names are created for example
507
     * when a new name as basionym, replaced synonym, etc to the new name is created.
508
     * <p>
509
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
510
     *
511
     * @param event
512
     * @throws RegistrationValidationException
513
     */
514
    @EventBusListenerMethod
515
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
516
        if(event.getPopup() instanceof TaxonNamePopupEditor){
517
            if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
518
                if(event.getReason().equals(Reason.SAVE)){
519
                    try {
520
                        // TODO move into a service class --------------
521
                        TransactionStatus txStatus = getRepo().startTransaction();
522
                        UUID taxonNameUuid = newNameForRegistrationPopupEditor.getBean().getUuid();
523
                        if(newNameForRegistrationPopupEditor.getBean().cdmEntity().isPersited()){
524
                            getRepo().getSession().refresh(newNameForRegistrationPopupEditor.getBean().cdmEntity());
525
                        }
526
                        Registration reg = getRepo().getRegistrationService().createRegistrationForName(taxonNameUuid);
527
                        if(!newNameBlockingRegistrations.isEmpty()){
528
                            for(Registration blockingReg : newNameBlockingRegistrations){
529
                                blockingReg = getRepo().getRegistrationService().load(blockingReg.getUuid());
530
                                reg.getBlockedBy().add(blockingReg);
531
                            }
532
                            getRepo().getRegistrationService().saveOrUpdate(reg);
533
                            newNameBlockingRegistrations.clear();
534
                        }
535
                        getRepo().commitTransaction(txStatus);
536
                        // --------------------------------------------------
537
                        // reload workingset into current session
538
                        loadWorkingSet(workingset.getCitationUuid());
539
                    } finally {
540
                        getRepo().getSession().clear(); // #7702
541
                        refreshView(true);
542
                        getView().getAddNewNameRegistrationButton().setEnabled(true);
543
                    }
544
                }
545
                // nullify and clear the memory on this popup editor in any case (SAVE, CANCEL, DELETE)
546
                newNameForRegistrationPopupEditor = null;
547
                newNameBlockingRegistrations.clear();
548
                getView().getAddNewNameRegistrationButton().setEnabled(true);
549
            } else {
550
                refreshView(true);
551
            }
552
        }
553
    }
554

    
555

    
556
    /**
557
     * Creates a new Registration for an exiting (previously published) name.
558
     *
559
     * @param event
560
     * @throws RegistrationValidationException
561
     */
562
    @EventBusListenerMethod
563
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
564

    
565
        if(!event.isStart()){
566
            return;
567
        }
568

    
569
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
570
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
571
        if(typifiedName != null){
572
            boolean doReloadWorkingSet = false;
573
            try {
574
                // TODO move into a service class --------------
575
                TransactionStatus txStatus = getRepo().startTransaction(true);
576
                Reference citation = getRepo().getReferenceService().load(workingset.getCitationUuid(), Arrays.asList("authorship.$", "inReference.authorship.$"));
577
                // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
578
                // to create a typification only registration in the working (publication) set which contains
579
                // the protologe. This is known from the nomenclatural reference.
580
                if(canCreateNameRegistrationFor(typifiedName)){
581
                    // the citation which is the base for workingset contains the protologe of the name and the name has not
582
                    // been registered before:
583
                    // create a registration for the name and the first typifications
584
                    Registration newRegistrationWithExistingName = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
585
                    workingset.add(new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation));
586
                    doReloadWorkingSet = true;
587
                } else {
588
                    if(!checkWokingsetContainsProtologe(typifiedName)){
589
                        // create a typification only registration
590
                        Registration typificationOnlyRegistration = getRepo().getRegistrationService().newRegistration();
591
                        if(!getRepo().getRegistrationService().checkRegistrationExistsFor(typifiedName)){
592
                            // oops, yet no registration for this name, so we create it as blocking registration:
593
                            Registration blockingNameRegistration = getRepo().getRegistrationService().createRegistrationForName(typifiedName.getUuid());
594
                            typificationOnlyRegistration.getBlockedBy().add(blockingNameRegistration);
595
                        }
596
                        RegistrationDTO regDTO = new RegistrationDTO(typificationOnlyRegistration, typifiedName, citation);
597
                        workingset.add(regDTO);
598
                    }
599
                }
600
                getRepo().commitTransaction(txStatus);
601
                // --------------------------------------------------
602
                // tell the view to update the workingset
603
            } finally {
604
                getRepo().getSession().clear(); // #7702;
605
                refreshView(doReloadWorkingSet);
606
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
607
            }
608
        } else {
609
            logger.error("Seletced name is NULL");
610
        }
611

    
612
    }
613

    
614

    
615
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
616
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
617

    
618
        if(!checkFromOwnView(event)){
619
            return;
620
        }
621

    
622
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
623
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
624
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
625
            popup.withDeleteButton(true);
626
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
627
            if(event.hasSource()){
628
                // propagate readonly state from source button to popup
629
                popup.setReadOnly(event.getSource().isReadOnly());
630
            }
631
        } else {
632
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
633
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
634
            popup.withDeleteButton(true);
635
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
636

    
637
            popup.getCitationCombobox().setEnabled(false);
638
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
639

    
640
            if(event.hasSource()){
641
                // propagate readonly state from source button to popup
642
                popup.setReadOnly(event.getSource().isReadOnly());
643
            }
644
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
645
        }
646
    }
647

    
648
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
649
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
650

    
651
        if(!event.hasSource()){
652
            return;
653
        }
654

    
655
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
656
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
657
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
658
            TypeDesignationWorkingsetEditorIdSet identifierSet;
659
            UUID typifiedNameUuid;
660

    
661
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
662
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
663
            if(typifiedNameRef != null){
664
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
665
                typifiedNameUuid = typifiedNameRef.getUuid();
666
            } else {
667
                // case of registrations with a name in the nomenclatural act.
668
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
669
            }
670

    
671
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
672
                    event.getRegistrationUuid(),
673
                    getView().getCitationUuid(),
674
                    typifiedNameUuid
675
                    );
676
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
677
            popup.loadInEditor(identifierSet);
678
            popup.withDeleteButton(true);
679
            if(event.hasSource()){
680
                // propagate readonly state from source component to popup
681
                popup.setReadOnly(event.getSource().isReadOnly());
682
            }
683
        } else {
684
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
685
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
686
            popup.withDeleteButton(true);
687
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
688
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
689
            Reference citation = regDto.getCitation();
690
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
691
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
692

    
693
                @Override
694
                public NameTypeDesignation createNewBean() {
695

    
696
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
697
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
698
                    nameTypeDesignation.setCitation(citation);
699
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
700
                    return nameTypeDesignation;
701
                }
702
            });
703
            popup.loadInEditor(null);
704
            popup.getCitationCombobox().setEnabled(false);
705
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
706
            if(event.hasSource()){
707
                // propagate readonly state from source component to popup
708
                popup.setReadOnly(event.getSource().isReadOnly());
709
            }
710
        }
711
    }
712

    
713
    /**
714
     * Performs final actions after a TypeDesignationEditor which has been
715
     * opened to add a TypeDesignation to a Registration object which was
716
     * created for an previously published name. Prior adding a typedesignation,
717
     * the according Registration object is dangling, that has no association to
718
     * any entity denoting an nomenclatural act which has a reference to a
719
     * publication. This means that the registration object is not in the
720
     * working set.
721
     *
722
     *
723
     * @param event
724
     * @throws RegistrationValidationException
725
     */
726
    @EventBusListenerMethod
727
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
728
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
729
            if(event.getReason().equals(Reason.SAVE)){
730
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
731
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
732
                refreshView(true);
733
            } else if(event.getReason().equals(Reason.CANCEL)){
734
                // noting to do
735
            }
736
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
737
            if(event.getReason().equals(Reason.SAVE)){
738
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
739

    
740
                try {
741
                    getRepo().getSession().clear();
742
                    // TODO move into a service class --------------
743
                    TransactionStatus txStatus = getRepo().startTransaction();
744
                    UUID regUUID = nameTypeDesignationPopupEditorRegistrationUUIDMap.get(event.getPopup());
745
                    Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getPopup()).getEditorActionContext();
746
                    Registration registration = findRegistrationInContext(context);
747
                    getRepo().getRegistrationService().addTypeDesignation(registration, typeDesignationUuid);
748
                    getRepo().getRegistrationService().saveOrUpdate(registration);
749
                    nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
750
                    getRepo().commitTransaction(txStatus);
751
                    // TODO move into a service class --------------
752
                } finally {
753
                    getRepo().getSession().clear();
754
                    refreshView(true);
755
                }
756
            } else if(event.getReason().equals(Reason.CANCEL)){
757
                // noting to do
758
            }
759

    
760
        }
761
        // ignore other editors
762
    }
763

    
764

    
765
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
766
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
767

    
768
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
769
            List<String> messages = new ArrayList<>();
770
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
771
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
772
            }
773
            getView().openDetailsPopup("Validation Problems", messages);
774
        }
775
    }
776

    
777
    @EventBusListenerMethod
778
    public void onEntityChangeEvent(EntityChangeEvent event){
779

    
780
        if(workingset == null){
781
            return;
782
        }
783
        if(Reference.class.isAssignableFrom(event.getEntityType())){
784

    
785
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
786
                if(event.isRemovedType()){
787
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
788
                } else {
789
                    refreshView(true);
790
                }
791
            }
792

    
793
        } else
794
        if(Registration.class.isAssignableFrom(event.getEntityType())){
795
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
796
                refreshView(true);
797
            }
798
        } else
799
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
800
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
801
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
802
                EditorActionContext rootContext = context.get(0);
803
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
804

    
805
                    try {
806
                        getRepo().getSession().clear();
807
                        // TODO move into a service class --------------
808
                        TransactionStatus txStatus = getRepo().startTransaction();
809
                        // create a blocking registration, the new Registration will be persisted
810
                        UUID taxonNameUUID = event.getEntityUuid();
811
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
812

    
813
                        if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
814
                            // Oha!! The event came from a popup editor and the
815
                            // first popup in the context is a TaxonNameEditor with un-persisted name
816
                            // This is a name for a new registration which has not yet been created.
817
                            // It is necessary to store blocking registrations in the newNameBlockingRegistrations
818
                            newNameBlockingRegistrations.add(blockingRegistration);
819
                            logger.debug("Blocking registration created and memorized");
820
                        } else {
821
                            // some new name somehow related to an existing registration
822
                            Registration registration = findRegistrationInContext(context);
823
                            registration.getBlockedBy().add(blockingRegistration);
824

    
825
                            if(registration.isPersited()){
826
                                getRepo().getRegistrationService().saveOrUpdate(registration);
827
                                logger.debug("Blocking registration created, added to registion and persited");
828
                            }
829
                            getRepo().commitTransaction(txStatus);
830
                            // TODO move into a service class --------------
831
                        }
832
                    } finally {
833
                        getRepo().getSession().clear();
834
                    }
835
                } else {
836
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
837
                    // this is set
838
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
839
                }
840
            }
841
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
842
                reg.getTypifiedNameRef() != null
843
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
844
                    refreshView(true);
845
            }
846
        } else
847
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
848
            if(workingset.getRegistrationDTOs().stream().anyMatch(
849
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
850
                            td -> td.getUuid() == event.getEntityUuid()
851
                            )
852
                        )
853
                    ){
854
                refreshView(true);
855
            }
856
        }
857
    }
858

    
859
    /**
860
     * @param context
861
     * @return
862
     */
863
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
864
        EditorActionContext rootCtx = context.get(0);
865
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
866
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
867
        Registration registration = registrationDTO.registration();
868

    
869
        if(registration.isPersited()){
870
             registration = getRepo().getRegistrationService().load(registration.getUuid());
871
             if(registration == null){
872
                 throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
873
             }
874
         } else {
875
             logger.trace("Registration is not yet persisted.");
876
         }
877
        return registration;
878
    }
879

    
880
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
881
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
882

    
883
        // FIXME check from own view!!!
884
        if(getView() == null){
885
            return;
886
        }
887

    
888
        UUID registrationUuid = event.getIdentifier();
889

    
890
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
891
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
892

    
893
            Set<RegistrationDTO> blockingRegs;
894
            if(regDto.registration().isPersited()){
895
                blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
896
            } else {
897
                blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
898
            }
899
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
900
        } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
901

    
902
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
903
            popup.loadMessagesFor(regDto.getUuid());
904

    
905
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
906
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
907
        }
908
    }
909

    
910
    /**
911
     * {@inheritDoc}
912
     */
913
    @Override
914
    public ICdmEntityUuidCacher getCache() {
915
        return cache;
916
    }
917

    
918
    /**
919
     * {@inheritDoc}
920
     */
921
    @Override
922
    public void addRootEntity(CdmBase entity) {
923
        rootEntities.add(entity);
924
        cache.load(entity);
925
    }
926

    
927

    
928
    /**
929
     * {@inheritDoc}
930
     */
931
    @Override
932
    public Collection<CdmBase> getRootEntities() {
933
        return rootEntities;
934
    }
935

    
936
    @Override
937
    public void destroy() throws Exception {
938
        super.destroy();
939
        disposeCache();
940
    }
941

    
942
    /**
943
     * {@inheritDoc}
944
     */
945
    @Override
946
    public void disposeCache() {
947
        cache.dispose();
948
    }
949

    
950
}
(13-13/21)