class BackendUtils {

    public static TArtifactTemplate synchronizeReferences(IRepository repository, ArtifactTemplateId id) throws IOException {
        TArtifactTemplate template = repository.getElement(id);
        List<TArtifactReference> toRemove = new ArrayList<>();
        List<RepositoryFileReference> toAdd = new ArrayList<>();
        TArtifactTemplate.ArtifactReferences artifactReferences = template.getArtifactReferences();
        DirectoryId fileDir = new ArtifactTemplateFilesDirectoryId(id);
        SortedSet<RepositoryFileReference> files = repository.getContainedFiles(fileDir);

        if (artifactReferences == null) {
            artifactReferences = new TArtifactTemplate.ArtifactReferences();
            template.setArtifactReferences(artifactReferences);
        }

        List<TArtifactReference> artRefList = artifactReferences.getArtifactReference();
        determineChanges(artRefList, files, toRemove, toAdd);

        if (toAdd.size() > 0 || toRemove.size() > 0) {
            // apply removal list
            toRemove.forEach(artRefList::remove);

            // apply addition list
            artRefList.addAll(toAdd.stream().map(fileRef -> {
                String path = Util.getUrlPath(fileRef);

                // put path into data structure
                // we do not use Include/Exclude as we directly reference a concrete file
                TArtifactReference artRef = new TArtifactReference();
                artRef.setReference(path);

                return artRef;
            }).collect(Collectors.toList()));

            // finally, persist only if something changed
            BackendUtils.persist(repository, id, template);
        }

        return template;
    }

}

class BackendUtilsTest {

    @Test
    public void synchronizeReferencesDoesNontRemoveExistantFileAndDoesNotRemoveUrls() throws Exception {

        ArtifactTemplateId artifactTemplateId = new ArtifactTemplateId("http://example.org", "test-artifact-template", false);

        // alternative test implementation: Use git-based repository
        // this test at hand is closer to the implementation, but easier to write

        IRepository repository = mock(IRepository.class);
        ArtifactTemplateFilesDirectoryId artifactTemplateFilesDirectoryId = new ArtifactTemplateFilesDirectoryId(artifactTemplateId);

        SortedSet<RepositoryFileReference> containedReferences = new TreeSet<>();
        RepositoryFileReference repositoryFileReference = new RepositoryFileReference(artifactTemplateId, "exists.txt");
        containedReferences.add(repositoryFileReference);

        when(repository.getContainedFiles(artifactTemplateFilesDirectoryId)).thenReturn(containedReferences);

        TArtifactTemplate artifactTemplate = createArtifactTemplateWithReferenceToAnUrlAndExistentFile();
        when(repository.getElement(artifactTemplateId)).thenReturn(artifactTemplate);
        TArtifactTemplate synchronizhedArtifactTemplate = BackendUtils.synchronizeReferences(repository, artifactTemplateId);

        assertEquals(createArtifactTemplateWithReferenceToAnUrlAndExistentFile(), synchronizhedArtifactTemplate);
    }

}