Project

General

Profile

Download (19.3 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2018 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.name;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.EnumSet;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Optional;
17
import java.util.UUID;
18
import java.util.stream.Collectors;
19

    
20
import org.apache.log4j.Logger;
21
import org.hibernate.criterion.Restrictions;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.context.annotation.Scope;
24
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
25

    
26
import com.vaadin.data.util.BeanItemContainer;
27
import com.vaadin.spring.annotation.SpringComponent;
28

    
29
import eu.etaxonomy.cdm.api.service.DeleteResult;
30
import eu.etaxonomy.cdm.api.service.IService;
31
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
32
import eu.etaxonomy.cdm.api.service.registration.RegistrationWorkingSetService;
33
import eu.etaxonomy.cdm.format.reference.ReferenceEllypsisFormatter;
34
import eu.etaxonomy.cdm.format.reference.ReferenceEllypsisFormatter.LabelType;
35
import eu.etaxonomy.cdm.model.common.Annotation;
36
import eu.etaxonomy.cdm.model.common.AnnotationType;
37
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
38
import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
39
import eu.etaxonomy.cdm.model.name.TaxonName;
40
import eu.etaxonomy.cdm.model.permission.CRUD;
41
import eu.etaxonomy.cdm.model.reference.NamedSource;
42
import eu.etaxonomy.cdm.model.reference.NamedSourceBase;
43
import eu.etaxonomy.cdm.model.reference.Reference;
44
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
45
import eu.etaxonomy.cdm.model.reference.ReferenceType;
46
import eu.etaxonomy.cdm.persistence.dao.initializer.EntityInitStrategy;
47
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
48
import eu.etaxonomy.cdm.service.CdmStore;
49
import eu.etaxonomy.cdm.service.UserHelperAccess;
50
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
51
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
52
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent.Type;
53
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
54
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
55
import eu.etaxonomy.cdm.vaadin.event.ToOneRelatedEntityButtonUpdater;
56
import eu.etaxonomy.cdm.vaadin.event.ToOneRelatedEntityReloader;
57
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
58
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
59
import eu.etaxonomy.cdm.vaadin.util.ReferenceEllypsisCaptionGenerator;
60
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
61
import eu.etaxonomy.cdm.vaadin.view.reference.RegistrationUiReferenceEditorFormConfigurator;
62
import eu.etaxonomy.vaadin.mvp.AbstractCdmEditorPresenter;
63
import eu.etaxonomy.vaadin.mvp.AbstractView;
64
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
65
import eu.etaxonomy.vaadin.mvp.BoundField;
66
import eu.etaxonomy.vaadin.ui.view.PopupView;
67

    
68
/**
69
 * @author a.kohlbecker
70
 * @since Jan 26, 2018
71
 *
72
 */
73
@SpringComponent
74
@Scope("prototype")
75
public class NameTypeDesignationPresenter
76
        extends AbstractCdmEditorPresenter<NameTypeDesignation, NameTypeDesignationEditorView> {
77

    
78
    private static final long serialVersionUID = 896305051895903033L;
79

    
80
    public static final Logger logger = Logger.getLogger(SpecimenTypeDesignationWorkingsetEditorPresenter.class);
81

    
82
    @Autowired
83
    private IRegistrationWorkingSetService registrationWorkingSetService;
84

    
85

    
86
    HashSet<TaxonName> typifiedNamesAsLoaded;
87

    
88
    private TaxonName typifiedNameInContext;
89

    
90
    /**
91
     * The unit of publication in which the type designation has been published.
92
     * This may be any type listed in {@link RegistrationUIDefaults#NOMECLATURAL_PUBLICATION_UNIT_TYPES}
93
     * but never a {@link ReferenceType#Section}
94
     */
95
    private NamedSourceBase publishedUnit;
96

    
97
    protected static BeanInstantiator<NameTypeDesignation> defaultBeanInstantiator = new BeanInstantiator<NameTypeDesignation>() {
98

    
99
        @Override
100
        public NameTypeDesignation createNewBean() {
101
            return NameTypeDesignation.NewInstance();
102
        }
103
    };
104

    
105
    private CdmFilterablePagingProvider<Reference,Reference> referencePagingProvider;
106

    
107
    private BeanInstantiator<Reference> newReferenceInstantiator;
108

    
109
    @Override
110
    protected BeanInstantiator<NameTypeDesignation> defaultBeanInstantiator(){
111
       return defaultBeanInstantiator;
112
    }
113

    
114
    @Override
115
    protected NameTypeDesignation loadBeanById(Object identifier) {
116
        NameTypeDesignation bean;
117

    
118
        NameTypeDesignationWorkingsetIds idset = (NameTypeDesignationWorkingsetIds)identifier;
119

    
120
        if(idset.isForNewTypeDesignation()) {
121
            Reference reference = getRepo().getReferenceService().load(idset.getPublishedUnitUuid());
122
            try {
123
                setPublishedUnit(NamedSource.NewPrimarySourceInstance(reference, null));
124
            } catch(Exception e) {
125
                throw new RuntimeException("Refernce of invalid type passed via NameTypeDesignationWorkingsetIds as publishedUnitUuid ", e);
126
            }
127
            EntityInitStrategy initstrategy = RegistrationWorkingSetService.NAME_INIT_STRATEGY
128
                    .clone()
129
                    .extend("typeDesignations", RegistrationWorkingSetService.TYPEDESIGNATION_INIT_STRATEGY, true);
130
            typifiedNameInContext = getRepo().getNameService().load(idset.getTypifiedNameUuid(), initstrategy.getPropertyPaths());
131
            bean = super.loadBeanById(null);
132
        } else {
133
            bean = super.loadBeanById(idset.getBaseEntityRef().getUuid());
134
            // TODO prevent from errors due to inconsistent data, two options:
135
            // 1. handle error condition here
136
            // 2. always set typifiedNameUuid in NameTypeDesignationWorkingsetIds
137
            typifiedNameInContext = bean.getTypifiedNames().iterator().next();
138
            try {
139
                setPublishedUnit(bean.getTypifiedNames().iterator().next().getNomenclaturalSource());
140
            } catch (Exception e) {
141
                // FIXME report error state instead
142
                logger.error("Error on finding published unit in " + bean, e);
143
            }
144
        }
145

    
146
        Reference typifiedNameNomRef = typifiedNameInContext.getNomenclaturalReference();
147
        while(typifiedNameNomRef.getType().equals(ReferenceType.Section)
148
                && typifiedNameNomRef.getInReference() != null) {
149
            typifiedNameNomRef = typifiedNameNomRef.getInReference();
150
        }
151
        getView().setInTypedesignationOnlyAct(Optional.of(typifiedNameNomRef != null && !typifiedNameNomRef.equals(getPublishedUnit().getCitation())));
152

    
153

    
154
        if (getPublishedUnit() != null) {
155
            // reduce available references to those which are sections of
156
            // the publicationUnit and the publishedUnit itself
157
            referencePagingProvider.getCriteria()
158
                    .add(Restrictions.or(
159
                            Restrictions.and(
160
                                    Restrictions.eq("inReference", getPublishedUnit().getCitation()),
161
                                    Restrictions.eq("type", ReferenceType.Section)),
162
                            Restrictions.idEq(publishedUnit.getCitation().getId()))
163
                         );
164

    
165
            // new Reference only a sub sections of the publishedUnit
166
            newReferenceInstantiator = new BeanInstantiator<Reference>() {
167
                @Override
168
                public Reference createNewBean() {
169
                    Reference newRef = ReferenceFactory.newSection();
170
                    Reference reference = getRepo().getReferenceService().load(
171
                            getPublishedUnit().getCitation().getUuid(),
172
                            ReferenceEllypsisFormatter.INIT_STRATEGY
173
                            );
174
                    newRef.setInReference(reference);
175
                    return newRef;
176
                }
177
            };
178
        }
179

    
180
        getView().getTypeStatusSelect().setContainerDataSource(provideTypeStatusTermItemContainer());
181

    
182
        return bean;
183
    }
184

    
185
    @Override
186
    protected NameTypeDesignation loadCdmEntity(UUID uuid) {
187
        EntityInitStrategy initStrategy = new EntityInitStrategy(Arrays.asList(new String []{
188
                "$",
189
                "annotations.*", // * is needed as log as we are using a table in FilterableAnnotationsField
190
                "typifiedNames.typeDesignations", // important !!
191
                "typifiedNames.nomenclaturalSource.citation",
192
                "typeName.$",
193
                "source.citation",
194
                "source.annotations",
195
                "source.markers",
196
                "source.links",
197
                }
198
        ));
199

    
200
        initStrategy.extend("citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
201
        NameTypeDesignation typeDesignation;
202
        if(uuid != null){
203
            typeDesignation = (NameTypeDesignation) getRepo().getNameService().loadTypeDesignation(uuid, initStrategy.getPropertyPaths());
204
        } else {
205
            typeDesignation = createNewBean();
206
        }
207

    
208
        typifiedNamesAsLoaded = new HashSet<>(typeDesignation.getTypifiedNames());
209

    
210
        return typeDesignation;
211
    }
212

    
213
    protected BeanItemContainer<NameTypeDesignationStatus> provideTypeStatusTermItemContainer() {
214

    
215
        BeanItemContainer<NameTypeDesignationStatus> container = cdmBeanItemContainerFactory.buildBeanItemContainer(NameTypeDesignationStatus.class);
216
        List<NameTypeDesignationStatus> filteredItems = container.getItemIds().stream().filter(tsb ->
217
                    getView().checkInTypeDesignationOnlyAct()
218
                    || tsb.hasDesignationSource() == true
219
                )
220
                .collect(Collectors.toList());
221
        container.removeAllItems();
222
        container.addAll(filteredItems);
223
        return container;
224

    
225
    }
226

    
227
    @Override
228
    public void handleViewEntered() {
229

    
230
        getView().getTypeStatusSelect().setContainerDataSource(cdmBeanItemContainerFactory.buildBeanItemContainer(NameTypeDesignationStatus.class));
231
        getView().getTypeStatusSelect().setItemCaptionPropertyId("description");
232
        getView().getTypeStatusSelect().setNullSelectionAllowed(true);
233

    
234
        getView().getDesignationReferenceCombobox().getSelect().setCaptionGenerator(
235
                new ReferenceEllypsisCaptionGenerator(LabelType.BIBLIOGRAPHIC, getView().getDesignationReferenceCombobox().getSelect())
236
                );
237
        referencePagingProvider = pagingProviderFactory.referencePagingProvider();
238
        getView().getDesignationReferenceCombobox().loadFrom(referencePagingProvider, referencePagingProvider, referencePagingProvider.getPageSize());
239
        getView().getDesignationReferenceCombobox().setNestedButtonStateUpdater(new ToOneRelatedEntityButtonUpdater<Reference>(getView().getDesignationReferenceCombobox()));
240
        getView().getDesignationReferenceCombobox().getSelect().addValueChangeListener(new ToOneRelatedEntityReloader<>(getView().getDesignationReferenceCombobox(), this));
241

    
242
        CdmFilterablePagingProvider<TaxonName,TaxonName> namePagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
243
        getView().getTypeNameField().loadFrom(namePagingProvider, namePagingProvider, namePagingProvider.getPageSize());
244
        getView().getTypeNameField().setNestedButtonStateUpdater(new ToOneRelatedEntityButtonUpdater<TaxonName>(getView().getTypeNameField()));
245
        getView().getTypeNameField().getSelect().addValueChangeListener(new ToOneRelatedEntityReloader<>(getView().getTypeNameField(), this));
246

    
247
        getView().getTypifiedNamesComboboxSelect().setPagingProviders(namePagingProvider, namePagingProvider, namePagingProvider.getPageSize(), this);
248

    
249
        getView().getAnnotationsField().setAnnotationTypeItemContainer(cdmBeanItemContainerFactory.buildVocabularyTermsItemContainer(
250
                AnnotationType.EDITORIAL().getVocabulary().getUuid()));
251

    
252
    }
253

    
254
    @Override
255
    protected void guaranteePerEntityCRUDPermissions(UUID identifier) {
256
        if(crud != null){
257
            newAuthorityCreated = UserHelperAccess.userHelper().createAuthorityForCurrentUser(NameTypeDesignation.class, identifier, crud, null);
258
        }
259
    }
260

    
261
    @Override
262
    protected void guaranteePerEntityCRUDPermissions(NameTypeDesignation bean) {
263
        // TODO Auto-generated method stub
264

    
265
    }
266

    
267
    @Override
268
    protected IService<NameTypeDesignation> getService() {
269
        // No TypeDesignationService :( so I need override the generic save and delete methods
270
        return null;
271
    }
272

    
273
    @Override
274
    protected void deleteBean(NameTypeDesignation bean){
275
        // deleteTypedesignation(uuid, uuid) needs to be called so the name is loaded in the transaction of the method and is saved.
276
        DeleteResult deletResult = getRepo().getNameService().deleteTypeDesignation(typifiedNameInContext.getUuid(), bean.getUuid());
277
        if(deletResult.isOk()){
278
            EntityChangeEvent changeEvent = new EntityChangeEvent(bean, Type.REMOVED, (AbstractView) getView());
279
            viewEventBus.publish(this, changeEvent);
280
        } else {
281
            CdmStore.handleDeleteresultInError(deletResult);
282
        }
283
    }
284

    
285
    @Override
286
    protected NameTypeDesignation preSaveBean(NameTypeDesignation bean) {
287

    
288
        if(!bean.hasDesignationSource()) {
289
            bean.setSource(null); // this effectively removes the designation reference and reference detail
290
        }
291

    
292
        // the typifiedNames can only be set on the name side, so we need to
293
        // handle changes explicitly here
294
        HashSet<TaxonName> typifiedNames = new HashSet<>(bean.getTypifiedNames());
295

    
296
        // handle adds
297
        for(TaxonName name : typifiedNames){
298
            if(name == null){
299
                throw new NullPointerException("typifiedName must not be null");
300
            }
301
            if(!name.getTypeDesignations().contains(bean)){
302
                name.addTypeDesignation(bean, false);
303
            }
304
        }
305
        // handle removed
306
        for(TaxonName name : typifiedNamesAsLoaded){
307
            if(!typifiedNames.contains(name)){
308
                name.removeTypeDesignation(bean);
309
            }
310
            // FIXME do we need to save the names here or is the delete cascaded from the typedesignation to the name?
311
        }
312

    
313
        // handle annotation changes
314
        List<Annotation> annotations = getView().getAnnotationsField().getValue();
315
        List<Annotation> currentAnnotations = new ArrayList<>(bean.getAnnotations());
316
        List<Annotation> annotationsSeen = new ArrayList<>();
317
        for(Annotation a : annotations){
318
            if(a == null){
319
                continue;
320
            }
321
            if(!currentAnnotations.contains(a)){
322
                bean.addAnnotation(a);
323
            }
324
            annotationsSeen.add(a);
325
        }
326
        for(Annotation a : currentAnnotations){
327
            if(!annotationsSeen.contains(a)){
328
                bean.removeAnnotation(a);
329
            }
330
        }
331
        return bean;
332
    }
333

    
334
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
335
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction action){
336

    
337
        if(!isFromOwnView(action)){
338
            return;
339
        }
340
        TaxonNamePopupEditor typeNamePopup = openPopupEditor(TaxonNamePopupEditor.class, action);
341
        typeNamePopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
342
        typeNamePopup.withDeleteButton(true);
343
        TaxonNamePopupEditorConfig.configure(typeNamePopup);
344
        typeNamePopup.loadInEditor(null);
345
    }
346

    
347
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
348
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction action){
349

    
350
        if(!isFromOwnView(action)){
351
            return;
352
        }
353

    
354
        TaxonNamePopupEditor typeNamePopup = openPopupEditor(TaxonNamePopupEditor.class, action);
355
        typeNamePopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
356
        typeNamePopup.withDeleteButton(true);
357
        TaxonNamePopupEditorConfig.configure(typeNamePopup);
358
        typeNamePopup.loadInEditor(action.getEntityUuid());
359

    
360
    }
361

    
362
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
363
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
364

    
365
        if (getView() == null || event.getSourceView() != getView()) {
366
            return;
367
        }
368
        ReferencePopupEditor referenceEditorPopup = openPopupEditor(ReferencePopupEditor.class, event);
369

    
370
        referenceEditorPopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
371
        referenceEditorPopup.withDeleteButton(true);
372
        RegistrationUiReferenceEditorFormConfigurator
373
            .create(newReferenceInstantiator != null)
374
            .configure(referenceEditorPopup, newReferenceInstantiator);
375
        referenceEditorPopup.loadInEditor(null);
376
    }
