001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.util.function;
018
019import java.util.Objects;
020import java.util.Optional;
021import java.util.concurrent.atomic.AtomicReference;
022import java.util.function.Consumer;
023import java.util.function.Predicate;
024import java.util.function.Supplier;
025
026public final class Suppliers {
027    private Suppliers() {
028    }
029
030    /**
031     * Returns a supplier which caches the result of the first call to {@link Supplier#get()}and returns that value on
032     * subsequent calls.
033     *
034     * @param  supplier the delegate {@link Supplier}.
035     * @param  <T>      the type of results supplied by this supplier.
036     * @return          the result fo the first call to the delegate's {@link Supplier#get()} method.
037     */
038    public static <T> Supplier<T> memorize(Supplier<T> supplier) {
039        final AtomicReference<T> valueHolder = new AtomicReference<>();
040        return new Supplier<T>() {
041            @Override
042            public T get() {
043                T supplied = valueHolder.get();
044                if (supplied == null) {
045                    synchronized (valueHolder) {
046                        supplied = valueHolder.get();
047                        if (supplied == null) {
048                            supplied = Objects.requireNonNull(supplier.get(), "Supplier should not return null");
049                            valueHolder.lazySet(supplied);
050                        }
051                    }
052                }
053                return supplied;
054            }
055        };
056    }
057
058    /**
059     * Returns a supplier which caches the result of the first call to {@link Supplier#get()} and returns that value on
060     * subsequent calls.
061     *
062     * @param  supplier the delegate {@link Supplier}.
063     * @param  consumer a consumer for any exception thrown by the {@link ThrowingSupplier#get()}.
064     * @param  <T>      the type of results supplied by this supplier.
065     * @return          the result fo the first call to the delegate's {@link Supplier#get()} method.
066     */
067    public static <T> Supplier<T> memorize(ThrowingSupplier<T, ? extends Exception> supplier, Consumer<Exception> consumer) {
068        final AtomicReference<T> valueHolder = new AtomicReference<>();
069        return new Supplier<T>() {
070            @Override
071            public T get() {
072                T supplied = valueHolder.get();
073                if (supplied == null) {
074                    synchronized (valueHolder) {
075                        supplied = valueHolder.get();
076                        if (supplied == null) {
077                            try {
078                                supplied = Objects.requireNonNull(supplier.get(), "Supplier should not return null");
079                                valueHolder.lazySet(supplied);
080                            } catch (Exception e) {
081                                consumer.accept(e);
082                            }
083                        }
084                    }
085                }
086                return supplied;
087            }
088        };
089    }
090
091    /**
092     * Returns a supplier that return a constant value.
093     *
094     * @param  value the constant value to return.
095     * @param  <T>   the type of results supplied by this supplier.
096     * @return       the supplied {@code value}.
097     */
098    public static <T> Supplier<T> constant(T value) {
099        return new Supplier<T>() {
100            @Override
101            public T get() {
102                return value;
103            }
104        };
105    }
106
107    /**
108     * Returns the first non null value provide by the given suppliers.
109     *
110     * @param  suppliers a list of supplier.
111     * @param  <T>       the type of results supplied by this supplier.
112     * @return           the optional computed value.
113     */
114    @SafeVarargs
115    public static <T> Optional<T> firstNotNull(ThrowingSupplier<T, Exception>... suppliers) throws Exception {
116        T answer = null;
117
118        for (ThrowingSupplier<T, Exception> supplier : suppliers) {
119            answer = supplier.get();
120            if (answer != null) {
121                break;
122            }
123        }
124
125        return Optional.ofNullable(answer);
126    }
127
128    /**
129     * Returns the first value provide by the given suppliers that matches the given predicate.
130     *
131     * @param  predicate the predicate used to evaluate the computed values.
132     * @param  suppliers a list fo supplier.
133     * @param  <T>       the type of results supplied by this supplier.
134     * @return           the optional matching value.
135     */
136    public static <T> Optional<T> firstMatching(Predicate<T> predicate, ThrowingSupplier<T, Exception>... suppliers)
137            throws Exception {
138        T answer = null;
139
140        for (ThrowingSupplier<T, Exception> supplier : suppliers) {
141            answer = supplier.get();
142            if (predicate.test(answer)) {
143                break;
144            }
145        }
146
147        return Optional.ofNullable(answer);
148    }
149}