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;
55 @ServiceProviders(value = {
56 @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;
65 private static final int LARGE_INDEX_SIZE_GB = 50;
66 private static final int GIANT_INDEX_SIZE_GB = 500;
78 public void indexArtifact(BlackboardArtifact artifact)
throws TskCoreException {
79 if (artifact == null) {
85 if (artifact.getArtifactID() > 0) {
88 final Ingester ingester = Ingester.getDefault();
91 ingester.indexMetaDataOnly(artifact);
92 ingester.indexText(
new ArtifactTextExtractor(), artifact, null);
93 }
catch (Ingester.IngesterException ex) {
94 throw new TskCoreException(ex.getCause().getMessage(), ex);
108 HttpSolrServer solrServer = null;
109 if (host == null || host.isEmpty()) {
113 solrServer =
new HttpSolrServer(
"http://" + host +
":" + Integer.toString(port) +
"/solr");
115 }
catch (SolrServerException ex) {
117 }
catch (IOException ex) {
118 String result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
119 String message = ex.getCause().getMessage().toLowerCase();
120 if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
122 if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
124 result = Bundle.SolrConnectionCheck_Port();
126 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
128 }
catch (IOException | MissingResourceException any) {
130 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.HostnameOrPort");
132 }
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
133 result = NbBundle.getMessage(
SolrSearchService.class,
"SolrConnectionCheck.Hostname");
136 }
catch (NumberFormatException ex) {
138 }
catch (IllegalArgumentException ex) {
141 if (null != solrServer) {
142 solrServer.shutdown();
153 "# {0} - case directory",
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
154 "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
155 "# {0} - index folder path",
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}"
160 IndexMetadata indexMetadata;
162 indexMetadata =
new IndexMetadata(caseDirectory);
163 }
catch (IndexMetadata.TextIndexMetadataException ex) {
164 logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class,
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
168 String currentSchema = IndexFinder.getCurrentSchemaVersion();
169 String currentSolr = IndexFinder.getCurrentSolrVersion();
170 for (Index index : indexMetadata.getIndexes()) {
171 if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
186 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
188 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
192 public void close() throws IOException {
197 return NbBundle.getMessage(this.getClass(),
"SolrSearchService.ServiceName");
209 "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
210 "SolrSearch.readingIndexes.msg=Reading text index metadata file",
211 "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
212 "SolrSearch.creatingNewIndex.msg=Creating new text index",
213 "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
214 "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
215 "SolrSearch.openCore.msg=Opening text index",
216 "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
217 "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
218 "SolrSearch.complete.msg=Text index successfully opened"})
225 int totalNumProgressUnits = 7;
226 int progressUnitsCompleted = 0;
230 List<Index> indexes =
new ArrayList<>();
231 progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
232 if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
235 progressUnitsCompleted++;
236 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
237 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath);
238 indexes = indexMetadata.getIndexes();
239 }
catch (IndexMetadata.TextIndexMetadataException ex) {
240 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
246 progressUnitsCompleted++;
247 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
248 Index oldIndex = IndexFinder.findOldIndexDir(theCase);
249 if (oldIndex != null) {
251 indexes.add(oldIndex);
260 Index currentVersionIndex = null;
261 if (indexes.isEmpty()) {
263 progressUnitsCompleted++;
264 progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
265 currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
267 indexes.add(currentVersionIndex);
270 progressUnitsCompleted++;
271 progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
272 currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
273 if (currentVersionIndex == null) {
275 progressUnitsCompleted++;
276 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
277 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
278 if (indexToUse == null) {
287 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
288 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
289 if (indexSolrVersion == currentSolrVersion) {
293 JOptionPane optionPane =
new JOptionPane(
294 NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.msg"),
295 JOptionPane.WARNING_MESSAGE,
296 JOptionPane.DEFAULT_OPTION);
298 SwingUtilities.invokeAndWait(() -> {
299 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(),
"SolrSearchService.IndexReadOnlyDialog.title"));
300 dialog.setVisible(
true);
302 }
catch (InterruptedException ex) {
305 }
catch (InvocationTargetException ex) {
310 currentVersionIndex = indexToUse;
320 if (!indexes.isEmpty()) {
321 IndexMetadata indexMetadata =
new IndexMetadata(caseDirPath, indexes);
323 }
catch (IndexMetadata.TextIndexMetadataException ex) {
330 long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
331 long sizeInGb = indexSizeInBytes / 1000000000;
332 if (sizeInGb < LARGE_INDEX_SIZE_GB) {
333 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
334 }
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
345 progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
363 KeywordSearchResultFactory.BlackboardResultWriter.stopAllWriters();
366 }
catch (InterruptedException ex) {
367 logger.log(Level.SEVERE,
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
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)