001 /**
002 *
003 * $Revision: 13745 $ $Date: 2008-07-14 15:07:17 +0200 (Mo, 14 Jul 2008) $
004 *
005 * This file is part of ** M y C o R e **
006 * Visit our homepage at http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, normally in the file license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 *
023 **/
024 package org.mycore.backend.hibernate;
025
026 import org.apache.log4j.Logger;
027 import org.hibernate.Session;
028 import org.hibernate.context.CurrentSessionContext;
029 import org.hibernate.context.ThreadLocalSessionContext;
030 import org.hibernate.engine.SessionFactoryImplementor;
031
032 import org.mycore.common.MCRSession;
033 import org.mycore.common.MCRSessionMgr;
034 import org.mycore.common.events.MCRSessionEvent;
035 import org.mycore.common.events.MCRSessionListener;
036
037 /**
038 * A {@link CurrentSessionContext} implementation which scopes the notion of
039 * current session by the current {@link MCRSession}. As the MCRSession can be
040 * used by more than one {@link Thread} at a time and {@link Session} is not
041 * threadsafe. This implementation allows the first thread of a
042 * {@link MCRSession} to keep the {@link Session} open for a long conversation.
043 *
044 * @author Thomas Scheffler (yagee)
045 *
046 * @version $Revision: 13745 $ $Date: 2008-07-14 15:07:17 +0200 (Mo, 14 Jul 2008) $
047 * @since 2.0
048 */
049 public class MCRSessionContext extends ThreadLocalSessionContext implements MCRSessionListener {
050
051 private static final long serialVersionUID = -801352757721845792L;
052
053 private static final String SESSION_KEY = "hibernateSession";
054
055 private static final Logger LOGGER = Logger.getLogger(MCRSessionContext.class);
056
057 ThreadLocal<Boolean> firstThread = new ThreadLocal<Boolean>() {
058 protected Boolean initialValue() {
059 return Boolean.FALSE;
060 }
061 };
062
063 public MCRSessionContext(SessionFactoryImplementor factory) {
064 super(factory);
065 MCRSessionMgr.addSessionListener(this);
066 }
067
068 public void sessionEvent(MCRSessionEvent event) {
069 MCRSession mcrSession = event.getSession();
070 Session currentSession;
071 switch (event.getType()) {
072 case activated:
073 if (event.getConcurrentAccessors() <= 1) {
074 // mark this Thread as first Thread of MCRSession
075 LOGGER.debug("First Thread to access " + mcrSession);
076 firstThread.set(true);
077 }
078 break;
079 case passivated:
080 currentSession = unbind(factory);
081 if (event.getConcurrentAccessors() <= 1) {
082 // save Session for later use;
083 LOGGER.debug("Saving hibernate Session for later use in " + mcrSession);
084 //mcrSession.put(SESSION_KEY, currentSession);
085 autoCloseSession(currentSession);
086 } else {
087 autoCloseSession(currentSession);
088 }
089 // reset firstThread marker as this Session passivates now
090 firstThread.remove();
091 break;
092 case destroyed:
093 currentSession = unbind(factory);
094 autoCloseSession(currentSession);
095 Object obj = mcrSession.get(SESSION_KEY);
096 if (obj != null && currentSession != obj) {
097 autoCloseSession((Session) obj);
098 }
099 firstThread.remove();
100 break;
101 case created:
102 break;
103 default:
104 break;
105 }
106 }
107
108 /**
109 * Closes Session if Session is still open.
110 */
111 private void autoCloseSession(Session currentSession) {
112 if (currentSession != null && currentSession.isOpen()) {
113 LOGGER.debug("Autoclosing current hibernate Session");
114 currentSession.close();
115 }
116 }
117
118 @Override
119 protected org.hibernate.classic.Session buildOrObtainSession() {
120 MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
121 if (firstThread.get()) {
122 LOGGER.debug("First Thread to access " + mcrSession);
123 LOGGER.debug("Try to reuse hibernate Session from current " + mcrSession);
124 Object obj = mcrSession.get(SESSION_KEY);
125 if (obj != null && ((Session) obj).isOpen()) {
126 LOGGER.debug("Reusing old hibernate Session.");
127 return (org.hibernate.classic.Session) obj;
128 } else if (obj == null) {
129 LOGGER.debug("No Hibernate Session found.");
130 } else if (!((Session) obj).isOpen()) {
131 LOGGER.debug("Found only a closed Hibernate Session.");
132 }
133
134 }
135 // creates a new one
136 LOGGER.debug("Obtaining new hibernate Session.");
137 org.hibernate.classic.Session session = super.buildOrObtainSession();
138 if (mcrSession.get(SESSION_KEY) == null || firstThread.get()) {
139 // must be a Sessions that started before this instance added as
140 // MCRSessionListener or old Session was closed
141 LOGGER.debug("Storing hibernate session in current MCRSession");
142 firstThread.set(true);
143 mcrSession.put(SESSION_KEY, session);
144 }
145 return session;
146 }
147
148 @Override
149 protected boolean isAutoCloseEnabled() {
150 return false;
151 }
152
153 @Override
154 protected boolean isAutoFlushEnabled() {
155 return false;
156 }
157
158 @Override
159 protected CleanupSynch buildCleanupSynch() {
160 return new CleanupSynch(factory) {
161 private static final long serialVersionUID = -7894370437708819993L;
162
163 public void afterCompletion(int arg0) {
164 }
165
166 public void beforeCompletion() {
167 }
168 };
169 }
170
171 }