From 8d294104c34f96f7e9e670f26483a3a0eaf81d87 Mon Sep 17 00:00:00 2001 From: Fabrice Bellingard Date: Thu, 14 Apr 2011 12:58:19 +0200 Subject: [SONAR-2347] Close a review when its corresponding violation does not exist anymore --- .../org/sonar/jpa/session/JpaDatabaseSession.java | 520 +++++++++++---------- 1 file changed, 263 insertions(+), 257 deletions(-) (limited to 'sonar-core') diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java b/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java index 09fb4894c88..6533b5ae5cf 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java @@ -1,257 +1,263 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar 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 for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.jpa.session; - -import org.apache.commons.lang.StringUtils; -import org.sonar.api.database.DatabaseSession; - -import java.util.*; - -import javax.persistence.EntityManager; -import javax.persistence.NonUniqueResultException; -import javax.persistence.PersistenceException; -import javax.persistence.Query; - -public class JpaDatabaseSession extends DatabaseSession { - - private final DatabaseConnector connector; - private EntityManager entityManager = null; - private int index = 0; - private boolean inTransaction = false; - - public JpaDatabaseSession(DatabaseConnector connector) { - this.connector = connector; - } - - /** - * Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling, - * which done in methods of this class. - */ - public EntityManager getEntityManager() { - return entityManager; - } - - public void start() { - entityManager = connector.createEntityManager(); - index = 0; - } - - public void stop() { - commit(); - if (entityManager != null && entityManager.isOpen()) { - entityManager.close(); - entityManager = null; - } - } - - public void commit() { - if (entityManager != null && inTransaction) { - if (entityManager.isOpen()) { - if (entityManager.getTransaction().getRollbackOnly()) { - entityManager.getTransaction().rollback(); - } else { - entityManager.getTransaction().commit(); - } - entityManager.clear(); - index = 0; - } - inTransaction = false; - } - } - - public void rollback() { - if (entityManager != null && inTransaction) { - entityManager.getTransaction().rollback(); - inTransaction = false; - } - } - - public T save(T model) { - startTransaction(); - internalSave(model, true); - return model; - } - - public Object saveWithoutFlush(Object model) { - startTransaction(); - internalSave(model, false); - return model; - } - - public boolean contains(Object model) { - startTransaction(); - return entityManager.contains(model); - } - - public void save(Object... models) { - startTransaction(); - for (Object model : models) { - save(model); - } - } - - private void internalSave(Object model, boolean flushIfNeeded) { - try { - entityManager.persist(model); - } catch (PersistenceException e) { - /* - * See http://jira.codehaus.org/browse/SONAR-2234 - * In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here. - */ - throw new PersistenceException("Unable to persist : " + model, e); - } - if (flushIfNeeded && (++index % BATCH_SIZE == 0)) { - commit(); - } - } - - public Object merge(Object model) { - startTransaction(); - return entityManager.merge(model); - } - - public void remove(Object model) { - startTransaction(); - entityManager.remove(model); - if (++index % BATCH_SIZE == 0) { - commit(); - } - } - - public void removeWithoutFlush(Object model) { - startTransaction(); - entityManager.remove(model); - } - - public T reattach(Class entityClass, Object primaryKey) { - startTransaction(); - return entityManager.getReference(entityClass, primaryKey); - } - - private void startTransaction() { - if (!inTransaction) { - entityManager.getTransaction().begin(); - inTransaction = true; - } - } - - /** - * Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling, - * which done in {@link #getSingleResult(Query, Object)}. - */ - public Query createQuery(String hql) { - startTransaction(); - return entityManager.createQuery(hql); - } - - /** - * @return the result or defaultValue, if not found - * @throws NonUniqueResultException if more than one result - */ - public T getSingleResult(Query query, T defaultValue) { - /* - * See http://jira.codehaus.org/browse/SONAR-2225 - * By default Hibernate throws NonUniqueResultException without meaningful information about context, - * so we improve it here by adding all results in error message. - * Note that in some rare situations we can receive too many results, which may lead to OOME, - * but actually it will mean that database is corrupted as we don't expect more than one result - * and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood. - */ - List result = query.getResultList(); - - if (result.size() == 1) { - return result.get(0); - - } else if (result.isEmpty()) { - return defaultValue; - - } else { - Set uniqueResult = new HashSet(result); - if (uniqueResult.size() > 1) { - throw new NonUniqueResultException("Expected single result, but got : " + result.toString()); - } else { - return uniqueResult.iterator().next(); - } - } - } - - public T getEntity(Class entityClass, Object id) { - startTransaction(); - return getEntityManager().find(entityClass, id); - } - - /** - * @return the result or null, if not found - * @throws NonUniqueResultException if more than one result - */ - public T getSingleResult(Class entityClass, Object... criterias) { - try { - return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null); - - } catch (NonUniqueResultException ex) { - NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName() - + " with criterias : " + StringUtils.join(criterias, ",")); - e.initCause(ex); - throw e; - } - } - - public List getResults(Class entityClass, Object... criterias) { - return getQueryForCriterias(entityClass, true, criterias).getResultList(); - } - - public List getResults(Class entityClass) { - return getQueryForCriterias(entityClass, false, null).getResultList(); - } - - private Query getQueryForCriterias(Class entityClass, boolean raiseError, Object... criterias) { - if (criterias == null && raiseError) { - throw new IllegalStateException("criterias parameter must be provided"); - } - startTransaction(); - StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o"); - if (criterias != null) { - hql.append(" WHERE "); - Map mappedCriterias = new HashMap(); - for (int i = 0; i < criterias.length; i += 2) { - mappedCriterias.put((String) criterias[i], criterias[i + 1]); - } - buildCriteriasHQL(hql, mappedCriterias); - Query query = getEntityManager().createQuery(hql.toString()); - - for (Map.Entry entry : mappedCriterias.entrySet()) { - query.setParameter(entry.getKey(), entry.getValue()); - } - return query; - } - return getEntityManager().createQuery(hql.toString()); - } - - private void buildCriteriasHQL(StringBuilder hql, Map mappedCriterias) { - for (Iterator i = mappedCriterias.keySet().iterator(); i.hasNext();) { - String criteria = i.next(); - hql.append("o.").append(criteria).append("=:").append(criteria); - if (i.hasNext()) { - hql.append(" AND "); - } - } - } - -} +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.jpa.session; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.database.DatabaseSession; + +import java.util.*; + +import javax.persistence.EntityManager; +import javax.persistence.NonUniqueResultException; +import javax.persistence.PersistenceException; +import javax.persistence.Query; + +public class JpaDatabaseSession extends DatabaseSession { + + private final DatabaseConnector connector; + private EntityManager entityManager = null; + private int index = 0; + private boolean inTransaction = false; + + public JpaDatabaseSession(DatabaseConnector connector) { + this.connector = connector; + } + + /** + * Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling, + * which done in methods of this class. + */ + public EntityManager getEntityManager() { + return entityManager; + } + + public void start() { + entityManager = connector.createEntityManager(); + index = 0; + } + + public void stop() { + commit(); + if (entityManager != null && entityManager.isOpen()) { + entityManager.close(); + entityManager = null; + } + } + + public void commit() { + if (entityManager != null && inTransaction) { + if (entityManager.isOpen()) { + if (entityManager.getTransaction().getRollbackOnly()) { + entityManager.getTransaction().rollback(); + } else { + entityManager.getTransaction().commit(); + } + entityManager.clear(); + index = 0; + } + inTransaction = false; + } + } + + public void rollback() { + if (entityManager != null && inTransaction) { + entityManager.getTransaction().rollback(); + inTransaction = false; + } + } + + public T save(T model) { + startTransaction(); + internalSave(model, true); + return model; + } + + public Object saveWithoutFlush(Object model) { + startTransaction(); + internalSave(model, false); + return model; + } + + public boolean contains(Object model) { + startTransaction(); + return entityManager.contains(model); + } + + public void save(Object... models) { + startTransaction(); + for (Object model : models) { + save(model); + } + } + + private void internalSave(Object model, boolean flushIfNeeded) { + try { + entityManager.persist(model); + } catch (PersistenceException e) { + /* + * See http://jira.codehaus.org/browse/SONAR-2234 + * In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here. + */ + throw new PersistenceException("Unable to persist : " + model, e); + } + if (flushIfNeeded && (++index % BATCH_SIZE == 0)) { + commit(); + } + } + + public Object merge(Object model) { + startTransaction(); + return entityManager.merge(model); + } + + public void remove(Object model) { + startTransaction(); + entityManager.remove(model); + if (++index % BATCH_SIZE == 0) { + commit(); + } + } + + public void removeWithoutFlush(Object model) { + startTransaction(); + entityManager.remove(model); + } + + public T reattach(Class entityClass, Object primaryKey) { + startTransaction(); + return entityManager.getReference(entityClass, primaryKey); + } + + private void startTransaction() { + if (!inTransaction) { + entityManager.getTransaction().begin(); + inTransaction = true; + } + } + + /** + * Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling, + * which done in {@link #getSingleResult(Query, Object)}. + */ + public Query createQuery(String hql) { + startTransaction(); + return entityManager.createQuery(hql); + } + + @Override + public Query createNativeQuery(String sql) { + startTransaction(); + return entityManager.createNativeQuery(sql); + } + + /** + * @return the result or defaultValue, if not found + * @throws NonUniqueResultException if more than one result + */ + public T getSingleResult(Query query, T defaultValue) { + /* + * See http://jira.codehaus.org/browse/SONAR-2225 + * By default Hibernate throws NonUniqueResultException without meaningful information about context, + * so we improve it here by adding all results in error message. + * Note that in some rare situations we can receive too many results, which may lead to OOME, + * but actually it will mean that database is corrupted as we don't expect more than one result + * and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood. + */ + List result = query.getResultList(); + + if (result.size() == 1) { + return result.get(0); + + } else if (result.isEmpty()) { + return defaultValue; + + } else { + Set uniqueResult = new HashSet(result); + if (uniqueResult.size() > 1) { + throw new NonUniqueResultException("Expected single result, but got : " + result.toString()); + } else { + return uniqueResult.iterator().next(); + } + } + } + + public T getEntity(Class entityClass, Object id) { + startTransaction(); + return getEntityManager().find(entityClass, id); + } + + /** + * @return the result or null, if not found + * @throws NonUniqueResultException if more than one result + */ + public T getSingleResult(Class entityClass, Object... criterias) { + try { + return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null); + + } catch (NonUniqueResultException ex) { + NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName() + + " with criterias : " + StringUtils.join(criterias, ",")); + e.initCause(ex); + throw e; + } + } + + public List getResults(Class entityClass, Object... criterias) { + return getQueryForCriterias(entityClass, true, criterias).getResultList(); + } + + public List getResults(Class entityClass) { + return getQueryForCriterias(entityClass, false, null).getResultList(); + } + + private Query getQueryForCriterias(Class entityClass, boolean raiseError, Object... criterias) { + if (criterias == null && raiseError) { + throw new IllegalStateException("criterias parameter must be provided"); + } + startTransaction(); + StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o"); + if (criterias != null) { + hql.append(" WHERE "); + Map mappedCriterias = new HashMap(); + for (int i = 0; i < criterias.length; i += 2) { + mappedCriterias.put((String) criterias[i], criterias[i + 1]); + } + buildCriteriasHQL(hql, mappedCriterias); + Query query = getEntityManager().createQuery(hql.toString()); + + for (Map.Entry entry : mappedCriterias.entrySet()) { + query.setParameter(entry.getKey(), entry.getValue()); + } + return query; + } + return getEntityManager().createQuery(hql.toString()); + } + + private void buildCriteriasHQL(StringBuilder hql, Map mappedCriterias) { + for (Iterator i = mappedCriterias.keySet().iterator(); i.hasNext();) { + String criteria = i.next(); + hql.append("o.").append(criteria).append("=:").append(criteria); + if (i.hasNext()) { + hql.append(" AND "); + } + } + } + +} -- cgit v1.2.3