Project

General

Profile

Download (8.79 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 java.util.Collection;
12
import java.util.EnumSet;
13
import java.util.HashSet;
14
import java.util.UUID;
15

    
16
import org.apache.log4j.Logger;
17
import org.hibernate.HibernateException;
18

    
19
import eu.etaxonomy.cdm.api.service.IService;
20
import eu.etaxonomy.cdm.cache.CdmTransientEntityCacher;
21
import eu.etaxonomy.cdm.debug.PersistentContextAnalyzer;
22
import eu.etaxonomy.cdm.model.ICdmCacher;
23
import eu.etaxonomy.cdm.model.common.CdmBase;
24
import eu.etaxonomy.cdm.model.common.User;
25
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
26
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
27
import eu.etaxonomy.cdm.service.CdmStore;
28
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
29
import eu.etaxonomy.cdm.vaadin.permission.UserHelper;
30
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
31
import eu.etaxonomy.vaadin.mvp.event.EditorPreSaveEvent;
32
import eu.etaxonomy.vaadin.mvp.event.EditorSaveEvent;
33

    
34
/**
35
 * Provides generic save operations of modified cdm entities.
36
 *
37
 * @author a.kohlbecker
38
 * @since Apr 5, 2017
39
 *
40
 */
41
public abstract class AbstractCdmEditorPresenter<DTO extends CdmBase, V extends ApplicationView<?>> extends AbstractEditorPresenter<DTO, V>
42
    implements CachingPresenter {
43

    
44
    private static final long serialVersionUID = 2218185546277084261L;
45

    
46
    private static final Logger logger = Logger.getLogger(AbstractCdmEditorPresenter.class);
47

    
48
    /**
49
     * if not null, this CRUD set is to be used to create a CdmAuthoritiy for the base entity which will be
50
     * granted to the current use as long this grant is not assigned yet.
51
     */
52
    protected EnumSet<CRUD> crud = null;
53

    
54

    
55
    private ICdmCacher cache;
56

    
57
    private java.util.Collection<CdmBase> rootEntities = new HashSet<>();
58

    
59
    public AbstractCdmEditorPresenter() {
60
        super();
61
        logger.trace(this._toString() + " constructor");
62
    }
63

    
64
    CdmStore<DTO, IService<DTO>> store ;
65

    
66
    protected CdmAuthority newAuthorityCreated;
67

    
68
    protected CdmStore<DTO, IService<DTO>> getStore() {
69
        if(store == null){
70
            store = new CdmStore<>(getRepo(), getService());
71
        }
72
        return store;
73
    }
74

    
75
    @Override
76
    protected DTO loadBeanById(Object identifier) {
77

    
78
        DTO cdmEntitiy;
79
        if(identifier != null) {
80
            UUID uuidIdentifier = (UUID)identifier;
81
            // CdmAuthority is needed before the bean is loaded into the session.
82
            // otherwise adding the authority to the user would cause a flush
83
            cdmEntitiy = loadCdmEntity(uuidIdentifier);
84
            guaranteePerEntityCRUDPermissions(cdmEntitiy);
85
        } else {
86
            cdmEntitiy = loadCdmEntity(null);
87
            if(cdmEntitiy != null){
88
                guaranteePerEntityCRUDPermissions(cdmEntitiy);
89
            }
90
        }
91
        cache = new CdmTransientEntityCacher(this);
92
        // need to use load but put see #7214
93
        cdmEntitiy = cache.load(cdmEntitiy);
94
        addRootEntity(cdmEntitiy);
95

    
96
        return cdmEntitiy;
97
    }
98

    
99
    /**
100
     * @param cdmEntitiy
101
     */
102
    @Override
103
    protected void adaptToUserPermission(DTO cdmEntitiy) {
104
        UserHelper userHelper = UserHelper.fromSession();
105
        boolean canDelte = userHelper.userHasPermission(cdmEntitiy, CRUD.DELETE);
106
        boolean canEdit = userHelper.userHasPermission(cdmEntitiy, CRUD.UPDATE);
107

    
108
        User user = userHelper.user();
109

    
110
        if(AbstractCdmPopupEditor.class.isAssignableFrom(getView().getClass())){
111
            AbstractCdmPopupEditor popupView = ((AbstractCdmPopupEditor)getView());
112

    
113
            if(!canEdit){
114
                popupView.setReadOnly(true); // never reset true to false here!
115
                logger.debug("setting editor to readonly");
116
            }
117
            if(!canDelte){
118
                popupView.withDeleteButton(false);
119
                logger.debug("removing delete button");
120
            }
121
        }
122

    
123
    }
124

    
125
    /**
126
     * @param identifier
127
     * @return
128
     */
129
    protected abstract DTO loadCdmEntity(UUID uuid);
130

    
131
    /**
132
     * Grant per entity CdmAuthority to the current user <b>for the bean which is not yet loaded</b>
133
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
134
     */
135
    protected abstract void guaranteePerEntityCRUDPermissions(UUID identifier);
136

    
137
    /**
138
     * Grant per entity CdmAuthority to the current user for the bean which is loaded
139
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
140
     */
141
     protected abstract void guaranteePerEntityCRUDPermissions(DTO bean);
142

    
143
    /**
144
     * @return
145
     */
146
    protected abstract IService<DTO> getService();
147

    
148
    @SuppressWarnings("unchecked")
149
    @Override
150
    // @EventBusListenerMethod // already annotated at super class
151
    public void onEditorPreSaveEvent(EditorPreSaveEvent preSaveEvent){
152

    
153
        if(!isFromOwnView(preSaveEvent)){
154
            return;
155
        }
156
        super.onEditorPreSaveEvent(preSaveEvent);
157
    }
158

    
159
    @SuppressWarnings("unchecked")
160
    @Override
161
    // @EventBusListenerMethod // already annotated at super class
162
    public void onEditorSaveEvent(EditorSaveEvent<DTO> saveEvent){
163

    
164
        if(!isFromOwnView(saveEvent)){
165
            return;
166
        }
167

    
168
        // the bean is now updated with the changes made by the user
169
        DTO bean = saveEvent.getBean();
170

    
171
        if(logger.isTraceEnabled()){
172
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(bean);
173
            pca.printEntityGraph(System.err);
174
            pca.printCopyEntities(System.err);
175
        }
176
        bean = handleTransientProperties(bean);
177

    
178
        if(logger.isTraceEnabled()){
179
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(bean);
180
            pca.printEntityGraph(System.err);
181
            pca.printCopyEntities(System.err);
182
        }
183
        try {
184
            EntityChangeEvent changeEvent = getStore().saveBean(bean, (AbstractView) getView());
185

    
186
            if(changeEvent != null){
187
                viewEventBus.publish(this, changeEvent);
188
            }
189
        } catch (HibernateException e){
190
            if(newAuthorityCreated != null){
191
                UserHelper.fromSession().removeAuthorityForCurrentUser(newAuthorityCreated);
192
            }
193
            throw e;
194
        }
195
    }
196

    
197
    /**
198
     * EditorPresenters for beans with transient properties should overwrite this method to
199
     * update the beanItem with the changes made to the transient properties.
200
     * <p>
201
     * This is necessary because Vaadin MethodProperties are readonly when no setter is
202
     * available. This can be the case with transient properties. Automatic updating
203
     * of the property during the fieldGroup commit does not work in this case.
204
     *
205
     * @deprecated editors should operate on DTOs instead, remove this method if unused.
206
     */
207
    @Deprecated
208
    protected DTO handleTransientProperties(DTO bean) {
209
        // no need to handle transient properties in the generic case
210
        return bean;
211
    }
212

    
213
//    @Override
214
//    protected DTO prepareAsFieldGroupDataSource(DTO bean){
215
//        DTO mergedBean = getStore().mergedBean(bean);
216
//        // DTO mergedBean = bean;
217
//        return mergedBean;
218
//    }
219

    
220
    /**
221
     * If the bean is contained in the session it is being updated by
222
     * doing an evict and merge. The fieldGroup is updated with the merged bean.
223
     *
224
     * @param bean
225
     *
226
     * @return The bean merged to the session or original bean in case a merge was not necessary.
227
     */
228
    private DTO mergedBean(DTO bean) {
229
        DTO mergedBean = getStore().mergedBean(bean);
230
        ((AbstractPopupEditor<DTO, AbstractCdmEditorPresenter<DTO, V>>)getView()).updateItemDataSource(mergedBean);
231
        return mergedBean;
232

    
233
    }
234

    
235
    @Override
236
    protected
237
    final void saveBean(DTO bean){
238
        // blank implementation, since this is not needed in this or any sub class
239
        // see onEditorSaveEvent() instead
240
    }
241

    
242
    @Override
243
    protected void deleteBean(DTO bean){
244
        EntityChangeEvent changeEvent = getStore().deleteBean(bean, (AbstractView) getView());
245
        if(changeEvent != null){
246
            viewEventBus.publish(this, changeEvent);
247
        }
248

    
249
    }
250

    
251
    /**
252
     * @param crud
253
     */
254
    public void setGrantsForCurrentUser(EnumSet<CRUD> crud) {
255
        this.crud = crud;
256

    
257
    }
258

    
259
    /**
260
     * {@inheritDoc}
261
     */
262
    @Override
263
    public ICdmCacher getCache() {
264
        return cache;
265
    }
266

    
267
    /**
268
     * {@inheritDoc}
269
     */
270
    @Override
271
    public void addRootEntity(CdmBase entity) {
272
        rootEntities.add(entity);
273
    }
274

    
275

    
276
    /**
277
     * {@inheritDoc}
278
     */
279
    @Override
280
    public Collection<CdmBase> getRootEntities() {
281
        return rootEntities;
282
    }
283

    
284

    
285
}
(1-1/9)