diff --git a/CoreComponentInterfaces/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java b/CoreComponentInterfaces/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java index bb91673725..3cd4fbcf98 100644 --- a/CoreComponentInterfaces/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java +++ b/CoreComponentInterfaces/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java @@ -39,8 +39,12 @@ public interface DataContentViewer { public String getTitle(); /** - * Get new DataContentViewer instance. + * Get new DataContentViewer instance. (This method is weird. We use the + * instance returned by the Lookup as a factory for the instances that + * are actually used.) */ + // TODO: extract the factory method out into a seperate interface that + // is used for the Lookup. public DataContentViewer getInstance(); /** diff --git a/KeywordSearch/build.xml b/KeywordSearch/build.xml index 19c410a8ee..e99df8ddb2 100644 --- a/KeywordSearch/build.xml +++ b/KeywordSearch/build.xml @@ -32,6 +32,8 @@ + + diff --git a/KeywordSearch/ivy.xml b/KeywordSearch/ivy.xml index 563bf9b310..3d0a84af01 100644 --- a/KeywordSearch/ivy.xml +++ b/KeywordSearch/ivy.xml @@ -2,7 +2,10 @@ + + + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java index 46691a755e..744ba3e949 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java @@ -23,15 +23,15 @@ import java.awt.event.ItemListener; import java.util.Collections; import java.util.List; +/** + * Panel displays HTML content sent to ExtractedContentViewer, and provides + * a combo-box to select between multiple sources. + */ class ExtractedContentPanel extends javax.swing.JPanel { - /** Creates new form ExtractedContentPanel */ ExtractedContentPanel() { initComponents(); - -// DefaultCaret caret = (DefaultCaret)extractedTextPane.getCaret(); -// caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); - + extractedTextPane.setContentType("text/html"); sourceComboBox.addItemListener(new ItemListener() { @@ -90,6 +90,12 @@ class ExtractedContentPanel extends javax.swing.JPanel { private javax.swing.JComboBox sourceComboBox; // End of variables declaration//GEN-END:variables + + /** + * Set the available sources (selects the first source in the list by + * default) + * @param sources + */ void setSources(List sources) { sourceComboBox.removeAllItems(); setPanelText(null); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index b398a081de..541a5c761b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -33,7 +33,11 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.datamodel.ContentNode; import org.apache.commons.lang.StringEscapeUtils; - +/** + * Displays marked-up (HTML) content for a Node. The sources are all the + * MarkupSource items in the selected Node's lookup, plus the content that + * Solr extracted (if there is any). + */ @ServiceProvider(service = DataContentViewer.class) public class ExtractedContentViewer implements DataContentViewer { @@ -46,36 +50,39 @@ public class ExtractedContentViewer implements DataContentViewer { @Override public void setNode(final ContentNode selectedNode) { - // to clear it + // to clear the viewer if (selectedNode == null) { resetComponent(); return; } - // custom markup from the node (if available) and default markup - // fetched from solr + // sources are custom markup from the node (if available) and default + // markup is fetched from solr List sources = new ArrayList(); sources.addAll(((Node) selectedNode).getLookup().lookupAll(MarkupSource.class)); - sources.add(new MarkupSource() { - @Override - public String getMarkup() { - try { - String content = StringEscapeUtils.escapeHtml(getSolrContent(selectedNode)); - return "
" + content.trim() + "
"; - } catch (SolrServerException ex) { - logger.log(Level.WARNING, "Couldn't get extracted content.", ex); - return ""; + if (solrHasContent(selectedNode)) { + sources.add(new MarkupSource() { + + @Override + public String getMarkup() { + try { + String content = StringEscapeUtils.escapeHtml(getSolrContent(selectedNode)); + return "
" + content.trim() + "
"; + } catch (SolrServerException ex) { + logger.log(Level.WARNING, "Couldn't get extracted content.", ex); + return ""; + } } - } - @Override - public String toString() { - return "Extracted Content"; - } - }); + @Override + public String toString() { + return "Extracted Content"; + } + }); + } // first source will be the default displayed setPanel(sources); @@ -112,10 +119,26 @@ public class ExtractedContentViewer implements DataContentViewer { Collection sources = ((Node) node).getLookup().lookupAll(MarkupSource.class); - if (!sources.isEmpty()) { - return true; - } + return !sources.isEmpty() || solrHasContent(node); + } + /** + * Set the MarkupSources for the panel to display (safe to call even if the + * panel hasn't been created yet) + * @param sources + */ + private void setPanel(List sources) { + if (panel != null) { + panel.setSources(sources); + } + } + + /** + * Check if Solr has extracted content for a given node + * @param node + * @return true if Solr has content, else false + */ + private boolean solrHasContent(ContentNode node) { Server.Core solrCore = KeywordSearch.getServer().getCore(); SolrQuery q = new SolrQuery(); q.setQuery("*:*"); @@ -130,12 +153,13 @@ public class ExtractedContentViewer implements DataContentViewer { } } - private void setPanel(List sources) { - if (panel != null) { - panel.setSources(sources); - } - } - + /** + * Get extracted content for a node from Solr + * @param cNode a node that has extracted content in Solr (check with + * solrHasContent(ContentNode)) + * @return the extracted content + * @throws SolrServerException if something goes wrong + */ private String getSolrContent(ContentNode cNode) throws SolrServerException { Server.Core solrCore = KeywordSearch.getServer().getCore(); SolrQuery q = new SolrQuery(); @@ -143,8 +167,6 @@ public class ExtractedContentViewer implements DataContentViewer { q.addFilterQuery("id:" + cNode.getContent().getId()); q.setFields("content"); - //TODO: for debugging, remove - String queryURL = q.toString(); String content = (String) solrCore.query(q).getResults().get(0).getFieldValue("content"); return content; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GetIngestableFilesContentVisitor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GetIngestableFilesContentVisitor.java index 4af2ee35b9..d9adf1fe25 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GetIngestableFilesContentVisitor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GetIngestableFilesContentVisitor.java @@ -40,9 +40,19 @@ import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.VolumeSystem; + +/** + * Visitor for getting all the files to try to index from any Content object. + * Currently gets all the files with a file extensions that match a list of + * document types that Tika/Solr-Cell supports. + */ class GetIngestableFilesContentVisitor implements ContentVisitor> { - private static Logger logger = Logger.getLogger(GetIngestableFilesContentVisitor.class.getName()); + private static final Logger logger = Logger.getLogger(GetIngestableFilesContentVisitor.class.getName()); + + // TODO: use a more robust method than checking file extension to determine + // whether to try a file + // supported extensions list from http://www.lucidimagination.com/devzone/technical-articles/content-extraction-tika private static final String[] supportedExtensions = {"tar", "jar", "zip", "bzip2", "gz", "tgz", "doc", "xls", "ppt", "rtf", "pdf", "html", "xhtml", "txt", @@ -52,6 +62,8 @@ class GetIngestableFilesContentVisitor implements ContentVisitor visit(FileSystem fs) { + // Files in the database have a filesystem field, so it's quick to + // get all the matching files for an entire filesystem with a query + SleuthkitCase sc = Case.getCurrentCase().getSleuthkitCase(); String query = "SELECT * FROM tsk_files WHERE fs_obj_id = " + fs.getId() @@ -119,11 +140,17 @@ class GetIngestableFilesContentVisitor implements ContentVisitor getAllFromChildren(Content c) { + /** + * Aggregate all the matches from visiting the children Content objects of the + * one passed + * @param parent + * @return + */ + private Collection getAllFromChildren(Content parent) { Collection all = new ArrayList(); try { - for (Content child : c.getChildren()) { + for (Content child : parent.getChildren()) { all.addAll(child.accept(this)); } } catch (TskException ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedMatchesSource.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedMatchesSource.java index faed12ab6a..cbec781053 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedMatchesSource.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedMatchesSource.java @@ -26,13 +26,17 @@ import org.apache.solr.client.solrj.response.QueryResponse; import org.sleuthkit.autopsy.keywordsearch.Server.Core; import org.sleuthkit.datamodel.Content; +/** + * Gets extracted content from Solr with the parts that match the query + * highlighted + */ class HighlightedMatchesSource implements MarkupSource { private static final Logger logger = Logger.getLogger(HighlightedMatchesSource.class.getName()); Content content; String solrQuery; Core solrCore; - + HighlightedMatchesSource(Content content, String solrQuery) { this(content, solrQuery, KeywordSearch.getServer().getCore()); } @@ -42,8 +46,6 @@ class HighlightedMatchesSource implements MarkupSource { this.solrQuery = solrQuery; this.solrCore = solrCore; } - - @Override public String getMarkup() { @@ -55,11 +57,6 @@ class HighlightedMatchesSource implements MarkupSource { q.setHighlightSimplePre(""); q.setHighlightSimplePost(""); q.setHighlightFragsize(0); // don't fragment the highlight - - - //TODO: remove (only for debugging) - String queryString = q.toString(); - try { QueryResponse response = solrCore.query(q); @@ -67,6 +64,7 @@ class HighlightedMatchesSource implements MarkupSource { if (contentHighlights == null) { return "No matches in content."; } else { + // extracted content (minus highlight tags) is HTML-escaped return "
" + contentHighlights.get(0).trim() + "
"; } } catch (SolrServerException ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexContentFilesAction.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexContentFilesAction.java index 2c78fbf791..ab9645f61a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexContentFilesAction.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexContentFilesAction.java @@ -39,6 +39,10 @@ import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.FsContent; +/** + * Action adds all supported files from the given Content object and its + * children to the Solr index. + */ public class IndexContentFilesAction extends AbstractAction { private static final Logger logger = Logger.getLogger(IndexContentFilesAction.class.getName()); @@ -47,6 +51,11 @@ public class IndexContentFilesAction extends AbstractAction { private String name; private Server.Core solrCore; + /** + * New action + * @param c source Content object to get files from + * @param name name to refer to the source by when displaying progress + */ public IndexContentFilesAction(Content c, String name) { this(c, name, KeywordSearch.getServer().getCore()); } @@ -60,9 +69,8 @@ public class IndexContentFilesAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { - - - // create the popUp window for it + + // create the popUp window to display progress String title = "Indexing files in " + name; final JFrame frame = new JFrame(title); @@ -81,10 +89,11 @@ public class IndexContentFilesAction extends AbstractAction { setProgress(0); + // track number complete or with errors int fileCount = files.size(); int finishedFiles = 0; int problemFiles = 0; - + for (FsContent f : files) { if (isCancelled()) { return problemFiles; @@ -124,6 +133,8 @@ public class IndexContentFilesAction extends AbstractAction { } finally { popUpWindow.setVisible(false); popUpWindow.dispose(); + + // notify user if there were problem files if (problemFiles > 0) { displayProblemFilesDialog(problemFiles); } @@ -133,6 +144,7 @@ public class IndexContentFilesAction extends AbstractAction { @Override protected void process(List messages) { + // display the latest message if (!messages.isEmpty()) { panel.setStatusText(messages.get(messages.size() - 1)); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexProgressPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexProgressPanel.java index 73a236bcd2..6150d17d3d 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexProgressPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexProgressPanel.java @@ -20,6 +20,9 @@ package org.sleuthkit.autopsy.keywordsearch; import java.awt.event.ActionListener; +/** + * Displays progress as files are indexed + */ class IndexProgressPanel extends javax.swing.JPanel { /** Creates new form IndexProgressPanel */ diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index b7502ebb38..97da36d064 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -35,7 +35,7 @@ import org.apache.solr.common.util.ContentStream; import org.sleuthkit.datamodel.FsContent; /** - * Handles ingesting files to a Solr server, given the url string for it + * Handles indexing files on a Solr core. */ class Ingester { @@ -62,9 +62,8 @@ class Ingester { * index. commit() should be called once you're done ingesting files. * * @param f File to ingest - * @throws org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException if - * there was an error processing the given file, but the Solr server is - * probably fine. + * @throws IngesterException if there was an error processing a specific + * file, but the Solr server is probably fine. */ void ingest(FsContent f) throws IngesterException { Map fields = new HashMap(); @@ -108,7 +107,11 @@ class Ingester { uncommitedIngests = true; } - + + /** + * Tells Solr to commit (necessary before ingested files will appear in + * searches) + */ void commit() { uncommitedIngests = false; try { @@ -121,12 +124,20 @@ class Ingester { } } + /** + * Helper to set document fields + * @param up request with document + * @param fields map of field-names->values + */ private static void setFields(ContentStreamUpdateRequest up, Map fields) { for (Entry field : fields.entrySet()) { up.setParam("literal." + field.getKey(), field.getValue()); } } + /** + * ContentStream to read() the data from a FsContent object + */ private static class FscContentStream implements ContentStream { FsContent f; @@ -166,6 +177,10 @@ class Ingester { } } + /** + * Indicates that there was an error with the specific ingest operation, + * but it's still okay to continue ingesting files. + */ static class IngesterException extends Exception { IngesterException(String message, Throwable ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java index 53b8bdaaf1..6675b05df2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java @@ -23,6 +23,10 @@ import java.util.logging.Logger; import org.openide.modules.ModuleInstall; import org.sleuthkit.autopsy.casemodule.Case; +/** + * Starts up the Solr server when the module is loaded, and stops it when the + * application is closed. + */ public class Installer extends ModuleInstall { @Override @@ -36,31 +40,26 @@ public class Installer extends ModuleInstall { if (server.isRunning()) { - logger.log(Level.WARNING, "Already a Solr server on out port, maybe leftoveer from a previous run. Trying to shut it down..."); + logger.log(Level.WARNING, "Already a Solr server on out port, maybe leftover from a previous run. Trying to shut it down..."); + // Send the stop message in case there's a solr server lingering from // a previous run of Autopsy that didn't exit cleanly server.stop(); - try { - Thread.sleep(10000); // let it die - } catch (InterruptedException ex) { - throw new RuntimeException(ex); - } - if (server.isRunning()) { throw new IllegalStateException("There's already a server running on our port that can't be shutdown."); } else { logger.log(Level.INFO, "Old Solr server shutdown successfully."); } } - + server.start(); - try { - Thread.sleep(1000); // give it a sec - //TODO: idle loop while waiting for it to start - } catch (InterruptedException ex) { - throw new RuntimeException(ex); - } + try { + Thread.sleep(1000); // give it a sec + //TODO: idle loop while waiting for it to start + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java index 41746e1515..23dab824dc 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java @@ -22,6 +22,9 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import org.sleuthkit.autopsy.casemodule.Case; +/** + * Static class to track singletons for KeywordSearch module + */ class KeywordSearch { private static final String BASE_URL = "http://localhost:8983/solr/"; @@ -36,6 +39,9 @@ class KeywordSearch { throw new AssertionError(); } + /** + * Listener to swap cores when the case changes + */ static class CaseChangeListener implements PropertyChangeListener { CaseChangeListener() { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java index b5bf4f7dd9..11d9bd735f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java @@ -39,6 +39,9 @@ import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.SleuthkitCase; +/** + * Provides a data explorer to perform Solr searches with + */ @ServiceProvider(service = DataExplorer.class, position = 300) public class KeywordSearchDataExplorer implements DataExplorer { @@ -61,10 +64,14 @@ public class KeywordSearchDataExplorer implements DataExplorer { if (theInstance == null) { theInstance = this; } else { - throw new RuntimeException("NOOO!!! Mulitple instances of KeywordSearchTopComponent! BAD!"); + throw new RuntimeException("Tried to instantiate mulitple instances of KeywordSearchTopComponent."); } } + /** + * Executes a query and populates a DataResult tab with the results + * @param solrQuery + */ private void search(String solrQuery) { List matches = new ArrayList(); @@ -72,8 +79,6 @@ public class KeywordSearchDataExplorer implements DataExplorer { boolean allMatchesFetched = false; final int ROWS_PER_FETCH = 10000; - - Server.Core solrCore = KeywordSearch.getServer().getCore(); SolrQuery q = new SolrQuery(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchNode.java index 26dd6bf33e..cb0561cc03 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchNode.java @@ -33,6 +33,9 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.TskException; +/** + * Root Node for keyword search results + */ class KeywordSearchNode extends AbstractNode implements ContentNode { private String solrQuery; @@ -40,13 +43,14 @@ class KeywordSearchNode extends AbstractNode implements ContentNode { KeywordSearchNode(List keys, final String solrQuery) { super(new RootContentChildren(keys) { - // Use filter node to add a MarkupSource for the search results - // to the lookup + @Override protected Node[] createNodes(Content key) { Node[] originalNodes = super.createNodes(key); Node[] filterNodes = new Node[originalNodes.length]; + // Use filter node to add a MarkupSource for the search results + // to the lookup int i = 0; for (Node original : originalNodes) { MarkupSource markup = new HighlightedMatchesSource(key, solrQuery); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MarkupSource.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MarkupSource.java index b4bc0fac4e..21f16032e0 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MarkupSource.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MarkupSource.java @@ -18,6 +18,10 @@ */ package org.sleuthkit.autopsy.keywordsearch; +/** + * Interface to provide HTML markup (to be displayed in ExtractedContentViewer) + * in a Node's lookup + */ public interface MarkupSource { /** diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ReadContentInputStream.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ReadContentInputStream.java index bc18306de3..9964cae612 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ReadContentInputStream.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ReadContentInputStream.java @@ -23,6 +23,9 @@ import java.io.InputStream; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskException; +/** + * InputStream to read bytes from a Content object's data + */ class ReadContentInputStream extends InputStream { private long position; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index f66552cceb..c10aa55b44 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -37,6 +37,9 @@ import org.openide.modules.InstalledFileLocator; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; +/** + * Handles for keeping track of a Solr server and its cores + */ class Server { private static final Logger logger = Logger.getLogger(Server.class.getName()); @@ -48,6 +51,10 @@ class Server { private String instanceDir; private File solrFolder; + /** + * New instance for the server at the given URL + * @param url should be something like "http://localhost:8983/solr/" + */ Server(String url) { try { this.solr = new CommonsHttpSolrServer(url); @@ -61,7 +68,7 @@ class Server { /** - * Helper class to handle output from Solr + * Helper threads to handle stderr/stdout from Solr process */ private static class InputStreamPrinter extends Thread { @@ -88,8 +95,9 @@ class Server { /** - * Tries to start a Solr instance. Returns immediately (probably before - * the server is ready) and doesn't check whether it was successful. + * Tries to start a Solr instance in a separate process. Returns immediately + * (probably before the server is ready) and doesn't check whether it was + * successful. */ void start() { logger.log(Level.INFO, "Starting Solr server from: " + solrFolder.getAbsolutePath()); @@ -180,13 +188,23 @@ class Server { /**** end single-case specific methods ****/ - + /** + * Open a core for the given case + * @param c + * @return + */ Core openCore(Case c) { String sep = File.separator; String dataDir = c.getCaseDirectory() + sep + "keywordsearch" + sep + "data"; return this.openCore(DEFAULT_CORE_NAME, new File(dataDir)); } + /** + * Open a new core + * @param coreName name to refer to the core by in Solr + * @param dataDir directory to load/store the core data from/to + * @return new core + */ Core openCore(String coreName, File dataDir) { try { if (!dataDir.exists()) { @@ -211,8 +229,10 @@ class Server { class Core { + // handle to the core in Solr private String name; - // server to access a core needs to be built from a URL with the + + // the server to access a core needs to be built from a URL with the // core in it, and is only good for core-specific operations private SolrServer solrCore; @@ -233,7 +253,7 @@ class Server { return solrCore.query(sq); } - void close () { + void close() { try { CoreAdminRequest.unloadCore(this.name, solr); } catch (SolrServerException ex) {