Coverage Report - org.owasp.dependencycheck.data.BaseDB
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseDB
45%
34/74
50%
10/20
2.8
 
 1  
 /*
 2  
  * This file is part of dependency-check-core.
 3  
  *
 4  
  * Dependency-check-core is free software: you can redistribute it and/or modify it
 5  
  * under the terms of the GNU General Public License as published by the Free
 6  
  * Software Foundation, either version 3 of the License, or (at your option) any
 7  
  * later version.
 8  
  *
 9  
  * Dependency-check-core is distributed in the hope that it will be useful, but
 10  
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 12  
  * details.
 13  
  *
 14  
  * You should have received a copy of the GNU General Public License along with
 15  
  * dependency-check-core. If not, see http://www.gnu.org/licenses/.
 16  
  *
 17  
  * Copyright (c) 2013 Jeremy Long. All Rights Reserved.
 18  
  */
 19  
 package org.owasp.dependencycheck.data;
 20  
 
 21  
 import java.io.BufferedReader;
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.io.InputStream;
 25  
 import java.io.InputStreamReader;
 26  
 import java.sql.Connection;
 27  
 import java.sql.DriverManager;
 28  
 import java.sql.PreparedStatement;
 29  
 import java.sql.ResultSet;
 30  
 import java.sql.SQLException;
 31  
 import java.sql.Statement;
 32  
 import java.util.logging.Level;
 33  
 import java.util.logging.Logger;
 34  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 35  
 import static org.owasp.dependencycheck.data.nvdcve.CveDB.DB_SCHEMA_VERSION;
 36  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 37  
 import org.owasp.dependencycheck.utils.Settings;
 38  
 
 39  
 /**
 40  
  *
 41  
  * @author Jeremy Long (jeremy.long@owasp.org)
 42  
  */
 43  21
 public class BaseDB {
 44  
 
 45  
     /**
 46  
      * Resource location for SQL file used to create the database schema.
 47  
      */
 48  
     public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
 49  
     /**
 50  
      * The version of the current DB Schema.
 51  
      */
 52  
     public static final String DB_SCHEMA_VERSION = "2.7";
 53  
     /**
 54  
      * Database connection
 55  
      */
 56  
     private Connection conn;
 57  
 
 58  
     /**
 59  
      * Returns the database connection.
 60  
      *
 61  
      * @return the database connection
 62  
      */
 63  
     protected Connection getConnection() {
 64  278
         return conn;
 65  
     }
 66  
 
 67  
     /**
 68  
      * Opens the database connection. If the database does not exist, it will
 69  
      * create a new one.
 70  
      *
 71  
      * @throws IOException thrown if there is an IO Exception
 72  
      * @throws SQLException thrown if there is a SQL Exception
 73  
      * @throws DatabaseException thrown if there is an error initializing a new
 74  
      * database
 75  
      * @throws ClassNotFoundException thrown if the h2 database driver cannot be
 76  
      * loaded
 77  
      */
 78  
     @edu.umd.cs.findbugs.annotations.SuppressWarnings(
 79  
             value = "DMI_EMPTY_DB_PASSWORD",
 80  
             justification = "Yes, I know... Blank password.")
 81  
     public void open() throws IOException, SQLException, DatabaseException, ClassNotFoundException {
 82  21
         final String fileName = CveDB.getDataDirectory().getCanonicalPath();
 83  21
         final File f = new File(fileName, "cve." + DB_SCHEMA_VERSION);
 84  21
         final File check = new File(f.getAbsolutePath() + ".h2.db");
 85  21
         final boolean createTables = !check.exists();
 86  21
         final String connStr = String.format("jdbc:h2:file:%s;AUTO_SERVER=TRUE", f.getAbsolutePath());
 87  21
         Class.forName("org.h2.Driver");
 88  21
         conn = DriverManager.getConnection(connStr, "sa", "");
 89  21
         if (createTables) {
 90  0
             createTables();
 91  
         }
 92  21
     }
 93  
 
 94  
     /**
 95  
      * Closes the DB4O database. Close should be called on this object when it
 96  
      * is done being used.
 97  
      */
 98  
     public void close() {
 99  37
         if (conn != null) {
 100  
             try {
 101  21
                 conn.close();
 102  0
             } catch (SQLException ex) {
 103  0
                 final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
 104  0
                 Logger.getLogger(BaseDB.class.getName()).log(Level.SEVERE, msg, ex);
 105  0
                 Logger.getLogger(BaseDB.class.getName()).log(Level.FINE, null, ex);
 106  21
             }
 107  21
             conn = null;
 108  
         }
 109  37
     }
 110  
 
 111  
     /**
 112  
      * Commits all completed transactions.
 113  
      *
 114  
      * @throws SQLException thrown if a SQL Exception occurs
 115  
      */
 116  
     public void commit() throws SQLException {
 117  1
         if (conn != null) {
 118  1
             conn.commit();
 119  
         }
 120  1
     }
 121  
 
 122  
     /**
 123  
      * Cleans up the object and ensures that "close" has been called.
 124  
      *
 125  
      * @throws Throwable thrown if there is a problem
 126  
      */
 127  
     @Override
 128  
     protected void finalize() throws Throwable {
 129  16
         close();
 130  16
         super.finalize(); //not necessary if extending Object.
 131  16
     }
 132  
 
 133  
     /**
 134  
      * Creates the database structure (tables and indexes) to store the CVE data
 135  
      *
 136  
      * @throws SQLException thrown if there is a sql exception
 137  
      * @throws DatabaseException thrown if there is a database exception
 138  
      */
 139  
     private void createTables() throws SQLException, DatabaseException {
 140  
         InputStream is;
 141  
         InputStreamReader reader;
 142  0
         BufferedReader in = null;
 143  
         try {
 144  0
             is = this.getClass().getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
 145  0
             reader = new InputStreamReader(is, "UTF-8");
 146  0
             in = new BufferedReader(reader);
 147  0
             final StringBuilder sb = new StringBuilder(2110);
 148  
             String tmp;
 149  0
             while ((tmp = in.readLine()) != null) {
 150  0
                 sb.append(tmp);
 151  
             }
 152  0
             Statement statement = null;
 153  
             try {
 154  0
                 statement = conn.createStatement();
 155  0
                 statement.execute(sb.toString());
 156  
             } finally {
 157  0
                 closeStatement(statement);
 158  0
             }
 159  0
         } catch (IOException ex) {
 160  0
             throw new DatabaseException("Unable to create database schema", ex);
 161  
         } finally {
 162  0
             if (in != null) {
 163  
                 try {
 164  0
                     in.close();
 165  0
                 } catch (IOException ex) {
 166  0
                     Logger.getLogger(CveDB.class
 167  
                             .getName()).log(Level.FINEST, null, ex);
 168  0
                 }
 169  
             }
 170  
         }
 171  0
     }
 172  
 
 173  
     /**
 174  
      * Retrieves the directory that the JAR file exists in so that we can ensure
 175  
      * we always use a common data directory.
 176  
      *
 177  
      * @return the data directory for this index.
 178  
      * @throws IOException is thrown if an IOException occurs of course...
 179  
      */
 180  
     public static File getDataDirectory() throws IOException {
 181  22
         final File path = Settings.getDataFile(Settings.KEYS.CVE_DATA_DIRECTORY);
 182  22
         if (!path.exists()) {
 183  1
             if (!path.mkdirs()) {
 184  0
                 throw new IOException("Unable to create NVD CVE Data directory");
 185  
             }
 186  
         }
 187  22
         return path;
 188  
     }
 189  
 
 190  
     /**
 191  
      * Returns the generated integer primary key for a newly inserted row.
 192  
      *
 193  
      * @param statement a prepared statement that just executed an insert
 194  
      * @return a primary key
 195  
      * @throws DatabaseException thrown if there is an exception obtaining the
 196  
      * key
 197  
      */
 198  
     protected int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
 199  0
         ResultSet rs = null;
 200  0
         int id = 0;
 201  
         try {
 202  0
             rs = statement.getGeneratedKeys();
 203  0
             rs.next();
 204  0
             id = rs.getInt(1);
 205  0
         } catch (SQLException ex) {
 206  0
             throw new DatabaseException("Unable to get primary key for inserted row");
 207  
         } finally {
 208  0
             closeResultSet(rs);
 209  0
         }
 210  0
         return id;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Closes the given statement object ignoring any exceptions that occur.
 215  
      *
 216  
      * @param statement a Statement object
 217  
      */
 218  
     public void closeStatement(Statement statement) {
 219  267
         if (statement != null) {
 220  
             try {
 221  267
                 statement.close();
 222  0
             } catch (SQLException ex) {
 223  0
                 Logger.getLogger(CveDB.class
 224  
                         .getName()).log(Level.FINEST, statement.toString(), ex);
 225  267
             }
 226  
         }
 227  267
     }
 228  
 
 229  
     /**
 230  
      * Closes the result set capturing and ignoring any SQLExceptions that
 231  
      * occur.
 232  
      *
 233  
      * @param rs a ResultSet to close
 234  
      */
 235  
     public void closeResultSet(ResultSet rs) {
 236  279
         if (rs != null) {
 237  
             try {
 238  279
                 rs.close();
 239  0
             } catch (SQLException ex) {
 240  0
                 Logger.getLogger(CveDB.class
 241  
                         .getName()).log(Level.FINEST, rs.toString(), ex);
 242  279
             }
 243  
         }
 244  279
     }
 245  
 }