/*
* This program is copyright (c) 2007 Hortis-GRC SA.
*
* This file is part of Sonar.
* Sonar is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package ch.hortis.sonar.jpa;
import ch.hortis.sonar.model.JdbcData;
import ch.hortis.sonar.model.SchemaInfo;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.NoResultException;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
/**
* Contains all functions to setup the database.
*/
public class Persistence {
public static final int MODEL_VERSION = 6;
protected final JdbcData jdbcData;
protected final Logger log;
private EntityManager manager;
protected Persistence(JdbcData jdbcData ) {
this.jdbcData = jdbcData;
this.log = LoggerFactory.getLogger( this.getClass().getName() );
}
public static Persistence create(JdbcData jdbcData) throws CreationException, ModelException {
Persistence persistence = new Persistence(jdbcData);
persistence.install();
return persistence;
}
public static boolean databaseExists( JdbcData jdbcData ) throws SQLException, ModelException {
Connection jdbcConn = null;
if ( jdbcData.getDatasource() != null ) {
DataSource ds = null;
try {
Context ctx = new InitialContext();
ds = (DataSource)ctx.lookup( jdbcData.getDatasource() );
} catch (Exception ex) {
SQLException sqlEx = new SQLException( "Error during datasource JNDI lookup" );
sqlEx.initCause( ex );
throw sqlEx;
}
jdbcConn = ds.getConnection();
} else {
try {
Class.forName( jdbcData.getDriverClassName() );
} catch ( ClassNotFoundException e ) {
throw new SQLException( "Cannot found sql driver " + jdbcData.getDriverClassName() );
}
jdbcConn = DriverManager.getConnection( jdbcData.getUrl(), jdbcData.getUsername(), jdbcData.getPassword() );
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = jdbcConn.createStatement();
rs = stmt.executeQuery( "SELECT version FROM " + SchemaInfo.TABLE_NAME );
while ( rs.next() ) {
int version = rs.getInt( 1 );
if ( version == MODEL_VERSION ) {
return true;
} else {
throw new ModelException("Database required model version (" + MODEL_VERSION + ") does not match current version (" + version + ")" );
}
}
} catch ( SQLException ex ) {
// don't care
} finally {
if ( rs != null ) rs.close();
if ( stmt != null ) stmt.close();
jdbcConn.close();
}
return false;
}
private void install() throws ModelException {
EntityManagerFactory factory = null;
SchemaInfo schemaInfo;
try {
factory = JPAUtil.getEntityManagerFactory(jdbcData, null);
} catch (javax.persistence.PersistenceException ex) {
log.debug("Persistence exception " + ex.getMessage());
// if an error exists trace should look like : org.hibernate.HibernateException: Missing table:
throw new ModelException( ex );
//createDatabase("create");
}
if ( manager == null ) {
manager = factory.createEntityManager();
}
Query query = manager.createQuery( "SELECT s FROM SchemaInfo s" );
try {
schemaInfo = (SchemaInfo)query.getSingleResult();
if ( schemaInfo.getVersion() != MODEL_VERSION ) {
throw new ModelException( "Database required model version (" + MODEL_VERSION + ") does not match current version (" + schemaInfo.getVersion() + ")");
}
} catch (NoResultException exception) {
throw new ModelException(exception.getMessage());
}
}
protected final void createDatabase(String creationMode) throws CreationException {
SchemaInfo schemaInfo = new SchemaInfo();
schemaInfo.setVersion( MODEL_VERSION );
Map<String, String> configuration = new HashMap<String, String>();
configuration.put("hibernate.hbm2ddl.auto", creationMode);
try {
EntityManagerFactory factory = JPAUtil.getEntityManagerFactory(jdbcData, configuration);
manager = factory.createEntityManager();
manager.getTransaction().begin();
manager.persist(schemaInfo);
manager.getTransaction().commit();
log.info("Database created");
} catch (javax.persistence.PersistenceException exception) {
throw new CreationException(exception);
}
}
public EntityManager getManager() {
return manager;
}
public void close() {
if ( manager.isOpen() ) {
manager.close();
}
}
public static class CreationException extends Exception {
private static final long serialVersionUID = 8635600658324384866L;
public CreationException(Throwable throwable) {
super(throwable);
}
}
public static class ModelException extends Exception {
private static final long serialVersionUID = 2768122252326410696L;
public ModelException(Throwable throwable) {
super(throwable);
}
public ModelException(String message) {
super(message);
}
}
protected final void setManager(EntityManager manager) {
this.manager = manager;
}
}