Project

General

Profile

Download (7.82 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.vaadin.mvp;
2

    
3
import java.io.Serializable;
4

    
5
import org.apache.log4j.Logger;
6
import org.hibernate.Session;
7
import org.hibernate.engine.internal.StatefulPersistenceContext;
8
import org.hibernate.engine.spi.SessionImplementor;
9
import org.springframework.beans.factory.DisposableBean;
10
import org.springframework.beans.factory.annotation.Autowired;
11
import org.springframework.beans.factory.annotation.Qualifier;
12
import org.springframework.security.core.context.SecurityContext;
13
import org.springframework.security.core.context.SecurityContextHolder;
14
import org.vaadin.spring.events.EventBus;
15

    
16
import com.vaadin.ui.Field;
17

    
18
import eu.etaxonomy.cdm.api.application.CdmRepository;
19
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction;
20
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
21
import eu.etaxonomy.vaadin.ui.navigation.NavigationManager;
22
import eu.etaxonomy.vaadin.ui.view.PopupView;
23

    
24
/**
25
 * AbstractPresenter is the base class of all presenter components. Presenter's
26
 * role is to govern the view and control the complex UI logic based on
27
 * notifications presenter receives from its view.
28
 *
29
 * @author Peter / Vaadin
30
 *
31
 * @param <V>
32
 *            type of the view this presenter governs
33
 */
34
public abstract class AbstractPresenter<V extends ApplicationView> implements Serializable, DisposableBean {
35

    
36

    
37
    private static final long serialVersionUID = 5260910510283481832L;
38

    
39
    public static final Logger logger = Logger.getLogger(AbstractPresenter.class);
40

    
41
	private V view;
42

    
43
	protected V getView() {
44
	    if(view == null){
45
            Logger.getLogger(this.getClass()).warn("CDM-VAADIN#6562: presenter " + toString() + " without view.");
46
        }
47
		return view;
48
	}
49

    
50
	@Autowired
51
	@Qualifier("cdmRepository")
52
	private CdmRepository repo;
53

    
54
	@Autowired
55
	private NavigationManager navigationManager;
56

    
57
    protected EventBus.ViewEventBus viewEventBus;
58

    
59
    @Autowired
60
    protected void setViewEventBus(EventBus.ViewEventBus viewEventBus){
61
        this.viewEventBus = viewEventBus;
62
        eventViewBusSubscription(viewEventBus);
63
    }
64

    
65
    /**
66
     * Override if needed, e.g. to skip subscription
67
     *
68
     * @param viewEventBus
69
     */
70
    protected void eventViewBusSubscription(EventBus.ViewEventBus viewEventBus){
71
            viewEventBus.subscribe(this);
72
    }
73

    
74
    public void unsubscribeFromEventBuses(){
75
        viewEventBus.unsubscribe(this);
76
    }
77

    
78

    
79
	//	protected DefaultTransactionDefinition definition = null;
80

    
81
    //	protected TransactionDefinition getTransactionDefinition(){
82
    //	    if(definition == null){
83
    //    	    definition = new DefaultTransactionDefinition();
84
    //    	    definition.setReadOnly(true);
85
    //	    }
86
    //	    return definition;
87
    //	}
88

    
89

    
90
	/**
91
	 * @return the repo
92
	 */
93
	public CdmRepository getRepo() {
94
	    return repo;
95
	}
96

    
97
	/**
98
     * @return
99
     *
100
     * FIXME is it ok to use the SecurityContextHolder or do we need to hold the context in the vaadin session?
101
     */
102
    protected SecurityContext currentSecurityContext() {
103
        return SecurityContextHolder.getContext();
104
    }
105

    
106
    /**
107
     * @return
108
     */
109
    protected Session getSession() {
110
        Session session = getRepo().getSession();
111
        if(logger.isTraceEnabled()){
112
            if(session.isOpen()){
113
                logger.trace(this._toString() + ".getSession() - session:" + session.hashCode() +", persistenceContext: " + ((SessionImplementor)session).getPersistenceContext() + " - " + session.toString());
114
            }  else {
115
                logger.trace(this._toString() + ".getSession() - session:" + session.hashCode() +"  is closed ");
116
            }
117
        }
118
        return session;
119
    }
120

    
121
    protected String _toString(){
122
        return this.getClass().getSimpleName() + "@" + this.hashCode();
123
    }
124

    
125
	/**
126
	 * Notifies the presenter that its view is initialized so that presenter can
127
	 * start its own initialization if required.
128
	 *
129
	 * @param view
130
	 */
131
	protected void init(V view) {
132
	    logger.trace(String.format("Presenter %s init()", _toString()));
133
		this.view = view;
134
		onPresenterReady();
135
	}
136

    
137

    
138
    /**
139
	 * Extending classes should overwrite this method in order to perform logic
140
	 * after presenter has finished initializing.
141
	 *
142
	 * At this point in the life cycle of the MVP the {@link AbstractView#initContent() initContent()}
143
	 * method has been executed already.
144
	 */
145
	protected void onPresenterReady() {
146
	    logger.trace(String.format("Presenter %s ready", _toString()));
147
	}
148

    
149
    /**
150
     * @return
151
     */
152
    private StatefulPersistenceContext getPersitenceContext() {
153
        return (StatefulPersistenceContext)((SessionImplementor)getSession()).getPersistenceContext();
154
    }
155

    
156
    public final void onViewEnter() {
157
	    logger.trace(String.format("%s onViewEnter()", _toString()));
158
	    handleViewEntered();
159
	}
160

    
161
	public void onViewExit() {
162
	    logger.trace(String.format("%s onViewExit()", _toString()));
163
	    handleViewExit();
164
	}
165

    
166
	/**
167
	 * Extending classes should overwrite this method to react to the event when
168
	 * user has navigated into the view that this presenter governs.
169
	 * For implementations of {@link AbstractPopupEditor AbstractPopupEditors} this is usually
170
	 * called before the data item has been bound. This order is guaranteed since popup editors
171
	 * are managed through the {@link NavigationManagerBean}
172
	 */
173
	public void handleViewEntered() {
174
	}
175

    
176
    /**
177
     * Extending classes may overwrite this method to react to
178
     * the event when user leaves the view that this presenter
179
     * governs. This method is executed before un-binding and closing the
180
     * conversation holder.
181
     */
182
    public void handleViewExit() {
183
    }
184

    
185
    /**
186
     * @return the navigationManager
187
     */
188
    public NavigationManager getNavigationManager() {
189
        return navigationManager;
190
    }
191

    
192
    /**
193
     * @param repo the repo to set
194
     */
195
    protected void setRepo(CdmRepository repo) {
196
        this.repo = repo;
197
    }
198

    
199
    /**
200
     * @param navigationManager the navigationManager to set
201
     */
202
    protected void setNavigationManager(NavigationManager navigationManager) {
203
        this.navigationManager = navigationManager;
204
    }
205

    
206
    protected boolean checkFromOwnView(AbstractEditorAction event) {
207
        return getView() != null && getView() == event.getSourceView();
208
    }
209

    
210
    /**
211
     * Opens a new PopView or editor of the type <code>popupViewClass</code> for the current view.
212
     * If the <code>event</code> is not null and if it contains a target field the newly created editor
213
     * will be registered with this field as target. Once the popup editor is being saved a
214
     * {@link eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent} will be emitted which will hold a
215
     * reference to the popup editor in the {@link eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent#getSourceView() sourceView}
216
     * property. By this reference the target field can be retrieved in editor presenters via the method
217
     * {@link AbstractEditorPresenter#boundTargetField(PopupView)}:
218
     * <p>
219
     * {@code
220
     *   BoundField targetField = boundTargetField(entityChangeEvent.getSourceView())
221
     * }
222
     * </p>
223
     * In case the target field is bound to a bean property the propertyId is available in the {@link BoundField}
224
     * object and can be used to decide on which bean property to update with the data saved in the popup editor or to
225
     * act in any other appropriate way.
226
     *
227
     * @param popupViewClass
228
     * @param event
229
     * @return
230
     */
231
    protected <T extends PopupView> T openPopupEditor(Class<T> popupViewClass, AbstractEditorAction<?> event) {
232
        Field<?> targetField = event != null? event.getTarget(): null;
233
        return getNavigationManager().showInPopup(popupViewClass, getView(), targetField);
234
    }
235

    
236
    protected boolean isFromOwnView(EntityChangeEvent event) {
237
        return event.getSourceView() != null && event.getSourceView().equals(getView());
238
    }
239

    
240
    @Override
241
    public
242
    void destroy() throws Exception {
243
        view = null;
244
    }
245

    
246
}
(8-8/13)