Project

General

Profile

Download (20.7 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.EnumSet;
13
import java.util.List;
14

    
15
import org.springframework.beans.factory.annotation.Autowired;
16
import org.springframework.context.event.EventListener;
17
import org.springframework.security.core.Authentication;
18
import org.springframework.transaction.TransactionStatus;
19

    
20
import com.vaadin.spring.annotation.SpringComponent;
21
import com.vaadin.spring.annotation.ViewScope;
22
import com.vaadin.ui.Label;
23
import com.vaadin.ui.UI;
24
import com.vaadin.ui.VerticalLayout;
25
import com.vaadin.ui.Window;
26

    
27
import eu.etaxonomy.cdm.api.service.INameService;
28
import eu.etaxonomy.cdm.api.service.IRegistrationService;
29
import eu.etaxonomy.cdm.api.service.idminter.IdentifierMinter.Identifier;
30
import eu.etaxonomy.cdm.api.service.idminter.RegistrationIdentifierMinter;
31
import eu.etaxonomy.cdm.model.common.User;
32
import eu.etaxonomy.cdm.model.name.Rank;
33
import eu.etaxonomy.cdm.model.name.Registration;
34
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
35
import eu.etaxonomy.cdm.model.name.TaxonName;
36
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
37
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
38
import eu.etaxonomy.cdm.model.reference.Reference;
39
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
40
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
41
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
42
import eu.etaxonomy.cdm.service.CdmStore;
43
import eu.etaxonomy.cdm.service.IRegistrationWorkingSetService;
44
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
45
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
46
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
47
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
48
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
49
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
50
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
51
import eu.etaxonomy.cdm.vaadin.model.EntityReference;
52
import eu.etaxonomy.cdm.vaadin.model.registration.RegistrationWorkingSet;
53
import eu.etaxonomy.cdm.vaadin.security.UserHelper;
54
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
55
import eu.etaxonomy.cdm.vaadin.util.converter.TypeDesignationSetManager.TypeDesignationWorkingSetType;
56
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
57
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
58
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorMode;
59
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
60
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
61
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
62
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
63
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
64

    
65
/**
66
 * @author a.kohlbecker
67
 * @since Mar 3, 2017
68
 *
69
 */
70
@SpringComponent
71
@ViewScope
72
public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> {
73

    
74
    private static final long serialVersionUID = 1L;
75

    
76
    @Autowired
77
    private IRegistrationWorkingSetService workingSetService;
78

    
79
    @Autowired
80
    private RegistrationIdentifierMinter minter;
81

    
82
    /**
83
     * @return the workingSetService
84
     */
85
    public IRegistrationWorkingSetService getWorkingSetService() {
86
        return workingSetService;
87
    }
88

    
89
    private RegistrationWorkingSet workingset;
90

    
91
    private TaxonName newTaxonNameForRegistration = null;
92

    
93
    private RegistrationDTO newRegistrationDTOWithExistingName;
94

    
95

    
96
    /**
97
     *
98
     */
99
    public RegistrationWorkingsetPresenter() {
100
    }
101

    
102

    
103
    /**
104
     * Always create a new Store
105
     *
106
     * @return
107
     */
108
    protected CdmStore<Registration, IRegistrationService> getRegistrationStore(){
109
        return new CdmStore<Registration, IRegistrationService>(getRepo(), getRepo().getRegistrationService());
110
    }
111

    
112
    /**
113
     * Always create a new Store
114
     *
115
     * @return
116
     */
117
    protected CdmStore<TaxonName, INameService> getTaxonNameStore(){
118
        return new  CdmStore<TaxonName, INameService>(getRepo(), getRepo().getNameService());
119
    }
120

    
121

    
122
    /**
123
     * @param taxonNameId
124
     * @return
125
     */
126
    protected Registration createNewRegistrationForName(Integer taxonNameId) {
127
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
128
        // move into RegistrationWorkflowStateMachine
129
        TransactionStatus txStatus = getRepo().startTransaction();
130
        long identifier = System.currentTimeMillis();
131

    
132
        Identifier<String> identifiers = minter.mint();
133
        if(identifiers.getIdentifier() == null){
134
            throw new RuntimeException("RegistrationIdentifierMinter configuration incomplete.");
135
        }
136
        Registration reg = Registration.NewInstance(
137
                identifiers.getIdentifier(),
138
                identifiers.getLocalId(),
139
                taxonNameId != null ? getRepo().getNameService().find(taxonNameId) : null,
140
                null);
141
        Authentication authentication = currentSecurityContext().getAuthentication();
142
        reg.setSubmitter((User)authentication.getPrincipal());
143
        EntityChangeEvent event = getRegistrationStore().saveBean(reg);
144
        UserHelper.fromSession().createAuthorityForCurrentUser(Registration.class, event.getEntityId(), Operation.UPDATE, RegistrationStatus.PREPARATION.name());
145
        getRepo().commitTransaction(txStatus);
146
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147
        return getRepo().getRegistrationService().find(event.getEntityId());
148
    }
149

    
150

    
151
    /**
152
     * @param doReload TODO
153
     *
154
     */
155
    protected void refreshView(boolean doReload) {
156
        if(doReload){
157
            loadWorkingSet(workingset.getCitationId());
158
        }
159
        getView().setWorkingset(workingset);
160
    }
161

    
162

    
163
    /**
164
     * {@inheritDoc}
165
     */
166
    @Override
167
    public void handleViewEntered() {
168

    
169
        super.handleViewEntered();
170

    
171
        loadWorkingSet(getView().getCitationID());
172
        getView().setWorkingset(workingset);
173

    
174
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
175
                getRepo().getNameService());
176
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenrator = new CdmTitleCacheCaptionGenerator<TaxonName>();
177
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenrator);
178
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
179
    }
