diff --git a/bindings/java/src/org/sleuthkit/datamodel/AnalysisResult.java b/bindings/java/src/org/sleuthkit/datamodel/AnalysisResult.java
index 2a3c629ea4840c0d0ed77ff728f98c9b2dffcc40..59b715e82887fc10604cf0ce9cdbc9bf2d13224f 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/AnalysisResult.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/AnalysisResult.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2020 Basis Technology Corp.
+ * Copyright 2020-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,7 +32,28 @@ public class AnalysisResult extends BlackboardArtifact {
 
 	private boolean ignoreResult = false; // ignore this analysis result when computing score of the parent object.
 
-	AnalysisResult( SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjId, long dataSourceObjId, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, Score score, String conclusion, String configuration, String justification) {
+	/**
+	 * Constructs an analysis result. 
+	 *
+	 * @param sleuthkitCase    The SleuthKit case (case database) that contains
+	 *                         the artifact data.
+	 * @param artifactID       The unique id for this artifact.
+	 * @param sourceObjId      The unique id of the content with which this
+	 *                         artifact is associated.
+	 * @param artifactObjId    The unique id this artifact, in tsk_objects.
+	 * @param dataSourceObjId  Object ID of the datasource where the artifact
+	 *                         was found. May be null.
+	 * @param artifactTypeID   The type id of this artifact.
+	 * @param artifactTypeName The type name of this artifact.
+	 * @param displayName      The display name of this artifact.
+	 * @param reviewStatus     The review status of this artifact.
+	 * @param score            The score assigned by the analysis.
+	 * @param conclusion       Conclusion arrived at by the analysis. May be
+	 *                         null.
+	 * @param configuration    Configuration used for analysis. May be null.
+	 * @param justification	   Justification for the analysis. May be null.
+	 */
+	AnalysisResult( SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjId, Long dataSourceObjId, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, Score score, String conclusion, String configuration, String justification) {
 		super(sleuthkitCase, artifactID, sourceObjId, artifactObjId, dataSourceObjId, artifactTypeID, artifactTypeName, displayName, reviewStatus);
 		this.score = score;
 		this.conclusion = (conclusion != null) ? conclusion : "";
@@ -40,7 +61,31 @@ public class AnalysisResult extends BlackboardArtifact {
 		this.justification = (justification != null) ? justification : "";
 	}
 
-	AnalysisResult(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjID, long dataSourceObjID, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, boolean isNew, Score score, String conclusion, String configuration, String justification) {
+	
+	/**
+	 * Constructs an analysis result. 
+	 *
+	 * @param sleuthkitCase    The SleuthKit case (case database) that contains
+	 *                         the artifact data.
+	 * @param artifactID       The unique id for this artifact.
+	 * @param sourceObjId      The unique id of the content with which this
+	 *                         artifact is associated.
+	 * @param artifactObjId    The unique id this artifact, in tsk_objects.
+	 * @param dataSourceObjId  Object ID of the datasource where the artifact
+	 *                         was found. May be null.
+	 * @param artifactTypeID   The type id of this artifact.
+	 * @param artifactTypeName The type name of this artifact.
+	 * @param displayName      The display name of this artifact.
+	 * @param reviewStatus     The review status of this artifact.
+	 * @param isNew            If this analysis result is newly created.
+	 * @param score            The score assigned by the analysis.
+	 * @param conclusion       Conclusion arrived at by the analysis. May be
+	 *                         null.
+	 * @param configuration    Configuration used for analysis. May be null.
+	 * @param justification	   Justification for the analysis. May be null.
+	 */
+	
+	AnalysisResult(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjID, Long dataSourceObjID, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, boolean isNew, Score score, String conclusion, String configuration, String justification) {
 		super(sleuthkitCase, artifactID, sourceObjId, artifactObjID, dataSourceObjID, artifactTypeID, artifactTypeName, displayName, reviewStatus, isNew);
 		this.score = score;
 		this.conclusion = (conclusion != null) ? conclusion : "";
diff --git a/bindings/java/src/org/sleuthkit/datamodel/Blackboard.java b/bindings/java/src/org/sleuthkit/datamodel/Blackboard.java
index eaa1d7ab93e2a0d2324853322d8df2aea116d025..a6344ce60a179285ce72bcb69507f64a33a2267a 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/Blackboard.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/Blackboard.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2018-2020 Basis Technology Corp.
+ * Copyright 2018-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -155,7 +155,7 @@ public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String disp
 	 *
 	 * @param artifactType    Type of analysis result artifact to create.
 	 * @param objId           Object id of parent.
-	 * @param dataSourceObjId Data source object id.
+	 * @param dataSourceObjId Data source object id, may be null.
 	 * @param score	          Score associated with this analysis result.
 	 * @param conclusion      Conclusion of the analysis, may be null or an
 	 *                        empty string.
@@ -172,7 +172,7 @@ public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String disp
 	 * @throws BlackboardException exception thrown if a critical error occurs
 	 *                             within TSK core
 	 */
-	public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection<BlackboardAttribute> attributesList, CaseDbTransaction transaction) throws BlackboardException {
+	public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection<BlackboardAttribute> attributesList, CaseDbTransaction transaction) throws BlackboardException {
 		
 		try {
 			// add analysis result
@@ -362,7 +362,8 @@ private List<AnalysisResult> resultSetToAnalysisResults(ResultSet resultSet) thr
 
 		while (resultSet.next()) {
 			analysisResults.add(new AnalysisResult(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
-					resultSet.getLong("artifact_obj_id"), resultSet.getLong("data_source_obj_id"),
+					resultSet.getLong("artifact_obj_id"),
+					resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
 					resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
 					BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")),
 					new Score(Score.Significance.fromID(resultSet.getInt("significance")), Score.Confidence.fromID(resultSet.getInt("confidence"))),
@@ -518,7 +519,8 @@ private List<DataArtifact> resultSetToDataArtifacts(ResultSet resultSet, CaseDbC
 			}
 			
 			dataArtifacts.add(new DataArtifact(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
-					resultSet.getLong("artifact_obj_id"), resultSet.getLong("data_source_obj_id"),
+					resultSet.getLong("artifact_obj_id"),
+					resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
 					resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
 					BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")), osAccount, false));
 		} //end for each resultSet
@@ -926,6 +928,7 @@ public BlackboardArtifact newBlackboardArtifact(BlackboardArtifact.Type artifact
 	 * @param sourceObjId     The content that is the source of this artifact.
 	 * @param dataSourceObjId The data source the artifact source content
 	 *                        belongs to, may be the same as the sourceObjId.
+	 *                        May be null.
 	 * @param attributes      The attributes. May be empty or null.
 	 * @param osAccount       The OS account associated with the artifact. May
 	 *                        be null.
@@ -934,7 +937,7 @@ public BlackboardArtifact newBlackboardArtifact(BlackboardArtifact.Type artifact
 	 *
 	 * @throws TskCoreException If a critical error occurs within tsk core.
 	 */
-	public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, long dataSourceObjId,
+	public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
 			Collection<BlackboardAttribute> attributes, OsAccount osAccount) throws TskCoreException {
 
 		CaseDbTransaction transaction = caseDb.beginTransaction();
@@ -964,6 +967,7 @@ public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long s
 	 * @param sourceObjId     The content that is the source of this artifact.
 	 * @param dataSourceObjId The data source the artifact source content
 	 *                        belongs to, may be the same as the sourceObjId.
+	 *                        May be null.
 	 * @param attributes      The attributes. May be empty or null.
 	 * @param osAccount       The OS account associated with the artifact. May
 	 *                        be null.
@@ -974,7 +978,7 @@ public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long s
 	 *
 	 * @throws TskCoreException If a critical error occurs within tsk core.
 	 */
-	public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, long dataSourceObjId,
+	public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
 			Collection<BlackboardAttribute> attributes, OsAccount osAccount, final CaseDbTransaction transaction) throws TskCoreException {
 
 		if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
diff --git a/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java b/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java
index 243288b93a37c972479dfa09ccb97e68c3366b44..d4e9b0441f1180489846fd41282856b48cc8c12f 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2011-2020 Basis Technology Corp.
+ * Copyright 2011-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -80,18 +80,18 @@ public class BlackboardArtifact implements Content {
 	 *
 	 * @param sleuthkitCase    The SleuthKit case (case database) that contains
 	 *                         the artifact data.
-	 * @param artifactID       The unique id for this artifact
+	 * @param artifactID       The unique id for this artifact.
 	 * @param sourceObjId      The unique id of the content with which this
 	 *                         artifact is associated.
-	 * @param artifactObjId    The unique id this artifact, in tsk_objects
+	 * @param artifactObjId    The unique id this artifact, in tsk_objects.
 	 * @param dataSourceObjId  Object ID of the datasource where the artifact
-	 *                         was found.
+	 *                         was found. May be null.
 	 * @param artifactTypeID   The type id of this artifact.
 	 * @param artifactTypeName The type name of this artifact.
 	 * @param displayName      The display name of this artifact.
 	 * @param reviewStatus     The review status of this artifact.
 	 */
-	BlackboardArtifact(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjId, long dataSourceObjId, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus) {
+	BlackboardArtifact(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjId, Long dataSourceObjId, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus) {
 
 		this.sleuthkitCase = sleuthkitCase;
 		this.artifactId = artifactID;
@@ -127,8 +127,9 @@ public class BlackboardArtifact implements Content {
 	 * @param artifactTypeName The type name of this artifact.
 	 * @param displayName      The display name of this artifact.
 	 * @param reviewStatus     The review status of this artifact.
+	 * @param isNew            If the artifact is newly created.
 	 */
-	BlackboardArtifact(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjID, long dataSourceObjID, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, boolean isNew) {
+	BlackboardArtifact(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjID, Long dataSourceObjID, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, boolean isNew) {
 		this(sleuthkitCase, artifactID, sourceObjId, artifactObjID, dataSourceObjID, artifactTypeID, artifactTypeName, displayName, reviewStatus);
 		if (isNew) {
 			/*
@@ -172,9 +173,9 @@ public long getObjectID() {
 	/**
 	 * Gets the object id of the data source for this artifact.
 	 *
-	 * @return The data source object id.
+	 * @return The data source object id, may be null.
 	 */
-	long getDataSourceObjectID() {
+	Long getDataSourceObjectID() {
 		return this.dataSourceObjId;
 	}
 
@@ -244,7 +245,7 @@ public String getShortDescription() throws TskCoreException {
 					ATTRIBUTE_TYPE.TSK_EMAIL_FROM,
 					ATTRIBUTE_TYPE.TSK_EMAIL_TO,
 					ATTRIBUTE_TYPE.TSK_EMAIL_HOME,
-					ATTRIBUTE_TYPE.TSK_EMAIL_OFFICE}; //in the order we want to use them 
+					ATTRIBUTE_TYPE.TSK_EMAIL_OFFICE}; //in the order we want to use them
 				for (ATTRIBUTE_TYPE t : typesThatCanHaveName) {
 					attr = getAttribute(new BlackboardAttribute.Type(t));
 					if (attr != null && !attr.getDisplayString().isEmpty()) {
@@ -268,7 +269,7 @@ public String getShortDescription() throws TskCoreException {
 			ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
 			ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
 			ATTRIBUTE_TYPE.TSK_DATETIME_START,
-			ATTRIBUTE_TYPE.TSK_DATETIME_END};  //in the order we want to use them 
+			ATTRIBUTE_TYPE.TSK_DATETIME_END};  //in the order we want to use them
 		BlackboardAttribute date;
 		for (ATTRIBUTE_TYPE t : typesThatCanHaveDate) {
 			date = getAttribute(new BlackboardAttribute.Type(t));
@@ -442,7 +443,7 @@ public String getUniquePath() throws TskCoreException {
 			if (myParent != null) {
 				tempUniquePath = myParent.getUniquePath();
 			}
-			
+
 			// Don't update uniquePath until it is complete.
 			uniquePath = tempUniquePath;
 		}
@@ -482,19 +483,19 @@ public ArrayList<BlackboardArtifact> getAllArtifacts() throws TskCoreException {
 	public List<AnalysisResult> getAllAnalysisResults() throws TskCoreException {
 		return sleuthkitCase.getBlackboard().getAnalysisResults(artifactObjId);
 	}
-	
+
 	@Override
 	public Score getAggregateScore() throws TskCoreException {
 		return sleuthkitCase.getScoringManager().getAggregateScore(artifactObjId);
-		
+
 	}
-	
+
 
 	@Override
 	public List<AnalysisResult> getAnalysisResults(BlackboardArtifact.Type artifactType) throws TskCoreException {
 		return sleuthkitCase.getBlackboard().getAnalysisResults(artifactObjId, artifactType.getTypeID()); //NON-NLS
 	}
-	
+
 	/**
 	 * Get all artifacts associated with this content that have the given type
 	 * name
@@ -698,7 +699,7 @@ public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactTyp
 			throw new TskCoreException("Error adding analysis result.", ex);
 		}
 	}
-	
+
 	@Override
 	public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection<BlackboardAttribute> attributesList, OsAccount osAccount) throws TskCoreException {
 
@@ -1051,7 +1052,7 @@ public enum ARTIFACT_TYPE implements SleuthkitVisitableItem {
 		 * create cookie artifacts.
 		 */
 		TSK_WEB_COOKIE(3, "TSK_WEB_COOKIE",
-				bundle.getString("BlackboardArtifact.tskWebCookie.text")), //NON-NLS				
+				bundle.getString("BlackboardArtifact.tskWebCookie.text")), //NON-NLS
 		/**
 		 * A Web history. Use methods in
 		 * org.sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper to
@@ -1541,8 +1542,8 @@ public <T> T accept(SleuthkitItemVisitor<T> visitor) {
 	/**
 	 * Enumeration to encapsulate categories of artifact.
 	 *
-	 * Some artifact types represent data directly extracted from a data source, 
-	 * while others may be the result of some analysis done on the extracted 
+	 * Some artifact types represent data directly extracted from a data source,
+	 * while others may be the result of some analysis done on the extracted
 	 * data.
 	 */
 	public enum Category {
diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java
index 4e355297be97c9c7770ef72d48b7e0933ad9243e..ff4063ad7f12b732fdbb607b2ca929a3158d6f49 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2020 Basis Technology Corp.
+ * Copyright 2020-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -262,7 +262,7 @@ private void createArtifactTables(Statement stmt) throws SQLException {
 		stmt.execute("CREATE TABLE blackboard_artifacts (artifact_id " + dbQueryHelper.getPrimaryKey() + " PRIMARY KEY, "
 				+ "obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, "
 				+ "artifact_obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, "
-				+ "data_source_obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, "
+				+ "data_source_obj_id " + dbQueryHelper.getBigIntType() + ", "
 				+ "artifact_type_id " + dbQueryHelper.getBigIntType() + " NOT NULL, "
 				+ "review_status_id INTEGER NOT NULL, "
 				+ "UNIQUE (artifact_obj_id),"
@@ -297,7 +297,7 @@ private void createAnalysisResultsTables(Statement stmt) throws SQLException  {
 				+ ")");		
 		
 		stmt.execute("CREATE TABLE tsk_aggregate_score( obj_id " + dbQueryHelper.getBigIntType() + " PRIMARY KEY, "
-				+ "data_source_obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, "
+				+ "data_source_obj_id " + dbQueryHelper.getBigIntType() + ", "
 				+ "significance INTEGER NOT NULL, "
 				+ "confidence INTEGER NOT NULL, "
 				+ "UNIQUE (obj_id),"
diff --git a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java
index 5b1aaa05fd99b552781a4e35e92474933ba5cf7d..476f823cf755b8d7d01d32490566c20ce7782d8b 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2017-2020 Basis Technology Corp.
+ * Copyright 2017-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -565,7 +565,8 @@ private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountTy
 			if (rs.next()) {
 				BlackboardArtifact.Type bbartType = db.getArtifactType(rs.getInt("artifact_type_id"));
 
-				accountArtifact = new BlackboardArtifact(db, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				accountArtifact = new BlackboardArtifact(db, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
 			}
@@ -1010,7 +1011,8 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev
 				BlackboardArtifact.Type bbartType = db.getArtifactType(rs.getInt("artifact_type_id"));
 				relationshipSources.add(new BlackboardArtifact(db, rs.getLong("artifact_id"),
 						rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
-						rs.getLong("data_source_obj_id"), bbartType.getTypeID(),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
+						bbartType.getTypeID(),
 						bbartType.getTypeName(), bbartType.getDisplayName(),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -1195,7 +1197,8 @@ public List<Content> getRelationshipSources(AccountDeviceInstance account1, Acco
 			ArrayList<Content> artifacts = new ArrayList<Content>();
 			while (rs.next()) {
 				BlackboardArtifact.Type bbartType = db.getArtifactType(rs.getInt("artifact_type_id"));
-				artifacts.add(new BlackboardArtifact(db, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(db, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
diff --git a/bindings/java/src/org/sleuthkit/datamodel/DataArtifact.java b/bindings/java/src/org/sleuthkit/datamodel/DataArtifact.java
index cd680c0e845c0f5f3158e6e2e69af8959d903a57..b2ee69cbb4a889b6483a06fac7a2d3103c6e4fff 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/DataArtifact.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/DataArtifact.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2020 Basis Technology Corp.
+ * Copyright 2020-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,8 +41,8 @@ public final class DataArtifact extends BlackboardArtifact {
 	 * @param sourceObjId      The unique id of the content with which this
 	 *                         artifact is associated.
 	 * @param artifactObjId    The object id of artifact, in tsk_objects.
-	 * @param dataSourceObjId  Object ID of the datasource where the artifact
-	 *                         was found.
+	 * @param dataSourceObjId  Object ID of the data source where the artifact
+	 *                         was found. May be null.
 	 * @param artifactTypeID   The type id of this artifact.
 	 * @param artifactTypeName The type name of this artifact.
 	 * @param displayName      The display name of this artifact.
@@ -51,7 +51,7 @@ public final class DataArtifact extends BlackboardArtifact {
 	 *                         null.
 	 * @param isNew            The object is newly created.
 	 */
-	DataArtifact(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjId, long dataSourceObjId, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, OsAccount osAccount, boolean isNew) {
+	DataArtifact(SleuthkitCase sleuthkitCase, long artifactID, long sourceObjId, long artifactObjId, Long dataSourceObjId, int artifactTypeID, String artifactTypeName, String displayName, ReviewStatus reviewStatus, OsAccount osAccount, boolean isNew) {
 		super(sleuthkitCase, artifactID, sourceObjId, artifactObjId, dataSourceObjId, artifactTypeID, artifactTypeName, displayName, reviewStatus, isNew);
 		this.osAccount = osAccount;
 	}
diff --git a/bindings/java/src/org/sleuthkit/datamodel/ScoringManager.java b/bindings/java/src/org/sleuthkit/datamodel/ScoringManager.java
index 217722839d4e8877c6a6ff7f126940313cf6fca8..4982534df6ef5bfd681f72ff48aa73bd0f555b51 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/ScoringManager.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/ScoringManager.java
@@ -18,6 +18,7 @@
  */
 package org.sleuthkit.datamodel;
 
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
@@ -121,7 +122,7 @@ private Score getAggregateScore(long objId, CaseDbConnection connection) throws
 	 *
 	 * @throws TskCoreException
 	 */
-	private void setAggregateScore(long objId, long dataSourceObjectId, Score score, CaseDbTransaction transaction) throws TskCoreException {
+	private void setAggregateScore(long objId, Long dataSourceObjectId, Score score, CaseDbTransaction transaction) throws TskCoreException {
 		CaseDbConnection connection = transaction.getConnection();
 		setAggregateScore(objId, dataSourceObjectId, score, connection);
 	}
@@ -129,28 +130,38 @@ private void setAggregateScore(long objId, long dataSourceObjectId, Score score,
 	/**
 	 * Inserts or updates the score for the given object.
 	 *
-	 * @param objId Object id of the object.
-	 * @param dataSourceObjectId Data source object id.
-	 * @param score  Score to be inserted/updated.
-	 * @param connection Connection to use for the update.
+	 * @param objId              Object id of the object.
+	 * @param dataSourceObjectId Data source object id, may be null.
+	 * @param score              Score to be inserted/updated.
+	 * @param connection         Connection to use for the update.
 	 *
 	 * @throws TskCoreException
 	 */
-	private void setAggregateScore(long objId, long dataSourceObjectId, Score score, CaseDbConnection connection) throws TskCoreException {
+	private void setAggregateScore(long objId, Long dataSourceObjectId, Score score, CaseDbConnection connection) throws TskCoreException {
 
-		String query = String.format("INSERT INTO tsk_aggregate_score (obj_id, data_source_obj_id, significance , confidence) VALUES (%d, %d, %d, %d)"
-				+ " ON CONFLICT (obj_id) DO UPDATE SET significance = %d, confidence = %d",
-				objId, dataSourceObjectId, score.getSignificance().getId(), score.getConfidence().getId(), score.getSignificance().getId(), score.getConfidence().getId() );
+		String insertSQLString = "INSERT INTO tsk_aggregate_score (obj_id, data_source_obj_id, significance , confidence) VALUES (?, ?, ?, ?)"
+				+ " ON CONFLICT (obj_id) DO UPDATE SET significance = ?, confidence = ?";
 
+		db.acquireSingleUserCaseWriteLock();
 		try {
-			db.acquireSingleUserCaseWriteLock();
+			PreparedStatement preparedStatement = connection.getPreparedStatement(insertSQLString, Statement.NO_GENERATED_KEYS);
+			preparedStatement.clearParameters();
 
-			try (Statement updateStatement = connection.createStatement()) {
-				updateStatement.executeUpdate(query);
-			} catch (SQLException ex) {
-				throw new TskCoreException("Error updating  aggregate score, query: " + query, ex);//NON-NLS
+			preparedStatement.setLong(1, objId);
+			if (dataSourceObjectId != null) {
+				preparedStatement.setLong(2, dataSourceObjectId);
+			} else {
+				preparedStatement.setNull(2, java.sql.Types.NULL);
 			}
+			preparedStatement.setInt(3, score.getSignificance().getId());
+			preparedStatement.setInt(4, score.getConfidence().getId());
 
+			preparedStatement.setInt(5, score.getSignificance().getId());
+			preparedStatement.setInt(6, score.getConfidence().getId());
+
+			connection.executeUpdate(preparedStatement);
+		} catch (SQLException ex) {
+			throw new TskCoreException(String.format("Error updating aggregate score, query: %s for objId = %d", insertSQLString, objId), ex);//NON-NLS
 		} finally {
 			db.releaseSingleUserCaseWriteLock();
 		}
@@ -163,16 +174,16 @@ private void setAggregateScore(long objId, long dataSourceObjectId, Score score,
 	 * Updates the score for the specified object, if the given analysis result
 	 * score is higher than the score the object already has.
 	 *
-	 * @param objId      Object id.
-	 * @param dataSourceObjectId Object id of the data source.
-	 * @param resultScore Score for a newly added analysis result.
-	 * @param transaction Transaction to use for the update.
+	 * @param objId              Object id.
+	 * @param dataSourceObjectId Object id of the data source, may be null.
+	 * @param resultScore        Score for a newly added analysis result.
+	 * @param transaction        Transaction to use for the update.
 	 *
 	 * @return Aggregate score for the object.
 	 *
 	 * @throws TskCoreException
 	 */
-	Score updateAggregateScore(long objId, long dataSourceObjectId, Score resultScore, CaseDbTransaction transaction) throws TskCoreException {
+	Score updateAggregateScore(long objId, Long dataSourceObjectId, Score resultScore, CaseDbTransaction transaction) throws TskCoreException {
 
 		// Get the current score 
 		Score currentScore = ScoringManager.this.getAggregateScore(objId, transaction);
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index 5651b40aeb839f3918c39e44c49781e8f9b8461c..b16bbc2de54cb42a72bc1dc669b42340944cd672 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -1,7 +1,7 @@
 /*
  * Sleuth Kit Data Model
  *
- * Copyright 2011-2020 Basis Technology Corp.
+ * Copyright 2011-2021 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -2393,7 +2393,7 @@ private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema8dot7(CaseDbSchem
 					+ ")");
 
 			statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
-					+ "data_source_obj_id " + bigIntDataType + " NOT NULL, "
+					+ "data_source_obj_id " + bigIntDataType + ", "
 					+ "significance INTEGER NOT NULL, "
 					+ "confidence INTEGER NOT NULL, "
 					+ "UNIQUE (obj_id),"
@@ -3479,7 +3479,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRI
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());	 //NON-NLS
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), 
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -3535,7 +3536,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRI
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), 
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -3583,7 +3585,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRI
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -3631,7 +3634,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRI
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -3679,7 +3683,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRI
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -3727,7 +3732,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRI
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -3950,7 +3956,8 @@ ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskC
 			rs = connection.executeQuery(statement, query);
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -4164,7 +4171,8 @@ public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactTyp
 					+ " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
 			ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
 			while (rs.next()) {
-				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
 			}
@@ -4204,7 +4212,8 @@ public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreE
 					+ "WHERE arts.artifact_id = " + artifactID
 					+ " AND arts.artifact_type_id = types.artifact_type_id");
 			if (rs.next()) {
-				return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
 			} else {
@@ -4966,7 +4975,8 @@ public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) th
 				BlackboardArtifact.Type type;
 				// artifact type is cached, so this does not necessarily call to the db
 				type = this.getArtifactType(rs.getInt("artifact_type_id"));
-				BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
+				BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
+						rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
 						type.getTypeID(), type.getTypeName(), type.getDisplayName(),
 						BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
 				matches.add(artifact);
@@ -5088,21 +5098,21 @@ BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, Stri
 	 * Creates a new analysis result by inserting a row in the artifacts table
 	 * and a corresponding row in the tsk_analysis_results table.
 	 *
-	 * @param artifactType       Analysis result artifact type.
-	 * @param obj_id             Object id of parent.
-	 * @param data_source_obj_id Data source object id.
-	 * @param score              Score.
-	 * @param conclusion         Conclusion, may be null or an empty string.
-	 * @param configuration      Configuration used by analysis, may be null or
-	 *                           an empty string.
-	 * @param justification      Justification, may be null or an empty string.
-	 * @param connection         Database connection to use.
+	 * @param artifactType    Analysis result artifact type.
+	 * @param objId           Object id of parent.
+	 * @param dataSourceObjId Data source object id, may be null.
+	 * @param score           Score.
+	 * @param conclusion      Conclusion, may be null or an empty string.
+	 * @param configuration   Configuration used by analysis, may be null or an
+	 *                        empty string.
+	 * @param justification   Justification, may be null or an empty string.
+	 * @param connection      Database connection to use.
 	 *
 	 * @return Analysis result.
 	 *
 	 * @throws TskCoreException
 	 */
-	AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long obj_id, long data_source_obj_id, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
+	AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
 		
 		if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
 			throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()) );
@@ -5112,13 +5122,13 @@ AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long obj_
 		acquireSingleUserCaseWriteLock();
 		try {
 			// add a row in tsk_objects
-			long artifact_obj_id = addObject(obj_id, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
+			long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
 
 			// add a row in blackboard_artifacts table
 			PreparedStatement insertArtifactstatement;
 			ResultSet resultSet = null;
 			try {
-				insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), obj_id, artifact_obj_id, data_source_obj_id, connection);
+				insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
 				connection.executeUpdate(insertArtifactstatement);
 				resultSet = insertArtifactstatement.getGeneratedKeys();
 				resultSet.next();
@@ -5130,7 +5140,7 @@ AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long obj_
 				analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
 				analysisResultsStatement.clearParameters();
 
-				analysisResultsStatement.setLong(1, artifact_obj_id);
+				analysisResultsStatement.setLong(1, artifactObjId);
 				analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
 				analysisResultsStatement.setInt(3, score.getSignificance().getId());
 				analysisResultsStatement.setInt(4, score.getConfidence().getId());
@@ -5139,7 +5149,7 @@ AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long obj_
 
 				connection.executeUpdate(analysisResultsStatement);
 
-				return new AnalysisResult(this, artifactID, obj_id, artifact_obj_id, data_source_obj_id, artifactType.getTypeID(),
+				return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
 						artifactType.getTypeName(), artifactType.getDisplayName(),
 						BlackboardArtifact.ReviewStatus.UNDECIDED, true,
 						score, (conclusion != null) ? conclusion : "",