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.List;
027import java.util.Map;
028import java.util.Objects;
029import java.util.Queue;
030import java.util.function.Supplier;
031
032/**
033 * Package local builder implementation as returned by the static methods of {@link ConflationQueueBuilder}.
034 *
035 * @param <K> the conflation key type
036 * @param <V> the value type
037 */
038class ConflationQueueBuilderImpl<K,V> implements ConflationQueueBuilder<K,V> {
039
040    private final CqFactory<K,V> cqFactory;
041
042    private Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier = () -> AppenderListener.NOOP;
043    private Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier = () -> PollerListener.NOOP;
044
045    private ConflationQueueBuilderImpl(final CqFactory<K,V> cqFactory) {
046        this.cqFactory = Objects.requireNonNull(cqFactory);
047    }
048
049    @Override
050    public ConflationQueueBuilder<K, V> withAppenderListener(final Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier) {
051        this.appenderListenerSupplier = Objects.requireNonNull(listenerSupplier);
052        return this;
053    }
054
055    @Override
056    public ConflationQueueBuilder<K, V> withPollerListener(final Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier) {
057        this.pollerListenerSupplier = Objects.requireNonNull(listenerSupplier);
058        return this;
059    }
060
061    @Override
062    public ExchangeConflationQueueBuilder<K,V> withExchangeValueSupport() {
063        return new EvictConflationQueueBuilder();
064    }
065
066    @Override
067    public ExchangeConflationQueueBuilder<K, V> withMerging(final Merger<? super K, V> merger) {
068        return new MergeConflationQueueBuilder(merger);
069    }
070
071    @Override
072    public ConflationQueue<K,V> build(final Supplier<? extends Queue<Object>> queueFactory) {
073        return cqFactory.atomicQueue(queueFactory, appenderListenerSupplier, pollerListenerSupplier);
074    }
075
076    /**
077     * Builder-internal factory for different types of conflation queues.
078     *
079     * @param <K> the conflation key type
080     * @param <V> the value type
081     */
082    interface CqFactory<K,V> {
083        /**
084         * Factory method for {@link AtomicConflationQueue}
085         * @param queueFactory factory for the backing queue
086         * @param appenderListenerSupplier  supplier acting as appender listener factory
087         * @param pollerListenerSupplier    supplier acting as poller listener factory
088         * @return a new {@link AtomicConflationQueue} instance
089         */
090        AtomicConflationQueue<K,V> atomicQueue(Supplier<? extends Queue<Object>> queueFactory,
091                                               Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
092                                               Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier);
093        /**
094         * Factory method for {@link EvictConflationQueue}.
095         * @param queueFactory factory for the backing queue
096         * @param appenderListenerSupplier  supplier acting as appender listener factory
097         * @param pollerListenerSupplier    supplier acting as poller listener factory
098         * @return a new {@link EvictConflationQueue} instance
099         */
100        EvictConflationQueue<K,V> evictQueue(Supplier<? extends Queue<Object>> queueFactory,
101                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
102                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier);
103        /**
104         * Factory method for {@link MergeConflationQueue}.
105         * @param queueFactory  factory for the backing queue
106         * @param merger        merge strategy to use when conflation occurs
107         * @param appenderListenerSupplier  supplier acting as appender listener factory
108         * @param pollerListenerSupplier    supplier acting as poller listener factory
109         * @return a new {@link MergeConflationQueue} instance
110         */
111        MergeConflationQueue<K,V> mergeQueue(Supplier<? extends Queue<Object>> queueFactory,
112                                             Merger<? super K, V> merger,
113                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
114                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier);
115    }
116
117    /**
118     * Default builder for the case that no conflation keys are declared.
119     *
120     * @param <K> the conflation key type
121     * @param <V> the value type
122     */
123    static class DefaultBuilder<K,V> extends ConflationQueueBuilderImpl<K,V> {
124        DefaultBuilder() {
125            super(new CqFactory<K, V>() {
126                @Override
127                public AtomicConflationQueue<K, V> atomicQueue(Supplier<? extends Queue<Object>> queueFactory,
128                                                               Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
129                                                               Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
130                    return new AtomicConflationQueue<>(queueFactory, appenderListenerSupplier.get(), pollerListenerSupplier.get());
131                }
132
133                @Override
134                public EvictConflationQueue<K, V> evictQueue(Supplier<? extends Queue<Object>> queueFactory,
135                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
136                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
137                    return new EvictConflationQueue<>(queueFactory, appenderListenerSupplier, pollerListenerSupplier);
138                }
139
140                @Override
141                public MergeConflationQueue<K, V> mergeQueue(Supplier<? extends Queue<Object>> queueFactory,
142                                                             Merger<? super K, V> merger,
143                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
144                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
145                    return new MergeConflationQueue<>(queueFactory, merger, appenderListenerSupplier, pollerListenerSupplier);
146                }
147            });
148        }
149    }
150
151    /**
152     * Builder for the case that an entry map factory has been provided.
153     *
154     * @param <K> the conflation key type
155     * @param <V> the value type
156     */
157    static class EntryMapFactoryBuilder<K,V> extends ConflationQueueBuilderImpl<K,V> {
158        EntryMapFactoryBuilder(final Supplier<? extends Map<Object,Object>> entryMapFactory) {
159            super(new CqFactory<K, V>() {
160                @Override
161                public AtomicConflationQueue<K, V> atomicQueue(Supplier<? extends Queue<Object>> queueFactory,
162                                                               Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
163                                                               Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
164                    return new AtomicConflationQueue<>(queueFactory, entryMapFactory, appenderListenerSupplier.get(), pollerListenerSupplier.get());
165                }
166
167                @Override
168                public EvictConflationQueue<K, V> evictQueue(Supplier<? extends Queue<Object>> queueFactory,
169                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
170                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
171                    return new EvictConflationQueue<>(queueFactory, entryMapFactory, appenderListenerSupplier, pollerListenerSupplier);
172                }
173
174                @Override
175                public MergeConflationQueue<K, V> mergeQueue(Supplier<? extends Queue<Object>> queueFactory,
176                                                             Merger<? super K, V> merger,
177                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
178                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
179                    return new MergeConflationQueue<>(queueFactory, entryMapFactory, merger, appenderListenerSupplier, pollerListenerSupplier);
180                }
181            });
182        }
183    }
184
185    /**
186     * Builder for enum conflation key types.
187     *
188     * @param <K> the conflation key type
189     * @param <V> the value type
190     */
191    static class EnumKeyBuilder<K extends Enum<K>,V> extends ConflationQueueBuilderImpl<K,V> {
192        EnumKeyBuilder(final Class<K> enumConflationKeyClass) {
193            super(new CqFactory<K, V>() {
194                @Override
195                public AtomicConflationQueue<K, V> atomicQueue(Supplier<? extends Queue<Object>> queueFactory,
196                                                               Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
197                                                               Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
198                    return AtomicConflationQueue.forEnumConflationKey(queueFactory, enumConflationKeyClass, appenderListenerSupplier.get(), pollerListenerSupplier.get());
199                }
200
201                @Override
202                public EvictConflationQueue<K, V> evictQueue(Supplier<? extends Queue<Object>> queueFactory,
203                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
204                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
205                    return EvictConflationQueue.forEnumConflationKey(queueFactory, enumConflationKeyClass, appenderListenerSupplier, pollerListenerSupplier);
206                }
207
208                @Override
209                public MergeConflationQueue<K, V> mergeQueue(Supplier<? extends Queue<Object>> queueFactory,
210                                                             Merger<? super K, V> merger,
211                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
212                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
213                    return MergeConflationQueue.forEnumConflationKey(queueFactory, merger, enumConflationKeyClass, appenderListenerSupplier, pollerListenerSupplier);
214                }
215            });
216        }
217    }
218
219    /**
220     * Builder for the case that conflation keys are declared.
221     *
222     * @param <K> the conflation key type
223     * @param <V> the value type
224     */
225    static class DeclaredKeysBuilder<K,V> extends ConflationQueueBuilderImpl<K,V> {
226        DeclaredKeysBuilder(final List<? extends K> allConflationKeys) {
227            super(new CqFactory<K, V>() {
228                @Override
229                public AtomicConflationQueue<K, V> atomicQueue(Supplier<? extends Queue<Object>> queueFactory,
230                                                               Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
231                                                               Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
232                    return new AtomicConflationQueue<>(queueFactory, allConflationKeys, appenderListenerSupplier.get(), pollerListenerSupplier.get());
233                }
234
235                @Override
236                public EvictConflationQueue<K, V> evictQueue(Supplier<? extends Queue<Object>> queueFactory,
237                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
238                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
239                    return new EvictConflationQueue<>(queueFactory, allConflationKeys, appenderListenerSupplier, pollerListenerSupplier);
240                }
241
242                @Override
243                public MergeConflationQueue<K, V> mergeQueue(Supplier<? extends Queue<Object>> queueFactory,
244                                                             Merger<? super K, V> merger,
245                                                             Supplier<? extends AppenderListener<? super K, ? super V>> appenderListenerSupplier,
246                                                             Supplier<? extends PollerListener<? super K, ? super V>> pollerListenerSupplier) {
247                    return new MergeConflationQueue<>(queueFactory, merger, allConflationKeys, appenderListenerSupplier, pollerListenerSupplier);
248                }
249            });
250        }
251    }
252
253    /**
254     * Builder for {@link EvictConflationQueue}.
255     */
256    class EvictConflationQueueBuilder implements ExchangeConflationQueueBuilder<K,V> {
257        @Override
258        public EvictConflationQueueBuilder withAppenderListener(final Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier) {
259            ConflationQueueBuilderImpl.this.withAppenderListener(listenerSupplier);
260            return this;
261        }
262
263        @Override
264        public EvictConflationQueueBuilder withPollerListener(final Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier) {
265            ConflationQueueBuilderImpl.this.withPollerListener(listenerSupplier);
266            return this;
267        }
268
269        @Override
270        public ExchangeConflationQueue<K, V> build(final Supplier<? extends Queue<Object>> queueFactory) {
271            return cqFactory.evictQueue(queueFactory, appenderListenerSupplier, pollerListenerSupplier);
272        }
273    }
274
275    /**
276     * Builder for {@link MergeConflationQueue}.
277     */
278    class MergeConflationQueueBuilder implements ExchangeConflationQueueBuilder<K,V> {
279        private final Merger<? super K, V> merger;
280        MergeConflationQueueBuilder(final Merger<? super K, V> merger) {
281            this.merger = Objects.requireNonNull(merger);
282        }
283        @Override
284        public MergeConflationQueueBuilder withAppenderListener(final Supplier<? extends AppenderListener<? super K, ? super V>> listenerSupplier) {
285            ConflationQueueBuilderImpl.this.withAppenderListener(listenerSupplier);
286            return this;
287        }
288
289        @Override
290        public MergeConflationQueueBuilder withPollerListener(final Supplier<? extends PollerListener<? super K, ? super V>> listenerSupplier) {
291            ConflationQueueBuilderImpl.this.withPollerListener(listenerSupplier);
292            return this;
293        }
294
295        @Override
296        public MergeConflationQueue<K, V> build(final Supplier<? extends Queue<Object>> queueFactory) {
297            return cqFactory.mergeQueue(queueFactory, merger, appenderListenerSupplier, pollerListenerSupplier);
298        }
299
300
301    }
302}