Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
AnnotationUtils.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers.annotations;
20 
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24 import java.util.function.Function;
25 import java.util.logging.Level;
26 import java.util.stream.Collectors;
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.commons.lang3.tuple.Pair;
29 import org.jsoup.Jsoup;
30 import org.jsoup.nodes.Document;
31 import org.jsoup.nodes.Element;
32 import org.openide.nodes.Node;
33 import org.openide.util.NbBundle;
44 import org.sleuthkit.datamodel.AbstractFile;
45 import org.sleuthkit.datamodel.AnalysisResult;
46 import org.sleuthkit.datamodel.BlackboardArtifact;
47 import org.sleuthkit.datamodel.BlackboardArtifactTag;
48 import org.sleuthkit.datamodel.BlackboardAttribute;
49 import org.sleuthkit.datamodel.Content;
50 import org.sleuthkit.datamodel.ContentTag;
51 import org.sleuthkit.datamodel.DataArtifact;
52 import org.sleuthkit.datamodel.SleuthkitCase;
53 import org.sleuthkit.datamodel.Tag;
54 import org.sleuthkit.datamodel.TskCoreException;
55 
59 public class AnnotationUtils {
60 
61  @NbBundle.Messages({
62  "AnnotationUtils.title=Annotations",
63  "AnnotationUtils.toolTip=Displays tags and comments associated with the selected content.",
64  "AnnotationUtils.centralRepositoryEntry.title=Central Repository Comments",
65  "AnnotationUtils.centralRepositoryEntryDataLabel.case=Case:",
66  "AnnotationUtils.centralRepositoryEntryDataLabel.type=Type:",
67  "AnnotationUtils.centralRepositoryEntryDataLabel.comment=Comment:",
68  "AnnotationUtils.centralRepositoryEntryDataLabel.path=Path:",
69  "AnnotationUtils.tagEntry.title=Tags",
70  "AnnotationUtils.tagEntryDataLabel.tag=Tag:",
71  "AnnotationUtils.tagEntryDataLabel.tagUser=Examiner:",
72  "AnnotationUtils.tagEntryDataLabel.comment=Comment:",
73  "AnnotationUtils.fileHitEntry.artifactCommentTitle=Artifact Comment",
74  "AnnotationUtils.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments",
75  "AnnotationUtils.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments",
76  "AnnotationUtils.fileHitEntry.interestingItemTitle=Interesting Item Comments",
77  "AnnotationUtils.fileHitEntry.setName=Set Name:",
78  "AnnotationUtils.fileHitEntry.comment=Comment:",
79  "AnnotationUtils.sourceFile.title=Source File",
80  "AnnotationUtils.onEmpty=No annotations were found for this particular item."
81  })
82 
83  private static final Logger logger = Logger.getLogger(AnnotationUtils.class.getName());
84 
85  private static final String EMPTY_HTML = "<html><head></head><body></body></html>";
86 
87  // describing table values for a tag
88  private static final List<ItemEntry<Tag>> TAG_ENTRIES = Arrays.asList(
89  new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_tag(),
90  (tag) -> (tag.getName() != null) ? tag.getName().getDisplayName() : null),
91  new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()),
92  new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_comment(), (tag) -> tag.getComment())
93  );
94 
95  private static final SectionConfig<Tag> TAG_CONFIG
96  = new SectionConfig<>(Bundle.AnnotationUtils_tagEntry_title(), TAG_ENTRIES);
97 
98  // Item set attributes and table configurations
99  private static final List<ItemEntry<BlackboardArtifact>> ITEMSET_HIT_ENTRIES = Arrays.asList(
100  new ItemEntry<>(Bundle.AnnotationUtils_fileHitEntry_setName(),
101  (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)),
102  new ItemEntry<>(Bundle.AnnotationUtils_fileHitEntry_comment(),
103  (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT))
104  );
105 
106  private static final SectionConfig<BlackboardArtifact> INTERESTING_FILE_CONFIG
107  = new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_interestingFileHitTitle(), ITEMSET_HIT_ENTRIES);
108 
109  private static final SectionConfig<BlackboardArtifact> INTERESTING_ITEM_CONFIG
110  = new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_interestingItemTitle(), ITEMSET_HIT_ENTRIES);
111 
112  private static final SectionConfig<BlackboardArtifact> HASHSET_CONFIG
113  = new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_hashSetHitTitle(), ITEMSET_HIT_ENTRIES);
114 
115  private static final SectionConfig<BlackboardArtifact> ARTIFACT_COMMENT_CONFIG
116  = new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_artifactCommentTitle(), ITEMSET_HIT_ENTRIES);
117 
118  // central repository attributes and table configuration
119  private static final List<ItemEntry<CorrelationAttributeInstance>> CR_COMMENTS_ENTRIES = Arrays.asList(
120  new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_case(),
121  cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null),
122  new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()),
123  new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath())
124  );
125 
126  private static final SectionConfig<CorrelationAttributeInstance> CR_COMMENTS_CONFIG
127  = new SectionConfig<>(Bundle.AnnotationUtils_centralRepositoryEntry_title(), CR_COMMENTS_ENTRIES);
128 
129  /*
130  * Private constructor for this utility class.
131  */
132  private AnnotationUtils() {
133 
134  }
135 
144  static DisplayTskItems getDisplayContent(Node node) {
145  BlackboardArtifactItem<?> artItem = node.getLookup().lookup(BlackboardArtifactItem.class);
146  BlackboardArtifact artifact = artItem == null ? null : artItem.getTskContent();
147 
148  Content content = artItem != null
149  ? artItem.getSourceContent()
150  : node.getLookup().lookup(AbstractFile.class);
151 
152  return new DisplayTskItems(artifact, content);
153  }
154 
162  public static boolean isSupported(Node node) {
163  return getDisplayContent(node).getContent() != null;
164  }
165 
175  public static Document buildDocument(Node node) {
176  Document html = Jsoup.parse(EMPTY_HTML);
177  Element body = html.getElementsByTag("body").first();
178 
179  DisplayTskItems displayItems = getDisplayContent(node);
180  BlackboardArtifact artifact = displayItems.getArtifact();
181  Content srcContent = displayItems.getContent();
182 
183  boolean somethingWasRendered = false;
184  if (artifact != null) {
185  somethingWasRendered = renderArtifact(body, artifact, srcContent);
186  } else {
187  somethingWasRendered = renderContent(body, srcContent, false);
188  }
189 
190  if (!somethingWasRendered) {
191  return null;
192  }
193 
194  return html;
195  }
196 
210  @SuppressWarnings("deprecation")
211  private static boolean renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent) {
212  boolean contentRendered = appendEntries(parent, TAG_CONFIG, getTags(bba), false, true);
213 
215  List<CorrelationAttributeInstance> centralRepoComments = getCentralRepositoryData(bba);
216  boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, false, !contentRendered);
217  contentRendered = contentRendered || crRendered;
218  }
219 
220  // if artifact is a hashset hit or interesting file and has a non-blank comment
221  if ((BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == bba.getArtifactTypeID()
222  || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID()
223  || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == bba.getArtifactTypeID()
224  || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM.getTypeID() == bba.getArtifactTypeID())
225  && (hasTskComment(bba))) {
226 
227  boolean filesetRendered = appendEntries(parent, ARTIFACT_COMMENT_CONFIG, Arrays.asList(bba), false, !contentRendered);
228  contentRendered = contentRendered || filesetRendered;
229  }
230 
231  Element sourceFileSection = appendSection(parent, Bundle.AnnotationUtils_sourceFile_title());
232  sourceFileSection.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName());
233 
234  Element sourceFileContainer = sourceFileSection.appendElement("div");
235  sourceFileContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName());
236 
237  boolean sourceFileRendered = renderContent(sourceFileContainer, sourceContent, true);
238 
239  if (!sourceFileRendered) {
240  sourceFileSection.remove();
241  }
242 
243  return contentRendered || sourceFileRendered;
244  }
245 
259  @SuppressWarnings("deprecation")
260  private static boolean renderContent(Element parent, Content sourceContent, boolean isSubheader) {
261  boolean contentRendered = appendEntries(parent, TAG_CONFIG, getTags(sourceContent), isSubheader, true);
262 
263  if (sourceContent instanceof AbstractFile) {
264  AbstractFile sourceFile = (AbstractFile) sourceContent;
265 
267  List<CorrelationAttributeInstance> centralRepoComments = getCentralRepositoryData(sourceFile);
268  boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, isSubheader,
269  !contentRendered);
270  contentRendered = contentRendered || crRendered;
271  }
272 
273  boolean hashsetRendered = appendEntries(parent, HASHSET_CONFIG,
274  getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT),
275  isSubheader,
276  !contentRendered);
277 
278  boolean interestingFileRendered = appendEntries(parent, INTERESTING_FILE_CONFIG,
279  getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT),
280  isSubheader,
281  !contentRendered);
282 
283  boolean interestingItemRendered = appendEntries(parent, INTERESTING_ITEM_CONFIG,
284  getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM),
285  isSubheader,
286  !contentRendered);
287 
288  contentRendered = contentRendered || hashsetRendered || interestingFileRendered || interestingItemRendered;
289  }
290  return contentRendered;
291  }
292 
300  private static List<ContentTag> getTags(Content sourceContent) {
301  try {
302  SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
303  return tskCase.getContentTagsByContent(sourceContent);
304  } catch (NoCurrentCaseException ex) {
305  logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
306  } catch (TskCoreException ex) {
307  logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS
308  }
309  return new ArrayList<>();
310  }
311 
319  private static List<BlackboardArtifactTag> getTags(BlackboardArtifact bba) {
320  try {
321  SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
322  return tskCase.getBlackboardArtifactTagsByArtifact(bba);
323  } catch (NoCurrentCaseException ex) {
324  logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
325  } catch (TskCoreException ex) {
326  logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS
327  }
328  return new ArrayList<>();
329  }
330 
340  private static List<BlackboardArtifact> getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type) {
341  try {
342  SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
343  return tskCase.getBlackboardArtifacts(type, sourceFile.getId()).stream()
344  .filter((bba) -> hasTskComment(bba) || hasTskSet(bba))
345  .collect(Collectors.toList());
346  } catch (NoCurrentCaseException ex) {
347  logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
348  } catch (TskCoreException ex) {
349  logger.log(Level.SEVERE, "Exception while getting file set hits from the case database.", ex); //NON-NLS
350  }
351  return new ArrayList<>();
352  }
353 
361  private static boolean hasTskComment(BlackboardArtifact artifact) {
362  return StringUtils.isNotBlank(tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT));
363  }
364 
372  private static boolean hasTskSet(BlackboardArtifact artifact) {
373  return StringUtils.isNotBlank(tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
374  }
375 
385  private static String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
386  if (artifact == null) {
387  return null;
388  }
389 
390  BlackboardAttribute attr = null;
391  try {
392  attr = artifact.getAttribute(new BlackboardAttribute.Type(attributeType));
393  } catch (TskCoreException ex) {
394  logger.log(Level.WARNING, String.format("Unable to fetch attribute of type %s for artifact %s", attributeType, artifact), ex);
395  }
396 
397  if (attr == null) {
398  return null;
399  }
400 
401  return attr.getValueString();
402  }
403 
413  private static List<CorrelationAttributeInstance> getCentralRepositoryData(BlackboardArtifact artifact) {
414  if (artifact == null) {
415  return new ArrayList<>();
416  }
417  List<CorrelationAttributeInstance> instances = new ArrayList<>();
418  if (artifact instanceof DataArtifact) {
419  instances.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) artifact));
420  } else if (artifact instanceof AnalysisResult) {
421  instances.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) artifact));
422  }
423 
424  List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = instances.stream()
425  .map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue()))
426  .collect(Collectors.toList());
427 
428  return getCorrelationAttributeComments(lookupKeys);
429  }
430 
440  private static List<CorrelationAttributeInstance> getCentralRepositoryData(AbstractFile sourceFile) {
441  if (sourceFile == null || StringUtils.isEmpty(sourceFile.getMd5Hash())) {
442  return new ArrayList<>();
443  }
444 
445  List<CorrelationAttributeInstance.Type> artifactTypes = null;
446  try {
448  } catch (CentralRepoException ex) {
449  logger.log(Level.SEVERE, "Error connecting to the Central Repository database.", ex); // NON-NLS
450  }
451 
452  if (artifactTypes == null || artifactTypes.isEmpty()) {
453  return new ArrayList<>();
454  }
455 
456  String md5 = sourceFile.getMd5Hash();
457 
458  // get key lookups for a file attribute types and the md5 hash
459  List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = artifactTypes.stream()
460  .filter((attributeType) -> attributeType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
461  .map((attributeType) -> Pair.of(attributeType, md5))
462  .collect(Collectors.toList());
463 
464  return getCorrelationAttributeComments(lookupKeys);
465  }
466 
475  private static List<CorrelationAttributeInstance> getCorrelationAttributeComments(List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys) {
476  List<CorrelationAttributeInstance> instancesToRet = new ArrayList<>();
477 
478  try {
479  // use lookup instances to find the actual correlation attributes for the items selected
480  for (Pair<CorrelationAttributeInstance.Type, String> typeVal : lookupKeys) {
481  instancesToRet.addAll(CentralRepository.getInstance()
482  .getArtifactInstancesByTypeValue(typeVal.getKey(), typeVal.getValue())
483  .stream()
484  // for each one found, if it has a comment, return
485  .filter((cai) -> StringUtils.isNotBlank(cai.getComment()))
486  .collect(Collectors.toList()));
487  }
488 
489  } catch (CentralRepoException ex) {
490  logger.log(Level.SEVERE, "Error connecting to the Central Repository database.", ex); // NON-NLS
492  logger.log(Level.WARNING, "Error normalizing instance from Central Repository database.", ex); // NON-NLS
493  }
494 
495  return instancesToRet;
496  }
497 
515  private static <T> boolean appendEntries(Element parent, AnnotationUtils.SectionConfig<T> config, List<? extends T> items,
516  boolean isSubsection, boolean isFirstSection) {
517  if (items == null || items.isEmpty()) {
518  return false;
519  }
520 
521  Element sectionDiv = (isSubsection) ? appendSubsection(parent, config.getTitle()) : appendSection(parent, config.getTitle());
522  if (!isFirstSection) {
523  sectionDiv.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName());
524  }
525 
526  Element sectionContainer = sectionDiv.appendElement("div");
527 
528  if (!isSubsection) {
529  sectionContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName());
530  }
531 
532  appendVerticalEntryTables(sectionContainer, items, config.getAttributes());
533  return true;
534  }
535 
546  private static <T> Element appendVerticalEntryTables(Element parent, List<? extends T> items, List<ItemEntry<T>> rowHeaders) {
547  boolean isFirst = true;
548  for (T item : items) {
549  if (item == null) {
550  continue;
551  }
552 
553  List<List<String>> tableData = rowHeaders.stream()
554  .map(row -> Arrays.asList(row.getItemName(), row.retrieveValue(item)))
555  .collect(Collectors.toList());
556 
557  Element childTable = appendTable(parent, 2, tableData, null);
558 
559  if (isFirst) {
560  isFirst = false;
561  } else {
562  childTable.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName());
563  }
564  }
565 
566  return parent;
567  }
568 
581  private static Element appendTable(Element parent, int columnNumber, List<List<String>> content, List<String> columnHeaders) {
582  Element table = parent.appendElement("table")
583  .attr("valign", "top")
584  .attr("align", "left");
585 
586  if (columnHeaders != null && !columnHeaders.isEmpty()) {
587  Element header = table.appendElement("thead");
588  appendRow(header, columnHeaders, columnNumber, true);
589  }
590  Element tableBody = table.appendElement("tbody");
591 
592  content.forEach((rowData) -> appendRow(tableBody, rowData, columnNumber, false));
593  return table;
594  }
595 
607  private static Element appendRow(Element rowParent, List<String> data, int columnNumber, boolean isHeader) {
608  String cellType = isHeader ? "th" : "td";
609  Element row = rowParent.appendElement("tr");
610  for (int i = 0; i < columnNumber; i++) {
611  Element cell = row.appendElement(cellType);
612 
613  if (i == 0) {
614  cell.attr("class", ContentViewerHtmlStyles.getKeyColumnClassName());
615  }
616 
617  if (data != null && i < data.size()) {
618  cell.appendElement("span")
619  .attr("class", ContentViewerHtmlStyles.getTextClassName())
620  .text(StringUtils.isEmpty(data.get(i)) ? "" : data.get(i));
621  }
622  }
623  return row;
624  }
625 
634  private static Element appendSection(Element parent, String headerText) {
635  Element sectionDiv = parent.appendElement("div");
636  Element header = sectionDiv.appendElement("h1");
637  header.text(headerText);
638  header.attr("class", ContentViewerHtmlStyles.getHeaderClassName());
639  return sectionDiv;
640  }
641 
650  private static Element appendSubsection(Element parent, String headerText) {
651  Element subsectionDiv = parent.appendElement("div");
652  Element header = subsectionDiv.appendElement("h2");
653  header.text(headerText);
654  header.attr("class", ContentViewerHtmlStyles.getHeaderClassName());
655  return subsectionDiv;
656  }
657 
665  static class ItemEntry<T> {
666 
667  private final String itemName;
668  private final Function<T, String> valueRetriever;
669 
670  ItemEntry(String itemName, Function<T, String> valueRetriever) {
671  this.itemName = itemName;
672  this.valueRetriever = valueRetriever;
673  }
674 
675  String getItemName() {
676  return itemName;
677  }
678 
679  Function<T, String> getValueRetriever() {
680  return valueRetriever;
681  }
682 
683  String retrieveValue(T object) {
684  return valueRetriever.apply(object);
685  }
686  }
687 
693  static class SectionConfig<T> {
694 
695  private final String title;
696  private final List<ItemEntry<T>> attributes;
697 
698  SectionConfig(String title, List<ItemEntry<T>> attributes) {
699  this.title = title;
700  this.attributes = attributes;
701  }
702 
706  String getTitle() {
707  return title;
708  }
709 
714  List<ItemEntry<T>> getAttributes() {
715  return attributes;
716  }
717  }
718 
723  static class DisplayTskItems {
724 
725  private final BlackboardArtifact artifact;
726  private final Content content;
727 
735  DisplayTskItems(BlackboardArtifact artifact, Content content) {
736  this.artifact = artifact;
737  this.content = content;
738  }
739 
743  BlackboardArtifact getArtifact() {
744  return artifact;
745  }
746 
750  Content getContent() {
751  return content;
752  }
753  }
754 }
static String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType)
static List< CorrelationAttributeInstance > getCentralRepositoryData(AbstractFile sourceFile)
static final SectionConfig< BlackboardArtifact > INTERESTING_ITEM_CONFIG
static Element appendRow(Element rowParent, List< String > data, int columnNumber, boolean isHeader)
static Element appendSubsection(Element parent, String headerText)
static< T > boolean appendEntries(Element parent, AnnotationUtils.SectionConfig< T > config, List<?extends T > items, boolean isSubsection, boolean isFirstSection)
static List< ContentTag > getTags(Content sourceContent)
static final SectionConfig< BlackboardArtifact > HASHSET_CONFIG
static final SectionConfig< BlackboardArtifact > INTERESTING_FILE_CONFIG
static Element appendSection(Element parent, String headerText)
static List< BlackboardArtifact > getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type)
static< T > Element appendVerticalEntryTables(Element parent, List<?extends T > items, List< ItemEntry< T >> rowHeaders)
static final List< ItemEntry< CorrelationAttributeInstance > > CR_COMMENTS_ENTRIES
List< CorrelationAttributeInstance.Type > getDefinedCorrelationTypes()
static List< BlackboardArtifactTag > getTags(BlackboardArtifact bba)
static List< CorrelationAttributeInstance > makeCorrAttrsForSearch(AnalysisResult analysisResult)
static final SectionConfig< BlackboardArtifact > ARTIFACT_COMMENT_CONFIG
static boolean hasTskComment(BlackboardArtifact artifact)
static Element appendTable(Element parent, int columnNumber, List< List< String >> content, List< String > columnHeaders)
static final SectionConfig< CorrelationAttributeInstance > CR_COMMENTS_CONFIG
static boolean renderContent(Element parent, Content sourceContent, boolean isSubheader)
static final List< ItemEntry< BlackboardArtifact > > ITEMSET_HIT_ENTRIES
static List< CorrelationAttributeInstance > getCentralRepositoryData(BlackboardArtifact artifact)
static List< CorrelationAttributeInstance > getCorrelationAttributeComments(List< Pair< CorrelationAttributeInstance.Type, String >> lookupKeys)
List< CorrelationAttributeInstance > getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type type, String value)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static boolean renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent)

Copyright © 2012-2022 Basis Technology. Generated on: Wed Oct 5 2022
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.