class SimpleCatalogUtilsService implements CatalogUtilsService {

    @Override
    public Set<Conflict> getConflicts(Resource sourceCommitId, Resource targetCommitId, RepositoryConnection conn) {
        long start = System.currentTimeMillis();
        // Does not take into account named graphs
        validateResource(sourceCommitId, commitFactory.getTypeIRI(), conn);
        validateResource(targetCommitId, commitFactory.getTypeIRI(), conn);

        ArrayList<Resource> sourceCommits = new ArrayList<>(getCommitChain(sourceCommitId, true, conn));
        ArrayList<Resource> targetCommits = new ArrayList<>(getCommitChain(targetCommitId, true, conn));
        ArrayList<Resource> commonCommits = new ArrayList<>(sourceCommits);
        commonCommits.retainAll(targetCommits);

        sourceCommits.removeAll(commonCommits);
        targetCommits.removeAll(commonCommits);

        sourceCommits.trimToSize();
        targetCommits.trimToSize();

        Difference sourceDiff = getCommitDifference(sourceCommits, conn);
        Difference targetDiff = getCommitDifference(targetCommits, conn);

        Model sourceAdds = sourceDiff.getAdditions();
        Set<Resource> sourceAddSubjects = sourceAdds.subjects();
        Model targetAdds = targetDiff.getAdditions();
        Set<Resource> targetAddSubjects = targetAdds.subjects();
        Model sourceDels = sourceDiff.getDeletions();
        Model targetDels = targetDiff.getDeletions();

        Set<Conflict> result = new HashSet<>();
        Model original = getCompiledResource(commonCommits, conn);

        Set<Statement> statementsToRemove = new HashSet<>();

        sourceDels.subjects().forEach(subject -> {
            Model sourceDelSubjectStatements = sourceDels.filter(subject, null, null);

            // Check for modification in left and right
            sourceDelSubjectStatements.forEach(statement -> {
                IRI pred = statement.getPredicate();
                Value obj = statement.getObject();

                if (targetDels.contains(subject, pred, obj)
                        && sourceAdds.contains(subject, pred, null)
                        && targetAdds.contains(subject, pred, null)) {
                    result.add(createConflict(subject, pred, sourceAdds, sourceDels, targetAdds, targetDels));
                    statementsToRemove.add(statement);
                }
            });

            // Check for deletion in left and addition in right if there are common parents
            if (commonCommits.size() != 0) {
                Model targetSubjectAdd = targetAdds.filter(subject, null, null);
                boolean sourceEntityDeleted = !sourceAddSubjects.contains(subject)
                        && sourceDelSubjectStatements.equals(original.filter(subject, null, null));
                boolean targetEntityDeleted = targetDels.containsAll(sourceDelSubjectStatements);

                if (sourceEntityDeleted && !targetEntityDeleted && targetSubjectAdd.size() > 0) {
                    result.add(createConflict(subject, null, sourceAdds, sourceDels, targetAdds, targetDels));
                    statementsToRemove.addAll(targetSubjectAdd);
                }
            }
        });

        statementsToRemove.forEach(statement -> Stream.of(sourceAdds, sourceDels, targetAdds, targetDels)
                .forEach(model -> model.remove(statement.getSubject(), statement.getPredicate(), null)));

        if (commonCommits.size() != 0) {
            targetDels.subjects().forEach(subject -> {
                // Check for deletion in right and addition in left if there are common parents
                Model targetDelSubjectStatements = targetDels.filter(subject, null, null);
                Model sourceSubjectAdd = sourceAdds.filter(subject, null, null);
                boolean targetEntityDeleted = !targetAddSubjects.contains(subject)
                        && targetDelSubjectStatements.equals(original.filter(subject, null, null));
                boolean sourceEntityDeleted = sourceDels.containsAll(targetDelSubjectStatements);

                if (targetEntityDeleted && !sourceEntityDeleted && sourceSubjectAdd.size() > 0) {
                    result.add(createConflict(subject, null, sourceAdds, sourceDels, targetAdds, targetDels));
                }
            });
        }

        log.trace("getConflicts took {}ms", System.currentTimeMillis() - start);
        return result;
    }

}