Project

General

Profile

Download (10.9 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
import org.springframework.beans.factory.annotation.Autowired;
19

    
20
import eu.etaxonomy.cdm.api.service.IService;
21
import eu.etaxonomy.cdm.api.utility.UserHelper;
22
import eu.etaxonomy.cdm.cache.CdmTransientEntityAndUuidCacher;
23
import eu.etaxonomy.cdm.debug.PersistentContextAnalyzer;
24
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
25
import eu.etaxonomy.cdm.model.common.CdmBase;
26
import eu.etaxonomy.cdm.model.common.User;
27
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
28
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
29
import eu.etaxonomy.cdm.service.CdmBeanItemContainerFactory;
30
import eu.etaxonomy.cdm.service.CdmFilterablePagingProviderFactory;
31
import eu.etaxonomy.cdm.service.CdmStore;
32
import eu.etaxonomy.cdm.service.UserHelperAccess;
33
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
34
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
35
import eu.etaxonomy.vaadin.mvp.event.EditorPreSaveEvent;
36
import eu.etaxonomy.vaadin.mvp.event.EditorSaveEvent;
37

    
38
/**
39
 * Provides generic save operations of modified cdm entities.
40
 *
41
 * @author a.kohlbecker
42
 * @since Apr 5, 2017
43
 *
44
 */
45
public abstract class CdmEditorPresenterBase<DTO, CDM extends CdmBase, V extends ApplicationView<?>> extends AbstractEditorPresenter<DTO, V>
46
    implements CachingPresenter {
47

    
48
    private static final long serialVersionUID = 2218185546277084261L;
49

    
50
    private static final Logger logger = Logger.getLogger(CdmEditorPresenterBase.class);
51

    
52
    protected BeanInstantiator<DTO> beanInstantiator = null;
53

    
54
    @Autowired
55
    protected CdmBeanItemContainerFactory cdmBeanItemContainerFactory;
56

    
57
    @Autowired
58
    protected CdmFilterablePagingProviderFactory pagingProviderFactory;
59

    
60
    /**
61
     * @param beanInstantiator the beanInstantiator to set
62
     */
63
    public void setBeanInstantiator(BeanInstantiator<DTO> beanInstantiator) {
64
        this.beanInstantiator = beanInstantiator;
65
    }
66

    
67

    
68
    protected DTO createNewBean() {
69
        if(this.beanInstantiator != null){
70
            return beanInstantiator.createNewBean();
71
        }
72
        return defaultBeanInstantiator().createNewBean();
73
    }
74

    
75
    /**
76
     * @return
77
     */
78
    protected abstract BeanInstantiator<DTO> defaultBeanInstantiator();
79

    
80
    /**
81
     * if not null, this CRUD set is to be used to create a CdmAuthoritiy for the base entity which will be
82
     * granted to the current use as long this grant is not assigned yet.
83
     */
84
    protected EnumSet<CRUD> crud = null;
85

    
86

    
87
    private ICdmEntityUuidCacher cache;
88

    
89
    private java.util.Collection<CdmBase> rootEntities = new HashSet<>();
90

    
91
    public CdmEditorPresenterBase() {
92
        super();
93
        logger.trace(this._toString() + " constructor");
94
    }
95

    
96
    CdmStore<CDM, IService<CDM>> store ;
97

    
98
    protected CdmAuthority newAuthorityCreated;
99

    
100

    
101
    protected CdmStore<CDM, IService<CDM>> getStore() {
102
        if(store == null){
103
            store = new CdmStore<>(getRepo(), getService());
104
        }
105
        return store;
106
    }
107

    
108
    @Override
109
    protected DTO loadBeanById(Object identifier) {
110

    
111
        CDM cdmEntitiy;
112
        if(identifier != null) {
113
            UUID uuidIdentifier = (UUID)identifier;
114
            // CdmAuthority is needed before the bean is loaded into the session.
115
            // otherwise adding the authority to the user would cause a flush
116
            cdmEntitiy = loadCdmEntity(uuidIdentifier);
117
            guaranteePerEntityCRUDPermissions(cdmEntitiy);
118
        } else {
119
            cdmEntitiy = loadCdmEntity(null);
120
            if(cdmEntitiy != null){
121
                guaranteePerEntityCRUDPermissions(cdmEntitiy);
122
            }
123
        }
124
        cache = new CdmTransientEntityAndUuidCacher(this);
125
        // need to use load but put see #7214
126
        cdmEntitiy = cache.load(cdmEntitiy);
127
        addRootEntity(cdmEntitiy);
128

    
129
        DTO dto = createDTODecorator(cdmEntitiy);
130

    
131
        return dto;
132
    }
133

    
134
    /**
135
     * @param cdmEntitiy
136
     * @return
137
     */
138
    protected abstract DTO createDTODecorator(CDM cdmEntitiy);
139

    
140
    /**
141
     * @param cdmEntitiy
142
     */
143
    @Override
144
    protected void adaptToUserPermission(DTO dto) {
145

    
146
        CDM cdmEntitiy = cdmEntity(dto);
147

    
148
        UserHelper userHelper = UserHelperAccess.userHelper();
149
        boolean canDelte = userHelper.userHasPermission(cdmEntitiy, CRUD.DELETE);
150
        boolean canEdit = userHelper.userHasPermission(cdmEntitiy, CRUD.UPDATE);
151

    
152
        User user = userHelper.user();
153

    
154
        if(AbstractCdmPopupEditor.class.isAssignableFrom(getView().getClass())){
155
            AbstractCdmPopupEditor popupView = ((AbstractCdmPopupEditor)getView());
156

    
157
            if(cdmEntitiy.isPersited() && !canEdit){
158
                popupView.setReadOnly(true); // never reset true to false here!
159
                logger.debug("setting editor to readonly");
160
            }
161
            if(!cdmEntitiy.isPersited() || !canDelte){
162
                popupView.withDeleteButton(false);
163
                logger.debug("removing delete button");
164
            }
165
        }
166

    
167
    }
168

    
169
    /**
170
     * @param dto
171
     * @return
172
     */
173
    protected abstract CDM cdmEntity(DTO dto);
174

    
175
    /**
176
     * @param identifier
177
     * @return
178
     */
179
    protected abstract CDM loadCdmEntity(UUID uuid);
180

    
181
    /**
182
     * Grant per entity CdmAuthority to the current user <b>for the bean which is not yet loaded</b>
183
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
184
     */
185
    protected abstract void guaranteePerEntityCRUDPermissions(UUID identifier);
186

    
187
    /**
188
     * Grant per entity CdmAuthority to the current user for the bean which is loaded
189
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
190
     */
191
     protected abstract void guaranteePerEntityCRUDPermissions(CDM bean);
192

    
193
    /**
194
     * @return
195
     */
196
    protected abstract IService<CDM> getService();
197

    
198
    @SuppressWarnings("unchecked")
199
    @Override
200
    // @EventBusListenerMethod // already annotated at super class
201
    public void onEditorPreSaveEvent(EditorPreSaveEvent preSaveEvent){
202

    
203
        if(!isFromOwnView(preSaveEvent)){
204
            return;
205
        }
206
        super.onEditorPreSaveEvent(preSaveEvent);
207
    }
208

    
209
    @Override
210
    // @EventBusListenerMethod // already annotated at super class
211
    public void onEditorSaveEvent(EditorSaveEvent<DTO> saveEvent){
212

    
213
        if(!isFromOwnView(saveEvent)){
214
            return;
215
        }
216

    
217
        // the bean is now updated with the changes made by the user
218
        DTO dto = saveEvent.getBean();
219
        CDM cdmEntity = cdmEntity(dto);
220

    
221
        if(logger.isTraceEnabled()){
222
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(cdmEntity);
223
            pca.printEntityGraph(System.err);
224
            pca.printCopyEntities(System.err);
225
        }
226

    
227
        if(logger.isTraceEnabled()){
228
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(cdmEntity);
229
            pca.printEntityGraph(System.err);
230
            pca.printCopyEntities(System.err);
231
        }
232
        EntityChangeEvent<?> changeEvent = null;
233
        try {
234
            dto = preSaveBean(dto);
235
            changeEvent = getStore().saveBean(cdmEntity, (AbstractView<?>) getView());
236

    
237
            if(changeEvent != null){
238
                viewEventBus.publish(this, changeEvent);
239
            }
240
        } catch (HibernateException e){
241
            if(newAuthorityCreated != null){
242
                UserHelperAccess.userHelper().removeAuthorityForCurrentUser(newAuthorityCreated);
243
            }
244
            throw e;
245
        } finally {
246
            postSaveBean(changeEvent);
247
        }
248
    }
249

    
250
    /**
251
     * This method is intended to be used for the following purposes:
252
     * <ol>
253
     *   <li>
254
     *   EditorPresenters for beans with transient properties can overwrite this method to
255
     *   update the beanItem with the changes made to the transient properties.
256
     *   This can be necessary because Vaadin MethodProperties are readonly when no setter is
257
     *   available. This can be the case with transient properties. Automatic updating
258
     *   of the property during the fieldGroup commit does not work in this case.
259
     *   Presenters, however, should <b>operate on DTOs instead, which can implement the missing setter</b>.</li>
260
     *
261
     *   <li>When modifying a bi-directional relation between two instances the user would
262
     *   need to have GrantedAuthorities for both sides of the relationship. This, however is not
263
     *   always possible. As a temporary solution the user can be granted the missing authority just
264
     *   for the time of saving the new relationship. You may also want to implement
265
     *   {@link #postSaveBean(EntityChangeEvent)} in this case.
266
     *   See {@link https://dev.e-taxonomy.eu/redmine/issues/7390 #7390}
267
     *   </li>
268
     * </ol>
269
     *
270
     */
271
    protected DTO preSaveBean(DTO bean) {
272
        // blank implementation, to be implemented by sub classes if needed
273
        return bean;
274
    }
275

    
276
    @Override
277
    protected
278
    final void saveBean(DTO bean){
279
        // blank implementation, since this is not needed in this or any sub class
280
        // see onEditorSaveEvent() instead
281
    }
282

    
283
    /**
284
     * Called after saving the DTO to the persistent storage.
285
     * This method is called in any case even if the save operation failed.
286
     * See {@link  #postSaveBean(EntityChangeEvent)}.
287
     *
288
     * @param changeEvent may be null in case of errors during the save operation
289
     */
290
    protected void postSaveBean(EntityChangeEvent changeEvent) {
291
        // blank implementation, to be implemented by sub classes if needed
292
    }
293

    
294
    @Override
295
    protected void deleteBean(DTO bean){
296
        CDM cdmEntity = cdmEntity(bean);
297
        EntityChangeEvent changeEvent = getStore().deleteBean(cdmEntity, (AbstractView) getView());
298
        if(changeEvent != null){
299
            viewEventBus.publish(this, changeEvent);
300
        }
301
    }
302

    
303

    
304
    /**
305
     * @param crud
306
     */
307
    public void setGrantsForCurrentUser(EnumSet<CRUD> crud) {
308
        this.crud = crud;
309

    
310
    }
311

    
312
    /**
313
     * {@inheritDoc}
314
     */
315
    @Override
316
    public ICdmEntityUuidCacher getCache() {
317
        return cache;
318
    }
319

    
320
    /**
321
     * {@inheritDoc}
322
     */
323
    @Override
324
    public void addRootEntity(CdmBase entity) {
325
        rootEntities.add(entity);
326
    }
327

    
328

    
329
    /**
330
     * {@inheritDoc}
331
     */
332
    @Override
333
    public Collection<CdmBase> getRootEntities() {
334
        return rootEntities;
335
    }
336

    
337

    
338
    /**
339
     * {@inheritDoc}
340
     */
341
    @Override
342
    public void destroy() throws Exception {
343
        super.destroy();
344
        disposeCache();
345
    }
346

    
347
    /**
348
     * {@inheritDoc}
349
     */
350
    @Override
351
    public void disposeCache() {
352
        cache.dispose();
353
    }
354
}
(13-13/14)