Project

General

Profile

Download (19.8 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("Reference 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
                "designationSource.citation",
198
                "designationSource.annotations",
199
                "designationSource.markers",
200
                "designationSource.links",
201
                }
202
        ));
203

    
204
        initStrategy.extend("typifiedNames.nomenclaturalSource.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
205
        initStrategy.extend("citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
206
        NameTypeDesignation typeDesignation;
207
        if(uuid != null){
208
            typeDesignation = (NameTypeDesignation) getRepo().getNameService().loadTypeDesignation(uuid, initStrategy.getPropertyPaths());
209
        } else {
210
            typeDesignation = createNewBean();
211
        }
212

    
213
        typifiedNamesAsLoaded = new HashSet<>(typeDesignation.getTypifiedNames());
214

    
215
        return typeDesignation;
216
    }
217

    
218
    protected BeanItemContainer<NameTypeDesignationStatus> provideTypeStatusTermItemContainer() {
219

    
220
        BeanItemContainer<NameTypeDesignationStatus> container = cdmBeanItemContainerFactory.buildBeanItemContainer(NameTypeDesignationStatus.class);
221
        List<NameTypeDesignationStatus> filteredItems = container.getItemIds().stream().filter(tsb ->
222
                    getView().checkInTypeDesignationOnlyAct()
223
                    || tsb.hasDesignationSource() == true
224
                )
225
                .collect(Collectors.toList());
226
        container.removeAllItems();
227
        container.addAll(filteredItems);
228
        return container;
229

    
230
    }
231

    
232
    @Override
233
    public void handleViewEntered() {
234

    
235
        getView().getTypeStatusSelect().setContainerDataSource(cdmBeanItemContainerFactory.buildBeanItemContainer(NameTypeDesignationStatus.class));
236
        getView().getTypeStatusSelect().setItemCaptionPropertyId("description");
237
        getView().getTypeStatusSelect().setNullSelectionAllowed(true);
238

    
239
        getView().getDesignationReferenceCombobox().getSelect().setCaptionGenerator(
240
                new ReferenceEllypsisCaptionGenerator(LabelType.BIBLIOGRAPHIC, getView().getDesignationReferenceCombobox().getSelect())
241
                );
242
        referencePagingProvider = pagingProviderFactory.referencePagingProvider();
243
        getView().getDesignationReferenceCombobox().loadFrom(referencePagingProvider, referencePagingProvider, referencePagingProvider.getPageSize());
244
        getView().getDesignationReferenceCombobox().setNestedButtonStateUpdater(new ToOneRelatedEntityButtonUpdater<Reference>(getView().getDesignationReferenceCombobox()));
245
        getView().getDesignationReferenceCombobox().getSelect().addValueChangeListener(new ToOneRelatedEntityReloader<>(getView().getDesignationReferenceCombobox(), this));
246

    
247
        CdmFilterablePagingProvider<TaxonName,TaxonName> namePagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
248
        getView().getTypeNameField().loadFrom(namePagingProvider, namePagingProvider, namePagingProvider.getPageSize());
249
        getView().getTypeNameField().setNestedButtonStateUpdater(new ToOneRelatedEntityButtonUpdater<TaxonName>(getView().getTypeNameField()));
250
        getView().getTypeNameField().getSelect().addValueChangeListener(new ToOneRelatedEntityReloader<>(getView().getTypeNameField(), this));
251

    
252
        getView().getTypifiedNamesComboboxSelect().setPagingProviders(namePagingProvider, namePagingProvider, namePagingProvider.getPageSize(), this);
253

    
254
        getView().getAnnotationsField().setAnnotationTypeItemContainer(cdmBeanItemContainerFactory.buildVocabularyTermsItemContainer(
255
                AnnotationType.EDITORIAL().getVocabulary().getUuid()));
256

    
257
    }
258

    
259
    @Override
260
    protected void guaranteePerEntityCRUDPermissions(UUID identifier) {
261
        if(crud != null){
262
            newAuthorityCreated = UserHelperAccess.userHelper().createAuthorityForCurrentUser(NameTypeDesignation.class, identifier, crud, null);
263
        }
264
    }
265

    
266
    @Override
267
    protected void guaranteePerEntityCRUDPermissions(NameTypeDesignation bean) {
268
        // TODO Auto-generated method stub
269

    
270
    }
271

    
272
    @Override
273
    protected IService<NameTypeDesignation> getService() {
274
        // No TypeDesignationService :( so I need override the generic save and delete methods
275
        return null;
276
    }
277

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

    
290
    @Override
291
    protected NameTypeDesignation preSaveBean(NameTypeDesignation bean) {
292

    
293
        if(!bean.hasDesignationSource()) {
294
            bean.setDesignationSource(null); // this effectively removes the designation reference and reference detail
295
        }
296

    
297
        if(bean.isNotDesignated()) {
298
            // having a type name makes no sense in this case, therefore we now remove it now
299
            bean.setTypeName(null);
300
        }
301

    
302
        // the typifiedNames can only be set on the name side, so we need to
303
        // handle changes explicitly here
304
        HashSet<TaxonName> typifiedNames = new HashSet<>(bean.getTypifiedNames());
305

    
306
        // handle adds
307
        for(TaxonName name : typifiedNames){
308
            if(name == null){
309
                throw new NullPointerException("typifiedName must not be null");
310
            }
311
            if(!name.getTypeDesignations().contains(bean)){
312
                name.addTypeDesignation(bean, false);
313
            }
314
        }
315
        // handle removed
316
        for(TaxonName name : typifiedNamesAsLoaded){
317
            if(!typifiedNames.contains(name)){
318
                name.removeTypeDesignation(bean);
319
            }
320
            // FIXME do we need to save the names here or is the delete cascaded from the typedesignation to the name?
321
        }
322

    
323
        // handle annotation changes
324
        List<Annotation> annotations = getView().getAnnotationsField().getValue();
325
        List<Annotation> currentAnnotations = new ArrayList<>(bean.getAnnotations());
326
        List<Annotation> annotationsSeen = new ArrayList<>();
327
        for(Annotation a : annotations){
328
            if(a == null){
329
                continue;
330
            }
331
            if(!currentAnnotations.contains(a)){
332
                bean.addAnnotation(a);
333
            }
334
            annotationsSeen.add(a);
335
        }
336
        for(Annotation a : currentAnnotations){
337
            if(!annotationsSeen.contains(a)){
338
                bean.removeAnnotation(a);
339
            }
340
        }
341
        return bean;
342
    }
343

    
344
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
345
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction action){
346

    
347
        if(!isFromOwnView(action)){
348
            return;
349
        }
350
        TaxonNamePopupEditor typeNamePopup = openPopupEditor(TaxonNamePopupEditor.class, action);
351
        typeNamePopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
352
        typeNamePopup.withDeleteButton(true);
353
        TaxonNamePopupEditorConfig.configure(typeNamePopup);
354
        typeNamePopup.loadInEditor(null);
355
    }
