split out core DB functions into a base class to support storing settings in the database

Former-commit-id: 0c9d507e2e9e229691965aca09ef9f6c9e7e0965
This commit is contained in:
Jeremy Long
2013-11-19 21:05:12 -05:00
parent d29f989c22
commit 3850ef4355
2 changed files with 280 additions and 233 deletions

View File

@@ -0,0 +1,245 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Dependency-check-core 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.
*
* You should have received a copy of the GNU General Public License along with
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import static org.owasp.dependencycheck.data.nvdcve.CveDB.DB_SCHEMA_VERSION;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class BaseDB {
/**
* Resource location for SQL file used to create the database schema.
*/
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
/**
* The version of the current DB Schema.
*/
public static final String DB_SCHEMA_VERSION = "2.7";
/**
* Database connection
*/
private Connection conn;
/**
* Returns the database connection.
*
* @return the database connection
*/
protected Connection getConnection() {
return conn;
}
/**
* Opens the database connection. If the database does not exist, it will
* create a new one.
*
* @throws IOException thrown if there is an IO Exception
* @throws SQLException thrown if there is a SQL Exception
* @throws DatabaseException thrown if there is an error initializing a new
* database
* @throws ClassNotFoundException thrown if the h2 database driver cannot be
* loaded
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
value = "DMI_EMPTY_DB_PASSWORD",
justification = "Yes, I know... Blank password.")
public void open() throws IOException, SQLException, DatabaseException, ClassNotFoundException {
final String fileName = CveDB.getDataDirectory().getCanonicalPath();
final File f = new File(fileName, "cve." + DB_SCHEMA_VERSION);
final File check = new File(f.getAbsolutePath() + ".h2.db");
final boolean createTables = !check.exists();
final String connStr = String.format("jdbc:h2:file:%s;AUTO_SERVER=TRUE", f.getAbsolutePath());
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(connStr, "sa", "");
if (createTables) {
createTables();
}
}
/**
* Closes the DB4O database. Close should be called on this object when it
* is done being used.
*/
public void close() {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
Logger.getLogger(BaseDB.class.getName()).log(Level.SEVERE, msg, ex);
Logger.getLogger(BaseDB.class.getName()).log(Level.FINE, null, ex);
}
conn = null;
}
}
/**
* Commits all completed transactions.
*
* @throws SQLException thrown if a SQL Exception occurs
*/
public void commit() throws SQLException {
if (conn != null) {
conn.commit();
}
}
/**
* Cleans up the object and ensures that "close" has been called.
*
* @throws Throwable thrown if there is a problem
*/
@Override
protected void finalize() throws Throwable {
close();
super.finalize(); //not necessary if extending Object.
}
/**
* Creates the database structure (tables and indexes) to store the CVE data
*
* @throws SQLException thrown if there is a sql exception
* @throws DatabaseException thrown if there is a database exception
*/
private void createTables() throws SQLException, DatabaseException {
InputStream is;
InputStreamReader reader;
BufferedReader in = null;
try {
is = this.getClass().getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
reader = new InputStreamReader(is, "UTF-8");
in = new BufferedReader(reader);
final StringBuilder sb = new StringBuilder(2110);
String tmp;
while ((tmp = in.readLine()) != null) {
sb.append(tmp);
}
Statement statement = null;
try {
statement = conn.createStatement();
statement.execute(sb.toString());
} finally {
closeStatement(statement);
}
} catch (IOException ex) {
throw new DatabaseException("Unable to create database schema", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Retrieves the directory that the JAR file exists in so that we can ensure
* we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
public static File getDataDirectory() throws IOException {
final File path = Settings.getFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
}
}
return path;
}
/**
* Returns the generated integer primary key for a newly inserted row.
*
* @param statement a prepared statement that just executed an insert
* @return a primary key
* @throws DatabaseException thrown if there is an exception obtaining the
* key
*/
protected int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
ResultSet rs = null;
int id = 0;
try {
rs = statement.getGeneratedKeys();
rs.next();
id = rs.getInt(1);
} catch (SQLException ex) {
throw new DatabaseException("Unable to get primary key for inserted row");
} finally {
closeResultSet(rs);
}
return id;
}
/**
* Closes the given statement object ignoring any exceptions that occur.
*
* @param statement a Statement object
*/
public void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, statement.toString(), ex);
}
}
}
/**
* Closes the result set capturing and ignoring any SQLExceptions that
* occur.
*
* @param rs a ResultSet to close
*/
public void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, rs.toString(), ex);
}
}
}
}