180

    
181

    
182
    /**
183
     * @param referenceID
184
     */
185
    protected void loadWorkingSet(Integer referenceID) {
186
        try {
187
            workingset = getWorkingSetService().loadWorkingSetByReferenceID(referenceID);
188
        } catch (RegistrationValidationException error) {
189
            logger.error(error);
190
            Window errorDialog = new Window("Validation Error");
191
            errorDialog.setModal(true);
192
            VerticalLayout subContent = new VerticalLayout();
193
            subContent.setMargin(true);
194
            errorDialog.setContent(subContent);
195
            subContent.addComponent(new Label(error.getMessage()));
196
            UI.getCurrent().addWindow(errorDialog);
197
        }
198
        if(workingset == null || workingset.getCitationId() == null){
199
            Reference citation = getRepo().getReferenceService().find(referenceID);
200
            workingset = new RegistrationWorkingSet(citation);
201
        }
202
    }
203

    
204
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).ADD && #event.sourceComponent == null")
205
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
206
        ReferencePopupEditor popup = getNavigationManager().showInPopup(ReferencePopupEditor.class);
207
        popup.loadInEditor(null);
208
    }
209

    
210
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT && #event.sourceComponent == null")
211
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
212
        ReferencePopupEditor popup = getNavigationManager().showInPopup(ReferencePopupEditor.class);
213
        popup.withDeleteButton(true);
214
        popup.loadInEditor(event.getEntityId());
215
    }
216

    
217
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT && #event.sourceComponent == null")
218
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
219
        RegistrationPopupEditor popup = getNavigationManager().showInPopup(RegistrationPopupEditor.class);
220
        popup.loadInEditor(event.getEntityId());
221
    }
222

    
223
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT")
224
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
225

    
226
        if(!checkFromOwnView(event)){
227
            return;
228
        }
229

    
230
        TaxonNamePopupEditor popup = getNavigationManager().showInPopup(TaxonNamePopupEditor.class);
231
        popup.withDeleteButton(true);
232
        configureTaxonNameEditor(popup);
233
        popup.loadInEditor(event.getEntityId());
234
        if(event.getSourceComponent() != null){
235
            popup.setReadOnly(event.getSourceComponent().isReadOnly());
236
        }
237

    
238
    }
239

    
240

    
241
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).ADD")
242
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
243

    
244
        newTaxonNameForRegistration = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
245
        newTaxonNameForRegistration.setNomenclaturalReference(getRepo().getReferenceService().find(workingset.getCitationId()));
246
        EntityChangeEvent nameSaveEvent = getTaxonNameStore().saveBean(newTaxonNameForRegistration);
247
        newTaxonNameForRegistration = getRepo().getNameService().find(nameSaveEvent.getEntityId());
248
        TaxonNamePopupEditor popup = getNavigationManager().showInPopup(TaxonNamePopupEditor.class);
249
        popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
250
        popup.withDeleteButton(true);
251
        configureTaxonNameEditor(popup);
