mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-25 10:32:00 +01:00
re-structured the database connection factory
Former-commit-id: 5d84399dcb20a271a8e41414ca0604e8a9908727
This commit is contained in:
@@ -24,6 +24,7 @@ import java.io.InputStream;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.Driver;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -50,6 +51,22 @@ public final class ConnectionFactory {
|
|||||||
* Resource location for SQL file used to create the database schema.
|
* Resource location for SQL file used to create the database schema.
|
||||||
*/
|
*/
|
||||||
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
|
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
|
||||||
|
/**
|
||||||
|
* The database driver used to connect to the database.
|
||||||
|
*/
|
||||||
|
private static Driver driver = null;
|
||||||
|
/**
|
||||||
|
* The database connection string.
|
||||||
|
*/
|
||||||
|
private static String connectionString = null;
|
||||||
|
/**
|
||||||
|
* The username to connect to the database.
|
||||||
|
*/
|
||||||
|
private static String userName = null;
|
||||||
|
/**
|
||||||
|
* The password for the database.
|
||||||
|
*/
|
||||||
|
private static String password = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor for this factory class; no instance is ever needed.
|
* Private constructor for this factory class; no instance is ever needed.
|
||||||
@@ -58,79 +75,130 @@ public final class ConnectionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new database connection object per the database configuration. This will load the appropriate
|
* Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be
|
||||||
* database driver, via the DriverManager, if configured.
|
* made successfully.
|
||||||
*
|
*
|
||||||
* @return a database connection object
|
* @throws DatabaseException thrown if we are unable to connect to the database
|
||||||
* @throws DatabaseException thrown if there is an exception loading the database connection
|
|
||||||
*/
|
*/
|
||||||
public static Connection getConnection() throws DatabaseException {
|
public static void initialize() throws DatabaseException {
|
||||||
Connection conn = null;
|
//load the driver if necessary
|
||||||
String connStr = null;
|
|
||||||
final String user = Settings.getString(Settings.KEYS.DB_USER, "dcuser");
|
|
||||||
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
|
||||||
final String pass = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
|
||||||
try {
|
|
||||||
connStr = getConnectionString();
|
|
||||||
|
|
||||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading database connection");
|
|
||||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Connection String: {0}", connStr);
|
|
||||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Database User: {0}", user);
|
|
||||||
boolean createTables = false;
|
|
||||||
if (connStr.startsWith("jdbc:h2:file:")) { //H2
|
|
||||||
createTables = needToCreateDatabaseStructure();
|
|
||||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Need to create DB Structure: {0}", createTables);
|
|
||||||
}
|
|
||||||
final String driverName = Settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
final String driverName = Settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
||||||
if (!driverName.isEmpty()) { //likely need to load the correct driver
|
if (!driverName.isEmpty()) { //likely need to load the correct driver
|
||||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver: {0}", driverName);
|
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver: {0}", driverName);
|
||||||
final String driverPath = Settings.getString(Settings.KEYS.DB_DRIVER_PATH, "");
|
final String driverPath = Settings.getString(Settings.KEYS.DB_DRIVER_PATH, "");
|
||||||
if (!driverPath.isEmpty()) { //ugh, driver is not on classpath?
|
try {
|
||||||
|
if (!driverPath.isEmpty()) {
|
||||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver from: {0}", driverPath);
|
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver from: {0}", driverPath);
|
||||||
DriverLoader.load(driverName, driverPath);
|
driver = DriverLoader.load(driverName, driverPath);
|
||||||
} else {
|
} else {
|
||||||
DriverLoader.load(driverName);
|
driver = DriverLoader.load(driverName);
|
||||||
}
|
}
|
||||||
|
} catch (DriverLoadException ex) {
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Unable to load database driver", ex);
|
||||||
|
throw new DatabaseException("Unable to load database driver");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
connectionString = getConnectionString();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE,
|
||||||
|
"Unable to retrieve the database connection string", ex);
|
||||||
|
throw new DatabaseException("Unable to retrieve the database connection string");
|
||||||
|
}
|
||||||
|
userName = Settings.getString(Settings.KEYS.DB_USER, "dcuser");
|
||||||
|
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
||||||
|
password = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
||||||
|
|
||||||
|
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading database connection");
|
||||||
|
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Connection String: {0}", connectionString);
|
||||||
|
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Database User: {0}", userName);
|
||||||
|
|
||||||
|
Connection conn = null;
|
||||||
|
try {
|
||||||
|
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
if (ex.getMessage().contains("java.net.UnknownHostException") && connectionString.contains("AUTO_SERVER=TRUE;")) {
|
||||||
|
connectionString = connectionString.replace("AUTO_SERVER=TRUE;", "");
|
||||||
|
try {
|
||||||
|
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||||
|
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Unable to start the database in server mode; reverting to single user mode");
|
||||||
|
} catch (SQLException sqlex) {
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Unable to connect to the database", ex);
|
||||||
|
throw new DatabaseException("Unable to connect to the database");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Unable to connect to the database", ex);
|
||||||
|
throw new DatabaseException("Unable to connect to the database");
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = DriverManager.getConnection(connStr, user, pass);
|
boolean shouldCreateSchema = false;
|
||||||
if (createTables) {
|
try {
|
||||||
|
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
||||||
|
shouldCreateSchema = !dbSchemaExists();
|
||||||
|
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Need to create DB Structure: {0}", shouldCreateSchema);
|
||||||
|
}
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Unable to verify database exists", ioex);
|
||||||
|
throw new DatabaseException("Unable to verify database exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldCreateSchema) {
|
||||||
try {
|
try {
|
||||||
createTables(conn);
|
createTables(conn);
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException dex) {
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, dex);
|
||||||
throw new DatabaseException("Unable to create the database structure");
|
throw new DatabaseException("Unable to create the database structure");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ensureSchemaVersion(conn);
|
ensureSchemaVersion(conn);
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException dex) {
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, dex);
|
||||||
throw new DatabaseException("Database schema does not match this version of dependency-check");
|
throw new DatabaseException("Database schema does not match this version of dependency-check");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} finally {
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
if (conn != null) {
|
||||||
throw new DatabaseException("Unable to load database");
|
|
||||||
} catch (DriverLoadException ex) {
|
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
|
||||||
throw new DatabaseException("Unable to load database driver");
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
if (ex.getMessage().contains("java.net.UnknownHostException") && connStr.contains("AUTO_SERVER=TRUE;")) {
|
|
||||||
final String newConnStr = connStr.replace("AUTO_SERVER=TRUE;", "");
|
|
||||||
try {
|
try {
|
||||||
conn = DriverManager.getConnection(newConnStr, user, pass);
|
conn.close();
|
||||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, newConnStr);
|
} catch (SQLException ex) {
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.WARNING, "Unable to start the database in server mode; reverting to single user mode");
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "An error occured closing the connection", ex);
|
||||||
} catch (SQLException sqlex) {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up resources and unloads any registered database drivers.
|
||||||
|
*/
|
||||||
|
public static void cleanup() {
|
||||||
|
if (driver != null) {
|
||||||
|
try {
|
||||||
|
DriverManager.deregisterDriver(driver);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "An error occured unloading the databse driver", ex);
|
||||||
|
}
|
||||||
|
driver = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new database connection object per the database configuration.
|
||||||
|
*
|
||||||
|
* @return a database connection object
|
||||||
|
* @throws DatabaseException thrown if there is an exception loading the database connection
|
||||||
|
*/
|
||||||
|
public static Connection getConnection() throws DatabaseException {
|
||||||
|
initialize();
|
||||||
|
Connection conn = null;
|
||||||
|
try {
|
||||||
|
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||||
|
} catch (SQLException ex) {
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||||
throw new DatabaseException("Unable to connect to the database");
|
throw new DatabaseException("Unable to connect to the database");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
|
||||||
throw new DatabaseException("Unable to connect to the database");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,11 +243,11 @@ public final class ConnectionFactory {
|
|||||||
* @return true if the H2 database file does not exist; otherwise false
|
* @return true if the H2 database file does not exist; otherwise false
|
||||||
* @throws IOException thrown if the data directory does not exist and cannot be created
|
* @throws IOException thrown if the data directory does not exist and cannot be created
|
||||||
*/
|
*/
|
||||||
private static boolean needToCreateDatabaseStructure() throws IOException {
|
private static boolean dbSchemaExists() throws IOException {
|
||||||
final File dir = getDataDirectory();
|
final File dir = getDataDirectory();
|
||||||
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
|
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
|
||||||
final File file = new File(dir, name);
|
final File file = new File(dir, name);
|
||||||
return !file.exists();
|
return file.exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -47,11 +47,12 @@ public final class DriverLoader {
|
|||||||
* Loads the specified class using the system class loader and registers the driver with the driver manager.
|
* Loads the specified class using the system class loader and registers the driver with the driver manager.
|
||||||
*
|
*
|
||||||
* @param className the fully qualified name of the desired class
|
* @param className the fully qualified name of the desired class
|
||||||
|
* @return the loaded Driver
|
||||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||||
*/
|
*/
|
||||||
public static void load(String className) throws DriverLoadException {
|
public static Driver load(String className) throws DriverLoadException {
|
||||||
final ClassLoader loader = DriverLoader.class.getClassLoader(); //ClassLoader.getSystemClassLoader();
|
final ClassLoader loader = DriverLoader.class.getClassLoader(); //ClassLoader.getSystemClassLoader();
|
||||||
load(className, loader);
|
return load(className, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,9 +65,10 @@ public final class DriverLoader {
|
|||||||
* @param className the fully qualified name of the desired class
|
* @param className the fully qualified name of the desired class
|
||||||
* @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list
|
* @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list
|
||||||
* of paths
|
* of paths
|
||||||
|
* @return the loaded Driver
|
||||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||||
*/
|
*/
|
||||||
public static void load(String className, String pathToDriver) throws DriverLoadException {
|
public static Driver load(String className, String pathToDriver) throws DriverLoadException {
|
||||||
final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
||||||
final ArrayList<URL> urls = new ArrayList<URL>();
|
final ArrayList<URL> urls = new ArrayList<URL>();
|
||||||
final String[] paths = pathToDriver.split(File.pathSeparator);
|
final String[] paths = pathToDriver.split(File.pathSeparator);
|
||||||
@@ -103,7 +105,7 @@ public final class DriverLoader {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
load(className, loader);
|
return load(className, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,15 +113,18 @@ public final class DriverLoader {
|
|||||||
*
|
*
|
||||||
* @param className the fully qualified name of the desired class
|
* @param className the fully qualified name of the desired class
|
||||||
* @param loader the class loader to use when loading the driver
|
* @param loader the class loader to use when loading the driver
|
||||||
|
* @return the loaded Driver
|
||||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||||
*/
|
*/
|
||||||
private static void load(String className, ClassLoader loader) throws DriverLoadException {
|
private static Driver load(String className, ClassLoader loader) throws DriverLoadException {
|
||||||
try {
|
try {
|
||||||
final Class c = Class.forName(className, true, loader);
|
final Class c = Class.forName(className, true, loader);
|
||||||
//final Class c = loader.loadClass(className);
|
//final Class c = loader.loadClass(className);
|
||||||
final Driver driver = (Driver) c.newInstance();
|
final Driver driver = (Driver) c.newInstance();
|
||||||
|
final Driver shim = new DriverShim(driver);
|
||||||
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
|
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
|
||||||
DriverManager.registerDriver(new DriverShim(driver));
|
DriverManager.registerDriver(shim);
|
||||||
|
return shim;
|
||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||||
|
|||||||
Reference in New Issue
Block a user