Sleuth Kit Java Bindings (JNI)  4.12.1
Java bindings for using The Sleuth Kit
Blackboard.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2018-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.datamodel;
20 
21 import com.google.common.annotations.Beta;
22 import com.google.common.collect.ImmutableSet;
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.text.MessageFormat;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Objects;
37 import java.util.Optional;
38 import java.util.Set;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.logging.Level;
41 import java.util.logging.Logger;
42 import java.util.stream.Collectors;
45 import static org.sleuthkit.datamodel.SleuthkitCase.closeConnection;
46 import static org.sleuthkit.datamodel.SleuthkitCase.closeResultSet;
47 import static org.sleuthkit.datamodel.SleuthkitCase.closeStatement;
48 
53 public final class Blackboard {
54 
55  private static final Logger LOGGER = Logger.getLogger(Blackboard.class.getName());
56 
57  /*
58  * ConcurrentHashMap semantics are fine for these caches to which entries
59  * are added, but never removed. There is also no need to keep each pair of
60  * related caches strictly consistent with each other, because cache misses
61  * will be extremely rare (standard types are loaded when the case is
62  * opened), and the cost of a cache miss is low.
63  */
64  private final Map<Integer, BlackboardArtifact.Type> typeIdToArtifactTypeMap = new ConcurrentHashMap<>();
65  private final Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap = new ConcurrentHashMap<>();
66  private final Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap = new ConcurrentHashMap<>();
67  private final Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap = new ConcurrentHashMap<>();
68 
69  static final int MIN_USER_DEFINED_TYPE_ID = 10000;
70 
71  private final SleuthkitCase caseDb;
72 
79  Blackboard(SleuthkitCase casedb) {
80  this.caseDb = Objects.requireNonNull(casedb, "Cannot create Blackboard for null SleuthkitCase");
81  }
82 
98  @Deprecated
99  public void postArtifact(BlackboardArtifact artifact, String moduleName) throws BlackboardException {
100  postArtifacts(Collections.singleton(artifact), moduleName, null);
101  }
102 
118  @Deprecated
119  public void postArtifacts(Collection<BlackboardArtifact> artifacts, String moduleName) throws BlackboardException {
120  postArtifacts(artifacts, moduleName, null);
121  }
122 
138  public void postArtifact(BlackboardArtifact artifact, String moduleName, Long ingestJobId) throws BlackboardException {
139  postArtifacts(Collections.singleton(artifact), moduleName, ingestJobId);
140  }
141 
157  public void postArtifacts(Collection<BlackboardArtifact> artifacts, String moduleName, Long ingestJobId) throws BlackboardException {
158  for (BlackboardArtifact artifact : artifacts) {
159  try {
160  caseDb.getTimelineManager().addArtifactEvents(artifact);
161  } catch (TskCoreException ex) {
162  throw new BlackboardException(String.format("Failed to add events to timeline for artifact '%s'", artifact), ex);
163  }
164  }
165  caseDb.fireTSKEvent(new ArtifactsPostedEvent(artifacts, moduleName, ingestJobId));
166  }
167 
182  public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName) throws BlackboardException {
183  return getOrAddArtifactType(typeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
184  }
185 
199  public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName, BlackboardArtifact.Category category) throws BlackboardException {
200  if (category == null) {
201  throw new BlackboardException("Category provided must be non-null");
202  }
203 
204  if (typeNameToArtifactTypeMap.containsKey(typeName)) {
205  return typeNameToArtifactTypeMap.get(typeName);
206  }
207 
208  Statement s = null;
209  ResultSet rs = null;
210  CaseDbTransaction trans = null;
211  try {
212  trans = caseDb.beginTransaction();
213 
214  CaseDbConnection connection = trans.getConnection();
215  s = connection.createStatement();
216  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + typeName + "'"); //NON-NLS
217  if (!rs.next()) {
218  rs.close();
219  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
220  int maxID = 0;
221  if (rs.next()) {
222  maxID = rs.getInt("highest_id");
223  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
224  maxID = MIN_USER_DEFINED_TYPE_ID;
225  } else {
226  maxID++;
227  }
228  }
229  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name, category_type) VALUES ('" + maxID + "', '" + typeName + "', '" + displayName + "', " + category.getID() + " )"); //NON-NLS
230  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, typeName, displayName, category);
231  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
232  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
233  trans.commit();
234  trans = null;
235  return type;
236  } else {
237  trans.commit();
238  trans = null;
239  try {
240  return getArtifactType(typeName);
241  } catch (TskCoreException ex) {
242  throw new BlackboardException("Failed to get or add artifact type: " + typeName, ex);
243  }
244  }
245  } catch (SQLException | TskCoreException ex) {
246  try {
247  if (trans != null) {
248  trans.rollback();
249  trans = null;
250  }
251  } catch (TskCoreException ex2) {
252  LOGGER.log(Level.SEVERE, "Error rolling back transaction", ex2);
253  }
254  throw new BlackboardException("Error adding artifact type: " + typeName, ex);
255  } finally {
256  closeResultSet(rs);
257  closeStatement(s);
258  if (trans != null) {
259  try {
260  trans.rollback();
261  } catch (TskCoreException ex) {
262  throw new BlackboardException("Error rolling back transaction", ex);
263  }
264  }
265  }
266  }
267 
278  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
279  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
280  return this.typeNameToAttributeTypeMap.get(attrTypeName);
281  }
282  CaseDbConnection connection = null;
283  Statement s = null;
284  ResultSet rs = null;
286  try {
287  connection = caseDb.getConnection();
288  s = connection.createStatement();
289  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
290  BlackboardAttribute.Type type = null;
291  if (rs.next()) {
292  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
293  rs.getString("display_name"), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
294  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
295  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
296  }
297  return type;
298  } catch (SQLException ex) {
299  throw new TskCoreException("Error getting attribute type id", ex);
300  } finally {
301  closeResultSet(rs);
302  closeStatement(s);
303  closeConnection(connection);
305  }
306  }
307 
319  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
320  return this.typeIdToAttributeTypeMap.get(typeID);
321  }
322  CaseDbConnection connection = null;
323  Statement s = null;
324  ResultSet rs = null;
326  try {
327  connection = caseDb.getConnection();
328  s = connection.createStatement();
329  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE attribute_type_id = " + typeID + ""); //NON-NLS
330  BlackboardAttribute.Type type = null;
331  if (rs.next()) {
332  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
333  rs.getString("display_name"), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
334  this.typeIdToAttributeTypeMap.put(typeID, type);
335  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
336  }
337  return type;
338  } catch (SQLException ex) {
339  throw new TskCoreException("Error getting attribute type id", ex);
340  } finally {
341  closeResultSet(rs);
342  closeStatement(s);
343  closeConnection(connection);
345  }
346  }
347 
358  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
359  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
360  return this.typeNameToArtifactTypeMap.get(artTypeName);
361  }
362  CaseDbConnection connection = null;
363  Statement s = null;
364  ResultSet rs = null;
366  try {
367  connection = caseDb.getConnection();
368  s = connection.createStatement();
369  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
370  BlackboardArtifact.Type type = null;
371  if (rs.next()) {
372  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
373  rs.getString("type_name"), rs.getString("display_name"),
374  BlackboardArtifact.Category.fromID(rs.getInt("category_type")));
375  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
376  this.typeNameToArtifactTypeMap.put(artTypeName, type);
377  }
378  return type;
379  } catch (SQLException ex) {
380  throw new TskCoreException("Error getting artifact type from the database", ex);
381  } finally {
382  closeResultSet(rs);
383  closeStatement(s);
384  closeConnection(connection);
386  }
387  }
388 
401  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
402  return typeIdToArtifactTypeMap.get(artTypeId);
403  }
404  CaseDbConnection connection = null;
405  Statement s = null;
406  ResultSet rs = null;
408  try {
409  connection = caseDb.getConnection();
410  s = connection.createStatement();
411  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
412  BlackboardArtifact.Type type = null;
413  if (rs.next()) {
414  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
415  rs.getString("type_name"), rs.getString("display_name"),
416  BlackboardArtifact.Category.fromID(rs.getInt("category_type")));
417  this.typeIdToArtifactTypeMap.put(artTypeId, type);
418  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
419  return type;
420  } else {
421  throw new TskCoreException("No artifact type found matching id: " + artTypeId);
422  }
423  } catch (SQLException ex) {
424  throw new TskCoreException("Error getting artifact type from the database", ex);
425  } finally {
426  closeResultSet(rs);
427  closeStatement(s);
428  closeConnection(connection);
430  }
431  }
432 
442  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
443  CaseDbConnection connection = null;
444  Statement statement = null;
445  ResultSet rs = null;
446 
447  String rowId;
448  switch (caseDb.getDatabaseType()) {
449  case POSTGRESQL:
450  rowId = "attrs.CTID";
451  break;
452  case SQLITE:
453  rowId = "attrs.ROWID";
454  break;
455  default:
456  throw new TskCoreException("Unknown database type: " + caseDb.getDatabaseType());
457  }
458 
460  try {
461  connection = caseDb.getConnection();
462  statement = connection.createStatement();
463  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
464  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
465  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
466  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
467  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
468  + "types.type_name AS type_name, types.display_name AS display_name "
469  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
470  + " AND attrs.attribute_type_id = types.attribute_type_id "
471  + " ORDER BY " + rowId);
472  ArrayList<BlackboardAttribute> attributes = new ArrayList<>();
473  while (rs.next()) {
474  final BlackboardAttribute attr = createAttributeFromResultSet(rs);
475  attr.setParentDataSourceID(artifact.getDataSourceObjectID());
476  attributes.add(attr);
477  }
478  return attributes;
479  } catch (SQLException ex) {
480  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
481  } finally {
482  closeResultSet(rs);
483  closeStatement(statement);
484  closeConnection(connection);
486  }
487  }
488 
499  @Beta
500  public <T extends BlackboardArtifact> void loadBlackboardAttributes(List<T> arts) throws TskCoreException {
501 
502  if (arts.isEmpty()) {
503  return;
504  }
505 
506  // Make a map of artifact ID to artifact
507  Map<Long, BlackboardArtifact> artifactMap = new HashMap<>();
508  for (BlackboardArtifact art : arts) {
509  artifactMap.put(art.getArtifactID(), art);
510  }
511 
512  // Make a map of artifact ID to attribute list
513  Map<Long, List<BlackboardAttribute>> attributeMap = new HashMap<>();
514 
515  // Get all artifact IDs as a comma-separated string
516  String idString = arts.stream().map(p -> Long.toString(p.getArtifactID())).collect(Collectors.joining(", "));
517 
518  String rowId;
519  switch (caseDb.getDatabaseType()) {
520  case POSTGRESQL:
521  rowId = "attrs.CTID";
522  break;
523  case SQLITE:
524  rowId = "attrs.ROWID";
525  break;
526  default:
527  throw new TskCoreException("Unknown database type: " + caseDb.getDatabaseType());
528  }
529 
530  // Get the attributes
531  CaseDbConnection connection = null;
532  Statement statement = null;
533  ResultSet rs = null;
535  try {
536  connection = caseDb.getConnection();
537  statement = connection.createStatement();
538  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
539  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
540  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
541  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
542  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
543  + "types.type_name AS type_name, types.display_name AS display_name "
544  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id IN (" + idString + ") "
545  + " AND attrs.attribute_type_id = types.attribute_type_id"
546  + " ORDER BY " + rowId);
547  while (rs.next()) {
548  final BlackboardAttribute attr = createAttributeFromResultSet(rs);
549  attr.setParentDataSourceID(artifactMap.get(attr.getArtifactID()).getDataSourceObjectID());
550 
551  // Collect the list of attributes for each artifact
552  if (!attributeMap.containsKey(attr.getArtifactID())) {
553  attributeMap.put(attr.getArtifactID(), new ArrayList<>());
554  }
555  attributeMap.get(attr.getArtifactID()).add(attr);
556  }
557 
558  // Save the attributes to the artifacts
559  for (Long artifactID : attributeMap.keySet()) {
560  artifactMap.get(artifactID).setAttributes(attributeMap.get(artifactID));
561  }
562 
563  } catch (SQLException ex) {
564  throw new TskCoreException("Error loading attributes", ex);
565  } finally {
566  closeResultSet(rs);
567  closeStatement(statement);
568  closeConnection(connection);
570  }
571  }
572 
581  private BlackboardAttribute createAttributeFromResultSet(ResultSet rs) throws SQLException {
582  int attributeTypeId = rs.getInt("attribute_type_id");
583  String attributeTypeName = rs.getString("type_name");
584  BlackboardAttribute.Type attributeType;
585  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
586  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
587  } else {
588  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
589  rs.getString("display_name"),
590  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getInt("value_type")));
591  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
592  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
593  }
594 
595  return new BlackboardAttribute(
596  rs.getLong("artifact_id"),
597  attributeType,
598  rs.getString("source"),
599  rs.getString("context"),
600  rs.getInt("value_int32"),
601  rs.getLong("value_int64"),
602  rs.getDouble("value_double"),
603  rs.getString("value_text"),
604  rs.getBytes("value_byte"), caseDb
605  );
606  }
607 
617  ArrayList<Attribute> getFileAttributes(final AbstractFile file) throws TskCoreException {
618  CaseDbConnection connection = null;
619  Statement statement = null;
620  ResultSet rs = null;
622  try {
623  connection = caseDb.getConnection();
624  statement = connection.createStatement();
625  rs = connection.executeQuery(statement, "SELECT attrs.id as id, attrs.obj_id AS obj_id, "
626  + "attrs.attribute_type_id AS attribute_type_id, "
627  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
628  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
629  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
630  + "types.type_name AS type_name, types.display_name AS display_name "
631  + "FROM tsk_file_attributes AS attrs "
632  + " INNER JOIN blackboard_attribute_types AS types "
633  + " ON attrs.attribute_type_id = types.attribute_type_id "
634  + " WHERE attrs.obj_id = " + file.getId());
635 
636  ArrayList<Attribute> attributes = new ArrayList<Attribute>();
637  while (rs.next()) {
638  int attributeTypeId = rs.getInt("attribute_type_id");
639  String attributeTypeName = rs.getString("type_name");
640  BlackboardAttribute.Type attributeType;
641  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
642  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
643  } else {
644  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
645  rs.getString("display_name"),
646  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getInt("value_type")));
647  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
648  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
649  }
650 
651  final Attribute attr = new Attribute(
652  rs.getLong("id"),
653  rs.getLong("obj_id"),
654  attributeType,
655  rs.getInt("value_int32"),
656  rs.getLong("value_int64"),
657  rs.getDouble("value_double"),
658  rs.getString("value_text"),
659  rs.getBytes("value_byte"), caseDb
660  );
661  attributes.add(attr);
662  }
663  return attributes;
664  } catch (SQLException ex) {
665  throw new TskCoreException("Error getting attributes for file, file id = " + file.getId(), ex);
666  } finally {
667  closeResultSet(rs);
668  closeStatement(statement);
669  closeConnection(connection);
671  }
672  }
673 
683  void initBlackboardArtifactTypes(CaseDbConnection connection) throws SQLException {
685  try (Statement statement = connection.createStatement()) {
686  /*
687  * Determine which types, if any, have already been added to the
688  * case database, and load them into the type caches. For a case
689  * that is being reopened, this should reduce the number of separate
690  * INSERT staements that will be executed below.
691  */
692  ResultSet resultSet = connection.executeQuery(statement, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
693  while (resultSet.next()) {
694  BlackboardArtifact.Type type = new BlackboardArtifact.Type(resultSet.getInt("artifact_type_id"),
695  resultSet.getString("type_name"), resultSet.getString("display_name"),
696  BlackboardArtifact.Category.fromID(resultSet.getInt("category_type")));
697  typeIdToArtifactTypeMap.put(type.getTypeID(), type);
698  typeNameToArtifactTypeMap.put(type.getTypeName(), type);
699  }
700 
701  /*
702  * INSERT any missing standard types. A conflict clause is used to
703  * avoid a potential race condition. It also eliminates the need to
704  * add schema update code when new types are added.
705  *
706  * The use here of the soon to be deprecated
707  * BlackboardArtifact.ARTIFACT_TYPE enum instead of the
708  * BlackboardArtifact.Type.STANDARD_TYPES collection currently
709  * ensures that the deprecated types in the former, and not in the
710  * latter, are added to the case database.
711  */
712  for (BlackboardArtifact.ARTIFACT_TYPE type : BlackboardArtifact.ARTIFACT_TYPE.values()) {
713  if (typeIdToArtifactTypeMap.containsKey(type.getTypeID())) {
714  continue;
715  }
716  if (caseDb.getDatabaseType() == TskData.DbType.POSTGRESQL) {
717  statement.execute("INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name, category_type) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "' , " + type.getCategory().getID() + ") ON CONFLICT DO NOTHING"); //NON-NLS
718  } else {
719  statement.execute("INSERT OR IGNORE INTO blackboard_artifact_types (artifact_type_id, type_name, display_name, category_type) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "' , " + type.getCategory().getID() + ")"); //NON-NLS
720  }
721  typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
722  typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
723  }
724  if (caseDb.getDatabaseType() == TskData.DbType.POSTGRESQL) {
725  int newPrimaryKeyIndex = Collections.max(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values())).getTypeID() + 1;
726  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
727  }
728  } finally {
730  }
731  }
732 
742  void initBlackboardAttributeTypes(CaseDbConnection connection) throws SQLException {
744  try (Statement statement = connection.createStatement()) {
745  /*
746  * Determine which types, if any, have already been added to the
747  * case database, and load them into the type caches. For a case
748  * that is being reopened, this should reduce the number of separate
749  * INSERT staements that will be executed below.
750  */
751  ResultSet resultSet = connection.executeQuery(statement, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
752  while (resultSet.next()) {
753  BlackboardAttribute.Type type = new BlackboardAttribute.Type(resultSet.getInt("attribute_type_id"),
754  resultSet.getString("type_name"), resultSet.getString("display_name"),
755  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(resultSet.getLong("value_type")));
756  typeIdToAttributeTypeMap.put(type.getTypeID(), type);
757  typeNameToAttributeTypeMap.put(type.getTypeName(), type);
758  }
759 
760  /*
761  * INSERT any missing standard types. A conflict clause is used to
762  * avoid a potential race condition. It also eliminates the need to
763  * add schema update code when new types are added.
764  *
765  * The use here of the soon to be deprecated
766  * BlackboardAttribute.ATTRIBUTE_TYPE enum instead of the
767  * BlackboardAttribute.Type.STANDARD_TYPES collection currently
768  * ensures that the deprecated types in the former, and not in the
769  * latter, are added to the case database.
770  */
771  for (BlackboardAttribute.ATTRIBUTE_TYPE type : BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
772  if (typeIdToAttributeTypeMap.containsKey(type.getTypeID())) {
773  continue;
774  }
775  if (caseDb.getDatabaseType() == TskData.DbType.POSTGRESQL) {
776  statement.execute("INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "', '" + type.getValueType().getType() + "') ON CONFLICT DO NOTHING"); //NON-NLS
777  } else {
778  statement.execute("INSERT OR IGNORE INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "', '" + type.getValueType().getType() + "')"); //NON-NLS
779  }
780  typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
781  typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
782  }
783  if (caseDb.getDatabaseType() == TskData.DbType.POSTGRESQL) {
784  int newPrimaryKeyIndex = Collections.max(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values())).getTypeID() + 1;
785  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
786  }
787  } finally {
789  }
790  }
791 
814  public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score,
815  String conclusion, String configuration, String justification, Collection<BlackboardAttribute> attributesList)
817 
818  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
819  throw new BlackboardException(String.format("Artifact type (name = %s) is not of Analysis Result category. ", artifactType.getTypeName()));
820  }
821 
822  CaseDbTransaction transaction = caseDb.beginTransaction();
823  try {
824  AnalysisResultAdded analysisResult = newAnalysisResult(artifactType, objId, dataSourceObjId, score,
825  conclusion, configuration, justification, attributesList, transaction);
826  transaction.commit();
827  return analysisResult;
828  } catch (TskCoreException | BlackboardException ex) {
829  try {
830  transaction.rollback();
831  } catch (TskCoreException ex2) {
832  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception. "
833  + "Error invoking newAnalysisResult with dataSourceObjId: "
834  + (dataSourceObjId == null ? "<null>" : dataSourceObjId)
835  + ", sourceObjId: " + objId, ex2);
836  }
837  throw ex;
838  }
839  }
840 
863  public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score,
864  String conclusion, String configuration, String justification, Collection<BlackboardAttribute> attributesList, CaseDbTransaction transaction) throws BlackboardException {
865 
866  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
867  throw new BlackboardException(String.format("Artifact type (name = %s) is not of Analysis Result category. ", artifactType.getTypeName()));
868  }
869 
870  try {
871  // add analysis result
872  AnalysisResult analysisResult = caseDb.newAnalysisResult(artifactType, objId, dataSourceObjId, score, conclusion, configuration, justification, transaction.getConnection());
873 
874  // add the given attributes
875  if (attributesList != null && !attributesList.isEmpty()) {
876  analysisResult.addAttributes(attributesList, transaction);
877  }
878 
879  // update the final score for the object
880  Score aggregateScore = caseDb.getScoringManager().updateAggregateScoreAfterAddition(objId, dataSourceObjId, analysisResult.getScore(), transaction);
881 
882  // return the analysis result and the current aggregate score.
883  return new AnalysisResultAdded(analysisResult, aggregateScore);
884 
885  } catch (TskCoreException ex) {
886  throw new BlackboardException("Failed to add analysis result.", ex);
887  }
888  }
889 
905 
906  CaseDbTransaction transaction = this.caseDb.beginTransaction();
907  try {
908  Score score = deleteAnalysisResult(analysisResult, transaction);
909  transaction.commit();
910  transaction = null;
911 
912  return score;
913  } finally {
914  if (transaction != null) {
915  transaction.rollback();
916  }
917  }
918  }
919 
933  public Score deleteAnalysisResult(long artifactObjId, CaseDbTransaction transaction) throws TskCoreException {
934 
935  List<AnalysisResult> analysisResults = getAnalysisResultsWhere(" artifacts.artifact_obj_id = " + artifactObjId, transaction.getConnection());
936 
937  if (analysisResults.isEmpty()) {
938  throw new TskCoreException(String.format("Analysis Result not found for artifact obj id %d", artifactObjId));
939  }
940 
941  return deleteAnalysisResult(analysisResults.get(0), transaction);
942  }
943 
957  private Score deleteAnalysisResult(AnalysisResult analysisResult, CaseDbTransaction transaction) throws TskCoreException {
958 
959  try {
960  CaseDbConnection connection = transaction.getConnection();
961 
962  // delete the blackboard artifacts row. This will also delete the tsk_analysis_result row
963  String deleteSQL = "DELETE FROM blackboard_artifacts WHERE artifact_obj_id = ?";
964 
965  PreparedStatement deleteStatement = connection.getPreparedStatement(deleteSQL, Statement.RETURN_GENERATED_KEYS);
966  deleteStatement.clearParameters();
967  deleteStatement.setLong(1, analysisResult.getId());
968 
969  deleteStatement.executeUpdate();
970 
971  // register the deleted result with the transaction so an event can be fired for it.
972  transaction.registerDeletedAnalysisResult(analysisResult.getObjectID());
973 
974  return caseDb.getScoringManager().updateAggregateScoreAfterDeletion(analysisResult.getObjectID(), analysisResult.getDataSourceObjectID(), transaction);
975 
976  } catch (SQLException ex) {
977  throw new TskCoreException(String.format("Error deleting analysis result with artifact obj id %d", analysisResult.getId()), ex);
978  }
979  }
980 
981  private final static String ANALYSIS_RESULT_QUERY_STRING_GENERIC = "SELECT DISTINCT artifacts.artifact_id AS artifact_id, " //NON-NLS
982  + " artifacts.obj_id AS obj_id, artifacts.artifact_obj_id AS artifact_obj_id, artifacts.data_source_obj_id AS data_source_obj_id, artifacts.artifact_type_id AS artifact_type_id, "
983  + " types.type_name AS type_name, types.display_name AS display_name, types.category_type as category_type,"//NON-NLS
984  + " artifacts.review_status_id AS review_status_id, " //NON-NLS
985  + " results.conclusion AS conclusion, results.significance AS significance, results.priority AS priority, "
986  + " results.configuration AS configuration, results.justification AS justification "
987  + " FROM blackboard_artifacts AS artifacts "
988  + " JOIN blackboard_artifact_types AS types " //NON-NLS
989  + " ON artifacts.artifact_type_id = types.artifact_type_id" //NON-NLS
990  + " LEFT JOIN tsk_analysis_results AS results "
991  + " ON artifacts.artifact_obj_id = results.artifact_obj_id "; //NON-NLS
992 
993  private final static String ANALYSIS_RESULT_QUERY_STRING_WITH_ATTRIBUTES
994  = ANALYSIS_RESULT_QUERY_STRING_GENERIC
995  + " JOIN blackboard_attributes AS attributes " //NON-NLS
996  + " ON artifacts.artifact_id = attributes.artifact_id " //NON-NLS
997  + " WHERE types.category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID(); // NON-NLS
998 
999  private final static String ANALYSIS_RESULT_QUERY_STRING_WHERE
1000  = ANALYSIS_RESULT_QUERY_STRING_GENERIC
1001  + " WHERE artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
1002  + " AND types.category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID(); // NON-NLS
1003 
1014  public List<AnalysisResult> getAnalysisResultsByType(int artifactTypeId) throws TskCoreException {
1015  return getAnalysisResultsWhere(" artifacts.artifact_type_id = " + artifactTypeId);
1016  }
1017 
1029  public List<AnalysisResult> getAnalysisResultsByType(int artifactTypeId, long dataSourceObjId) throws TskCoreException {
1030  return getAnalysisResultsWhere(" artifacts.artifact_type_id = " + artifactTypeId + " AND artifacts.data_source_obj_id = " + dataSourceObjId);
1031  }
1032 
1046  public List<AnalysisResult> getAnalysisResults(long dataSourceObjId, Integer artifactTypeID) throws TskCoreException {
1048  try (CaseDbConnection connection = caseDb.getConnection()) {
1049  String whereClause = " artifacts.data_source_obj_id = " + dataSourceObjId;
1050  if (artifactTypeID != null) {
1051  whereClause += " AND artifacts.artifact_type_id = " + artifactTypeID;
1052  }
1053  return getAnalysisResultsWhere(whereClause, connection);
1054  } finally {
1056  }
1057  }
1058 
1069  public List<AnalysisResult> getAnalysisResults(long sourceObjId) throws TskCoreException {
1070  return getAnalysisResultsWhere(" artifacts.obj_id = " + sourceObjId);
1071  }
1072 
1083  List<DataArtifact> getDataArtifactsBySource(long sourceObjId) throws TskCoreException {
1085  try (CaseDbConnection connection = caseDb.getConnection()) {
1086  return getDataArtifactsWhere(String.format(" artifacts.obj_id = %d", sourceObjId), connection);
1087  } finally {
1089  }
1090  }
1091 
1101  public boolean hasDataArtifacts(long sourceObjId) throws TskCoreException {
1102  return hasArtifactsOfCategory(BlackboardArtifact.Category.DATA_ARTIFACT, sourceObjId);
1103  }
1104 
1115  public boolean hasAnalysisResults(long sourceObjId) throws TskCoreException {
1116  return hasArtifactsOfCategory(BlackboardArtifact.Category.ANALYSIS_RESULT, sourceObjId);
1117  }
1118 
1131  private boolean hasArtifactsOfCategory(BlackboardArtifact.Category category, long sourceObjId) throws TskCoreException {
1132  String queryString = "SELECT COUNT(*) AS count " //NON-NLS
1133  + " FROM blackboard_artifacts AS arts "
1134  + " JOIN blackboard_artifact_types AS types " //NON-NLS
1135  + " ON arts.artifact_type_id = types.artifact_type_id" //NON-NLS
1136  + " WHERE types.category_type = " + category.getID()
1137  + " AND arts.obj_id = " + sourceObjId;
1138 
1140  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
1141  Statement statement = connection.createStatement();
1142  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
1143  if (resultSet.next()) {
1144  return resultSet.getLong("count") > 0;
1145  }
1146  return false;
1147  } catch (SQLException ex) {
1148  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
1149  } finally {
1151  }
1152  }
1153 
1166  List<AnalysisResult> getAnalysisResults(long sourceObjId, CaseDbConnection connection) throws TskCoreException {
1167  return getAnalysisResultsWhere(" artifacts.obj_id = " + sourceObjId, connection);
1168  }
1169 
1181  public List<AnalysisResult> getAnalysisResults(long sourceObjId, int artifactTypeId) throws TskCoreException {
1182  // Get the artifact type to check that it in the analysis result category.
1183  BlackboardArtifact.Type artifactType = getArtifactType(artifactTypeId);
1184  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
1185  throw new TskCoreException(String.format("Artifact type id %d is not in analysis result catgeory.", artifactTypeId));
1186  }
1187 
1188  String whereClause = " types.artifact_type_id = " + artifactTypeId
1189  + " AND artifacts.obj_id = " + sourceObjId;
1190  return getAnalysisResultsWhere(whereClause);
1191  }
1192 
1204  public List<AnalysisResult> getAnalysisResultsWhere(String whereClause) throws TskCoreException {
1206  try (CaseDbConnection connection = caseDb.getConnection()) {
1207  return getAnalysisResultsWhere(whereClause, connection);
1208  } finally {
1210  }
1211  }
1212 
1225  List<AnalysisResult> getAnalysisResultsWhere(String whereClause, CaseDbConnection connection) throws TskCoreException {
1226 
1227  final String queryString = ANALYSIS_RESULT_QUERY_STRING_WHERE
1228  + " AND " + whereClause;
1229 
1230  try (Statement statement = connection.createStatement();
1231  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
1232 
1233  List<AnalysisResult> analysisResults = resultSetToAnalysisResults(resultSet);
1234  return analysisResults;
1235  } catch (SQLException ex) {
1236  throw new TskCoreException(String.format("Error getting analysis results for WHERE clause = '%s'", whereClause), ex);
1237  }
1238  }
1239 
1249  public AnalysisResult getAnalysisResultById(long artifactObjId) throws TskCoreException {
1250 
1251  String whereClause = " artifacts.artifact_obj_id = " + artifactObjId;
1252  List<AnalysisResult> results = getAnalysisResultsWhere(whereClause);
1253 
1254  if (results.isEmpty()) { // throw an error if no analysis result found by id.
1255  throw new TskCoreException(String.format("Error getting analysis result with id = '%d'", artifactObjId));
1256  }
1257  if (results.size() > 1) { // should not happen - throw an error
1258  throw new TskCoreException(String.format("Multiple analysis results found with id = '%d'", artifactObjId));
1259  }
1260 
1261  return results.get(0);
1262  }
1263 
1279  private List<AnalysisResult> resultSetToAnalysisResults(ResultSet resultSet) throws SQLException, TskCoreException {
1280  ArrayList<AnalysisResult> analysisResults = new ArrayList<>();
1281 
1282  while (resultSet.next()) {
1283  analysisResults.add(new AnalysisResult(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
1284  resultSet.getLong("artifact_obj_id"),
1285  resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
1286  resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
1287  BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")),
1288  new Score(Score.Significance.fromID(resultSet.getInt("significance")), Score.Priority.fromID(resultSet.getInt("priority"))),
1289  resultSet.getString("conclusion"), resultSet.getString("configuration"), resultSet.getString("justification")));
1290  } //end for each resultSet
1291 
1292  return analysisResults;
1293  }
1294 
1295  private final static String DATA_ARTIFACT_QUERY_STRING_GENERIC = "SELECT DISTINCT artifacts.artifact_id AS artifact_id, " //NON-NLS
1296  + "artifacts.obj_id AS obj_id, artifacts.artifact_obj_id AS artifact_obj_id, artifacts.data_source_obj_id AS data_source_obj_id, artifacts.artifact_type_id AS artifact_type_id, " //NON-NLS
1297  + " types.type_name AS type_name, types.display_name AS display_name, types.category_type as category_type,"//NON-NLS
1298  + " artifacts.review_status_id AS review_status_id, " //NON-NLS
1299  + " data_artifacts.os_account_obj_id as os_account_obj_id " //NON-NLS
1300  + " FROM blackboard_artifacts AS artifacts " //NON-NLS
1301  + " JOIN blackboard_artifact_types AS types " //NON-NLS
1302  + " ON artifacts.artifact_type_id = types.artifact_type_id" //NON-NLS
1303  + " LEFT JOIN tsk_data_artifacts AS data_artifacts " //NON-NLS
1304  + " ON artifacts.artifact_obj_id = data_artifacts.artifact_obj_id "; //NON-NLS
1305 
1306  private final static String DATA_ARTIFACT_QUERY_STRING_WITH_ATTRIBUTES
1307  = DATA_ARTIFACT_QUERY_STRING_GENERIC
1308  + " JOIN blackboard_attributes AS attributes " //NON-NLS
1309  + " ON artifacts.artifact_id = attributes.artifact_id " //NON-NLS
1310  + " WHERE types.category_type = " + BlackboardArtifact.Category.DATA_ARTIFACT.getID(); // NON-NLS
1311 
1312  private final static String DATA_ARTIFACT_QUERY_STRING_WHERE
1313  = DATA_ARTIFACT_QUERY_STRING_GENERIC
1314  + " WHERE artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
1315  + " AND types.category_type = " + BlackboardArtifact.Category.DATA_ARTIFACT.getID(); // NON-NLS
1316 
1329  public List<DataArtifact> getDataArtifacts(long dataSourceObjId, Integer artifactTypeID) throws TskCoreException {
1331  try (CaseDbConnection connection = caseDb.getConnection()) {
1332  String whereClause = " artifacts.data_source_obj_id = " + dataSourceObjId;
1333  if (artifactTypeID != null) {
1334  whereClause += " AND artifacts.artifact_type_id = " + artifactTypeID;
1335  }
1336  return getDataArtifactsWhere(whereClause, connection);
1337  } finally {
1339  }
1340  }
1341 
1353  public List<DataArtifact> getDataArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
1354 
1355  // Get the artifact type to check that it in the data artifact category.
1356  BlackboardArtifact.Type artifactType = getArtifactType(artifactTypeID);
1357  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
1358  throw new TskCoreException(String.format("Artifact type id %d is not in data artifact catgeory.", artifactTypeID));
1359  }
1360 
1362  try (CaseDbConnection connection = caseDb.getConnection()) {
1363  String whereClause = "artifacts.data_source_obj_id = " + dataSourceObjId
1364  + " AND artifacts.artifact_type_id = " + artifactTypeID;
1365 
1366  return getDataArtifactsWhere(whereClause, connection);
1367  } finally {
1369  }
1370  }
1371 
1382  public List<DataArtifact> getDataArtifacts(int artifactTypeID) throws TskCoreException {
1383  // Get the artifact type to check that it in the data artifact category.
1384  BlackboardArtifact.Type artifactType = getArtifactType(artifactTypeID);
1385  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
1386  throw new TskCoreException(String.format("Artifact type id %d is not in data artifact catgeory.", artifactTypeID));
1387  }
1388 
1390  try (CaseDbConnection connection = caseDb.getConnection()) {
1391  String whereClause = " artifacts.artifact_type_id = " + artifactTypeID;
1392 
1393  return getDataArtifactsWhere(whereClause, connection);
1394  } finally {
1396  }
1397  }
1398 
1409  public DataArtifact getDataArtifactById(long artifactObjId) throws TskCoreException {
1411  try (CaseDbConnection connection = caseDb.getConnection()) {
1412  String whereClause = " artifacts.artifact_obj_id = " + artifactObjId;
1413 
1414  List<DataArtifact> artifacts = getDataArtifactsWhere(whereClause, connection);
1415  if (artifacts.isEmpty()) { // throw an error if no analysis result found by id.
1416  throw new TskCoreException(String.format("Error getting data artifact with id = '%d'", artifactObjId));
1417  }
1418  if (artifacts.size() > 1) { // should not happen - throw an error
1419  throw new TskCoreException(String.format("Multiple data artifacts found with id = '%d'", artifactObjId));
1420  }
1421 
1422  return artifacts.get(0);
1423  } finally {
1425  }
1426  }
1427 
1438  public List<DataArtifact> getDataArtifactsWhere(String whereClause) throws TskCoreException {
1440  try (CaseDbConnection connection = caseDb.getConnection()) {
1441  return getDataArtifactsWhere(whereClause, connection);
1442  } finally {
1444  }
1445  }
1446 
1459  List<DataArtifact> getDataArtifactsWhere(String whereClause, CaseDbConnection connection) throws TskCoreException {
1460 
1461  final String queryString = DATA_ARTIFACT_QUERY_STRING_WHERE
1462  + " AND " + whereClause + " ";
1463 
1464  try (Statement statement = connection.createStatement();
1465  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
1466 
1467  List<DataArtifact> dataArtifacts = resultSetToDataArtifacts(resultSet);
1468  return dataArtifacts;
1469  } catch (SQLException ex) {
1470  throw new TskCoreException(String.format("Error getting data artifacts with queryString = %s", queryString), ex);
1471  }
1472  }
1473 
1489  private List<DataArtifact> resultSetToDataArtifacts(ResultSet resultSet) throws SQLException, TskCoreException {
1490  ArrayList<DataArtifact> dataArtifacts = new ArrayList<>();
1491 
1492  while (resultSet.next()) {
1493 
1494  Long osAccountObjId = resultSet.getLong("os_account_obj_id");
1495  if (resultSet.wasNull()) {
1496  osAccountObjId = null;
1497  }
1498 
1499  dataArtifacts.add(new DataArtifact(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
1500  resultSet.getLong("artifact_obj_id"),
1501  resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
1502  resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
1503  BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")), osAccountObjId, false));
1504  } //end for each resultSet
1505 
1506  return dataArtifacts;
1507  }
1508 
1526  public synchronized BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException {
1527  // check local cache
1528  if (typeNameToAttributeTypeMap.containsKey(typeName)) {
1529  return typeNameToAttributeTypeMap.get(typeName);
1530  }
1531 
1532  CaseDbTransaction trans = null;
1533  try {
1534  trans = this.caseDb.beginTransaction();
1535  String matchingAttrQuery = "SELECT attribute_type_id, type_name, display_name, value_type "
1536  + "FROM blackboard_attribute_types WHERE type_name = ?";
1537  // find matching attribute name
1538  PreparedStatement query = trans.getConnection().getPreparedStatement(matchingAttrQuery, Statement.RETURN_GENERATED_KEYS);
1539  query.clearParameters();
1540  query.setString(1, typeName);
1541  try (ResultSet rs = query.executeQuery()) {
1542  // if previously existing, commit the results and return the attribute type
1543  if (rs.next()) {
1544  trans.commit();
1545  trans = null;
1547  rs.getInt("attribute_type_id"),
1548  rs.getString("type_name"),
1549  rs.getString("display_name"),
1551  );
1552 
1553  this.typeIdToAttributeTypeMap.put(foundType.getTypeID(), foundType);
1554  this.typeNameToAttributeTypeMap.put(foundType.getTypeName(), foundType);
1555 
1556  return foundType;
1557  }
1558  }
1559 
1560  // if not found in database, insert
1561  String insertStatement = "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES (\n"
1562  // get the maximum of the attribute type id's or the min user defined type id and add 1 to it for the new id
1563  + "(SELECT MAX(q.attribute_type_id) FROM (SELECT attribute_type_id FROM blackboard_attribute_types UNION SELECT " + (MIN_USER_DEFINED_TYPE_ID - 1) + ") q) + 1,\n"
1564  // typeName, displayName, valueType
1565  + "?, ?, ?)";
1566 
1567  PreparedStatement insertPreparedStatement = trans.getConnection().getPreparedStatement(insertStatement, Statement.RETURN_GENERATED_KEYS);
1568  insertPreparedStatement.clearParameters();
1569  insertPreparedStatement.setString(1, typeName);
1570  insertPreparedStatement.setString(2, displayName);
1571  insertPreparedStatement.setLong(3, valueType.getType());
1572 
1573  int numUpdated = insertPreparedStatement.executeUpdate();
1574 
1575  // get id for inserted to create new attribute.
1576  Integer attrId = null;
1577 
1578  if (numUpdated > 0) {
1579  try (ResultSet insertResult = insertPreparedStatement.getGeneratedKeys()) {
1580  if (insertResult.next()) {
1581  attrId = insertResult.getInt(1);
1582  }
1583  }
1584  }
1585 
1586  if (attrId == null) {
1587  throw new BlackboardException(MessageFormat.format(
1588  "Error adding attribute type. Item with name {0} was not inserted successfully into the database.", typeName));
1589  }
1590 
1591  trans.commit();
1592  trans = null;
1593 
1594  BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrId, typeName, displayName, valueType);
1595  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
1596  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
1597  return type;
1598  } catch (SQLException | TskCoreException ex) {
1599  throw new BlackboardException("Error adding attribute type: " + typeName, ex);
1600  } finally {
1601  try {
1602  if (trans != null) {
1603  trans.rollback();
1604  trans = null;
1605  }
1606  } catch (TskCoreException ex2) {
1607  LOGGER.log(Level.SEVERE, "Error rolling back transaction", ex2);
1608  }
1609  }
1610  }
1611 
1623  public List<BlackboardArtifact.Type> getArtifactTypesInUse(long dataSourceObjId) throws TskCoreException {
1624 
1625  final String queryString = "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
1626  + "types.type_name AS type_name, "
1627  + "types.display_name AS display_name, "
1628  + "types.category_type AS category_type "
1629  + "FROM blackboard_artifact_types AS types "
1630  + "INNER JOIN blackboard_artifacts AS arts "
1631  + "ON arts.artifact_type_id = types.artifact_type_id "
1632  + "WHERE arts.data_source_obj_id = " + dataSourceObjId;
1633 
1635  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
1636  Statement statement = connection.createStatement();
1637  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
1638 
1639  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<>();
1640  while (resultSet.next()) {
1641  uniqueArtifactTypes.add(new BlackboardArtifact.Type(resultSet.getInt("artifact_type_id"),
1642  resultSet.getString("type_name"), resultSet.getString("display_name"),
1643  BlackboardArtifact.Category.fromID(resultSet.getInt("category_type"))));
1644  }
1645  return uniqueArtifactTypes;
1646  } catch (SQLException ex) {
1647  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
1648  } finally {
1650  }
1651  }
1652 
1665  public long getArtifactsCount(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
1666  return getArtifactsCountHelper(artifactTypeID,
1667  "blackboard_artifacts.data_source_obj_id = '" + dataSourceObjId + "';");
1668  }
1669 
1681  public long getArtifactsCount(int artifactTypeID) throws TskCoreException {
1682  return getArtifactsCountHelper(artifactTypeID, null);
1683  }
1684 
1697  public List<BlackboardArtifact> getArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
1698  String whereClause = String.format("artifacts.data_source_obj_id = %d", dataSourceObjId);
1699  return getArtifactsWhere(getArtifactType(artifactTypeID), whereClause);
1700  }
1701 
1714  public List<BlackboardArtifact> getArtifacts(Collection<BlackboardArtifact.Type> artifactTypes,
1715  Collection<Long> dataSourceObjIds) throws TskCoreException {
1716 
1717  if (artifactTypes.isEmpty() || dataSourceObjIds.isEmpty()) {
1718  return new ArrayList<>();
1719  }
1720 
1721  String analysisResultQuery = "";
1722  String dataArtifactQuery = "";
1723 
1724  for (BlackboardArtifact.Type type : artifactTypes) {
1725  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
1726  if (!analysisResultQuery.isEmpty()) {
1727  analysisResultQuery += " OR ";
1728  }
1729  analysisResultQuery += "types.artifact_type_id = " + type.getTypeID();
1730  } else {
1731  if (!dataArtifactQuery.isEmpty()) {
1732  dataArtifactQuery += " OR ";
1733  }
1734  dataArtifactQuery += "types.artifact_type_id = " + type.getTypeID();
1735  }
1736  }
1737 
1738  String dsQuery = "";
1739  for (long dsId : dataSourceObjIds) {
1740  if (!dsQuery.isEmpty()) {
1741  dsQuery += " OR ";
1742  }
1743  dsQuery += "artifacts.data_source_obj_id = " + dsId;
1744  }
1745 
1746  List<BlackboardArtifact> artifacts = new ArrayList<>();
1747 
1748  if (!analysisResultQuery.isEmpty()) {
1749  String fullQuery = "( " + analysisResultQuery + " ) AND (" + dsQuery + ") ";
1750  artifacts.addAll(this.getAnalysisResultsWhere(fullQuery));
1751  }
1752 
1753  if (!dataArtifactQuery.isEmpty()) {
1754  String fullQuery = "( " + dataArtifactQuery + " ) AND (" + dsQuery + ") ";
1755  artifacts.addAll(this.getDataArtifactsWhere(fullQuery));
1756  }
1757 
1758  return artifacts;
1759  }
1760 
1777  public List<BlackboardArtifact> getArtifacts(BlackboardArtifact.Type artifactType,
1778  BlackboardAttribute.Type attributeType, String value, Long dataSourceObjId,
1779  boolean showRejected) throws TskCoreException {
1780 
1781  String query = " AND artifacts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
1782  + " AND attributes.attribute_type_id = " + attributeType.getTypeID() //NON-NLS
1783  + ((value == null || value.isEmpty()) ? "" : " AND attributes.value_text = '" + value + "'") //NON-NLS
1784  + (showRejected ? "" : " AND artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()) //NON-NLS
1785  + (dataSourceObjId != null ? " AND artifacts.data_source_obj_id = " + dataSourceObjId : ""); //NON-NLS
1786 
1787  List<BlackboardArtifact> artifacts = new ArrayList<>();
1789 
1790  String finalQuery = (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT
1791  ? ANALYSIS_RESULT_QUERY_STRING_WITH_ATTRIBUTES + query
1792  : DATA_ARTIFACT_QUERY_STRING_WITH_ATTRIBUTES + query);
1793 
1794  try (CaseDbConnection connection = caseDb.getConnection()) {
1795  try (Statement statement = connection.createStatement();
1796  ResultSet resultSet = connection.executeQuery(statement, finalQuery);) {
1797 
1798  if (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
1799  artifacts.addAll(resultSetToAnalysisResults(resultSet));
1800  } else {
1801  artifacts.addAll(resultSetToDataArtifacts(resultSet));
1802  }
1803  } catch (SQLException ex) {
1804  throw new TskCoreException(String.format("Error getting results with queryString = '%s'", finalQuery), ex);
1805  }
1806  } finally {
1808  }
1809  return artifacts;
1810  }
1811 
1833  public List<BlackboardArtifact> getExactMatchKeywordSearchResults(String keyword, TskData.KeywordSearchQueryType searchType, String kwsListName, Long dataSourceId) throws TskCoreException {
1834  return getKeywordSearchResults(keyword, "", searchType, kwsListName, dataSourceId);
1835  }
1836 
1862  public List<BlackboardArtifact> getKeywordSearchResults(String keyword, String regex, TskData.KeywordSearchQueryType searchType, String kwsListName, Long dataSourceId) throws TskCoreException {
1863 
1864  String dataSourceClause = dataSourceId == null
1865  ? ""
1866  : " AND artifacts.data_source_obj_id = ? "; // dataSourceId
1867 
1868  String kwsListClause = (kwsListName == null || kwsListName.isEmpty()
1869  ? " WHERE r.set_name IS NULL "
1870  : " WHERE r.set_name = ? ");
1871 
1872  String keywordClause = (keyword == null || keyword.isEmpty()
1873  ? ""
1874  : " AND r.keyword = ? ");
1875 
1876  String searchTypeClause = (searchType == null
1877  ? ""
1878  : " AND r.search_type = ? ");
1879 
1880  String regexClause = (regex == null || regex.isEmpty()
1881  ? ""
1882  : " AND r.regexp_str = ? ");
1883 
1884  String query = "SELECT r.* FROM ( "
1885  + " SELECT DISTINCT artifacts.artifact_id AS artifact_id, "
1886  + " artifacts.obj_id AS obj_id, "
1887  + " artifacts.artifact_obj_id AS artifact_obj_id, "
1888  + " artifacts.data_source_obj_id AS data_source_obj_id, "
1889  + " artifacts.artifact_type_id AS artifact_type_id, "
1890  + " types.type_name AS type_name, "
1891  + " types.display_name AS display_name, "
1892  + " types.category_type as category_type,"
1893  + " artifacts.review_status_id AS review_status_id, "
1894  + " results.conclusion AS conclusion, "
1895  + " results.significance AS significance, "
1896  + " results.priority AS priority, "
1897  + " results.configuration AS configuration, "
1898  + " results.justification AS justification, "
1899  + " (SELECT value_text FROM blackboard_attributes attr WHERE attr.artifact_id = artifacts.artifact_id AND attr.attribute_type_id = "
1900  + BlackboardAttribute.Type.TSK_SET_NAME.getTypeID() + " LIMIT 1) AS set_name, "
1901  + " (SELECT value_int32 FROM blackboard_attributes attr WHERE attr.artifact_id = artifacts.artifact_id AND attr.attribute_type_id = "
1902  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID() + " LIMIT 1) AS search_type, "
1903  + " (SELECT value_text FROM blackboard_attributes attr WHERE attr.artifact_id = artifacts.artifact_id AND attr.attribute_type_id = "
1904  + BlackboardAttribute.Type.TSK_KEYWORD_REGEXP.getTypeID() + " LIMIT 1) AS regexp_str, "
1905  + " (SELECT value_text FROM blackboard_attributes attr WHERE attr.artifact_id = artifacts.artifact_id AND attr.attribute_type_id = "
1906  + BlackboardAttribute.Type.TSK_KEYWORD.getTypeID() + " LIMIT 1) AS keyword "
1907  + " FROM blackboard_artifacts artifacts "
1908  + " JOIN blackboard_artifact_types AS types "
1909  + " ON artifacts.artifact_type_id = types.artifact_type_id "
1910  + " LEFT JOIN tsk_analysis_results AS results "
1911  + " ON artifacts.artifact_obj_id = results.artifact_obj_id "
1912  + " WHERE types.category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
1913  + " AND artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID() + " "
1914  + dataSourceClause + " ) r "
1915  + kwsListClause
1916  + keywordClause
1917  + searchTypeClause
1918  + regexClause;
1919 
1920  List<BlackboardArtifact> artifacts = new ArrayList<>();
1922  try (CaseDbConnection connection = caseDb.getConnection()) {
1923 
1924  try {
1925  PreparedStatement preparedStatement = connection.getPreparedStatement(query, Statement.RETURN_GENERATED_KEYS);
1926  preparedStatement.clearParameters();
1927  int paramIdx = 0;
1928  if (dataSourceId != null) {
1929  preparedStatement.setLong(++paramIdx, dataSourceId);
1930  }
1931 
1932  if (!(kwsListName == null || kwsListName.isEmpty())) {
1933  preparedStatement.setString(++paramIdx, kwsListName);
1934  }
1935 
1936  if (!(keyword == null || keyword.isEmpty())) {
1937  preparedStatement.setString(++paramIdx, keyword);
1938  }
1939 
1940  if (searchType != null) {
1941  preparedStatement.setInt(++paramIdx, searchType.getType());
1942  }
1943 
1944  if (!(regex == null || regex.isEmpty())) {
1945  preparedStatement.setString(++paramIdx, regex);
1946  }
1947 
1948  try (ResultSet resultSet = connection.executeQuery(preparedStatement)) {
1949  artifacts.addAll(resultSetToAnalysisResults(resultSet));
1950  }
1951 
1952  } catch (SQLException ex) {
1953  throw new TskCoreException(String.format("Error getting keyword search results with queryString = '%s'", query), ex);
1954  }
1955  } finally {
1957  }
1958  return artifacts;
1959  }
1960 
1974  private long getArtifactsCountHelper(int artifactTypeID, String whereClause) throws TskCoreException {
1975  String queryString = "SELECT COUNT(*) AS count FROM blackboard_artifacts "
1976  + "WHERE blackboard_artifacts.artifact_type_id = " + artifactTypeID
1977  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID();
1978 
1979  if (whereClause != null) {
1980  queryString += " AND " + whereClause;
1981  }
1982 
1984  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
1985  Statement statement = connection.createStatement();
1986  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
1987  long count = 0;
1988  if (resultSet.next()) {
1989  count = resultSet.getLong("count");
1990  }
1991  return count;
1992  } catch (SQLException ex) {
1993  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
1994  } finally {
1996  }
1997  }
1998 
2012  public boolean artifactExists(Content content, BlackboardArtifact.Type artifactType, Collection<BlackboardAttribute> attributes) throws TskCoreException {
2013  List<BlackboardArtifact> existingArtifacts = content.getArtifacts(artifactType.getTypeID());
2014  for (BlackboardArtifact artifact : existingArtifacts) {
2015  if (attributesMatch(artifact.getAttributes(), attributes)) {
2016  return true;
2017  }
2018  }
2019  return false;
2020  }
2021 
2037  @Deprecated
2038  public boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType, Collection<BlackboardAttribute> attributes) throws TskCoreException {
2039  return artifactExists(content, getArtifactType(artifactType.getTypeID()), attributes);
2040  }
2041 
2051  private boolean attributesMatch(Collection<BlackboardAttribute> fileAttributesList, Collection<BlackboardAttribute> expectedAttributesList) {
2052  for (BlackboardAttribute expectedAttribute : expectedAttributesList) {
2053  boolean match = false;
2054  for (BlackboardAttribute fileAttribute : fileAttributesList) {
2055  BlackboardAttribute.Type attributeType = fileAttribute.getAttributeType();
2056  if (attributeType.getTypeID() != expectedAttribute.getAttributeType().getTypeID()) {
2057  continue;
2058  }
2059 
2060  Object fileAttributeValue;
2061  Object expectedAttributeValue;
2062  switch (attributeType.getValueType()) {
2063  case BYTE:
2064  fileAttributeValue = fileAttribute.getValueBytes();
2065  expectedAttributeValue = expectedAttribute.getValueBytes();
2066  break;
2067  case DOUBLE:
2068  fileAttributeValue = fileAttribute.getValueDouble();
2069  expectedAttributeValue = expectedAttribute.getValueDouble();
2070  break;
2071  case INTEGER:
2072  fileAttributeValue = fileAttribute.getValueInt();
2073  expectedAttributeValue = expectedAttribute.getValueInt();
2074  break;
2075  case LONG: // Fall-thru
2076  case DATETIME:
2077  fileAttributeValue = fileAttribute.getValueLong();
2078  expectedAttributeValue = expectedAttribute.getValueLong();
2079  break;
2080  case STRING: // Fall-thru
2081  case JSON:
2082  fileAttributeValue = fileAttribute.getValueString();
2083  expectedAttributeValue = expectedAttribute.getValueString();
2084  break;
2085  default:
2086  fileAttributeValue = fileAttribute.getDisplayString();
2087  expectedAttributeValue = expectedAttribute.getDisplayString();
2088  break;
2089  }
2090 
2091  /*
2092  * If the exact attribute was found, mark it as a match to
2093  * continue looping through the expected attributes list.
2094  */
2095  if (fileAttributeValue instanceof byte[]) {
2096  if (Arrays.equals((byte[]) fileAttributeValue, (byte[]) expectedAttributeValue)) {
2097  match = true;
2098  break;
2099  }
2100  } else if (fileAttributeValue.equals(expectedAttributeValue)) {
2101  match = true;
2102  break;
2103  }
2104  }
2105  if (!match) {
2106  /*
2107  * The exact attribute type/value combination was not found.
2108  */
2109  return false;
2110  }
2111  }
2112 
2113  /*
2114  * All attribute type/value combinations were found in the provided
2115  * attributes list.
2116  */
2117  return true;
2118 
2119  }
2120 
2124  public static final class BlackboardException extends Exception {
2125 
2126  private static final long serialVersionUID = 1L;
2127 
2133  BlackboardException(String message) {
2134  super(message);
2135  }
2136 
2144  BlackboardException(String message, Throwable cause) {
2145  super(message, cause);
2146  }
2147  }
2148 
2165  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
2166  Collection<BlackboardAttribute> attributes, Long osAccountId) throws TskCoreException {
2167 
2168  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
2169  throw new TskCoreException(String.format("Artifact type (name = %s) is not of Data Artifact category. ", artifactType.getTypeName()));
2170  }
2171 
2172  CaseDbTransaction transaction = caseDb.beginTransaction();
2173  try {
2174  DataArtifact dataArtifact = newDataArtifact(artifactType, sourceObjId, dataSourceObjId,
2175  attributes, osAccountId, transaction);
2176  transaction.commit();
2177  return dataArtifact;
2178  } catch (TskCoreException ex) {
2179  try {
2180  transaction.rollback();
2181  } catch (TskCoreException ex2) {
2182  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception. "
2183  + "Error invoking newDataArtifact with dataSourceObjId: " + dataSourceObjId + ", sourceObjId: " + sourceObjId, ex2);
2184  }
2185  throw ex;
2186  }
2187  }
2188 
2209  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
2210  Collection<BlackboardAttribute> attributes, Long osAccountObjId, final CaseDbTransaction transaction) throws TskCoreException {
2211 
2212  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
2213  throw new TskCoreException(String.format("Artifact type (name = %s) is not of Data Artifact category. ", artifactType.getTypeName()));
2214  }
2215 
2216  try {
2217  CaseDbConnection connection = transaction.getConnection();
2218  long artifact_obj_id = caseDb.addObject(sourceObjId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
2219  PreparedStatement statement = caseDb.createInsertArtifactStatement(artifactType.getTypeID(), sourceObjId, artifact_obj_id, dataSourceObjId, connection);
2220 
2221  connection.executeUpdate(statement);
2222  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2223  resultSet.next();
2224  DataArtifact dataArtifact = new DataArtifact(caseDb, resultSet.getLong(1), //last_insert_rowid()
2225  sourceObjId, artifact_obj_id, dataSourceObjId, artifactType.getTypeID(),
2226  artifactType.getTypeName(), artifactType.getDisplayName(), BlackboardArtifact.ReviewStatus.UNDECIDED,
2227  osAccountObjId, true);
2228 
2229  // Add a row in tsk_data_artifact if the os account is present
2230  if (osAccountObjId != null) {
2231  String insertDataArtifactSQL = "INSERT INTO tsk_data_artifacts (artifact_obj_id, os_account_obj_id) VALUES (?, ?)";
2232 
2233  statement = connection.getPreparedStatement(insertDataArtifactSQL, Statement.NO_GENERATED_KEYS);
2234  statement.clearParameters();
2235 
2236  statement.setLong(1, artifact_obj_id);
2237  statement.setLong(2, osAccountObjId);
2238  connection.executeUpdate(statement);
2239 
2240  // Add an OS account instance
2241  caseDb.getOsAccountManager().newOsAccountInstance(osAccountObjId, dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, connection);
2242  }
2243 
2244  // if attributes are provided, add them to the artifact.
2245  if (Objects.nonNull(attributes) && !attributes.isEmpty()) {
2246  dataArtifact.addAttributes(attributes, transaction);
2247  }
2248 
2249  return dataArtifact;
2250  }
2251  } catch (SQLException ex) {
2252  throw new TskCoreException(String.format("Error creating a data artifact with type id = %d, objId = %d, and data source oj id = %d ", artifactType.getTypeID(), sourceObjId, dataSourceObjId), ex);
2253  }
2254  }
2255 
2267  List<BlackboardArtifact> getArtifactsBySourceId(BlackboardArtifact.Type artifactType, long sourceObjId) throws TskCoreException {
2268  String whereClause = String.format("artifacts.obj_id = %d", sourceObjId);
2269  return getArtifactsWhere(artifactType, whereClause);
2270  }
2271 
2281  List<BlackboardArtifact> getArtifactsByType(BlackboardArtifact.Type artifactType) throws TskCoreException {
2282  List<BlackboardArtifact> artifacts = new ArrayList<>();
2283  if (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
2284  artifacts.addAll(getAnalysisResultsByType(artifactType.getTypeID()));
2285  } else {
2286  artifacts.addAll(getDataArtifacts(artifactType.getTypeID()));
2287  }
2288  return artifacts;
2289  }
2290 
2308  private List<BlackboardArtifact> getArtifactsWhere(BlackboardArtifact.Type artifactType, String whereClause) throws TskCoreException {
2309  List<BlackboardArtifact> artifacts = new ArrayList<>();
2310  String whereWithType = whereClause + " AND artifacts.artifact_type_id = " + artifactType.getTypeID();
2311 
2312  if (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
2313  artifacts.addAll(getAnalysisResultsWhere(whereWithType));
2314  } else {
2315  artifacts.addAll(getDataArtifactsWhere(whereWithType));
2316  }
2317 
2318  return artifacts;
2319  }
2320 
2326  final public class ArtifactsPostedEvent {
2327 
2328  private final String moduleName;
2329  private final ImmutableSet<BlackboardArtifact.Type> artifactTypes;
2330  private final ImmutableSet<BlackboardArtifact> artifacts;
2331  private final Long ingestJobId;
2332 
2344  private ArtifactsPostedEvent(Collection<BlackboardArtifact> artifacts, String moduleName, Long ingestJobId) throws BlackboardException {
2345  Set<Integer> typeIDS = artifacts.stream()
2347  .collect(Collectors.toSet());
2348  Set<BlackboardArtifact.Type> types = new HashSet<>();
2349  for (Integer typeID : typeIDS) {
2350  try {
2351  types.add(getArtifactType(typeID));
2352  } catch (TskCoreException tskCoreException) {
2353  throw new BlackboardException("Error getting artifact type by id.", tskCoreException);
2354  }
2355  }
2356  artifactTypes = ImmutableSet.copyOf(types);
2357  this.artifacts = ImmutableSet.copyOf(artifacts);
2358  this.moduleName = moduleName;
2359  this.ingestJobId = ingestJobId;
2360  }
2361 
2367  public Collection<BlackboardArtifact> getArtifacts() {
2368  return ImmutableSet.copyOf(artifacts);
2369  }
2370 
2378  public Collection<BlackboardArtifact> getArtifacts(BlackboardArtifact.Type artifactType) {
2379  Set<BlackboardArtifact> tempSet = artifacts.stream()
2380  .filter(artifact -> artifact.getArtifactTypeID() == artifactType.getTypeID())
2381  .collect(Collectors.toSet());
2382  return ImmutableSet.copyOf(tempSet);
2383  }
2384 
2390  public String getModuleName() {
2391  return moduleName;
2392  }
2393 
2400  return ImmutableSet.copyOf(artifactTypes);
2401  }
2402 
2409  public Optional<Long> getIngestJobId() {
2410  return Optional.ofNullable(ingestJobId);
2411  }
2412 
2413  }
2414 }
static Priority fromID(int id)
Definition: Score.java:184
List< BlackboardArtifact > getArtifacts(Collection< BlackboardArtifact.Type > artifactTypes, Collection< Long > dataSourceObjIds)
static Significance fromID(int id)
Definition: Score.java:118
AnalysisResult getAnalysisResultById(long artifactObjId)
void postArtifact(BlackboardArtifact artifact, String moduleName)
Definition: Blackboard.java:99
List< DataArtifact > getDataArtifacts(int artifactTypeID, long dataSourceObjId)
List< DataArtifact > getDataArtifacts(long dataSourceObjId, Integer artifactTypeID)
boolean hasAnalysisResults(long sourceObjId)
void postArtifacts(Collection< BlackboardArtifact > artifacts, String moduleName)
void addAttributes(Collection< BlackboardAttribute > attributes)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountId)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
DataArtifact getDataArtifactById(long artifactObjId)
Collection< BlackboardArtifact > getArtifacts()
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName, BlackboardArtifact.Category category)
Score deleteAnalysisResult(AnalysisResult analysisResult)
void postArtifacts(Collection< BlackboardArtifact > artifacts, String moduleName, Long ingestJobId)
List< AnalysisResult > getAnalysisResults(long sourceObjId)
Collection< BlackboardArtifact > getArtifacts(BlackboardArtifact.Type artifactType)
List< BlackboardArtifact > getExactMatchKeywordSearchResults(String keyword, TskData.KeywordSearchQueryType searchType, String kwsListName, Long dataSourceId)
List< DataArtifact > getDataArtifacts(int artifactTypeID)
List< AnalysisResult > getAnalysisResults(long dataSourceObjId, Integer artifactTypeID)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList, CaseDbTransaction transaction)
List< AnalysisResult > getAnalysisResultsWhere(String whereClause)
List< BlackboardArtifact > getArtifacts(int artifactTypeID, long dataSourceObjId)
synchronized BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
Score deleteAnalysisResult(long artifactObjId, CaseDbTransaction transaction)
boolean artifactExists(Content content, BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributes)
BlackboardArtifact.Type getArtifactType(String artTypeName)
List< AnalysisResult > getAnalysisResults(long sourceObjId, int artifactTypeId)
OsAccountInstance newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType)
void postArtifact(BlackboardArtifact artifact, String moduleName, Long ingestJobId)
List< BlackboardArtifact > getArtifacts(BlackboardArtifact.Type artifactType, BlackboardAttribute.Type attributeType, String value, Long dataSourceObjId, boolean showRejected)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountObjId, final CaseDbTransaction transaction)
List< AnalysisResult > getAnalysisResultsByType(int artifactTypeId, long dataSourceObjId)
Collection< BlackboardArtifact.Type > getArtifactTypes()
List< DataArtifact > getDataArtifactsWhere(String whereClause)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName)
boolean hasDataArtifacts(long sourceObjId)
List< BlackboardArtifact > getKeywordSearchResults(String keyword, String regex, TskData.KeywordSearchQueryType searchType, String kwsListName, Long dataSourceId)
long getArtifactsCount(int artifactTypeID, long dataSourceObjId)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
List< BlackboardArtifact.Type > getArtifactTypesInUse(long dataSourceObjId)
boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType, Collection< BlackboardAttribute > attributes)
BlackboardArtifact.Type getArtifactType(int artTypeId)
long getArtifactsCount(int artifactTypeID)
List< AnalysisResult > getAnalysisResultsByType(int artifactTypeId)

Copyright © 2011-2021 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.