252
        popup.loadInEditor(newTaxonNameForRegistration.getId());
253
        // disable NomReferenceCombobox:
254
        // the in the registration application inReferences should only edited centrally
255
        // setEnabled must be set at last otherwise it will not be effective
256
        popup.getNomReferenceCombobox().setEnabled(false);
257
    }
258

    
259
    /**
260
     * TODO consider putting this into a Configurer Bean per UIScope.
261
     * In the configurator bean this methods popup papamerter should be of the type
262
     * AbstractPopupEditor
263
     *
264
     * @param popup
265
     */
266
    protected void configureTaxonNameEditor(TaxonNamePopupEditor popup) {
267
        popup.enableMode(TaxonNamePopupEditorMode.suppressReplacementAuthorshipData);
268

    
269
    }
270

    
271
    /**
272
     * Creates a new <code>Registration</code> for a new name that has just been edited
273
     * using the <code>TaxonNamePopupEditor</code>. The new name was previously created
274
     * in this presenter as <code>newTaxonNameForRegistration</code> (see {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)})
275
     * and is either filled with data (<code>Reason.SAVE</code>) or it is still empty
276
     * (<code>Reason.CANCEL</code>).
277
     *
278
     *
279
     * @param event
280
     * @throws RegistrationValidationException
281
     */
282
    @EventListener
283
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
284
        if(event.getPopup() instanceof TaxonNamePopupEditor){
285
            TransactionStatus txStatus = getRepo().startTransaction();
286
            if(event.getReason().equals(Reason.SAVE)){
287
                if(newTaxonNameForRegistration != null){
288
                    int taxonNameId = newTaxonNameForRegistration.getId();
289
                    getRepo().getSession().refresh(newTaxonNameForRegistration);
290
                    Registration reg = createNewRegistrationForName(taxonNameId);
291
                    // reload workingset into current session
292
                    loadWorkingSet(workingset.getCitationId());
293
                    workingset.add(reg);
294
                }
295
                refreshView(true);
296
            } else if(event.getReason().equals(Reason.CANCEL)){
297
                if(newTaxonNameForRegistration != null){
298
                    // clean up
299
                    getTaxonNameStore().deleteBean(newTaxonNameForRegistration);
300
                }
301
            }
302
            getRepo().commitTransaction(txStatus);
303
            newTaxonNameForRegistration = null;
304
        }
305
    }
306

    
307

    
308
    /**
309
     * Creates a new Registration for an exiting (previously published name).
310
     *
311
     * @param event
312
     * @throws RegistrationValidationException
313
     */
314
    @EventListener(condition = "#event.action == T(eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction.Action).start")
315
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
316

    
317
        getView().getAddExistingNameCombobox().commit();
318
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
319
        if(typifiedName != null){
320
            Registration newRegistrationWithExistingName = createNewRegistrationForName(null);
321
            Reference citation = getRepo().getReferenceService().find(workingset.getCitationId());
322
            newRegistrationDTOWithExistingName = new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation);
323
            workingset.add(newRegistrationDTOWithExistingName);
324
            // tell the view to update the workingset
325
            getView().setWorkingset(workingset);
326
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
327
            getView().getAddExistingNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
328
        } else {
329
            logger.error("Seletced name is NULL");
330
        }
331

    
332
    }
333

    
334
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT")
335
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
336

    
337
        if(!checkFromOwnView(event)){
338
            return;
339
        }
340

    
341
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
342
            SpecimenTypeDesignationWorkingsetPopupEditor popup = getNavigationManager().showInPopup(SpecimenTypeDesignationWorkingsetPopupEditor.class);
343
            popup.withDeleteButton(true);
344
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationId(), event.getEntityId()));
345
            if(event.getSourceComponent() != null){
346
                popup.setReadOnly(event.getSourceComponent().isReadOnly());
347
            }
348
        } else {
349
            // TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET
350
            // FIXME implement NameTypeDesignationWorkingsetPopupEditor
351
        }
352
    }
353

    
354
    @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).ADD && #event.sourceComponent == null")
