/**
* Copyright (C) 2007 - 2016 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* • Apache License, version 2.0
* • Apache Software License, version 1.0
* • GNU Lesser General Public License, version 3
* • Mozilla Public License, versions 1.0, 1.1 and 2.0
* • Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* License version 2 and the aforementioned licenses.
*
* 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.
*/
package org.n52.wps.server.database;
import java.io.File;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @note Uses lazy initialization without synchronization
*/
public class DerbyDatabase extends AbstractDatabase {
private static Logger LOGGER = LoggerFactory.getLogger(DerbyDatabase.class); // Get access to the global logger.
private static String connectionURL = null;
private static Connection conn = null;
private static DerbyDatabase db = new DerbyDatabase(); // Static loading.
/**
* Static initialization is guaranteed to be thread-safe and no synchronization must be incurred.
*/
private DerbyDatabase() {
try {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
String dbDriverURI = "jdbc:derby";
DerbyDatabase.connectionURL = dbDriverURI + ":" + getDatabasePath() + File.separator + getDatabaseName();
LOGGER.debug("Database connection URL is: " + DerbyDatabase.connectionURL);
} catch(ClassNotFoundException cnf_ex) {
LOGGER.error("Database cannot be loaded: " + connectionURL);
throw new UnsupportedDatabaseException("The database class could not be loaded.");
}
if(!DerbyDatabase.createConnection()) {
throw new RuntimeException("Creating database connection failed.");
}
if(!DerbyDatabase.createResultTable()) {
throw new RuntimeException("Creating result table failed.");
}
if(!DerbyDatabase.createPreparedStatements()) {
throw new RuntimeException("Creating prepared statements failed.");
}
}
public static synchronized DerbyDatabase getInstance() {
if (DerbyDatabase.conn == null) {
if(!DerbyDatabase.createConnection()) {
throw new RuntimeException("Creating database connection failed.");
}
if(!DerbyDatabase.createResultTable()) {
throw new RuntimeException("Creating result table failed.");
}
if(!DerbyDatabase.createPreparedStatements()) {
throw new RuntimeException("Creating prepared statements failed.");
}
}
return DerbyDatabase.db;
}
private static boolean createConnection() {
Properties props = new Properties();
DerbyDatabase.conn = null;
// Try to connect to an existing database. Note that create is set to true.
try {
DerbyDatabase.conn = DriverManager.getConnection(
DerbyDatabase.connectionURL + ";create=true", props);
LOGGER.info("Connected to WPS database.");
} catch (SQLException e) {
LOGGER.error("Could not connect to or create the database.");
return false;
}
return true;
}
private static boolean createResultTable() {
try {
ResultSet rs = null;
DatabaseMetaData meta = DerbyDatabase.conn.getMetaData();
rs = meta.getTables(null, null, "RESULTS",
new String[] { "TABLE" });
if (!rs.next()) {
LOGGER.info("Table RESULTS does not yet exist.");
Statement st = DerbyDatabase.conn.createStatement();
st.executeUpdate(DerbyDatabase.creationString);
DerbyDatabase.conn.commit();
rs = null;
meta = DerbyDatabase.conn.getMetaData();
rs = meta.getTables(null, null, "RESULTS",
new String[] { "TABLE" });
if (rs.next()) {
LOGGER.info("Succesfully created table RESULTS.");
} else {
LOGGER.error("Could not create table RESULTS.");
return false;
}
// Set upcoming statements to autocommit.
DerbyDatabase.conn.setAutoCommit(false);
}
} catch (SQLException e) {
LOGGER.error("Connection to the HSQL database failed: "
+ e.getMessage());
return false;
}
return true;
}
private static boolean createPreparedStatements() {
// Create prepared staments (more efficient).
try {
DerbyDatabase.closePreparedStatements();
DerbyDatabase.insertSQL = DerbyDatabase.conn.prepareStatement(insertionString);
DerbyDatabase.selectSQL = DerbyDatabase.conn.prepareStatement(selectionString);
DerbyDatabase.updateSQL = DerbyDatabase.conn.prepareStatement(updateString);
} catch (SQLException e) {
LOGGER.error("Could not create the prepared statements.");
return false;
}
return true;
}
@Override
public Connection getConnection() {
return DerbyDatabase.conn;
}
@Override
public String getConnectionURL() {
return DerbyDatabase.connectionURL;
}
/**
* Shutdown the database in a clean, safe way.
*/
/*
public void shutdown() {
boolean gotSQLExc = false;
try {
HSQLDatabase.conn.close();
DriverManager.getConnection(HSQLDatabase.connectionURL);
HSQLDatabase.db = null;
System.gc();
} catch (SQLException se) {
if (se.getSQLState().equals("XJ015")) {
gotSQLExc = true;
}
}
if (!gotSQLExc) {
LOGGER.error("Database did not shut down normally");
} else {
LOGGER.info("Database shut down normally");
}
}
*/
/**
* Shutdown the database in a clean, safe way.
*/
@Override
public void shutdown() {
boolean flag0 = false, flag1 = false;
try {
if (DerbyDatabase.conn != null) {
// Close PreparedStatements if needed.
flag0 = closePreparedStatements();
DerbyDatabase.conn = DriverManager.getConnection(DerbyDatabase.connectionURL + ";shutdown=true");
// Return to connection pool.
DerbyDatabase.conn.close();
DerbyDatabase.conn = null;
flag1 = true;
// Force garbage collection.
System.gc();
// Setting the database to null;
DerbyDatabase.db = null;
}
} catch (SQLException sql_ex) {
LOGGER.error("Error occured while closing connection: " +
sql_ex.getMessage() + "::"
+ "closed prepared statements?" + flag0
+ ";closed connection?" + flag1);
return;
} catch(Exception exception) {
LOGGER.error("Error occured while closing connection: " +
exception.getMessage() + "::"
+ "closed prepared statements?" + flag0
+ ";closed connection?" + flag1);
return;
} finally {
// Make sure the connection is returned to the pool.
if (DerbyDatabase.conn!= null) {
try { DerbyDatabase.conn.close(); } catch (SQLException e) { ; }
DerbyDatabase.conn = null;
}
}
LOGGER.info("Derby database connection is closed succesfully");
}
/**
* Always make sure the statements are closed, when you exit.
*/
private static boolean closePreparedStatements() {
try {
if(DerbyDatabase.insertSQL != null) {
DerbyDatabase.insertSQL.close();
DerbyDatabase.insertSQL = null;
}
if(DerbyDatabase.selectSQL != null) {
DerbyDatabase.selectSQL.close();
DerbyDatabase.selectSQL = null;
}
if(DerbyDatabase.updateSQL != null) {
DerbyDatabase.updateSQL.close();
DerbyDatabase.updateSQL = null;
}
} catch(SQLException sql_ex) {
LOGGER.error("Prepared statements could not be closed.");
return false;
}
return true;
}
@Override
public boolean deleteStoredResponse(String id) {
// TODO Auto-generated method stub
return false;
}
@Override
public File lookupResponseAsFile(String id) {
// TODO Auto-generated method stub
return null;
}
}