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.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 org.apache.solr.client.solrj.SolrServerException;
31 import org.openide.util.NbBundle;
32 import org.openide.util.lookup.ServiceProvider;
33 import org.openide.util.lookup.ServiceProviders;
55 @ServiceProviders(value = {
56 @ServiceProvider(service = KeywordSearchService.class),
57 @ServiceProvider(service = AutopsyService.class)
61 private static final String BAD_IP_ADDRESS_FORMAT =
"ioexception occurred when talking to server";
62 private static final String SERVER_REFUSED_CONNECTION =
"server refused connection";
63 private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
82 public void index(Content content)
throws TskCoreException {
96 if (content == null) {
99 final Ingester ingester = Ingester.getDefault();
100 if (content instanceof BlackboardArtifact) {
101 BlackboardArtifact artifact = (BlackboardArtifact) content;
102 if (artifact.getArtifactID() > 0) {
112 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
113 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
114 ingester.indexMetaDataOnly(artifact, sourceName);
115 ingester.indexText(blackboardExtractedTextReader, artifact.getArtifactID(), sourceName, content, null);
117 throw new TskCoreException(
"Error indexing artifact", ex);
122 Reader contentExtractedTextReader = contentExtractor.
getReader();
123 ingester.indexText(contentExtractedTextReader, content.getId(), content.getName(), content, null);
128 Reader stringsExtractedTextReader = stringsExtractor.
getReader();
129 ingester.indexStrings(stringsExtractedTextReader, content.getId(), content.getName(), content, null);
131 throw new TskCoreException(
"Error indexing content", ex1);
152 if (host == null || host.isEmpty()) {
157 }
catch (SolrServerException ex) {
158 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
160 }
catch (IOException ex) {
161 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
162 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
163 String message = ex.getCause().getMessage().toLowerCase();
164 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
166 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
168 result = Bundle.SolrConnectionCheck_Port();
170 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
172 }
catch (IOException | MissingResourceException any) {
174 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
176 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
177 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
180 }
catch (NumberFormatException ex) {
181 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
183 }
catch (IllegalArgumentException ex) {
184 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
202 ddsServer.deleteDataSource(dataSourceId);
204 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.DeleteDataSource.msg", dataSourceId), ex);
215 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
216 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
217 "# {0} - collection name",
"SolrSearchService.exceptionMessage.unableToDeleteCollection=Unable to delete collection {0}",
218 "# {0} - index folder path",
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}"
223 IndexMetadata indexMetadata;
225 indexMetadata =
new IndexMetadata(caseDirectory);
226 }
catch (IndexMetadata.TextIndexMetadataException ex) {
227 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
231 if (indexMetadata.getIndexes().isEmpty()) {
233 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
235 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
239 for (Index index : indexMetadata.getIndexes()) {
246 File indexDir =
new File(index.getIndexPath()).getParentFile();
247 if (indexDir.exists()) {
257 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
270 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
271 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
272 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
273 "SolrSearch.creatingNewIndex.msg=Creating new text index",
274 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
275 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
276 "SolrSearch.openCore.msg=Opening text index. For large cases this may take several minutes.",
277 "# {0} - futureVersion",
"# {1} - currentVersion",
278 "SolrSearch.futureIndexVersion.msg=The text index for the case is for Solr {0}. This version of Autopsy is compatible with Solr {1}.",
279 "SolrSearch.unableToFindIndex.msg=Unable to find index that can be used for this case",
280 "SolrSearch.complete.msg=Text index successfully opened"})
287 int totalNumProgressUnits = 7;
288 int progressUnitsCompleted = 0;
292 List<Index> indexes =
new ArrayList<>();
293 progress.
progress(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
294 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
297 progressUnitsCompleted++;
298 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
299 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
300 indexes = indexMetadata.getIndexes();
301 }
catch (IndexMetadata.TextIndexMetadataException ex) {
302 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
312 Index currentVersionIndex = null;
313 if (indexes.isEmpty()) {
315 progressUnitsCompleted++;
316 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
317 currentVersionIndex = IndexFinder.createLatestVersionIndex(theCase);
319 indexes.add(currentVersionIndex);
322 progressUnitsCompleted++;
323 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
324 currentVersionIndex = IndexFinder.findLatestVersionIndex(indexes);
325 if (currentVersionIndex == null) {
327 progressUnitsCompleted++;
328 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
329 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
330 if (indexToUse == null) {
333 String futureIndexVersion = IndexFinder.isFutureIndexPresent(indexes);
334 if (!futureIndexVersion.isEmpty()) {
335 throw new AutopsyServiceException(Bundle.SolrSearch_futureIndexVersion_msg(futureIndexVersion, IndexFinder.getCurrentSolrVersion()));
345 if (!indexToUse.isCompatible(IndexFinder.getCurrentSchemaVersion())) {
346 String msg =
"Text index schema version " + indexToUse.getSchemaVersion() +
" is not compatible with current schema";
347 logger.log(Level.WARNING, msg);
351 currentVersionIndex = indexToUse;
357 if (!indexes.isEmpty()) {
358 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
360 }
catch (IndexMetadata.TextIndexMetadataException ex) {
366 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
377 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
396 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
399 }
catch (InterruptedException ex) {
400 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
419 @NbBundle.Messages(
"SolrSearchService.indexingError=Unable to index blackboard artifact.")
421 void handleNewArtifacts(Blackboard.ArtifactsPostedEvent event) {
422 for (BlackboardArtifact artifact : event.getArtifacts()) {
423 if ((artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) &&
424 (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID())){
427 }
catch (TskCoreException ex) {
429 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex);
430 MessageNotifyUtil.Notify.error(Bundle.SolrSearchService_indexingError(), artifact.getDisplayName());
447 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
448 if (artifact == null) {
454 if (artifact.getArtifactID() > 0) {
457 final Ingester ingester = Ingester.getDefault();
460 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
462 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
463 ingester.indexMetaDataOnly(artifact, sourceName);
464 ingester.indexText(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null);
466 throw new TskCoreException(ex.getCause().getMessage(), ex);
static synchronized IngestManager getInstance()
void index(Content content)
void indexArtifact(BlackboardArtifact artifact)
void openCaseResources(CaseContext context)
String getCaseDirectory()
static synchronized Server getServer()
boolean isIngestRunning()
ProgressIndicator getProgressIndicator()
volatile boolean cancelRequested
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)
void progress(String message)
void tryConnect(String host, int port)