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;
 
   55 @ServiceProviders(value = {
 
   56     @ServiceProvider(service = KeywordSearchService.class)
 
   58     @ServiceProvider(service = AutopsyService.class)}
 
   62     private static final String BAD_IP_ADDRESS_FORMAT = 
"ioexception occurred when talking to server"; 
 
   63     private static final String SERVER_REFUSED_CONNECTION = 
"server refused connection"; 
 
   64     private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
 
   65     private static final int LARGE_INDEX_SIZE_GB = 50;
 
   66     private static final int GIANT_INDEX_SIZE_GB = 500;
 
   78     public void indexArtifact(BlackboardArtifact artifact) 
throws TskCoreException {
 
   79         if (artifact == null) {
 
   85         if (artifact.getArtifactID() > 0) {
 
   88         final Ingester ingester = Ingester.getDefault();
 
   91             ingester.indexMetaDataOnly(artifact);
 
   92             ingester.indexText(
new ArtifactTextExtractor(), artifact, null);
 
   93         } 
catch (Ingester.IngesterException ex) {
 
   94             throw new TskCoreException(ex.getCause().getMessage(), ex);
 
  108         HttpSolrServer solrServer = null;
 
  109         if (host == null || host.isEmpty()) {
 
  113             solrServer = 
new HttpSolrServer(
"http://" + host + 
":" + Integer.toString(port) + 
"/solr"); 
 
  115         } 
catch (SolrServerException ex) {
 
  117         } 
catch (IOException ex) {
 
  118             String result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  119             String message = ex.getCause().getMessage().toLowerCase();
 
  120             if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
 
  122                     if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
 
  124                         result = Bundle.SolrConnectionCheck_Port();
 
  126                         result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  128                 } 
catch (IOException | MissingResourceException any) {
 
  130                     result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  132             } 
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
 
  133                 result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.Hostname"); 
 
  136         } 
catch (NumberFormatException ex) {
 
  138         } 
catch (IllegalArgumentException ex) {
 
  141             if (null != solrServer) {
 
  142                 solrServer.shutdown();
 
  153         "# {0} - case directory", 
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
 
  154         "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
 
  155         "# {0} - index folder path", 
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}" 
  160         IndexMetadata indexMetadata;
 
  162             indexMetadata = 
new IndexMetadata(caseDirectory);
 
  163         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  164             logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class, 
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
 
  168         String currentSchema = IndexFinder.getCurrentSchemaVersion();
 
  169         String currentSolr = IndexFinder.getCurrentSolrVersion();
 
  170         for (Index index : indexMetadata.getIndexes()) {
 
  171             if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
 
  186                  "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  188                  "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  192     public void close() throws IOException {
 
  197         return NbBundle.getMessage(this.getClass(), 
"SolrSearchService.ServiceName");
 
  209         "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
 
  210         "SolrSearch.readingIndexes.msg=Reading text index metadata file",
 
  211         "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
 
  212         "SolrSearch.creatingNewIndex.msg=Creating new text index",
 
  213         "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
 
  214         "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
 
  215         "SolrSearch.openCore.msg=Opening text index",
 
  216         "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
 
  217         "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
 
  218         "SolrSearch.complete.msg=Text index successfully opened"})
 
  225         int totalNumProgressUnits = 7;
 
  226         int progressUnitsCompleted = 0;
 
  230         List<Index> indexes = 
new ArrayList<>();
 
  231         progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
 
  232         if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
 
  235                 progressUnitsCompleted++;
 
  236                 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  237                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath);
 
  238                 indexes = indexMetadata.getIndexes();
 
  239             } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  240                 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
 
  246             progressUnitsCompleted++;
 
  247             progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  248             Index oldIndex = IndexFinder.findOldIndexDir(theCase);
 
  249             if (oldIndex != null) {
 
  251                 indexes.add(oldIndex);
 
  260         Index currentVersionIndex = null;
 
  261         if (indexes.isEmpty()) {
 
  263             progressUnitsCompleted++;
 
  264             progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
 
  265             currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
 
  267             indexes.add(currentVersionIndex);
 
  270             progressUnitsCompleted++;
 
  271             progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
 
  272             currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
 
  273             if (currentVersionIndex == null) {
 
  275                 progressUnitsCompleted++;
 
  276                 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
 
  277                 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
 
  278                 if (indexToUse == null) {
 
  287                 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
 
  288                 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
 
  289                 if (indexSolrVersion == currentSolrVersion) {
 
  293                         JOptionPane optionPane = 
new JOptionPane(
 
  294                                 NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.msg"),
 
  295                                 JOptionPane.WARNING_MESSAGE,
 
  296                                 JOptionPane.DEFAULT_OPTION);
 
  298                             SwingUtilities.invokeAndWait(() -> {
 
  299                                 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.title"));
 
  300                                 dialog.setVisible(
true);
 
  302                         } 
catch (InterruptedException ex) {
 
  305                         } 
catch (InvocationTargetException ex) {
 
  310                     currentVersionIndex = indexToUse;
 
  320             if (!indexes.isEmpty()) {
 
  321                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath, indexes);
 
  323         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  330             long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
 
  331             long sizeInGb = indexSizeInBytes / 1000000000;
 
  332             if (sizeInGb < LARGE_INDEX_SIZE_GB) {
 
  333                 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
 
  334             } 
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
 
  345         progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
 
  363         KeywordSearchResultFactory.BlackboardResultWriter.stopAllWriters();
 
  366         } 
catch (InterruptedException ex) {
 
  367             logger.log(Level.SEVERE, 
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
 
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)