diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/BaseDB.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/BaseDB.java new file mode 100644 index 000000000..c2aa757ef --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/BaseDB.java @@ -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); + } + } + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java index e169208d1..101468fc6 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java @@ -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; // /** * 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 = ?"; // - /** - * 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 set = new HashSet(); 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 cveEntries = new HashSet(); 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