001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.api.database;
021
022 import org.hibernate.ejb.EntityManagerFactoryImpl;
023 import org.hibernate.ejb.HibernateEntityManagerFactory;
024 import org.hibernate.stat.QueryStatistics;
025 import org.hibernate.stat.Statistics;
026 import org.slf4j.Logger;
027
028 import javax.persistence.*;
029
030 public class StatisticsEntityManager implements EntityManager {
031
032 private final EntityManager manager;
033 private final Logger logger;
034 private EntityTransaction transaction;
035 private EntityManagerFactory factory;
036
037 public StatisticsEntityManager(EntityManagerFactory factory, EntityManager manager, Logger logger) {
038 super();
039 this.manager = manager;
040 this.logger = logger;
041 this.factory = factory;
042 }
043
044 public void clear() {
045 manager.clear();
046 }
047
048 public void close() {
049 manager.close();
050 }
051
052 public boolean contains(Object entity) {
053 return manager.contains(entity);
054 }
055
056 public Query createNamedQuery(String name) {
057 return manager.createNamedQuery(name);
058 }
059
060 public Query createNativeQuery(String sqlString) {
061 return manager.createNativeQuery(sqlString);
062 }
063
064 public Query createNativeQuery(String sqlString, Class resultClass) {
065 return manager.createNativeQuery(sqlString, resultClass);
066 }
067
068 public Query createNativeQuery(String sqlString, String resultSetMapping) {
069 return manager.createNativeQuery(sqlString, resultSetMapping);
070 }
071
072 public Query createQuery(String qlString) {
073 return manager.createQuery(qlString);
074 }
075
076 public <T> T find(Class<T> entityClass, Object primaryKey) {
077 long start = System.currentTimeMillis();
078 T hit = manager.find(entityClass, primaryKey);
079 long stop = System.currentTimeMillis() - start;
080 logger.info("Find took " + stop + " ms");
081 return hit;
082 }
083
084 public void flush() {
085 long start = System.currentTimeMillis();
086 manager.flush();
087 long stop = System.currentTimeMillis() - start;
088 logger.info("Flush took " + stop + " ms");
089 }
090
091 public Object getDelegate() {
092 return manager.getDelegate();
093 }
094
095 public FlushModeType getFlushMode() {
096 return manager.getFlushMode();
097 }
098
099 public <T> T getReference(Class<T> entityClass, Object primaryKey) {
100 return manager.getReference(entityClass, primaryKey);
101 }
102
103 private String getCallerStack(int depth) {
104 StackTraceElement[] stack = Thread.currentThread().getStackTrace();
105 return stack[depth].toString();
106 }
107
108 public EntityTransaction getTransaction() {
109 if (transaction == null) {
110 transaction = new EntityTransaction() {
111
112 private long beginTs;
113
114 public void begin() {
115 beginTs = System.currentTimeMillis();
116 manager.getTransaction().begin();
117 }
118
119 public void commit() {
120 long start = System.currentTimeMillis();
121 manager.getTransaction().commit();
122 Long commitTimeTaken = System.currentTimeMillis() - start;
123 Long transactionTimeTaken = System.currentTimeMillis() - beginTs;
124 logger.info("{}: Commit took {} ms, global transaction took {} ms",
125 new Object[]{getCallerStack(5), commitTimeTaken, transactionTimeTaken});
126
127 dumpStatistics();
128 beginTs = 0;
129 }
130
131 public boolean getRollbackOnly() {
132 return manager.getTransaction().getRollbackOnly();
133 }
134
135 public boolean isActive() {
136 return manager.getTransaction().isActive();
137 }
138
139 public void rollback() {
140 long start = System.currentTimeMillis();
141 manager.getTransaction().rollback();
142 long rollbackTimeTaken = System.currentTimeMillis() - start;
143 long transactionTimeTaken = System.currentTimeMillis() - beginTs;
144 logger.info("Rollback took " + rollbackTimeTaken + " ms, global transaction took " + transactionTimeTaken + " ms");
145 beginTs = 0;
146 }
147
148 public void setRollbackOnly() {
149 manager.getTransaction().setRollbackOnly();
150 }
151
152 };
153 }
154 return transaction;
155 }
156
157 public boolean isOpen() {
158 return manager.isOpen();
159 }
160
161 public void joinTransaction() {
162 manager.joinTransaction();
163 }
164
165 public void lock(Object entity, LockModeType lockMode) {
166 manager.lock(entity, lockMode);
167 }
168
169 public <T> T merge(T entity) {
170 return manager.merge(entity);
171 }
172
173 public void persist(Object entity) {
174 manager.persist(entity);
175 }
176
177 public void refresh(Object entity) {
178 manager.refresh(entity);
179 }
180
181 public void remove(Object entity) {
182 manager.remove(entity);
183 }
184
185 public void setFlushMode(FlushModeType flushMode) {
186 manager.setFlushMode(flushMode);
187 }
188
189 private void dumpStatistics() {
190 if (logger.isDebugEnabled() && factory instanceof EntityManagerFactoryImpl) {
191
192 HibernateEntityManagerFactory hibernateFactory = (HibernateEntityManagerFactory) factory;
193 Statistics stats = hibernateFactory.getSessionFactory().getStatistics();
194 for (String query : stats.getQueries()) {
195 QueryStatistics stat = stats.getQueryStatistics(query);
196 StringBuilder sb = new StringBuilder();
197 sb.append(stats.getQueryExecutionMaxTime());
198 sb.append("ms, count=");
199 sb.append(stat.getExecutionCount());
200 sb.append(", sql=");
201 sb.append(stat.getCategoryName());
202 logger.debug(sb.toString());
203 }
204 stats.clear();
205 }
206 }
207
208 }