/** * */ package org.phoenicis.apps.repository; import java.net.URI; import java.nio.ByteBuffer; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.function.Function; import org.phoenicis.apps.dto.ApplicationDTO; import org.phoenicis.apps.dto.CategoryDTO; import org.phoenicis.apps.dto.ResourceDTO; import org.phoenicis.apps.dto.ScriptDTO; public abstract class MergeableRepository implements Repository { /** * This method merges multiple application sources into a single list of * category dtos. For this it receives a map, containing a binding between * all application sources and their category dto lists, and an array * containing all application sources that should be merged in the correct * order. While merging the application source it prioritizes a later * application source over an earlier one. This means, that if two * application sources contain the same script, the script from the later * application source is taken. * * @param categoriesMap * A map containing a binding between the application sources and * their category dtos * @param repositories * A list containing all application sources in the order in * which they should be merged * @return A list containing category dtos of the merged application * sources. If no application sources were given, an empty list is * returned */ protected List<CategoryDTO> mergeRepositories(Map<Repository, List<CategoryDTO>> categoriesMap, List<Repository> repositories) { int numberOfRepositories = repositories.size(); if (numberOfRepositories == 0) { return Collections.emptyList(); } /* * Take the first application source, from behind, as the default one */ final Map<String, CategoryDTO> mergedCategories = createSortedMap( categoriesMap.get(repositories.get(numberOfRepositories - 1)), CategoryDTO::getName); for (int otherRepositoryIndex = numberOfRepositories - 2; otherRepositoryIndex >= 0; otherRepositoryIndex--) { final List<CategoryDTO> otherCategories = categoriesMap.get(repositories.get(otherRepositoryIndex)); final Map<String, CategoryDTO> otherCategoriesMap = createSortedMap(otherCategories, CategoryDTO::getName); for (String categoryName : otherCategoriesMap.keySet()) { final CategoryDTO category = otherCategoriesMap.get(categoryName); if (mergedCategories.containsKey(categoryName)) { mergedCategories.put(categoryName, mergeCategories(mergedCategories.get(categoryName), category)); } else { mergedCategories.put(categoryName, category); } } } return new ArrayList<>(mergedCategories.values()); } protected CategoryDTO mergeCategories(CategoryDTO leftCategory, CategoryDTO rightCategory) { final Map<String, ApplicationDTO> leftApplications = createSortedMap(leftCategory.getApplications(), ApplicationDTO::getName); final Map<String, ApplicationDTO> rightApplications = createSortedMap(rightCategory.getApplications(), ApplicationDTO::getName); final SortedMap<String, ApplicationDTO> mergedApps = new TreeMap<>(rightApplications); for (String applicationName : leftApplications.keySet()) { final ApplicationDTO application = leftApplications.get(applicationName); if (mergedApps.containsKey(applicationName)) { mergedApps.put(applicationName, mergeApplications(mergedApps.get(applicationName), application)); } else { mergedApps.put(applicationName, application); } } final List<ApplicationDTO> applications = new ArrayList<>(mergedApps.values()); applications.sort(ApplicationDTO.nameComparator()); return new CategoryDTO.Builder().withApplications(applications).withType(leftCategory.getType()) .withIcon(leftCategory.getIcon()).withName(leftCategory.getName()).build(); } protected ApplicationDTO mergeApplications(ApplicationDTO leftApplication, ApplicationDTO rightApplication) { final List<ScriptDTO> scripts = mergeListOfDtos(leftApplication.getScripts(), rightApplication.getScripts(), ScriptDTO::getScriptName, ScriptDTO.nameComparator()); final List<ResourceDTO> resources = mergeListOfDtos(leftApplication.getResources(), rightApplication.getResources(), ResourceDTO::getName, ResourceDTO.nameComparator()); final Set<URI> mergeMiniaturesSet = new HashSet<URI>(leftApplication.getMiniatures()); mergeMiniaturesSet.addAll(rightApplication.getMiniatures()); return new ApplicationDTO.Builder().withName(leftApplication.getName()).withResources(resources) .withScripts(scripts).withDescription(leftApplication.getDescription()) .withIcon(leftApplication.getIcon()).withMiniatures(new ArrayList<>(mergeMiniaturesSet)).build(); } protected <T> List<T> mergeListOfDtos(List<T> leftList, List<T> rightList, Function<T, String> nameSupplier, Comparator<T> sorter) { final Map<String, T> left = createSortedMap(leftList, nameSupplier); final Map<String, T> right = createSortedMap(rightList, nameSupplier); final SortedMap<String, T> merged = new TreeMap<>(left); for (String name : right.keySet()) { final T dto = right.get(name); if (!merged.containsKey(name)) { merged.put(name, dto); } } final List<T> result = new ArrayList<>(merged.values()); result.sort(sorter); return result; } protected <T> Map<String, T> createSortedMap(List<T> dtos, Function<T, String> nameProvider) { final SortedMap<String, T> map = new TreeMap<>(); dtos.forEach(dto -> map.put(nameProvider.apply(dto), dto)); return map; } }