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
019/**
020 * A lifecycle-aware round-trip interface that combines both {@link BeanSupplier} (for serialization)
021 * and {@link BeanConsumer} (for parsing) on the same property or class.
022 *
023 * <p>
024 * Use this interface when the same object needs to:
025 * <ul>
026 *    <li>Provide beans to a serializer (via {@link #iterator()})
027 *    <li>Receive beans from a parser (via {@link #acceptThrows(Object)})
028 * </ul>
029 *
030 * <p>
031 * The lifecycle methods ({@link #begin()}, {@link #complete()}, {@link #onError(Exception)}) are
032 * shared across both directions. The implementation implicitly knows its direction from which data
033 * method is called first after {@link #begin()}:
034 * <ul>
035 *    <li>{@link #iterator()} called first → read mode (serialization)
036 *    <li>{@link #acceptThrows(Object)} called first → write mode (parsing)
037 * </ul>
038 *
039 * <p>
040 * The framework drives the lifecycle:
041 * <ol>
042 *    <li>Calls {@link #begin()} before the first data operation
043 *    <li>Reads via {@link #iterator()} (serializer) or writes via {@link #acceptThrows(Object)} (parser)
044 *    <li>If an exception occurs, calls {@link #onError(Exception)}
045 *    <li>Always calls {@link #complete()} at the end (like {@code finally})
046 * </ol>
047 *
048 * <p>
049 * Since {@code BeanChannel} extends {@link BeanConsumer}, a {@code BeanChannel} instance passes
050 * the parser's {@code instanceof BeanConsumer} check. Since it extends {@link BeanSupplier}, it
051 * also passes the serializer's {@code instanceof BeanSupplier} check — both directions work.
052 *
053 * <h5 class='section'>Example (DB-backed round-trip channel):</h5>
054 * <p class='bjava'>
055 *    <ja>@Marshalled</ja>(factory=ItemChannelFactory.<jk>class</jk>)
056 *    <jk>public class</jk> ItemChannel <jk>implements</jk> BeanChannel&lt;Item&gt; {
057 *       <jk>private</jk> Connection <jv>conn</jv>;
058 *       <jk>private boolean</jk> <jv>writeMode</jv>;
059 *
060 *       <ja>@Override</ja> <jk>public void</jk> begin() <jk>throws</jk> Exception {
061 *          <jv>conn</jv> = <jv>ds</jv>.getConnection();
062 *          <jv>conn</jv>.setAutoCommit(<jk>false</jk>);
063 *       }
064 *
065 *       <jc>// Serializer calls iterator() — read mode</jc>
066 *       <ja>@Override</ja> <jk>public</jk> Iterator&lt;Item&gt; iterator() {
067 *          <jk>return new</jk> ResultSetIterator&lt;&gt;(...);
068 *       }
069 *
070 *       <jc>// Parser calls acceptThrows() — write mode</jc>
071 *       <ja>@Override</ja> <jk>public void</jk> acceptThrows(Item <jv>item</jv>) <jk>throws</jk> Exception {
072 *          <jv>writeMode</jv> = <jk>true</jk>;
073 *          <jc>// insert item...</jc>
074 *       }
075 *
076 *       <ja>@Override</ja> <jk>public void</jk> onError(Exception <jv>e</jv>) <jk>throws</jk> Exception {
077 *          <jk>if</jk> (<jv>writeMode</jv>) <jv>conn</jv>.rollback();
078 *          <jk>throw</jk> <jv>e</jv>;
079 *       }
080 *
081 *       <ja>@Override</ja> <jk>public void</jk> complete() <jk>throws</jk> Exception {
082 *          <jk>if</jk> (<jv>writeMode</jv>) <jv>conn</jv>.commit();
083 *          <jv>conn</jv>.close();
084 *       }
085 *    }
086 * </p>
087 *
088 * <h5 class='section'>See Also:</h5><ul>
089 *    <li class='jc'>{@link BeanConsumer} - Parse-only lifecycle interface
090 *    <li class='jc'>{@link BeanSupplier} - Serialize-only lifecycle interface
091 *    <li class='jc'>{@link BeanFactory} - Universal factory for DI framework integration
092 *    <li class='jc'>{@link ListBeanChannel} - Simple in-memory implementation
093 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a>
094 * </ul>
095 *
096 * @param <T> The type of bean read and written by this channel.
097 */
098@SuppressWarnings({
099   "java:S112" // throws Exception intentional - lifecycle methods may throw any checked exception
100})
101public interface BeanChannel<T> extends BeanSupplier<T>, BeanConsumer<T> {
102
103   @Override
104   default void begin() throws Exception {}
105
106   @Override
107   default void complete() throws Exception {}
108
109   @Override
110   default void onError(Exception e) throws Exception {
111      throw e;
112   }
113}