19 package org.sleuthkit.autopsy.keywordsearch;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.lang.reflect.InvocationTargetException;
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.JDialog;
31 import javax.swing.JOptionPane;
32 import javax.swing.SwingUtilities;
33 import org.apache.commons.lang.math.NumberUtils;
34 import org.apache.commons.io.FileUtils;
35 import org.apache.solr.client.solrj.SolrServerException;
36 import org.apache.solr.client.solrj.impl.HttpSolrServer;
37 import org.openide.util.NbBundle;
38 import org.openide.util.lookup.ServiceProvider;
39 import org.openide.util.lookup.ServiceProviders;
59 @ServiceProviders(value = {
60 @ServiceProvider(service = KeywordSearchService.class)
62 @ServiceProvider(service = AutopsyService.class)}
66 private static final String BAD_IP_ADDRESS_FORMAT =
"ioexception occurred when talking to server";
67 private static final String SERVER_REFUSED_CONNECTION =
"server refused connection";
68 private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
69 private static final int LARGE_INDEX_SIZE_GB = 50;
70 private static final int GIANT_INDEX_SIZE_GB = 500;
89 public void index(Content content)
throws TskCoreException {
103 if (content == null) {
106 final Ingester ingester = Ingester.getDefault();
107 if (content instanceof BlackboardArtifact) {
108 BlackboardArtifact artifact = (BlackboardArtifact) content;
109 if (artifact.getArtifactID() > 0) {
119 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
120 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
121 ingester.indexMetaDataOnly(artifact, sourceName);
122 ingester.indexText(blackboardExtractedTextReader, artifact.getArtifactID(), sourceName, content, null);
124 throw new TskCoreException(
"Error indexing artifact", ex);
129 Reader contentExtractedTextReader = contentExtractor.
getReader();
130 ingester.indexText(contentExtractedTextReader, content.getId(), content.getName(), content, null);
135 Reader stringsExtractedTextReader = stringsExtractor.
getReader();
136 ingester.indexText(stringsExtractedTextReader,content.getId(),content.getName(), content, null);
138 throw new TskCoreException(
"Error indexing content", ex1);
155 HttpSolrServer solrServer = null;
156 if (host == null || host.isEmpty()) {
160 solrServer =
new HttpSolrServer(
"http://" + host +
":" + Integer.toString(port) +
"/solr");
162 }
catch (SolrServerException ex) {
164 }
catch (IOException ex) {
165 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
166 String message = ex.getCause().getMessage().toLowerCase();
167 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
169 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
171 result = Bundle.SolrConnectionCheck_Port();
173 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
175 }
catch (IOException | MissingResourceException any) {
177 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
179 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
180 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
183 }
catch (NumberFormatException ex) {
185 }
catch (IllegalArgumentException ex) {
188 if (null != solrServer) {
189 solrServer.shutdown();
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} - 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 String currentSchema = IndexFinder.getCurrentSchemaVersion();
216 String currentSolr = IndexFinder.getCurrentSolrVersion();
217 for (Index index : indexMetadata.getIndexes()) {
218 if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
233 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
235 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
239 public void close() throws IOException {
244 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
257 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
258 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
259 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
260 "SolrSearch.creatingNewIndex.msg=Creating new text index",
261 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
262 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
263 "SolrSearch.openCore.msg=Opening text index",
264 "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
265 "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
266 "SolrSearch.complete.msg=Text index successfully opened"})
273 int totalNumProgressUnits = 7;
274 int progressUnitsCompleted = 0;
278 List<Index> indexes =
new ArrayList<>();
279 progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
280 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
283 progressUnitsCompleted++;
284 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
285 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
286 indexes = indexMetadata.getIndexes();
287 }
catch (IndexMetadata.TextIndexMetadataException ex) {
288 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
294 progressUnitsCompleted++;
295 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
296 Index oldIndex = IndexFinder.findOldIndexDir(theCase);
297 if (oldIndex != null) {
299 indexes.add(oldIndex);
308 Index currentVersionIndex = null;
309 if (indexes.isEmpty()) {
311 progressUnitsCompleted++;
312 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
313 currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
315 indexes.add(currentVersionIndex);
318 progressUnitsCompleted++;
319 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
320 currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
321 if (currentVersionIndex == null) {
323 progressUnitsCompleted++;
324 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
325 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
326 if (indexToUse == null) {
335 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
336 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
337 if (indexSolrVersion == currentSolrVersion) {
341 JOptionPane optionPane =
new JOptionPane(
342 NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.msg"),
343 JOptionPane.WARNING_MESSAGE,
344 JOptionPane.DEFAULT_OPTION);
346 SwingUtilities.invokeAndWait(() -> {
347 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.title"));
348 dialog.setVisible(
true);
350 }
catch (InterruptedException ex) {
353 }
catch (InvocationTargetException ex) {
358 currentVersionIndex = indexToUse;
368 if (!indexes.isEmpty()) {
369 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
371 }
catch (IndexMetadata.TextIndexMetadataException ex) {
378 long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
379 long sizeInGb = indexSizeInBytes / 1000000000;
380 if (sizeInGb < LARGE_INDEX_SIZE_GB) {
381 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
382 }
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
393 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
412 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
415 }
catch (InterruptedException ex) {
416 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
437 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
438 if (artifact == null) {
444 if (artifact.getArtifactID() > 0) {
447 final Ingester ingester = Ingester.getDefault();
450 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
452 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
453 ingester.indexMetaDataOnly(artifact, sourceName);
454 ingester.indexText(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null);
456 throw new TskCoreException(ex.getCause().getMessage(), ex);
void index(Content content)
void indexArtifact(BlackboardArtifact artifact)
static boolean runningWithGUI
void start(String message, int totalWorkUnits)
void openCaseResources(CaseContext context)
String getCaseDirectory()
static synchronized Server getServer()
ProgressIndicator getProgressIndicator()
volatile boolean cancelRequested
void closeCaseResources(CaseContext context)
void deleteTextIndex(CaseMetadata metadata)
synchronized static Logger getLogger(String name)
static boolean deleteDir(File dirPath)
void progress(String message)
void tryConnect(String host, int port)
void switchToIndeterminate(String message)