20 package org.sleuthkit.autopsy.keywordsearch;
 
   22 import java.util.ArrayList;
 
   23 import java.util.Collection;
 
   24 import java.util.HashMap;
 
   25 import java.util.List;
 
   27 import java.util.Map.Entry;
 
   28 import java.util.concurrent.CancellationException;
 
   29 import java.util.concurrent.ExecutionException;
 
   30 import java.util.concurrent.atomic.AtomicLong;
 
   31 import java.util.logging.Level;
 
   32 import javax.swing.SwingUtilities;
 
   33 import javax.swing.SwingWorker;
 
   34 import java.util.Timer;
 
   35 import java.util.TimerTask;
 
   36 import org.netbeans.api.progress.aggregate.AggregateProgressFactory;
 
   37 import org.netbeans.api.progress.aggregate.AggregateProgressHandle;
 
   38 import org.netbeans.api.progress.aggregate.ProgressContributor;
 
   39 import org.openide.util.Cancellable;
 
   40 import org.openide.util.NbBundle;
 
   61     private Map<Long, SearchJobInfo> 
jobs = 
new HashMap<>(); 
 
   65         updateTimer = 
new Timer(NbBundle.getMessage(
this.getClass(), 
"SearchRunner.updateTimer.title.text"), 
true); 
 
   73         if (instance == null) {
 
   85     public synchronized void startJob(
long jobId, 
long dataSourceId, List<String> keywordListNames) {
 
   86         if (jobs.containsKey(jobId) == 
false) {
 
   87             logger.log(Level.INFO, 
"Adding job {0}", jobId); 
 
   89             jobs.put(jobId, jobData);         
 
   93         jobs.get(jobId).incrementModuleReferenceCount();
 
   96         if ((jobs.size() > 0) && (updateTimerRunning == 
false)) {
 
   97             final long updateIntervalMs = ((long)KeywordSearchSettings.getUpdateFrequency().getTime()) * 60 * 1000;
 
   98             updateTimer.scheduleAtFixedRate(
new UpdateTimerTask(), updateIntervalMs, updateIntervalMs);
 
   99             updateTimerRunning = 
true;
 
  110         boolean readyForFinalSearch = 
false;
 
  112             job = jobs.get(jobId);
 
  120                 readyForFinalSearch = 
true;
 
  124         if (readyForFinalSearch) {          
 
  137         logger.log(Level.INFO, 
"Stopping job {0}", jobId); 
 
  142             job = jobs.get(jobId);
 
  149             if ((currentSearcher != null) && (!currentSearcher.isDone())) {
 
  150                 currentSearcher.cancel(
true);
 
  162         for(String listName : keywordListNames) {
 
  163             logger.log(Level.INFO, 
"Adding keyword list {0} to all jobs", listName); 
 
  165                 j.addKeywordListName(listName);
 
  181             logger.log(Level.WARNING, 
"Error executing Solr query to check number of indexed files: ", ex); 
 
  192         logger.log(Level.INFO, 
"Running final search for jobid {0}", job.
getJobId());         
 
  200                 finalSearcher.execute(); 
 
  205             } 
catch (InterruptedException | ExecutionException ex) {
 
  206                 logger.log(Level.WARNING, 
"Job {1} final search thread failed: {2}", 
new Object[]{job.getJobId(), ex}); 
 
  221             if (jobs.isEmpty()) {
 
  223                 updateTimerRunning = 
false;
 
  231                 for(Entry<Long, SearchJobInfo> j : jobs.entrySet()) {
 
  260         public SearchJobInfo(
long jobId, 
long dataSourceId, List<String> keywordListNames) {
 
  264             currentResults = 
new HashMap<>();
 
  265             workerRunning = 
false;
 
  282             if (!keywordListNames.contains(keywordListName)) {
 
  283                 keywordListNames.add(keywordListName);
 
  288             return currentResults.get(k);
 
  292             currentResults.put(k, resultsIDs);
 
  300             workerRunning = flag;           
 
  312             moduleReferenceCount.incrementAndGet();
 
  316             return moduleReferenceCount.decrementAndGet();
 
  325                 while(workerRunning) {
 
  326                     finalSearchLock.wait(); 
 
  336                 workerRunning = 
false;
 
  337                 finalSearchLock.notify();
 
  348     private final class Searcher extends SwingWorker<Object, Void> {
 
  365             keywords = 
new ArrayList<>();
 
  366             keywordToList = 
new HashMap<>();
 
  367             keywordLists = 
new ArrayList<>();
 
  378             final String displayName = NbBundle.getMessage(this.getClass(), 
"KeywordSearchIngestModule.doInBackGround.displayName")
 
  379                     + (finalRun ? (
" - " + NbBundle.getMessage(this.getClass(), 
"KeywordSearchIngestModule.doInBackGround.finalizeMsg")) : 
"");
 
  380             final String pgDisplayName = displayName + (
" (" + NbBundle.getMessage(this.getClass(), 
"KeywordSearchIngestModule.doInBackGround.pendingMsg") + 
")");
 
  381             progressGroup = AggregateProgressFactory.createSystemHandle(pgDisplayName, null, 
new Cancellable() {
 
  383                 public boolean cancel() {
 
  384                     logger.log(Level.INFO, 
"Cancelling the searcher by user."); 
 
  385                     if (progressGroup != null) {
 
  386                         progressGroup.setDisplayName(displayName + 
" " + NbBundle.getMessage(
this.getClass(), 
"SearchRunner.doInBackGround.cancelMsg"));
 
  394             ProgressContributor[] subProgresses = 
new ProgressContributor[keywords.size()];
 
  396             for (Keyword keywordQuery : keywords) {
 
  397                 subProgresses[i] = AggregateProgressFactory.createProgressContributor(keywordQuery.getQuery());
 
  398                 progressGroup.addContributor(subProgresses[i]);
 
  402             progressGroup.start();
 
  407                 progressGroup.setDisplayName(displayName);
 
  409                 int keywordsSearched = 0;
 
  411                 for (Keyword keywordQuery : keywords) {
 
  412                     if (this.isCancelled()) {
 
  413                         logger.log(Level.INFO, 
"Cancel detected, bailing before new keyword processed: {0}", keywordQuery.getQuery()); 
 
  417                     final String queryStr = keywordQuery.getQuery();
 
  418                     final KeywordList list = keywordToList.get(queryStr);
 
  422                     if (keywordsSearched > 0) {
 
  423                         subProgresses[keywordsSearched - 1].finish();
 
  426                     KeywordSearchQuery keywordSearchQuery = null;
 
  428                     boolean isRegex = !keywordQuery.isLiteral();
 
  430                         keywordSearchQuery = 
new TermComponentQuery(list, keywordQuery);
 
  432                         keywordSearchQuery = 
new LuceneQuery(list, keywordQuery);
 
  433                         keywordSearchQuery.escape();
 
  439                     final KeywordQueryFilter dataSourceFilter = 
new KeywordQueryFilter(KeywordQueryFilter.FilterType.DATA_SOURCE, job.
getDataSourceId());
 
  440                     keywordSearchQuery.addFilter(dataSourceFilter);
 
  442                     QueryResults queryResults;
 
  446                         queryResults = keywordSearchQuery.performQuery();
 
  448                         logger.log(Level.WARNING, 
"Error performing query: " + keywordQuery.getQuery(), ex); 
 
  453                     } 
catch (CancellationException e) {
 
  454                         logger.log(Level.INFO, 
"Cancel detected, bailing during keyword query: {0}", keywordQuery.getQuery()); 
 
  456                     } 
catch (Exception e) {
 
  457                         logger.log(Level.WARNING, 
"Error performing query: " + keywordQuery.getQuery(), e); 
 
  465                     if (!newResults.getKeywords().isEmpty()) {
 
  470                         Collection<BlackboardArtifact> newArtifacts = 
new ArrayList<>();
 
  473                         int totalUnits = newResults.getKeywords().size();
 
  474                         subProgresses[keywordsSearched].start(totalUnits);
 
  475                         int unitProgress = 0;
 
  476                         String queryDisplayStr = keywordQuery.getQuery();
 
  477                         if (queryDisplayStr.length() > 50) {
 
  478                             queryDisplayStr = queryDisplayStr.substring(0, 49) + 
"...";
 
  480                         subProgresses[keywordsSearched].progress(list.getName() + 
": " + queryDisplayStr, unitProgress);
 
  483                         newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], 
this, list.getIngestMessages());
 
  488                     subProgresses[keywordsSearched].progress(
"");
 
  495             catch (Exception ex) {
 
  496                 logger.log(Level.WARNING, 
"searcher exception occurred", ex); 
 
  502                     logger.log(Level.INFO, 
"Searcher took to run: {0} secs.", stopWatch.
getElapsedTimeSecs()); 
 
  517             } 
catch (InterruptedException | ExecutionException e) {
 
  518                 logger.log(Level.SEVERE, 
"Error performing keyword search: " + e.getMessage()); 
 
  520                                                                       NbBundle.getMessage(this.getClass(),
 
  521                                                                                           "SearchRunner.Searcher.done.err.msg"), e.getMessage()));
 
  523             catch (java.util.concurrent.CancellationException ex) {
 
  531             XmlKeywordSearchList loader = XmlKeywordSearchList.getCurrent();
 
  534             keywordToList.clear();
 
  535             keywordLists.clear();
 
  537             for (String name : keywordListNames) {
 
  539                 keywordLists.add(list);
 
  540                 for (Keyword k : list.getKeywords()) {
 
  542                     keywordToList.put(k.getQuery(), list);
 
  553             SwingUtilities.invokeLater(
new Runnable() {
 
  556                     progressGroup.finish();
 
  565             QueryResults newResults = 
new QueryResults(queryResult.getQuery(), queryResult.getKeywordList());
 
  567             for (Keyword keyword : queryResult.getKeywords()) {
 
  568                 List<KeywordHit> queryTermResults = queryResult.getResults(keyword);
 
  571                 List<Long> queryTermResultsIDs = 
new ArrayList<>();
 
  572                 for (KeywordHit ch : queryTermResults) {
 
  573                     queryTermResultsIDs.add(ch.getSolrObjectId());
 
  577                 if (curTermResults == null) {
 
  579                     newResults.addResult(keyword, queryTermResults);
 
  582                     for (KeywordHit res : queryTermResults) {
 
  583                         if (!curTermResults.contains(res.getSolrObjectId())) {
 
  585                             List<KeywordHit> newResultsFs = newResults.getResults(keyword);
 
  586                             if (newResultsFs == null) {
 
  587                                 newResultsFs = 
new ArrayList<>();
 
  588                                 newResults.addResult(keyword, newResultsFs);
 
  590                             newResultsFs.add(res);
 
  591                             curTermResults.add(res.getSolrObjectId());
 
synchronized List< String > getKeywordListNames()
 
int queryNumIndexedFiles()
 
SearchJobInfo(long jobId, long dataSourceId, List< String > keywordListNames)
 
long getElapsedTimeSecs()
 
synchronized void addKeywordResults(Keyword k, List< Long > resultsIDs)
 
AggregateProgressHandle progressGroup
 
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
 
static void fireNumIndexedFilesChange(Integer oldNum, Integer newNum)
 
synchronized void addKeywordListName(String keywordListName)
 
volatile boolean workerRunning
 
List< KeywordList > keywordLists
 
long decrementModuleReferenceCount()
 
AtomicLong moduleReferenceCount
 
synchronized void startJob(long jobId, long dataSourceId, List< String > keywordListNames)
 
static synchronized Server getServer()
 
boolean isWorkerRunning()
 
void doFinalSearch(SearchJobInfo job)
 
static final Logger logger
 
synchronized void setCurrentSearcher(SearchRunner.Searcher searchRunner)
 
final Object finalSearchLock
 
List< String > keywordListNames
 
synchronized List< Long > currentKeywordResults(Keyword k)
 
Map< Keyword, List< Long > > currentResults
 
Map< String, KeywordList > keywordToList
 
static synchronized SearchRunner getInstance()
 
synchronized void addKeywordListsToAllJobs(List< String > keywordListNames)
 
void postMessage(final IngestMessage message)
 
List< String > keywordListNames
 
Map< Long, SearchJobInfo > jobs
 
static SearchRunner instance
 
void incrementModuleReferenceCount()
 
void waitForCurrentWorker()
 
QueryResults filterResults(QueryResults queryResult)
 
SearchRunner.Searcher currentSearcher
 
static Ingester getIngester()
 
volatile boolean updateTimerRunning
 
synchronized SearchRunner.Searcher getCurrentSearcher()
 
static Logger getLogger(String name)
 
void setWorkerRunning(boolean flag)
 
static synchronized IngestServices getInstance()