Autopsy  4.11.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AbstractAbstractFileNode.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2019 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.datamodel;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.lang.ref.WeakReference;
24 import java.util.ArrayList;
25 import java.util.EnumSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.logging.Level;
30 import java.util.stream.Collectors;
31 import org.apache.commons.io.FilenameUtils;
32 import org.apache.commons.lang3.StringUtils;
33 import org.apache.commons.lang3.tuple.Pair;
34 import org.openide.nodes.Sheet;
35 import org.openide.util.NbBundle;
36 import org.openide.util.WeakListeners;
52 import static org.sleuthkit.autopsy.datamodel.Bundle.*;
61 import org.sleuthkit.datamodel.AbstractFile;
62 import org.sleuthkit.datamodel.BlackboardArtifact;
63 import org.sleuthkit.datamodel.Content;
64 import org.sleuthkit.datamodel.ContentTag;
65 import org.sleuthkit.datamodel.Tag;
66 import org.sleuthkit.datamodel.TskCoreException;
67 import org.sleuthkit.datamodel.TskData;
68 
74 public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends AbstractContentNode<T> {
75 
76  private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName());
77 
78  private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
80 
84  AbstractAbstractFileNode(T abstractFile) {
85  super(abstractFile);
86  String ext = abstractFile.getNameExtension();
87  if (StringUtils.isNotBlank(ext)) {
88  ext = "." + ext;
89  // If this is an archive file we will listen for ingest events
90  // that will notify us when new content has been identified.
91  if (FileTypeExtensions.getArchiveExtensions().contains(ext)) {
93  }
94  }
95 
97  backgroundTasksPool.submit(new TranslationTask(
98  new WeakReference<>(this), weakPcl));
99  }
100 
101  // Listen for case events so that we can detect when the case is closed
102  // or when tags are added.
104  }
105 
115  @Override
116  protected void finalize() throws Throwable {
117  super.finalize();
118  removeListeners();
119  }
120 
121  private void removeListeners() {
124  }
125 
126  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
127  String eventType = evt.getPropertyName();
128 
129  // Is this a content changed event?
130  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
131  if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
132  return;
133  }
134  ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
135  if ((moduleContentEvent.getSource() instanceof Content) == false) {
136  return;
137  }
138  Content newContent = (Content) moduleContentEvent.getSource();
139 
140  // Does the event indicate that content has been added to *this* file?
141  if (getContent().getId() == newContent.getId()) {
142  // If so, refresh our children.
143  try {
144  // We only want to refresh our parents children if we are in the
145  // data sources branch of the tree. The parent nodes in other
146  // branches of the tree (e.g. File Types and Deleted Files) do
147  // not need to be refreshed.
148  BaseChildFactory.post(getParentNode().getName(), new RefreshKeysEvent());
149  } catch (NullPointerException ex) {
150  // Skip
151  } catch (NoSuchEventBusException ex) {
152  logger.log(Level.WARNING, "Failed to post key refresh event", ex); //NON-NLS
153  }
154  }
155  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
156  if (evt.getNewValue() == null) {
157  // case was closed. Remove listeners so that we don't get called with a stale case handle
158  removeListeners();
159  }
160  /*
161  * No need to do any asynchrony around tag added, deleted or CR
162  * change events, they are so infrequent and user driven that we can
163  * just keep a simple blocking approach, where we go out to the
164  * database ourselves.
165  */
166  } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
168  if (event.getAddedTag().getContent().equals(content)) {
169  List<Tag> tags = this.getAllTagsFromDatabase();
170  Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
171  Score value = scorePropAndDescr.getLeft();
172  String descr = scorePropAndDescr.getRight();
174  updateSheet(new NodeProperty<>(SCORE.toString(), SCORE.toString(), descr, value),
175  new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, getCommentProperty(tags, attribute))
176  );
177  }
178  } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
180  if (event.getDeletedTagInfo().getContentID() == content.getId()) {
181  List<Tag> tags = getAllTagsFromDatabase();
182  Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
183  Score value = scorePropAndDescr.getLeft();
184  String descr = scorePropAndDescr.getRight();
186  updateSheet(new NodeProperty<>(SCORE.toString(), SCORE.toString(), descr, value),
187  new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, getCommentProperty(tags, attribute))
188  );
189  }
190  } else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
192  if (event.getContentID() == content.getId()) {
193  List<Tag> tags = getAllTagsFromDatabase();
195  updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, getCommentProperty(tags, attribute)));
196  }
197  } else if (eventType.equals(NodeSpecificEvents.TRANSLATION_AVAILABLE.toString())) {
198  this.setDisplayName(evt.getNewValue().toString());
199  //Set the tooltip
200  this.setShortDescription(content.getName());
201  updateSheet(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, content.getName()));
202  } else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString())) {
203  SCOData scoData = (SCOData) evt.getNewValue();
204  if (scoData.getScoreAndDescription() != null) {
205  updateSheet(new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
206  }
207  if (scoData.getComment() != null) {
208  updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, scoData.getComment()));
209  }
210  if (scoData.getCountAndDescription() != null
212  updateSheet(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
213  }
214  }
215  };
224  private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
225 
226  /*
227  * This is called when the node is first initialized. Any new updates or
228  * changes happen by directly manipulating the sheet. That means we can fire
229  * off background events everytime this method is called and not worry about
230  * duplicated jobs.
231  */
232  @Override
233  protected synchronized Sheet createSheet() {
234  Sheet sheet = new Sheet();
235  Sheet.Set sheetSet = Sheet.createPropertiesSet();
236  sheet.put(sheetSet);
237 
238  //This will fire off fresh background tasks.
239  List<NodeProperty<?>> newProperties = getProperties();
240  newProperties.forEach((property) -> {
241  sheetSet.put(property);
242  });
243 
244  return sheet;
245  }
246 
247  @NbBundle.Messages({"AbstractAbstractFileNode.nameColLbl=Name",
248  "AbstractAbstractFileNode.originalName=Original Name",
249  "AbstractAbstractFileNode.createSheet.score.name=S",
250  "AbstractAbstractFileNode.createSheet.comment.name=C",
251  "AbstractAbstractFileNode.createSheet.count.name=O",
252  "AbstractAbstractFileNode.locationColLbl=Location",
253  "AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time",
254  "AbstractAbstractFileNode.changeTimeColLbl=Change Time",
255  "AbstractAbstractFileNode.accessTimeColLbl=Access Time",
256  "AbstractAbstractFileNode.createdTimeColLbl=Created Time",
257  "AbstractAbstractFileNode.sizeColLbl=Size",
258  "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
259  "AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)",
260  "AbstractAbstractFileNode.modeColLbl=Mode",
261  "AbstractAbstractFileNode.useridColLbl=UserID",
262  "AbstractAbstractFileNode.groupidColLbl=GroupID",
263  "AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.",
264  "AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.",
265  "AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
266  "AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
267  "AbstractAbstractFileNode.knownColLbl=Known",
268  "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
269  "AbstractAbstractFileNode.objectId=Object ID",
270  "AbstractAbstractFileNode.mimeType=MIME Type",
271  "AbstractAbstractFileNode.extensionColLbl=Extension"})
273 
274  NAME(AbstractAbstractFileNode_nameColLbl()),
275  ORIGINAL_NAME(AbstractAbstractFileNode_originalName()),
276  SCORE(AbstractAbstractFileNode_createSheet_score_name()),
277  COMMENT(AbstractAbstractFileNode_createSheet_comment_name()),
278  OCCURRENCES(AbstractAbstractFileNode_createSheet_count_name()),
279  LOCATION(AbstractAbstractFileNode_locationColLbl()),
280  MOD_TIME(AbstractAbstractFileNode_modifiedTimeColLbl()),
281  CHANGED_TIME(AbstractAbstractFileNode_changeTimeColLbl()),
282  ACCESS_TIME(AbstractAbstractFileNode_accessTimeColLbl()),
283  CREATED_TIME(AbstractAbstractFileNode_createdTimeColLbl()),
284  SIZE(AbstractAbstractFileNode_sizeColLbl()),
285  FLAGS_DIR(AbstractAbstractFileNode_flagsDirColLbl()),
286  FLAGS_META(AbstractAbstractFileNode_flagsMetaColLbl()),
287  MODE(AbstractAbstractFileNode_modeColLbl()),
288  USER_ID(AbstractAbstractFileNode_useridColLbl()),
289  GROUP_ID(AbstractAbstractFileNode_groupidColLbl()),
290  META_ADDR(AbstractAbstractFileNode_metaAddrColLbl()),
291  ATTR_ADDR(AbstractAbstractFileNode_attrAddrColLbl()),
292  TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
293  TYPE_META(AbstractAbstractFileNode_typeMetaColLbl()),
294  KNOWN(AbstractAbstractFileNode_knownColLbl()),
295  MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
296  ObjectID(AbstractAbstractFileNode_objectId()),
297  MIMETYPE(AbstractAbstractFileNode_mimeType()),
298  EXTENSION(AbstractAbstractFileNode_extensionColLbl());
299 
300  final private String displayString;
301 
302  private AbstractFilePropertyType(String displayString) {
303  this.displayString = displayString;
304  }
305 
306  @Override
307  public String toString() {
308  return displayString;
309  }
310  }
311 
315  private List<NodeProperty<?>> getProperties() {
316  List<NodeProperty<?>> properties = new ArrayList<>();
317  properties.add(new NodeProperty<>(NAME.toString(), NAME.toString(), NO_DESCR, getContentDisplayName(content)));
318  /*
319  * Initialize an empty place holder value. At the bottom, we kick off a
320  * background task that promises to update these values.
321  */
322 
324  properties.add(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, ""));
325  }
326 
327  // Create place holders for S C O
328  properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), VALUE_LOADING, ""));
329  properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), VALUE_LOADING, ""));
331  properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, ""));
332  }
333 
334  // Get the SCO columns data in a background task
335  backgroundTasksPool.submit(new GetSCOTask(
336  new WeakReference<>(this), weakPcl));
337 
338  properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content)));
339  properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getMtime(), content)));
340  properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCtime(), content)));
341  properties.add(new NodeProperty<>(ACCESS_TIME.toString(), ACCESS_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getAtime(), content)));
342  properties.add(new NodeProperty<>(CREATED_TIME.toString(), CREATED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCrtime(), content)));
343  properties.add(new NodeProperty<>(SIZE.toString(), SIZE.toString(), NO_DESCR, content.getSize()));
344  properties.add(new NodeProperty<>(FLAGS_DIR.toString(), FLAGS_DIR.toString(), NO_DESCR, content.getDirFlagAsString()));
345  properties.add(new NodeProperty<>(FLAGS_META.toString(), FLAGS_META.toString(), NO_DESCR, content.getMetaFlagsAsString()));
346  properties.add(new NodeProperty<>(KNOWN.toString(), KNOWN.toString(), NO_DESCR, content.getKnown().getName()));
347  properties.add(new NodeProperty<>(MD5HASH.toString(), MD5HASH.toString(), NO_DESCR, StringUtils.defaultString(content.getMd5Hash())));
348  properties.add(new NodeProperty<>(MIMETYPE.toString(), MIMETYPE.toString(), NO_DESCR, StringUtils.defaultString(content.getMIMEType())));
349  properties.add(new NodeProperty<>(EXTENSION.toString(), EXTENSION.toString(), NO_DESCR, content.getNameExtension()));
350 
351  return properties;
352  }
353 
363  @NbBundle.Messages("AbstractAbstractFileNode.tagsProperty.displayName=Tags")
364  @Deprecated
365  protected void addTagProperty(Sheet.Set sheetSet) {
366  List<ContentTag> tags = getContentTagsFromDatabase();
367  sheetSet.put(new NodeProperty<>("Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
368  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName())
369  .distinct()
370  .collect(Collectors.joining(", "))));
371  }
372 
383  @Deprecated
384  protected static String getHashSetHitsCsvList(AbstractFile file) {
385  try {
386  return StringUtils.join(file.getHashSetNames(), ", ");
387  } catch (TskCoreException tskCoreException) {
388  logger.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS
389  return "";
390  }
391  }
392 
393  @NbBundle.Messages({
394  "AbstractAbstractFileNode.createSheet.count.displayName=O",
395  "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
396  "# {0} - occurenceCount",
397  "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurences of the MD5 correlation value"})
398  @Override
399  protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) {
400  Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting
401  String description = defaultDescription;
402  try {
403  //don't perform the query if there is no correlation value
404  if (attributeType != null && StringUtils.isNotBlank(attributeValue)) {
405  count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attributeType, attributeValue);
406  description = Bundle.AbstractAbstractFileNode_createSheet_count_description(count);
407  } else if (attributeType != null) {
408  description = Bundle.AbstractAbstractFileNode_createSheet_count_hashLookupNotRun_description();
409  }
410  } catch (EamDbException ex) {
411  logger.log(Level.WARNING, "Error getting count of datasources with correlation attribute", ex);
413  logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
414  }
415  return Pair.of(count, description);
416  }
417 
418  @NbBundle.Messages({
419  "AbstractAbstractFileNode.createSheet.score.displayName=S",
420  "AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.",
421  "AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.",
422  "AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
423  "AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
424  "AbstractAbstractFileNode.createSheet.noScore.description=No score"})
425  @Override
426  protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
428  String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
429  if (content.getKnown() == TskData.FileKnown.BAD) {
431  description = Bundle.AbstractAbstractFileNode_createSheet_notableFile_description();
432  }
433  try {
434  if (score == DataResultViewerTable.Score.NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT).isEmpty()) {
436  description = Bundle.AbstractAbstractFileNode_createSheet_interestingResult_description();
437  }
438  } catch (TskCoreException ex) {
439  logger.log(Level.WARNING, "Error getting artifacts for file: " + content.getName(), ex);
440  }
441  if (!tags.isEmpty() && (score == DataResultViewerTable.Score.NO_SCORE || score == DataResultViewerTable.Score.INTERESTING_SCORE)) {
443  description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description();
444  for (Tag tag : tags) {
445  if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
447  description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description();
448  break;
449  }
450  }
451  }
452  return Pair.of(score, description);
453  }
454 
455  @NbBundle.Messages({
456  "AbstractAbstractFileNode.createSheet.comment.displayName=C"})
457  @Override
458  protected HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
459 
461 
462  for (Tag tag : tags) {
463  if (!StringUtils.isBlank(tag.getComment())) {
464  //if the tag is null or empty or contains just white space it will indicate there is not a comment
466  break;
467  }
468  }
469  if (attribute != null && !StringUtils.isBlank(attribute.getComment())) {
472  } else {
474  }
475  }
476  return status;
477  }
478 
483  String getTranslatedFileName() {
484  //If already in complete English, don't translate.
485  if (content.getName().matches("^\\p{ASCII}+$")) {
486  return "";
487  }
488  TextTranslationService tts = TextTranslationService.getInstance();
489  if (tts.hasProvider()) {
490  //Seperate out the base and ext from the contents file name.
491  String base = FilenameUtils.getBaseName(content.getName());
492  try {
493  String translation = tts.translate(base);
494  String ext = FilenameUtils.getExtension(content.getName());
495 
496  //If we have no extension, then we shouldn't add the .
497  String extensionDelimiter = (ext.isEmpty()) ? "" : ".";
498 
499  //Talk directly to this nodes pcl, fire an update when the translation
500  //is complete.
501  if (!translation.isEmpty()) {
502  return translation + extensionDelimiter + ext;
503  }
504  } catch (NoServiceProviderException noServiceEx) {
505  logger.log(Level.WARNING, "Translate unsuccessful because no TextTranslator "
506  + "implementation was provided.", noServiceEx.getMessage());
507  } catch (TranslationException noTranslationEx) {
508  logger.log(Level.WARNING, "Could not successfully translate file name "
509  + content.getName(), noTranslationEx.getMessage());
510  }
511  }
512  return "";
513  }
514 
520  List<ContentTag> getContentTagsFromDatabase() {
521  List<ContentTag> tags = new ArrayList<>();
522  try {
523  tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(content));
524  } catch (TskCoreException | NoCurrentCaseException ex) {
525  logger.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex);
526  }
527  return tags;
528  }
529 
530  @Override
531  protected List<Tag> getAllTagsFromDatabase() {
532  return new ArrayList<>(getContentTagsFromDatabase());
533  }
534 
535  @Override
537  CorrelationAttributeInstance attribute = null;
539  attribute = EamArtifactUtil.getInstanceFromContent(content);
540  }
541  return attribute;
542  }
543 
544  static String getContentPath(AbstractFile file) {
545  try {
546  return file.getUniquePath();
547  } catch (TskCoreException ex) {
548  logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on " + file.getName(), ex); //NON-NLS
549  return ""; //NON-NLS
550  }
551  }
552 
553  static String getContentDisplayName(AbstractFile file) {
554  String name = file.getName();
555  switch (name) {
556  case "..":
557  return DirectoryNode.DOTDOTDIR;
558  case ".":
559  return DirectoryNode.DOTDIR;
560  default:
561  return name;
562  }
563  }
564 
575  static public void fillPropertyMap(Map<String, Object> map, AbstractFile content) {
576  map.put(NAME.toString(), getContentDisplayName(content));
577  map.put(LOCATION.toString(), getContentPath(content));
578  map.put(MOD_TIME.toString(), ContentUtils.getStringTime(content.getMtime(), content));
579  map.put(CHANGED_TIME.toString(), ContentUtils.getStringTime(content.getCtime(), content));
580  map.put(ACCESS_TIME.toString(), ContentUtils.getStringTime(content.getAtime(), content));
581  map.put(CREATED_TIME.toString(), ContentUtils.getStringTime(content.getCrtime(), content));
582  map.put(SIZE.toString(), content.getSize());
583  map.put(FLAGS_DIR.toString(), content.getDirFlagAsString());
584  map.put(FLAGS_META.toString(), content.getMetaFlagsAsString());
585  map.put(KNOWN.toString(), content.getKnown().getName());
586  map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash()));
587  map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType()));
588  map.put(EXTENSION.toString(), content.getNameExtension());
589  }
590 }
synchronized void updateSheet(NodeProperty<?>...newProps)
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static String getStringTime(long epochSeconds, TimeZone tzone)
static synchronized IngestManager getInstance()
Pair< DataResultViewerTable.Score, String > getScorePropertyAndDescription(List< Tag > tags)
static void fillPropertyMap(Map< String, Object > map, AbstractFile content)
Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value)
static CorrelationAttributeInstance getInstanceFromContent(Content content)
Pair< Long, String > getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription)
static void post(String nodeName, Object event)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
HasCommentStatus getCommentProperty(List< Tag > tags, CorrelationAttributeInstance attribute)
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:441
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:486

Copyright © 2012-2018 Basis Technology. Generated on: Fri Jun 21 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.