diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties index e3853e4d59..562d4366b1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties @@ -1,6 +1,9 @@ +CTL_KeywordSearchListAction=List +CTL_KeywordSearchListTopComponent=List CTL_KeywordSearchTabsTopComponentAction=Keyword Search CTL_KeywordSearchTabsTopComponentTopComponent=Keyword Search -HINT_KeywordSearchTabsTopComponentTopComponent=This is a Keyword Search window +HINT_KeywordSearchListTopComponent=Keyword Search List +HINT_KeywordSearchTabsTopComponentTopComponent=Keyword Search window OpenIDE-Module-Name=KeywordSearch IndexProgressPanel.statusText.text=Status text IndexProgressPanel.cancelButton.text=Cancel @@ -17,5 +20,17 @@ KeywordSearchSimpleTopComponent.filesIndexedValLabel.text=- KeywordSearchSimpleTopComponent.filesIndexedNameLabel.text=Files indexed: KeywordSearchSimpleTopComponent.queryLabel.text=Query: KeywordSearchSimpleTopComponent.searchButton.text=Search -KeywordSearchSimpleTopComponent.regexQRadioButton.text=RegEx -KeywordSearchSimpleTopComponent.luceneQRadioButton.text=Lucene +KeywordSearchListTopComponent.searchButton.text=Search +KeywordSearchListTopComponent.filesIndexedNameLabel.text=Files indexed: +KeywordSearchListTopComponent.filesIndexedValLabel.text=- +KeywordSearchListTopComponent.titleLabel.text=Search for or load a saved list of keywords +KeywordSearchListTopComponent.listLabel.text=Current list of keywords: +KeywordSearchListTopComponent.addWordButton.text=Add +KeywordSearchListTopComponent.loadListButton.text=Load +KeywordSearchListTopComponent.addWordField.text= +KeywordSearchListTopComponent.saveListButton.text=Save +KeywordSearchListTopComponent.chLiteralWord.text=Literal +KeywordSearchListTopComponent.addWordLabel.text=Add a new word: +KeywordSearchListTopComponent.deleteWordButton.text=Delete +KeywordSearchListTopComponent.deleteAllWordsButton.text=Delete All +KeywordSearchSimpleTopComponent.chRegex.text=RegEx diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java index c6aef55e82..c6728a4fa0 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java @@ -95,7 +95,7 @@ public class KeywordSearchDataExplorer implements DataExplorer { * @param solrQuery */ private void searchRegexQuery(String regexQuery) { - RegexQuery rq = new RegexQuery(regexQuery); + TermComponentQuery rq = new TermComponentQuery(regexQuery); if (rq.validate()) { rq.execute(); } else { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListTopComponent.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListTopComponent.form new file mode 100644 index 0000000000..385c224ce0 --- /dev/null +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListTopComponent.form @@ -0,0 +1,229 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListTopComponent.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListTopComponent.java new file mode 100644 index 0000000000..c8d6836fdd --- /dev/null +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListTopComponent.java @@ -0,0 +1,305 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sleuthkit.autopsy.keywordsearch; + +import java.awt.event.ActionListener; +import java.util.logging.Logger; +import org.openide.util.NbBundle; +import org.openide.windows.TopComponent; +import org.netbeans.api.settings.ConvertAsProperties; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; + +/** + * Top component which displays something. + */ +@ConvertAsProperties(dtd = "-//org.sleuthkit.autopsy.keywordsearch//KeywordSearchList//EN", +autostore = false) +@TopComponent.Description(preferredID = "KeywordSearchListTopComponent", +//iconBase="SET/PATH/TO/ICON/HERE", +persistenceType = TopComponent.PERSISTENCE_NEVER) +@TopComponent.Registration(mode = "output", openAtStartup = false) +@ActionID(category = "Window", id = "org.sleuthkit.autopsy.keywordsearch.KeywordSearchListTopComponent") +@ActionReference(path = "Menu/Window" /*, position = 333 */) +@TopComponent.OpenActionRegistration(displayName = "#CTL_KeywordSearchListAction", +preferredID = "KeywordSearchListTopComponent") +public final class KeywordSearchListTopComponent extends TopComponent implements KeywordSearchTopComponentInterface { + + private Logger logger = Logger.getLogger(KeywordSearchListTopComponent.class.getName()); + + public KeywordSearchListTopComponent() { + initComponents(); + customizeComponents(); + setName(NbBundle.getMessage(KeywordSearchListTopComponent.class, "CTL_KeywordSearchListTopComponent")); + setToolTipText(NbBundle.getMessage(KeywordSearchListTopComponent.class, "HINT_KeywordSearchListTopComponent")); + + } + + private void customizeComponents() { + chLiteralWord.setToolTipText("Literal word (auto-escape special regex characters)"); + addWordButton.setToolTipText(("Add a new word to the keyword search list")); + addWordField.setToolTipText("Enter a new word or regex to search"); + + loadListButton.setToolTipText("Load a new keyword list from file"); + saveListButton.setToolTipText("Save the current keyword list to a file"); + searchButton.setToolTipText("Execute the keyword list search using the current list"); + deleteWordButton.setToolTipText("Delete selected word(s) from the list"); + deleteAllWordsButton.setToolTipText("Delete all words from the list (clear it)"); + + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + searchButton = new javax.swing.JButton(); + filesIndexedNameLabel = new javax.swing.JLabel(); + filesIndexedValLabel = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + jList1 = new javax.swing.JList(); + titleLabel = new javax.swing.JLabel(); + listLabel = new javax.swing.JLabel(); + addWordField = new javax.swing.JTextField(); + addWordLabel = new javax.swing.JLabel(); + addWordButton = new javax.swing.JButton(); + loadListButton = new javax.swing.JButton(); + deleteWordButton = new javax.swing.JButton(); + deleteAllWordsButton = new javax.swing.JButton(); + saveListButton = new javax.swing.JButton(); + chLiteralWord = new javax.swing.JCheckBox(); + + org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.searchButton.text")); // NOI18N + searchButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + searchButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(filesIndexedNameLabel, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.filesIndexedNameLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(filesIndexedValLabel, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.filesIndexedValLabel.text")); // NOI18N + + jScrollPane1.setViewportView(jList1); + + org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.titleLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(listLabel, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.listLabel.text")); // NOI18N + + addWordField.setText(org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.addWordField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(addWordLabel, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.addWordLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(addWordButton, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.addWordButton.text")); // NOI18N + addWordButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addWordButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(loadListButton, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.loadListButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(deleteWordButton, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.deleteWordButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(deleteAllWordsButton, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.deleteAllWordsButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(saveListButton, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.saveListButton.text")); // NOI18N + saveListButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + saveListButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(chLiteralWord, org.openide.util.NbBundle.getMessage(KeywordSearchListTopComponent.class, "KeywordSearchListTopComponent.chLiteralWord.text")); // NOI18N + chLiteralWord.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chLiteralWordActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(filesIndexedNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filesIndexedValLabel)) + .addComponent(searchButton) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(titleLabel) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(loadListButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(saveListButton)) + .addComponent(chLiteralWord) + .addComponent(addWordField, javax.swing.GroupLayout.PREFERRED_SIZE, 152, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(addWordButton))) + .addGap(66, 66, 66)) + .addComponent(listLabel) + .addComponent(addWordLabel) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(deleteWordButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deleteAllWordsButton)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 217, javax.swing.GroupLayout.PREFERRED_SIZE)))) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(titleLabel) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(loadListButton) + .addComponent(saveListButton)) + .addGap(19, 19, 19) + .addComponent(addWordLabel) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(addWordButton) + .addComponent(addWordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(27, 27, 27)) + .addGroup(layout.createSequentialGroup() + .addComponent(chLiteralWord) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED))) + .addGap(12, 12, 12) + .addComponent(listLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(deleteWordButton) + .addComponent(deleteAllWordsButton)) + .addGap(30, 30, 30) + .addComponent(searchButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(filesIndexedNameLabel) + .addComponent(filesIndexedValLabel)) + .addGap(42, 42, 42)) + ); + }// //GEN-END:initComponents + + private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_searchButtonActionPerformed + + private void addWordButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addWordButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_addWordButtonActionPerformed + + private void saveListButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveListButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_saveListButtonActionPerformed + + private void chLiteralWordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chLiteralWordActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chLiteralWordActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton addWordButton; + private javax.swing.JTextField addWordField; + private javax.swing.JLabel addWordLabel; + private javax.swing.JCheckBox chLiteralWord; + private javax.swing.JButton deleteAllWordsButton; + private javax.swing.JButton deleteWordButton; + private javax.swing.JLabel filesIndexedNameLabel; + private javax.swing.JLabel filesIndexedValLabel; + private javax.swing.JList jList1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JLabel listLabel; + private javax.swing.JButton loadListButton; + private javax.swing.JButton saveListButton; + private javax.swing.JButton searchButton; + private javax.swing.JLabel titleLabel; + // End of variables declaration//GEN-END:variables + @Override + public void componentOpened() { + // TODO add custom code on component opening + } + + @Override + public void componentClosed() { + // TODO add custom code on component closing + } + + void writeProperties(java.util.Properties p) { + // better to version settings since initial version as advocated at + // http://wiki.apidesign.org/wiki/PropertyFiles + p.setProperty("version", "1.0"); + // TODO store your settings + } + + void readProperties(java.util.Properties p) { + String version = p.getProperty("version"); + // TODO read your settings according to their version + } + + @Override + public boolean isMultiwordQuery() { + return true; + } + + @Override + public void addSearchButtonListener(ActionListener l) { + searchButton.addActionListener(l); + } + + @Override + public String getQueryText() { + return null; + } + + @Override + public boolean isLuceneQuerySelected() { + return false; + } + + @Override + public boolean isRegexQuerySelected() { + return true; + } + + @Override + public void setFilesIndexed(int filesIndexed) { + filesIndexedValLabel.setText(Integer.toString(filesIndexed)); + if (filesIndexed == 0) { + searchButton.setEnabled(false); + } else { + searchButton.setEnabled(true); + } + } + + +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java index 17f11fbac2..7839c7706f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQuery.java @@ -18,6 +18,9 @@ */ package org.sleuthkit.autopsy.keywordsearch; +import java.util.List; +import org.sleuthkit.datamodel.FsContent; + public interface KeywordSearchQuery { /** @@ -26,8 +29,23 @@ public interface KeywordSearchQuery { */ public boolean validate(); + /** - * execute the query + * execute query and return results without publishing them + * @return + */ + public List performQuery(); + + + /** + * execute the query and publish results */ public void execute(); + + /** + * escape the query string and use the escaped string in the query + */ + public void escape(); + + } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java similarity index 50% rename from KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java rename to KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index 6798340925..cd7f725644 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -21,31 +21,20 @@ package org.sleuthkit.autopsy.keywordsearch; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; -import javax.swing.SwingWorker; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.response.TermsResponse; -import org.apache.solr.client.solrj.response.TermsResponse.Term; -import org.netbeans.api.progress.ProgressHandle; -import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; -import org.openide.windows.TopComponent; -import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode.FsContentPropertyType; import org.sleuthkit.autopsy.datamodel.KeyValueNode; @@ -54,182 +43,97 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.FsContent; -public class RegexQuery implements KeywordSearchQuery { +/** + * + * factory responsible for assembling nodes in the right way + * and performing lazy queries as needed + */ +public class KeywordSearchResultFactory extends ChildFactory { + + public enum Presentation { + + COLLAPSE, STRUCTURE + }; - private static final int TERMS_UNLIMITED = -1; - //corresponds to field in Solr schema, analyzed with white-space tokenizer only - private static final String TERMS_SEARCH_FIELD = "content_ws"; - private static final String TERMS_HANDLER = "/terms"; - private static final int TERMS_TIMEOUT = 90 * 1000; //in ms - private String regexQuery; - private static Logger logger = Logger.getLogger(RegexQuery.class.getName()); - //common properties (superset of all Node properties) to be displayed as columns //these are merged with FsContentPropertyType defined properties - private static enum CommonPropertyTypes { + public static enum CommonPropertyTypes { + QUERY { + @Override public String toString() { return "Query"; } - }, + }, MATCH { + @Override public String toString() { return "Match"; } - }, - /* MATCH_RANK { - @Override - public String toString() { - return "Match Rank"; - } - },*/ + }, } - + private Presentation presentation; + private Collection queries; + private Collection things; + private static final Logger logger = Logger.getLogger(KeywordSearchResultFactory.class.getName()); - public RegexQuery(String query) { - this.regexQuery = query; + KeywordSearchResultFactory(Collection queries, Collection things, Presentation presentation) { + this.queries = queries; + this.things = things; + this.presentation = presentation; } - @Override - public boolean validate() { - boolean valid = true; - try { - Pattern.compile(regexQuery); - } catch (PatternSyntaxException ex1) { - valid = false; - } catch (IllegalArgumentException ex2) { - valid = false; - } - return valid; + KeywordSearchResultFactory(String query, Collection things, Presentation presentation) { + queries = new ArrayList(); + queries.add(query); + this.presentation = presentation; + this.things = things; } - @Override - public void execute() { - - final SolrQuery q = new SolrQuery(); - q.setQueryType(TERMS_HANDLER); - q.setTerms(true); - q.setTermsLimit(TERMS_UNLIMITED); - q.setTermsRegexFlag("case_insensitive"); - //q.setTermsLimit(200); - //q.setTermsRegexFlag(regexFlag); - //q.setTermsRaw(true); - q.setTermsRegex(regexQuery); - q.addTermsField(TERMS_SEARCH_FIELD); - q.setTimeAllowed(TERMS_TIMEOUT); - - logger.log(Level.INFO, "Executing TermsComponent query: " + q.toString()); - - final SwingWorker worker = new RegexQueryWorker(q); - worker.execute(); - } - - /** - * map Terms to generic Nodes with key/value pairs properties - * @param terms - */ - private void publishNodes(List terms) { - - Collection things = new ArrayList(); - - Iterator it = terms.iterator(); - int termID = 0; - //long totalMatches = 0; - while (it.hasNext()) { - Term term = it.next(); - Map kvs = new LinkedHashMap(); - long matches = term.getFrequency(); - final String match = term.getTerm(); - setCommonProperty(kvs, CommonPropertyTypes.MATCH, match); - //setCommonProperty(kvs, CommonPropertyTypes.MATCH_RANK, Long.toString(matches)); - things.add(new KeyValueThing(match, kvs, ++termID)); - //totalMatches += matches; - } - - Node rootNode = null; - if (things.size() > 0) { - Children childThingNodes = - Children.create(new RegexResultQueryChildFactory(regexQuery, things), true); - - rootNode = new AbstractNode(childThingNodes); - } else { - rootNode = Node.EMPTY; - } - - final String pathText = "RegEx query"; - // String pathText = "RegEx query: " + regexQuery - //+ " Files with exact matches: " + Long.toString(totalMatches) + " (also listing approximate matches)"; - - TopComponent searchResultWin = DataResultTopComponent.createInstance("Keyword search", pathText, rootNode, things.size()); - searchResultWin.requestActive(); // make it the active top component - - } - /** * call this at least for the parent Node, to make sure all common * properties are displayed as columns (since we are doing lazy child Node load * we need to preinitialize properties when sending parent Node) * @param toSet property set map for a Node */ - private static void initCommonProperties(Map toSet) { - CommonPropertyTypes [] commonTypes = CommonPropertyTypes.values(); + public static void initCommonProperties(Map toSet) { + CommonPropertyTypes[] commonTypes = CommonPropertyTypes.values(); final int COMMON_PROPS_LEN = commonTypes.length; - for (int i = 0; i< COMMON_PROPS_LEN; ++i) { + for (int i = 0; i < COMMON_PROPS_LEN; ++i) { toSet.put(commonTypes[i].toString(), ""); } - - FsContentPropertyType [] fsTypes = FsContentPropertyType.values(); + + FsContentPropertyType[] fsTypes = FsContentPropertyType.values(); final int FS_PROPS_LEN = fsTypes.length; - for (int i = 0; i< FS_PROPS_LEN; ++i) { + for (int i = 0; i < FS_PROPS_LEN; ++i) { toSet.put(fsTypes[i].toString(), ""); } } - - private static void setCommonProperty(Map toSet, CommonPropertyTypes type, String value) { + + public static void setCommonProperty(Map toSet, CommonPropertyTypes type, String value) { final String typeStr = type.toString(); toSet.put(typeStr, value); } - - /** - * factory produces top level result nodes showing query used - */ - class RegexResultQueryChildFactory extends ChildFactory { - Collection queries; - Collection things; - - - RegexResultQueryChildFactory(Collectionqueries, Collection things) { - this.queries = queries; - this.things = things; - } - - RegexResultQueryChildFactory(String query, Collection things) { - queries = new ArrayList(); - queries.add(query); - this.things = things; + @Override + protected boolean createKeys(List toPopulate) { + int id = 0; + for (String query : queries) { + Map map = new LinkedHashMap(); + initCommonProperties(map); + setCommonProperty(map, CommonPropertyTypes.QUERY, query); + toPopulate.add(new KeyValueThing(query, map, ++id)); } - @Override - protected boolean createKeys(List toPopulate) { - int id = 0; - for (String query : queries) { - Map map = new LinkedHashMap(); - initCommonProperties(map); - setCommonProperty(map, CommonPropertyTypes.QUERY, query); - toPopulate.add(new KeyValueThing(query, map, ++id)); - } - - return true; - } + return true; + } - @Override - protected Node createNodeForKey(KeyValueThing thing) { - return new KeyValueNode(thing, Children.create(new RegexResultChildFactory(things), true)); - } + @Override + protected Node createNodeForKey(KeyValueThing thing) { + return new KeyValueNode(thing, Children.create(new RegexResultChildFactory(things), true)); } /** @@ -273,7 +177,7 @@ public class RegexQuery implements KeywordSearchQuery { //use Lucene query to get files with regular expression match result final String keywordQuery = thing.getName(); LuceneQuery filesQuery = new LuceneQuery(keywordQuery); - List matches = filesQuery.doQuery(); + List matches = filesQuery.performQuery(); //get unique match result files Set uniqueMatches = new TreeSet(new Comparator() { @@ -287,15 +191,14 @@ public class RegexQuery implements KeywordSearchQuery { uniqueMatches.addAll(matches); int resID = 0; - for (FsContent f : uniqueMatches) { + for (FsContent f : uniqueMatches) { Map resMap = new LinkedHashMap(); - AbstractFsContentNode.fillPropertyMap(resMap, (File)f); + AbstractFsContentNode.fillPropertyMap(resMap, (File) f); toPopulate.add(new KeyValueThingContent(f.getName(), resMap, ++resID, f, keywordQuery)); } return true; } - @Override protected Node createNodeForKey(KeyValueThing thing) { @@ -309,7 +212,8 @@ public class RegexQuery implements KeywordSearchQuery { //TODO option in GUI to include approximate matches (faster) boolean matchFound = false; if (contentStr != null) {//if not null, some error getting from Solr, handle it by not filtering out - Pattern p = Pattern.compile(regexQuery, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + final String keywordQuery = thing.getName(); + Pattern p = Pattern.compile(keywordQuery, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); Matcher m = p.matcher(contentStr); matchFound = m.find(); } @@ -362,64 +266,4 @@ public class RegexQuery implements KeywordSearchQuery { } } } - - class RegexQueryWorker extends SwingWorker, Void> { - - private SolrQuery q; - private ProgressHandle progress; - - RegexQueryWorker(SolrQuery q) { - this.q = q; - } - - @Override - protected List doInBackground() throws Exception { - progress = ProgressHandleFactory.createHandle("RegEx query task"); - progress.start(); - progress.progress("Running RegEx query."); - - Server.Core solrCore = KeywordSearch.getServer().getCore(); - - - List terms = null; - try { - TermsResponse tr = solrCore.queryTerms(q); - terms = tr.getTerms(TERMS_SEARCH_FIELD); - } catch (SolrServerException ex) { - logger.log(Level.SEVERE, "Error executing the regex terms query: " + regexQuery, ex); - return null; //no need to create result view, just display error dialog - } - - progress.progress("RegEx query completed."); - - //debug query - //StringBuilder sb = new StringBuilder(); - //for (Term t : terms) { - // sb.append(t.getTerm() + " : " + t.getFrequency() + "\n"); - //} - //logger.log(Level.INFO, "TermsComponent query result: " + sb.toString()); - //end debug query - - return terms; - } - - @Override - protected void done() { - if (!this.isCancelled()) { - try { - List terms = get(); - publishNodes(terms); - } catch (InterruptedException e) { - logger.log(Level.INFO, "Exception while executing regex query,", e); - - } catch (ExecutionException e) { - logger.log(Level.INFO, "Exception while executing regex query,", e); - } finally { - progress.finish(); - } - } - - - } - } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.form index be5325951e..57a7e9b7cd 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.form @@ -25,10 +25,8 @@ - - - - + + @@ -48,8 +46,7 @@ - - + @@ -119,20 +116,15 @@ - - - - - - - - - + - + + + + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.java index 364c1e22bc..ef2cab2559 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchSimpleTopComponent.java @@ -30,8 +30,7 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key public KeywordSearchSimpleTopComponent() { initComponents(); setName("Simple"); - buttonGroup1.add(luceneQRadioButton); - buttonGroup1.add(regexQRadioButton); + buttonGroup1.add(chRegex); searchButton.setEnabled(false); putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE); @@ -53,8 +52,7 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key queryLabel = new javax.swing.JLabel(); filesIndexedNameLabel = new javax.swing.JLabel(); filesIndexedValLabel = new javax.swing.JLabel(); - luceneQRadioButton = new javax.swing.JRadioButton(); - regexQRadioButton = new javax.swing.JRadioButton(); + chRegex = new javax.swing.JCheckBox(); queryTextArea.setColumns(20); queryTextArea.setRows(5); @@ -68,10 +66,12 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key filesIndexedValLabel.setText(org.openide.util.NbBundle.getMessage(KeywordSearchSimpleTopComponent.class, "KeywordSearchSimpleTopComponent.filesIndexedValLabel.text")); // NOI18N - luceneQRadioButton.setSelected(true); - luceneQRadioButton.setText(org.openide.util.NbBundle.getMessage(KeywordSearchSimpleTopComponent.class, "KeywordSearchSimpleTopComponent.luceneQRadioButton.text")); // NOI18N - - regexQRadioButton.setText(org.openide.util.NbBundle.getMessage(KeywordSearchSimpleTopComponent.class, "KeywordSearchSimpleTopComponent.regexQRadioButton.text")); // NOI18N + chRegex.setText(org.openide.util.NbBundle.getMessage(KeywordSearchSimpleTopComponent.class, "KeywordSearchSimpleTopComponent.chRegex.text")); // NOI18N + chRegex.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chRegexActionPerformed(evt); + } + }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -82,10 +82,8 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(queryLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(luceneQRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(regexQRadioButton)) + .addGap(62, 62, 62) + .addComponent(chRegex)) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 599, Short.MAX_VALUE) .addComponent(searchButton) .addGroup(layout.createSequentialGroup() @@ -100,8 +98,7 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(queryLabel) - .addComponent(luceneQRadioButton) - .addComponent(regexQRadioButton)) + .addComponent(chRegex)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) @@ -116,15 +113,19 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key filesIndexedNameLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(KeywordSearchSimpleTopComponent.class, "KeywordSearchTopComponent.filesIndexedNameLabel.AccessibleContext.accessibleName")); // NOI18N filesIndexedValLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(KeywordSearchSimpleTopComponent.class, "KeywordSearchTopComponent.filesIndexedValLabel.AccessibleContext.accessibleName")); // NOI18N }// //GEN-END:initComponents + + private void chRegexActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chRegexActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chRegexActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JCheckBox chRegex; private javax.swing.JLabel filesIndexedNameLabel; private javax.swing.JLabel filesIndexedValLabel; private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JRadioButton luceneQRadioButton; private javax.swing.JLabel queryLabel; private javax.swing.JTextArea queryTextArea; - private javax.swing.JRadioButton regexQRadioButton; private javax.swing.JButton searchButton; // End of variables declaration//GEN-END:variables @@ -135,6 +136,11 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key queryTextArea.setText(""); } + @Override + public boolean isMultiwordQuery() { + return false; + } + @Override public void addSearchButtonListener(ActionListener l) { searchButton.addActionListener(l); @@ -147,12 +153,12 @@ public class KeywordSearchSimpleTopComponent extends TopComponent implements Key @Override public boolean isLuceneQuerySelected() { - return luceneQRadioButton.isSelected(); + return !chRegex.isSelected(); } @Override public boolean isRegexQuerySelected() { - return regexQRadioButton.isSelected(); + return chRegex.isSelected(); } /** diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.form index 4b1b7a5f54..747df8cbdb 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.form @@ -1,6 +1,6 @@ -
+ diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.java index 0033deb149..c79492d7fc 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTabsTopComponent.java @@ -89,6 +89,7 @@ public final class KeywordSearchTabsTopComponent extends TopComponent implements private void initTabs() { tabs.addTab("Simple", null, new KeywordSearchSimpleTopComponent(), "Single keyword or regex search"); + tabs.addTab("List", null, new KeywordSearchListTopComponent(), "Search for or load a saved list of keywords."); } @Override @@ -97,7 +98,6 @@ public final class KeywordSearchTabsTopComponent extends TopComponent implements @Override public void componentClosed() { - } void writeProperties(java.util.Properties p) { @@ -112,6 +112,15 @@ public final class KeywordSearchTabsTopComponent extends TopComponent implements // read your settings according to their version } + @Override + public boolean isMultiwordQuery() { + KeywordSearchTopComponentInterface selected = (KeywordSearchTopComponentInterface) tabs.getSelectedComponent(); + if (selected == null) { + return false; + } + return selected.isMultiwordQuery(); + } + @Override public void addSearchButtonListener(ActionListener l) { final int tabsCount = tabs.getTabCount(); @@ -159,6 +168,7 @@ public final class KeywordSearchTabsTopComponent extends TopComponent implements } class KeywordSearchServerListener implements PropertyChangeListener { + @Override public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTopComponentInterface.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTopComponentInterface.java index 6f9c946624..f15ceafc27 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTopComponentInterface.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTopComponentInterface.java @@ -27,6 +27,7 @@ import java.awt.event.ActionListener; */ public interface KeywordSearchTopComponentInterface { + boolean isMultiwordQuery(); boolean isLuceneQuerySelected(); boolean isRegexQuerySelected(); String getQueryText(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java index b3af7aa7cc..c79d88d168 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java @@ -43,11 +43,22 @@ public class LuceneQuery implements KeywordSearchQuery { private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName()); - private String query; + private String query; //original unescaped query + private String queryEscaped; + private boolean isEscaped; public LuceneQuery(String query) { this.query = query; + this.queryEscaped = query; + isEscaped = false; } + + @Override + public void escape() { + queryEscaped = KeywordSearchUtil.escapeLuceneQuery(query); + isEscaped = true; + } + /** * Just perform the query and return result without updating the GUI @@ -55,7 +66,7 @@ public class LuceneQuery implements KeywordSearchQuery { * @param query * @return matches List */ - public List doQuery() throws RuntimeException { + public List performQuery() throws RuntimeException { List matches = new ArrayList(); boolean allMatchesFetched = false; @@ -65,7 +76,6 @@ public class LuceneQuery implements KeywordSearchQuery { SolrQuery q = new SolrQuery(); - final String queryEscaped = KeywordSearchUtil.escapeLuceneQuery(query); q.setQuery(queryEscaped); q.setRows(ROWS_PER_FETCH); q.setFields("id"); @@ -107,7 +117,8 @@ public class LuceneQuery implements KeywordSearchQuery { @Override public void execute() { - List matches = doQuery(); + escape(); + List matches = performQuery(); String pathText = "Lucene query: " + query; Node rootNode = new KeywordSearchNode(matches, query); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java new file mode 100644 index 0000000000..2e157eef40 --- /dev/null +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -0,0 +1,230 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.keywordsearch; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import javax.swing.SwingWorker; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.TermsResponse; +import org.apache.solr.client.solrj.response.TermsResponse.Term; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.windows.TopComponent; +import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; +import org.sleuthkit.autopsy.datamodel.KeyValueThing; +import org.sleuthkit.datamodel.FsContent; + +public class TermComponentQuery implements KeywordSearchQuery { + + private static final int TERMS_UNLIMITED = -1; + //corresponds to field in Solr schema, analyzed with white-space tokenizer only + private static final String TERMS_SEARCH_FIELD = "content_ws"; + private static final String TERMS_HANDLER = "/terms"; + private static final int TERMS_TIMEOUT = 90 * 1000; //in ms + + private static Logger logger = Logger.getLogger(TermComponentQuery.class.getName()); + + + + private String termsQuery; + private String queryEscaped; + private boolean isEscaped; + + + public TermComponentQuery(String query) { + this.termsQuery = query; + this.queryEscaped = query; + isEscaped = false; + } + + @Override + public void escape() { + isEscaped = true; + //will use prefix terms component query instead of regex + //to treat the query as a word + } + + + + + @Override + public boolean validate() { + boolean valid = true; + try { + Pattern.compile(termsQuery); + } catch (PatternSyntaxException ex1) { + valid = false; + } catch (IllegalArgumentException ex2) { + valid = false; + } + return valid; + } + + + protected void executeQuery() { + final SolrQuery q = new SolrQuery(); + q.setQueryType(TERMS_HANDLER); + q.setTerms(true); + q.setTermsLimit(TERMS_UNLIMITED); + q.setTermsRegexFlag("case_insensitive"); + //q.setTermsLimit(200); + //q.setTermsRegexFlag(regexFlag); + //q.setTermsRaw(true); + q.setTermsRegex(termsQuery); + q.addTermsField(TERMS_SEARCH_FIELD); + q.setTimeAllowed(TERMS_TIMEOUT); + + logger.log(Level.INFO, "Executing TermsComponent query: " + q.toString()); + + final SwingWorker worker = new TermsQueryWorker(q); + worker.execute(); + } + + @Override + public List performQuery() { + return null; + } + + + + @Override + public void execute() { + executeQuery(); + + } + + /** + * map Terms to generic Nodes with key/value pairs properties + * @param terms + */ + private void publishNodes(List terms) { + + Collection things = new ArrayList(); + + Iterator it = terms.iterator(); + int termID = 0; + //long totalMatches = 0; + while (it.hasNext()) { + Term term = it.next(); + Map kvs = new LinkedHashMap(); + //long matches = term.getFrequency(); + final String match = term.getTerm(); + KeywordSearchResultFactory.setCommonProperty(kvs, KeywordSearchResultFactory.CommonPropertyTypes.MATCH, match); + //setCommonProperty(kvs, CommonPropertyTypes.MATCH_RANK, Long.toString(matches)); + things.add(new KeyValueThing(match, kvs, ++termID)); + //totalMatches += matches; + } + + Node rootNode = null; + if (things.size() > 0) { + Children childThingNodes = + Children.create(new KeywordSearchResultFactory(termsQuery, things, KeywordSearchResultFactory.Presentation.COLLAPSE), true); + + rootNode = new AbstractNode(childThingNodes); + } else { + rootNode = Node.EMPTY; + } + + final String pathText = "RegEx query"; + // String pathText = "RegEx query: " + termsQuery + //+ " Files with exact matches: " + Long.toString(totalMatches) + " (also listing approximate matches)"; + + TopComponent searchResultWin = DataResultTopComponent.createInstance("Keyword search", pathText, rootNode, things.size()); + searchResultWin.requestActive(); // make it the active top component + + } + + + + + + class TermsQueryWorker extends SwingWorker, Void> { + + private SolrQuery q; + private ProgressHandle progress; + + TermsQueryWorker(SolrQuery q) { + this.q = q; + } + + @Override + protected List doInBackground() throws Exception { + progress = ProgressHandleFactory.createHandle("Terms query task"); + progress.start(); + progress.progress("Running Terms query."); + + Server.Core solrCore = KeywordSearch.getServer().getCore(); + + + List terms = null; + try { + TermsResponse tr = solrCore.queryTerms(q); + terms = tr.getTerms(TERMS_SEARCH_FIELD); + } catch (SolrServerException ex) { + logger.log(Level.SEVERE, "Error executing the regex terms query: " + termsQuery, ex); + return null; //no need to create result view, just display error dialog + } + + progress.progress("Terms query completed."); + + //debug query + //StringBuilder sb = new StringBuilder(); + //for (Term t : terms) { + // sb.append(t.getTerm() + " : " + t.getFrequency() + "\n"); + //} + //logger.log(Level.INFO, "TermsComponent query result: " + sb.toString()); + //end debug query + + return terms; + } + + @Override + protected void done() { + if (!this.isCancelled()) { + try { + List terms = get(); + publishNodes(terms); + } catch (InterruptedException e) { + logger.log(Level.INFO, "Exception while executing regex query,", e); + + } catch (ExecutionException e) { + logger.log(Level.INFO, "Exception while executing regex query,", e); + } finally { + progress.finish(); + } + } + + + } + } +}