> responseHighlightID = responseHighlight.get(Long.toString(contentID));
@@ -140,7 +133,12 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
highlightedContent = insertAnchors(highlightedContent);
return "" + highlightedContent + "
";
}
- } catch (SolrServerException ex) {
+ }
+ catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Couldn't query markup.", ex);
+ return "";
+ }
+ catch (SolrServerException ex) {
logger.log(Level.INFO, "Could not query markup. ", ex);
return "";
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
index 3b5dfd5367..5e9b659028 100755
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
@@ -24,8 +24,13 @@ import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
@@ -41,11 +46,12 @@ import org.sleuthkit.datamodel.ReadContentInputStream;
class Ingester {
private static final Logger logger = Logger.getLogger(Ingester.class.getName());
- private SolrServer solrCore;
private boolean uncommitedIngests = false;
+ private final ExecutorService upRequestExecutor = Executors.newSingleThreadExecutor();
+ static final int UP_REQUEST_TIMEOUT_SECS = 30 * 60; //30 min TODO use variable time depending on file size
+ private final Server solrServer = KeywordSearch.getServer();
- Ingester(SolrServer solrCore) {
- this.solrCore = solrCore;
+ Ingester() {
}
@Override
@@ -108,42 +114,79 @@ class Ingester {
* content, but the Solr server is probably fine.
*/
private void ingest(ContentStream cs, Map fields) throws IngesterException {
- ContentStreamUpdateRequest up = new ContentStreamUpdateRequest("/update/extract");
+ final ContentStreamUpdateRequest up = new ContentStreamUpdateRequest("/update/extract");
up.addContentStream(cs);
setFields(up, fields);
up.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
//logger.log(Level.INFO, "Ingesting " + fields.get("file_name"));
+
up.setParam("commit", "false");
- try {
- solrCore.request(up);
- // should't get any checked exceptions,
- } catch (IOException ex) {
- // It's possible that we will have IO errors
- throw new IngesterException("Problem reading file.", ex);
- } catch (IllegalStateException ex) {
- // problems with content
- throw new IngesterException("Problem reading file.", ex);
- } catch (SolrServerException ex) {
- // If there's a problem talking to Solr, something is fundamentally
- // wrong with ingest
- throw new IngesterException("Problem with Solr", ex);
- } catch (SolrException ex) {
- // Tika problems result in an unchecked SolrException
- ErrorCode ec = ErrorCode.getErrorCode(ex.code());
- // When Tika has problems with a document, it throws a server error
- // but it's okay to continue with other documents
- if (ec.equals(ErrorCode.SERVER_ERROR)) {
- throw new IngesterException("Problem posting file contents to Solr. SolrException error code: " + ec, ex);
- } else {
- // shouldn't get any other error codes
- throw ex;
- }
+ final Future f = upRequestExecutor.submit(new UpRequestTask(up));
+ try {
+ //TODO use timeout proportional to content size
+ f.get(UP_REQUEST_TIMEOUT_SECS, TimeUnit.SECONDS);
+ } catch (TimeoutException te) {
+ logger.log(Level.WARNING, "Solr timeout encountered, trying to restart Solr");
+ //TODO restart solr might be needed to recover from some error conditions
+ hardSolrRestart();
+ throw new IngesterException("Solr index request time out for id: " + fields.get("id") + ", name: " + fields.get("file_name"));
+ } catch (Exception e) {
+ throw new IngesterException("Problem posting content to Solr, id: " + fields.get("id") + ", name: " + fields.get("file_name"), e);
+ }
+ uncommitedIngests = true;
+ }
+
+
+ //attempt to restart Solr and recover from its internal error
+ private void hardSolrRestart() {
+ solrServer.closeCore();
+ solrServer.stop();
+
+ solrServer.start();
+ solrServer.openCore();
+
+
+ }
+
+ private class UpRequestTask implements Runnable {
+
+ ContentStreamUpdateRequest up;
+
+ UpRequestTask(ContentStreamUpdateRequest up) {
+ this.up = up;
}
- uncommitedIngests = true;
+ @Override
+ public void run() {
+ try {
+ solrServer.request(up);
+ } catch (NoOpenCoreException ex) {
+ throw new RuntimeException("No Solr core available, cannot index the content", ex);
+ } catch (IllegalStateException ex) {
+ // problems with content
+ throw new RuntimeException("Problem reading file.", ex);
+ } catch (SolrServerException ex) {
+ // If there's a problem talking to Solr, something is fundamentally
+ // wrong with ingest
+ throw new RuntimeException("Problem with Solr", ex);
+ } catch (SolrException ex) {
+ // Tika problems result in an unchecked SolrException
+ ErrorCode ec = ErrorCode.getErrorCode(ex.code());
+
+ // When Tika has problems with a document, it throws a server error
+ // but it's okay to continue with other documents
+ if (ec.equals(ErrorCode.SERVER_ERROR)) {
+ throw new RuntimeException("Problem posting file contents to Solr. SolrException error code: " + ec, ex);
+ } else {
+ // shouldn't get any other error codes
+ throw ex;
+ }
+ }
+
+ }
}
/**
@@ -152,13 +195,12 @@ class Ingester {
*/
void commit() {
try {
- solrCore.commit();
+ solrServer.commit();
uncommitedIngests = false;
- // if commit doesn't work, something's broken
- } catch (IOException ex) {
- throw new RuntimeException(ex);
+ } catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Error commiting index", ex);
} catch (SolrServerException ex) {
- throw new RuntimeException(ex);
+ logger.log(Level.WARNING, "Error commiting index", ex);
}
}
@@ -170,6 +212,8 @@ class Ingester {
private static void setFields(ContentStreamUpdateRequest up, Map fields) {
for (Entry field : fields.entrySet()) {
up.setParam("literal." + field.getKey(), field.getValue());
+
+
}
}
@@ -224,5 +268,9 @@ class Ingester {
IngesterException(String message, Throwable ex) {
super(message, ex);
}
+
+ IngesterException(String message) {
+ super(message);
+ }
}
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java
index 3d6c90ad0b..9ab4ee9203 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java
@@ -27,6 +27,7 @@ import org.openide.nodes.Node;
import org.openide.nodes.Node.Property;
import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet;
+import org.openide.util.Exceptions;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
@@ -52,7 +53,14 @@ class KeywordSearchFilterNode extends FilterNode {
String getSnippet() {
final Content content = this.getOriginal().getLookup().lookup(Content.class);
- final String snippet = LuceneQuery.querySnippet(solrQuery, content.getId(), false, true);
+ String snippet;
+ try {
+ snippet = LuceneQuery.querySnippet(solrQuery, content.getId(), false, true);
+ } catch (NoOpenCoreException ex) {
+ //logger.log(Level.WARNING, "Could not perform the snippet query. ", ex);
+ return "";
+ }
+
return snippet;
}
@@ -101,7 +109,7 @@ class KeywordSearchFilterNode extends FilterNode {
return propertySets;
}
-
+
/**
* Right click action for the nodes that we want to pass to the directory
* table and the output view.
@@ -113,18 +121,17 @@ class KeywordSearchFilterNode extends FilterNode {
public Action[] getActions(boolean popup) {
List actions = new ArrayList();
-
+
Content content = this.getOriginal().getLookup().lookup(Content.class);
actions.addAll(content.accept(new GetPopupActionsContentVisitor()));
-
+
//actions.add(new IndexContentFilesAction(nodeContent, "Index"));
return actions.toArray(new Action[actions.size()]);
}
-
-
+
private class GetPopupActionsContentVisitor extends ContentVisitor.Default> {
-
+
@Override
public List visit(File f) {
List actions = new ArrayList();
@@ -133,10 +140,10 @@ class KeywordSearchFilterNode extends FilterNode {
actions.add(new ExtractAction("Extract File", getOriginal()));
return actions;
}
+
@Override
protected List defaultVisit(Content c) {
return new ArrayList();
}
-
}
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java
index 50febd1667..b8adc68806 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java
@@ -88,8 +88,7 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent
public enum IngestStatus {
- INGESTED, EXTRACTED_INGESTED, SKIPPED,
- };
+ INGESTED, EXTRACTED_INGESTED, SKIPPED,};
private Map ingestStatus;
private Map> reportedHits; //already reported hits
@@ -219,16 +218,10 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent
this.managerProxy = managerProxy;
- Server.Core solrCore = null;
- try {
- solrCore = KeywordSearch.getServer().getCore();
- } catch (SolrServerException ex) {
- logger.log(Level.WARNING, "Could not get Solr core", ex);
- managerProxy.postMessage(IngestMessage.createErrorMessage(++messageID, instance, "Error initializing.", "Keyword indexing and search cannot proceed. Try restarting the application."));
- return;
- }
+ Server solrServer = KeywordSearch.getServer();
- ingester = solrCore.getIngester();
+
+ ingester = solrServer.getIngester();
ingestStatus = new HashMap();
@@ -348,7 +341,7 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent
private void indexChangeNotify() {
//signal a potential change in number of indexed files
try {
- final int numIndexedFiles = KeywordSearch.getServer().getCore().queryNumIndexedFiles();
+ final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
SwingUtilities.invokeLater(new Runnable() {
@Override
@@ -356,6 +349,8 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent
KeywordSearch.changeSupport.firePropertyChange(KeywordSearch.NUM_FILES_CHANGE_EVT, null, new Integer(numIndexedFiles));
}
});
+ } catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files: ", ex);
} catch (SolrServerException se) {
logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files: ", se);
}
@@ -591,6 +586,12 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent
try {
queryResult = del.performQuery();
+ } catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), ex);
+ //no reason to continue with next query if recovery failed
+ //or wait for recovery to kick in and run again later
+ //likely case has closed and threads are being interrupted
+ break;
} catch (Exception e) {
logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), e);
continue;
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchPanel.java
index 260111b25e..157dbc6fa9 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchPanel.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchPanel.java
@@ -46,7 +46,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
*
* @author dfickling
*/
-public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
+public class KeywordSearchPanel extends AbstractKeywordSearchPerformer {
private static final Logger logger = Logger.getLogger(KeywordSearchPanel.class.getName());
private KeywordPropertyChangeListener listener;
@@ -60,14 +60,15 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
}
private void customizeComponents() {
-
+
listener = new KeywordPropertyChangeListener();
-
+
KeywordSearch.getServer().addServerActionListener(listener);
-
+
Case.addPropertyChangeListener(listener);
-
+
searchBox.addFocusListener(new FocusListener() {
+
@Override
public void focusGained(FocusEvent e) {
if (searchBox.getText().equals("Search...")) {
@@ -76,6 +77,7 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
entered = true;
}
}
+
@Override
public void focusLost(FocusEvent e) {
if (searchBox.getText().equals("")) {
@@ -90,10 +92,9 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
public void actionPerformed(ActionEvent e) {
listsMenu.setVisible(false);
}
-
});
// Adding border of six to account for menu border
- listsMenu.setSize(listsPanel.getPreferredSize().width+6, listsPanel.getPreferredSize().height+6);
+ listsMenu.setSize(listsPanel.getPreferredSize().width + 6, listsPanel.getPreferredSize().height + 6);
listsMenu.add(listsPanel);
listsMenu.addPopupMenuListener(new PopupMenuListener() {
@@ -111,9 +112,8 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
public void popupMenuCanceled(PopupMenuEvent e) {
listsButton.setSelected(false);
}
-
});
-
+
searchBox.setComponentPopupMenu(rightClickMenu);
ActionListener actList = new ActionListener() {
@@ -140,9 +140,9 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
copyMenuItem.addActionListener(actList);
pasteMenuItem.addActionListener(actList);
selectAllMenuItem.addActionListener(actList);
-
+
}
-
+
private void resetSearchBox() {
searchBox.setEditable(true);
searchBox.setText("Search...");
@@ -293,8 +293,9 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
}// //GEN-END:initComponents
private void searchBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchBoxActionPerformed
- if(!entered)
+ if (!entered) {
return;
+ }
getRootPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
search();
@@ -326,7 +327,6 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
private void settingsLabelMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_settingsLabelMouseExited
settingsLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/dropdown-icon.png")));
}//GEN-LAST:event_settingsLabelMouseExited
-
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JMenuItem copyMenuItem;
private javax.swing.JMenuItem cutMenuItem;
@@ -362,7 +362,7 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
public List getQueryList() {
throw new UnsupportedOperationException("No list for single-keyword search");
}
-
+
private class KeywordPropertyChangeListener implements PropertyChangeListener {
@Override
@@ -370,7 +370,7 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
String changed = evt.getPropertyName();
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
-
+
if (changed.equals(Case.CASE_CURRENT_CASE)) {
if (newValue == null) {
setFields(false);
@@ -382,10 +382,14 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
switch (state) {
case STARTED:
try {
- final int numIndexedFiles = KeywordSearch.getServer().getCore().queryNumIndexedFiles();
+ final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
KeywordSearch.changeSupport.firePropertyChange(KeywordSearch.NUM_FILES_CHANGE_EVT, null, new Integer(numIndexedFiles));
//setFilesIndexed(numIndexedFiles);
- } catch (SolrServerException se) {
+ }
+ catch (NoOpenCoreException ex) {
+ logger.log(Level.SEVERE, "Error executing Solr query, " + ex);
+ }
+ catch (SolrServerException se) {
logger.log(Level.SEVERE, "Error executing Solr query, " + se.getMessage());
}
break;
@@ -395,8 +399,8 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
}
}
}
-
- private void setFields(boolean enabled){
+
+ private void setFields(boolean enabled) {
searchBox.setEnabled(enabled);
regExCheckboxMenuItem.setEnabled(enabled);
settingsLabel.setEnabled(enabled);
@@ -405,25 +409,25 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer{
active = enabled;
}
}
-
- private void maybeShowSettingsPopup (MouseEvent evt) {
- if(!active) {
+
+ private void maybeShowSettingsPopup(MouseEvent evt) {
+ if (!active) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
return;
}
-
+
settingsMenu.show(searchBoxPanel, 0, searchBoxPanel.getHeight());
}
-
- private void maybeShowListsPopup (MouseEvent evt) {
- if(!active) {
+
+ private void maybeShowListsPopup(MouseEvent evt) {
+ if (!active) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
return;
}
- listsMenu.show(listsButton, listsButton.getWidth()-listsMenu.getWidth(), listsButton.getHeight()-1);
+ listsMenu.show(listsButton, listsButton.getWidth() - listsMenu.getWidth(), listsButton.getHeight() - 1);
}
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java
index 00d7a37fdf..c991cd7dec 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java
@@ -36,10 +36,10 @@ public interface KeywordSearchQuery {
/**
* execute query and return results without publishing them
* return results for all matching terms
- *
+ * @throws NoOpenCoreException if query failed due to server error, this could be a notification to stop processing
* @return
*/
- public Map> performQuery();
+ public Map> performQuery() throws NoOpenCoreException;
@@ -84,8 +84,9 @@ public interface KeywordSearchQuery {
* @param newFsHit fscontent for which to write results for this hit
* @param listName listname
* @return collection of results (with cached bb artifacts/attributes) created and written
+ * @throws NoOpenCoreException if could not write to bb because required query failed due to server error, this could be a notification to stop processing
*/
- public KeywordWriteResult writeToBlackBoard(String termHit, FsContent newFsHit, String listName);
+ public KeywordWriteResult writeToBlackBoard(String termHit, FsContent newFsHit, String listName) throws NoOpenCoreException;
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java
index b03eacc290..5b24b40ec8 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java
@@ -225,7 +225,13 @@ public class KeywordSearchResultFactory extends ChildFactory {
}
//execute the query and get fscontents matching
- Map> tcqRes = tcq.performQuery();
+ Map> tcqRes;
+ try {
+ tcqRes = tcq.performQuery();
+ } catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Could not perform the query. ", ex);
+ return false;
+ }
final Set fsContents = new HashSet();
for (String key : tcqRes.keySet()) {
fsContents.addAll(tcqRes.get(key));
@@ -247,8 +253,14 @@ public class KeywordSearchResultFactory extends ChildFactory {
AbstractFsContentNode.fillPropertyMap(resMap, f);
setCommonProperty(resMap, CommonPropertyTypes.MATCH, f.getName());
if (literal_query) {
- final String snippet = LuceneQuery.querySnippet(tcq.getEscapedQueryString(), f.getId(), false, true);
- setCommonProperty(resMap, CommonPropertyTypes.CONTEXT, snippet);
+ try {
+ String snippet;
+ snippet = LuceneQuery.querySnippet(tcq.getEscapedQueryString(), f.getId(), false, true);
+ setCommonProperty(resMap, CommonPropertyTypes.CONTEXT, snippet);
+ } catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Could not perform the query. ", ex);
+ return false;
+ }
}
final String highlightQueryEscaped = getHighlightQuery(tcq, literal_query, tcqRes, f);
toPopulate.add(new KeyValueQueryContent(f.getName(), resMap, ++resID, f, highlightQueryEscaped, tcq));
@@ -367,7 +379,14 @@ public class KeywordSearchResultFactory extends ChildFactory {
LuceneQuery filesQuery = new LuceneQuery(keywordQuery);
filesQuery.escape();
- Map> matchesRes = filesQuery.performQuery();
+ Map> matchesRes;
+ try {
+ matchesRes = filesQuery.performQuery();
+ } catch (NoOpenCoreException ex) {
+ logger.log(Level.WARNING, "Could not perform the query. ", ex);
+ return false;
+ }
+
Set matches = new HashSet();
for (String key : matchesRes.keySet()) {
matches.addAll(matchesRes.get(key));
@@ -435,7 +454,7 @@ public class KeywordSearchResultFactory extends ChildFactory {
* worker for writing results to bb, with progress bar, cancellation,
* and central registry of workers to be stopped when case is closed
*/
- static class ResultWriter extends SwingWorker