Project

General

Profile

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

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

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

    
46
    private static final long serialVersionUID = 2218185546277084261L;
47

    
48
    private static final Logger logger = Logger.getLogger(CdmEditorPresenterBase.class);
49

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

    
56

    
57
    private ICdmCacher cache;
58

    
59
    private java.util.Collection<CdmBase> rootEntities = new HashSet<>();
60

    
61
    public CdmEditorPresenterBase() {
62
        super();
63
        logger.trace(this._toString() + " constructor");
64
    }
65

    
66
    CdmStore<CDM, IService<CDM>> store ;
67

    
68
    protected CdmAuthority newAuthorityCreated;
69

    
70
    @Autowired
71
    protected CdmFilterablePagingProviderFactory pagingProviderFactory;
72

    
73
    protected CdmStore<CDM, IService<CDM>> getStore() {
74
        if(store == null){
75
            store = new CdmStore<>(getRepo(), getService());
76
        }
77
        return store;
78
    }
79

    
80
    @Override
81
    protected DTO loadBeanById(Object identifier) {
82

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

    
101
        DTO dto = createDTODecorator(cdmEntitiy);
102

    
103
        return dto;
104
    }
105

    
106
    /**
107
     * @param cdmEntitiy
108
     * @return
109
     */
110
    protected abstract DTO createDTODecorator(CDM cdmEntitiy);
111

    
112
    /**
113
     * @param cdmEntitiy
114
     */
115
    @Override
116
    protected void adaptToUserPermission(DTO dto) {
117

    
118
        CDM cdmEntitiy = cdmEntity(dto);
119

    
120
        VaadinUserHelper userHelper = VaadinUserHelper.fromSession();
121
        boolean canDelte = userHelper.userHasPermission(cdmEntitiy, CRUD.DELETE);
122
        boolean canEdit = userHelper.userHasPermission(cdmEntitiy, CRUD.UPDATE);
123

    
124
        User user = userHelper.user();
125

    
126
        if(AbstractCdmPopupEditor.class.isAssignableFrom(getView().getClass())){
127
            AbstractCdmPopupEditor popupView = ((AbstractCdmPopupEditor)getView());
128

    
129
            if(!canEdit){
130
                popupView.setReadOnly(true); // never reset true to false here!
131
                logger.debug("setting editor to readonly");
132
            }
133
            if(!canDelte){
134
                popupView.withDeleteButton(false);
135
                logger.debug("removing delete button");
136
            }
137
        }
138

    
139
    }
140

    
141
    /**
142
     * @param dto
143
     * @return
144
     */
145
    protected abstract CDM cdmEntity(DTO dto);
146

    
147
    /**
148
     * @param identifier
149
     * @return
150
     */
151
    protected abstract CDM loadCdmEntity(UUID uuid);
152

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

    
159
    /**
160
     * Grant per entity CdmAuthority to the current user for the bean which is loaded
161
     * into the editor. The <code>CRUD</code> to be granted are stored in the <code>crud</code> field.
162
     */
163
     protected abstract void guaranteePerEntityCRUDPermissions(CDM bean);
164

    
165
    /**
166
     * @return
167
     */
168
    protected abstract IService<CDM> getService();
169

    
170
    @SuppressWarnings("unchecked")
171
    @Override
172
    // @EventBusListenerMethod // already annotated at super class
173
    public void onEditorPreSaveEvent(EditorPreSaveEvent preSaveEvent){
174

    
175
        if(!isFromOwnView(preSaveEvent)){
176
            return;
177
        }
178
        super.onEditorPreSaveEvent(preSaveEvent);
179
    }
180

    
181
    @Override
182
    // @EventBusListenerMethod // already annotated at super class
183
    public void onEditorSaveEvent(EditorSaveEvent<DTO> saveEvent){
184

    
185
        if(!isFromOwnView(saveEvent)){
186
            return;
187
        }
188

    
189
        // the bean is now updated with the changes made by the user
190
        DTO dto = saveEvent.getBean();
191
        CDM cdmEntity = cdmEntity(dto);
192

    
193
        if(logger.isTraceEnabled()){
194
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(cdmEntity);
195
            pca.printEntityGraph(System.err);
196
            pca.printCopyEntities(System.err);
197
        }
198

    
199
        if(logger.isTraceEnabled()){
200
            PersistentContextAnalyzer pca = new PersistentContextAnalyzer(cdmEntity);
201
            pca.printEntityGraph(System.err);
202
            pca.printCopyEntities(System.err);
203
        }
204
        EntityChangeEvent<?> changeEvent = null;
205
        try {
206
            dto = preSaveBean(dto);
207
            changeEvent = getStore().saveBean(cdmEntity, (AbstractView<?>) getView());
208

    
209
            if(changeEvent != null){
210
                viewEventBus.publish(this, changeEvent);
211
            }
212
        } catch (HibernateException e){
213
            if(newAuthorityCreated != null){
214
                VaadinUserHelper.fromSession().removeAuthorityForCurrentUser(newAuthorityCreated);
215
            }
216
            throw e;
217
        } finally {
218
            postSaveBean(changeEvent);
219
        }
220
    }
221

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

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

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

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

    
274
    }
275

    
276
    /**
277
     * @param crud
278
     */
279
    public void setGrantsForCurrentUser(EnumSet<CRUD> crud) {
280
        this.crud = crud;
281

    
282
    }
283

    
284
    /**
285
     * {@inheritDoc}
286
     */
287
    @Override
288
    public ICdmCacher getCache() {
289
        return cache;
290
    }
291

    
292
    /**
293
     * {@inheritDoc}
294
     */
295
    @Override
296
    public void addRootEntity(CdmBase entity) {
297
        rootEntities.add(entity);
298
    }
299

    
300

    
301
    /**
302
     * {@inheritDoc}
303
     */
304
    @Override
305
    public Collection<CdmBase> getRootEntities() {
306
        return rootEntities;
307
    }
308

    
309

    
310
}
(13-13/13)