1 /*
2 * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3 * the spring framework, http://el4j.sf.net
4 * Copyright (C) 2006 by ELCA Informatique SA, Av. de la Harpe 22-24,
5 * 1000 Lausanne, Switzerland, http://www.elca.ch
6 *
7 * EL4J is published under the GNU Lesser General Public License (LGPL)
8 * Version 2.1. See http://www.gnu.org/licenses/
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * For alternative licensing, please contact info@elca.ch
16 */
17 package ch.elca.el4j.services.persistence.hibernate;
18
19 import java.io.Serializable;
20
21 import org.aopalliance.intercept.MethodInterceptor;
22 import org.aopalliance.intercept.MethodInvocation;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25 import org.hibernate.FlushMode;
26 import org.hibernate.Session;
27 import org.hibernate.SessionFactory;
28 import org.springframework.dao.DataAccessResourceFailureException;
29 import org.springframework.orm.hibernate3.SessionFactoryUtils;
30 import org.springframework.orm.hibernate3.SessionHolder;
31 import org.springframework.transaction.support.TransactionSynchronizationManager;
32
33 /**
34 * This interceptor is similar to {@link OpenSessionInViewInterceptor}, but can
35 * also be used e.g. for batch job processing where no HTTP requests are used.
36 * Another use case is to take this class as a replacement for
37 * {@link HibernateInterceptor}, now having more control over the flush mode and
38 * a single session feature.
39 *
40 *
41 * @svnLink $Revision: 3881 $;$Date: 2009-08-04 15:22:05 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/hibernate/src/main/java/ch/elca/el4j/services/persistence/hibernate/OpenSessionInServiceInterceptor.java $
42 *
43 * @author Pham Quoc Ky (QKP)
44 */
45 public class OpenSessionInServiceInterceptor implements MethodInterceptor,
46 Serializable {
47
48 /**
49 * The logger.
50 */
51 private static Logger s_logger
52 = LoggerFactory.getLogger(OpenSessionInServiceInterceptor.class);
53
54 /**
55 * Is single session mode used?
56 */
57 private boolean m_singleSession = true;
58
59 /**
60 * The Hibernate session factory.
61 */
62 private SessionFactory m_sessionFactory;
63
64 /**
65 * The flushing stragtegy to use.
66 */
67 private FlushMode m_flushMode = FlushMode.COMMIT;
68
69
70 /**
71 * @return the singleSession
72 */
73 public boolean isSingleSession() {
74 return m_singleSession;
75 }
76
77 /**
78 * @param singleSession
79 * the singleSession to set
80 */
81 public void setSingleSession(boolean singleSession) {
82 this.m_singleSession = singleSession;
83 }
84
85 /**
86 * @return the sessionFactory
87 */
88 public SessionFactory getSessionFactory() {
89 return m_sessionFactory;
90 }
91
92 /**
93 * @param sessionFactory
94 * the sessionFactory to set
95 */
96 public void setSessionFactory(SessionFactory sessionFactory) {
97 this.m_sessionFactory = sessionFactory;
98 }
99
100 /**
101 * @return the flushMode
102 */
103 public FlushMode getFlushMode() {
104 return m_flushMode;
105 }
106
107 /**
108 * @param flushMode
109 * the flushMode to set
110 */
111 public void setFlushMode(FlushMode flushMode) {
112 this.m_flushMode = flushMode;
113 }
114
115 /**
116 * {@inheritDoc}
117 */
118 public Object invoke(MethodInvocation invocation) throws Throwable {
119 boolean participate = false;
120
121 if (isSingleSession()) {
122 // single session mode
123 if (TransactionSynchronizationManager
124 .hasResource(m_sessionFactory)) {
125 // Do not modify the Session: just set the participate flag.
126 participate = true;
127 } else {
128 s_logger.debug("Opening single Hibernate Session in "
129 + "OpenSessionInServiceInterceptor");
130 Session session = getSession(m_sessionFactory);
131 TransactionSynchronizationManager.bindResource(
132 m_sessionFactory, new SessionHolder(session));
133 }
134 } else {
135 // deferred close mode
136 if (SessionFactoryUtils.isDeferredCloseActive(m_sessionFactory)) {
137 // Do not modify deferred close: just set the participate flag.
138 participate = true;
139 } else {
140 SessionFactoryUtils.initDeferredClose(m_sessionFactory);
141 }
142 }
143
144 try {
145 return invocation.proceed();
146 } finally {
147 if (!participate) {
148 if (isSingleSession()) {
149 // single session mode
150 SessionHolder sessionHolder = (SessionHolder)
151 TransactionSynchronizationManager
152 .unbindResource(m_sessionFactory);
153 s_logger.debug("Closing single Hibernate Session in "
154 + "OpenSessionInServiceInterceptor");
155 closeSession(sessionHolder.getSession());
156 } else {
157 // deferred close mode
158 SessionFactoryUtils.processDeferredClose(m_sessionFactory);
159 }
160 }
161 }
162 }
163
164 /**
165 * Get a Session for the SessionFactory that this filter uses.
166 * Note that this just applies in single session mode!
167 * <p>
168 * The default implementation delegates to the
169 * <code>SessionFactoryUtils.getSession</code> method and sets the
170 * <code>Session</code>'s flush mode to "NEVER".
171 * <p>
172 * Can be overridden in subclasses for creating a Session with a custom
173 * entity interceptor or JDBC exception translator.
174 *
175 * @param sessionFactory
176 * the SessionFactory that this filter uses
177 * @return the Session to use
178 * @throws DataAccessResourceFailureException
179 * if the Session could not be created
180 * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory,
181 * boolean)
182 * @see org.hibernate.FlushMode#COMMIT
183 */
184 protected Session getSession(SessionFactory sessionFactory)
185 throws DataAccessResourceFailureException {
186
187 Session session = SessionFactoryUtils.getSession(sessionFactory, true);
188 FlushMode flushMode = getFlushMode();
189 if (flushMode != null) {
190 session.setFlushMode(flushMode);
191 }
192
193 return session;
194 }
195
196 /**
197 * Close the given Session. Note that this just applies in single
198 * session mode!
199 * <p>
200 * Can be overridden in subclasses, e.g. for flushing the Session before
201 * closing it. See class-level javadoc for a discussion of flush handling.
202 * Note that you should also override getSession accordingly, to set the
203 * flush mode to something else than NEVER.
204 *
205 * @param session
206 * the Session used for filtering
207 */
208 protected void closeSession(Session session) {
209 SessionFactoryUtils.closeSession(session);
210 }
211 }