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;
58 @ServiceProviders(value = {
59 @ServiceProvider(service = KeywordSearchService.class)
61 @ServiceProvider(service = AutopsyService.class)}
65 private static final String BAD_IP_ADDRESS_FORMAT =
"ioexception occurred when talking to server";
66 private static final String SERVER_REFUSED_CONNECTION =
"server refused connection";
67 private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
68 private static final int LARGE_INDEX_SIZE_GB = 50;
69 private static final int GIANT_INDEX_SIZE_GB = 500;
88 public void index(Content content)
throws TskCoreException {
102 if (content == null) {
105 final Ingester ingester = Ingester.getDefault();
106 if (content instanceof BlackboardArtifact) {
107 BlackboardArtifact artifact = (BlackboardArtifact) content;
108 if (artifact.getArtifactID() > 0) {
118 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
119 ingester.indexMetaDataOnly(artifact, sourceName);
120 ingester.indexText(blackboardReader, artifact.getArtifactID(), sourceName, content, null);
122 throw new TskCoreException(ex.getCause().getMessage(), ex);
127 ingester.indexText(contentReader, content.getId(), content.getName(), content, null);
132 }
catch (Ingester.IngesterException ex1) {
133 throw new TskCoreException(ex.getCause().getMessage(), ex1);
150 HttpSolrServer solrServer = null;
151 if (host == null || host.isEmpty()) {
155 solrServer =
new HttpSolrServer(
"http://" + host +
":" + Integer.toString(port) +
"/solr");
157 }
catch (SolrServerException ex) {
159 }
catch (IOException ex) {
160 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
161 String message = ex.getCause().getMessage().toLowerCase();
162 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
164 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
166 result = Bundle.SolrConnectionCheck_Port();
168 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
170 }
catch (IOException | MissingResourceException any) {
172 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
174 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
175 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
178 }
catch (NumberFormatException ex) {
180 }
catch (IllegalArgumentException ex) {
183 if (null != solrServer) {
184 solrServer.shutdown();
195 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
196 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
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 String currentSchema = IndexFinder.getCurrentSchemaVersion();
211 String currentSolr = IndexFinder.getCurrentSolrVersion();
212 for (Index index : indexMetadata.getIndexes()) {
213 if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
228 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
230 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
234 public void close() throws IOException {
239 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
252 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
253 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
254 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
255 "SolrSearch.creatingNewIndex.msg=Creating new text index",
256 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
257 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
258 "SolrSearch.openCore.msg=Opening text index",
259 "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
260 "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
261 "SolrSearch.complete.msg=Text index successfully opened"})
268 int totalNumProgressUnits = 7;
269 int progressUnitsCompleted = 0;
273 List<Index> indexes =
new ArrayList<>();
274 progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
275 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
278 progressUnitsCompleted++;
279 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
280 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
281 indexes = indexMetadata.getIndexes();
282 }
catch (IndexMetadata.TextIndexMetadataException ex) {
283 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
289 progressUnitsCompleted++;
290 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
291 Index oldIndex = IndexFinder.findOldIndexDir(theCase);
292 if (oldIndex != null) {
294 indexes.add(oldIndex);
303 Index currentVersionIndex = null;
304 if (indexes.isEmpty()) {
306 progressUnitsCompleted++;
307 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
308 currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
310 indexes.add(currentVersionIndex);
313 progressUnitsCompleted++;
314 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
315 currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
316 if (currentVersionIndex == null) {
318 progressUnitsCompleted++;
319 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
320 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
321 if (indexToUse == null) {
330 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
331 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
332 if (indexSolrVersion == currentSolrVersion) {
336 JOptionPane optionPane =
new JOptionPane(
337 NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.msg"),
338 JOptionPane.WARNING_MESSAGE,
339 JOptionPane.DEFAULT_OPTION);
341 SwingUtilities.invokeAndWait(() -> {
342 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.title"));
343 dialog.setVisible(
true);
345 }
catch (InterruptedException ex) {
348 }
catch (InvocationTargetException ex) {
353 currentVersionIndex = indexToUse;
363 if (!indexes.isEmpty()) {
364 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
366 }
catch (IndexMetadata.TextIndexMetadataException ex) {
373 long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
374 long sizeInGb = indexSizeInBytes / 1000000000;
375 if (sizeInGb < LARGE_INDEX_SIZE_GB) {
376 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
377 }
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
388 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
407 AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
410 }
catch (InterruptedException ex) {
411 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
432 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
433 if (artifact == null) {
439 if (artifact.getArtifactID() > 0) {
442 final Ingester ingester = Ingester.getDefault();
445 String sourceName = artifact.getDisplayName() +
"_" + artifact.getArtifactID();
447 ingester.indexMetaDataOnly(artifact, sourceName);
448 ingester.indexText(contentSpecificReader, artifact.getId(), sourceName, artifact, null);
450 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 Reader getStringsReader(Content content, Lookup context)
static synchronized Server getServer()
static Reader getReader(Content content, Lookup context)
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)