/** * 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; } }