@Override public void call(T item) throws Exception { for (Callback<T> callback : callbacks) { callback.call(item); } } }
/** * Collect {@code <T>} into a buffer, and invoke the given callback whenever * the buffer is full, during an explicit commit, or on close. */ public static <T> BatchingCallback<T> batchInto(int size, Callback<? super List<T>> out) { return new BatchingCallback<T>(size, out); }
/** * Create a new Callback which transforms its items according to a {@link Function} * and then invokes the original callback. */ public static <A, B> Callback<A> transform(Callback<? super B> callback, Function<? super A, ? extends B> transformer) { return new TransformedCallback<A, B>(callback, transformer); }
@Test public void testWildcards() throws Exception { CallbackCollector<Object> callback = new CallbackCollector<>(); Callback<String> strCallback = transform(callback, Functions.toStringFunction()); strCallback.call("foo"); strCallback.call("bar"); Function<Super, Class<?>> superFunction = new Function<Super, Class<?>>() { @Override @Nullable public Class<?> apply(@Nullable Super input) { return input.getClass(); } }; Callback<Super> superCallback = transform(callback, superFunction); Callback<Sub> subCallback = transform(callback, superFunction); superCallback.call(new Super()); superCallback.call(new Sub()); subCallback.call(new Sub()); assertEquals(Lists.newArrayList("foo", "bar", Super.class, Sub.class, Sub.class), callback.getItems()); }
@Test public void testGood() throws Exception { ExecutorService executor = MoreExecutors.sameThreadExecutor(); CallbackCollector<List<String>> out = new CallbackCollector<>(); BatchingCallback<String> batcher = BatchingCallback.batchInto(2, executor, out, false); batcher.call("a"); batcher.call("b"); batcher.call("c"); batcher.call("d"); batcher.call("e"); batcher.commit(); assertEquals(of(of("a", "b"), of("c", "d"), of("e")), out.getItems()); }
@Test public void testSimple() throws Exception { CallbackCollector<String> callback = new CallbackCollector<>(); Callback<Integer> tested = transform(callback, new Function<Integer, String>() { @Override @Nullable public String apply(@Nullable Integer input) { return input == null ? null : Integer.toHexString(input); } }); tested.call(null); tested.call(15); tested.call(0xDEADBEEF); assertEquals(Lists.newArrayList(null, "f", "deadbeef"), callback.getItems()); }
/** * Alternate method of committing, for use with {@code try-with-resources}. */ @Override public void close() { commit(); }
/** * For every element, invoke the given callback. * Stops if {@link CallbackRefusedException} is thrown. */ @SafeVarargs public static <T> void stream(Callback<T> callback, T... items) throws Exception { stream(callback, Arrays.asList(items)); }
@Override public void call(Collection<String> item) throws Exception { if (items.size() > 1) { throw new CallbackRefusedException(); } items.add(item); } };
/** * Explicitly flush the buffer, even if it is not full. * @return true if the flush succeeds, false if the delegate throws {@code CallbackRefusedException} */ public boolean commit() { try { commitInternal(); return true; } catch (CallbackRefusedException e) { return false; } }
/** * Combine multiple callbacks into a single callback, preserving order. */ public static <T> Callback<T> chain(Iterable<Callback<T>> callbacks) { return new ChainCallback<T>(callbacks); }
/** * Collect {@code <T>} into a buffer, and schedule the given callback with the given executor * whenever the buffer is full. If failFast is false and any exceptions are thrown, a * {@link BatchingCallbackExecutionException} is thrown when the BatchingCallback is {@link #commit()}ed. * It suppresses all of the other thrown exceptions. If failFast is true and an exception is thrown, it * is rethrown as soon as it is noticed and further invocations will generate {@link CallbackRefusedException}. */ public static <T> BatchingCallback<T> batchInto(int size, ExecutorService executor, Callback<? super List<T>> out, boolean failFast) { return new ExecutorBatchingCallback<T>(size, executor, out, failFast); }
ExecutorBatchingCallback(int size, ExecutorService executor, Callback<? super List<T>> out, boolean failFast) { super(size, new ExecutorCallback<>(executor, out, failFast)); }
/** * Combine multiple callbacks into a single callback, preserving order. */ @SafeVarargs public static <T> Callback<T> chain(Callback<T>... callbacks) { return chain(Arrays.asList(callbacks)); }
@Test public void testBatchingCallback() throws Exception { CallbackCollector<List<String>> collector = new CallbackCollector<>(); try (BatchingCallback<String> batcher = BatchingCallback.batchInto(2, collector)) { batcher.call("a"); batcher.call("b"); batcher.call("c"); batcher.commit(); batcher.call("d"); batcher.call("e"); batcher.call("f"); } assertEquals(of( of("a", "b"), of("c"), of("d", "e"), of("f") ), collector.getItems()); }
@Override public Void call() throws Exception { out.call(item); return null; } }
/** * Add an item to the buffer. May cause a commit if the buffer is full. * @throws CallbackRefusedException if the delegate throws. */ @Override public void call(T item) throws CallbackRefusedException { while (!list.offer(item)) { commitInternal(); } }
/** * For every element in the iterable, invoke the given callback. * Stops if {@link CallbackRefusedException} is thrown. */ public static <T> void stream(Callback<T> callback, Iterable<T> iterable) throws Exception { for (T item : iterable) { try { callback.call(item); } catch (CallbackRefusedException e) { return; } } }
@Override public void call(A item) throws Exception { callback.call(transformer.apply(item)); } }