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.BiFunction;
27  import java.util.function.Function;
28  
29  import org.apache.maven.api.Service;
30  import org.apache.maven.api.annotations.Experimental;
31  import org.apache.maven.api.annotations.Nonnull;
32  import org.apache.maven.api.annotations.Nullable;
33  
34  /**
35   * The Interpolator service provides methods for variable substitution in strings and maps.
36   * It allows for the replacement of placeholders (e.g., ${variable}) with their corresponding values.
37   *
38   * @since 4.0.0
39   */
40  @Experimental
41  public interface Interpolator extends Service {
42  
43      /**
44       * Interpolates the values in the given map using the provided callback function.
45       * This method defaults to setting empty strings for unresolved placeholders.
46       *
47       * @param properties The map containing key-value pairs to be interpolated.
48       * @param callback The function to resolve variable values not found in the map.
49       */
50      default void interpolate(@Nonnull Map<String, String> properties, @Nullable Function<String, String> callback) {
51          interpolate(properties, callback, null, true);
52      }
53  
54      /**
55       * Interpolates the values in the given map using the provided callback function.
56       *
57       * @param map The map containing key-value pairs to be interpolated.
58       * @param callback The function to resolve variable values not found in the map.
59       * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings. If false, they are left unchanged.
60       */
61      default void interpolate(
62              @Nonnull Map<String, String> map, @Nullable Function<String, String> callback, boolean defaultsToEmpty) {
63          interpolate(map, callback, null, defaultsToEmpty);
64      }
65  
66      /**
67       * Interpolates the values in the given map using the provided callback function.
68       *
69       * @param map The map containing key-value pairs to be interpolated.
70       * @param callback The function to resolve variable values not found in the map.
71       * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings.  If false, they are left unchanged.
72       */
73      void interpolate(
74              @Nonnull Map<String, String> map,
75              @Nullable Function<String, String> callback,
76              @Nullable BiFunction<String, String, String> postprocessor,
77              boolean defaultsToEmpty);
78  
79      /**
80       * Interpolates a single string value using the provided callback function.
81       * This method defaults to not replacing unresolved placeholders.
82       *
83       * @param val The string to be interpolated.
84       * @param callback The function to resolve variable values.
85       * @return The interpolated string, or null if the input was null.
86       */
87      @Nullable
88      default String interpolate(@Nullable String val, @Nullable Function<String, String> callback) {
89          return interpolate(val, callback, false);
90      }
91  
92      /**
93       * Interpolates a single string value using the provided callback function.
94       *
95       * @param val The string to be interpolated.
96       * @param callback The function to resolve variable values.
97       * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings.
98       * @return The interpolated string, or null if the input was null.
99       */
100     @Nullable
101     default String interpolate(
102             @Nullable String val, @Nullable Function<String, String> callback, boolean defaultsToEmpty) {
103         return interpolate(val, callback, null, defaultsToEmpty);
104     }
105 
106     /**
107      * Interpolates a single string value using the provided callback function.
108      *
109      * @param val The string to be interpolated.
110      * @param callback The function to resolve variable values.
111      * @param defaultsToEmpty If true, unresolved placeholders are replaced with empty strings.
112      * @return The interpolated string, or null if the input was null.
113      */
114     @Nullable
115     String interpolate(
116             @Nullable String val,
117             @Nullable Function<String, String> callback,
118             @Nullable BiFunction<String, String, String> postprocessor,
119             boolean defaultsToEmpty);
120 
121     /**
122      * Creates a composite function from a collection of functions.
123      *
124      * @param functions A collection of functions, each taking a String as input and returning a String.
125      * @return A function that applies each function in the collection in order until a non-null result is found.
126      *         If all functions return null, the composite function returns null.
127      *
128      * @throws NullPointerException if the input collection is null or contains null elements.
129      */
130     static Function<String, String> chain(Collection<? extends Function<String, String>> functions) {
131         return s -> {
132             for (Function<String, String> function : functions) {
133                 String v = function.apply(s);
134                 if (v != null) {
135                     return v;
136                 }
137             }
138             return null;
139         };
140     }
141 
142     @SafeVarargs
143     static Function<String, String> chain(Function<String, String>... functions) {
144         return chain(List.of(functions));
145     }
146 
147     /**
148      * Memoizes a given function that takes a String input and produces a String output.
149      * This method creates a new function that caches the results of the original function,
150      * improving performance for repeated calls with the same input.
151      *
152      * @param callback The original function to be memoized. It takes a String as input and returns a String.
153      * @return A new {@code Function<String, String>} that caches the results of the original function.
154      *         If the original function returns null for a given input, null will be cached and returned for subsequent calls with the same input.
155      *
156      * @see Function
157      * @see Optional
158      * @see HashMap#computeIfAbsent(Object, Function)
159      */
160     static Function<String, String> memoize(Function<String, String> callback) {
161         Map<String, Optional<String>> cache = new HashMap<>();
162         return s -> cache.computeIfAbsent(s, v -> Optional.ofNullable(callback.apply(v)))
163                 .orElse(null);
164     }
165 }