{
/**
* sort the groups by some priority metric to be determined and implemented
*/
- public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)));
+ public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)).reversed());
@Override
public int compare(DrawableGroup o1, DrawableGroup o2) {
diff --git a/KeywordSearch/ivy.xml b/KeywordSearch/ivy.xml
index 6135777192..3ceb4e6378 100644
--- a/KeywordSearch/ivy.xml
+++ b/KeywordSearch/ivy.xml
@@ -5,10 +5,6 @@
-
-
-
-
@@ -22,19 +18,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/KeywordSearch/nbproject/project.properties b/KeywordSearch/nbproject/project.properties
index 3a5a642995..5aa1b716e0 100644
--- a/KeywordSearch/nbproject/project.properties
+++ b/KeywordSearch/nbproject/project.properties
@@ -124,9 +124,6 @@ file.reference.slf4j-api-1.7.12.jar=release/modules/ext/slf4j-api-1.7.12.jar
file.reference.solr-solrj-4.9.1-javadoc.jar=release/modules/ext/solr-solrj-4.9.1-javadoc.jar
file.reference.solr-solrj-4.9.1-sources.jar=release/modules/ext/solr-solrj-4.9.1-sources.jar
file.reference.solr-solrj-4.9.1.jar=release/modules/ext/solr-solrj-4.9.1.jar
-file.reference.solr-solrj-6.2.1-javadoc.jar=release/modules/ext/solr-solrj-6.2.1-javadoc.jar
-file.reference.solr-solrj-6.2.1-sources.jar=release/modules/ext/solr-solrj-6.2.1-sources.jar
-file.reference.solr-solrj-6.2.1.jar=release/modules/ext/solr-solrj-6.2.1.jar
file.reference.spring-aop-3.1.2.RELEASE.jar=release/modules/ext/spring-aop-3.1.2.RELEASE.jar
file.reference.spring-asm-3.1.2.RELEASE.jar=release/modules/ext/spring-asm-3.1.2.RELEASE.jar
file.reference.spring-beans-3.1.2.RELEASE.jar=release/modules/ext/spring-beans-3.1.2.RELEASE.jar
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties
index 050e2d687e..99d88938ce 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties
@@ -213,7 +213,7 @@ Server.queryNumFileChunks.exception.msg=Error getting number of file chunks,
Server.query.exception.msg=Error running query\: {0}
Server.query2.exception.msg=Error running query\: {0}
Server.queryTerms.exception.msg=Error running terms query\: {0}
-Server.connect.exception.msg=Failed to connect to Solr server\:
+Server.connect.exception.msg=Failed to connect to Solr server\: {0}
Server.openCore.exception.msg=Keyword search service not yet running
Server.openCore.exception.cantOpen.msg=Could not create or open index
Server.openCore.exception.noIndexDir.msg=Index directory could not be created or is missing
@@ -315,8 +315,6 @@ GlobalListsManagementPanel.copyListButton.text=Copy List
GlobalListsManagementPanel.renameListButton.text=Edit List Name
GlobalEditListPanel.editWordButton.text=Edit Keyword
SolrSearchService.ServiceName=Solr Keyword Search Service
-SolrSearchService.IndexUpgradeDialog.title=Text Index Upgrade Required In Order To Open Case
-SolrSearchService.IndexUpgradeDialog.msg=The text index upgrade can take some time.
When completed, you will be able to see existing keyword search results and perform literal keyword searches,
but you will not be able to add new text to the index or perform regex searches. You may instead open the case
with your previous version of this application. Do you wish to proceed with the index upgrade?
SolrSearchService.IndexReadOnlyDialog.title=Text Index Is Read-Only
-SolrSearchService.IndexReadOnlyDialog.msg=The text index for this case is read-only.
You will be able to see existing keyword search results and perform literal keyword searches,
but you will not be able to add new text to the index or perform regex searches. You may instead open the case
with your previous version of this application.
+SolrSearchService.IndexReadOnlyDialog.msg=The text index for this case is read-only.
You will be able to see existing keyword search results and perform exact match and substring match keyword searches,
but you will not be able to add new text to the index or perform regex searches. You may instead open the case
with your previous version of this application.
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle_ja.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle_ja.properties
index 78412ea29e..04b64d7414 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle_ja.properties
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle_ja.properties
@@ -270,7 +270,7 @@ HighlightedMatchesSource.getMarkup.queryFailedMsg=>> responseHighlight = response.getHighlighting();
- String highlightField = isLiteral
- ? LuceneQuery.HIGHLIGHT_FIELD
- : Server.Schema.CONTENT_STR.toString();
+
if (responseHighlight == null) {
highlightedContent = attemptManualHighlighting(response.getResults(), highlightField, keywords);
} else {
@@ -433,6 +445,7 @@ class HighlightedText implements IndexedText {
return 0;
}
return this.numberOfHitsPerPage.get(this.currentPage);
+
}
/**
@@ -445,7 +458,7 @@ class HighlightedText implements IndexedText {
* to a Solr query. We expect there to only ever be
* a single document.
*
- * @return Either a string with the keyword highlighted or a string
+ * @return Either a string with the keyword highlighted via HTML span tags or a string
* indicating that we did not find a hit in the document.
*/
static String attemptManualHighlighting(SolrDocumentList solrDocumentList, String highlightField, Collection keywords) {
@@ -465,38 +478,41 @@ class HighlightedText implements IndexedText {
// not see highlighted text in the content viewer.
text = StringEscapeUtils.escapeHtml(text);
- StringBuilder highlightedText = new StringBuilder("");
+ TreeRangeSet highlights = TreeRangeSet.create();
- //do a highlighting pass for each keyword
+ //for each keyword find the locations of hits and record them in the RangeSet
for (String keyword : keywords) {
- //we also need to escape the keyword so that it matches the escpared text
+ //we also need to escape the keyword so that it matches the escaped text
final String escapedKeyword = StringEscapeUtils.escapeHtml(keyword);
- int textOffset = 0;
- int hitOffset = StringUtils.indexOfIgnoreCase(text, escapedKeyword, textOffset);
+ int searchOffset = 0;
+ int hitOffset = StringUtils.indexOfIgnoreCase(text, escapedKeyword, searchOffset);
while (hitOffset != -1) {
- // Append the portion of text up to (but not including) the hit.
- highlightedText.append(text.substring(textOffset, hitOffset));
- // Add in the highlighting around the keyword.
- highlightedText.append(HIGHLIGHT_PRE);
- highlightedText.append(keyword);
- highlightedText.append(HIGHLIGHT_POST);
+ // Advance the search offset past the keyword.
+ searchOffset = hitOffset + escapedKeyword.length();
- // Advance the text offset past the keyword.
- textOffset = hitOffset + escapedKeyword.length();
+ //record the location of the hit, possibly merging it with other hits
+ highlights.add(Range.closedOpen(hitOffset, searchOffset));
- hitOffset = StringUtils.indexOfIgnoreCase(text, escapedKeyword, textOffset);
+ //look for next hit
+ hitOffset = StringUtils.indexOfIgnoreCase(text, escapedKeyword, searchOffset);
}
- // Append the remainder of text field
- highlightedText.append(text.substring(textOffset, text.length()));
-
- if (highlightedText.length() == 0) {
- return NbBundle.getMessage(HighlightedText.class, "HighlightedMatchesSource.getMarkup.noMatchMsg");
- }
- //reset for next pass
- text = highlightedText.toString();
- highlightedText = new StringBuilder("");
}
- return text;
+
+ StringBuilder highlightedText = new StringBuilder(text);
+ int totalHighLightLengthInserted = 0;
+ //for each range to be highlighted...
+ for (Range highlightRange : highlights.asRanges()) {
+ int hStart = highlightRange.lowerEndpoint();
+ int hEnd = highlightRange.upperEndpoint();
+
+ //insert the pre and post tag, adjusting indices for previously added tags
+ highlightedText.insert(hStart + totalHighLightLengthInserted, HIGHLIGHT_PRE);
+ totalHighLightLengthInserted += HIGHLIGHT_PRE.length();
+ highlightedText.insert(hEnd + totalHighLightLengthInserted, HIGHLIGHT_POST);
+ totalHighLightLengthInserted += HIGHLIGHT_POST.length();
+ }
+
+ return highlightedText.toString();
}
/**
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java
index 5d79639fc5..e5db5b6a10 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2011-2016 Basis Technology Corp.
+ * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,6 +25,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import net.htmlparser.jericho.Attributes;
+import net.htmlparser.jericho.Config;
+import net.htmlparser.jericho.LoggerProvider;
import net.htmlparser.jericho.Renderer;
import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.StartTag;
@@ -49,6 +51,11 @@ class HtmlTextExtractor extends FileTextExtractor {
"text/html", //NON-NLS NON-NLS
"text/javascript" //NON-NLS
);
+
+ static {
+ // Disable Jericho HTML Parser log messages.
+ Config.LoggerProvider = LoggerProvider.DISABLED;
+ }
@Override
boolean isContentTypeSpecific() {
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java
index 6ecf83bdce..b4a09e226e 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java
@@ -27,7 +27,7 @@ import java.util.List;
import org.apache.commons.lang.math.NumberUtils;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.autopsy.framework.AutopsyService;
+import org.sleuthkit.autopsy.appservices.AutopsyService;
/**
* This class handles the task of finding and identifying KWS index folders.
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
index ad9e151e9e..0ec43d4b3e 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
@@ -315,16 +315,16 @@ class Ingester {
*
* @return The field map of fields that are common to all file classes.
*/
- private Map getCommonFields(AbstractFile af) {
+ private Map getCommonFields(AbstractFile file) {
Map params = new HashMap<>();
- params.put(Server.Schema.ID.toString(), Long.toString(af.getId()));
+ params.put(Server.Schema.ID.toString(), Long.toString(file.getId()));
try {
- params.put(Server.Schema.IMAGE_ID.toString(), Long.toString(af.getDataSource().getId()));
+ params.put(Server.Schema.IMAGE_ID.toString(), Long.toString(file.getDataSource().getId()));
} catch (TskCoreException ex) {
- logger.log(Level.SEVERE, "Could not get data source id to properly index the file " + af.getId(), ex); //NON-NLS
+ logger.log(Level.SEVERE, "Could not get data source id to properly index the file " + file.getId(), ex); //NON-NLS
params.put(Server.Schema.IMAGE_ID.toString(), Long.toString(-1));
}
- params.put(Server.Schema.FILE_NAME.toString(), af.getName());
+ params.put(Server.Schema.FILE_NAME.toString(), file.getName());
return params;
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java
index 6f3c11f8cb..08a6b38165 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2011-2016 Basis Technology Corp.
+ * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -446,7 +446,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
}
if (extractor == null) {
- logger.log(Level.INFO, "No text extractor found for file id:{0}, name: {1}, detected format: {2}", new Object[]{aFile.getId(), aFile.getName(), detectedFormat}); //NON-NLS
+ // No text extractor found.
return false;
}
@@ -561,7 +561,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
return;
}
if (!extractTextAndIndex(aFile, fileType)) {
- logger.log(Level.WARNING, "Text extractor not found for file. Extracting strings only. File: ''{0}'' (id:{1}).", new Object[]{aFile.getName(), aFile.getId()}); //NON-NLS
+ // Text extractor not found for file. Extract string only.
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
} else {
putIngestStatus(jobId, aFile.getId(), IngestStatus.TEXT_INGESTED);
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java
index a5925e9f2e..3a55aad646 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java
@@ -187,7 +187,7 @@ public class Server {
private int currentSolrServerPort = 0;
private int currentSolrStopPort = 0;
private static final boolean DEBUG = false;//(Version.getBuildType() == Version.Type.DEVELOPMENT);
- private static final String SOLR = "solr";
+ private static final String SOLR = "solr";
private static final String CORE_PROPERTIES = "core.properties";
public enum CORE_EVT_STATES {
@@ -636,7 +636,7 @@ public class Server {
* Creates/opens a Solr core (index) for a case.
*
* @param theCase The case for which the core is to be created/opened.
- * @param index The text index that the Solr core should be using.
+ * @param index The text index that the Solr core should be using.
*
* @throws KeywordSearchModuleException If an error occurs while
* creating/opening the core.
@@ -645,14 +645,14 @@ public class Server {
currentCoreLock.writeLock().lock();
try {
currentCore = openCore(theCase, index);
-
+
try {
// execute a test query. if it fails, an exception will be thrown
queryNumIndexedFiles();
} catch (NoOpenCoreException ex) {
throw new KeywordSearchModuleException(NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex);
}
-
+
serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STARTED);
} finally {
currentCoreLock.writeLock().unlock();
@@ -684,7 +684,7 @@ public class Server {
currentCoreLock.readLock().unlock();
}
}
-
+
void closeCore() throws KeywordSearchModuleException {
currentCoreLock.writeLock().lock();
try {
@@ -713,7 +713,6 @@ public class Server {
/**
* ** end single-case specific methods ***
*/
-
/**
* Deletes the keyword search core for a case.
*
@@ -721,46 +720,41 @@ public class Server {
*/
@NbBundle.Messages({
"# {0} - core name", "Server.deleteCore.exception.msg=Failed to delete Solr core {0}",})
- void deleteCore(String coreName) throws KeywordSearchServiceException {
- /*
- * Send a core unload request to the Solr server, with the parameters
- * that request deleting the index and the instance directory
- * (deleteInstanceDir removes everything related to the core, the index
- * directory, the configuration files, etc.) set to true.
- * NOTE: this method doesn't delete the actual Solr index directory. That is
- * done as part of deleting case output directory.
- */
-
- // check whether the core we are deleting is the currently open core
- currentCoreLock.readLock().lock();
+ void deleteCore(String coreName, Case.CaseType caseType) throws KeywordSearchServiceException {
try {
- if (null != currentCore) {
- if (currentCore.getName().equals(coreName)) {
- // close current core first
- closeCore();
- }
+ HttpSolrServer solrServer;
+ if (caseType == CaseType.SINGLE_USER_CASE) {
+ Integer localSolrServerPort = Integer.decode(ModuleSettings.getConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT));
+ solrServer = new HttpSolrServer("http://localhost:" + localSolrServerPort + "/solr"); //NON-NLS
+ } else {
+ String host = UserPreferences.getIndexingServerHost();
+ String port = UserPreferences.getIndexingServerPort();
+ solrServer = new HttpSolrServer("http://" + host + ":" + port + "/solr"); //NON-NLS
}
- } catch (KeywordSearchModuleException ex) {
- throw new KeywordSearchServiceException(NbBundle.getMessage(Server.class, "Server.close.exception.msg"), ex);
- } finally {
- currentCoreLock.readLock().unlock();
- }
-
- try {
- HttpSolrServer solrServer = new HttpSolrServer("http://" + UserPreferences.getIndexingServerHost() + ":" + UserPreferences.getIndexingServerPort() + "/solr"); //NON-NLS
connectToSolrServer(solrServer);
- org.apache.solr.client.solrj.request.CoreAdminRequest.unloadCore(coreName, true, true, solrServer);
- } catch (SolrServerException | IOException ex) {
+ CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, solrServer);
+ if (null != response.getCoreStatus(coreName).get("instanceDir")) { //NON-NLS
+ /*
+ * Send a core unload request to the Solr server, with the
+ * parameter set that request deleting the index and the
+ * instance directory (deleteInstanceDir = true). Note that this
+ * removes everything related to the core on the server (the
+ * index directory, the configuration files, etc.), but does not
+ * delete the actual Solr text index because it is currently
+ * stored in the case directory.
+ */
+ org.apache.solr.client.solrj.request.CoreAdminRequest.unloadCore(coreName, true, true, solrServer);
+ }
+ } catch (SolrServerException | HttpSolrServer.RemoteSolrException | IOException ex) {
throw new KeywordSearchServiceException(Bundle.Server_deleteCore_exception_msg(coreName), ex);
}
}
-
/**
* Creates/opens a Solr core (index) for a case.
*
* @param theCase The case for which the core is to be created/opened.
- * @param index The text index that the Solr core should be using.
+ * @param index The text index that the Solr core should be using.
*
* @return An object representing the created/opened core.
*
@@ -780,7 +774,7 @@ public class Server {
connectToSolrServer(currentSolrServer);
} catch (SolrServerException | IOException ex) {
- throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg"), ex);
+ throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
}
try {
@@ -891,8 +885,8 @@ public class Server {
}
/**
- * Execute query that gets only number of all Solr file chunks (not
- * logical files) indexed without actually returning the content.
+ * Execute query that gets only number of all Solr file chunks (not logical
+ * files) indexed without actually returning the content.
*
* @return int representing number of indexed chunks
*
@@ -916,8 +910,8 @@ public class Server {
}
/**
- * Execute query that gets only number of all Solr documents indexed
- * (files and chunks) without actually returning the documents
+ * Execute query that gets only number of all Solr documents indexed (files
+ * and chunks) without actually returning the documents
*
* @return int representing number of indexed files (files and chunks)
*
@@ -970,11 +964,10 @@ public class Server {
/**
* Execute query that gets number of indexed file chunks for a file
*
- * @param fileID file id of the original file broken into chunks and
- * indexed
+ * @param fileID file id of the original file broken into chunks and indexed
*
- * @return int representing number of indexed file chunks, 0 if there is
- * no chunks
+ * @return int representing number of indexed file chunks, 0 if there is no
+ * chunks
*
* @throws KeywordSearchModuleException
* @throws NoOpenCoreException
@@ -1206,8 +1199,7 @@ public class Server {
}
/**
- * Determines whether or not the index files folder for a Solr core
- * exists.
+ * Determines whether or not the index files folder for a Solr core exists.
*
* @param coreName the name of the core.
*
@@ -1233,7 +1225,7 @@ public class Server {
private final String name;
private final CaseType caseType;
-
+
private final Index textIndex;
// the server to access a core needs to be built from a URL with the
@@ -1272,7 +1264,7 @@ public class Server {
private Index getIndexInfo() {
return this.textIndex;
}
-
+
private QueryResponse query(SolrQuery sq) throws SolrServerException, IOException {
return solrCore.query(sq);
}
@@ -1385,8 +1377,8 @@ public class Server {
* Execute query that gets only number of all Solr files (not chunks)
* indexed without actually returning the files
*
- * @return int representing number of indexed files (entire files,
- * not chunks)
+ * @return int representing number of indexed files (entire files, not
+ * chunks)
*
* @throws SolrServerException
*/
@@ -1447,11 +1439,11 @@ public class Server {
/**
* Execute query that gets number of indexed file chunks for a file
*
- * @param contentID file id of the original file broken into chunks
- * and indexed
+ * @param contentID file id of the original file broken into chunks and
+ * indexed
*
- * @return int representing number of indexed file chunks, 0 if there
- * is no chunks
+ * @return int representing number of indexed file chunks, 0 if there is
+ * no chunks
*
* @throws SolrServerException
*/
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
index acde9d77fc..eee3ac4dad 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
@@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.keywordsearch;
+import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
@@ -37,9 +38,10 @@ import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
import org.sleuthkit.autopsy.core.RuntimeProperties;
+import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.autopsy.framework.AutopsyService;
-import org.sleuthkit.autopsy.framework.ProgressIndicator;
+import org.sleuthkit.autopsy.appservices.AutopsyService;
+import org.sleuthkit.autopsy.progress.ProgressIndicator;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
import org.sleuthkit.datamodel.BlackboardArtifact;
@@ -50,7 +52,8 @@ import org.sleuthkit.datamodel.TskCoreException;
* text indexing and search.
*/
@ServiceProviders(value = {
- @ServiceProvider(service = KeywordSearchService.class),
+ @ServiceProvider(service = KeywordSearchService.class)
+ ,
@ServiceProvider(service = AutopsyService.class)}
)
public class SolrSearchService implements KeywordSearchService, AutopsyService {
@@ -138,16 +141,17 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
}
}
- @NbBundle.Messages({"# {0} - case directory",
- "SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from caseDirectory: {0}",
- "# {0} - case directory",
- "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case"
- })
/**
* Deletes Solr core for a case.
*
* @param metadata The CaseMetadata which will have its core deleted.
*/
+ @NbBundle.Messages({"# {0} - case directory",
+ "SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from caseDirectory: {0}",
+ "# {0} - case directory",
+ "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
+ "SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}"
+ })
@Override
public void deleteTextIndex(CaseMetadata metadata) throws KeywordSearchServiceException {
String caseDirectory = metadata.getCaseDirectory();
@@ -163,13 +167,23 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
String currentSolr = IndexFinder.getCurrentSolrVersion();
for (Index index : indexMetadata.getIndexes()) {
if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
- KeywordSearch.getServer().deleteCore(index.getIndexName());
- return; //only one core exists for each combination of solr and schema version
+ /*
+ * Unload/delete the core on the server and then delete the text
+ * index files.
+ */
+ KeywordSearch.getServer().deleteCore(index.getIndexName(), metadata.getCaseType());
+ if (!FileUtil.deleteDir(new File(index.getIndexPath()).getParentFile())) {
+ throw new KeywordSearchServiceException(Bundle.SolrSearchService_exceptionMessage_failedToDeleteIndexFiles(index.getIndexPath()));
+ }
}
+ return; //only one core exists for each combination of solr and schema version
}
+
//this code this code will only execute if an index for the current core was not found
- logger.log(Level.WARNING, NbBundle.getMessage(SolrSearchService.class, "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
- throw new KeywordSearchServiceException(NbBundle.getMessage(SolrSearchService.class, "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
+ logger.log(Level.WARNING, NbBundle.getMessage(SolrSearchService.class,
+ "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
+ throw new KeywordSearchServiceException(NbBundle.getMessage(SolrSearchService.class,
+ "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
}
@Override
@@ -200,6 +214,10 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
"SolrSearch.openCore.msg=Opening text index",
"SolrSearch.complete.msg=Text index successfully opened"})
public void openCaseResources(CaseContext context) throws AutopsyServiceException {
+ if (context.cancelRequested()) {
+ return;
+ }
+
ProgressIndicator progress = context.getProgressIndicator();
int totalNumProgressUnits = 7;
int progressUnitsCompleted = 0;
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java
index 940c5d0f76..4ccc8d76c5 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java
@@ -47,7 +47,7 @@ class StringsTextExtractor extends FileTextExtractor {
EXTRACT_UTF16, ///< extract UTF16 text, true/false
EXTRACT_UTF8, ///< extract UTF8 text, true/false
};
-
+
private final List