Revision 2f02081c
Added by Andreas Kohlbecker over 6 years ago
src/main/java/eu/etaxonomy/vaadin/mvp/AbstractPresenter.java | ||
---|---|---|
4 | 4 |
|
5 | 5 |
import org.apache.log4j.Logger; |
6 | 6 |
import org.hibernate.Session; |
7 |
import org.hibernate.engine.internal.StatefulPersistenceContext; |
|
7 | 8 |
import org.hibernate.engine.spi.SessionImplementor; |
8 | 9 |
import org.springframework.beans.factory.annotation.Autowired; |
9 | 10 |
import org.springframework.beans.factory.annotation.Qualifier; |
10 | 11 |
import org.springframework.security.core.context.SecurityContext; |
11 | 12 |
import org.springframework.security.core.context.SecurityContextHolder; |
12 |
import org.springframework.transaction.IllegalTransactionStateException; |
|
13 |
import org.springframework.transaction.TransactionDefinition; |
|
14 |
import org.springframework.transaction.support.DefaultTransactionDefinition; |
|
15 |
|
|
16 |
import com.vaadin.server.ServletPortletHelper; |
|
17 |
import com.vaadin.server.VaadinRequest; |
|
18 |
import com.vaadin.server.VaadinService; |
|
19 |
import com.vaadin.server.VaadinSession; |
|
20 |
import com.vaadin.ui.UI; |
|
21 | 13 |
|
22 | 14 |
import eu.etaxonomy.cdm.api.application.CdmRepository; |
23 |
import eu.etaxonomy.cdm.vaadin.server.CdmSpringVaadinServletService; |
|
24 |
import eu.etaxonomy.cdm.vaadin.server.RequestStartListener; |
|
25 |
import eu.etaxonomy.cdm.vaadin.session.IntraViewConversationDirector; |
|
26 |
import eu.etaxonomy.cdm.vaadin.session.ViewScopeConversationHolder; |
|
27 | 15 |
import eu.etaxonomy.vaadin.ui.navigation.NavigationManager; |
28 | 16 |
import eu.etaxonomy.vaadin.ui.navigation.NavigationManagerBean; |
29 | 17 |
|
... | ... | |
37 | 25 |
* @param <V> |
38 | 26 |
* type of the view this presenter governs |
39 | 27 |
*/ |
40 |
public abstract class AbstractPresenter<V extends ApplicationView> implements Serializable, IntraViewConversationDirector, RequestStartListener {
|
|
28 |
public abstract class AbstractPresenter<V extends ApplicationView> implements Serializable { |
|
41 | 29 |
|
42 | 30 |
|
43 | 31 |
private static final long serialVersionUID = 5260910510283481832L; |
... | ... | |
61 | 49 |
@Autowired |
62 | 50 |
private NavigationManager navigationManager; |
63 | 51 |
|
64 |
private ViewScopeConversationHolder conversationHolder; |
|
65 |
|
|
66 |
protected DefaultTransactionDefinition definition = null; |
|
67 |
|
|
68 |
protected boolean conversationBound; |
|
69 |
|
|
70 |
@Autowired |
|
71 |
private void setConversationHolder(ViewScopeConversationHolder conversationHolder){ |
|
72 |
this.conversationHolder = conversationHolder; |
|
73 |
this.conversationHolder.setDefinition(getTransactionDefinition()); |
|
74 |
} |
|
75 |
|
|
76 |
protected TransactionDefinition getTransactionDefinition(){ |
|
77 |
if(definition == null){ |
|
78 |
definition = new DefaultTransactionDefinition(); |
|
79 |
definition.setReadOnly(true); |
|
80 |
} |
|
81 |
return definition; |
|
82 |
} |
|
83 | 52 |
|
53 |
// protected DefaultTransactionDefinition definition = null; |
|
84 | 54 |
|
55 |
// protected TransactionDefinition getTransactionDefinition(){ |
|
56 |
// if(definition == null){ |
|
57 |
// definition = new DefaultTransactionDefinition(); |
|
58 |
// definition.setReadOnly(true); |
|
59 |
// } |
|
60 |
// return definition; |
|
61 |
// } |
|
85 | 62 |
|
86 | 63 |
|
87 | 64 |
/** |
88 | 65 |
* @return the repo |
89 | 66 |
*/ |
90 | 67 |
public CdmRepository getRepo() { |
91 |
if(!conversationBound){ |
|
92 |
// this is the central access point for getting access to the service layer. |
|
93 |
// In case the presenter needs access to the repository, it most probably will use |
|
94 |
// a service, so it is a good idea to bind the conversation at this point. |
|
95 |
bindConversation(); |
|
96 |
} |
|
97 | 68 |
return repo; |
98 | 69 |
} |
99 | 70 |
|
... | ... | |
110 | 81 |
* @return |
111 | 82 |
*/ |
112 | 83 |
protected Session getSession() { |
113 |
Session session = conversationHolder.getSession();
|
|
84 |
Session session = getRepo().getSession();
|
|
114 | 85 |
logger.trace(this._toString() + ".getSession() - session:" + session.hashCode() +", persistenceContext: " + ((SessionImplementor)session).getPersistenceContext() + " - " + session.toString()); |
115 | 86 |
return session; |
116 | 87 |
} |
... | ... | |
125 | 96 |
* |
126 | 97 |
* @param view |
127 | 98 |
*/ |
128 |
protected final void init(V view) {
|
|
99 |
protected void init(V view) { |
|
129 | 100 |
logger.trace(String.format("Presenter %s init()", _toString())); |
130 | 101 |
this.view = view; |
131 |
// bind the conversation to the thread of the first request send to the according View |
|
132 |
// all other requests are handled in onRequestStart() |
|
133 |
// logger.trace(String.format(">>>>> %s init() bind()", _toString())); |
|
134 |
ensureBoundConversation(); |
|
135 |
// register as request start and end listener |
|
136 |
VaadinService service = UI.getCurrent().getSession().getService(); |
|
137 |
if(service instanceof CdmSpringVaadinServletService){ |
|
138 |
logger.trace(String.format("~~~~~ %s register as request listener", _toString())); |
|
139 |
((CdmSpringVaadinServletService)service).addRequestEndListener(this); |
|
140 |
if(logger.isTraceEnabled()){ |
|
141 |
((CdmSpringVaadinServletService)service).addRequestStartListener(this); |
|
142 |
} |
|
143 |
} else { |
|
144 |
throw new RuntimeException("Using the CdmSpringVaadinServletService is required for proper per view conversation handling"); |
|
145 |
} |
|
146 | 102 |
onPresenterReady(); |
147 | 103 |
} |
148 | 104 |
|
149 |
/** |
|
150 |
* Returns <code>true</code> for: |
|
151 |
* <ul> |
|
152 |
* <li>..</li> |
|
153 |
* <ul> |
|
154 |
* |
|
155 |
* Return <code>false</code> for: |
|
156 |
* |
|
157 |
* <ul> |
|
158 |
* <li>UILD request in a existing view, like clicking on a button</li> |
|
159 |
* <ul> |
|
160 |
* |
|
161 |
* @return |
|
162 |
protected boolean isActiveView(){ |
|
163 |
return UI.getCurrent() != null && getView() != null && getView() == navigationManager.getCurrentView(); |
|
164 |
} |
|
165 |
*/ |
|
166 |
|
|
167 |
/** |
|
168 |
* |
|
169 |
*/ |
|
170 |
protected void bindConversation() { |
|
171 |
logger.trace(String.format(">>>>> %s bind()", _toString())); |
|
172 |
conversationHolder.bind(); |
|
173 |
conversationBound = true; |
|
174 |
} |
|
175 |
|
|
176 |
@Override |
|
177 |
public void ensureBoundConversation() { |
|
178 |
if(!conversationBound){ |
|
179 |
bindConversation(); |
|
180 |
} |
|
181 |
if(!conversationHolder.isTransactionActive()){ |
|
182 |
logger.trace(String.format(">> %s starting transaction ", _toString())); |
|
183 |
conversationHolder.startTransaction(); |
|
184 |
} |
|
185 |
} |
|
186 |
|
|
187 |
/** |
|
188 |
* |
|
189 |
*/ |
|
190 |
protected void unbindConversation() { |
|
191 |
logger.trace(String.format("<<<<< %s unbind()", _toString())); |
|
192 |
conversationHolder.unbind(); |
|
193 |
// FIXME conversationHolder.isTransactionActive() always returns true |
|
194 |
// see https://dev.e-taxonomy.eu/redmine/issues/6780 |
|
195 |
if(false && conversationHolder.isTransactionActive()){ |
|
196 |
logger.trace(String.format("<< %s comitting transaction ", _toString())); |
|
197 |
try{ |
|
198 |
conversationHolder.commit(false); |
|
199 |
} catch (IllegalTransactionStateException | IllegalStateException e){ |
|
200 |
// log this exception, but stop from propagating |
|
201 |
// FIXME remove this catch once https://dev.e-taxonomy.eu/redmine/issues/6780 is fixed |
|
202 |
logger.error(e.getMessage()); |
|
203 |
} |
|
204 |
} |
|
205 |
conversationBound = false; |
|
206 |
} |
|
207 | 105 |
|
208 | 106 |
/** |
209 | 107 |
* Extending classes should overwrite this method in order to perform logic |
... | ... | |
217 | 115 |
} |
218 | 116 |
|
219 | 117 |
/** |
220 |
* <b>ONLY USED FOR LOGGING</b> when Level==TRACE |
|
221 |
* {@inheritDoc} |
|
222 |
*/ |
|
223 |
@Override |
|
224 |
public void onRequestStart(VaadinRequest request){ |
|
225 |
|
|
226 |
if( ! requestNeedsConversation(request) ){ |
|
227 |
// ignore hartbeat, fileupload, push etc |
|
228 |
logger.trace("ignoring request:" + request.getPathInfo()); |
|
229 |
return; |
|
230 |
} |
|
231 |
logger.trace("onRequestStart() " + request.getPathInfo() + " " + _toString()); |
|
232 |
} |
|
233 |
|
|
234 |
/** |
|
235 |
* @param request |
|
236 | 118 |
* @return |
237 | 119 |
*/ |
238 |
protected boolean requestNeedsConversation(VaadinRequest request) { |
|
239 |
return !( |
|
240 |
ServletPortletHelper.isAppRequest(request) // includes published file request |
|
241 |
|| ServletPortletHelper.isFileUploadRequest(request) |
|
242 |
|| ServletPortletHelper.isHeartbeatRequest(request) |
|
243 |
|| ServletPortletHelper.isPushRequest(request) |
|
244 |
); |
|
245 |
} |
|
246 |
|
|
247 |
@Override |
|
248 |
public void onRequestEnd(VaadinRequest request, VaadinSession session){ |
|
249 |
|
|
250 |
if( ! requestNeedsConversation(request) ){ |
|
251 |
// ignore hartbeat, fileupload, push etc |
|
252 |
logger.trace("ignoring request:" + request.getPathInfo()); |
|
253 |
return; |
|
254 |
} |
|
255 |
|
|
256 |
// always unbind at the end of a request to clean up the threadLocal variables in the |
|
257 |
// TransactionManager. This is crucial since applications containers manage threads in a pool |
|
258 |
// and the recycled threads may still have a reference to a SessionHolder from the processing |
|
259 |
// of a former request |
|
260 |
logger.trace("onRequestEnd() " + request.getPathInfo() + " " + _toString()); |
|
261 |
if(conversationBound){ |
|
262 |
unbindConversation(); |
|
263 |
} |
|
120 |
private StatefulPersistenceContext getPersitenceContext() { |
|
121 |
return (StatefulPersistenceContext)((SessionImplementor)getSession()).getPersistenceContext(); |
|
264 | 122 |
} |
265 | 123 |
|
266 | 124 |
public final void onViewEnter() { |
... | ... | |
268 | 126 |
handleViewEntered(); |
269 | 127 |
} |
270 | 128 |
|
271 |
public final void onViewExit() {
|
|
129 |
public void onViewExit() { |
|
272 | 130 |
logger.trace(String.format("%s onViewExit()", _toString())); |
273 | 131 |
handleViewExit(); |
274 |
// un-register as request start and end listener |
|
275 |
if(conversationBound){ |
|
276 |
logger.trace(String.format("<<<<< %s onViewExit() unbind()", _toString())); |
|
277 |
conversationHolder.unbind(); |
|
278 |
conversationBound = false; |
|
279 |
} |
|
280 |
logger.trace(String.format("<<<<< %s onViewExit() close()", _toString())); |
|
281 |
conversationHolder.close(); |
|
282 |
VaadinService service = UI.getCurrent().getSession().getService(); |
|
283 |
if(service instanceof CdmSpringVaadinServletService){ |
|
284 |
logger.trace(String.format("~~~~~ %s un-register as request listener", _toString())); |
|
285 |
((CdmSpringVaadinServletService)service).removeRequestEndListener(this); |
|
286 |
if(logger.isTraceEnabled()){ |
|
287 |
((CdmSpringVaadinServletService)service).removeRequestStartListener(this); |
|
288 |
} |
|
289 |
} else { |
|
290 |
throw new RuntimeException("Using the CdmSpringVaadinServletService is required for proper per view conversation handling"); |
|
291 |
} |
|
292 | 132 |
} |
293 | 133 |
|
294 | 134 |
/** |
... | ... | |
317 | 157 |
return navigationManager; |
318 | 158 |
} |
319 | 159 |
|
320 |
protected ViewScopeConversationHolder getConversationHolder(){ |
|
321 |
return conversationHolder; |
|
322 |
} |
|
323 |
|
|
324 | 160 |
/** |
325 | 161 |
* @param repo the repo to set |
326 | 162 |
*/ |
... | ... | |
335 | 171 |
this.navigationManager = navigationManager; |
336 | 172 |
} |
337 | 173 |
|
338 |
|
|
339 |
|
|
340 | 174 |
} |
Also available in: Unified diff
ref #7046 completely removing open session per view implementation and adding init strategies for Name and Typedesignation editor