001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2011 SonarSource 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.jpa.session; 021 022 import org.slf4j.Logger; 023 import org.slf4j.LoggerFactory; 024 import org.sonar.api.utils.Logs; 025 import org.sonar.core.persistence.Database; 026 import org.sonar.core.persistence.dialect.Dialect; 027 import org.sonar.jpa.entity.SchemaMigration; 028 029 import javax.persistence.EntityManager; 030 import javax.persistence.EntityManagerFactory; 031 import javax.persistence.Persistence; 032 import java.sql.Connection; 033 import java.sql.SQLException; 034 import java.util.Map; 035 import java.util.Properties; 036 037 public abstract class AbstractDatabaseConnector implements DatabaseConnector { 038 protected static final Logger LOG = LoggerFactory.getLogger(AbstractDatabaseConnector.class); 039 040 protected Database database; 041 private EntityManagerFactory factory = null; 042 private int databaseVersion = SchemaMigration.VERSION_UNKNOWN; 043 private boolean operational = false; 044 private boolean started = false; 045 046 protected AbstractDatabaseConnector(Database database) { 047 this.database = database; 048 } 049 050 public String getDialectId() { 051 return database.getDialect().getId(); 052 } 053 054 /** 055 * Indicates if the connector is operational : database connection OK and schema version OK 056 */ 057 public boolean isOperational() { 058 return operational; 059 } 060 061 /** 062 * Indicates if the connector is started : database connection OK and schema version OK or KO 063 */ 064 protected boolean isStarted() { 065 return started; 066 } 067 068 public void start() { 069 if (!started) { 070 testConnection(); 071 started = true; 072 } 073 if (!operational) { 074 boolean upToDate = upToDateSchemaVersion(); 075 if (upToDate) { 076 Logs.INFO.info("Initializing Hibernate"); 077 factory = createEntityManagerFactory(); 078 operational = true; 079 } 080 } 081 } 082 083 public void stop() { 084 if (factory != null && factory.isOpen()) { 085 factory.close(); 086 factory = null; 087 } 088 operational = false; 089 started = false; 090 database = null; 091 } 092 093 public EntityManagerFactory getEntityManagerFactory() { 094 return factory; 095 } 096 097 protected void setEntityManagerFactory(EntityManagerFactory factory) { 098 this.factory = factory; 099 } 100 101 protected EntityManagerFactory createEntityManagerFactory() { 102 // other settings are stored into /META-INF/persistence.xml 103 Properties props = database.getHibernateProperties(); 104 logHibernateSettings(props); 105 return Persistence.createEntityManagerFactory("sonar", props); 106 } 107 108 private void logHibernateSettings(Properties props) { 109 if (LOG.isDebugEnabled()) { 110 for (Map.Entry<Object, Object> entry : props.entrySet()) { 111 LOG.debug(entry.getKey() + ": " + entry.getValue()); 112 } 113 } 114 } 115 116 public EntityManager createEntityManager() { 117 return factory.createEntityManager(); 118 } 119 120 private String testConnection() throws DatabaseException { 121 Connection connection = null; 122 try { 123 connection = getConnection(); 124 return connection.getMetaData().getURL(); 125 126 } catch (SQLException e) { 127 throw new DatabaseException("Cannot open connection to database: " + e.getMessage(), e); 128 129 } finally { 130 close(connection); 131 } 132 } 133 134 protected int loadVersion() { 135 Connection connection = null; 136 try { 137 connection = getConnection(); 138 return SchemaMigration.getCurrentVersion(connection); 139 140 } catch (SQLException e) { 141 // schema not created 142 return 0; 143 } finally { 144 close(connection); 145 } 146 } 147 148 private void close(Connection connection) { 149 if (connection != null) { 150 try { 151 connection.close(); 152 } catch (SQLException e) { 153 // why does close() throw a checked-exception ??? 154 } 155 } 156 } 157 158 protected boolean upToDateSchemaVersion() { 159 if (databaseVersion == SchemaMigration.LAST_VERSION) { 160 return true; 161 } 162 databaseVersion = loadVersion(); 163 return databaseVersion == SchemaMigration.LAST_VERSION; 164 } 165 166 public final int getDatabaseVersion() { 167 return databaseVersion; 168 } 169 170 public final Dialect getDialect() { 171 return database.getDialect(); 172 } 173 }