1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.utils; 17 18 import java.util.List; 19 import java.util.function.Predicate; 20 import java.util.function.UnaryOperator; 21 import software.amazon.awssdk.annotations.SdkProtectedApi; 22 import software.amazon.awssdk.utils.internal.DefaultConditionalDecorator; 23 24 /** 25 * An interface that defines a class that contains a transform for another type as well as a condition for whether 26 * that transform should be applied. 27 * 28 * @param <T> A type that can be decorated, or transformed, through applying a function. 29 */ 30 @FunctionalInterface 31 @SdkProtectedApi 32 public interface ConditionalDecorator<T> { 33 predicate()34 default Predicate<T> predicate() { 35 return t -> true; 36 } 37 38 transform()39 UnaryOperator<T> transform(); 40 create(Predicate<T> predicate, UnaryOperator<T> transform)41 static <T> ConditionalDecorator<T> create(Predicate<T> predicate, UnaryOperator<T> transform) { 42 DefaultConditionalDecorator.Builder<T> builder = new DefaultConditionalDecorator.Builder<>(); 43 return builder.predicate(predicate).transform(transform).build(); 44 } 45 46 /** 47 * This function will transform an initially supplied value with provided transforming, or decorating, functions that are 48 * conditionally and sequentially applied. For each pair of condition and transform: if the condition evaluates to true, the 49 * transform will be applied to the incoming value and the output from the transform is the input to the next transform. 50 * <p> 51 * If the supplied collection is ordered, the function is guaranteed to apply the transforms in the order in which they appear 52 * in the collection. 53 * 54 * @param initialValue The untransformed start value 55 * @param decorators A list of condition to transform 56 * @param <T> The type of the value 57 * @return A single transformed value that is the result of applying all transforms evaluated to true 58 */ decorate(T initialValue, List<ConditionalDecorator<T>> decorators)59 static <T> T decorate(T initialValue, List<ConditionalDecorator<T>> decorators) { 60 return decorators.stream() 61 .filter(d -> d.predicate().test(initialValue)) 62 .reduce(initialValue, 63 (element, decorator) -> decorator.transform().apply(element), 64 (el1, el2) -> { throw new IllegalStateException("Should not reach here, combine function not " 65 + "needed unless executed in parallel."); }); 66 } 67 } 68