19 package org.sleuthkit.autopsy.keywordsearch;
 
   21 import java.awt.Component;
 
   23 import java.io.IOException;
 
   24 import java.io.Reader;
 
   25 import java.net.InetAddress;
 
   26 import java.util.ArrayList;
 
   27 import java.util.List;
 
   28 import java.util.MissingResourceException;
 
   29 import java.util.logging.Level;
 
   30 import javax.swing.JOptionPane;
 
   31 import org.apache.solr.client.solrj.SolrServerException;
 
   32 import org.openide.util.NbBundle;
 
   33 import org.openide.util.lookup.ServiceProvider;
 
   34 import org.openide.util.lookup.ServiceProviders;
 
   35 import org.openide.windows.WindowManager;
 
   61 @ServiceProviders(value = {
 
   62     @ServiceProvider(service = KeywordSearchService.class),
 
   63     @ServiceProvider(service = AutopsyService.class)
 
   67     private static final String BAD_IP_ADDRESS_FORMAT = 
"ioexception occurred when talking to server"; 
 
   68     private static final String SERVER_REFUSED_CONNECTION = 
"server refused connection"; 
 
   69     private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
 
   86         if (content == null) {
 
   89         final Ingester ingester = Ingester.getDefault();
 
   91             BlackboardArtifact artifact = (BlackboardArtifact) content;
 
  101                 Reader blackboardExtractedTextReader = KeywordSearchUtil.getReader(content);
 
  103                 ingester.indexMetaDataOnly(artifact, sourceName);
 
  105                 ingester.search(blackboardExtractedTextReader, artifact.
getArtifactID(), sourceName, content, null, 
true, 
true, null);
 
  106             } 
catch (Exception ex) {
 
  112                 Reader reader = KeywordSearchUtil.getReader(content);
 
  114                 ingester.search(reader, content.getId(), content.getName(), content, null, 
true, 
true, null);
 
  115             } 
catch (Exception ex) {
 
  136         if (host == null || host.isEmpty()) {
 
  141         } 
catch (SolrServerException ex) {
 
  142             logger.log(Level.SEVERE, 
"Unable to connect to Solr server. Host: " + host + 
", port: " + port, ex);
 
  144         } 
catch (IOException ex) {
 
  145             logger.log(Level.SEVERE, 
"Unable to connect to Solr server. Host: " + host + 
", port: " + port, ex);
 
  146             String result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  147             String message = ex.getCause().getMessage().toLowerCase();
 
  148             if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
 
  150                     if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
 
  152                         result = Bundle.SolrConnectionCheck_Port();
 
  154                         result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  156                 } 
catch (IOException | MissingResourceException any) {
 
  158                     result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  160             } 
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
 
  161                 result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.Hostname"); 
 
  164         } 
catch (NumberFormatException ex) {
 
  165             logger.log(Level.SEVERE, 
"Unable to connect to Solr server. Host: " + host + 
", port: " + port, ex);
 
  167         } 
catch (IllegalArgumentException ex) {
 
  168             logger.log(Level.SEVERE, 
"Unable to connect to Solr server. Host: " + host + 
", port: " + port, ex);
 
  186             ddsServer.deleteDataSource(dataSourceId);
 
  188             logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class, 
"SolrSearchService.DeleteDataSource.msg", dataSourceId), ex);
 
  199         "# {0} - case directory", 
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
 
  200         "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
 
  201         "# {0} - collection name", 
"SolrSearchService.exceptionMessage.unableToDeleteCollection=Unable to delete collection {0}",
 
  202         "# {0} - index folder path", 
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}" 
  207         IndexMetadata indexMetadata;
 
  209             indexMetadata = 
new IndexMetadata(caseDirectory);
 
  210         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  211             logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class, 
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
 
  215         if (indexMetadata.getIndexes().isEmpty()) {
 
  217                     "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  219                     "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  223         for (Index index : indexMetadata.getIndexes()) {
 
  230             File indexDir = 
new File(index.getIndexPath()).getParentFile();
 
  241         return NbBundle.getMessage(this.getClass(), 
"SolrSearchService.ServiceName");
 
  254         "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
 
  255         "SolrSearch.readingIndexes.msg=Reading text index metadata file",
 
  256         "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
 
  257         "SolrSearch.creatingNewIndex.msg=Creating new text index",
 
  258         "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
 
  259         "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
 
  260         "SolrSearch.openCore.msg=Opening text index. For large cases this may take several minutes.",
 
  261         "# {0} - futureVersion", 
"# {1} - currentVersion",
 
  262         "SolrSearch.futureIndexVersion.msg=The text index for the case is for Solr {0}. This version of Autopsy is compatible with Solr {1}.",
 
  263         "SolrSearch.unableToFindIndex.msg=Unable to find index that can be used for this case",
 
  264         "SolrSearch.complete.msg=Text index successfully opened"})
 
  271         int totalNumProgressUnits = 7;
 
  272         int progressUnitsCompleted = 0;
 
  276         List<Index> indexes = 
new ArrayList<>();
 
  277         progress.
