/** * Abiquo community edition * cloud management application for hybrid clouds * Copyright (C) 2008-2010 - Abiquo Holdings S.L. * * This application is free software; you can redistribute it and/or * modify it under the terms of the GNU LESSER GENERAL PUBLIC * LICENSE as published by the Free Software Foundation under * version 3 of the License * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * LESSER GENERAL PUBLIC LICENSE v.3 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package com.abiquo.server.core.common.persistence; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import org.hibernate.classic.Session; import org.hibernate.stat.Statistics; public class HibernateSessionAllocationChecker { private boolean statisticsEnabledOnEntry; private long outstandingSessionsOnEntry; private int openMySqlConnectionsOnEntry; private long sessionsNotReleasedAfterCreation; private int mySqlConnectionsNoReleasedAfterCreation; private EntityManagerFactory factory; private int getMySqlConnectionCount(Connection connection) throws SQLException { assert connection != null; Statement query = connection.createStatement(); try { ResultSet rs = query.executeQuery("show global status like 'Threads_connected'"); try { boolean found = rs.next(); assert found; String result = rs.getString(2); return Integer.parseInt(result); } finally { rs.close(); } } finally { query.close(); } } public HibernateSessionAllocationChecker(EntityManagerFactory factory) { assert factory != null; this.factory = factory; EntityManager em = factory.createEntityManager(); try { Session session = (Session) em.getDelegate(); Statistics statistics = session.getSessionFactory().getStatistics(); this.statisticsEnabledOnEntry = statistics.isStatisticsEnabled(); statistics.setStatisticsEnabled(true); this.outstandingSessionsOnEntry = statistics.getSessionOpenCount() - statistics.getSessionCloseCount(); try { this.openMySqlConnectionsOnEntry = getMySqlConnectionCount(session.connection()); } catch (SQLException e) { throw new RuntimeException(e); } } finally { em.close(); } } private boolean resultObtained; private void ensureResultObtained() { if (!resultObtained) { EntityManager em = factory.createEntityManager(); try { Session session = (Session) em.getDelegate(); Statistics statistics = session.getSessionFactory().getStatistics(); assert statistics.isStatisticsEnabled() : "Somebody else disabled the statistics: DON'T do, or do not use this component"; long outstandingSessionsOnExit = statistics.getSessionOpenCount() - statistics.getSessionCloseCount(); this.sessionsNotReleasedAfterCreation = outstandingSessionsOnExit - this.outstandingSessionsOnEntry; assert sessionsNotReleasedAfterCreation >= 0 : "Somebody else played with the statistics (maybe cleared/disabled them?): DON'T do, or do not use this component"; // System.err.println( "OUTSTANDING SESSIONS: " + // sessionsNotReleasedAfterCreation); try { this.mySqlConnectionsNoReleasedAfterCreation = getMySqlConnectionCount(session.connection()) - this.openMySqlConnectionsOnEntry; } catch (SQLException e) { throw new RuntimeException(e); } // Reset statistics to the state they were before we started to // be interested in open/closed session count statistics.setStatisticsEnabled(this.statisticsEnabledOnEntry); } finally { em.close(); } resultObtained = true; } } public long getOutstandingMySqlConnections() { ensureResultObtained(); return this.mySqlConnectionsNoReleasedAfterCreation; } public long getOutstandingSessions() { ensureResultObtained(); return this.sessionsNotReleasedAfterCreation; } }