19 package org.sleuthkit.autopsy.keywordsearch;
 
   22 import java.io.IOException;
 
   23 import java.lang.reflect.InvocationTargetException;
 
   24 import java.net.InetAddress;
 
   25 import java.util.ArrayList;
 
   26 import java.util.List;
 
   27 import java.util.MissingResourceException;
 
   28 import java.util.logging.Level;
 
   29 import javax.swing.JDialog;
 
   30 import javax.swing.JOptionPane;
 
   31 import javax.swing.SwingUtilities;
 
   32 import org.apache.commons.lang.math.NumberUtils;
 
   33 import org.apache.commons.io.FileUtils;
 
   34 import org.apache.solr.client.solrj.SolrServerException;
 
   35 import org.apache.solr.client.solrj.impl.HttpSolrServer;
 
   36 import org.openide.util.NbBundle;
 
   37 import org.openide.util.lookup.ServiceProvider;
 
   38 import org.openide.util.lookup.ServiceProviders;
 
   56 @ServiceProviders(value = {
 
   57     @ServiceProvider(service = KeywordSearchService.class)
 
   59     @ServiceProvider(service = AutopsyService.class)}
 
   63     private static final String BAD_IP_ADDRESS_FORMAT = 
"ioexception occurred when talking to server"; 
 
   64     private static final String SERVER_REFUSED_CONNECTION = 
"server refused connection"; 
 
   65     private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
 
   66     private static final int LARGE_INDEX_SIZE_GB = 50;
 
   67     private static final int GIANT_INDEX_SIZE_GB = 500;
 
   79     public void indexArtifact(BlackboardArtifact artifact) 
throws TskCoreException {
 
   80         if (artifact == null) {
 
   86         if (artifact.getArtifactID() > 0) {
 
   89         final Ingester ingester = Ingester.getDefault();
 
   92             ingester.indexMetaDataOnly(artifact);
 
   93             ingester.indexText(
new ArtifactTextExtractor(), artifact, null);
 
   94         } 
catch (Ingester.IngesterException ex) {
 
   95             throw new TskCoreException(ex.getCause().getMessage(), ex);
 
  105     public void index(Content content) 
throws TskCoreException {
 
  106         if (content == null) {
 
  109         final Ingester ingester = Ingester.getDefault();
 
  112             ingester.indexText(
new TikaTextExtractor(), content, null);
 
  113         } 
catch (Ingester.IngesterException ex) {
 
  116                 ingester.indexText(
new StringsTextExtractor(), content, null);
 
  117             } 
catch (Ingester.IngesterException ex1) {
 
  118                 throw new TskCoreException(ex.getCause().getMessage(), ex1);
 
  138         HttpSolrServer solrServer = null;
 
  139         if (host == null || host.isEmpty()) {
 
  143             solrServer = 
new HttpSolrServer(
"http://" + host + 
":" + Integer.toString(port) + 
"/solr"); 
 
  145         } 
catch (SolrServerException ex) {
 
  147         } 
catch (IOException ex) {
 
  148             String result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  149             String message = ex.getCause().getMessage().toLowerCase();
 
  150             if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
 
  152                     if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
 
  154                         result = Bundle.SolrConnectionCheck_Port();
 
  156                         result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  158                 } 
catch (IOException | MissingResourceException any) {
 
  160                     result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  162             } 
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
 
  163                 result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.Hostname"); 
 
  166         } 
catch (NumberFormatException ex) {
 
  168         } 
catch (IllegalArgumentException ex) {
 
  171             if (null != solrServer) {
 
  172                 solrServer.shutdown();
 
  183         "# {0} - case directory", 
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
 
  184         "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
 
  185         "# {0} - index folder path", 
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}" 
  190         IndexMetadata indexMetadata;
 
  192             indexMetadata = 
new IndexMetadata(caseDirectory);
 
  193         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  194             logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class, 
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
 
  198         String currentSchema = IndexFinder.getCurrentSchemaVersion();
 
  199         String currentSolr = IndexFinder.getCurrentSolrVersion();
 
  200         for (Index index : indexMetadata.getIndexes()) {
 
  201             if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
 
  216                  "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  218                  "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  222     public void close() throws IOException {
 
  227         return NbBundle.getMessage(this.getClass(), 
"SolrSearchService.ServiceName");
 
  239         "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
 
  240         "SolrSearch.readingIndexes.msg=Reading text index metadata file",
 
  241         "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
 
  242         "SolrSearch.creatingNewIndex.msg=Creating new text index",
 
  243         "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
 
  244         "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
 
  245         "SolrSearch.openCore.msg=Opening text index",
 
  246         "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
 
  247         "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
 
  248         "SolrSearch.complete.msg=Text index successfully opened"})
 
  255         int totalNumProgressUnits = 7;
 
  256         int progressUnitsCompleted = 0;
 
  260         List<Index> indexes = 
new ArrayList<>();
 
  261         progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
 
  262         if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
 
  265                 progressUnitsCompleted++;
 
  266                 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  267                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath);
 
  268                 indexes = indexMetadata.getIndexes();
 
  269             } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  270                 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
 
  276             progressUnitsCompleted++;
 
  277             progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  278             Index oldIndex = IndexFinder.findOldIndexDir(theCase);
 
  279             if (oldIndex != null) {
 
  281                 indexes.add(oldIndex);
 
  290         Index currentVersionIndex = null;
 
  291         if (indexes.isEmpty()) {
 
  293             progressUnitsCompleted++;
 
  294             progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
 
  295             currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
 
  297             indexes.add(currentVersionIndex);
 
  300             progressUnitsCompleted++;
 
  301             progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
 
  302             currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
 
  303             if (currentVersionIndex == null) {
 
  305                 progressUnitsCompleted++;
 
  306                 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
 
  307                 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
 
  308                 if (indexToUse == null) {
 
  317                 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
 
  318                 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
 
  319                 if (indexSolrVersion == currentSolrVersion) {
 
  323                         JOptionPane optionPane = 
new JOptionPane(
 
  324                                 NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.msg"),
 
  325                                 JOptionPane.WARNING_MESSAGE,
 
  326                                 JOptionPane.DEFAULT_OPTION);
 
  328                             SwingUtilities.invokeAndWait(() -> {
 
  329                                 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.title"));
 
  330                                 dialog.setVisible(
true);
 
  332                         } 
catch (InterruptedException ex) {
 
  335                         } 
catch (InvocationTargetException ex) {
 
  340                     currentVersionIndex = indexToUse;
 
  350             if (!indexes.isEmpty()) {
 
  351                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath, indexes);
 
  353         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  360             long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
 
  361             long sizeInGb = indexSizeInBytes / 1000000000;
 
  362             if (sizeInGb < LARGE_INDEX_SIZE_GB) {
 
  363                 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
 
  364             } 
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
 
  375         progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
 
  393         AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
 
  396         } 
catch (InterruptedException ex) {
 
  397             logger.log(Level.SEVERE, 
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", 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)
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)