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