All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.addc.commons.database.derby.DerbyDatabase Maven / Gradle / Ivy

Go to download

The addc-base library supplies classes for creating UUIDs, converting between types, outputting byte arrays with different formats, support for Julian dates, delay generators, parsing properties files and support for I18N.

There is a newer version: 2.6
Show newest version
package com.addc.commons.database.derby;

import java.io.File;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.addc.commons.Constants;
import com.addc.commons.database.Database;
import com.addc.commons.database.DatabaseException;

/**
 * The DerbyDatabase represents a Derby database using the embedded Derby JDBC
 * driver.
 * 
 */
@SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes")
public class DerbyDatabase implements Database {
    private static final Logger LOGGER= LoggerFactory.getLogger(DerbyDatabase.class);

    private static final String DRIVER= "org.apache.derby.jdbc.EmbeddedDriver";
    private static final String PROTOCOL= "jdbc:derby:";
    private static final String CREATE_ATTRIBUTE= ";create=true";
    private static final String SHUTDOWN_ATTRIBUTE= ";shutdown=true;deregister=false";
    private static final String ENCRYPT_ATTRIBUTE= ";dataEncryption=true;encryptionAlgorithm=AES/CBC/NoPadding;encryptionKey=";
    private static final char[] SEED= "wfhsuz+A++KNASGAfYDgxQhzsLrG3AnN".toCharArray();

    private final String dbUri;
    private final String location;

    // We need this class load as otherwise the JDBC cannot find the driver when
    // running in a web application.
    static {
        try {
            Class.forName(DRIVER).newInstance();
            LOGGER.debug("Loaded the appropriate driver");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(
                    "Unable to load or instanntiatethe JDBC driver " + DRIVER + ". Check your CLASSPATH.", e);
        }
    }

    /**
     * Create new DerbyDatabase
     * 
     * @param directory
     *            the directory where the database should be placed
     * @param isConfidential
     *            whether the database contains data in encrypted form
     * @throws DatabaseException
     *             if there is any error while loading the database engine
     */
    public DerbyDatabase(String directory, boolean isConfidential) throws DatabaseException {
        try {
            if (isConfidential) {
                this.dbUri= PROTOCOL + directory + ENCRYPT_ATTRIBUTE + generateSecret();
            } else {
                this.dbUri= PROTOCOL + directory;
            }

            createOrOpen();
            File dbPath= new File(directory);
            this.location= dbPath.getAbsolutePath();
        } catch (SQLException e) {
            throw new DatabaseException("Failed to create Derby database", e);
        }
    }

    @Override
    public void shutdown() {
        try {
            LOGGER.info("Shutdown the database");
            DriverManager.getConnection(dbUri + SHUTDOWN_ATTRIBUTE);
        } catch (SQLException e) {
            // See
            // http://db.apache.org/derby/docs/dev/getstart/rwwdactivity3.html
            // for an explanation of this check
            if (((e.getErrorCode() == 45000) && ("08006".equals(e.getSQLState())))) {
                // We got the expected exception
                // Note that for single database shutdown, the expected
                // SQL state is "08006", and the error code is 45000.
                LOGGER.info("Derby database is closed");
            } else {
                // if the error code or SQLState are different, we have
                // an unexpected exception (shutdown failed)
                LOGGER.warn("Derby database closed abnormally", e);
            }
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection(dbUri);
    }

    @Override
    public boolean hasTable(String tableName) {
        boolean result= false;
        Connection conn= null;
        ResultSet tables= null;
        try {
            conn= getConnection();
            DatabaseMetaData metadata= conn.getMetaData();
            tables= metadata.getTables(conn.getCatalog(), null, tableName, null);
            result= tables.next();
        } catch (SQLException e) {
            LOGGER.error("SQL error occured while checking table " + tableName + " in the database", e);
        } finally {
            close(tables);
            close(conn);
        }

        return result;
    }

    @Override
    public String getLocation() {
        return location;
    }

    /**
     * Generates an AES encryption key - based on the hard coded value of SEED -
     * of 256 bits keys size
     * 
     * @return the key used for encryption
     */
    private String generateSecret() {
        String str= new String(SEED);
        BigInteger secret= new BigInteger(str.substring(0, 32).getBytes(Constants.UTF8));
        return secret.toString(16);
    }

    private void createOrOpen() throws SQLException {
        Connection conn= null;
        try {
            conn= DriverManager.getConnection(dbUri + CREATE_ATTRIBUTE);
        } finally {
            close(conn);
        }
    }

    private void close(AutoCloseable obj) {
        if (obj != null) {
            try {
                obj.close();
            } catch (Exception e) {
                LOGGER.error("Error closing object", e);
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy