Project

General

Profile

Download (5.78 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.vaadin.mvp;
10

    
11
import org.apache.log4j.Logger;
12
import org.hibernate.Session;
13
import org.hibernate.engine.spi.SessionImplementor;
14
import org.springframework.context.event.EventListener;
15
import org.springframework.transaction.TransactionStatus;
16

    
17
import com.vaadin.data.fieldgroup.BeanFieldGroup;
18
import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
19
import com.vaadin.data.util.BeanItem;
20

    
21
import eu.etaxonomy.cdm.model.common.CdmBase;
22
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
23
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent.Type;
24
import eu.etaxonomy.vaadin.mvp.event.EditorPreSaveEvent;
25
import eu.etaxonomy.vaadin.mvp.event.EditorSaveEvent;
26

    
27
/**
28
 * Provides generic save operations of modified cdm entities.
29
 *
30
 * @author a.kohlbecker
31
 * @since Apr 5, 2017
32
 *
33
 */
34
public abstract class AbstractCdmEditorPresenter<DTO extends CdmBase, V extends ApplicationView<?>> extends AbstractEditorPresenter<DTO, V> {
35

    
36
    private static final long serialVersionUID = 2218185546277084261L;
37

    
38
    private static final Logger logger = Logger.getLogger(AbstractCdmEditorPresenter.class);
39

    
40
    TransactionStatus tx = null;
41

    
42
    public AbstractCdmEditorPresenter() {
43
        super();
44
        logger.trace(this._toString() + " constructor");
45
    }
46

    
47
    @Override
48
    @EventListener
49
    public void onEditorPreSaveEvent(EditorPreSaveEvent preSaveEvent){
50

    
51
        if(tx != null){
52
            // @formatter:off
53
            // holding the TransactionStatus as state is not good design. we should change the save operation
54
            // in the EditorView so that the presenter can process the save in one method call.
55
            // Problems:
56
            // 1. the fieldGroup needs a open session and read transaction during the validation, otherwise
57
            //    LazyInitialisationExceptions occur.
58
            // 2. passing the TransactionState to the view also doesn't seem like a good idea.
59
            // @formatter:on
60
            throw new RuntimeException("Can't process a second save operation while another one is in progress.");
61
        }
62
        super.onEditorPreSaveEvent(preSaveEvent);
63

    
64
        logger.trace(this._toString() + ".onEditorPreSaveEvent - starting transaction");
65
        tx = getRepo().startTransaction(true);
66
        // merge the bean and update the fieldGroup with the merged bean, so that updating
67
        // of field values in turn of the commit are can not cause LazyInitializationExeptions
68
        // the bean still has the original values at this point
69
        logger.trace(this._toString() + ".onEditorPreSaveEvent - merging bean into session");
70
        mergedBean(preSaveEvent.getCommitEvent());
71

    
72
    }
73

    
74
    @Override
75
    @EventListener
76
    public void onEditorSaveEvent(EditorSaveEvent saveEvent){
77

    
78
        // the bean is now updated with the changes made by the user
79
        // merge the bean into the session, ...
80
        logger.trace(this._toString() + ".onEditorSaveEvent - merging bean into session");
81
        DTO bean = mergedBean(saveEvent.getCommitEvent());
82

    
83
        Type changeEventType;
84
        if(bean.getId() > 1){
85
            changeEventType = Type.MODIFIED;
86
        } else {
87
            changeEventType = Type.CREATED;
88
        }
89
        getRepo().getCommonService().saveOrUpdate(bean);
90
        getSession().flush();
91
        logger.trace(this._toString() + ".onEditorSaveEvent - session flushed");
92
        getRepo().commitTransaction(tx);
93
        tx = null;
94
        logger.trace(this._toString() + ".onEditorSaveEvent - transaction comitted");
95
        eventBus.publishEvent(new EntityChangeEvent(bean.getClass(), bean.getId(), changeEventType));
96
    }
97

    
98
    /**
99
     * Obtains the bean from the fieldGroup. If the bean is contained in the session is being updated by
100
     * doing an evict and merge. The fieldGroup is updated with the merged bean.
101
     *
102
     *
103
     * @param CommitEvent
104
     * @return The bean merged to the session or original bean in case a merge was not necessary.
105
     */
106
    private DTO mergedBean(CommitEvent commitEvent) {
107
        // using just some service to get hold of the session
108
        Session session = getSession();
109
        @SuppressWarnings("unchecked")
110
        BeanItem<DTO> itemDataSource = ((BeanFieldGroup<DTO>)commitEvent.getFieldBinder()).getItemDataSource();
111
        DTO bean = itemDataSource.getBean();
112
        if(session.contains(bean)){
113

    
114
            if(session.isOpen()){
115
                // evict bean before merge to avoid duplicate beans in same session
116
                logger.trace(this._toString() + ".mergedBean() - evict " + bean.toString());
117
                session.evict(bean);
118
            }
119
            logger.trace(this._toString() + ".mergedBean() - doing merge of" + bean.toString());
120
            @SuppressWarnings("unchecked")
121
            DTO mergedBean = (DTO) session.merge(bean);
122
            logger.trace(this._toString() + ".mergedBean() - bean after merge " + bean.toString());
123
            itemDataSource.setBean(mergedBean);
124
            return mergedBean;
125
        }
126
        return bean;
127
    }
128

    
129

    
130
    /**
131
     * @return
132
     */
133
    private Session getSession() {
134
        Session session = getRepo().getUserService().getSession();
135
        logger.trace(this._toString() + ".getSession() - session:" + session.hashCode() +", persistenceContext: " + ((SessionImplementor)session).getPersistenceContext() + " - " + session.toString());
136
        return session;
137
    }
138

    
139
    @Override
140
    protected final void saveBean(DTO bean){
141
        // blank implementation, since this is not needed in this or any sub class
142
    }
143

    
144
    private String _toString(){
145
        return this.getClass().getSimpleName() + "@" + this.hashCode();
146
    }
147

    
148
}
(1-1/8)