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.function.Supplier; 027 028/** 029 * A listener for an {@link ConflationQueue.Poller poller} of a {@link ConflationQueue} for instance useful to 030 * record performance metrics related to poll operations. The listener or a supplier thereof is usually passed to 031 * the constructor of a conflation queue. Note that listeners must be thread safe if used in a multi-consumer 032 * environment; best practice is to use separate listener instances for each consumer thread e.g. by using 033 * {@link #threadLocal(Supplier)} or {@link #threadLocalSupplier(Supplier)}. 034 * 035 * @param <K> the type of the conflation key 036 * @param <V> the type of values in the queue 037 */ 038@FunctionalInterface 039public interface PollerListener<K,V> { 040 041 /** 042 * Called whenever a value is polled via any of the {@link ConflationQueue.Poller#poll() poll} methods. By default 043 * this method is also invoked when the queue was found empty (with null key and value) unless 044 * {@link #polledButFoundEmpty(ConflationQueue)} is overridden and implemented differently. 045 * 046 * @param queue the conflation queue, sometimes useful to record queue size metrics, never null 047 * @param key the conflation key, may be null for poll invocations of the empty queue 048 * @param value the value that was polled, or null for unsuccessful poll invocations (i.e. when the queue was found 049 * empty) 050 */ 051 void polled(ConflationQueue<? extends K, ? extends V> queue, K key, V value); 052 053 /** 054 * Called whenever a poll attempt was made but the queue was found empty. The default implementation delegates the 055 * call to {@link #polled(ConflationQueue, Object, Object)} passing nulls for key and value. 056 * 057 * @param queue the conflation queue, sometimes useful to record queue size metrics, never null 058 */ 059 default void polledButFoundEmpty(final ConflationQueue<? extends K, ? extends V> queue) { 060 polled(queue, null, null); 061 } 062 063 /** 064 * Constant for a no-op listener. 065 */ 066 PollerListener<Object,Object> NOOP = (q, k, v) -> {}; 067 068 /** 069 * Creates a poller listener that delegates to thread-local listener instances created on demand by the given 070 * supplier. This listener can be passed to the constructors of {@link AtomicConflationQueue} which use a single 071 * poller instance for all consumer threads. 072 * 073 * @param listenerSupplier the supplier acting as factory for per-thread listener instances 074 * @param <K> the type of the conflation key 075 * @param <V> the type of values in the queue 076 * @return a listener that delegates to thread-local listener instances 077 */ 078 static <K,V> PollerListener<K,V> threadLocal(final Supplier<? extends PollerListener<K,V>> listenerSupplier) { 079 final ThreadLocal<PollerListener<K,V>> threadLocal = ThreadLocal.withInitial(listenerSupplier); 080 return (q,k,v) -> threadLocal.get().polled(q,k,v); 081 } 082 083 /** 084 * Creates a thread local supplier that creates a new instance once for every caller thread. This listener can be 085 * passed to the constructors of {@link EvictConflationQueue} and {@link MergeConflationQueue} which use a per 086 * thread poller instances; the returned supplier will create a new thread-local listener instance for every 087 * poller instance that is created. 088 * 089 * @param listenerSupplier the supplier acting as factory for per-thread listener instances 090 * @param <L> the poller listener (sub-)type 091 * @return a supplier creating thread-local listener instances 092 */ 093 static <L extends PollerListener<?,?>> Supplier<L> threadLocalSupplier(final Supplier<L> listenerSupplier) { 094 return ThreadLocal.withInitial(listenerSupplier)::get; 095 } 096}