Project

General

Profile

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

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.EnumSet;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Objects;
20
import java.util.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
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
152

    
153

    
154
    private ICdmEntityUuidCacher cache;
155

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

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

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

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

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

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

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

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

    
249
            private static final long serialVersionUID = 7099181280977511048L;
250

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

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

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

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

    
280

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

    
285
    }
286

    
287
    private void applyWorkingset(){
288
         getView().setWorkingset(workingset);
289
        // PagingProviders and CacheGenerator for the existingNameCombobox
290
        activateComboboxes();
291
        // update the messages
292
        // updateMessages(); // disabled see  #7908
293
    }
294

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

    
302
    protected void updateMessages() {
303
        User user = UserHelperAccess.userHelper().user();
304
        for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
305
            Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
306

    
307
            RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
308
            try {
309
                int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
310

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

    
331
                }
332
            } catch (ExternalServiceException e) {
333
                messageButton.setComponentError(new SystemError(e.getMessage(), e));
334
            }
335
        }
336
    }
337

    
338

    
339
    /**
340
     * @param referenceID
341
     */
342
    protected void loadWorkingSet(UUID referenceUuid) {
343

    
344
        try {
345
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
346
        } catch (RegistrationValidationException error) {
347
            logger.error(error);
348
            showErrorDialog("Validation Error", error.getMessage());
349
        } catch(PermissionDeniedException e){
350
            logger.info(e);
351
            ((AccessRestrictedView)getView()).setAccessDeniedMessage(e.getMessage());
352
        }
353
        cache = new CdmTransientEntityAndUuidCacher(this);
354
        for(Registration registration : workingset.getRegistrations()) {
355
            addRootEntity(registration);
356
        }
357
    }
358

    
359
    /**
360
     * @param errorDialogCaption
361
     * @param errorMessage
362
     */
363
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
364
        Window errorDialog = new Window(errorDialogCaption);
365
        errorDialog.setModal(true);
366
        VerticalLayout subContent = new VerticalLayout();
367
        subContent.setMargin(true);
368
        errorDialog.setContent(subContent);
369
        subContent.addComponent(new Label(errorMessage));
370
        UI.getCurrent().addWindow(errorDialog);
371
    }
372

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

    
391

    
392
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
393
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
394

    
395
        if(!checkFromOwnView(event)){
396
            return;
397
        }
398

    
399
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
400
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
401
        popup.loadInEditor(null);
402
    }
403

    
404
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
405
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
406

    
407
        if(!checkFromOwnView(event)){
408
            return;
409
        }
410
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
411
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
412
        popup.withDeleteButton(true);
413
        popup.loadInEditor(event.getEntityUuid());
414
    }
415

    
416
    @EventBusListenerMethod
417
    public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
418
        if(event.getPopup() instanceof ReferencePopupEditor){
419
            if(event.getReason().equals(Reason.SAVE)){
420
                refreshView(true);
421
            }
422
        }
423
    }
424

    
425
    @EventBusListenerMethod
426
    public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
427
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
428
            if(event.getReason().equals(Reason.SAVE)){
429
                refreshView(true);
430
            }
431
        }
432
    }
433

    
434
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
435
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
436

    
437
        if(!checkFromOwnView(event)){
438
            return;
439
        }
440

    
441
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
442
        popup.loadInEditor(event.getEntityUuid());
443
    }
444

    
445
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
446
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
447

    
448
        if(!checkFromOwnView(event)){
449
            return;
450
        }
451

    
452
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
453
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
454
        popup.withDeleteButton(true);
455
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
456
        popup.loadInEditor(event.getEntityUuid());
457
        if(event.hasSource() && event.getSource().isReadOnly()){
458
            // avoid resetting readonly to false
459
            popup.setReadOnly(true);
460
        }
461

    
462
    }
463

    
464

    
465
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
466
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
467

    
468
        if(!checkFromOwnView(event)){
469
            return;
470
        }
471

    
472
        getView().getAddNewNameRegistrationButton().setEnabled(false);
473
        if(newNameForRegistrationPopupEditor == null){
474
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
475
            newNameForRegistrationPopupEditor = popup;
476
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
477
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
478
            popup.withDeleteButton(true);
479
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
480

    
481
                @Override
482
                public TaxonName createNewBean() {
483
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
484
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
485
                    return newTaxonName;
486
                }
487
            });
488
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
489
            popup.loadInEditor(null);
490
        }
491
    }
492

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

    
548

    
549
    /**
550
     * Creates a new Registration for an exiting (previously published) name.
551
     *
552
     * @param event
553
     * @throws RegistrationValidationException
554
     */
