Project

General

Profile

Download (6.45 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * 
3
 */
4
package eu.etaxonomy.cdm.api.application;
5

    
6
import javax.sql.DataSource;
7

    
8
import org.apache.log4j.Logger;
9
import org.hibernate.FlushMode;
10
import org.hibernate.LockMode;
11
import org.hibernate.Session;
12
import org.hibernate.SessionFactory;
13
import org.springframework.beans.factory.annotation.Autowired;
14
import org.springframework.jdbc.datasource.DataSourceUtils;
15
import org.springframework.orm.hibernate3.SessionFactoryUtils;
16
import org.springframework.orm.hibernate3.SessionHolder;
17
import org.springframework.transaction.PlatformTransactionManager;
18
import org.springframework.transaction.TransactionDefinition;
19
import org.springframework.transaction.TransactionStatus;
20
import org.springframework.transaction.support.TransactionSynchronizationManager;
21

    
22
/**
23
 * This is an implementation of the session-per-conversation pattern for usage
24
 * in a Spring context.
25
 *  
26
 * @see http://www.hibernate.org/42.html
27
 * 
28
 * @author n.hoffmann
29
 * @created 12.03.2009
30
 * @version 1.0
31
 */
32
public class ConversationHolder {
33

    
34
	/**
35
	 * This class logger instance 
36
	 */
37
	private static final Logger logger = Logger.getLogger(ConversationHolder.class);
38

    
39
	/**
40
	 * The applications session factory
41
	 */
42
	@Autowired
43
	private SessionFactory sessionFactory;
44
	
45
	/**
46
	 * The datasource associated with the application context
47
	 */
48
	@Autowired
49
	private DataSource dataSource;
50
	
51
	/**
52
	 * 
53
	 */
54
	@Autowired
55
	private PlatformTransactionManager transactionManager;
56
	
57
	/**
58
	 * The persistence context for this conversation
59
	 */
60
	private Session longSession = null;
61

    
62
	/**
63
	 * Spring communicates with hibernate sessions via a SessionHolder object
64
	 */
65
	private SessionHolder sessionHolder = null;
66

    
67
	/**
68
	 * see TransactionDefinition
69
	 */
70
	private TransactionDefinition definition;
71
	
72
	/**
73
	 * This conversations transaction
74
	 */
75
	private TransactionStatus transactionStatus;
76
	
77
	/**
78
	 * Simple constructor
79
	 */
80
	public ConversationHolder(){}
81
	
82
	/**
83
	 * 
84
	 * @param dataSource
85
	 */
86
	public ConversationHolder(DataSource dataSource) {
87
		this.dataSource = dataSource;
88
	}
89

    
90
	/**
91
	 * 
92
	 * @param dataSource
93
	 * @param sessionFactory
94
	 */
95
	public ConversationHolder(DataSource dataSource, SessionFactory sessionFactory) {
96
		this(dataSource);
97
		this.sessionFactory = sessionFactory;
98
	}
99

    
100
	public ConversationHolder(DataSource dataSource, SessionFactory sessionFactory, 
101
			PlatformTransactionManager transactionManager) {
102
		this(dataSource, sessionFactory);
103
		this.transactionManager = transactionManager;
104
	}
105
	
106
	/**
107
	 * 
108
	 * @param dataSource
109
	 * @param sessionFactory
110
	 * @param session
111
	 */
112
	public ConversationHolder(DataSource dataSource, SessionFactory sessionFactory,
113
			PlatformTransactionManager transactionManager, Session session) {
114
		this(dataSource, sessionFactory, transactionManager);
115
		longSession = session;
116
	}
117
	
118

    
119

    
120

    
121
	/**
122
	 * This method has to be called when starting a new unit-of-work. All required resources are
123
	 * bound so that SessionFactory.getCurrentSession() returns the right session for this conversation
124
	 */
125
	public void preExecute() {
126

    
127
		if (longSession == null) {
128
			longSession = SessionFactoryUtils.getNewSession(getSessionFactory());
129
			longSession.setFlushMode(FlushMode.MANUAL);
130
		}
131

    
132
		if(sessionHolder == null){
133
			sessionHolder = new SessionHolder(longSession);
134
		}
135
		
136
		if (!longSession.isConnected()){
137
			longSession.reconnect(DataSourceUtils.getConnection(dataSource));
138
		}
139
		
140
		if(TransactionSynchronizationManager.hasResource(getSessionFactory())){
141
			TransactionSynchronizationManager.unbindResource(getSessionFactory());
142
		}
143
		
144
		TransactionSynchronizationManager.bindResource(getSessionFactory(),
145
				sessionHolder);
146

    
147
		if(TransactionSynchronizationManager.isSynchronizationActive()){
148
			TransactionSynchronizationManager.clearSynchronization();
149
		}
150
		
151
		TransactionSynchronizationManager.initSynchronization();
152
	}
153

    
154
	/**
155
	 * This method is to be run to free up resources after the unit-of-work has completed 
156
	 * 
157
	 * TODO 
158
	 * we do not need this in a test environment as the junit magic will try to 
159
	 * clear up resources after the tests are run and if the resources are unbound 
160
	 * manually beforehand, it will result in exceptions.
161
	 * maybe we need this in a live environment
162
	 */
163
	public void postExecute() {
164
		//TransactionSynchronizationManager.unbindResource(getSessionFactory());
165
		//TransactionSynchronizationManager.clearSynchronization();
166
	}
167
	
168
	/**
169
	 * Creates an instance of TransactionStatus and binds it to this conversation manager.
170
	 * At the moment we allow only on transaction per conversation holder.
171
	 * 
172
	 * @return the transaction status bound to this conversation holder
173
	 */
174
	public TransactionStatus startTransaction(){
175
		if (isTransactionActive()){
176
			logger.warn("We allow only one transaction at the moment but startTransaction " +
177
					"was called a second time.\nReturning the transaction already associated with this " +
178
					"ConversationManager");
179
		}else{	
180
			transactionStatus = transactionManager.getTransaction(definition);
181
		}
182
		return transactionStatus;
183
	}
184
	
185
	/** 
186
	 * @return if there is a running transaction
187
	 */
188
	public boolean isTransactionActive(){
189
		return transactionStatus != null;
190
	}
191
	
192
	/**
193
	 * Commit a running transaction
194
	 */
195
	public void commit(){
196
		if(isTransactionActive()){
197
			transactionManager.commit(transactionStatus);
198
			// Reset the transactionStatus.
199
			transactionStatus = null;
200
			// Commiting a transaction frees all resources.
201
			// Since we are in a conversation we directly rebind those resources.
202
			preExecute();
203
		}else{
204
			logger.warn("No active transaction but commit was called");
205
		}
206
	}
207

    
208
	/**
209
	 * close the session if it is still open
210
	 */
211
	public void dispose() {
212
		if (longSession != null && longSession.isOpen()){
213
			longSession.close();
214
		}
215
	}
216

    
217
	/**
218
	 * @return the session associated with this conversation manager 
219
	 */
220
	public Session getSession() {
221
		return longSession;
222
	}
223
	
224
	/** 
225
	 * @return the session factory that is bound to this conversation manager
226
	 */
227
	protected SessionFactory getSessionFactory() {
228
		return sessionFactory;
229
	}
230

    
231
	/**
232
	 * Facades Session.lock()
233
	 */
234
	public void lock(Object persistentObject, LockMode lockMode) {
235
		longSession.lock(persistentObject, lockMode);
236
	}
237
	
238
	public void lock(String entityName, Object persistentObject, LockMode lockMode){
239
		longSession.lock(entityName, persistentObject, lockMode);
240
	}
241

    
242
	/**
243
	 * @return the definition
244
	 */
245
	public TransactionDefinition getDefinition() {
246
		return definition;
247
	}
248

    
249
	/**
250
	 * @param definition the definition to set
251
	 */
252
	public void setDefinition(TransactionDefinition definition) {
253
		this.definition = definition;
254
	}
255

    
256
}
(3-3/4)