001: package com.technoetic.xplanner.db.hibernate;
002:
003: import java.io.PrintWriter;
004: import java.io.Serializable;
005: import java.io.Writer;
006: import java.lang.reflect.Method;
007: import java.sql.Connection;
008: import java.util.Map;
009: import javax.naming.NamingException;
010: import javax.naming.Reference;
011:
012: import net.sf.hibernate.Databinder;
013: import net.sf.hibernate.HibernateException;
014: import net.sf.hibernate.Interceptor;
015: import net.sf.hibernate.Session;
016: import net.sf.hibernate.SessionFactory;
017: import net.sf.hibernate.exception.SQLExceptionConverter;
018: import net.sf.hibernate.metadata.ClassMetadata;
019: import net.sf.hibernate.metadata.CollectionMetadata;
020: import org.apache.log4j.Logger;
021: import com.thoughtworks.proxy.Invoker;
022: import com.thoughtworks.proxy.factory.StandardProxyFactory;
023: import com.thoughtworks.proxy.toys.echo.Echoing;
024:
025: import com.technoetic.xplanner.util.LogUtil;
026:
027: public class XPlannerSessionFactory implements SessionFactory {
028: protected static final Logger LOG = LogUtil.getLogger();
029:
030: private SessionFactory delegate;
031:
032: public XPlannerSessionFactory(SessionFactory delegate) {
033: this .delegate = delegate;
034: }
035:
036: public void close() throws HibernateException {
037: delegate.close();
038: }
039:
040: public void evict(Class persistentClass) throws HibernateException {
041: delegate.evict(persistentClass);
042: }
043:
044: public void evict(Class persistentClass, Serializable id)
045: throws HibernateException {
046: delegate.evict(persistentClass, id);
047: }
048:
049: public void evictCollection(String roleName)
050: throws HibernateException {
051: delegate.evictCollection(roleName);
052: }
053:
054: public void evictCollection(String roleName, Serializable id)
055: throws HibernateException {
056: delegate.evictCollection(roleName, id);
057: }
058:
059: public void evictQueries() throws HibernateException {
060: delegate.evictQueries();
061: }
062:
063: public void evictQueries(String cacheRegion)
064: throws HibernateException {
065: delegate.evictQueries(cacheRegion);
066: }
067:
068: public SQLExceptionConverter getSQLExceptionConverter() {
069: return delegate.getSQLExceptionConverter();
070: }
071:
072: public Map getAllClassMetadata() throws HibernateException {
073: return delegate.getAllClassMetadata();
074: }
075:
076: public Map getAllCollectionMetadata() throws HibernateException {
077: return delegate.getAllCollectionMetadata();
078: }
079:
080: public ClassMetadata getClassMetadata(Class persistentClass)
081: throws HibernateException {
082: return delegate.getClassMetadata(persistentClass);
083: }
084:
085: public CollectionMetadata getCollectionMetadata(String roleName)
086: throws HibernateException {
087: return delegate.getCollectionMetadata(roleName);
088: }
089:
090: public Databinder openDatabinder() throws HibernateException {
091: return delegate.openDatabinder();
092: }
093:
094: public Session openSession() throws HibernateException {
095: Session session = delegate
096: .openSession(new XPlannerInterceptor());
097: return logAndWrapNewSessionIfDebug(session);
098: }
099:
100: public Session openSession(Connection connection) {
101: Session session = delegate.openSession(connection,
102: new XPlannerInterceptor());
103: return logAndWrapNewSessionIfDebug(session);
104: }
105:
106: public Session openSession(Connection connection,
107: Interceptor interceptor) {
108: Session session = delegate.openSession(connection, interceptor);
109: return logAndWrapNewSessionIfDebug(session);
110: }
111:
112: public Session openSession(Interceptor interceptor)
113: throws HibernateException {
114: Session session = delegate.openSession(interceptor);
115: return logAndWrapNewSessionIfDebug(session);
116: }
117:
118: private Session logAndWrapNewSessionIfDebug(final Session session) {
119: if (LOG.isDebugEnabled()) {
120: PrintWriter out = new PrintWriter(
121: new Log4JDebugLoggerWriter());
122: return (Session) Echoing.object(Session.class, session,
123: out, new StandardProxyFactory() {
124: public boolean canProxy(Class type) {
125: return Session.class.isAssignableFrom(type);
126: }
127:
128: public Object createProxy(Class[] types,
129: Invoker invoker) {
130: return super .createProxy(types,
131: new SessionCountingInvoker(session,
132: invoker));
133: }
134: });
135: }
136: return session;
137: }
138:
139: public Reference getReference() throws NamingException {
140: return delegate.getReference();
141: }
142:
143: private static int lastId = 0;
144: private static int sessionCount = 0;
145:
146: class SessionCountingInvoker implements Invoker {
147: private Session session;
148: private int id;
149: private Invoker invoker;
150: private StackTraceElement[] creationStack;
151:
152: public SessionCountingInvoker(Session session, Invoker invoker) {
153: this .session = session;
154: this .invoker = invoker;
155: this .creationStack = getStackTraceForMethod("openSession");
156: this .id = ++lastId;
157: LOG.debug("Session.new() -> " + ++sessionCount
158: + " opened. " + this + " was opened:\n"
159: + getStackTraceString(creationStack));
160: }
161:
162: public String toString() {
163: return "session #" + id + " (" + session + ")";
164: }
165:
166: private StackTraceElement[] getStackTraceForMethod(
167: String methodName) {
168: StackTraceElement[] stackTrace = new Throwable()
169: .getStackTrace();
170: stackTrace = pruneTopDownToOpenSessionFrame(stackTrace,
171: methodName);
172: stackTrace = pruneBottomUpToFirstXPlannerFrame(stackTrace);
173: return stackTrace;
174: }
175:
176: private StackTraceElement[] pruneBottomUpToFirstXPlannerFrame(
177: StackTraceElement[] stackTrace) {
178: int firstXPlannerFrameIndex = findFirstXPlannerFrameIndex(stackTrace);
179: StackTraceElement[] prunedStackTrace = new StackTraceElement[firstXPlannerFrameIndex + 1];
180: System.arraycopy(stackTrace, 0, prunedStackTrace, 0,
181: firstXPlannerFrameIndex + 1);
182: return prunedStackTrace;
183: }
184:
185: private int findFirstXPlannerFrameIndex(
186: StackTraceElement[] stackTrace) {
187: for (int i = stackTrace.length - 1; i >= 0; i--) {
188: StackTraceElement frame = stackTrace[i];
189: if (frame.getClassName().indexOf("xplanner") != -1
190: || frame.getClassName().indexOf(
191: "springframework") != -1) {
192: return i;
193: }
194: }
195: return stackTrace.length - 1;
196: }
197:
198: private StackTraceElement[] pruneTopDownToOpenSessionFrame(
199: StackTraceElement[] stackTrace, String methodName) {
200: int openSessionFrameIndex = findFirstTopFrameIndexForMethod(
201: stackTrace, methodName);
202: StackTraceElement[] prunedStackTrace = new StackTraceElement[stackTrace.length
203: - openSessionFrameIndex];
204: System.arraycopy(stackTrace, openSessionFrameIndex,
205: prunedStackTrace, 0, prunedStackTrace.length);
206: return prunedStackTrace;
207: }
208:
209: private int findFirstTopFrameIndexForMethod(
210: StackTraceElement[] stackTrace, String methodName) {
211: for (int i = 0; i < stackTrace.length; i++) {
212: StackTraceElement frame = stackTrace[i];
213: if (methodName.equals(frame.getMethodName())) {
214: return i;
215: }
216: }
217: return 0;
218: }
219:
220: private String getStackTraceString(
221: StackTraceElement[] stackTrace) {
222: StringBuffer buf = new StringBuffer();
223: buf.append("\n");
224: for (int i = 0; i < stackTrace.length; i++) {
225: StackTraceElement frame = stackTrace[i];
226: buf.append("\tat " + frame + "\n");
227: }
228: buf.append("\n");
229: return buf.toString();
230: }
231:
232: public Object invoke(Object proxy, Method method, Object[] args)
233: throws Throwable {
234: Object result = null;
235: boolean connected = session.isConnected();
236: try {
237: return invoker.invoke(proxy, method, args);
238: } finally {
239: if (method.getName().equals("close")) {
240: if (connected) {
241: --sessionCount;
242: }
243: LOG
244: .debug("Session.close() -> "
245: + (!connected ? "did not close session. "
246: : " ")
247: + sessionCount
248: + " still opened. "
249: + this
250: + " was closed:\n"
251: + getStackTraceString(getStackTraceForMethod("close")));
252: }
253: }
254: }
255:
256: protected void finalize() throws Throwable {
257: super .finalize();
258: if (session.isOpen()) {
259: LOG.debug(" ############# Session.finalize() -> "
260: + this + " was not closed ###############\n"
261: + "Session was allocated from:\n"
262: + getStackTraceString(creationStack));
263: }
264: }
265: }
266:
267: private static class Log4JDebugLoggerWriter extends Writer {
268: StringBuffer buf = new StringBuffer();
269:
270: public void close() {
271: }
272:
273: public void flush() {
274: LOG.debug(buf.toString());
275: buf = new StringBuffer();
276: }
277:
278: public void write(char[] cbuf, int off, int len) {
279: buf.append(cbuf, off, len);
280: }
281: }
282: }
|