diff --git a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java
index fc3c0ab9c0650b043b9fcdc5cafb1cf6c6744505..c885c0714fa14ecbc5017204c066e2e61280b607 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java
@@ -18,7 +18,6 @@
  */
 package org.sleuthkit.datamodel;
 
-import com.google.common.annotations.Beta;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -42,8 +41,6 @@
 import static org.sleuthkit.datamodel.SleuthkitCase.closeConnection;
 import static org.sleuthkit.datamodel.SleuthkitCase.closeResultSet;
 import static org.sleuthkit.datamodel.SleuthkitCase.closeStatement;
-import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
-import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
 
 /**
  * Provides an API to create Accounts and communications/relationships between
@@ -199,15 +196,17 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam
 		if (this.accountTypeToTypeIdMap.containsKey(accountType)) {
 			return accountType;
 		}
-		
+
 		CaseDbTransaction transaction = this.db.beginTransaction();
 		try {
 			org.sleuthkit.datamodel.Account.Type retAccountType = addAccountType(accountTypeName, displayName, transaction);
 			transaction.commit();
+			transaction = null;
 			return retAccountType;
-		} catch (TskCoreException ex) {
-			transaction.rollback();
-			throw ex;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 	}
 
@@ -235,12 +234,12 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam
 
 		try {
 			PreparedStatement initialSelectStmt = trans.getConnection().getPreparedStatement(
-					"SELECT * FROM account_types WHERE type_name = ?", 
+					"SELECT * FROM account_types WHERE type_name = ?",
 					Statement.RETURN_GENERATED_KEYS
 			);
 			initialSelectStmt.clearParameters();
 			initialSelectStmt.setString(1, accountTypeName);
-			
+
 			// try to get cached account type
 			try (ResultSet initialSelectRs = initialSelectStmt.executeQuery()) {
 				if (initialSelectRs.next()) {
@@ -253,14 +252,14 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam
 
 			// if not in database, insert
 			PreparedStatement insertStmt = trans.getConnection().getPreparedStatement(
-				"INSERT INTO account_types (type_name, display_name) VALUES (?, ?)",
-				Statement.RETURN_GENERATED_KEYS
+					"INSERT INTO account_types (type_name, display_name) VALUES (?, ?)",
+					Statement.RETURN_GENERATED_KEYS
 			);
 
 			insertStmt.clearParameters();
-			insertStmt.setString(1, accountTypeName);				
+			insertStmt.setString(1, accountTypeName);
 			insertStmt.setString(2, displayName);
-				
+
 			int affectedRows = insertStmt.executeUpdate();
 			if (affectedRows > 0) {
 				try (ResultSet insertRsKeys = insertStmt.getGeneratedKeys()) {
@@ -272,7 +271,7 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam
 					}
 				}
 			}
-			
+
 			throw new SQLException(MessageFormat.format("Account with type name: {0} and display name: {1} could not be created", accountTypeName, displayName));
 		} catch (SQLException ex) {
 			throw new TskCoreException("Error adding account type", ex);
@@ -312,9 +311,11 @@ public AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Acc
 					sourceFile, attributes, ingestJobId, transaction);
 
 			transaction.commit();
-		} catch (TskCoreException ex) {
-			transaction.rollback();
-			throw ex;
+			transaction = null;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 
 		if (accountFileInstance != null) {
@@ -451,21 +452,21 @@ public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, Stri
 	public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, CaseDbConnection caseDbConnection) throws TskCoreException, InvalidAccountIDException {
 		try {
 			PreparedStatement stmt = caseDbConnection.getPreparedStatement(
-					"SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?", 
+					"SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?",
 					Statement.NO_GENERATED_KEYS
 			);
-		
+
 			stmt.clearParameters();
 			stmt.setInt(1, getAccountTypeId(accountType));
 			stmt.setString(2, normalizeAccountID(accountType, accountUniqueID));
-			
+
 			try (ResultSet rs = stmt.executeQuery()) {
 				if (rs.next()) {
 					return new Account(rs.getInt("account_id"), accountType,
 							rs.getString("account_unique_identifier"));
 				} else {
 					return null;
-				}				
+				}
 			}
 		} catch (SQLException ex) {
 			throw new TskCoreException("Error adding an account", ex);
@@ -483,17 +484,18 @@ public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, Stri
 	 *
 	 * @throws TskCoreException
 	 */
