Project

General

Profile

Download (9.58 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 CdmEditorPresenterBase<DTO, CDM 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(CdmEditorPresenterBase.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 CdmEditorPresenterBase() {
60
        super();
61
        logger.trace(this._toString() + " constructor");
62
    }
63

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

    
66
    protected CdmAuthority newAuthorityCreated;
67

    
68
    protected CdmStore<CDM, IService<CDM>> 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
        CDM 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
        DTO dto = createDTODecorator(cdmEntitiy);
97

    
98
        return dto;
99
    }
100

    
101
    /**
102
     * @param cdmEntitiy
103
     * @return
104
     */
105
    protected abstract DTO createDTODecorator(CDM cdmEntitiy);
106

    
107
    /**
108
     * @param cdmEntitiy
109
     */
110
    @Override
111
    protected void adaptToUserPermission(DTO dto) {
112

    
113
        CDM cdmEntitiy = cdmEntity(dto);
114

    
115
        UserHelper userHelper = UserHelper.fromSession();
116
        boolean canDelte = userHelper.userHasPermission(cdmEntitiy, CRUD.DELETE);
117
        boolean canEdit = userHelper.userHasPermission(cdmEntitiy, CRUD.UPDATE);
118

    
119
        User user = userHelper.user();
120

    
121
        if(AbstractCdmPopupEditor.class.isAssignableFrom(getView().getClass())){
122
            AbstractCdmPopupEditor popupView = ((AbstractCdmPopupEditor)getView());
123

    
124
            if(!canEdit){
125
                popupView.setReadOnly(true); // never reset true to false here!
126
                logger.debug("setting editor to readonly");
127
            }
128
            if(!canDelte){
129
                popupView.withDeleteButton(false);
130
                logger.debug("removing delete button");
131
            }
132
        }
133

    
134
    }
135

    
136
    /**
137
     * @param dto
138
     * @return
139
     */
140
    protected abstract CDM cdmEntity(DTO dto);
141

    
142
    /**
143
     * @param identifier
144
     * @return
145
     */
146
    protected abstract CDM loadCdmEntity(UUID uuid);
147

    
148
    /**
149
     * Grant per entity CdmAuthority to the current user <b>for the bean which is not yet loaded</b>
150
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
151
     */
152
    protected abstract void guaranteePerEntityCRUDPermissions(UUID identifier);
153

    
154
    /**
155
     * Grant per entity CdmAuthority to the current user for the bean which is loaded
156
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
157
     */
158
     protected abstract void guaranteePerEntityCRUDPermissions(CDM bean);
159

    
160
    /**
161
     * @return
162
     */
163
    protected abstract IService<CDM> getService();
164

    
165
    @SuppressWarnings("unchecked")
166
    @Override
167
    // @EventBusListenerMethod // already annotated at super class
168
    public void onEditorPreSaveEvent(EditorPreSaveEvent preSaveEvent){
169

    
170
        if(!isFromOwnView(preSaveEvent)){
171
            return;
172
        }
173
        super.onEditorPreSaveEvent(preSaveEvent);
174
    }
175

    
176
    @SuppressWarnings("unchecked")
177
    @Override
178
    // @EventBusListenerMethod // already annotated at super class
179
    public void onEditorSaveEvent(EditorSaveEvent<DTO> saveEvent){
180

    
181
        if(!isFromOwnView(saveEvent)){
182
            return;
183
        }
184

    
185
        // the bean is now updated with the changes made by the user
186
        DTO dto = saveEvent.getBean();
187
        CDM cdmEntity = cdmEntity(dto);
188

    
189
        if(logger.isTraceEnabled()){
190
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(cdmEntity);
191
            pca.printEntityGraph(System.err);
192
            pca.printCopyEntities(System.err);
193
        }
194

    
195
        if(logger.isTraceEnabled()){
196
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(cdmEntity);
197
            pca.printEntityGraph(System.err);
198
            pca.printCopyEntities(System.err);
199
        }
200
        EntityChangeEvent changeEvent = null;
201
        try {
202
            dto = preSaveBean(dto);
203
            changeEvent = getStore().saveBean(cdmEntity, (AbstractView) getView());
204

    
205
            if(changeEvent != null){
206
                viewEventBus.publish(this, changeEvent);
207
            }
208
        } catch (HibernateException e){
209
            if(newAuthorityCreated != null){
210
                UserHelper.fromSession().removeAuthorityForCurrentUser(newAuthorityCreated);
211
            }
212
            throw e;
213
        } finally {
214
            postSaveBean(changeEvent);
215
        }
216
    }
217

    
218
    /**
219
     * This method is intended to be used for the following purposes:
220
     * <ol>
221
     *   <li>
222
     *   EditorPresenters for beans with transient properties can overwrite this method to
223
     *   update the beanItem with the changes made to the transient properties.
224
     *   This can be necessary because Vaadin MethodProperties are readonly when no setter is
225
     *   available. This can be the case with transient properties. Automatic updating
226
     *   of the property during the fieldGroup commit does not work in this case.
227
     *   Presenters, however, should <b>operate on DTOs instead, which can implement the missing setter</b>.</li>
228
     *
229
     *   <li>When modifying a bi-directional relation between two instances the user would
230
     *   need to have GrantedAuthorities for both sides of the relationship. This, however is not
231
     *   always possible. As a temporary solution the user can be granted the missing authority just
232
     *   for the time of saving the new relationship. You may also want to implement
233
     *   {@link #postSaveBean(EntityChangeEvent)} in this case.
234
     *   See {@link https://dev.e-taxonomy.eu/redmine/issues/7390 #7390}
235
     *   </li>
236
     * </ol>
237
     *
238
     */
239
    protected DTO preSaveBean(DTO bean) {
240
        // blank implementation, to be implemented by sub classes if needed
241
        return bean;
242
    }
243

    
244
    @Override
245
    protected
246
    final void saveBean(DTO bean){
247
        // blank implementation, since this is not needed in this or any sub class
248
        // see onEditorSaveEvent() instead
249
    }
250

    
251
    /**
252
     * Called after saving the DTO to the persistent storage.
253
     * This method is called in any case even if the save operation failed.
254
     * See {@link  #postSaveBean(EntityChangeEvent)}.
255
     *
256
     * @param changeEvent may be null in case of errors during the save operation
257
     */
258
    protected void postSaveBean(EntityChangeEvent changeEvent) {
259
        // blank implementation, to be implemented by sub classes if needed
260
    }
261

    
262
    @Override
263
    protected void deleteBean(DTO bean){
264
        CDM cdmEntity = cdmEntity(bean);
265
        EntityChangeEvent changeEvent = getStore().deleteBean(cdmEntity, (AbstractView) getView());
266
        if(changeEvent != null){
267
            viewEventBus.publish(this, changeEvent);
268
        }
269

    
270
    }
271

    
272
    /**
273
     * @param crud
274
     */
275
    public void setGrantsForCurrentUser(EnumSet<CRUD> crud) {
276
        this.crud = crud;
277

    
278
    }
279

    
280
    /**
281
     * {@inheritDoc}
282
     */
283
    @Override
284
    public ICdmCacher getCache() {
285
        return cache;
286
    }
287

    
288
    /**
289
     * {@inheritDoc}
290
     */
291
    @Override
292
    public void addRootEntity(CdmBase entity) {
293
        rootEntities.add(entity);
294
    }
295

    
296

    
297
    /**
298
     * {@inheritDoc}
299
     */
300
    @Override
301
    public Collection<CdmBase> getRootEntities() {
302
        return rootEntities;
303
    }
304

    
305

    
306
}
(12-12/12)