Project

General

Profile

Download (40.3 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 neen opend 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 TODO
213
     *
214
     */
215
    protected void refreshView(boolean doReload) {
216
        if(workingset == null){
217
            return; // nothing to do
218
        }
219
        if(doReload){
220
            loadWorkingSet(workingset.getCitationUuid());
221
        }
222
        applyWorkingset();
223
    }
224

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

    
235
            private static final long serialVersionUID = 7099181280977511048L;
236

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

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

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

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

    
266

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

    
271
    }
272

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

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

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

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

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

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

    
324

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

    
330
        try {
331
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
332
        } catch (RegistrationValidationException error) {
333
            logger.error(error);
334
            showErrorDialog("Validation Error", error.getMessage());
335
        } catch(PermissionDeniedException e){
336
            logger.info(e);
337
            ((AccessRestrictedView)getView()).setAccessDeniedMessage(e.getMessage());
338
        }
339
        cache = new CdmTransientEntityAndUuidCacher(this);
340
        for(Registration registration : workingset.getRegistrations()) {
341
            addRootEntity(registration);
342
        }
343
    }
344

    
345
    /**
346
     * @param errorDialogCaption
347
     * @param errorMessage
348
     */
349
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
350
        Window errorDialog = new Window(errorDialogCaption);
351
        errorDialog.setModal(true);
352
        VerticalLayout subContent = new VerticalLayout();
353
        subContent.setMargin(true);
354
        errorDialog.setContent(subContent);
355
        subContent.addComponent(new Label(errorMessage));
356
        UI.getCurrent().addWindow(errorDialog);
357
    }
358

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

    
377

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

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

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

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

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

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

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

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

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

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

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

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

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

    
448
    }
449

    
450

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

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

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

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

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

    
534

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

    
544
        if(!event.isStart()){
545
            return;
546
        }
547

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

    
591
    }
592

    
593

    
594
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
595
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
596

    
597
        if(!checkFromOwnView(event)){
598
            return;
599
        }
600

    
601
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
602
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
603
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
604
            popup.withDeleteButton(true);
605
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
606
            if(event.hasSource()){
607
                // propagate readonly state from source button to popup
608
                popup.setReadOnly(event.getSource().isReadOnly());
609
            }
610
        } else {
611
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
612
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
613
            popup.withDeleteButton(true);
614
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
615

    
616
            popup.getCitationCombobox().setEnabled(false);
617
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
618

    
619
            if(event.hasSource()){
620
                // propagate readonly state from source button to popup
621
                popup.setReadOnly(event.getSource().isReadOnly());
622
            }
623
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
624
        }
625
    }
626

    
627
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
628
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
629

    
630
        if(!event.hasSource()){
631
            return;
632
        }
633

    
634
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
635
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
636
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
637
            TypeDesignationWorkingsetEditorIdSet identifierSet;
638
            UUID typifiedNameUuid;
639

    
640
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
641
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
642
            if(typifiedNameRef != null){
643
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
644
                typifiedNameUuid = typifiedNameRef.getUuid();
645
            } else {
646
                // case of registrations with a name in the nomenclatural act.
647
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
648
            }
649

    
650
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
651
                    event.getRegistrationUuid(),
652
                    getView().getCitationUuid(),
653
                    typifiedNameUuid
654
                    );
655
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
656
            popup.loadInEditor(identifierSet);
657
            popup.withDeleteButton(true);
658
            if(event.hasSource()){
659
                // propagate readonly state from source component to popup
660
                popup.setReadOnly(event.getSource().isReadOnly());
661
            }
662
        } else {
663
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
664
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
665
            popup.withDeleteButton(true);
666
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
667
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
668
            Reference citation = regDto.getCitation();
669
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
670
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
671

    
672
                @Override
673
                public NameTypeDesignation createNewBean() {
674

    
675
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
676
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
677
                    nameTypeDesignation.setCitation(citation);
678
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
679
                    return nameTypeDesignation;
680
                }
681
            });
682
            popup.loadInEditor(null);
683
            popup.getCitationCombobox().setEnabled(false);
684
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
685
            if(event.hasSource()){
686
                // propagate readonly state from source component to popup
687
                popup.setReadOnly(event.getSource().isReadOnly());
688
            }
689
        }
690
    }
691

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

    
728
        }
