Project

General

Profile

Download (6.21 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
import eu.etaxonomy.vaadin.mvp.event.EditorViewEvent;
27

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

    
37
    private static final long serialVersionUID = 2218185546277084261L;
38

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

    
41
    TransactionStatus tx = null;
42

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

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

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

    
75
    }
76

    
77
    @Override
78
    @EventListener
79
    public void onEditorSaveEvent(EditorSaveEvent saveEvent){
80
        if(!isResponsible(saveEvent)){
81
            return;
82
        }
83
        // the bean is now updated with the changes made by the user
84
        // merge the bean into the session, ...
85
        logger.trace(this._toString() + ".onEditorSaveEvent - merging bean into session");
86
        DTO bean = mergedBean(saveEvent.getCommitEvent());
87

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

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

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

    
134

    
135
    /**
136
     * @return
137
     */
138
    private Session getSession() {
139
        Session session = getRepo().getUserService().getSession();
140
        logger.trace(this._toString() + ".getSession() - session:" + session.hashCode() +", persistenceContext: " + ((SessionImplementor)session).getPersistenceContext() + " - " + session.toString());
141
        return session;
142
    }
143

    
144
    /**
145
     * see  #6673 (https://dev.e-taxonomy.eu/redmine/issues/6673)
146
     * @param event
147
     * @return
148
     */
149
    private boolean isResponsible(EditorViewEvent event){
150
        return event.getView().getClass().equals(getViewType());
151
    }
152

    
153
    @Override
154
    protected final void saveBean(DTO bean){
155
        // blank implementation, since this is not needed in this or any sub class
156
    }
157

    
158
    private String _toString(){
159
        return this.getClass().getSimpleName() + "@" + this.hashCode();
160
    }
161

    
162
}
(1-1/8)