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) {
96 Reader blackboardExtractedTextReader = KeywordSearchUtil.getReader(content);
97 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
98 ingester.indexMetaDataOnly(artifact, sourceName);
100 ingester.search(blackboardExtractedTextReader, artifact.getArtifactID(), sourceName, content, null,
true,
true, null);
101 }
catch (Exception ex) {
102 throw new TskCoreException(
"Error indexing artifact", ex);
107 Reader reader = KeywordSearchUtil.getReader(content);
109 ingester.search(reader, content.getId(), content.getName(), content, null,
true,
true, null);
110 }
catch (Exception ex) {
111 throw new TskCoreException(
"Error indexing content", ex);
131 if (host == null || host.isEmpty()) {
136 }
catch (SolrServerException ex) {
137 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
139 }
catch (IOException ex) {
140 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
141 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
142 String message = ex.getCause().getMessage().toLowerCase();
143 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
145 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
147 result = Bundle.SolrConnectionCheck_Port();
149 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
151 }
catch (IOException | MissingResourceException any) {
153 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
155 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
156 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
159 }
catch (NumberFormatException ex) {
160 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
162 }
catch (IllegalArgumentException ex) {
163 logger.log(Level.SEVERE,
"Unable to connect to Solr server. Host: " + host +
", port: " + port, ex);
181 ddsServer.deleteDataSource(dataSourceId);
183 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.DeleteDataSource.msg", dataSourceId), ex);
194 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
195 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
196 "# {0} - collection name",
"SolrSearchService.exceptionMessage.unableToDeleteCollection=Unable to delete collection {0}",
197 "# {0} - index folder path",
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}"
202 IndexMetadata indexMetadata;
204 indexMetadata =
new IndexMetadata(caseDirectory);
205 }
catch (IndexMetadata.TextIndexMetadataException ex) {
206 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
210 if (indexMetadata.getIndexes().isEmpty()) {
212 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
214 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
218 for (Index index : indexMetadata.getIndexes()) {
225 File indexDir =
new File(index.getIndexPath()).getParentFile();
226 if (indexDir.exists()) {
236 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
249 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
250 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
251 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
252 "SolrSearch.creatingNewIndex.msg=Creating new text index",
253 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
254 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
255 "SolrSearch.openCore.msg=Opening text index. For large cases this may take several minutes.",
256 "# {0} - futureVersion",
"# {1} - currentVersion",
257 "SolrSearch.futureIndexVersion.msg=The text index for the case is for Solr {0}. This version of Autopsy is compatible with Solr {1}.",
258 "SolrSearch.unableToFindIndex.msg=Unable to find index that can be used for this case",
259 "SolrSearch.complete.msg=Text index successfully opened"})
266 int totalNumProgressUnits = 7;
267 int progressUnitsCompleted = 0;
271 List<Index> indexes =
new ArrayList<>();
272 progress.
progress(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
273 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
276 progressUnitsCompleted++;
277 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
278 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
279 indexes = indexMetadata.getIndexes();
280 }
catch (IndexMetadata.TextIndexMetadataException ex) {
281 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
291 Index currentVersionIndex = null;
292 if (indexes.isEmpty()) {
294 progressUnitsCompleted++;
295 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
296 currentVersionIndex = IndexFinder.createLatestVersionIndex(theCase);
298 indexes.add(currentVersionIndex);
301 progressUnitsCompleted++;
302 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
303 currentVersionIndex = IndexFinder.findLatestVersionIndex(indexes);
304 if (currentVersionIndex == null) {
306 progressUnitsCompleted++;
307 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
308 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
309 if (indexToUse == null) {
312 String futureIndexVersion = IndexFinder.isFutureIndexPresent(indexes);
313 if (!futureIndexVersion.isEmpty()) {
314 throw new AutopsyServiceException(Bundle.SolrSearch_futureIndexVersion_msg(futureIndexVersion, IndexFinder.getCurrentSolrVersion()));
324 if (!indexToUse.isCompatible(IndexFinder.getCurrentSchemaVersion())) {
325 String msg =
"Text index schema version " + indexToUse.getSchemaVersion() +
" is not compatible with current schema";
326 logger.log(Level.WARNING, msg);
330 currentVersionIndex = indexToUse;
336 if (!indexes.isEmpty()) {
337 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
339 }
catch (IndexMetadata.TextIndexMetadataException ex) {
345 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
356 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
375 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
378 }
catch (InterruptedException ex) {
379 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
404 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
405 if (artifact == null) {
411 if (artifact.getArtifactID() > 0) {
414 final Ingester ingester = Ingester.getDefault();
417 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
419 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
420 ingester.indexMetaDataOnly(artifact, sourceName);
421 ingester.search(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null,
true,
true, null);
422 }
catch (Exception ex) {
423 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)