19 package org.sleuthkit.autopsy.keywordsearch;
 
   21 import com.google.common.eventbus.Subscribe;
 
   23 import java.io.IOException;
 
   24 import java.io.Reader;
 
   25 import java.lang.reflect.InvocationTargetException;
 
   26 import java.net.InetAddress;
 
   27 import java.util.ArrayList;
 
   28 import java.util.List;
 
   29 import java.util.MissingResourceException;
 
   30 import java.util.logging.Level;
 
   31 import javax.swing.JDialog;
 
   32 import javax.swing.JOptionPane;
 
   33 import javax.swing.SwingUtilities;
 
   34 import org.apache.commons.io.FileUtils;
 
   35 import org.apache.commons.lang.math.NumberUtils;
 
   36 import org.apache.solr.client.solrj.SolrServerException;
 
   37 import org.apache.solr.client.solrj.impl.HttpSolrServer;
 
   38 import org.openide.util.NbBundle;
 
   39 import org.openide.util.lookup.ServiceProvider;
 
   40 import org.openide.util.lookup.ServiceProviders;
 
   62 @ServiceProviders(value = {
 
   63     @ServiceProvider(service = KeywordSearchService.class)
 
   65     @ServiceProvider(service = AutopsyService.class)
 
   69     private static final String BAD_IP_ADDRESS_FORMAT = 
"ioexception occurred when talking to server"; 
 
   70     private static final String SERVER_REFUSED_CONNECTION = 
"server refused connection"; 
 
   71     private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
 
   72     private static final int LARGE_INDEX_SIZE_GB = 50;
 
   73     private static final int GIANT_INDEX_SIZE_GB = 500;
 
   92     public void index(Content content) 
throws TskCoreException {
 
  106         if (content == null) {
 
  109         final Ingester ingester = Ingester.getDefault();
 
  110         if (content instanceof BlackboardArtifact) {
 
  111             BlackboardArtifact artifact = (BlackboardArtifact) content;
 
  112             if (artifact.getArtifactID() > 0) {
 
  122                 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
 
  123                 String sourceName = artifact.getDisplayName() + 
"_" + artifact.getArtifactID();
 
  124                 ingester.indexMetaDataOnly(artifact, sourceName);
 
  125                 ingester.indexText(blackboardExtractedTextReader, artifact.getArtifactID(), sourceName, content, null);
 
  127                 throw new TskCoreException(
"Error indexing artifact", ex);
 
  132                 Reader contentExtractedTextReader = contentExtractor.
getReader();
 
  133                 ingester.indexText(contentExtractedTextReader, content.getId(), content.getName(), content, null);
 
  138                     Reader stringsExtractedTextReader = stringsExtractor.
getReader();
 
  139                     ingester.indexText(stringsExtractedTextReader, content.getId(), content.getName(), content, null);
 
  141                     throw new TskCoreException(
"Error indexing content", ex1);
 
  158         HttpSolrServer solrServer = null;
 
  159         if (host == null || host.isEmpty()) {
 
  163             solrServer = 
new HttpSolrServer(
"http://" + host + 
":" + Integer.toString(port) + 
"/solr"); 
 
  165         } 
catch (SolrServerException ex) {
 
  167         } 
catch (IOException ex) {
 
  168             String result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  169             String message = ex.getCause().getMessage().toLowerCase();
 
  170             if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
 
  172                     if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
 
  174                         result = Bundle.SolrConnectionCheck_Port();
 
  176                         result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  178                 } 
catch (IOException | MissingResourceException any) {
 
  180                     result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  182             } 
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
 
  183                 result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.Hostname"); 
 
  186         } 
catch (NumberFormatException ex) {
 
  188         } 
catch (IllegalArgumentException ex) {
 
  191             if (null != solrServer) {
 
  192                 solrServer.shutdown();
 
  203         "# {0} - case directory", 
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
 
  204         "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
 
  205         "# {0} - index folder path", 
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}" 
  210         IndexMetadata indexMetadata;
 
  212             indexMetadata = 
new IndexMetadata(caseDirectory);
 
  213         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  214             logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class, 
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
 
  218         String currentSchema = IndexFinder.getCurrentSchemaVersion();
 
  219         String currentSolr = IndexFinder.getCurrentSolrVersion();
 
  220         for (Index index : indexMetadata.getIndexes()) {
 
  221             if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
 
  236                 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  238                 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  243         return NbBundle.getMessage(this.getClass(), 
"SolrSearchService.ServiceName");
 
  256         "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
 
  257         "SolrSearch.readingIndexes.msg=Reading text index metadata file",
 
  258         "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
 
  259         "SolrSearch.creatingNewIndex.msg=Creating new text index",
 
  260         "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
 
  261         "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
 
  262         "SolrSearch.openCore.msg=Opening text index",
 
  263         "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
 
  264         "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
 
  265         "SolrSearch.complete.msg=Text index successfully opened"})
 
  272         int totalNumProgressUnits = 7;
 
  273         int progressUnitsCompleted = 0;
 
  277         List<Index> indexes = 
new ArrayList<>();
 
  278         progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
 
  279         if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
 
  282                 progressUnitsCompleted++;
 
  283                 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  284                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath);
 
  285                 indexes = indexMetadata.getIndexes();
 
  286             } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  287                 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
 
  293             progressUnitsCompleted++;
 
  294             progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  295             Index oldIndex = IndexFinder.findOldIndexDir(theCase);
 
  296             if (oldIndex != null) {
 
  298                 indexes.add(oldIndex);
 
  307         Index currentVersionIndex = null;
 
  308         if (indexes.isEmpty()) {
 
  310             progressUnitsCompleted++;
 
  311             progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
 
  312             currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
 
  314             indexes.add(currentVersionIndex);
 
  317             progressUnitsCompleted++;
 
  318             progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
 
  319             currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
 
  320             if (currentVersionIndex == null) {
 
  322                 progressUnitsCompleted++;
 
  323                 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
 
  324                 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
 
  325                 if (indexToUse == null) {
 
  334                 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
 
  335                 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
 
  336                 if (indexSolrVersion == currentSolrVersion) {
 
  340                         JOptionPane optionPane = 
new JOptionPane(
 
  341                                 NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.msg"),
 
  342                                 JOptionPane.WARNING_MESSAGE,
 
  343                                 JOptionPane.DEFAULT_OPTION);
 
  345                             SwingUtilities.invokeAndWait(() -> {
 
  346                                 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.title"));
 
  347                                 dialog.setVisible(
true);
 
  349                         } 
catch (InterruptedException ex) {
 
  352                         } 
catch (InvocationTargetException ex) {
 
  357                     currentVersionIndex = indexToUse;
 
  367             if (!indexes.isEmpty()) {
 
  368                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath, indexes);
 
  370         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  377             long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
 
  378             long sizeInGb = indexSizeInBytes / 1000000000;
 
  379             if (sizeInGb < LARGE_INDEX_SIZE_GB) {
 
  380                 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
 
  381             } 
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
 
  397         progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
 
  416         AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
 
  419         } 
catch (InterruptedException ex) {
 
  420             logger.log(Level.SEVERE, 
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
 
  437     @NbBundle.Messages(
"SolrSearchService.indexingError=Unable to index blackboard artifact.")
 
  439     void handleNewArtifacts(Blackboard.ArtifactsPostedEvent event) {
 
  440         for (BlackboardArtifact artifact : event.getArtifacts()) {
 
  441             if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { 
 
  444                 } 
catch (TskCoreException ex) {
 
  446                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex); 
 
  447                     MessageNotifyUtil.Notify.error(Bundle.SolrSearchService_indexingError(), artifact.getDisplayName());
 
  464     public void indexArtifact(BlackboardArtifact artifact) 
throws TskCoreException {
 
  465         if (artifact == null) {
 
  471         if (artifact.getArtifactID() > 0) {
 
  474         final Ingester ingester = Ingester.getDefault();
 
  477             String sourceName = artifact.getDisplayName() + 
"_" + artifact.getArtifactID();
 
  479             Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
 
  480             ingester.indexMetaDataOnly(artifact, sourceName);
 
  481             ingester.indexText(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null);
 
  483             throw new TskCoreException(ex.getCause().getMessage(), ex);
 
void index(Content content)
 
void indexArtifact(BlackboardArtifact artifact)
 
static boolean runningWithGUI
 
void start(String message, int totalWorkUnits)
 
void openCaseResources(CaseContext context)
 
String getCaseDirectory()
 
static synchronized Server getServer()
 
ProgressIndicator getProgressIndicator()
 
volatile boolean cancelRequested
 
void closeCaseResources(CaseContext context)
 
void deleteTextIndex(CaseMetadata metadata)
 
SleuthkitCase getSleuthkitCase()
 
synchronized static Logger getLogger(String name)
 
static boolean deleteDir(File dirPath)
 
void progress(String message)
 
void tryConnect(String host, int port)
 
void switchToIndeterminate(String message)