19 package org.sleuthkit.autopsy.keywordsearch;
21 import java.awt.EventQueue;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.LinkedHashMap;
27 import java.util.List;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.locks.ReentrantReadWriteLock;
32 import java.util.logging.Level;
33 import org.openide.util.NbBundle;
35 import javax.swing.SwingWorker;
36 import org.netbeans.api.progress.ProgressHandle;
37 import org.netbeans.api.progress.ProgressHandleFactory;
38 import org.openide.nodes.ChildFactory;
39 import org.openide.nodes.Children;
40 import org.openide.nodes.Node;
41 import org.openide.util.Cancellable;
42 import org.openide.util.lookup.Lookups;
61 class KeywordSearchResultFactory
extends ChildFactory<KeyValueQueryContent> {
69 public String toString() {
70 return BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getDisplayName();
75 public String toString() {
76 return BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getDisplayName();
81 public String toString() {
82 return BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getDisplayName();
86 private Collection<QueryRequest> queryRequests;
91 this.queryRequests = queryRequests;
102 public static void initCommonProperties(Map<String, Object> toSet) {
103 CommonPropertyTypes[] commonTypes = CommonPropertyTypes.values();
104 final int COMMON_PROPS_LEN = commonTypes.length;
105 for (
int i = 0; i < COMMON_PROPS_LEN; ++i) {
106 toSet.put(commonTypes[i].toString(),
"");
109 AbstractAbstractFileNode.AbstractFilePropertyType[] fsTypes = AbstractAbstractFileNode.AbstractFilePropertyType.values();
110 final int FS_PROPS_LEN = fsTypes.length;
111 for (
int i = 0; i < FS_PROPS_LEN; ++i) {
112 toSet.put(fsTypes[i].toString(),
"");
116 public static void setCommonProperty(Map<String, Object> toSet, CommonPropertyTypes type, String value) {
117 final String typeStr = type.toString();
118 toSet.put(typeStr, value);
121 public static void setCommonProperty(Map<String, Object> toSet, CommonPropertyTypes type, Boolean value) {
122 final String typeStr = type.toString();
123 toSet.put(typeStr, value);
127 protected boolean createKeys(List<KeyValueQueryContent> toPopulate) {
129 for (QueryRequest queryRequest : queryRequests) {
130 Map<String, Object> map = queryRequest.getProperties();
131 initCommonProperties(map);
132 final String query = queryRequest.getQueryString();
133 setCommonProperty(map, CommonPropertyTypes.KEYWORD, query);
134 setCommonProperty(map, CommonPropertyTypes.REGEX, !queryRequest.getQuery().isLiteral());
135 createFlatKeys(queryRequest, toPopulate);
148 private boolean createFlatKeys(QueryRequest queryRequest, List<KeyValueQueryContent> toPopulate) {
152 final KeywordSearchQuery keywordSearchQuery = queryRequest.getQuery();
153 if (!keywordSearchQuery.validate()) {
161 QueryResults queryResults;
163 queryResults = keywordSearchQuery.performQuery();
164 }
catch (NoOpenCoreException ex) {
165 logger.log(Level.SEVERE,
"Could not perform the query " + keywordSearchQuery.getQueryString(), ex);
170 List<KeyValueQueryContent> tempList =
new ArrayList<>();
171 for (KeywordHit hit : getOneHitPerObject(queryResults)) {
175 Map<String, Object> properties =
new LinkedHashMap<>();
176 Content content = hit.getContent();
177 if (content instanceof AbstractFile) {
178 AbstractFsContentNode.fillPropertyMap(properties, (AbstractFile) content);
180 properties.put(AbstractAbstractFileNode.AbstractFilePropertyType.LOCATION.toString(), content.getName());
186 if (hit.hasSnippet()) {
187 setCommonProperty(properties, CommonPropertyTypes.CONTEXT, hit.getSnippet());
194 final String highlightQueryEscaped = getHighlightQuery(keywordSearchQuery, keywordSearchQuery.isLiteral(), queryResults, content);
196 String name = content.getName();
197 if (hit.isArtifactHit()) {
198 name = hit.getArtifact().getDisplayName() +
" Artifact";
200 tempList.add(
new KeyValueQueryContent(name, properties, ++
id, hit.getSolrObjectId(), content, highlightQueryEscaped, keywordSearchQuery, queryResults));
205 toPopulate.addAll(tempList);
211 new BlackboardResultWriter(queryResults, queryRequest.getQuery().getKeywordList().getName()).execute();
225 Collection<KeywordHit> getOneHitPerObject(QueryResults queryResults) {
226 HashMap<Long, KeywordHit> hits =
new HashMap<Long, KeywordHit>();
227 for (Keyword keyWord : queryResults.getKeywords()) {
228 for (KeywordHit hit : queryResults.getResults(keyWord)) {
230 if (!hits.containsKey(hit.getSolrObjectId())) {
231 hits.put(hit.getSolrObjectId(), hit);
233 if (hit.getChunkId() < hits.get(hit.getSolrObjectId()).getChunkId()) {
234 hits.put(hit.getSolrObjectId(), hit);
239 return hits.values();
252 private String getHighlightQuery(KeywordSearchQuery query,
boolean literal_query, QueryResults queryResults, Content content) {
253 String highlightQueryEscaped;
256 highlightQueryEscaped = query.getQueryString();
260 StringBuilder highlightQuery =
new StringBuilder();
262 if (queryResults.getKeywords().size() == 1) {
264 Keyword term = queryResults.getKeywords().iterator().next();
265 highlightQuery.append(term.toString());
268 List<String> hitTerms =
new ArrayList<>();
269 for (Keyword keyword : queryResults.getKeywords()) {
270 for (KeywordHit hit : queryResults.getResults(keyword)) {
271 if (hit.getContent().equals(content)) {
272 hitTerms.add(keyword.toString());
278 final int lastTerm = hitTerms.size() - 1;
280 for (String term : hitTerms) {
282 final String termS = KeywordSearchUtil.escapeLuceneQuery(term);
283 highlightQuery.append(
"\"");
284 highlightQuery.append(termS);
285 highlightQuery.append(
"\"");
286 if (lastTerm != curTerm) {
287 highlightQuery.append(
" ");
290 highlightQuery.append(LuceneQuery.HIGHLIGHT_FIELD_REGEX).append(
":");
297 highlightQueryEscaped = highlightQuery.toString();
300 return highlightQueryEscaped;
304 protected Node createNodeForKey(KeyValueQueryContent key) {
305 final Content content = key.getContent();
306 final String queryStr = key.getQueryStr();;
307 QueryResults hits = key.getHits();
309 Node kvNode =
new KeyValueNode(key, Children.LEAF, Lookups.singleton(content));
313 HighlightedText highlights =
new HighlightedText(key.solrObjectId, queryStr, !key.getQuery().isLiteral(),
false, hits);
314 return new KeywordSearchFilterNode(highlights, kvNode);
321 class KeyValueQueryContent
extends KeyValue {
323 private long solrObjectId;
324 private Content content;
325 private String queryStr;
326 private QueryResults hits;
327 private KeywordSearchQuery query;
344 public KeyValueQueryContent(String name, Map<String, Object> map,
int id,
long solrObjectId, Content content, String queryStr, KeywordSearchQuery query, QueryResults hits) {
345 super(name, map,
id);
346 this.solrObjectId = solrObjectId;
347 this.content = content;
348 this.queryStr = queryStr;
353 Content getContent() {
357 String getQueryStr() {
361 QueryResults getHits() {
365 KeywordSearchQuery getQuery() {
374 static class BlackboardResultWriter
extends SwingWorker<Object, Void> {
376 private static List<BlackboardResultWriter> writers =
new ArrayList<>();
378 private static final ReentrantReadWriteLock rwLock =
new ReentrantReadWriteLock(
true);
380 private ProgressHandle progress;
381 private KeywordSearchQuery query;
382 private String listName;
383 private QueryResults hits;
384 private Collection<BlackboardArtifact> newArtifacts =
new ArrayList<>();
385 private static final int QUERY_DISPLAY_LEN = 40;
387 BlackboardResultWriter(QueryResults hits, String listName) {
389 this.query = hits.getQuery();
390 this.listName = listName;
393 protected void finalizeWorker() {
394 deregisterWriter(
this);
396 EventQueue.invokeLater(
new Runnable() {
405 protected Object doInBackground() throws Exception {
406 registerWriter(
this);
407 final String queryStr = query.getQueryString();
408 final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) +
" ..." : queryStr;
413 progress = ProgressHandleFactory.createHandle(
414 NbBundle.getMessage(
this.getClass(),
"KeywordSearchResultFactory.progress.saving", queryDisp),
new Cancellable() {
416 public boolean cancel() {
417 return BlackboardResultWriter.this.cancel(
true);
422 newArtifacts = hits.writeAllHitsToBlackBoard(progress, null,
this,
false);
431 protected void done() {
435 }
catch (InterruptedException | ExecutionException ex) {
436 logger.log(Level.SEVERE,
"Error querying ", ex);
440 private static synchronized void registerWriter(BlackboardResultWriter writer) {
444 private static synchronized void deregisterWriter(BlackboardResultWriter writer) {
445 writers.remove(writer);
448 static synchronized void stopAllWriters() {
449 for (BlackboardResultWriter w : writers) {
synchronized static Logger getLogger(String name)