View Javadoc

    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.cpe;
    20
    21  import java.io.IOException;
    22  import java.util.HashMap;
    23  import java.util.Map;
    24  import java.util.logging.Level;
    25  import java.util.logging.Logger;
    26  import org.apache.lucene.analysis.Analyzer;
    27  import org.apache.lucene.analysis.core.KeywordAnalyzer;
    28  import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
    29  import org.apache.lucene.document.Document;
    30  import org.apache.lucene.index.CorruptIndexException;
    31  import org.apache.lucene.index.DirectoryReader;
    32  import org.apache.lucene.index.IndexReader;
    33  import org.apache.lucene.queryparser.classic.ParseException;
    34  import org.apache.lucene.queryparser.classic.QueryParser;
    35  import org.apache.lucene.search.IndexSearcher;
    36  import org.apache.lucene.search.Query;
    37  import org.apache.lucene.search.TopDocs;
    38  import org.apache.lucene.util.Version;
    39  import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
    40  import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
    41
    42  /**
    43   *
    44   * @author Jeremy Long (jeremy.long@owasp.org)
    45   */
    46  public class CpeIndexReader extends BaseIndex {
    47
    48      /**
    49       * The Lucene IndexReader.
    50       */
    51      private IndexReader indexReader;
    52      /**
    53       * The Lucene IndexSearcher.
    54       */
    55      private IndexSearcher indexSearcher;
    56      /**
    57       * The Lucene Analyzer used for Searching.
    58       */
    59      private Analyzer searchingAnalyzer;
    60      /**
    61       * The Lucene QueryParser used for Searching.
    62       */
    63      private QueryParser queryParser;
    64      /**
    65       * The search field analyzer for the product field.
    66       */
    67      private SearchFieldAnalyzer productSearchFieldAnalyzer;
    68      /**
    69       * The search field analyzer for the vendor field.
    70       */
    71      private SearchFieldAnalyzer vendorSearchFieldAnalyzer;
    72
    73      /**
    74       * Opens the CPE Index.
    75       *
    76       * @throws IOException is thrown if an IOException occurs opening the index.
    77       */
    78      @Override
    79      public void open() throws IOException {
    80          //TODO add spinlock (shared)
    81          super.open();
    82          indexReader = DirectoryReader.open(getDirectory());
    83          indexSearcher = new IndexSearcher(indexReader);
    84          searchingAnalyzer = createSearchingAnalyzer();
    85          queryParser = new QueryParser(Version.LUCENE_43, Fields.DOCUMENT_KEY, searchingAnalyzer);
    86      }
    87
    88      /**
    89       * Closes the CPE Index.
    90       */
    91      @Override
    92      public void close() {
    93          //TODO remove spinlock (shared)
    94          if (searchingAnalyzer != null) {
    95              searchingAnalyzer.close();
    96              searchingAnalyzer = null;
    97          }
    98          if (indexReader != null) {
    99              try {
    100                 indexReader.close();
    101             } catch (IOException ex) {
    102                 Logger.getLogger(CpeIndexReader.class.getName()).log(Level.FINEST, null, ex);
    103             }
    104             indexReader = null;
    105         }
    106         queryParser = null;
    107         indexSearcher = null;
    108         super.close();
    109     }
    110
    111     /**
    112      * Searches the index using the given search string.
    113      *
    114      * @param searchString the query text
    115      * @param maxQueryResults the maximum number of documents to return
    116      * @return the TopDocs found by the search
    117      * @throws ParseException thrown when the searchString is invalid
    118      * @throws IOException is thrown if there is an issue with the underlying
    119      * Index
    120      */
    121     public TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
    122         if (searchString == null || searchString.trim().isEmpty()) {
    123             throw new ParseException("Query is null or empty");
    124         }
    125         if (queryParser == null) {
    126             if (isOpen()) {
    127                 final String msg = String.format("QueryParser is null for query: '%s'. Attempting to reopen index.",
    128                         searchString);
    129                 Logger.getLogger(CpeIndexReader.class.getName()).log(Level.WARNING, msg);
    130                 close();
    131                 open();
    132             } else {
    133                 final String msg = String.format("QueryParser is null, but data source is open, for query: '%s'. Attempting to reopen index.",
    134                         searchString);
    135                 Logger.getLogger(CpeIndexReader.class.getName()).log(Level.WARNING, msg);
    136                 close();
    137                 open();
    138             }
    139         }
    140         final Query query = queryParser.parse(searchString);
    141         return indexSearcher.search(query, maxQueryResults);
    142     }
    143
    144     /**
    145      * Searches the index using the given query.
    146      *
    147      * @param query the query used to search the index
    148      * @param maxQueryResults the max number of results to return
    149      * @return the TopDocs found be the query
    150      * @throws CorruptIndexException thrown if the Index is corrupt
    151      * @throws IOException thrown if there is an IOException
    152      */
    153     public TopDocs search(Query query, int maxQueryResults) throws CorruptIndexException, IOException {
    154         resetSearchingAnalyzer();
    155         return indexSearcher.search(query, maxQueryResults);
    156     }
    157
    158     /**
    159      * Retrieves a document from the Index.
    160      *
    161      * @param documentId the id of the document to retrieve
    162      * @return the Document
    163      * @throws IOException thrown if there is an IOException
    164      */
    165     public Document getDocument(int documentId) throws IOException {
    166         return indexSearcher.doc(documentId);
    167     }
    168
    169     /**
    170      * Creates an Analyzer for searching the CPE Index.
    171      *
    172      * @return the CPE Analyzer.
    173      */
    174     @SuppressWarnings("unchecked")
    175     private Analyzer createSearchingAnalyzer() {
    176         final Map fieldAnalyzers = new HashMap();
    177         fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
    178         productSearchFieldAnalyzer = new SearchFieldAnalyzer(Version.LUCENE_43);
    179         vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(Version.LUCENE_43);
    180         fieldAnalyzers.put(Fields.PRODUCT, productSearchFieldAnalyzer);
    181         fieldAnalyzers.put(Fields.VENDOR, vendorSearchFieldAnalyzer);
    182
    183         return new PerFieldAnalyzerWrapper(new FieldAnalyzer(Version.LUCENE_43), fieldAnalyzers);
    184     }
    185
    186     /**
    187      * Resets the searching analyzers
    188      */
    189     private void resetSearchingAnalyzer() {
    190         if (productSearchFieldAnalyzer != null) {
    191             productSearchFieldAnalyzer.clear();
    192         }
    193         if (vendorSearchFieldAnalyzer != null) {
    194             vendorSearchFieldAnalyzer.clear();
    195         }
    196     }
    197
    198     /**
    199      * Returns the number of CPE entries stored in the index.
    200      *
    201      * @return the number of CPE entries stored in the index
    202      */
    203     public int numDocs() {
    204         if (indexReader == null) {
    205             return -1;
    206         }
    207         return indexReader.numDocs();
    208     }
    209 }