377

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

    
381
        if (!isFromOwnView(event)) {
382
            return;
383
        }
384
        ReferencePopupEditor referenceEditorPopup = openPopupEditor(ReferencePopupEditor.class, event);
385

    
386
        referenceEditorPopup.withDeleteButton(true);
387
        // TODO this should be configurable per UI -
388
        // RegistrationUiReferenceEditorFormConfigurator as spring bean,
389
        // different spring profiles
390
        // see also similar methods in TaxonName and SpecimenTypeDesigationEditors
391
        RegistrationUiReferenceEditorFormConfigurator
392
            .create(newReferenceInstantiator != null)
393
            .configure(referenceEditorPopup, newReferenceInstantiator);
394
        referenceEditorPopup.loadInEditor(event.getEntityUuid());
395
    }
396

    
397
    @EventBusListenerMethod
398
    public void onEntityChangeEvent(EntityChangeEvent<?>event){
399

    
400
        BoundField boundTargetField = boundTargetField((PopupView) event.getSourceView());
401

    
402
        if(boundTargetField != null){
403
            if(boundTargetField.matchesPropertyIdPath("typeName")){
404
                if(event.isCreateOrModifiedType()){
405
                    getCache().load(event.getEntity());
406
                    if(event.isCreatedType()){
407
                        getView().getTypeNameField().setValue((TaxonName) event.getEntity());
408
                    } else {
409
                        getView().getTypeNameField().reload();
410
                    }
411
                }
412
                if(event.isRemovedType()){
413
                    getView().getTypeNameField().selectNewItem(null);
414
                }
415

    
416
            }
417
        }
418
    }
419

    
420
    /**
421
     * @return
422
     *  the {@link #publishedUnit}
423
     */
424
    public NamedSourceBase getPublishedUnit() {
425
        return publishedUnit;
426
    }
427

    
428
    /**
429
     * @param publishedUnit
430
     *  The unit of publication in which the type designation has been published.
431
     *  This may be any type listed in {@link RegistrationUIDefaults#NOMECLATURAL_PUBLICATION_UNIT_TYPES}
432
     */
433
    protected void setPublishedUnit(NamedSourceBase publishedUnit) throws Exception {
434
        if(publishedUnit == null) {
435
            throw new NullPointerException();
436
        }
437
        if(publishedUnit.getCitation() == null) {
438
            throw new NullPointerException("The citation of the published unit must not be null.");
439
        }
440
        if(!RegistrationUIDefaults.NOMECLATURAL_PUBLICATION_UNIT_TYPES.contains(publishedUnit.getCitation().getType())) {
441
            throw new Exception("The referrence type '"  + publishedUnit.getType() + "'is not allowed for publishedUnit.");
442
        }
443
        this.publishedUnit = publishedUnit;
444
    }
445

    
446
}
(4-4/18)