View File

@@ -18,14 +18,7 @@
*/
package org.owasp.dependencycheck.data.nvdcve;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -36,6 +29,7 @@ import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.BaseDB;
import org.owasp.dependencycheck.data.cpe.IndexEntry;
import org.owasp.dependencycheck.data.cwe.CweDB;
import org.owasp.dependencycheck.dependency.Reference;
@@ -43,78 +37,65 @@ import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.owasp.dependencycheck.utils.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
import org.owasp.dependencycheck.utils.Settings;
/**
* The database holding information about the NVD CVE data.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class CveDB {
public class CveDB extends BaseDB {
/**
* Resource location for SQL file used to create the database schema.
*/
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
/**
* The version of the current DB Schema.
*/
public static final String DB_SCHEMA_VERSION = "2.7";
/**
* Database connection
*/
private Connection conn;
//<editor-fold defaultstate="collapsed" desc="Constants to create, maintain, and retrieve data from the CVE Database">
/**
* SQL Statement to delete references by vulnerability ID.
*/
public static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
private static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
/**
* SQL Statement to delete software by vulnerability ID.
*/
public static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
private static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
/**
* SQL Statement to delete a vulnerability by CVE.
*/
public static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE cve = ?";
private static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE cve = ?";
/**
* SQL Statement to cleanup orphan entries. Yes, the db schema could be a
* little tighter, but what we have works well to keep the data file size
* down a bit.
*/
public static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
private static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
/**
* SQL Statement to insert a new reference.
*/
public static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
private static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
/**
* SQL Statement to insert a new software.
*/
public static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
private static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
/**
* SQL Statement to insert a new cpe.
*/
public static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
private static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
/**
* SQL Statement to get a CPEProductID.
*/
public static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
private static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
/**
* SQL Statement to insert a new vulnerability.
*/
public static final String INSERT_VULNERABILITY = "INSERT INTO vulnerability (cve, description, cwe, cvssScore, cvssAccessVector, "
private static final String INSERT_VULNERABILITY = "INSERT INTO vulnerability (cve, description, cwe, cvssScore, cvssAccessVector, "
+ "cvssAccessComplexity, cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
/**
* SQL Statement to update a vulnerability.
*/
public static final String UPDATE_VULNERABILITY = "UPDATE vulnerability SET description=?, cwe=?, cvssScore=?, cvssAccessVector=?, "
private static final String UPDATE_VULNERABILITY = "UPDATE vulnerability SET description=?, cwe=?, cvssScore=?, cvssAccessVector=?, "
+ "cvssAccessComplexity=?, cvssAuthentication=?, cvssConfidentialityImpact=?, cvssIntegrityImpact=?, cvssAvailabilityImpact=? "
+ "WHERE id=?";
/**
* SQL Statement to find CVE entries based on CPE data.
*/
public static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
private static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
+ "FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveId "
+ "INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId "
+ "WHERE vendor = ? AND product = ?";
@@ -124,19 +105,19 @@ public class CveDB {
/**
* SQL Statement to find the CPE entry based on the vendor and product.
*/
public static final String SELECT_CPE_ENTRIES = "SELECT cpe FROM cpeEntry WHERE vendor = ? AND product = ?";
private static final String SELECT_CPE_ENTRIES = "SELECT cpe FROM cpeEntry WHERE vendor = ? AND product = ?";
/**
* SQL Statement to select references by CVEID.
*/
public static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
private static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
/**
* SQL Statement to select vendor and product for lucene index.
*/
public static final String SELECT_VENDOR_PRODUCT_LIST = "SELECT vendor, product FROM cpeEntry GROUP BY vendor, product";
private static final String SELECT_VENDOR_PRODUCT_LIST = "SELECT vendor, product FROM cpeEntry GROUP BY vendor, product";
/**
* SQL Statement to select software by CVEID.
*/
public static final String SELECT_SOFTWARE = "SELECT cpe, previousVersion "
private static final String SELECT_SOFTWARE = "SELECT cpe, previousVersion "
+ "FROM software INNER JOIN cpeEntry ON software.cpeEntryId = cpeEntry.id WHERE cveid = ?";
// public static final String SELECT_SOFTWARE = "SELECT part, vendor, product, version, revision, previousVersion "
// + "FROM software INNER JOIN cpeProduct ON cpeProduct.id = software.cpeProductId LEFT JOIN cpeVersion ON "
@@ -144,80 +125,14 @@ public class CveDB {
/**
* SQL Statement to select a vulnerability by CVEID.
*/
public static final String SELECT_VULNERABILITY = "SELECT id, description, cwe, cvssScore, cvssAccessVector, cvssAccessComplexity, "
private static final String SELECT_VULNERABILITY = "SELECT id, description, cwe, cvssScore, cvssAccessVector, cvssAccessComplexity, "
+ "cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact FROM vulnerability WHERE cve = ?";
/**
* SQL Statement to select a vulnerability's primary key.
*/
public static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
private static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
//</editor-fold>
/**
* Opens the database connection. If the database does not exist, it will
* create a new one.
*
* @throws IOException thrown if there is an IO Exception
* @throws SQLException thrown if there is a SQL Exception
* @throws DatabaseException thrown if there is an error initializing a new
* database
* @throws ClassNotFoundException thrown if the h2 database driver cannot be
* loaded
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
value = "DMI_EMPTY_DB_PASSWORD",
justification = "Yes, I know... Blank password.")
public void open() throws IOException, SQLException, DatabaseException, ClassNotFoundException {
final String fileName = CveDB.getDataDirectory().getCanonicalPath();
final File f = new File(fileName, "cve." + DB_SCHEMA_VERSION);
final File check = new File(f.getAbsolutePath() + ".h2.db");
final boolean createTables = !check.exists();
final String connStr = String.format("jdbc:h2:file:%s;AUTO_SERVER=TRUE", f.getAbsolutePath());
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(connStr, "sa", "");
if (createTables) {
createTables();
}
}
/**
* Commits all completed transactions.
*
* @throws SQLException thrown if a SQL Exception occurs
*/
public void commit() throws SQLException {
if (conn != null) {
conn.commit();
}
}
/**
* Cleans up the object and ensures that "close" has been called.
*
* @throws Throwable thrown if there is a problem
*/
@Override
protected void finalize() throws Throwable {
close();
super.finalize(); //not necessary if extending Object.
}
/**
* Closes the DB4O database. Close should be called on this object when it
* is done being used.
*/
public void close() {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
}
conn = null;
}
}
/**
* Searches the CPE entries in the database and retrieves all entries for a
* given vendor and product combination. The returned list will include all
@@ -233,7 +148,7 @@ public class CveDB {
ResultSet rs = null;
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(SELECT_CPE_ENTRIES);
ps = getConnection().prepareStatement(SELECT_CPE_ENTRIES);
ps.setString(1, vendor);
ps.setString(2, product);
rs = ps.executeQuery();
@@ -261,7 +176,7 @@ public class CveDB {
final Set<IndexEntry> set = new HashSet<IndexEntry>();
ResultSet rs = null;
try {
PreparedStatement ps = conn.prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
PreparedStatement ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
rs = ps.executeQuery();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
@@ -290,7 +205,7 @@ public class CveDB {
PreparedStatement ps;
final HashSet<String> cveEntries = new HashSet<String>();
try {
ps = conn.prepareStatement(SELECT_CVE_FROM_SOFTWARE);
ps = getConnection().prepareStatement(SELECT_CVE_FROM_SOFTWARE);
ps.setString(1, cpe.getVendor());
ps.setString(2, cpe.getProduct());
rs = ps.executeQuery();
@@ -333,7 +248,7 @@ public class CveDB {
ResultSet rsS = null;
Vulnerability vuln = null;
try {
psV = conn.prepareStatement(SELECT_VULNERABILITY);
psV = getConnection().prepareStatement(SELECT_VULNERABILITY);
psV.setString(1, cve);
rsV = psV.executeQuery();
if (rsV.next()) {
@@ -357,13 +272,13 @@ public class CveDB {
vuln.setCvssIntegrityImpact(rsV.getString(9));
vuln.setCvssAvailabilityImpact(rsV.getString(10));
psR = conn.prepareStatement(SELECT_REFERENCE);
psR = getConnection().prepareStatement(SELECT_REFERENCE);
psR.setInt(1, cveId);
rsR = psR.executeQuery();
while (rsR.next()) {
vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
}
psS = conn.prepareStatement(SELECT_SOFTWARE);
psS = getConnection().prepareStatement(SELECT_SOFTWARE);
psS.setInt(1, cveId);
rsS = psS.executeQuery();
while (rsS.next()) {
@@ -408,15 +323,15 @@ public class CveDB {
PreparedStatement insertSoftware = null;
try {
selectVulnerabilityId = conn.prepareStatement(SELECT_VULNERABILITY_ID);
deleteReferences = conn.prepareStatement(DELETE_REFERENCE);
deleteSoftware = conn.prepareStatement(DELETE_SOFTWARE);
updateVulnerability = conn.prepareStatement(UPDATE_VULNERABILITY);
insertVulnerability = conn.prepareStatement(INSERT_VULNERABILITY, Statement.RETURN_GENERATED_KEYS);
insertReference = conn.prepareStatement(INSERT_REFERENCE);
selectCpeId = conn.prepareStatement(SELECT_CPE_ID);
insertCpe = conn.prepareStatement(INSERT_CPE, Statement.RETURN_GENERATED_KEYS);
insertSoftware = conn.prepareStatement(INSERT_SOFTWARE);
selectVulnerabilityId = getConnection().prepareStatement(SELECT_VULNERABILITY_ID);
deleteReferences = getConnection().prepareStatement(DELETE_REFERENCE);
deleteSoftware = getConnection().prepareStatement(DELETE_SOFTWARE);
updateVulnerability = getConnection().prepareStatement(UPDATE_VULNERABILITY);
insertVulnerability = getConnection().prepareStatement(INSERT_VULNERABILITY, Statement.RETURN_GENERATED_KEYS);
insertReference = getConnection().prepareStatement(INSERT_REFERENCE);
selectCpeId = getConnection().prepareStatement(SELECT_CPE_ID);
insertCpe = getConnection().prepareStatement(INSERT_CPE, Statement.RETURN_GENERATED_KEYS);
insertSoftware = getConnection().prepareStatement(INSERT_SOFTWARE);
int vulnerabilityId = 0;
selectVulnerabilityId.setString(1, vuln.getName());
ResultSet rs = selectVulnerabilityId.executeQuery();
@@ -526,23 +441,6 @@ public class CveDB {
}
}
/**
* Retrieves the directory that the JAR file exists in so that we can ensure
* we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
public static File getDataDirectory() throws IOException {
final File path = Settings.getFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
}
}
return path;
}
/**
* It is possible that orphaned rows may be generated during database
* updates. This should be called after all updates have been completed to
@@ -551,7 +449,7 @@ public class CveDB {
public void cleanupDatabase() {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(CLEANUP_ORPHANS);
ps = getConnection().prepareStatement(CLEANUP_ORPHANS);
if (ps != null) {
ps.executeUpdate();
}
@@ -562,102 +460,6 @@ public class CveDB {
}
}
/**
* Creates the database structure (tables and indexes) to store the CVE data
*
* @throws SQLException thrown if there is a sql exception
* @throws DatabaseException thrown if there is a database exception
*/
protected void createTables() throws SQLException, DatabaseException {
InputStream is;
InputStreamReader reader;
BufferedReader in = null;
try {
is = this.getClass().getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
reader = new InputStreamReader(is, "UTF-8");
in = new BufferedReader(reader);
final StringBuilder sb = new StringBuilder(2110);
String tmp;
while ((tmp = in.readLine()) != null) {
sb.append(tmp);
}
Statement statement = null;
try {
statement = conn.createStatement();
statement.execute(sb.toString());
} finally {
closeStatement(statement);
}
} catch (IOException ex) {
throw new DatabaseException("Unable to create database schema", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Closes the given statement object ignoring any exceptions that occur.
*
* @param statement a Statement object
*/
private void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, statement.toString(), ex);
}
}
}
/**
* Closes the result set capturing and ignoring any SQLExceptions that
* occur.
*
* @param rs a ResultSet to close
*/
public void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, rs.toString(), ex);
}
}
}
/**
* Returns the generated integer primary key for a newly inserted row.
*
* @param statement a prepared statement that just executed an insert
* @return a primary key
* @throws DatabaseException thrown if there is an exception obtaining the
* key
*/
private int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
ResultSet rs = null;
int id = 0;
try {
rs = statement.getGeneratedKeys();
rs.next();
id = rs.getInt(1);
} catch (SQLException ex) {
throw new DatabaseException("Unable to get primary key for inserted row");
} finally {
closeResultSet(rs);
}
return id;
}
/**
* Determines if the given identifiedVersion is affected by the given cpeId
* and previous version flag. A non-null, non-empty string passed to the