555
    @EventBusListenerMethod
556
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
557

    
558
        if(!event.isStart()){
559
            return;
560
        }
561

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

    
605
    }
606

    
607

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

    
611
        if(!checkFromOwnView(event)){
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
            popup.withDeleteButton(true);
619
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
620
            if(event.hasSource()){
621
                // propagate readonly state from source button to popup
622
                popup.setReadOnly(event.getSource().isReadOnly());
623
            }
624
        } else {
625
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
626
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
627
            popup.withDeleteButton(true);
628
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
629

    
630
            popup.getCitationCombobox().setEnabled(false);
631
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
632

    
633
            if(event.hasSource()){
634
                // propagate readonly state from source button to popup
635
                popup.setReadOnly(event.getSource().isReadOnly());
636
            }
637
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
638
        }
639
    }
640

    
641
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
642
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
643

    
644
        if(!event.hasSource()){
645
            return;
646
        }
647

    
648
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
649
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
650
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
651
            TypeDesignationWorkingsetEditorIdSet identifierSet;
652
            UUID typifiedNameUuid;
653

    
654
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
655
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
656
            if(typifiedNameRef != null){
657
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
658
                typifiedNameUuid = typifiedNameRef.getUuid();
659
            } else {
660
                // case of registrations with a name in the nomenclatural act.
661
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
662
            }
663

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

    
686
                @Override
687
                public NameTypeDesignation createNewBean() {
688

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

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

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

    
753
        }
754
        // ignore other editors
755
    }
756

    
757

    
758
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
759
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
760

    
761
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
762
            List<String> messages = new ArrayList<>();
763
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
764
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
765
            }
766
            getView().openDetailsPopup("Validation Problems", messages);
767
        }
768
    }
769

    
770
    @EventBusListenerMethod
771
    public void onEntityChangeEvent(EntityChangeEvent event){
772

    
773
        if(workingset == null){
774
            return;
775
        }
776
        if(Reference.class.isAssignableFrom(event.getEntityType())){
777

    
778
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
779
                if(event.isRemovedType()){
780
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
781
                } else {
782
                    refreshView(true);
783
                }
784
            }
785

    
786
        } else
787
        if(Registration.class.isAssignableFrom(event.getEntityType())){
788
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
789
                refreshView(true);
790
            }
791
        } else
792
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
793
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
794
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
795
                EditorActionContext rootContext = context.get(0);
796
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
797

    
798
                    try {
799
                        getRepo().getSession().clear();
800
                        // TODO move into a service class --------------
801
                        TransactionStatus txStatus = getRepo().startTransaction();
802
                        // create a blocking registration, the new Registration will be persisted
803
                        UUID taxonNameUUID = event.getEntityUuid();
804
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
805

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

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

    
852
    /**
853
     * @param context
854
     * @return
855
     */
856
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
857
        EditorActionContext rootCtx = context.get(0);
858
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
859
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
860
        Registration registration = registrationDTO.registration();
861

    
862
        if(registration.isPersited()){
863
             registration = getRepo().getRegistrationService().load(registration.getUuid());
864
             if(registration == null){
865
                 throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
866
             }
867
         } else {
868
             logger.trace("Registration is not yet persisted.");
869
         }
870
        return registration;
871
    }
872

    
873
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
874
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
875

    
876
        // FIXME check from own view!!!
877
        if(getView() == null){
878
            return;
879
        }
880

    
881
        UUID registrationUuid = event.getIdentifier();
882

    
883
        RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
884
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
885

    
886
            Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
887
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
888
        } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
889

    
890
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
891
            popup.loadMessagesFor(regDto.getUuid());
892

    
893
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
894
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
895
        }
896
    }
897

    
898
    /**
899
     * {@inheritDoc}
900
     */
901
    @Override
902
    public ICdmEntityUuidCacher getCache() {
903
        return cache;
904
    }
905

    
906
    /**
907
     * {@inheritDoc}
908
     */
909
    @Override
910
    public void addRootEntity(CdmBase entity) {
911
        rootEntities.add(entity);
912
        cache.load(entity);
913
    }
914

    
915

    
916
    /**
917
     * {@inheritDoc}
918
     */
919
    @Override
920
    public Collection<CdmBase> getRootEntities() {
921
        return rootEntities;
922
    }
923

    
924
    @Override
925
    public void destroy() throws Exception {
926
        super.destroy();
927
        disposeCache();
928
    }
929

    
930
    /**
931
     * {@inheritDoc}
932
     */
933
    @Override
934
    public void disposeCache() {
935
        cache.dispose();
936
    }
937

    
938
}
(13-13/21)