355
    public void onAddNewTypeDesignationWorkingset(TypeDesignationWorkingsetEditorAction event) {
356

    
357
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
358
            SpecimenTypeDesignationWorkingsetPopupEditor popup = getNavigationManager().showInPopup(SpecimenTypeDesignationWorkingsetPopupEditor.class);
359
            TypeDesignationWorkingsetEditorIdSet identifierSet;
360
            Integer typifiedNameId;
361
            if(newRegistrationDTOWithExistingName != null){
362
                typifiedNameId = newRegistrationDTOWithExistingName.getTypifiedNameRef().getId();
363
            } else {
364
                RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationId()).get();
365
                EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
366
                if(typifiedNameRef != null){
367
                    // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
368
                    typifiedNameId = typifiedNameRef.getId();
369
                } else {
370
                    // case of registrations with a name in the nomenclatural act.
371
                    typifiedNameId = registrationDTO.getNameRef().getId();
372
                }
373
            }
374
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
375
                    event.getRegistrationId(),
376
                    getView().getCitationID(),
377
                    typifiedNameId
378
                    );
379
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
380
            popup.loadInEditor(identifierSet);
381
            popup.withDeleteButton(true);
382
        } else {
383
            // TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET
384
            // FIXME implement NameTypeDesignationWorkingsetPopupEditor
385
        }
386
    }
387

    
388
    /**
389
     * Performs final actions after a TypeDesignationEditor which has been
390
     * opened to add a TypeDesignation to a Registration object which was
391
     * created for an previously published name. Prior adding a typedesignation,
392
     * the according Registration object is dangling, that has no association to
393
     * any entity denoting an nomenclatural act which has a reference to a
394
     * publication. This means that the registration object is not in the
395
     * working set.
396
     *
397
     *
398
     * @param event
399
     * @throws RegistrationValidationException
400
     */
401
    @EventListener
402
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
403
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
404
            if(event.getReason().equals(Reason.SAVE)){
405
                refreshView(true);
406
            } else if(event.getReason().equals(Reason.CANCEL)){
407
                // clean up
408
                if(newRegistrationDTOWithExistingName != null){
409
                    getRegistrationStore().deleteBean(newRegistrationDTOWithExistingName.registration());
410
                }
411
            }
412
            // set newRegistrationDTOWithExistingName NULL in any case
413
            newRegistrationDTOWithExistingName = null;
414
        }
415
    }
416

    
417

    
418
    @EventListener(classes=ShowDetailsEvent.class, condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.model.registration.RegistrationWorkingSet)")
419
    public void onShowRegistrationWorkingSetMessages(ShowDetailsEvent<?,?> event) { // WARNING don't use more specific generic type arguments
420
        List<String> messages = new ArrayList<>();
421
        for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
422
            dto.getMessages().forEach(m -> messages.add(dto.getSummary() + ": " + m));
423
        }
424
        if(event.getProperty().equals("messages")){
425
            getView().openDetailsPopup("Messages", messages);
426
        }
427
    }
428

    
429
    @EventListener(classes=ShowDetailsEvent.class, condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.view.registration.RegistrationDTO)")
430
    public void onShowRegistrationMessages(ShowDetailsEvent<?,?> event) { // WARNING don't use more specific generic type arguments
431
        RegistrationDTO regDto = workingSetService.loadDtoById((Integer)event.getIdentifier());
432
        if(event.getProperty().equals("messages")){
433
            if(getView() != null){
434
                getView().openDetailsPopup("Messages", regDto.getMessages());
435
            }
436
        }
437
    }
438

    
439
    @EventListener
440
    public void onEntityChangeEvent(EntityChangeEvent event){
441
        if(workingset == null){
442
            return;
443
        }
444
        if(Reference.class.isAssignableFrom(event.getEntityType())){
445
            if(workingset.getCitationId().equals(event.getEntityId())){
446
                refreshView(true);
447
            }
448
        } else
449
        if(Registration.class.isAssignableFrom(event.getEntityType())){
450
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getId() == event.getEntityId())){
451
                refreshView(true);
452
            }
453
        } else
454
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
455
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
456
                reg.getTypifiedNameRef() != null
457
                && reg.getTypifiedNameRef().getId() == event.getEntityId())){
458
                    refreshView(true);
459
            }
460
        } else
461
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
462
            if(workingset.getRegistrationDTOs().stream().anyMatch(
463
                    reg -> reg.getTypeDesignations().stream().anyMatch(
464
                            td -> td.getId() == event.getEntityId()
465
                            )
466
                        )
467
                    ){
468
                refreshView(true);
469
            }
470
        }
471

    
472
    }
473

    
474
}
(12-12/19)