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.verifyPredicate;
024import static java.util.Objects.requireNonNull;
025
026import java.util.function.Function;
027import java.util.function.Predicate;
028import java.util.function.Supplier;
029
030/**
031 * Represents a predicate (boolean-valued function) of one argument and may
032 * throw an exception.
033 * <h3>General contract</h3>
034 * <ul>
035 * <li><b>{@link #test(Object) boolean test(T t) throws E}</b>&nbsp;-&nbsp;The
036 * functional method.</li>
037 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code Predicate<T>}</li>
038 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code Predicate<T>}</li>
039 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code Predicate<T>}</li>
040 * </ul>
041 *
042 * @see Predicate
043 * @param <T>
044 *            the type of the input to the predicate
045 * @param <E>
046 *            the type of the potential exception of the function
047 */
048@FunctionalInterface
049public interface PredicateWithException<T, E extends Exception> extends
050                PrimitiveReturnExceptionHandlerSupport<Predicate<T>, PredicateWithException<T, E>>, BooleanDefaultValue {
051
052        /**
053         * Evaluates this predicate on the given argument.
054         *
055         * @param t
056         *            the input argument
057         * @return {@code true} if the input argument matches the predicate, otherwise
058         *         {@code false}
059         * @throws E
060         *             any exception
061         * @see Predicate#test(Object)
062         */
063        boolean test(T t) throws E;
064
065        @Override
066        default Predicate<T> uncheckOrIgnore(boolean uncheck) {
067                return value -> {
068                        try {
069                                return test(value);
070                        } catch (Exception e) {
071                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
072                                return defaultValue();
073                        }
074                };
075        }
076
077        /**
078         * Returns a composed predicate that represents a short-circuiting logical AND
079         * of this predicate and another. When evaluating the composed predicate, if
080         * this predicate is {@code false}, then the {@code other} predicate is not
081         * evaluated.
082         *
083         * <p>
084         * Any exceptions thrown during evaluation of either predicate are relayed to
085         * the caller; if evaluation of this predicate throws an exception, the
086         * {@code other} predicate will not be evaluated.
087         *
088         * @param other
089         *            a predicate that will be logically-ANDed with this predicate
090         * @return a composed predicate that represents the short-circuiting logical AND
091         *         of this predicate and the {@code other} predicate
092         * @throws NullPointerException
093         *             if other is null
094         * @see #or(PredicateWithException)
095         * @see #negate()
096         */
097        default PredicateWithException<T, E> and(PredicateWithException<? super T, ? extends E> other) {
098                requireNonNull(other);
099                return t -> test(t) && other.test(t);
100        }
101
102        /**
103         * Returns a predicate that represents the logical negation of this predicate.
104         *
105         * @return a predicate that represents the logical negation of this predicate
106         * @see #and(PredicateWithException)
107         * @see #or(PredicateWithException)
108         */
109        default PredicateWithException<T, E> negate() {
110                return t -> !test(t);
111        }
112
113        /**
114         * Negate a {@code PredicateWithException}.
115         *
116         * @param predicate
117         *            to be negate
118         * @param <T>
119         *            the type of the input to the predicate
120         * @param <E>
121         *            the type of the potential exception
122         * @return the negated predicate
123         * @see #negate()
124         * @throws NullPointerException
125         *             if predicate is null
126         */
127        static <T, E extends Exception> PredicateWithException<T, E> negate(PredicateWithException<T, E> predicate) {
128                return verifyPredicate(predicate).negate();
129        }
130
131        /**
132         * Returns a composed predicate that represents a short-circuiting logical OR of
133         * this predicate and another. When evaluating the composed predicate, if this
134         * predicate is {@code true}, then the {@code other} predicate is not evaluated.
135         *
136         * <p>
137         * Any exceptions thrown during evaluation of either predicate are relayed to
138         * the caller; if evaluation of this predicate throws an exception, the
139         * {@code other} predicate will not be evaluated.
140         *
141         * @param other
142         *            a predicate that will be logically-ORed with this predicate
143         * @return a composed predicate that represents the short-circuiting logical OR
144         *         of this predicate and the {@code other} predicate
145         * @throws NullPointerException
146         *             if other is null
147         * @see #and(PredicateWithException)
148         * @see #negate()
149         */
150        default PredicateWithException<T, E> or(PredicateWithException<? super T, ? extends E> other) {
151                requireNonNull(other);
152                return t -> test(t) || other.test(t);
153        }
154
155        /**
156         * Returns a predicate that always throw exception.
157         *
158         * @param exceptionBuilder
159         *            the supplier to create the exception
160         * @param <T>
161         *            the type of the input to the predicate
162         * @param <E>
163         *            the type of the exception
164         * @return a predicate that always throw exception
165         */
166        static <T, E extends Exception> PredicateWithException<T, E> failing(Supplier<E> exceptionBuilder) {
167                return t -> {
168                        throw exceptionBuilder.get();
169                };
170        }
171
172        /**
173         * Converts a {@code PredicateWithException} to a {@code Predicate} that wraps
174         * exception to {@code RuntimeException}.
175         *
176         * @param predicate
177         *            to be unchecked
178         * @param <T>
179         *            the type of the input to the predicate
180         * @param <E>
181         *            the type of the potential exception
182         * @return the unchecked exception
183         * @see #uncheck()
184         * @see #unchecked(PredicateWithException, Function)
185         * @throws NullPointerException
186         *             if predicate is null
187         */
188        static <T, E extends Exception> Predicate<T> unchecked(PredicateWithException<T, E> predicate) {
189                return verifyPredicate(predicate).uncheck();
190        }
191
192        /**
193         * Converts a {@code PredicateWithException} to a {@code Predicate} that wraps
194         * exception to {@code RuntimeException} by using the provided mapping function.
195         *
196         * @param predicate
197         *            the be unchecked
198         * @param exceptionMapper
199         *            a function to convert the exception to the runtime exception.
200         * @param <T>
201         *            the type of the input object to the function
202         * @param <E>
203         *            the type of the potential exception
204         * @return the unchecked exception
205         * @see #uncheck()
206         * @see #unchecked(PredicateWithException)
207         * @throws NullPointerException
208         *             if predicate or exceptionMapper is null
209         */
210        static <T, E extends Exception> Predicate<T> unchecked(PredicateWithException<T, E> predicate,
211                        Function<Exception, RuntimeException> exceptionMapper) {
212                verifyPredicate(predicate);
213                verifyExceptionMapper(exceptionMapper);
214                return new PredicateWithException<T, E>() {
215
216                        @Override
217                        public boolean test(T t) throws E {
218                                return predicate.test(t);
219                        }
220
221                        @Override
222                        public Function<Exception, RuntimeException> exceptionMapper() {
223                                return exceptionMapper;
224                        }
225
226                }.uncheck();
227        }
228
229        /**
230         * Converts a {@code PredicateWithException} to a lifted {@code Predicate}
231         * returning {@code false} in case of exception.
232         *
233         * @param predicate
234         *            to be lifted
235         * @param <T>
236         *            the type of the input to the predicate
237         * @param <E>
238         *            the type of the potential exception
239         * @return the lifted predicate
240         * @see #lift()
241         * @throws NullPointerException
242         *             if predicate is null
243         */
244        static <T, E extends Exception> Predicate<T> lifted(PredicateWithException<T, E> predicate) {
245                return verifyPredicate(predicate).lift();
246        }
247
248        /**
249         * Converts a {@code PredicateWithException} to a lifted {@code Predicate}
250         * returning {@code false} in case of exception.
251         *
252         * @param predicate
253         *            to be lifted
254         * @param <T>
255         *            the type of the input to the predicate
256         * @param <E>
257         *            the type of the potential exception
258         * @return the lifted predicate
259         * @see #ignore()
260         * @throws NullPointerException
261         *             if predicate is null
262         */
263        static <T, E extends Exception> Predicate<T> ignored(PredicateWithException<T, E> predicate) {
264                return verifyPredicate(predicate).ignore();
265        }
266
267        /**
268         * Converts a {@code PredicateWithException} to a lifted {@code Predicate}
269         * returning a default value in case of exception.
270         *
271         * @param predicate
272         *            to be lifted
273         * @param defaultValue
274         *            value in case of exception
275         * @param <T>
276         *            the type of the input to the predicate
277         * @param <E>
278         *            the type of the potential exception
279         * @return the lifted predicate
280         * @see #ignore()
281         * @see #ignored(PredicateWithException)
282         * @throws NullPointerException
283         *             if predicate is null
284         * @since 3.0.0
285         */
286        static <T, E extends Exception> Predicate<T> ignored(PredicateWithException<T, E> predicate, boolean defaultValue) {
287                verifyPredicate(predicate);
288                return new PredicateWithException<T, E>() {
289
290                        @Override
291                        public boolean test(T t) throws E {
292                                return predicate.test(t);
293                        }
294
295                        @Override
296                        public boolean defaultValue() {
297                                return defaultValue;
298                        }
299
300                }.ignore();
301        }
302
303}