19 package org.sleuthkit.autopsy.keywordsearch;
22 import java.io.IOException;
23 import java.lang.reflect.InvocationTargetException;
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 javax.swing.JDialog;
30 import javax.swing.JOptionPane;
31 import javax.swing.SwingUtilities;
32 import org.apache.commons.lang.math.NumberUtils;
33 import org.apache.commons.io.FileUtils;
34 import org.apache.solr.client.solrj.SolrServerException;
35 import org.apache.solr.client.solrj.impl.HttpSolrServer;
36 import org.openide.util.NbBundle;
37 import org.openide.util.lookup.ServiceProvider;
38 import org.openide.util.lookup.ServiceProviders;
56 @ServiceProviders(value = {
57 @ServiceProvider(service = KeywordSearchService.class)
59 @ServiceProvider(service = AutopsyService.class)}
63 private static final String BAD_IP_ADDRESS_FORMAT =
"ioexception occurred when talking to server";
64 private static final String SERVER_REFUSED_CONNECTION =
"server refused connection";
65 private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
66 private static final int LARGE_INDEX_SIZE_GB = 50;
67 private static final int GIANT_INDEX_SIZE_GB = 500;
86 public void index(Content content)
throws TskCoreException {
100 if (content == null) {
103 final Ingester ingester = Ingester.getDefault();
104 if (content instanceof BlackboardArtifact) {
105 BlackboardArtifact artifact = (BlackboardArtifact) content;
106 if (artifact.getArtifactID() > 0) {
115 ingester.indexMetaDataOnly(artifact);
116 ingester.indexText(
new ArtifactTextExtractor(), artifact, null);
117 }
catch (Ingester.IngesterException ex) {
118 throw new TskCoreException(ex.getCause().getMessage(), ex);
122 ingester.indexText(
new TikaTextExtractor(), content, null);
123 }
catch (Ingester.IngesterException ex) {
126 ingester.indexText(
new StringsTextExtractor(), content, null);
127 }
catch (Ingester.IngesterException ex1) {
128 throw new TskCoreException(ex.getCause().getMessage(), ex1);
145 HttpSolrServer solrServer = null;
146 if (host == null || host.isEmpty()) {
150 solrServer =
new HttpSolrServer(
"http://" + host +
":" + Integer.toString(port) +
"/solr");
152 }
catch (SolrServerException ex) {
154 }
catch (IOException ex) {
155 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
156 String message = ex.getCause().getMessage().toLowerCase();
157 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
159 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
161 result = Bundle.SolrConnectionCheck_Port();
163 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
165 }
catch (IOException | MissingResourceException any) {
167 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
169 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
170 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
173 }
catch (NumberFormatException ex) {
175 }
catch (IllegalArgumentException ex) {
178 if (null != solrServer) {
179 solrServer.shutdown();
190 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
191 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
192 "# {0} - index folder path",
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}"
197 IndexMetadata indexMetadata;
199 indexMetadata =
new IndexMetadata(caseDirectory);
200 }
catch (IndexMetadata.TextIndexMetadataException ex) {
201 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
205 String currentSchema = IndexFinder.getCurrentSchemaVersion();
206 String currentSolr = IndexFinder.getCurrentSolrVersion();
207 for (Index index : indexMetadata.getIndexes()) {
208 if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
223 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
225 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
229 public void close() throws IOException {
234 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
247 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
248 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
249 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
250 "SolrSearch.creatingNewIndex.msg=Creating new text index",
251 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
252 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
253 "SolrSearch.openCore.msg=Opening text index",
254 "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
255 "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
256 "SolrSearch.complete.msg=Text index successfully opened"})
263 int totalNumProgressUnits = 7;
264 int progressUnitsCompleted = 0;
268 List<Index> indexes =
new ArrayList<>();
269 progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
270 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
273 progressUnitsCompleted++;
274 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
275 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
276 indexes = indexMetadata.getIndexes();
277 }
catch (IndexMetadata.TextIndexMetadataException ex) {
278 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
284 progressUnitsCompleted++;
285 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
286 Index oldIndex = IndexFinder.findOldIndexDir(theCase);
287 if (oldIndex != null) {
289 indexes.add(oldIndex);
298 Index currentVersionIndex = null;
299 if (indexes.isEmpty()) {
301 progressUnitsCompleted++;
302 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
303 currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
305 indexes.add(currentVersionIndex);
308 progressUnitsCompleted++;
309 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
310 currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
311 if (currentVersionIndex == null) {
313 progressUnitsCompleted++;
314 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
315 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
316 if (indexToUse == null) {
325 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
326 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
327 if (indexSolrVersion == currentSolrVersion) {
331 JOptionPane optionPane =
new JOptionPane(
332 NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.msg"),
333 JOptionPane.WARNING_MESSAGE,
334 JOptionPane.DEFAULT_OPTION);
336 SwingUtilities.invokeAndWait(() -> {
337 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.title"));
338 dialog.setVisible(
true);
340 }
catch (InterruptedException ex) {
343 }
catch (InvocationTargetException ex) {
348 currentVersionIndex = indexToUse;
358 if (!indexes.isEmpty()) {
359 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
361 }
catch (IndexMetadata.TextIndexMetadataException ex) {
368 long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
369 long sizeInGb = indexSizeInBytes / 1000000000;
370 if (sizeInGb < LARGE_INDEX_SIZE_GB) {
371 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
372 }
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
383 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
402 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
405 }
catch (InterruptedException ex) {
406 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
427 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
428 if (artifact == null) {
434 if (artifact.getArtifactID() > 0) {
437 final Ingester ingester = Ingester.getDefault();
440 ingester.indexMetaDataOnly(artifact);
441 ingester.indexText(
new ArtifactTextExtractor(), artifact, null);
442 }
catch (Ingester.IngesterException ex) {
443 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)