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.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.ThrowableUtils.*;
021
022/**
023 * A functional interface representing an operation that accepts five arguments, returns no result, and may throw a checked exception.
024 *
025 * <p>
026 * This interface extends {@link Consumer5} to allow the functional method
027 * to throw checked exceptions. The default {@link #apply(Object, Object, Object, Object, Object)} method wraps any checked exceptions in a
028 * {@link RuntimeException}, making it compatible with standard {@link Consumer5} usage while still allowing
029 * the implementation to throw checked exceptions via {@link #acceptThrows(Object, Object, Object, Object, Object)}.
030 *
031 * <h5 class='section'>Features:</h5>
032 * <ul class='spaced-list'>
033 *    <li>Functional interface - can be used with lambda expressions and method references
034 *    <li>Exception support - allows checked exceptions to be thrown via {@link #acceptThrows(Object, Object, Object, Object, Object)}
035 *    <li>Compatible with Consumer5 - implements {@link Consumer5#apply(Object, Object, Object, Object, Object)} by wrapping exceptions
036 *    <li>Dual interface - can be used as both Consumer5 and ThrowingConsumer5
037 * </ul>
038 *
039 * <h5 class='section'>Use Cases:</h5>
040 * <ul class='spaced-list'>
041 *    <li>Five-argument operations that may throw I/O exceptions
042 *    <li>Validation operations that may throw validation exceptions
043 *    <li>Side-effect operations that may fail with checked exceptions
044 *    <li>Operations that need to propagate checked exceptions
045 * </ul>
046 *
047 * <h5 class='section'>Usage:</h5>
048 * <p class='bjava'>
049 *    <jc>// Lambda with exception</jc>
050 *    ThrowingConsumer5&lt;String,Integer,Boolean,Double,Long&gt; <jv>fileWriter</jv> = (<jv>path</jv>, <jv>content</jv>, <jv>append</jv>, <jv>timeout</jv>, <jv>timestamp</jv>) -&gt; {
051 *       <jk>if</jk> (<jv>append</jv>) {
052 *          Files.write(Paths.get(<jv>path</jv>), <jv>content</jv>.getBytes(), StandardOpenOption.APPEND);
053 *       } <jk>else</jk> {
054 *          Files.write(Paths.get(<jv>path</jv>), <jv>content</jv>.getBytes());
055 *       }
056 *    };
057 *
058 *    <jc>// Using acceptThrows to get checked exception</jc>
059 *    <jk>try</jk> {
060 *       <jv>fileWriter</jv>.acceptThrows(<js>"/tmp/output.txt"</js>, <js>"Hello World"</js>, <jk>true</jk>, 5.0, 1234567890L);
061 *    } <jk>catch</jk> (IOException <jv>e</jv>) {
062 *       <jc>// Handle checked exception</jc>
063 *    }
064 *
065 *    <jc>// Using apply wraps exception in RuntimeException</jc>
066 *    <jv>fileWriter</jv>.apply(<js>"/tmp/output.txt"</js>, <js>"Hello World"</js>, <jk>true</jk>, 5.0, 1234567890L);  <jc>// May throw RuntimeException</jc>
067 * </p>
068 *
069 * <h5 class='section'>Exception Handling:</h5>
070 * <ul class='spaced-list'>
071 *    <li>{@link #acceptThrows(Object, Object, Object, Object, Object)} - Throws checked exceptions directly
072 *    <li>{@link #apply(Object, Object, Object, Object, Object)} - Wraps checked exceptions in {@link RuntimeException}
073 *    <li>Use {@code acceptThrows} when you need to handle specific checked exceptions
074 *    <li>Use {@code apply} when you want standard Consumer5 behavior
075 * </ul>
076 *
077 * <h5 class='section'>See Also:</h5><ul>
078 *    <li class='jc'>{@link ThrowingConsumer} - Single-argument consumer that throws exceptions
079 *    <li class='jc'>{@link ThrowingConsumer2} - Two-argument consumer that throws exceptions
080 *    <li class='jc'>{@link ThrowingConsumer3} - Three-argument consumer that throws exceptions
081 *    <li class='jc'>{@link ThrowingConsumer4} - Four-argument consumer that throws exceptions
082 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsBasics">juneau-commons Basics</a>
083 * </ul>
084 *
085 * @param <A> The type of the first argument to the operation.
086 * @param <B> The type of the second argument to the operation.
087 * @param <C> The type of the third argument to the operation.
088 * @param <D> The type of the fourth argument to the operation.
089 * @param <E> The type of the fifth argument to the operation.
090 */
091@FunctionalInterface
092public interface ThrowingConsumer5<A,B,C,D,E> extends Consumer5<A,B,C,D,E> {
093
094   /**
095    * Performs this operation on the given arguments, wrapping any checked exceptions in a {@link RuntimeException}.
096    *
097    * <p>
098    * This is the default implementation that makes this interface compatible with {@link Consumer5}.
099    * It calls {@link #acceptThrows(Object, Object, Object, Object, Object)} and wraps any checked exceptions.
100    *
101    * @param a The first operation argument.
102    * @param b The second operation argument.
103    * @param c The third operation argument.
104    * @param d The fourth operation argument.
105    * @param e The fifth operation argument.
106    * @throws RuntimeException if {@link #acceptThrows(Object, Object, Object, Object, Object)} throws a checked exception.
107    */
108   @Override
109   default void apply(A a, B b, C c, D d, E e) {
110      try {
111         acceptThrows(a, b, c, d, e);
112      } catch (Exception ex) {
113         throw toRex(ex);
114      }
115   }
116
117   /**
118    * Returns a composed {@link ThrowingConsumer5} that performs, in sequence, this operation followed by the {@code after} operation.
119    *
120    * <p>
121    * This method enables operation composition, allowing you to chain multiple operations together.
122    * If performing either operation throws an exception, it is relayed to the caller of the composed operation.
123    * If performing this operation throws an exception, the {@code after} operation will not be performed.
124    *
125    * @param after The operation to perform after this operation. Must not be <jk>null</jk>.
126    * @return A composed {@link ThrowingConsumer5} that performs in sequence this operation followed by the {@code after} operation.
127    * @throws NullPointerException if {@code after} is <jk>null</jk>.
128    */
129   default ThrowingConsumer5<A,B,C,D,E> andThen(ThrowingConsumer5<? super A,? super B,? super C,? super D,? super E> after) {  // NOSONAR - false positive on generics
130      assertArgNotNull("after", after);
131      return (A a, B b, C c, D d, E e) -> {
132         acceptThrows(a, b, c, d, e);
133         after.acceptThrows(a, b, c, d, e);
134      };
135   }
136
137   /**
138    * Performs this operation on the given arguments, potentially throwing a checked exception.
139    *
140    * <p>
141    * This is the functional method that implementations must provide. It allows checked exceptions
142    * to be thrown directly, unlike the standard {@link Consumer5#apply(Object, Object, Object, Object, Object)} method.
143    *
144    * <h5 class='section'>Example:</h5>
145    * <p class='bjava'>
146    *    ThrowingConsumer5&lt;String,Integer,Boolean,Double,Long&gt; <jv>validator</jv> = (<jv>name</jv>, <jv>age</jv>, <jv>active</jv>, <jv>score</jv>, <jv>timestamp</jv>) -&gt; {
147    *       <jk>if</jk> (<jv>name</jv> == <jk>null</jk> || <jv>name</jv>.isEmpty()) {
148    *          <jk>throw new</jk> ValidationException(<js>"Name cannot be empty"</js>);
149    *       }
150    *       <jk>if</jk> (<jv>age</jv> &lt; 0) {
151    *          <jk>throw new</jk> ValidationException(<js>"Age cannot be negative"</js>);
152    *       }
153    *    };
154    *
155    *    <jk>try</jk> {
156    *       <jv>validator</jv>.acceptThrows(<js>""</js>, -1, <jk>true</jk>, 0.0, 0L);
157    *    } <jk>catch</jk> (ValidationException <jv>e</jv>) {
158    *       <jc>// Handle checked exception</jc>
159    *    }
160    * </p>
161    *
162    * @param a The first operation argument.
163    * @param b The second operation argument.
164    * @param c The third operation argument.
165    * @param d The fourth operation argument.
166    * @param e The fifth operation argument.
167    * @throws Exception If an error occurs during operation execution.
168    */
169   void acceptThrows(A a, B b, C c, D d, E e) throws Exception;
170}
171