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 java.util.concurrent.CompletableFuture.completedFuture;
023import static java.util.concurrent.CompletableFuture.failedFuture;
024
025import java.util.Optional;
026import java.util.concurrent.Callable;
027import java.util.concurrent.CompletionStage;
028import java.util.function.Function;
029
030/**
031 * Root interface to support global operations related to exception handling for
032 * functional interface returning Object result.
033 *
034 * @param <F>
035 *            the type of the java standard functional interface. For example,
036 *            {@code Function<T,R>}.
037 * @param <L>
038 *            the type of the lifted functional interface. For example,
039 *            {@code Function<T,Optional<R>>}.
040 * @param <S>
041 *            the type of the staged functional interface. For example,
042 *            {@code Function<T,CompletionStage<R>>}.
043 * @param <T>
044 *            the type of the return type of the Functional interface.
045 */
046public interface ObjectReturnExceptionHandlerSupport<F, L, S, T, Z extends ObjectReturnExceptionHandlerSupport<F, L, S, T, Z>>
047                extends ExceptionHandlerSupport<F, L, Z> {
048
049        /**
050         * Converts this functional interface to the corresponding one in java and wrap
051         * exception using {@link #exceptionMapper()}.
052         * <p>
053         * Conceptually, the exception encapsulation is done in the following way :
054         *
055         * <pre>
056         * (xxx) -&gt; {
057         *      try {
058         *              return realaction(xxx);
059         *      } catch (Exception e) {
060         *              throw new exceptionMapper().apply(e);
061         *      }
062         * }
063         * </pre>
064         *
065         * @return the unchecked operation
066         * @see #lift()
067         * @see #ignore()
068         */
069        @Override
070        F uncheck();
071
072        /**
073         * Converts this functional interface to a lifted one. The lifted version return
074         * an Optional of the original return type.
075         * <p>
076         * Conceptually, this is done by :
077         *
078         * <pre>
079         * (xxx) -&gt; {
080         *      try {
081         *              return Optional.ofNullable(realaction(xxx));
082         *      } catch (Exception e) {
083         *              return Optional.empty();
084         *      }
085         * }
086         * </pre>
087         *
088         * @return the lifted function
089         * @see #uncheck()
090         * @see #ignore()
091         */
092        @Override
093        L lift();
094
095        /**
096         * Converts this functional interface to the corresponding java standard
097         * functional interface returning a null in case of error.
098         * <p>
099         * The principle is :
100         *
101         * <pre>
102         * (xxx) -&gt; {
103         *      try {
104         *              return realaction(xxx);
105         *      } catch (Exception e) {
106         *              return null;
107         *      }
108         * }
109         * </pre>
110         *
111         * @return the operation that ignore error
112         * @see #uncheck()
113         * @see #lift()
114         */
115        @Override
116        F ignore();
117
118        /**
119         * Converts this functional interface to the corresponding java standard
120         * functional interface with staged result.
121         *
122         * @return the operation supporting stage.
123         * @since 1.1.0
124         * @see CompletionStage
125         */
126        S stage();
127
128        /**
129         * Defines the default value (by default {@code null}) returned by the ignore
130         * and ignored method.
131         *
132         * @return the default value for the ignore/ignored method.
133         * @since 3.0.0
134         */
135        default T defaultValue() {
136                return null;
137        }
138
139        /**
140         * Used internally to support the exception interception.
141         *
142         * @param internal
143         *            the call to be done
144         * @param exceptionhandler
145         *            the exception handler. May throw RuntimeException or return some
146         *            default value.
147         * @return the result
148         * @throws RuntimeException
149         *             in case of error
150         * @param <T>
151         *            type of the return value
152         */
153        static <T> T unchecked(Callable<T> internal, Function<Exception, T> exceptionhandler) {
154                try {
155                        return internal.call();
156                } catch (Exception e) {
157                        // exceptionhandler must throw the exception if needed
158                        return exceptionhandler.apply(e);
159                }
160        }
161
162        /**
163         * Used internally to support the exception interception.
164         *
165         * @param internal
166         *            the call to be done
167         * @return the completion stage
168         * @throws RuntimeException
169         *             in case of error
170         * @param <T>
171         *            type of the return value
172         */
173        static <T> CompletionStage<T> staged(Callable<T> internal) {
174                try {
175                        return completedFuture(internal.call());
176                } catch (Exception e) {
177                        return failedFuture(e);
178                }
179        }
180
181        /**
182         * Used internally to support the exception interception.
183         *
184         * @return exception handler to support exception control
185         */
186        default Function<Exception, T> throwingHandler() {
187                return e -> {
188                        throw exceptionMapper().apply(e);
189                };
190        }
191
192        /**
193         * Used internally to support the exception interception.
194         *
195         * @return exception handler to ignore exception
196         */
197        default Function<Exception, Optional<T>> notThrowingHandler() {
198                return e -> Optional.empty();
199        }
200}