View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.api.services;
20  
21  import java.util.Collection;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Optional;
26  import java.util.function.BinaryOperator;
27  import java.util.function.Function;
28  import java.util.function.UnaryOperator;
29  
30  import org.apache.maven.api.Service;
31  import org.apache.maven.api.annotations.Experimental;
32  import org.apache.maven.api.annotations.Nonnull;
33  import org.apache.maven.api.annotations.Nullable;
34  
35  /**
36   * The Interpolator service provides methods for variable substitution in strings and maps.
37   * It allows for the replacement of placeholders (e.g., ${variable}) with their corresponding values.
38   *
39   * @since 4.0.0
40   */
41  @Experimental
42  public interface Interpolator extends Service {
43  
44      /**
45       * Interpolates the values in the given map using the provided callback function.
46       * This method defaults to setting empty strings for unresolved placeholders.
47       *
48       * @param properties The map containing key-value pairs to be interpolated.
49       * @param callback The function to resolve variable values not found in the map.
50       */
51      default void interpolate(@Nonnull Map<String, String> properties, @Nullable UnaryOperator<String> callback) {
52          interpolate(properties, callback, null, true);
53      }
54  
55      /**
56       * Interpolates the values in the given map using the provided callback function.
57       *
58       * @param map The map containing key-value pairs to be interpolated.
59       * @param callback The function to resolve variable values not found in the map.
60       * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings. If false, they are left unchanged.
61       */
62      default void interpolate(
63              @Nonnull Map<String, String> map, @Nullable UnaryOperator<String> callback, boolean defaultsToEmpty) {
64          interpolate(map, callback, null, defaultsToEmpty);
65      }
66  
67      /**
68       * Interpolates the values in the given map using the provided callback function.
69       *
70       * @param map The map containing key-value pairs to be interpolated.
71       * @param callback The function to resolve variable values not found in the map.
72       * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings.  If false, they are left unchanged.
73       */
74      void interpolate(
75              @Nonnull Map<String, String> map,
76              @Nullable UnaryOperator<String> callback,
77              @Nullable BinaryOperator<String> postprocessor,
78              boolean defaultsToEmpty);
79  
80      /**
81       * Interpolates a single string value using the provided callback function.
82       * This method defaults to not replacing unresolved placeholders.
83       *
84       * @param val The string to be interpolated.
85       * @param callback The function to resolve variable values.
86       * @return The interpolated string, or null if the input was null.
87       */
88      @Nullable
89      default String interpolate(@Nullable String val, @Nullable UnaryOperator<String> callback) {
90          return interpolate(val, callback, false);
91      }
92  
93      /**
94       * Interpolates a single string value using the provided callback function.
95       *
96       * @param val The string to be interpolated.
97       * @param callback The function to resolve variable values.
98       * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings.
99       * @return The interpolated string, or null if the input was null.
100      */
101     @Nullable
102     default String interpolate(
103             @Nullable String val, @Nullable UnaryOperator<String> callback, boolean defaultsToEmpty) {
104         return interpolate(val, callback, null, defaultsToEmpty);
105     }
106 
107     /**
108      * Interpolates a single string value using the provided callback function.
109      *
110      * @param val The string to be interpolated.
111      * @param callback The function to resolve variable values.
112      * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings.
113      * @return The interpolated string, or null if the input was null.
114      */
115     @Nullable
116     String interpolate(
117             @Nullable String val,
118             @Nullable UnaryOperator<String> callback,
119             @Nullable BinaryOperator<String> postprocessor,
120             boolean defaultsToEmpty);
121 
122     /**
123      * Creates a composite function from a collection of functions.
124      *
125      * @param functions A collection of functions, each taking a String as input and returning a String.
126      * @return A function that applies each function in the collection in order until a non-null result is found.
127      *         If all functions return null, the composite function returns null.
128      *
129      * @throws NullPointerException if the input collection is null or contains null elements.
130      */
131     static UnaryOperator<String> chain(Collection<? extends UnaryOperator<String>> functions) {
132         return s -> {
133             for (UnaryOperator<String> function : functions) {
134                 String v = function.apply(s);
135                 if (v != null) {
136                     return v;
137                 }
138             }
139             return null;
140         };
141     }
142 
143     @SafeVarargs
144     static UnaryOperator<String> chain(UnaryOperator<String>... functions) {
145         return chain(List.of(functions));
146     }
147 
148     /**
149      * Memoizes a given function that takes a String input and produces a String output.
150      * This method creates a new function that caches the results of the original function,
151      * improving performance for repeated calls with the same input.
152      *
153      * @param callback The original function to be memoized. It takes a String as input and returns a String.
154      * @return A new {@code UnaryOperator<String>} that caches the results of the original function.
155      *         If the original function returns null for a given input, null will be cached and returned for subsequent calls with the same input.
156      *
157      * @see Function
158      * @see Optional
159      * @see HashMap#computeIfAbsent(Object, Function)
160      */
161     static UnaryOperator<String> memoize(UnaryOperator<String> callback) {
162         Map<String, Optional<String>> cache = new HashMap<>();
163         return s -> cache.computeIfAbsent(s, v -> Optional.ofNullable(callback.apply(v)))
164                 .orElse(null);
165     }
166 }