001/**
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2019 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.Map;
029import java.util.Queue;
030import java.util.function.Supplier;
031
032/**
033 * Builder for the different types of conflation queues serving as alternative to the queue constructors;  a builder is
034 * returned by the static methods of this interface.
035 *
036 * @param <K> the type of the conflation key
037 * @param <V> the type of elements in the queue
038 */
039public interface ConflationQueueBuilder<K,V> {
040
041    /**
042     * Creates an initial builder;  use this method only when conflation keys are not known in advance
043     *
044     * @param <K> the type of the conflation key
045     * @param <V> the type of elements in the queue
046     * @return a new builder
047     */
048    static <K,V> ConflationQueueBuilder<K,V> builder() {
049        return new ConflationQueueBuilderImpl.DefaultBuilder<>();
050    }
051
052    /**
053     * Creates an initial builder;  use this method only when conflation keys are not known in advance.
054     *
055     * @param keyType   the type of the conflation key, used only to infer the generic type of the builder
056     * @param valueType the type of elements in the queue, used only to infer the generic type of the builder
057     * @param <K> the type of the conflation key
058     * @param <V> the type of elements in the queue
059     * @return a new builder
060     */
061    static <K,V> ConflationQueueBuilder<K,V> builder(@SuppressWarnings("unused") final Class<K> keyType,
062                                                     @SuppressWarnings("unused") final Class<V> valueType) {
063        return new ConflationQueueBuilderImpl.DefaultBuilder<>();
064    }
065
066    /**
067     * Creates an initial builder;  use this method only when conflation keys are not known in advance.  If multiple
068     * producers are used, the map returned by the given map factory should be thread-safe.
069     *
070     * @param entryMapFactory the factory to create the map that manages entries per conflation key
071     * @param <K> the type of the conflation key
072     * @param <V> the type of elements in the queue
073     * @return a new builder
074     */
075    static <K,V> ConflationQueueBuilder<K,V> builder(final Supplier<? extends Map<Object,Object>> entryMapFactory) {
076        return new ConflationQueueBuilderImpl.EntryMapFactoryBuilder<>(entryMapFactory);
077    }
078
079    /**
080     * Creates an initial builder;  use this method only when conflation keys are not known in advance.  If multiple
081     * producers are used, the map returned by the given map factory should be thread-safe.
082     *
083     * @param keyType   the type of the conflation key, used only to infer the generic type of the builder
084     * @param valueType the type of elements in the queue, used only to infer the generic type of the builder
085     * @param entryMapFactory the factory to create the map that manages entries per conflation key
086     * @param <K> the type of the conflation key
087     * @param <V> the type of elements in the queue
088     * @return a new builder
089     */
090    static <K,V> ConflationQueueBuilder<K,V> builder(@SuppressWarnings("unused") final Class<K> keyType,
091                                                     @SuppressWarnings("unused") final Class<V> valueType,
092                                                     final Supplier<? extends Map<Object,Object>> entryMapFactory) {
093        return new ConflationQueueBuilderImpl.EntryMapFactoryBuilder<>(entryMapFactory);
094    }
095
096    /**
097     * Creates an initial builder given all conflation keys (exhaustive!).
098     *
099     * @param allConflationKeys an exhaustive list of all conflation keys that will ever be used for the queue
100     * @param <K> the type of the conflation key
101     * @param <V> the type of elements in the queue
102     * @return a new builder
103     */
104    @SafeVarargs
105    static <K,V> ConflationQueueBuilder<K,V> declareAllConflationKeys(final K... allConflationKeys) {
106        //NOTE: this creates garbage
107        return declareAllConflationKeys(Arrays.asList(allConflationKeys));
108    }
109
110    /**
111     * Creates an initial builder given all conflation keys (exhaustive!).
112     *
113     * @param allConflationKeys an exhaustive list of all conflation keys that will ever be used for the queue
114     * @param <K> the type of the conflation key
115     * @param <V> the type of elements in the queue
116     * @return a new builder
117     */
118    static <K,V> ConflationQueueBuilder<K,V> declareAllConflationKeys(final List<K> allConflationKeys) {
119        return new ConflationQueueBuilderImpl.DeclaredKeysBuilder<>(allConflationKeys);
120    }
121
122    /**
123     * Creates an initial builder given all conflation keys (exhaustive!).
124     *
125     * @param allConflationKeys an exhaustive list of all conflation keys that will ever be used for the queue
126     * @param valueType         the type of elements in the queue, used only to infer the generic type of the builder
127     * @param <K> the type of the conflation key
128     * @param <V> the type of elements in the queue
129     * @return a new builder
130     */
131    static <K,V> ConflationQueueBuilder<K,V> declareAllConflationKeys(final List<K> allConflationKeys,
132                                                                      @SuppressWarnings("unused") final Class<V> valueType) {
133        return new ConflationQueueBuilderImpl.DeclaredKeysBuilder<>(allConflationKeys);
134    }
135
136    /**
137     * Creates an initial builder given the enum conflation key class.
138     *
139     * @param keyType   the type of the conflation key
140     * @param <K> the type of the conflation key
141     * @param <V> the type of elements in the queue
142     * @return a new builder
143     */
144    static <K extends Enum<K>,V> ConflationQueueBuilder<K,V> forEnumConflationKey(final Class<K> keyType) {
145        return new ConflationQueueBuilderImpl.EnumKeyBuilder<>(keyType);
146    }
147
148    /**
149     * Creates an initial builder given the enum conflation key class.
150     *
151     * @param keyType   the type of the conflation key
152     * @param valueType the type of elements in the queue, used only to infer the generic type of the builder
153     * @param <K> the type of the conflation key
154     * @param <V> the type of elements in the queue
155     * @return a new builder
156     */
157    static <K extends Enum<K>,V> ConflationQueueBuilder<K,V> forEnumConflationKey(final Class<K> keyType,
158                                                                                  @SuppressWarnings("unused") final Class<V> valueType) {
159        return new ConflationQueueBuilderImpl.EnumKeyBuilder<>(keyType);
160    }
161
162    /**
163     * Register a listener as created by the specified supplier when creating queue appenders.  The created listeners
164     * must be thread safe for multi-producer queues, e.g. consider using
165     * {@link AppenderListener#threadLocalSupplier(Supplier)}.
166     *
167     * @param listenerSupplier  a listener supplier acting as listener factory
168     * @return the builder
169     */
170    ConflationQueueBuilder<K,V> withAppenderListener(Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier);
171
172    /**
173     * Register a listener as created by the specified supplier when creating queue pollers.  The created listeners
174     * must be thread safe for multi-consumer queues, e.g. consider using
175     * {@link PollerListener#threadLocalSupplier(Supplier)}.
176     *
177     * @param listenerSupplier  a listener supplier acting as listener factory
178     * @return the builder
179     */
180    ConflationQueueBuilder<K,V> withPollerListener(Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier);
181
182    /**
183     * Switch builder mode to create a conflation queue that allows exchanging of elements between the consumer and the
184     * producer, that is, the builder will now create a {@link ExchangeConflationQueue}.
185     *
186     * @return a builder for an {@link ExchangeConflationQueue}, more specifically an {@link EvictConflationQueue}
187     * @see ExchangeConflationQueue
188     * @see EvictConflationQueue
189     * @see #withMerging(Merger)
190     */
191    ExchangeConflationQueueBuilder<K,V> withExchangeValueSupport();
192
193    /**
194     * Switch builder mode to create a conflation queue that supports merging of old and new values when conflation
195     * occurs, that is, the builder will now create a {@link MergeConflationQueue}.
196     *
197     * @param merger merge strategy to use when conflation occurs
198     * @return a builder for an {@link ExchangeConflationQueue}, more specifically a {@link MergeConflationQueue}
199     * @see ExchangeConflationQueue
200     * @see MergeConflationQueue
201     * @see #withExchangeValueSupport()
202     */
203    ExchangeConflationQueueBuilder<K,V> withMerging(Merger<? super K, V> merger);
204
205    /**
206     * Builds and returns a new conflation queue instance using the given queue factory for the backing queue.  The
207     * backing queue determines whether single or multiple producers and consumers are supported.
208     *
209     * @param queueFactory the factory to create the backing queue
210     * @return a new conflation queue instance
211     */
212    ConflationQueue<K,V> build(Supplier<? extends Queue<Object>> queueFactory);
213
214    /**
215     * Builder for {@link ExchangeConflationQueue} subtypes.
216     *
217     * @param <K> the type of the conflation key
218     * @param <V> the type of elements in the queue
219     */
220    interface ExchangeConflationQueueBuilder<K,V> {
221        /**
222         * Register a listener as created by the specified supplier when creating queue appenders.  The created listeners
223         * must be thread safe for multi-producer queues, e.g. consider using
224         * {@link AppenderListener#threadLocalSupplier(Supplier)}.
225         *
226         * @param listenerSupplier  a listener supplier acting as listener factory
227         * @return the builder
228         */
229        ExchangeConflationQueueBuilder<K,V> withAppenderListener(Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier);
230
231        /**
232         * Register a listener as created by the specified supplier when creating queue pollers.  The created listeners
233         * must be thread safe for multi-consumer queues, e.g. consider using
234         * {@link PollerListener#threadLocalSupplier(Supplier)}.
235         *
236         * @param listenerSupplier  a listener supplier acting as listener factory
237         * @return the builder
238         */
239        ExchangeConflationQueueBuilder<K,V> withPollerListener(Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier);
240
241        /**
242         * Builds and returns a new exchange conflation queue instance using the given queue factory for the backing
243         * queue.  The backing queue determines whether single or multiple producers and consumers are supported.
244         *
245         * @param queueFactory the factory to create the backing queue
246         * @return a new exchange conflation queue instance
247         */
248        ExchangeConflationQueue<K,V> build(Supplier<? extends Queue<Object>> queueFactory);
249    }
250}