-	private DataArtifact newDataArtifact(Content content, BlackboardArtifact.Type artType, 
+	private DataArtifact newDataArtifact(Content content, BlackboardArtifact.Type artType,
 			Collection<BlackboardAttribute> attributes, CaseDbTransaction trans) throws TskCoreException {
-		
-		Long dataSourceObjId;
+
+		long dataSourceObjId;
 		if (content instanceof AbstractFile) {
 			dataSourceObjId = ((AbstractFile) content).getDataSourceObjectId();
+		} else if (content instanceof BlackboardArtifact) {
+			dataSourceObjId = ((BlackboardArtifact) content).getDataSourceObjectID();
 		} else if (content instanceof DataSource) {
 			dataSourceObjId = content.getId();
 		} else {
-			// can be null for anything else
-			dataSourceObjId = null;
+			dataSourceObjId = getDataSourceObjId(trans.getConnection(), content.getId());
 		}
 
 		return getSleuthkitCase().getBlackboard().newDataArtifact(
@@ -505,7 +507,63 @@ private DataArtifact newDataArtifact(Content content, BlackboardArtifact.Type ar
 				trans);
 	}
 
-	
+	/**
+	 * Iteratively checks tsk_objects table for parents until arriving at a
+	 * tsk_objects entry that is of type IMG. If no IMG type is reached, returns
+	 * 0.
+	 *
+	 * @param conn  The database connection.
+	 * @param objId The starting object id.
+	 *
+	 * @return The object id of the parent data source or 0.
+	 *
+	 * @throws TskCoreException
+	 */
+	private long getDataSourceObjId(CaseDbConnection conn, long objId) throws TskCoreException {
+
+		this.db.acquireSingleUserCaseReadLock();
+		try {
+			while (objId > 0) {
+				try (PreparedStatement pStmt = conn.getPreparedStatement(
+						"SELECT par_obj_id, type FROM tsk_objects WHERE obj_id = ?",
+						Statement.NO_GENERATED_KEYS)) {
+
+					pStmt.clearParameters();
+					pStmt.setLong(1, objId);
+					try (ResultSet rs = pStmt.executeQuery()) {
+						if (rs.next()) {
+							TskData.ObjectType type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
+							// if the current id is an image, we have found the data source id.
+							if (type == TskData.ObjectType.IMG) {
+								return objId;
+							}
+
+							Long parId = rs.getLong("par_obj_id");
+							// if no parent id, there is no data source associated with this content.
+							if (rs.wasNull()) {
+								return 0;
+							}
+
+							// otherwise, keep iterating
+							objId = parId;
+
+						} else {
+							// if no record matching the object id, set the data source object id to 0.
+							return 0;
+						}
+					}
+				}
+			}
+		} catch (SQLException ex) {
+			throw new TskCoreException("Error getting Content by ID.", ex);
+		} finally {
+			this.db.releaseSingleUserCaseReadLock();
+		}
+
+		// in this event, simply return 0.
+		return 0;
+	}
+
 	/**
 	 * Adds relationships between the sender and each of the recipient account
 	 * instances and between all recipient account instances. All account
@@ -537,9 +595,11 @@ public void addRelationships(AccountFileInstance sender, List<AccountFileInstanc
 		try {
 			addRelationships(sender, recipients, sourceArtifact, relationshipType, dateTime, transaction);
 			transaction.commit();
-		} catch (TskCoreException ex) {
-			transaction.rollback();
-			throw ex;
+			transaction = null;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 	}
 
@@ -678,7 +738,7 @@ private Account getOrCreateAccount(Account.Type accountType, String accountUniqu
 			}
 
 			try {
-				PreparedStatement insertStmt = trans.getConnection().getPreparedStatement(query, Statement.NO_GENERATED_KEYS);
+				PreparedStatement insertStmt = trans.getConnection().getPreparedStatement(query, Statement.RETURN_GENERATED_KEYS);
 				insertStmt.clearParameters();
 				insertStmt.setInt(1, getAccountTypeId(accountType));
 				String accountUniqueIdentifier = normalizeAccountID(accountType, accountUniqueID);
@@ -687,14 +747,14 @@ private Account getOrCreateAccount(Account.Type accountType, String accountUniqu
 					try (ResultSet rs = insertStmt.getGeneratedKeys()) {
 						if (rs.next()) {
 							return new Account(
-									rs.getInt(1), 
+									rs.getInt(1),
 									accountType,
 									accountUniqueIdentifier
 							);
 						}
 					}
-				} 
-				
+				}
+
 				return null;
 			} catch (SQLException ex) {
 				throw new TskCoreException("Error adding an account", ex);
@@ -790,7 +850,7 @@ private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountTy
 		try {
 			PreparedStatement pStatement = transaction.getConnection().getPreparedStatement(queryStr, Statement.NO_GENERATED_KEYS);
 			pStatement.clearParameters();
-			
+
 			int paramIdx = 0;
 			pStatement.setInt(++paramIdx, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID());
 			pStatement.setString(++paramIdx, accountUniqueID);
@@ -1170,7 +1230,7 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev
 		for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
 			final Long accountID = entry.getKey();
 			String datasourceObjIdsCSV = CommManagerSqlStringUtils.buildCSVString(entry.getValue());
-			
+
 			adiSQLClauses.add(
 					"( "
 					+ (!datasourceObjIdsCSV.isEmpty() ? "( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + " ) ) AND" : "")
@@ -1179,8 +1239,8 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev
 			);
 		}
 		String adiSQLClause = CommManagerSqlStringUtils.joinAsStrings(adiSQLClauses, " OR ");
-		
-		if(adiSQLClause.isEmpty()) {
+
+		if (adiSQLClause.isEmpty()) {
 			LOGGER.log(Level.SEVERE, "There set of AccountDeviceInstances had no valid data source ids.");
 			return Collections.emptySet();
 		}
@@ -1196,7 +1256,7 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev
 
 		// Basic join.
 		String limitQuery = " account_relationships AS relationships";
-		
+
 		// If the user set filters expand this to be a subquery that selects
 		// accounts based on the filter.
 		String limitStr = getMostRecentFilterLimitSQL(filter);
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index fe35bc0ac907198d88bfeba3f5a0a3da7cb8c538..11002c2d978356091580c73b3e1a21c94ccb098f 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -8480,10 +8480,12 @@ public LayoutFile addLayoutFile(String fileName,
 			LayoutFile lf = addLayoutFile(fileName, size, dirFlag, metaFlag, 
 					ctime, crtime, atime, mtime, fileRanges, parent, dataSourceId, transaction);
 			transaction.commit();
+			transaction = null;
 			return lf;
-		} catch (TskCoreException ex) {
-			transaction.rollback();
-			throw ex;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();	
+			}
 		}
 	}
 	
diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java
index 3243cbf970e2d82e3595c4d9654129152ba99c79..d738ac8f9b99ff652357f2287d2b86de3400c256 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java
@@ -315,9 +315,11 @@ public BlackboardArtifact addContact(String contactName,
 		try {
 			contactArt = addContact(contactName, phoneNumber, homePhoneNumber, mobilePhoneNumber, emailAddr, transaction, additionalAttributes);
 			transaction.commit();
-		} catch (TskCoreException | BlackboardException ex) {
-			transaction.rollback();
-			throw ex;
+			transaction = null;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 
 		if (contactArt != null) {
@@ -615,9 +617,11 @@ public BlackboardArtifact addMessage(String messageType,
 		try {
 			msgArt = addMessage(messageType, direction, senderId, recipientIdsList, dateTime, readStatus, subject, messageText, threadId, transaction, otherAttributesList);
 			transaction.commit();
-		} catch (TskCoreException | BlackboardException ex) {
-			transaction.rollback();
-			throw ex;
+			transaction = null;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 
 		if (msgArt != null) {
@@ -943,9 +947,11 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction,
 		try {
 			callLogArt = addCalllog(direction, callerId, calleeIdsList, startDateTime, endDateTime, mediaType, transaction, otherAttributesList);
 			transaction.commit();
-		} catch (TskCoreException | BlackboardException ex) {
-			transaction.rollback();
-			throw ex;
+			transaction = null;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 
 		if (callLogArt != null) {
@@ -1084,8 +1090,6 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction,
 		Content content = getContent();
 		BlackboardArtifact callLogArtifact = newDataArtifact(content, CALLOG_TYPE, attributes, trans);
 
-		callLogArtifact.addAttributes(attributes);
-
 		// create relationships between caller/callees
 		try {
 			getSleuthkitCase().getCommunicationsManager().addRelationships(callerAccountInstance,
@@ -1130,9 +1134,11 @@ public void addAttachments(BlackboardArtifact message, MessageAttachments attach
 			dataSourceObjId = dataSourceObjId == null ? 0L : dataSourceObjId;
 			attachmentArts = addAttachments(message, dataSourceObjId, attachments, getModuleName(), transaction);
 			transaction.commit();
-		} catch (TskCoreException ex) {
-			transaction.rollback();
-			throw ex;
+			transaction = null;
+		} finally {
+			if (transaction != null) {
+				transaction.rollback();
+			}
 		}
 
 		attachmentArts = (attachmentArts == null) ? Collections.emptyList() : attachmentArts;