001/**
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2018 nobark (tools4j), Marco Terzer, Anton Anufriev
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.tools4j.nobark.queue;
025
026import java.util.Arrays;
027import java.util.List;
028import java.util.Queue;
029import java.util.function.Supplier;
030
031/**
032 * Builder for the different types of conflation queues serving as alternative to the queue constructors;  a builder is
033 * returned by the static methods of this interface.
034 *
035 * @param <K> the type of the conflation key
036 * @param <V> the type of elements in the queue
037 */
038public interface ConflationQueueBuilder<K,V> {
039
040    /**
041     * Creates an initial builder;  use this method only when conflation keys are not known in advance
042     * @return a new builder
043     *
044     * @param <K> the type of the conflation key
045     * @param <V> the type of elements in the queue
046     */
047    static <K,V> ConflationQueueBuilder<K,V> builder() {
048        return new ConflationQueueBuilderImpl.DefaultBuilder<>();
049    }
050
051    /**
052     * Creates an initial builder;  use this method only when conflation keys are not known in advance.
053     *
054     * @param keyType   the type of the conflation key, used only to infer the generic type of the builder
055     * @param valueType the type of elements in the queue, used only to infer the generic type of the builder
056     * @param <K> the type of the conflation key
057     * @param <V> the type of elements in the queue
058     * @return a new builder
059     */
060    static <K,V> ConflationQueueBuilder<K,V> builder(final Class<K> keyType, final Class<V> valueType) {
061        return new ConflationQueueBuilderImpl.DefaultBuilder<>();
062    }
063
064    /**
065     * Creates an initial builder given all conflation keys (exhaustive!).
066     *
067     * @param allConflationKeys an exhaustive list of all conflation keys that will ever be used for the queue
068     * @param <K> the type of the conflation key
069     * @param <V> the type of elements in the queue
070     * @return a new builder
071     */
072    @SafeVarargs
073    static <K,V> ConflationQueueBuilder<K,V> declareAllConflationKeys(final K... allConflationKeys) {
074        //NOTE: this creates garbage
075        return declareAllConflationKeys(Arrays.asList(allConflationKeys));
076    }
077
078    /**
079     * Creates an initial builder given all conflation keys (exhaustive!).
080     *
081     * @param allConflationKeys an exhaustive list of all conflation keys that will ever be used for the queue
082     * @param <K> the type of the conflation key
083     * @param <V> the type of elements in the queue
084     * @return a new builder
085     */
086    static <K,V> ConflationQueueBuilder<K,V> declareAllConflationKeys(final List<K> allConflationKeys) {
087        return new ConflationQueueBuilderImpl.DeclaredKeysBuilder<>(allConflationKeys);
088    }
089
090    /**
091     * Creates an initial builder given all conflation keys (exhaustive!).
092     *
093     * @param allConflationKeys an exhaustive list of all conflation keys that will ever be used for the queue
094     * @param valueType         the type of elements in the queue, used only to infer the generic type of the builder
095     * @param <K> the type of the conflation key
096     * @param <V> the type of elements in the queue
097     * @return a new builder
098     */
099    static <K,V> ConflationQueueBuilder<K,V> declareAllConflationKeys(final List<K> allConflationKeys,
100                                                                      final Class<V> valueType) {
101        return new ConflationQueueBuilderImpl.DeclaredKeysBuilder<>(allConflationKeys);
102    }
103
104    /**
105     * Creates an initial builder given the enum conflation key class.
106     *
107     * @param keyType   the type of the conflation key
108     * @param <K> the type of the conflation key
109     * @param <V> the type of elements in the queue
110     * @return a new builder
111     */
112    static <K extends Enum<K>,V> ConflationQueueBuilder<K,V> forEnumConflationKey(final Class<K> keyType) {
113        return new ConflationQueueBuilderImpl.EnumKeyBuilder<>(keyType);
114    }
115
116    /**
117     * Creates an initial builder given the enum conflation key class.
118     *
119     * @param keyType   the type of the conflation key
120     * @param valueType the type of elements in the queue, used only to infer the generic type of the builder
121     * @param <K> the type of the conflation key
122     * @param <V> the type of elements in the queue
123     * @return a new builder
124     */
125    static <K extends Enum<K>,V> ConflationQueueBuilder<K,V> forEnumConflationKey(final Class<K> keyType,
126                                                                                  final Class<V> valueType) {
127        return new ConflationQueueBuilderImpl.EnumKeyBuilder<>(keyType);
128    }
129
130    /**
131     * Register a listener as created by the specified supplier when creating queue appenders.  The created listeners
132     * must be thread safe for multi-producer queues, e.g. consider using
133     * {@link AppenderListener#threadLocalSupplier(Supplier)}.
134     *
135     * @param listenerSupplier  a listener supplier acting as listener factory
136     * @return the builder
137     */
138    ConflationQueueBuilder<K,V> withAppenderListener(Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier);
139
140    /**
141     * Register a listener as created by the specified supplier when creating queue pollers.  The created listeners
142     * must be thread safe for multi-consumer queues, e.g. consider using
143     * {@link PollerListener#threadLocalSupplier(Supplier)}.
144     *
145     * @param listenerSupplier  a listener supplier acting as listener factory
146     * @return the builder
147     */
148    ConflationQueueBuilder<K,V> withPollerListener(Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier);
149
150    /**
151     * Switch builder mode to create a conflation queue that allows exchanging of elements between the consumer and the
152     * producer, that is, the builder will now create a {@link ExchangeConflationQueue}.
153     *
154     * @return a builder for an {@link ExchangeConflationQueue}, more specifically an {@link EvictConflationQueue}
155     * @see ExchangeConflationQueue
156     * @see EvictConflationQueue
157     * @see #withMerging(Merger)
158     */
159    ExchangeConflationQueueBuilder<K,V> withExchangeValueSupport();
160
161    /**
162     * Switch builder mode to create a conflation queue that supports merging of old and new values when conflation
163     * occurs, that is, the builder will now create a {@link MergeConflationQueue}.
164     *
165     * @param merger merge strategy to use when conflation occurs
166     * @return a builder for an {@link ExchangeConflationQueue}, more specifically a {@link MergeConflationQueue}
167     * @see ExchangeConflationQueue
168     * @see MergeConflationQueue
169     * @see #withExchangeValueSupport()
170     */
171    ExchangeConflationQueueBuilder<K,V> withMerging(Merger<? super K, V> merger);
172
173    /**
174     * Builds and returns a new conflation queue instance using the given queue factory for the backing queue.  The
175     * backing queue determines whether single or multiple producers and consumers are supported.
176     *
177     * @param queueFactory the factory to create the backing queue
178     * @return a new conflation queue instance
179     */
180    ConflationQueue<K,V> build(Supplier<? extends Queue<Object>> queueFactory);
181
182    /**
183     * Builder for {@link ExchangeConflationQueue} subtypes.
184     *
185     * @param <K> the type of the conflation key
186     * @param <V> the type of elements in the queue
187     */
188    interface ExchangeConflationQueueBuilder<K,V> {
189        /**
190         * Register a listener as created by the specified supplier when creating queue appenders.  The created listeners
191         * must be thread safe for multi-producer queues, e.g. consider using
192         * {@link AppenderListener#threadLocalSupplier(Supplier)}.
193         *
194         * @param listenerSupplier  a listener supplier acting as listener factory
195         * @return the builder
196         */
197        ExchangeConflationQueueBuilder<K,V> withAppenderListener(Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier);
198
199        /**
200         * Register a listener as created by the specified supplier when creating queue pollers.  The created listeners
201         * must be thread safe for multi-consumer queues, e.g. consider using
202         * {@link PollerListener#threadLocalSupplier(Supplier)}.
203         *
204         * @param listenerSupplier  a listener supplier acting as listener factory
205         * @return the builder
206         */
207        ExchangeConflationQueueBuilder<K,V> withPollerListener(Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier);
208
209        /**
210         * Builds and returns a new exchange conflation queue instance using the given queue factory for the backing
211         * queue.  The backing queue determines whether single or multiple producers and consumers are supported.
212         *
213         * @param queueFactory the factory to create the backing queue
214         * @return a new exchange conflation queue instance
215         */
216        ExchangeConflationQueue<K,V> build(Supplier<? extends Queue<Object>> queueFactory);
217    }
218}