001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.function;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020import static org.apache.juneau.commons.utils.ThrowableUtils.*;
021
022import java.util.function.*;
023
024/**
025 * A functional interface representing a function that accepts five arguments, produces a result, and may throw a checked exception.
026 *
027 * <p>
028 * This interface extends {@link Function5} to allow the functional method
029 * to throw checked exceptions. The default {@link #apply(Object, Object, Object, Object, Object)} method wraps any checked exceptions in a
030 * {@link RuntimeException}, making it compatible with standard {@link Function5} usage while still allowing
031 * the implementation to throw checked exceptions via {@link #applyThrows(Object, Object, Object, Object, Object)}.
032 *
033 * <h5 class='section'>Features:</h5>
034 * <ul class='spaced-list'>
035 *    <li>Functional interface - can be used with lambda expressions and method references
036 *    <li>Exception support - allows checked exceptions to be thrown via {@link #applyThrows(Object, Object, Object, Object, Object)}
037 *    <li>Compatible with Function5 - implements {@link Function5#apply(Object, Object, Object, Object, Object)} by wrapping exceptions
038 *    <li>Dual interface - can be used as both Function5 and ThrowingFunction5
039 * </ul>
040 *
041 * <h5 class='section'>Use Cases:</h5>
042 * <ul class='spaced-list'>
043 *    <li>Five-argument transformations that may throw I/O exceptions
044 *    <li>Parsing operations that may throw validation exceptions
045 *    <li>Data conversion that may fail with checked exceptions
046 *    <li>Operations that need to propagate checked exceptions
047 * </ul>
048 *
049 * <h5 class='section'>Usage:</h5>
050 * <p class='bjava'>
051 *    <jc>// Lambda with exception</jc>
052 *    ThrowingFunction5&lt;String,String,String,String,String,File&gt; <jv>fileParser</jv> = (<jv>dir</jv>, <jv>subdir1</jv>, <jv>subdir2</jv>, <jv>subdir3</jv>, <jv>name</jv>) -&gt; {
053 *       Path <jv>path</jv> = Paths.get(<jv>dir</jv>, <jv>subdir1</jv>, <jv>subdir2</jv>, <jv>subdir3</jv>, <jv>name</jv>);
054 *       <jk>if</jk> (! Files.exists(<jv>path</jv>)) {
055 *          <jk>throw new</jk> FileNotFoundException(<js>"File not found: "</js> + <jv>path</jv>);
056 *       }
057 *       <jk>return</jk> <jv>path</jv>.toFile();
058 *    };
059 *
060 *    <jc>// Using applyThrows to get checked exception</jc>
061 *    <jk>try</jk> {
062 *       File <jv>file</jv> = <jv>fileParser</jv>.applyThrows(<js>"/tmp"</js>, <js>"data"</js>, <js>"2024"</js>, <js>"01"</js>, <js>"file.txt"</js>);
063 *    } <jk>catch</jk> (FileNotFoundException <jv>e</jv>) {
064 *       <jc>// Handle checked exception</jc>
065 *    }
066 *
067 *    <jc>// Using apply wraps exception in RuntimeException</jc>
068 *    File <jv>file</jv> = <jv>fileParser</jv>.apply(<js>"/tmp"</js>, <js>"data"</js>, <js>"2024"</js>, <js>"01"</js>, <js>"file.txt"</js>);  <jc>// May throw RuntimeException</jc>
069 * </p>
070 *
071 * <h5 class='section'>Exception Handling:</h5>
072 * <ul class='spaced-list'>
073 *    <li>{@link #applyThrows(Object, Object, Object, Object, Object)} - Throws checked exceptions directly
074 *    <li>{@link #apply(Object, Object, Object, Object, Object)} - Wraps checked exceptions in {@link RuntimeException}
075 *    <li>Use {@code applyThrows} when you need to handle specific checked exceptions
076 *    <li>Use {@code apply} when you want standard Function5 behavior
077 * </ul>
078 *
079 * <h5 class='section'>See Also:</h5><ul>
080 *    <li class='jc'>{@link ThrowingFunction} - Single-argument function that throws exceptions
081 *    <li class='jc'>{@link ThrowingFunction2} - Two-argument function that throws exceptions
082 *    <li class='jc'>{@link ThrowingFunction3} - Three-argument function that throws exceptions
083 *    <li class='jc'>{@link ThrowingFunction4} - Four-argument function that throws exceptions
084 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommons">juneau-commons</a>
085 * </ul>
086 *
087 * @param <A> The type of the first argument to the function.
088 * @param <B> The type of the second argument to the function.
089 * @param <C> The type of the third argument to the function.
090 * @param <D> The type of the fourth argument to the function.
091 * @param <E> The type of the fifth argument to the function.
092 * @param <R> The type of the result of the function.
093 */
094@FunctionalInterface
095@SuppressWarnings({
096   "java:S112", // throws Exception intentional - function may throw any checked exception
097   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
098})
099public interface ThrowingFunction5<A,B,C,D,E,R> extends Function5<A,B,C,D,E,R> {
100
101   /**
102    * Applies this function to the given arguments, wrapping any checked exceptions in a {@link RuntimeException}.
103    *
104    * <p>
105    * This is the default implementation that makes this interface compatible with {@link Function5}.
106    * It calls {@link #applyThrows(Object, Object, Object, Object, Object)} and wraps any checked exceptions.
107    *
108    * @param a The first function argument.
109    * @param b The second function argument.
110    * @param c The third function argument.
111    * @param d The fourth function argument.
112    * @param e The fifth function argument.
113    * @return The function result.
114    * @throws RuntimeException if {@link #applyThrows(Object, Object, Object, Object, Object)} throws a checked exception.
115    */
116   @Override
117   default R apply(A a, B b, C c, D d, E e) {
118      try {
119         return applyThrows(a, b, c, d, e);
120      } catch (Exception ex) {
121         throw toRex(ex);
122      }
123   }
124
125   /**
126    * Returns a composed function that first applies this function to its input, and then applies
127    * the {@code after} function to the result.
128    *
129    * <p>
130    * This method enables function composition, allowing you to chain multiple transformations together.
131    * The composed function will throw exceptions from this function, but the {@code after} function
132    * is a standard {@link Function} that does not throw checked exceptions.
133    *
134    * @param <V> The type of output of the {@code after} function, and of the composed function.
135    * @param after The function to apply after this function is applied. Must not be <jk>null</jk>.
136    * @return A composed {@link ThrowingFunction5} that first applies this function and then applies the {@code after} function.
137    * @throws NullPointerException if {@code after} is <jk>null</jk>.
138    */
139   @Override
140   default <V> ThrowingFunction5<A,B,C,D,E,V> andThen(Function<? super R,? extends V> after) {
141      reqnn("after", after);
142      return (A a, B b, C c, D d, E e) -> after.apply(applyThrows(a, b, c, d, e));
143   }
144
145   /**
146    * Applies this function to the given arguments, potentially throwing a checked exception.
147    *
148    * <p>
149    * This is the functional method that implementations must provide. It allows checked exceptions
150    * to be thrown directly, unlike the standard {@link Function5#apply(Object, Object, Object, Object, Object)} method.
151    *
152    * <h5 class='section'>Example:</h5>
153    * <p class='bjava'>
154    *    ThrowingFunction5&lt;String,Integer,Boolean,Double,Long,Integer&gt; <jv>parser</jv> = (<jv>s</jv>, <jv>base</jv>, <jv>signed</jv>, <jv>multiplier</jv>, <jv>offset</jv>) -&gt; {
155    *       <jk>try</jk> {
156    *          <jk>int</jk> <jv>value</jv> = Integer.parseInt(<jv>s</jv>, <jv>base</jv>);
157    *          <jv>value</jv> = <jv>signed</jv> ? <jv>value</jv> : Math.abs(<jv>value</jv>);
158    *          <jk>return</jk> (<jk>int</jk>)(<jv>value</jv> * <jv>multiplier</jv> + <jv>offset</jv>);
159    *       } <jk>catch</jk> (NumberFormatException <jv>e</jv>) {
160    *          <jk>throw new</jk> ParseException(<js>"Invalid number: "</js> + <jv>s</jv> + <js>" in base "</js> + <jv>base</jv>, 0);
161    *       }
162    *    };
163    *
164    *    <jk>try</jk> {
165    *       <jk>int</jk> <jv>value</jv> = <jv>parser</jv>.applyThrows(<js>"123"</js>, 10, <jk>true</jk>, 2.0, 100L);
166    *    } <jk>catch</jk> (ParseException <jv>e</jv>) {
167    *       <jc>// Handle checked exception</jc>
168    *    }
169    * </p>
170    *
171    * @param a The first function argument.
172    * @param b The second function argument.
173    * @param c The third function argument.
174    * @param d The fourth function argument.
175    * @param e The fifth function argument.
176    * @return The function result.
177    * @throws Exception If an error occurs during function execution.
178    */
179   R applyThrows(A a, B b, C c, D d, E e) throws Exception;
180}
181