View Javadoc

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 }