729
        // ignore other editors
730
    }
731

    
732

    
733
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
734
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
735

    
736
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
737
            List<String> messages = new ArrayList<>();
738
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
739
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
740
            }
741
            getView().openDetailsPopup("Validation Problems", messages);
742
        }
743
    }
744

    
745
    @EventBusListenerMethod
746
    public void onEntityChangeEvent(EntityChangeEvent event){
747

    
748
        if(workingset == null){
749
            return;
750
        }
751
        if(Reference.class.isAssignableFrom(event.getEntityType())){
752

    
753
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
754
                if(event.isRemovedType()){
755
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
756
                } else {
757
                    refreshView(true);
758
                }
759
            }
760

    
761
        } else
762
        if(Registration.class.isAssignableFrom(event.getEntityType())){
763
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
764
                refreshView(true);
765
            }
766
        } else
767
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
768
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
769
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
770
                EditorActionContext rootContext = context.get(0);
771
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
772

    
773
                    try {
774
                        getRepo().getSession().clear();
775
                        TransactionStatus txStatus = getRepo().startTransaction();
776
                        // create a blocking registration, the new Registration will be persisted
777
                        UUID taxonNameUUID = event.getEntityUuid();
778
                        Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
779

    
780
                        if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
781
                            // Oha!! The event came from a popup editor and the
782
                            // first popup in the context is a TaxonNameEditor with un-persisted name
783
                            // This is a name for a new registration which has not yet been created.
784
                            // It is necessary to store blocking registrations in the newNameBlockingRegistrations
785
                            newNameBlockingRegistrations.add(blockingRegistration);
786
                            logger.debug("Blocking registration created and memorized");
787
                        } else {
788
                            // some new name related somehow to an existing registration
789
                            TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
790
                            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(regReference.getUuid()).get();
791
                            Registration registration = registrationDTO.registration();
792

    
793
                                registration = getRepo().getRegistrationService().load(registration.getUuid());
794
                                if(registration == null){
795
                                    throw new NullPointerException("Registration not found for " + regReference + " which has been hold in the rootContext");
796
                                }
797
                                registration.getBlockedBy().add(blockingRegistration);
798
                                getRepo().getRegistrationService().saveOrUpdate(registration);
799
                                getRepo().commitTransaction(txStatus);
800
                            logger.debug("Blocking registration created and added to registion");
801
                        }
802
                    } finally {
803
                        getRepo().getSession().clear();
804
                    }
805
                } else {
806
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
807
                    // this is set
808
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
809
                }
810
            }
811
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
812
                reg.getTypifiedNameRef() != null
813
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
814
                    refreshView(true);
815
            }
816
        } else
817
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
818
            if(workingset.getRegistrationDTOs().stream().anyMatch(
819
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
820
                            td -> td.getUuid() == event.getEntityUuid()
821
                            )
822
                        )
823
                    ){
824
                refreshView(true);
825
            }
826
        }
827
    }
828

    
829
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
830
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
831

    
832
        // FIXME check from own view!!!
833
        if(getView() == null){
834
            return;
835
        }
836

    
837
        UUID registrationUuid = event.getIdentifier();
838

    
839
        RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
840
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
841

    
842
            Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
843
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
844
        } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
845

    
846
            RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
847
            popup.loadMessagesFor(regDto.getUuid());
848

    
849
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
850
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
851
        }
852
    }
853

    
854
    /**
855
     * {@inheritDoc}
856
     */
857
    @Override
858
    public ICdmEntityUuidCacher getCache() {
859
        return cache;
860
    }
861

    
862
    /**
863
     * {@inheritDoc}
864
     */
865
    @Override
866
    public void addRootEntity(CdmBase entity) {
867
        rootEntities.add(entity);
868
        cache.load(entity);
869
    }
870

    
871

    
872
    /**
873
     * {@inheritDoc}
874
     */
875
    @Override
876
    public Collection<CdmBase> getRootEntities() {
877
        return rootEntities;
878
    }
879

    
880
    @Override
881
    public void destroy() throws Exception {
882
        super.destroy();
883
        disposeCache();
884
    }
885

    
886
    /**
887
     * {@inheritDoc}
888
     */
889
    @Override
890
    public void disposeCache() {
891
        cache.dispose();
892
    }
893

    
894
}
(13-13/21)