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;
79 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
80 if (artifact == null) {
86 if (artifact.getArtifactID() > 0) {
89 final Ingester ingester = Ingester.getDefault();
92 ingester.indexMetaDataOnly(artifact);
93 ingester.indexText(
new ArtifactTextExtractor(), artifact, null);
94 }
catch (Ingester.IngesterException ex) {
95 throw new TskCoreException(ex.getCause().getMessage(), ex);
105 public void index(Content content)
throws TskCoreException {
106 if (content == null) {
109 final Ingester ingester = Ingester.getDefault();
112 ingester.indexText(
new TikaTextExtractor(), content, null);
113 }
catch (Ingester.IngesterException ex) {
116 ingester.indexText(
new StringsTextExtractor(), content, null);
117 }
catch (Ingester.IngesterException ex1) {
118 throw new TskCoreException(ex.getCause().getMessage(), ex1);
138 HttpSolrServer solrServer = null;
139 if (host == null || host.isEmpty()) {
143 solrServer =
new HttpSolrServer(
"http://" + host +
":" + Integer.toString(port) +
"/solr");
145 }
catch (SolrServerException ex) {
147 }
catch (IOException ex) {
148 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
149 String message = ex.getCause().getMessage().toLowerCase();
150 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
152 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
154 result = Bundle.SolrConnectionCheck_Port();
156 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
158 }
catch (IOException | MissingResourceException any) {
160 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
162 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
163 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
166 }
catch (NumberFormatException ex) {
168 }
catch (IllegalArgumentException ex) {
171 if (null != solrServer) {
172 solrServer.shutdown();
183 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
184 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
185 "# {0} - index folder path",
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}"
190 IndexMetadata indexMetadata;
192 indexMetadata =
new IndexMetadata(caseDirectory);
193 }
catch (IndexMetadata.TextIndexMetadataException ex) {
194 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
198 String currentSchema = IndexFinder.getCurrentSchemaVersion();
199 String currentSolr = IndexFinder.getCurrentSolrVersion();
200 for (Index index : indexMetadata.getIndexes()) {
201 if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
216 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
218 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
222 public void close() throws IOException {
227 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
239 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
240 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
241 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
242 "SolrSearch.creatingNewIndex.msg=Creating new text index",
243 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
244 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
245 "SolrSearch.openCore.msg=Opening text index",
246 "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
247 "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
248 "SolrSearch.complete.msg=Text index successfully opened"})
255 int totalNumProgressUnits = 7;
256 int progressUnitsCompleted = 0;
260 List<Index> indexes =
new ArrayList<>();
261 progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
262 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
265 progressUnitsCompleted++;
266 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
267 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
268 indexes = indexMetadata.getIndexes();
269 }
catch (IndexMetadata.TextIndexMetadataException ex) {
270 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
276 progressUnitsCompleted++;
277 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
278 Index oldIndex = IndexFinder.findOldIndexDir(theCase);
279 if (oldIndex != null) {
281 indexes.add(oldIndex);
290 Index currentVersionIndex = null;
291 if (indexes.isEmpty()) {
293 progressUnitsCompleted++;
294 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
295 currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
297 indexes.add(currentVersionIndex);
300 progressUnitsCompleted++;
301 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
302 currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
303 if (currentVersionIndex == null) {
305 progressUnitsCompleted++;
306 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
307 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
308 if (indexToUse == null) {
317 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
318 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
319 if (indexSolrVersion == currentSolrVersion) {
323 JOptionPane optionPane =
new JOptionPane(
324 NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.msg"),
325 JOptionPane.WARNING_MESSAGE,
326 JOptionPane.DEFAULT_OPTION);
328 SwingUtilities.invokeAndWait(() -> {
329 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.title"));
330 dialog.setVisible(
true);
332 }
catch (InterruptedException ex) {
335 }
catch (InvocationTargetException ex) {
340 currentVersionIndex = indexToUse;
350 if (!indexes.isEmpty()) {
351 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
353 }
catch (IndexMetadata.TextIndexMetadataException ex) {
360 long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
361 long sizeInGb = indexSizeInBytes / 1000000000;
362 if (sizeInGb < LARGE_INDEX_SIZE_GB) {
363 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
364 }
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
375 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
393 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
396 }
catch (InterruptedException ex) {
397 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", 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)