001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.oscal.lib.profile.resolver; 007 008import gov.nist.secauto.metaschema.core.util.CollectionUtil; 009 010import java.util.Collections; 011import java.util.LinkedHashMap; 012import java.util.List; 013import java.util.Map; 014import java.util.Objects; 015import java.util.function.Function; 016import java.util.stream.Collectors; 017import java.util.stream.Stream; 018 019import edu.umd.cs.findbugs.annotations.NonNull; 020import edu.umd.cs.findbugs.annotations.Nullable; 021 022public final class ModifyPhaseUtils { 023 private ModifyPhaseUtils() { 024 // disable construction 025 } 026 027 public static <T> Function<? super T, String> identityKey() { 028 return item -> Integer.toString(Objects.hashCode(item)); 029 } 030 031 public static <T, R> Function<? super T, String> identifierKey(@NonNull Function<T, R> identifierFunction) { 032 return item -> { 033 R identifier = identifierFunction.apply(item); 034 String retval; 035 if (identifier == null) { 036 retval = Integer.toString(Objects.hashCode(item)); 037 } else { 038 retval = identifier.toString(); 039 } 040 return retval; 041 }; 042 } 043 044 @SuppressWarnings("PMD.OnlyOneReturn") // readability 045 public static <T> T mergeItem(@Nullable T original, @Nullable T additional) { 046 if (additional == null) { 047 return original; 048 } 049 050 return additional; 051 } 052 053 @SuppressWarnings("PMD.OnlyOneReturn") // readability 054 public static <T> List<T> merge(@Nullable List<T> original, @Nullable List<T> additional, 055 Function<? super T, String> keyFunction) { 056 if (additional == null || additional.isEmpty()) { 057 return original; 058 } 059 060 if (original == null || original.isEmpty()) { 061 return additional; 062 } 063 064 // reverse the stream 065 List<T> reversed = Stream.concat( 066 CollectionUtil.listOrEmpty(original).stream(), 067 CollectionUtil.listOrEmpty(additional).stream()) 068 .collect(Collectors.collectingAndThen( 069 Collectors.toList(), 070 l -> { 071 Collections.reverse(l); 072 return l; 073 })); 074 075 // build a map of each unique identity 076 Map<String, List<T>> identityMap = reversed.stream() 077 .collect(Collectors.groupingBy(keyFunction, LinkedHashMap::new, Collectors.toList())); 078 079 // build a reversed list of items, using the first item 080 return identityMap.values().stream() 081 .map(list -> list.stream().findFirst().get()) 082 .collect(Collectors.collectingAndThen( 083 Collectors.toList(), 084 l -> { 085 Collections.reverse(l); 086 return l; 087 })); 088 } 089}