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