001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit.extensions.exceptions;
021
022import static ch.powerunit.extensions.exceptions.Constants.verifyExceptionMapper;
023import static ch.powerunit.extensions.exceptions.Constants.verifySupplier;
024
025import java.util.Optional;
026import java.util.concurrent.CompletionStage;
027import java.util.function.Function;
028import java.util.function.Supplier;
029
030/**
031 * Represents a supplier of results that may thrown exception.
032 *
033 * <p>
034 * There is no requirement that a new or distinct result be returned each time
035 * the supplier is invoked.
036 * <h3>General contract</h3>
037 * <ul>
038 * <li><b>{@link #get() T get() throws E}</b>&nbsp;-&nbsp;The functional
039 * method.</li>
040 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code Supplier<T>}</li>
041 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code Supplier<Optional<T>>}</li>
042 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code Supplier<T>}</li>
043 * </ul>
044 *
045 * @see Supplier
046 * @param <T>
047 *            the type of results supplied by this supplier
048 * @param <E>
049 *            the type of the potential exception of the operation
050 */
051@FunctionalInterface
052public interface SupplierWithException<T, E extends Exception> extends
053                ObjectReturnExceptionHandlerSupport<Supplier<T>, Supplier<Optional<T>>, Supplier<CompletionStage<T>>, T, SupplierWithException<T, E>> {
054
055        /**
056         * Gets a result.
057         *
058         * @return the result.
059         * @throws E
060         *             any exception
061         * @see Supplier#get()
062         */
063        T get() throws E;
064
065        /**
066         * Converts this {@code SupplierWithException} to a {@code Supplier} that wraps
067         * exception to {@code RuntimeException}.
068         *
069         * @return the unchecked supplier
070         * @see #unchecked(SupplierWithException)
071         * @see #unchecked(SupplierWithException, Function)
072         */
073        @Override
074        default Supplier<T> uncheck() {
075                return () -> ObjectReturnExceptionHandlerSupport.unchecked(this::get, throwingHandler());
076        }
077
078        /**
079         * Converts this {@code SupplierWithException} to a lifted {@code Supplier}
080         * using {@code Optional} as return value.
081         *
082         * @return the lifted supplier
083         * @see #lifted(SupplierWithException)
084         */
085        @Override
086        default Supplier<Optional<T>> lift() {
087                return () -> ObjectReturnExceptionHandlerSupport.unchecked(() -> Optional.ofNullable(get()),
088                                notThrowingHandler());
089        }
090
091        /**
092         * Converts this {@code SupplierWithException} to a lifted {@code Supplier}
093         * returning {@code null} (or the value redefined by the method
094         * {@link #defaultValue()}) in case of exception.
095         *
096         * @return the supplier that ignore error
097         * @see #ignored(SupplierWithException)
098         */
099        @Override
100        default Supplier<T> ignore() {
101                return () -> lift().get().orElse(defaultValue());
102        }
103
104        /**
105         * Convert this {@code SupplierWithException} to a lifted {@code Supplier}
106         * return {@code CompletionStage} as return value.
107         *
108         * @return the lifted supplier
109         * @see #staged(SupplierWithException)
110         */
111        @Override
112        default Supplier<CompletionStage<T>> stage() {
113                return () -> ObjectReturnExceptionHandlerSupport.staged(this::get);
114        }
115
116        /**
117         * Returns a supplier that always throw exception.
118         *
119         * @param exceptionBuilder
120         *            the supplier to create the exception
121         * @param <T>
122         *            the type of the return object to the operation
123         * @param <E>
124         *            the type of the exception
125         * @return an operation that always throw exception
126         */
127        static <T, E extends Exception> SupplierWithException<T, E> failing(Supplier<E> exceptionBuilder) {
128                return () -> {
129                        throw exceptionBuilder.get();
130                };
131        }
132
133        /**
134         * Converts a {@code SupplierWithException} to a {@code Supplier} that wraps
135         * exception to {@code RuntimeException}.
136         *
137         * @param supplier
138         *            to be unchecked
139         * @param <T>
140         *            the type of the output object to the operation
141         * @param <E>
142         *            the type of the potential exception
143         * @return the unchecked exception
144         * @see #uncheck()
145         * @see #unchecked(SupplierWithException, Function)
146         * @throws NullPointerException
147         *             if supplier is null
148         */
149        static <T, E extends Exception> Supplier<T> unchecked(SupplierWithException<T, E> supplier) {
150                return verifySupplier(supplier).uncheck();
151        }
152
153        /**
154         * Converts a {@code SupplierWithException} to a {@code Supplier} that wraps
155         * exception to {@code RuntimeException} by using the provided mapping function.
156         *
157         * @param supplier
158         *            the be unchecked
159         * @param exceptionMapper
160         *            a function to convert the exception to the runtime exception.
161         * @param <T>
162         *            the type of the output object to the operation
163         * @param <E>
164         *            the type of the potential exception
165         * @return the unchecked exception
166         * @see #uncheck()
167         * @see #unchecked(SupplierWithException)
168         * @throws NullPointerException
169         *             if supplier or exceptionMapper is null
170         */
171        static <T, E extends Exception> Supplier<T> unchecked(SupplierWithException<T, E> supplier,
172                        Function<Exception, RuntimeException> exceptionMapper) {
173                verifySupplier(supplier);
174                verifyExceptionMapper(exceptionMapper);
175                return new SupplierWithException<T, E>() {
176
177                        @Override
178                        public T get() throws E {
179                                return supplier.get();
180                        }
181
182                        @Override
183                        public Function<Exception, RuntimeException> exceptionMapper() {
184                                return exceptionMapper;
185                        }
186
187                }.uncheck();
188        }
189
190        /**
191         * Converts a {@code SupplierWithException} to a lifted {@code Supplier} using
192         * {@code Optional} as return value.
193         *
194         * @param supplier
195         *            to be lifted
196         * @param <T>
197         *            the type of the output object to the function
198         * @param <E>
199         *            the type of the potential exception
200         * @return the lifted function
201         * @see #lift()
202         * @throws NullPointerException
203         *             if supplier is null
204         */
205        static <T, E extends Exception> Supplier<Optional<T>> lifted(SupplierWithException<T, E> supplier) {
206                return verifySupplier(supplier).lift();
207        }
208
209        /**
210         * Converts a {@code SupplierWithException} to a lifted {@code Supplier}
211         * returning {@code null} in case of exception.
212         *
213         * @param supplier
214         *            to be lifted
215         * @param <T>
216         *            the type of the output object to the function
217         * @param <E>
218         *            the type of the potential exception
219         * @return the lifted supplier
220         * @see #ignore()
221         * @throws NullPointerException
222         *             if supplier is null
223         */
224        static <T, E extends Exception> Supplier<T> ignored(SupplierWithException<T, E> supplier) {
225                return verifySupplier(supplier).ignore();
226        }
227
228        /**
229         * Converts a {@code SupplierWithException} to a lifted {@code Supplier}
230         * returning a default value in case of exception.
231         *
232         * @param supplier
233         *            to be lifted
234         * @param defaultValue
235         *            the default value in case of exception
236         * @param <T>
237         *            the type of the output object to the function
238         * @param <E>
239         *            the type of the potential exception
240         * @return the lifted supplier
241         * @see #ignore()
242         * @see #ignored(SupplierWithException)
243         * @throws NullPointerException
244         *             if supplier is null
245         * @since 3.0.0
246         */
247        static <T, E extends Exception> Supplier<T> ignored(SupplierWithException<T, E> supplier, T defaultValue) {
248                verifySupplier(supplier);
249                return new SupplierWithException<T, E>() {
250
251                        @Override
252                        public T get() throws E {
253                                return supplier.get();
254                        }
255
256                        @Override
257                        public T defaultValue() {
258                                return defaultValue;
259                        }
260
261                }.ignore();
262        }
263
264        /**
265         * Convert this {@code SupplierWithException} to a lifted {@code Supplier}
266         * return {@code CompletionStage} as return value.
267         *
268         * @param supplier
269         *            to be lifted
270         * @param <T>
271         *            the type of the output object to the function
272         * @param <E>
273         *            the type of the potential exception
274         * @return the lifted supplier
275         * @see #stage()
276         * @throws NullPointerException
277         *             if supplier is null
278         */
279        static <T, E extends Exception> Supplier<CompletionStage<T>> staged(SupplierWithException<T, E> supplier) {
280                return verifySupplier(supplier).stage();
281        }
282
283        /**
284         * Converts a {@code SupplierWithException} to a {@code FunctionWithException}.
285         *
286         * @param supplier
287         *            the supplier to be converted
288         * @param <T>
289         *            the input type of the function
290         * @param <R>
291         *            the result type of the function
292         * @param <E>
293         *            the type of the potential exception
294         * @return the function
295         * @throws NullPointerException
296         *             if consumer is null
297         * @since 1.2.0
298         */
299        static <T, R, E extends Exception> FunctionWithException<T, R, E> asFunction(SupplierWithException<R, E> supplier) {
300                return verifySupplier(supplier).asFunction();
301        }
302
303        /**
304         * Converts a {@code SupplierWithException} to a {@code FunctionWithException} .
305         *
306         * @param <T1>
307         *            the input parameter of the function
308         * @return the function
309         * @since 1.2.0
310         */
311        default <T1> FunctionWithException<T1, T, E> asFunction() {
312                return t -> get();
313        }
314
315}