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.verifyFunction;
024
025import java.util.Optional;
026import java.util.function.BiFunction;
027import java.util.function.BinaryOperator;
028import java.util.function.Function;
029import java.util.function.Supplier;
030
031/**
032 * Represents an operation upon two operands of the same type, that may throw
033 * exception, producing a result of the same type as the operands. This is a
034 * specialization of {@link BiFunctionWithException} for the case where the
035 * operands and the result are all of the same type.
036 * <p>
037 * As this interface must return the same type of the input, a lifted version
038 * which returns {@code Optional} is not possible.
039 * <h3>General contract</h3>
040 * <ul>
041 * <li><b>{@link #apply(Object, Object) T apply(T t, T u) throws
042 * E}</b>&nbsp;-&nbsp;The functional method.</li>
043 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code BinaryOperator<T>}</li>
044 * <li><b>lift</b>&nbsp;-&nbsp;Return a
045 * {@code BiFunction<T,T,<Optional<T>>}</li>
046 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code BinaryOperator<T>}</li>
047 * </ul>
048 *
049 * @see BiFunctionWithException
050 * @see BinaryOperator
051 * @param <T>
052 *            the type of the operands and result of the operator
053 * @param <E>
054 *            the type of the potential exception of the function
055 */
056@FunctionalInterface
057public interface BinaryOperatorWithException<T, E extends Exception> extends BiFunctionWithException<T, T, T, E> {
058
059        /**
060         * Converts this {@code BinaryOperatorWithException} to a {@code BinaryOperator}
061         * that convert exception to {@code RuntimeException}.
062         *
063         * @return the unchecked function
064         * @see #unchecked(BinaryOperatorWithException)
065         * @see #unchecked(BinaryOperatorWithException, Function)
066         */
067        @Override
068        default BinaryOperator<T> uncheck() {
069                return (t, u) -> ObjectReturnExceptionHandlerSupport.unchecked(() -> apply(t, u), throwingHandler());
070        }
071
072        /**
073         * Converts this {@code BinaryOperatorWithException} to a lifted
074         * {@code BinaryOperator} returning {@code null} in case of exception.
075         *
076         * @return the function that ignore error
077         * @see #ignored(BinaryOperatorWithException)
078         */
079        @Override
080        default BinaryOperator<T> ignore() {
081                return (t, u) -> ObjectReturnExceptionHandlerSupport.unchecked(() -> apply(t, u), e -> null);
082        }
083
084        @Override
085        default BinaryOperatorWithException<T, E> documented(Supplier<String> toString) {
086                return (BinaryOperatorWithException<T, E>) BiFunctionWithException.super.documented(toString);
087        }
088
089        /**
090         * Returns a binary operator that always throw exception.
091         *
092         * @param exceptionBuilder
093         *            the supplier to create the exception
094         * @param <T>
095         *            the type of the operands and result of the operator
096         * @param <E>
097         *            the type of the exception
098         * @return a function that always throw exception
099         */
100        static <T, E extends Exception> BinaryOperatorWithException<T, E> failing(Supplier<E> exceptionBuilder) {
101                return (t, u) -> {
102                        throw exceptionBuilder.get();
103                };
104        }
105
106        /**
107         * Converts a {@code BinaryOperatorWithException} to a {@code BinaryOperator}
108         * that convert exception to {@code RuntimeException}.
109         *
110         * @param function
111         *            to be unchecked
112         * @param <T>
113         *            the type of the operands and result of the operator
114         * @param <E>
115         *            the type of the potential exception
116         * @return the unchecked exception
117         * @see #uncheck()
118         * @see #unchecked(BinaryOperatorWithException, Function)
119         * @throws NullPointerException
120         *             if function is null
121         */
122        static <T, E extends Exception> BinaryOperator<T> unchecked(BinaryOperatorWithException<T, E> function) {
123                return verifyFunction(function).uncheck();
124        }
125
126        /**
127         * Converts a {@code BinaryOperatorWithException} to a {@code BinaryOperator}
128         * that convert exception to {@code RuntimeException} by using the provided
129         * mapping function.
130         *
131         * @param function
132         *            the be unchecked
133         * @param exceptionMapper
134         *            a function to convert the exception to the runtime exception.
135         * @param <T>
136         *            the type of the operands and result of the operator
137         * @param <E>
138         *            the type of the potential exception
139         * @return the unchecked exception
140         * @see #uncheck()
141         * @see #unchecked(BinaryOperatorWithException)
142         * @throws NullPointerException
143         *             if function or exceptionMapper is null
144         */
145        static <T, E extends Exception> BinaryOperator<T> unchecked(BinaryOperatorWithException<T, E> function,
146                        Function<Exception, RuntimeException> exceptionMapper) {
147                verifyFunction(function);
148                verifyExceptionMapper(exceptionMapper);
149                return new BinaryOperatorWithException<T, E>() {
150
151                        @Override
152                        public T apply(T t, T u) throws E {
153                                return function.apply(t, u);
154                        }
155
156                        @Override
157                        public Function<Exception, RuntimeException> exceptionMapper() {
158                                return exceptionMapper;
159                        }
160
161                }.uncheck();
162        }
163
164        /**
165         * Converts a {@code BinaryOperatorWithException} to a lifted {@code Function}
166         * returning an optional in case of exception.
167         *
168         * @param function
169         *            the be unchecked
170         * @param <T>
171         *            the type of the operands and result of the operator
172         * @param <E>
173         *            the type of the potential exception
174         * @return the lifted function
175         * @see #ignore()
176         * @throws NullPointerException
177         *             if function is null
178         */
179        static <T, E extends Exception> BiFunction<T, T, Optional<T>> lifted(BinaryOperatorWithException<T, E> function) {
180                return verifyFunction(function).lift();
181        }
182
183        /**
184         * Converts a {@code BinaryOperatorWithException} to a lifted
185         * {@code BinaryOperator} returning {@code null} in case of exception.
186         *
187         * @param function
188         *            the be unchecked
189         * @param <T>
190         *            the type of the operands and result of the operator
191         * @param <E>
192         *            the type of the potential exception
193         * @return the lifted function
194         * @see #ignore()
195         * @throws NullPointerException
196         *             if function is null
197         */
198        static <T, E extends Exception> BinaryOperator<T> ignored(BinaryOperatorWithException<T, E> function) {
199                return verifyFunction(function).ignore();
200        }
201
202}