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)