19 package org.sleuthkit.autopsy.keywordsearch;
22 import java.io.IOException;
23 import java.io.Reader;
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 org.apache.solr.client.solrj.SolrServerException;
30 import org.openide.util.NbBundle;
31 import org.openide.util.lookup.ServiceProvider;
32 import org.openide.util.lookup.ServiceProviders;
56 @ServiceProviders(value = {
57 @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;
80 public void index(Content content)
throws TskCoreException {
81 if (content == null) {
84 final Ingester ingester = Ingester.getDefault();
85 if (content instanceof BlackboardArtifact) {
86 BlackboardArtifact artifact = (BlackboardArtifact) content;
87 if (artifact.getArtifactID() > 0) {
97 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
98 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
99 ingester.indexMetaDataOnly(artifact, sourceName);
100 ingester.indexText(blackboardExtractedTextReader, artifact.getArtifactID(), sourceName, content, null);
102 throw new TskCoreException(
"Error indexing artifact", ex);
107 Reader contentExtractedTextReader = contentExtractor.
getReader();
108 ingester.indexText(contentExtractedTextReader, content.getId(), content.getName(), content, null);
113 Reader stringsExtractedTextReader = stringsExtractor.
getReader();
114 ingester.indexStrings(stringsExtractedTextReader, content.getId(), content.getName(), content, null);
116 throw new TskCoreException(
"Error indexing content", ex1);
137 if (host == null || host.isEmpty()) {
142 }
catch (SolrServerException ex) {
143 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
145 }
catch (IOException ex) {
146 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
147 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
148 String message = ex.getCause().getMessage().toLowerCase();
149 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
151 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
153 result = Bundle.SolrConnectionCheck_Port();
155 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
157 }
catch (IOException | MissingResourceException any) {
159 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
161 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
162 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
165 }
catch (NumberFormatException ex) {
166 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
168 }
catch (IllegalArgumentException ex) {
169 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
187 ddsServer.deleteDataSource(dataSourceId);
189 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.DeleteDataSource.msg", dataSourceId), ex);
200 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
201 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
202 "# {0} - collection name",
"SolrSearchService.exceptionMessage.unableToDeleteCollection=Unable to delete collection {0}",
203 "# {0} - index folder path",
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}" 208 IndexMetadata indexMetadata;
210 indexMetadata =
new IndexMetadata(caseDirectory);
211 }
catch (IndexMetadata.TextIndexMetadataException ex) {
212 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
216 if (indexMetadata.getIndexes().isEmpty()) {
218 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
220 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
224 for (Index index : indexMetadata.getIndexes()) {
231 File indexDir =
new File(index.getIndexPath()).getParentFile();
232 if (indexDir.exists()) {
242 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
255 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
256 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
257 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
258 "SolrSearch.creatingNewIndex.msg=Creating new text index",
259 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
260 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
261 "SolrSearch.openCore.msg=Opening text index. For large cases this may take several minutes.",
262 "# {0} - futureVersion",
"# {1} - currentVersion",
263 "SolrSearch.futureIndexVersion.msg=The text index for the case is for Solr {0}. This version of Autopsy is compatible with Solr {1}.",
264 "SolrSearch.unableToFindIndex.msg=Unable to find index that can be used for this case",
265 "SolrSearch.complete.msg=Text index successfully opened"})
272 int totalNumProgressUnits = 7;
273 int progressUnitsCompleted = 0;
277 List<Index> indexes =
new ArrayList<>();
278 progress.
progress(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
279 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
282 progressUnitsCompleted++;
283 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
284 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
285 indexes = indexMetadata.getIndexes();
286 }
catch (IndexMetadata.TextIndexMetadataException ex) {
287 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
297 Index currentVersionIndex = null;
298 if (indexes.isEmpty()) {
300 progressUnitsCompleted++;
301 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
302 currentVersionIndex = IndexFinder.createLatestVersionIndex(theCase);
304 indexes.add(currentVersionIndex);
307 progressUnitsCompleted++;
308 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
309 currentVersionIndex = IndexFinder.findLatestVersionIndex(indexes);
310 if (currentVersionIndex == null) {
312 progressUnitsCompleted++;
313 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
314 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
315 if (indexToUse == null) {
318 String futureIndexVersion = IndexFinder.isFutureIndexPresent(indexes);
319 if (!futureIndexVersion.isEmpty()) {
320 throw new AutopsyServiceException(Bundle.SolrSearch_futureIndexVersion_msg(futureIndexVersion, IndexFinder.getCurrentSolrVersion()));
330 if (!indexToUse.isCompatible(IndexFinder.getCurrentSchemaVersion())) {
331 String msg =
"Text index schema version " + indexToUse.getSchemaVersion() +
" is not compatible with current schema";
332 logger.log(Level.WARNING, msg);
336 currentVersionIndex = indexToUse;
342 if (!indexes.isEmpty()) {
343 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
345 }
catch (IndexMetadata.TextIndexMetadataException ex) {
351 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
362 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
381 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
384 }
catch (InterruptedException ex) {
385 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
410 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
411 if (artifact == null) {
417 if (artifact.getArtifactID() > 0) {
420 final Ingester ingester = Ingester.getDefault();
423 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
425 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
426 ingester.indexMetaDataOnly(artifact, sourceName);
427 ingester.indexText(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null);
429 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)