mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Fixed bug that caused null pointer exception when displaying keyword hits. Other minor refactoring
This commit is contained in:
parent
9b546fcbec
commit
ac6c6da3e3
@ -109,7 +109,7 @@ KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly
|
|||||||
KeywordSearchIngestModule.init.tryStopSolrMsg={0}<br />Please try stopping old java Solr process (if it exists) and restart the application.
|
KeywordSearchIngestModule.init.tryStopSolrMsg={0}<br />Please try stopping old java Solr process (if it exists) and restart the application.
|
||||||
KeywordSearchIngestModule.init.noKwInLstMsg=No keywords in keyword list.
|
KeywordSearchIngestModule.init.noKwInLstMsg=No keywords in keyword list.
|
||||||
KeywordSearchIngestModule.init.onlyIdxKwSkipMsg=Only indexing will be done and and keyword search will be skipped (you can still add keyword lists using the Keyword Lists - Add to Ingest).
|
KeywordSearchIngestModule.init.onlyIdxKwSkipMsg=Only indexing will be done and and keyword search will be skipped (you can still add keyword lists using the Keyword Lists - Add to Ingest).
|
||||||
KeywordSearchIngestModule.doInBackGround.displayName=Keyword Search
|
KeywordSearchIngestModule.doInBackGround.displayName=Periodic Keyword Search
|
||||||
KeywordSearchIngestModule.doInBackGround.finalizeMsg= - Finalizing
|
KeywordSearchIngestModule.doInBackGround.finalizeMsg= - Finalizing
|
||||||
KeywordSearchIngestModule.doInBackGround.pendingMsg= (Pending)
|
KeywordSearchIngestModule.doInBackGround.pendingMsg= (Pending)
|
||||||
SearchRunner.doInBackGround.cancelMsg= (Cancelling...)
|
SearchRunner.doInBackGround.cancelMsg= (Cancelling...)
|
||||||
|
@ -146,12 +146,12 @@
|
|||||||
<Component class="javax.swing.JComboBox" name="sourceComboBox">
|
<Component class="javax.swing.JComboBox" name="sourceComboBox">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||||
<Connection code="new javax.swing.DefaultComboBoxModel<MarkupSource>()" type="code"/>
|
<Connection code="new javax.swing.DefaultComboBoxModel<org.sleuthkit.autopsy.keywordsearch.TextMarkup>()" type="code"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox<>()"/>
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox<>()"/>
|
||||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<MarkupSource>"/>
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<org.sleuthkit.autopsy.keywordsearch.TextMarkup>"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="hitLabel">
|
<Component class="javax.swing.JLabel" name="hitLabel">
|
||||||
|
@ -130,14 +130,14 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
@Override
|
@Override
|
||||||
public void itemStateChanged(ItemEvent e) {
|
public void itemStateChanged(ItemEvent e) {
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
MarkupSource source = (MarkupSource) e.getItem();
|
TextMarkup source = (TextMarkup) e.getItem();
|
||||||
setMarkup(source);
|
setMarkup(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
setSources(new ArrayList<MarkupSource>());
|
setSources(new ArrayList<TextMarkup>());
|
||||||
|
|
||||||
extractedTextPane.setComponentPopupMenu(rightClickMenu);
|
extractedTextPane.setComponentPopupMenu(rightClickMenu);
|
||||||
ActionListener actList = new ActionListener() {
|
ActionListener actList = new ActionListener() {
|
||||||
@ -205,7 +205,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
extractedTextPane.setPreferredSize(new java.awt.Dimension(700, 400));
|
extractedTextPane.setPreferredSize(new java.awt.Dimension(700, 400));
|
||||||
jScrollPane1.setViewportView(extractedTextPane);
|
jScrollPane1.setViewportView(extractedTextPane);
|
||||||
|
|
||||||
sourceComboBox.setModel(new javax.swing.DefaultComboBoxModel<MarkupSource>());
|
sourceComboBox.setModel(new javax.swing.DefaultComboBoxModel<TextMarkup>());
|
||||||
|
|
||||||
hitLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.text")); // NOI18N
|
hitLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.text")); // NOI18N
|
||||||
hitLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.toolTipText")); // NOI18N
|
hitLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.toolTipText")); // NOI18N
|
||||||
@ -358,11 +358,11 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
private javax.swing.JLabel pagesLabel;
|
private javax.swing.JLabel pagesLabel;
|
||||||
private javax.swing.JPopupMenu rightClickMenu;
|
private javax.swing.JPopupMenu rightClickMenu;
|
||||||
private javax.swing.JMenuItem selectAllMenuItem;
|
private javax.swing.JMenuItem selectAllMenuItem;
|
||||||
private javax.swing.JComboBox<MarkupSource> sourceComboBox;
|
private javax.swing.JComboBox<TextMarkup> sourceComboBox;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
void refreshCurrentMarkup() {
|
void refreshCurrentMarkup() {
|
||||||
MarkupSource ms = (MarkupSource) sourceComboBox.getSelectedItem();
|
TextMarkup ms = (TextMarkup) sourceComboBox.getSelectedItem();
|
||||||
setMarkup(ms);
|
setMarkup(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,11 +372,11 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param sources
|
* @param sources
|
||||||
*/
|
*/
|
||||||
void setSources(List<MarkupSource> sources) {
|
void setSources(List<TextMarkup> sources) {
|
||||||
sourceComboBox.removeAllItems();
|
sourceComboBox.removeAllItems();
|
||||||
setPanelText(null, false);
|
setPanelText(null, false);
|
||||||
|
|
||||||
for (MarkupSource ms : sources) {
|
for (TextMarkup ms : sources) {
|
||||||
sourceComboBox.addItem(ms);
|
sourceComboBox.addItem(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,8 +391,8 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @return currently available sources on the panel
|
* @return currently available sources on the panel
|
||||||
*/
|
*/
|
||||||
public List<MarkupSource> getSources() {
|
public List<TextMarkup> getSources() {
|
||||||
ArrayList<MarkupSource> sources = new ArrayList<>();
|
ArrayList<TextMarkup> sources = new ArrayList<>();
|
||||||
for (int i = 0; i < sourceComboBox.getItemCount(); ++i) {
|
for (int i = 0; i < sourceComboBox.getItemCount(); ++i) {
|
||||||
sources.add(sourceComboBox.getItemAt(i));
|
sources.add(sourceComboBox.getItemAt(i));
|
||||||
}
|
}
|
||||||
@ -403,8 +403,8 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
* Get the source selected in the combo box
|
* Get the source selected in the combo box
|
||||||
* @return currently selected Source
|
* @return currently selected Source
|
||||||
*/
|
*/
|
||||||
public MarkupSource getSelectedSource() {
|
public TextMarkup getSelectedSource() {
|
||||||
return (MarkupSource) sourceComboBox.getSelectedItem();
|
return (TextMarkup) sourceComboBox.getSelectedItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPanelText(String text, boolean detectDirection) {
|
private void setPanelText(String text, boolean detectDirection) {
|
||||||
@ -565,7 +565,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param source the selected source
|
* @param source the selected source
|
||||||
*/
|
*/
|
||||||
void updateControls(MarkupSource source) {
|
void updateControls(TextMarkup source) {
|
||||||
updatePageControls(source);
|
updatePageControls(source);
|
||||||
updateSearchControls(source);
|
updateSearchControls(source);
|
||||||
}
|
}
|
||||||
@ -575,7 +575,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param source selected source
|
* @param source selected source
|
||||||
*/
|
*/
|
||||||
void updatePageControls(MarkupSource source) {
|
void updatePageControls(TextMarkup source) {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
enableNextPageControl(false);
|
enableNextPageControl(false);
|
||||||
enablePrevPageControl(false);
|
enablePrevPageControl(false);
|
||||||
@ -614,7 +614,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param source selected source
|
* @param source selected source
|
||||||
*/
|
*/
|
||||||
void updateSearchControls(MarkupSource source) {
|
void updateSearchControls(TextMarkup source) {
|
||||||
//setup search controls
|
//setup search controls
|
||||||
if (source != null && source.isSearchable()) {
|
if (source != null && source.isSearchable()) {
|
||||||
|
|
||||||
@ -646,7 +646,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param source
|
* @param source
|
||||||
*/
|
*/
|
||||||
private void scrollToCurrentHit(final MarkupSource source) {
|
private void scrollToCurrentHit(final TextMarkup source) {
|
||||||
if (source == null || !source.isSearchable()) {
|
if (source == null || !source.isSearchable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -666,7 +666,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
* Updates GUI in GUI thread and gets markup in
|
* Updates GUI in GUI thread and gets markup in
|
||||||
* background thread. To be invoked from GUI thread only.
|
* background thread. To be invoked from GUI thread only.
|
||||||
*/
|
*/
|
||||||
private void setMarkup(MarkupSource source) {
|
private void setMarkup(TextMarkup source) {
|
||||||
setPanelText(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.setMarkup.panelTxt"), false);
|
setPanelText(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.setMarkup.panelTxt"), false);
|
||||||
new SetMarkupWorker(source).execute();
|
new SetMarkupWorker(source).execute();
|
||||||
}
|
}
|
||||||
@ -678,11 +678,11 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*/
|
*/
|
||||||
private final class SetMarkupWorker extends SwingWorker<Object, Void> {
|
private final class SetMarkupWorker extends SwingWorker<Object, Void> {
|
||||||
|
|
||||||
private MarkupSource source;
|
private TextMarkup source;
|
||||||
private String markup;
|
private String markup;
|
||||||
private ProgressHandle progress;
|
private ProgressHandle progress;
|
||||||
|
|
||||||
SetMarkupWorker(MarkupSource source) {
|
SetMarkupWorker(TextMarkup source) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
|
private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
|
||||||
private ExtractedContentPanel panel;
|
private ExtractedContentPanel panel;
|
||||||
private volatile Node currentNode = null;
|
private volatile Node currentNode = null;
|
||||||
private MarkupSource currentSource = null;
|
private TextMarkup currentSource = null;
|
||||||
private final IsDirVisitor isDirVisitor = new IsDirVisitor();
|
private final IsDirVisitor isDirVisitor = new IsDirVisitor();
|
||||||
|
|
||||||
|
|
||||||
@ -80,10 +80,11 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
* for the text markedup by SOLR and another that just displayed
|
* for the text markedup by SOLR and another that just displayed
|
||||||
* raw text.
|
* raw text.
|
||||||
*/
|
*/
|
||||||
final List<MarkupSource> sources = new ArrayList<MarkupSource>();
|
final List<TextMarkup> sources = new ArrayList<TextMarkup>();
|
||||||
|
|
||||||
//add additional registered sources for this node
|
// See if the node has any sources attached to it and add them to our
|
||||||
sources.addAll(selectedNode.getLookup().lookupAll(MarkupSource.class));
|
// internal list
|
||||||
|
sources.addAll(selectedNode.getLookup().lookupAll(TextMarkup.class));
|
||||||
|
|
||||||
|
|
||||||
// if it doesn't have any SOLR content, then we won't add more sources
|
// if it doesn't have any SOLR content, then we won't add more sources
|
||||||
@ -98,9 +99,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make a new source for the raw content
|
// make a new source for the raw content
|
||||||
MarkupSource rawSource = new RawMarkupSource(content);
|
TextMarkup rawSource = new RawTextMarkup(content);
|
||||||
// @@@ NOTE: We used to do some level of caching between instances when this
|
|
||||||
// was an inner class. Consider doing so again and save rawSource at the class level
|
|
||||||
|
|
||||||
currentSource = rawSource;
|
currentSource = rawSource;
|
||||||
sources.add(rawSource);
|
sources.add(rawSource);
|
||||||
@ -118,7 +117,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scrollToCurrentHit() {
|
private void scrollToCurrentHit() {
|
||||||
final MarkupSource source = panel.getSelectedSource();
|
final TextMarkup source = panel.getSelectedSource();
|
||||||
if (source == null || !source.isSearchable()) {
|
if (source == null || !source.isSearchable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -157,7 +156,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetComponent() {
|
public void resetComponent() {
|
||||||
setPanel(new ArrayList<MarkupSource>());
|
setPanel(new ArrayList<TextMarkup>());
|
||||||
panel.resetDisplay();
|
panel.resetDisplay();
|
||||||
currentNode = null;
|
currentNode = null;
|
||||||
currentSource = null;
|
currentSource = null;
|
||||||
@ -171,7 +170,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
// see if the node has a MarkupSource object in it
|
// see if the node has a MarkupSource object in it
|
||||||
// BC @@@ This seems to be added from the upper right search.
|
// BC @@@ This seems to be added from the upper right search.
|
||||||
Collection<? extends MarkupSource> sources = node.getLookup().lookupAll(MarkupSource.class);
|
Collection<? extends TextMarkup> sources = node.getLookup().lookupAll(TextMarkup.class);
|
||||||
if (sources.isEmpty() == false) {
|
if (sources.isEmpty() == false) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -204,7 +203,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
*
|
*
|
||||||
* @param sources
|
* @param sources
|
||||||
*/
|
*/
|
||||||
private void setPanel(List<MarkupSource> sources) {
|
private void setPanel(List<TextMarkup> sources) {
|
||||||
if (panel != null) {
|
if (panel != null) {
|
||||||
panel.setSources(sources);
|
panel.setSources(sources);
|
||||||
}
|
}
|
||||||
@ -266,7 +265,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
MarkupSource source = panel.getSelectedSource();
|
TextMarkup source = panel.getSelectedSource();
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
// reset
|
// reset
|
||||||
panel.updateControls(null);
|
panel.updateControls(null);
|
||||||
@ -306,7 +305,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
MarkupSource source = panel.getSelectedSource();
|
TextMarkup source = panel.getSelectedSource();
|
||||||
final boolean hasPreviousItem = source.hasPreviousItem();
|
final boolean hasPreviousItem = source.hasPreviousItem();
|
||||||
final boolean hasPreviousPage = source.hasPreviousPage();
|
final boolean hasPreviousPage = source.hasPreviousPage();
|
||||||
int indexVal = 0;
|
int indexVal = 0;
|
||||||
|
@ -37,15 +37,14 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordQueryFilter.FilterType;
|
|||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets extracted content from Solr with the parts that match the query
|
* Highlights hits for a given document. Knows about pages and such for the content viewer.
|
||||||
* highlighted
|
|
||||||
*/
|
*/
|
||||||
class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
class HighlightedTextMarkup implements TextMarkup, HighlightLookup {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(HighlightedMatchesSource.class.getName());
|
private static final Logger logger = Logger.getLogger(HighlightedTextMarkup.class.getName());
|
||||||
private static final String HIGHLIGHT_PRE = "<span style='background:yellow'>"; //NON-NLS
|
private static final String HIGHLIGHT_PRE = "<span style='background:yellow'>"; //NON-NLS
|
||||||
private static final String HIGHLIGHT_POST = "</span>"; //NON-NLS
|
private static final String HIGHLIGHT_POST = "</span>"; //NON-NLS
|
||||||
private static final String ANCHOR_PREFIX = HighlightedMatchesSource.class.getName() + "_";
|
private static final String ANCHOR_PREFIX = HighlightedTextMarkup.class.getName() + "_";
|
||||||
|
|
||||||
private Content content;
|
private Content content;
|
||||||
private String keywordHitQuery;
|
private String keywordHitQuery;
|
||||||
@ -62,17 +61,17 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
private List<Integer> pages;
|
private List<Integer> pages;
|
||||||
private QueryResults hits = null; //original hits that may get passed in
|
private QueryResults hits = null; //original hits that may get passed in
|
||||||
private String originalQuery = null; //or original query if hits are not available
|
private String originalQuery = null; //or original query if hits are not available
|
||||||
private boolean inited = false;
|
private boolean isPageInfoLoaded = false;
|
||||||
private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT);
|
private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT);
|
||||||
|
|
||||||
HighlightedMatchesSource(Content content, String keywordHitQuery, boolean isRegex) {
|
HighlightedTextMarkup(Content content, String keywordHitQuery, boolean isRegex) {
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.keywordHitQuery = keywordHitQuery;
|
this.keywordHitQuery = keywordHitQuery;
|
||||||
this.isRegex = isRegex;
|
this.isRegex = isRegex;
|
||||||
this.group = true;
|
this.group = true;
|
||||||
this.hitsPages = new LinkedHashMap<Integer, Integer>();
|
this.hitsPages = new LinkedHashMap<>();
|
||||||
this.pages = new ArrayList<Integer>();
|
this.pages = new ArrayList<>();
|
||||||
this.pagesToHits = new HashMap<Integer, Integer>();
|
this.pagesToHits = new HashMap<>();
|
||||||
|
|
||||||
this.solrServer = KeywordSearch.getServer();
|
this.solrServer = KeywordSearch.getServer();
|
||||||
this.numberPages = 0;
|
this.numberPages = 0;
|
||||||
@ -82,23 +81,26 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//when the results are not known and need to requery to get hits
|
//when the results are not known and need to requery to get hits
|
||||||
HighlightedMatchesSource(Content content, String solrQuery, boolean isRegex, String originalQuery) {
|
HighlightedTextMarkup(Content content, String solrQuery, boolean isRegex, String originalQuery) {
|
||||||
this(content, solrQuery, isRegex);
|
this(content, solrQuery, isRegex);
|
||||||
this.originalQuery = originalQuery;
|
this.originalQuery = originalQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlightedMatchesSource(Content content, String solrQuery, boolean isRegex, QueryResults hits) {
|
HighlightedTextMarkup(Content content, String solrQuery, boolean isRegex, QueryResults hits) {
|
||||||
this(content, solrQuery, isRegex);
|
this(content, solrQuery, isRegex);
|
||||||
this.hits = hits;
|
this.hits = hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlightedMatchesSource(Content content, String solrQuery, boolean isRegex, boolean group, QueryResults hits) {
|
HighlightedTextMarkup(Content content, String solrQuery, boolean isRegex, boolean group, QueryResults hits) {
|
||||||
this(content, solrQuery, isRegex, hits);
|
this(content, solrQuery, isRegex, hits);
|
||||||
this.group = group;
|
this.group = group;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
/**
|
||||||
if (inited) {
|
* The main goal of this method is to figure out which pages / chunks have hits.
|
||||||
|
*/
|
||||||
|
private void loadPageInfo() {
|
||||||
|
if (isPageInfoLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -122,26 +124,22 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
//extract pages of interest, sorted
|
//extract pages of interest, sorted
|
||||||
final long contentId = content.getId();
|
final long contentId = content.getId();
|
||||||
|
|
||||||
|
/* If this is being called from the artifacts / dir tree, then we
|
||||||
|
* need to perform the search to get the highlights.
|
||||||
|
*/
|
||||||
if (hits == null) {
|
if (hits == null) {
|
||||||
//special case, aka in case of dir tree, we don't know which chunks
|
|
||||||
//reperform search query for the content to get matching chunks info
|
|
||||||
KeywordSearchQuery chunksQuery = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keyword keywordQuery = new Keyword(this.originalQuery,
|
|
||||||
* !isRegex); if (this.isRegex) { chunksQuery = new
|
|
||||||
* TermComponentQuery(keywordQuery); } else { chunksQuery = new
|
|
||||||
* LuceneQuery(keywordQuery); chunksQuery.escape(); }
|
|
||||||
*/
|
|
||||||
String queryStr = KeywordSearchUtil.escapeLuceneQuery(this.keywordHitQuery);
|
String queryStr = KeywordSearchUtil.escapeLuceneQuery(this.keywordHitQuery);
|
||||||
if (isRegex) {
|
if (isRegex) {
|
||||||
//use white-space sep. field to get exact matches only of regex query result
|
//use white-space sep. field to get exact matches only of regex query result
|
||||||
queryStr = Server.Schema.CONTENT_WS + ":" + "\"" + queryStr + "\"";
|
queryStr = Server.Schema.CONTENT_WS + ":" + "\"" + queryStr + "\"";
|
||||||
}
|
}
|
||||||
Keyword keywordQuery = new Keyword(queryStr, false);
|
|
||||||
chunksQuery = new LuceneQuery(hits.getKeywordList(), keywordQuery);
|
Keyword keywordQuery = new Keyword(queryStr, !isRegex);
|
||||||
KeywordQueryFilter contentIdFilter = new KeywordQueryFilter(FilterType.CHUNK, contentId);
|
List<Keyword> keywords = new ArrayList<>();
|
||||||
chunksQuery.addFilter(contentIdFilter);
|
keywords.add(keywordQuery);
|
||||||
|
KeywordSearchQuery chunksQuery = new LuceneQuery(new KeywordList(keywords), keywordQuery);
|
||||||
|
|
||||||
|
chunksQuery.addFilter(new KeywordQueryFilter(FilterType.CHUNK, contentId));
|
||||||
try {
|
try {
|
||||||
hits = chunksQuery.performQuery();
|
hits = chunksQuery.performQuery();
|
||||||
} catch (NoOpenCoreException ex) {
|
} catch (NoOpenCoreException ex) {
|
||||||
@ -182,11 +180,11 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
pages.add(1);
|
pages.add(1);
|
||||||
pagesToHits.put(1, 0);
|
pagesToHits.put(1, 0);
|
||||||
}
|
}
|
||||||
inited = true;
|
isPageInfoLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//constructor for dummy singleton factory instance for Lookup
|
//constructor for dummy singleton factory instance for Lookup
|
||||||
private HighlightedMatchesSource() {
|
private HighlightedTextMarkup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -291,7 +289,7 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMarkup() {
|
public String getMarkup() {
|
||||||
init(); //inits once
|
loadPageInfo(); //inits once
|
||||||
|
|
||||||
String highLightField = null;
|
String highLightField = null;
|
||||||
|
|
||||||
@ -446,7 +444,7 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
//this instance does not actually work with Solr
|
//this instance does not actually work with Solr
|
||||||
public static synchronized HighlightLookup getDefault() {
|
public static synchronized HighlightLookup getDefault() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new HighlightedMatchesSource();
|
instance = new HighlightedTextMarkup();
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -454,6 +452,6 @@ class HighlightedMatchesSource implements MarkupSource, HighlightLookup {
|
|||||||
@Override
|
@Override
|
||||||
//factory method, i.e. invoked on dummy (Lookup) instance
|
//factory method, i.e. invoked on dummy (Lookup) instance
|
||||||
public HighlightLookup createInstance(Content c, String keywordHitQuery, boolean isRegex, String originalQuery) {
|
public HighlightLookup createInstance(Content c, String keywordHitQuery, boolean isRegex, String originalQuery) {
|
||||||
return new HighlightedMatchesSource(c, keywordHitQuery, isRegex, originalQuery);
|
return new HighlightedTextMarkup(c, keywordHitQuery, isRegex, originalQuery);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,7 +45,7 @@ import org.sleuthkit.datamodel.File;
|
|||||||
*/
|
*/
|
||||||
class KeywordSearchFilterNode extends FilterNode {
|
class KeywordSearchFilterNode extends FilterNode {
|
||||||
|
|
||||||
KeywordSearchFilterNode(HighlightedMatchesSource highlights, Node original) {
|
KeywordSearchFilterNode(HighlightedTextMarkup highlights, Node original) {
|
||||||
super(original, null, new ProxyLookup(Lookups.singleton(highlights), original.getLookup()));
|
super(original, null, new ProxyLookup(Lookups.singleton(highlights), original.getLookup()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,6 +27,8 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
*/
|
*/
|
||||||
interface KeywordSearchQuery {
|
interface KeywordSearchQuery {
|
||||||
|
|
||||||
|
KeywordList getKeywordList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* validate the query pre execution
|
* validate the query pre execution
|
||||||
* @return true if the query passed validation
|
* @return true if the query passed validation
|
||||||
|
@ -164,14 +164,8 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get listname
|
|
||||||
String listName = "";
|
String listName = queryRequest.getQuery().getKeywordList().getName();
|
||||||
if (queryRequests.size() > 1) {
|
|
||||||
KeywordList list = XmlKeywordSearchList.getCurrent().getListWithKeyword(keywordSearchQuery.getQueryString());
|
|
||||||
if (list != null) {
|
|
||||||
listName = list.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean literal_query = keywordSearchQuery.isLiteral();
|
final boolean literal_query = keywordSearchQuery.isLiteral();
|
||||||
|
|
||||||
@ -305,7 +299,7 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
|||||||
|
|
||||||
//wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization
|
//wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization
|
||||||
// store the data in HighlightedMatchesSource so that it can be looked up (in content viewer)
|
// store the data in HighlightedMatchesSource so that it can be looked up (in content viewer)
|
||||||
HighlightedMatchesSource highlights = new HighlightedMatchesSource(content, queryStr, !key.getQuery().isLiteral(), false, hits);
|
HighlightedTextMarkup highlights = new HighlightedTextMarkup(content, queryStr, !key.getQuery().isLiteral(), false, hits);
|
||||||
return new KeywordSearchFilterNode(highlights, kvNode);
|
return new KeywordSearchFilterNode(highlights, kvNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ package org.sleuthkit.autopsy.keywordsearch;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -32,10 +31,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.apache.solr.client.solrj.SolrQuery;
|
import org.apache.solr.client.solrj.SolrQuery;
|
||||||
import org.apache.solr.client.solrj.SolrRequest.METHOD;
|
import org.apache.solr.client.solrj.SolrRequest.METHOD;
|
||||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||||
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
|
||||||
import org.apache.solr.common.SolrDocument;
|
import org.apache.solr.common.SolrDocument;
|
||||||
import org.apache.solr.common.SolrDocumentList;
|
import org.apache.solr.common.SolrDocumentList;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Version;
|
import org.sleuthkit.autopsy.coreutils.Version;
|
||||||
@ -76,20 +73,15 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
* @param keywordQuery
|
* @param keywordQuery
|
||||||
*/
|
*/
|
||||||
public LuceneQuery(KeywordList keywordList, Keyword keywordQuery) {
|
public LuceneQuery(KeywordList keywordList, Keyword keywordQuery) {
|
||||||
this(keywordQuery.getQuery());
|
|
||||||
this.keywordList = keywordList;
|
this.keywordList = keywordList;
|
||||||
this.keywordQuery = keywordQuery;
|
this.keywordQuery = keywordQuery;
|
||||||
|
|
||||||
|
// @@@ BC: Long-term, we should try to get rid of this string and use only the
|
||||||
|
// keyword object. Refactoring did not make its way through this yet.
|
||||||
|
this.keywordString = keywordQuery.getQuery();
|
||||||
|
this.keywordStringEscaped = this.keywordString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor with keyword string to process
|
|
||||||
* @param queryStr Keyword to search for
|
|
||||||
*/
|
|
||||||
public LuceneQuery(String queryStr) {
|
|
||||||
this.keywordString = queryStr;
|
|
||||||
this.keywordStringEscaped = queryStr;
|
|
||||||
isEscaped = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addFilter(KeywordQueryFilter filter) {
|
public void addFilter(KeywordQueryFilter filter) {
|
||||||
@ -196,9 +188,9 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the query and return result
|
* Perform the query and return results of unique files.
|
||||||
* @param snippets True if results should have a snippet
|
* @param snippets True if results should have a snippet
|
||||||
* @return list of ContentHit objects
|
* @return list of ContentHit objects. One per file with hit (ignores multiple hits of the word in the same doc)
|
||||||
* @throws NoOpenCoreException
|
* @throws NoOpenCoreException
|
||||||
*/
|
*/
|
||||||
private List<ContentHit> performLuceneQuery(boolean snippets) throws NoOpenCoreException {
|
private List<ContentHit> performLuceneQuery(boolean snippets) throws NoOpenCoreException {
|
||||||
@ -215,10 +207,12 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
try {
|
try {
|
||||||
QueryResponse response = solrServer.query(q, METHOD.POST);
|
QueryResponse response = solrServer.query(q, METHOD.POST);
|
||||||
SolrDocumentList resultList = response.getResults();
|
SolrDocumentList resultList = response.getResults();
|
||||||
|
|
||||||
|
// objectId_chunk -> "text" -> List of previews
|
||||||
Map<String, Map<String, List<String>>> highlightResponse = response.getHighlighting();
|
Map<String, Map<String, List<String>>> highlightResponse = response.getHighlighting();
|
||||||
|
|
||||||
// get the unique set of files with hits
|
// get the unique set of files with hits
|
||||||
Set<SolrDocument> solrDocumentsWithMatches = filterDuplicateSolrDocuments(resultList);
|
Set<SolrDocument> uniqueSolrDocumentsWithHits = filterDuplicateSolrDocuments(resultList);
|
||||||
|
|
||||||
allMatchesFetched = start + MAX_RESULTS >= resultList.getNumFound();
|
allMatchesFetched = start + MAX_RESULTS >= resultList.getNumFound();
|
||||||
|
|
||||||
@ -230,7 +224,7 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SolrDocument resultDoc : solrDocumentsWithMatches) {
|
for (SolrDocument resultDoc : uniqueSolrDocumentsWithHits) {
|
||||||
ContentHit contentHit;
|
ContentHit contentHit;
|
||||||
try {
|
try {
|
||||||
contentHit = createContentHitFromQueryResults(resultDoc, highlightResponse, snippets, sleuthkitCase);
|
contentHit = createContentHitFromQueryResults(resultDoc, highlightResponse, snippets, sleuthkitCase);
|
||||||
@ -486,6 +480,11 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeywordList getKeywordList() {
|
||||||
|
return keywordList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares SolrDocuments based on their ID's. Two SolrDocuments with
|
* Compares SolrDocuments based on their ID's. Two SolrDocuments with
|
||||||
* different chunk numbers are considered equal.
|
* different chunk numbers are considered equal.
|
||||||
@ -493,6 +492,8 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
private class SolrDocumentComparatorIgnoresChunkId implements Comparator<SolrDocument> {
|
private class SolrDocumentComparatorIgnoresChunkId implements Comparator<SolrDocument> {
|
||||||
@Override
|
@Override
|
||||||
public int compare(SolrDocument left, SolrDocument right) {
|
public int compare(SolrDocument left, SolrDocument right) {
|
||||||
|
// ID is in the form of ObjectId_Chunk
|
||||||
|
|
||||||
String idName = Server.Schema.ID.toString();
|
String idName = Server.Schema.ID.toString();
|
||||||
String leftID = left.getFieldValue(idName).toString();
|
String leftID = left.getFieldValue(idName).toString();
|
||||||
int index = leftID.indexOf(Server.ID_CHUNK_SEP);
|
int index = leftID.indexOf(Server.ID_CHUNK_SEP);
|
||||||
|
@ -32,18 +32,18 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
* Display content with just raw text, no markup
|
* Display content with just raw text, no markup
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class RawMarkupSource implements MarkupSource {
|
class RawTextMarkup implements TextMarkup {
|
||||||
private int numPages = 0;
|
private int numPages = 0;
|
||||||
private int currentPage = 0;
|
private int currentPage = 0;
|
||||||
private boolean hasChunks = false;
|
private boolean hasChunks = false;
|
||||||
|
|
||||||
private Content currentContent;
|
private final Content currentContent;
|
||||||
//keep last content cached
|
//keep last content cached
|
||||||
private String cachedString;
|
private String cachedString;
|
||||||
private int cachedChunk;
|
private int cachedChunk;
|
||||||
private static final Logger logger = Logger.getLogger(RawMarkupSource.class.getName());
|
private static final Logger logger = Logger.getLogger(RawTextMarkup.class.getName());
|
||||||
|
|
||||||
RawMarkupSource(Content content) {
|
RawTextMarkup(Content content) {
|
||||||
currentContent = content;
|
currentContent = content;
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
@ -49,15 +49,15 @@ class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
private static final String TERMS_SEARCH_FIELD = Server.Schema.CONTENT_WS.toString();
|
private static final String TERMS_SEARCH_FIELD = Server.Schema.CONTENT_WS.toString();
|
||||||
private static final String TERMS_HANDLER = "/terms"; //NON-NLS
|
private static final String TERMS_HANDLER = "/terms"; //NON-NLS
|
||||||
private static final int TERMS_TIMEOUT = 90 * 1000; //in ms
|
private static final int TERMS_TIMEOUT = 90 * 1000; //in ms
|
||||||
private static Logger logger = Logger.getLogger(TermComponentQuery.class.getName());
|
private static final Logger logger = Logger.getLogger(TermComponentQuery.class.getName());
|
||||||
private String queryEscaped;
|
private String queryEscaped;
|
||||||
private KeywordList keywordList;
|
private final KeywordList keywordList;
|
||||||
private Keyword keyword;
|
private final Keyword keyword;
|
||||||
private boolean isEscaped;
|
private boolean isEscaped;
|
||||||
private List<Term> terms;
|
private List<Term> terms;
|
||||||
private final List<KeywordQueryFilter> filters = new ArrayList<>();
|
private final List<KeywordQueryFilter> filters = new ArrayList<>();
|
||||||
private String field;
|
private String field;
|
||||||
private static int MAX_TERMS_RESULTS = 20000;
|
private static final int MAX_TERMS_RESULTS = 20000;
|
||||||
|
|
||||||
private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT);
|
private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT);
|
||||||
|
|
||||||
@ -221,7 +221,8 @@ class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
for (Term term : terms) {
|
for (Term term : terms) {
|
||||||
final String termStr = KeywordSearchUtil.escapeLuceneQuery(term.getTerm());
|
final String termStr = KeywordSearchUtil.escapeLuceneQuery(term.getTerm());
|
||||||
|
|
||||||
LuceneQuery filesQuery = new LuceneQuery(termStr);
|
LuceneQuery filesQuery = new LuceneQuery(keywordList, new Keyword(termStr, true));
|
||||||
|
|
||||||
//filesQuery.setField(TERMS_SEARCH_FIELD);
|
//filesQuery.setField(TERMS_SEARCH_FIELD);
|
||||||
for (KeywordQueryFilter filter : filters) {
|
for (KeywordQueryFilter filter : filters) {
|
||||||
//set filter
|
//set filter
|
||||||
@ -252,4 +253,9 @@ class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeywordList getKeywordList() {
|
||||||
|
return keywordList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import java.util.LinkedHashMap;
|
|||||||
* highlight the keyword hits and a version that does not do markup
|
* highlight the keyword hits and a version that does not do markup
|
||||||
* so that you can simply view the stored text.
|
* so that you can simply view the stored text.
|
||||||
*/
|
*/
|
||||||
interface MarkupSource {
|
interface TextMarkup {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return text optionally marked up with the subsest of HTML that Swing
|
* @return text optionally marked up with the subsest of HTML that Swing
|
@ -19,9 +19,9 @@
|
|||||||
Services
|
Services
|
||||||
======================================================= -->
|
======================================================= -->
|
||||||
<folder name="Services">
|
<folder name="Services">
|
||||||
<file name="org-sleuthkit-autopsy-keywordsearch-HighlightedMatchesSource.instance">
|
<file name="org-sleuthkit-autopsy-keywordsearch-HighlightedTextMarkup.instance">
|
||||||
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.datamodel.HighlightLookup"/>
|
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.datamodel.HighlightLookup"/>
|
||||||
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.keywordsearch.HighlightedMatchesSource.getDefault"/>
|
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.keywordsearch.HighlightedTextMarkup.getDefault"/>
|
||||||
<attr name="position" intvalue="250"/>
|
<attr name="position" intvalue="250"/>
|
||||||
</file>
|
</file>
|
||||||
</folder>
|
</folder>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user