com.addc.commons.database.derby.DerbyDatabase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of addc-base Show documentation
Show all versions of addc-base Show documentation
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.
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);
}
}
}
}