356

    
357
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
358
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction action){
359

    
360
        if(!isFromOwnView(action)){
361
            return;
362
        }
363

    
364
        TaxonNamePopupEditor typeNamePopup = openPopupEditor(TaxonNamePopupEditor.class, action);
365
        typeNamePopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
366
        typeNamePopup.withDeleteButton(true);
367
        TaxonNamePopupEditorConfig.configure(typeNamePopup);
368
        typeNamePopup.loadInEditor(action.getEntityUuid());
369

    
370
    }
371

    
372
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
373
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
374

    
375
        if (getView() == null || event.getSourceView() != getView()) {
376
            return;
377
        }
378
        ReferencePopupEditor referenceEditorPopup = openPopupEditor(ReferencePopupEditor.class, event);
379

    
380
        referenceEditorPopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
381
        referenceEditorPopup.withDeleteButton(true);
382
        RegistrationUiReferenceEditorFormConfigurator
383
            .create(newReferenceInstantiator != null)
384
            .configure(referenceEditorPopup, newReferenceInstantiator);
385
        referenceEditorPopup.loadInEditor(null);
386
    }
387

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

    
391
        if (!isFromOwnView(event)) {
392
            return;
393
        }
394
        ReferencePopupEditor referenceEditorPopup = openPopupEditor(ReferencePopupEditor.class, event);
395

    
396
        referenceEditorPopup.withDeleteButton(true);
397
        // TODO this should be configurable per UI -
398
        // RegistrationUiReferenceEditorFormConfigurator as spring bean,
399
        // different spring profiles
400
        // see also similar methods in TaxonName and SpecimenTypeDesigationEditors
401
        RegistrationUiReferenceEditorFormConfigurator
402
            .create(newReferenceInstantiator != null)
403
            .configure(referenceEditorPopup, newReferenceInstantiator);
404
        referenceEditorPopup.loadInEditor(event.getEntityUuid());
405
    }
406

    
407
    @EventBusListenerMethod
408
    public void onEntityChangeEvent(EntityChangeEvent<?>event){
409

    
410
        BoundField boundTargetField = boundTargetField((PopupView) event.getSourceView());
411

    
412
        if(boundTargetField != null){
413
            if(boundTargetField.matchesPropertyIdPath("typeName")){
414
                if(event.isCreateOrModifiedType()){
415
                    getCache().load(event.getEntity());
416
                    if(event.isCreatedType()){
417
                        getView().getTypeNameField().setValue((TaxonName) event.getEntity());
418
                    } else {
419
                        getView().getTypeNameField().reload();
420
                    }
421
                }
422
                if(event.isRemovedType()){
423
                    getView().getTypeNameField().selectNewItem(null);
424
                }
425

    
426
            }
427
        }
428
    }
429

    
430
    /**
431
     * @return
432
     *  the {@link #publishedUnit}
433
     */
434
    public NamedSourceBase getPublishedUnit() {
435
        return publishedUnit;
436
    }
437

    
438
    /**
439
     * @param publishedUnit
440
     *  The unit of publication in which the type designation has been published.
441
     *  This may be any type listed in {@link RegistrationUIDefaults#NOMECLATURAL_PUBLICATION_UNIT_TYPES}
442
     */
443
    protected void setPublishedUnit(NamedSourceBase publishedUnit) throws Exception {
444
        if(publishedUnit == null) {
445
            throw new NullPointerException();
446
        }
447
        if(publishedUnit.getCitation() == null) {
448
            throw new NullPointerException("The citation of the published unit must not be null.");
449
        }
450
        if(!RegistrationUIDefaults.NOMECLATURAL_PUBLICATION_UNIT_TYPES.contains(publishedUnit.getCitation().getType())) {
451
            throw new Exception("The referrence type '"  + publishedUnit.getType() + "'is not allowed for publishedUnit.");
452
        }
453
        this.publishedUnit = publishedUnit;
454
    }
455

    
456
}
(4-4/18)