001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2024–2025 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.bean;
015
016import java.util.List;
017import java.util.Objects;
018
019import java.util.concurrent.ConcurrentHashMap;
020
021import java.util.function.BiFunction;
022import java.util.function.Function;
023
024/**
025 * A {@linkplain FunctionalInterface functional interface} whose implementations can <dfn>reduce</dfn> an unspecified
026 * notional collection of elements to a single element according to some <em>criteria</em>.
027 *
028 * <p>This interface is related to, but should not be confused with, the {@link Reducer} interface, implementations of
029 * which can be used to build {@link Reducible} instances.</p>
030 *
031 * @param <C> the type of criteria
032 *
033 * @param <T> the element type
034 *
035 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
036 *
037 * @see #reduce(Object)
038 *
039 * @see Reducer
040 *
041 * @deprecated This interface is not really needed and is tentatively deprecated.
042 */
043@Deprecated(since = "0.0.18")
044@FunctionalInterface
045public interface Reducible<C, T> {
046
047
048  /*
049   * Instance methods.
050   */
051
052
053  /**
054   * Given a criteria object, which may be {@code null}, returns an object that represents the <em>reduction</em> of a
055   * notional collection of objects.
056   *
057   * <p>Most {@link Reducible} implementations will return determinate values from invocations of this method, but there
058   * is no requirement to do so.</p>
059   *
060   * @param criteria the criteria; may be {@code null} to indicate no criteria
061   *
062   * @return a single object, or {@code null}
063   *
064   * @exception ReductionException if reduction could not occur or if an error occurs
065   */
066  public T reduce(final C criteria);
067
068
069  /*
070   * Static methods.
071   */
072
073
074  /**
075   * Calls the {@link #of(Selectable, Reducer, BiFunction)} method with the supplied {@code selectable}, the supplied {@code r}, and a reference to the {@link Reducer#fail(List, Object)} method,
076   * and returns the result.
077   *
078   * @param <C> the criteria type
079   *
080   * @param <E> the element type
081   *
082   * @param selectable a {@link Selectable}; must not be {@code null}
083   *
084   * @param r a {@link Reducer}; must not be {@code null}
085   *
086   * @return a {@link Reducible}; never {@code null}
087   *
088   * @exception NullPointerException if {@code selectable} or {@code r} is {@code null}
089   *
090   * @see #of(Selectable, Reducer, BiFunction)
091   *
092   * @see Reducer#fail(List, Object)
093   */
094  public static <C, E> Reducible<C, E> of(final Selectable<C, E> selectable,
095                                          final Reducer<C, E> r) {
096    return of(selectable, r, Reducer::fail);
097  }
098
099  /**
100   * Returns a {@link Reducible} implementation that uses the supplied {@link Reducer} for its reduction operations.
101   *
102   * @param <C> the criteria type
103   *
104   * @param <E> the element type
105   *
106   * @param selectable a {@link Selectable}; must not be {@code null}
107   *
108   * @param r a {@link Reducer}; must not be {@code null}
109   *
110   * @param failureHandler a {@link BiFunction} serving as the supplied {@link Reducer}'s <dfn>failure handler</dfn>;
111   * must not be {@code null}
112   *
113   * @return a {@link Reducible}; never {@code null}
114   *
115   * @exception NullPointerException if any argument is {@code null}
116   *
117   * @see Reducer
118   */
119  public static <C, E> Reducible<C, E> of(final Selectable<C, E> selectable,
120                                          final Reducer<C, E> r,
121                                          final BiFunction<? super List<? extends E>, ? super C, ? extends E> failureHandler) {
122    Objects.requireNonNull(selectable, "selectable");
123    Objects.requireNonNull(r, "r");
124    final BiFunction<? super List<? extends E>, ? super C, ? extends E> fh = Objects.requireNonNull(failureHandler, "failureHandler");
125    return c -> r.reduce(selectable.select(c), c, fh);
126  }
127
128  /**
129   * Calls the {@link #ofCaching(Selectable, Reducer, BiFunction)} method with the supplied {@code selectable}, the
130   * supplied {@code r}, the supplied {@code failureHandler}, and a reference to the {@link Reducer#fail(List, Object)}
131   * method, and returns its result.
132   *
133   * @param <C> the criteria type
134   *
135   * @param <E> the element type
136   *
137   * @param selectable a {@link Selectable}; must not be {@code null}
138   *
139   * @param r a {@link Reducer}; must not be {@code null}
140   *
141   * @return a {@link Reducible}; never {@code null}
142   *
143   * @exception NullPointerException if any argument is {@code null}
144   *
145   * @see #ofCaching(Selectable, Reducer, BiFunction)
146   */
147  public static <C, E> Reducible<C, E> ofCaching(final Selectable<C, E> selectable, final Reducer<C, E> r) {
148    return ofCaching(selectable, r, Reducer::fail);
149  }
150
151  /**
152   * Calls the {@link #ofCaching(Selectable, Reducer, BiFunction, BiFunction)} method with the supplied {@code
153   * selectable}, the supplied {@code r}, the supplied {@code fh}, and a reference to the {@link
154   * ConcurrentHashMap#computeIfAbsent(Object, java.util.function.Function) computeIfAbsent(Object, Function)} method of
155   * a new {@link ConcurrentHashMap}, and returns its result.
156   *
157   * @param <C> the criteria type
158   *
159   * @param <E> the element type
160   *
161   * @param selectable a {@link Selectable}; must not be {@code null}
162   *
163   * @param r a {@link Reducer}; must not be {@code null}
164   *
165   * @param fh a {@link BiFunction} serving as the supplied {@link Reducer}'s <dfn>failure handler</dfn>;
166   * must not be {@code null}
167   *
168   * @return a {@link Reducible}; never {@code null}
169   *
170   * @exception NullPointerException if any argument is {@code null}
171   *
172   * @see #ofCaching(Selectable, Reducer, BiFunction, BiFunction)
173   */
174  public static <C, E> Reducible<C, E> ofCaching(final Selectable<C, E> selectable,
175                                                 final Reducer<C, E> r,
176                                                 final BiFunction<? super List<? extends E>, ? super C, ? extends E> fh) {
177    return ofCaching(selectable, r, fh, new ConcurrentHashMap<C, E>()::computeIfAbsent);
178  }
179
180  /**
181   * Returns a {@link Reducible} implementation that uses the supplied {@link Reducer} for its reduction operations and
182   * the supplied {@code computeIfAbsent} {@link BiFunction} for its caching implementation.
183   *
184   * @param <C> the criteria type
185   *
186   * @param <E> the element type
187   *
188   * @param selectable a {@link Selectable}; must not be {@code null}
189   *
190   * @param r a {@link Reducer}; must not be {@code null}
191   *
192   * @param fh a {@link BiFunction} serving as the supplied {@link Reducer}'s <dfn>failure handler</dfn>; must not be
193   * {@code null}
194   *
195   * @param cache a {@link BiFunction} with the same semantics as the {@link
196   * java.util.Map#computeIfAbsent(Object, java.util.function.Function)} method; must not be {@code null}
197   *
198   * @return a {@link Reducible}; never {@code null}
199   *
200   * @exception NullPointerException if any argument is {@code null}
201   *
202   * @see #of(Selectable, Reducer, BiFunction)
203   *
204   * @see java.util.Map#computeIfAbsent(Object, java.util.function.Function)
205   */
206  public static <C, E> Reducible<C, E> ofCaching(final Selectable<C, E> selectable,
207                                                 final Reducer<C, E> r,
208                                                 final BiFunction<? super List<? extends E>, ? super C, ? extends E> fh,
209                                                 final BiFunction<? super C, Function<C, E>, ? extends E> cache) {
210    Objects.requireNonNull(cache, "cache");
211    final Reducible<C, E> reducible = of(selectable, r, fh);
212    return c -> cache.apply(c, reducible::reduce);
213  }
214
215}