progress(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
 
  278         if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
 
  281                 progressUnitsCompleted++;
 
  282                 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  283                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath);
 
  284                 indexes = indexMetadata.getIndexes();
 
  285             } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  286                 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
 
  296         Index currentVersionIndex = null;
 
  297         if (indexes.isEmpty()) {
 
  299             progressUnitsCompleted++;
 
  300             progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
 
  301             currentVersionIndex = IndexFinder.createLatestVersionIndex(theCase);
 
  303             indexes.add(currentVersionIndex);
 
  306             progressUnitsCompleted++;
 
  307             progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
 
  308             currentVersionIndex = IndexFinder.findLatestVersionIndex(indexes);
 
  309             if (currentVersionIndex == null) {
 
  311                 progressUnitsCompleted++;
 
  312                 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
 
  313                 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
 
  314                 if (indexToUse == null) {
 
  317                     String futureIndexVersion = IndexFinder.isFutureIndexPresent(indexes);
 
  318                     if (!futureIndexVersion.isEmpty()) {
 
  319                         throw new AutopsyServiceException(Bundle.SolrSearch_futureIndexVersion_msg(futureIndexVersion, IndexFinder.getCurrentSolrVersion()));
 
  330                 if (!IndexFinder.getCurrentSolrVersion().equals(indexToUse.getSolrVersion())) {
 
  331                     Index prevIndex = indexToUse;
 
  332                     indexToUse = tryUpgradeSolrVersion(context, indexToUse);
 
  333                     if (indexToUse != prevIndex) {
 
  334                         indexes.add(indexToUse);    
 
  343                 if (!indexToUse.isCompatible(IndexFinder.getCurrentSchemaVersion())) {
 
  344                     String msg = 
"Text index schema version " + indexToUse.getSchemaVersion() + 
" is not compatible with current schema";
 
  345                     logger.log(Level.WARNING, msg);
 
  349                 currentVersionIndex = indexToUse;
 
  355             if (!indexes.isEmpty()) {
 
  356                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath, indexes);
 
  358         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  364             progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
 
  375         progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
 
  379     private static final long WAIT_TIME_MILLIS = 2000;
 
  389         "Server_configureSolrConnection_unsupportedSolrTitle=Unsupported Keyword Search in Case",
 
  390         "# {0} - solrVersion",
 
  392         "Server_configureSolrConnection_unsupportedSolrDesc=<html><body><p style=\"width: 400px\">This case was made with an older version of Keyword Search that is no longer supported.  You can continue without upgrading, but some Keyword Search functionality will not be usable while the case is open, and you will encounter errors.  You can also choose to upgrade the Keyword Search version for the case.  If you choose to do this, you will need to run Keyword Search with Solr indexing selected in order to use features like ad hoc search with images in the case.</p></body></html>",
 
  393         "Server_configureSolrConnection_unsupportedSolrDisableOpt=Continue",
 
  394         "Server_configureSolrConnection_unsupportedSolrUpgradeOpt=Upgrade Solr Core" 
  399             Component parentComponent = WindowManager.getDefault().getMainWindow();
 
  401                 parentComponent = progInd.getDialog();
 
  413                 Thread.sleep(WAIT_TIME_MILLIS);
 
  414             } 
catch (InterruptedException ex) {
 
  422             int selection = JOptionPane.showOptionDialog(
 
  424                     Bundle.Server_configureSolrConnection_unsupportedSolrDesc(index.getSolrVersion(), context.
getCase().
getDisplayName()),
 
  425                     Bundle.Server_configureSolrConnection_unsupportedSolrTitle(),
 
  426                     JOptionPane.YES_NO_OPTION,
 
  427                     JOptionPane.WARNING_MESSAGE,
 
  430                         Bundle.Server_configureSolrConnection_unsupportedSolrDisableOpt(),
 
  431                         Bundle.Server_configureSolrConnection_unsupportedSolrUpgradeOpt()
 
  433                     Bundle.Server_configureSolrConnection_unsupportedSolrDisableOpt());
 
  435             if (selection == 1) {
 
  436                 return IndexFinder.createLatestVersionIndex(context.
getCase());
 
  459         AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
 
  462         } 
catch (InterruptedException ex) {
 
  463             logger.log(Level.SEVERE, 
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
 
  489         if (artifact == null) {
 
  495         if (artifact.getArtifactID() > 0) {
 
  498         final Ingester ingester = Ingester.getDefault();
 
  501             String sourceName = artifact.getDisplayName() + 
"_" + artifact.getArtifactID();
 
  503             Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
 
  504             ingester.indexMetaDataOnly(artifact, sourceName);
 
  505             ingester.search(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null, 
true, 
true, null);
 
  506         } 
catch (Exception ex) {
 
static synchronized IngestManager getInstance()
void index(Content content)
void indexArtifact(BlackboardArtifact artifact)
static boolean runningWithGUI
void openCaseResources(CaseContext context)
String getCaseDirectory()
static synchronized Server getServer()
boolean isIngestRunning()
ProgressIndicator getProgressIndicator()
volatile boolean cancelRequested
void unregisterForEvents(Object listener)
void closeCaseResources(CaseContext context)
void deleteTextIndex(CaseMetadata metadata)
SleuthkitCase getSleuthkitCase()
void deleteDataSource(Long dataSourceId)
synchronized static Logger getLogger(String name)
static boolean deleteDir(File dirPath)
Index tryUpgradeSolrVersion(CaseContext context, Index index)
void progress(String message)
void registerForEvents(Object listener)
void tryConnect(String host, int port)