/*
* Copyright (C) 2013 Jan Pokorsky
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.cas.lib.proarc.common.dao.empiredb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Timestamp;
import javax.sql.DataSource;
import org.apache.empire.data.DataType;
import org.apache.empire.db.DBCmdType;
import org.apache.empire.db.DBColumn;
import org.apache.empire.db.DBDatabase;
import org.apache.empire.db.DBDatabaseDriver;
import org.apache.empire.db.DBObject;
import org.apache.empire.db.DBSQLScript;
import org.apache.empire.db.DBTable;
import org.apache.empire.db.DBTableColumn;
import org.apache.empire.db.postgresql.DBDatabaseDriverPostgreSQL;
import org.apache.empire.db.postgresql.PostgreDDLGenerator;
/**
*
* @author Jan Pokorsky
*/
public final class EmpireConfiguration {
private final ProarcDatabase schema;
private String jdbcClass;
private String jdbcURL;
private String jdbcUser;
private String jdbcPwd;
private String empireDBDriverClass;
private String databaseName;
private DataSource dataSource;
public EmpireConfiguration(
String jdbcClass,
String jdbcURL,
String jdbcUser,
String jdbcPwd,
String empireDBDriverClass,
String databaseName
) {
this(databaseName, empireDBDriverClass);
this.jdbcClass = jdbcClass;
this.jdbcURL = jdbcURL;
this.jdbcUser = jdbcUser;
this.jdbcPwd = jdbcPwd;
}
public EmpireConfiguration(String databaseName, String empireDBDriverClass, DataSource dataSource) {
this(databaseName, empireDBDriverClass);
this.dataSource = dataSource;
}
protected EmpireConfiguration(String databaseName, String empireDBDriverClass) {
this.empireDBDriverClass = empireDBDriverClass;
this.databaseName = databaseName;
schema = new ProarcDatabase();
}
public ProarcDatabase getSchema() {
return schema;
}
public DBDatabaseDriver getDriver() {
if (DBDatabaseDriverPostgreSQL.class.getName().equals(empireDBDriverClass)) {
if (databaseName == null || databaseName.isEmpty()) {
// throw new IllegalStateException("databaseName\n" + toString());
}
// DBDatabaseDriverPostgreSQL drv = new DBDatabaseDriverPostgreSQL();
DBDatabaseDriverPostgreSQL drv = new FixedDBDatabaseDriverPostgreSQL();
// drv.setDatabaseName(databaseName);
return drv;
} else {
throw new UnsupportedOperationException("empireDBDriverClass\n" + toString());
}
}
public Connection getConnection() throws SQLException {
if (dataSource != null) {
return dataSource.getConnection();
} else {
return getPostgresConnection();
}
}
private Connection getPostgresConnection() throws SQLException {
try {
Class.forName(jdbcClass);
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(jdbcClass, ex);
}
Connection c = DriverManager.getConnection(jdbcURL, jdbcUser, jdbcPwd);
c.setAutoCommit(false);
return c;
}
public static EmpireConfiguration postgres(DataSource ds) {
return new EmpireConfiguration(null, DBDatabaseDriverPostgreSQL.class.getName(), ds);
}
@Override
public String toString() {
return "EmpireConfiguration{"
+ "jdbcClass=" + jdbcClass
+ ", jdbcURL=" + jdbcURL
+ ", jdbcUser=" + jdbcUser
// + ", jdbcPwd=" + jdbcPwd
+ ", empireDBDriverClass=" + empireDBDriverClass
+ ", databaseName=" + databaseName
+ ", dataSource=" + dataSource
+ '}';
}
private static final class FixedDBDatabaseDriverPostgreSQL extends DBDatabaseDriverPostgreSQL {
private static final long serialVersionUID = 1L;
private PostgreDDLGenerator ddlGenerator;
public FixedDBDatabaseDriverPostgreSQL() {
// e.g. for DATETIME:
// addColumn("CREATED", DataType.DATETIME, 0, true, SYSDATE);
// generate DEFAULT NOW()
// see DBDDLGenerator.appendColumnDesc
setDDLColumnDefaults(true);
}
@Override
public String getSQLPhrase(int phrase) {
switch (phrase) {
// store milliseconds within timestamp
// see http://empire-db.15390.n3.nabble.com/DBSequence-Table-and-PostGre-td925674.html
case SQL_DATETIME_PATTERN :
return "yyyy-MM-dd HH:mm:ss.SSS";
}
return super.getSQLPhrase(phrase); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void getDDLScript(DBCmdType type, DBObject dbo, DBSQLScript script) {
if (ddlGenerator == null) {
ddlGenerator = new FixedPostgreDDLGenerator(this);
}
// forward request
ddlGenerator.getDDLScript(type, dbo, script);
}
@Override
protected String getSQLDateTimeString(Object value, int sqlTemplate, int sqlPattern, int sqlCurrentDate) {
if (value instanceof Timestamp && sqlPattern == SQL_DATETIME_PATTERN) {
// gets timestamp in full precision
// Postgres default timestamp precision is microseconds!
return '\'' +((Timestamp) value).toString() + '\'';
}
return super.getSQLDateTimeString(value, sqlTemplate, sqlPattern, sqlCurrentDate);
}
@Override
public Timestamp getUpdateTimestamp(Connection conn) {
return new Timestamp(System.currentTimeMillis());
}
}
/**
* The generator does not create a sequence for newly added table to existing database.
* {@code createDatabase} and {@code createTable} fix it.
*
* <p>For now the generator creates no sequence as they are produced by PostgreSql.
*/
private static final class FixedPostgreDDLGenerator extends PostgreDDLGenerator {
private boolean isCreateDatabase;
public FixedPostgreDDLGenerator(DBDatabaseDriverPostgreSQL driver) {
super(driver);
}
@Override
protected void createDatabase(DBDatabase db, DBSQLScript script) {
isCreateDatabase = true;
try {
super.createDatabase(db, script);
} finally {
isCreateDatabase = false;
}
}
@Override
protected void createTable(DBTable t, DBSQLScript script) {
if (!isCreateDatabase) {
for (DBColumn c : t.getColumns()) {
if (c.getDataType() == DataType.AUTOINC) {
createSequence(t.getDatabase(), (DBTableColumn) c, script);
}
}
}
super.createTable(t, script);
}
@Override
protected void createSequence(DBDatabase db, DBTableColumn c, DBSQLScript script) {
// PostgreSql creates sequences itself for SERIAL type.
}
}
}