Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * Copyright 2013 Josh Elser * */ package cosmos.results; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import org.apache.accumulo.core.client.ScannerBase; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Stopwatch; import com.google.common.collect.Iterables; import cosmos.trace.Tracer; /** * */ public class CloseableIterable<T> implements Results<T> { protected final ScannerBase scanner; protected final Iterable<T> iterable; protected final Tracer tracer; protected final String description; protected final Stopwatch sw; protected boolean closed = false; public CloseableIterable(ScannerBase scanner, Iterable<T> iterable, Tracer t, String desc, Stopwatch sw) { checkNotNull(scanner); checkNotNull(iterable); checkNotNull(t); checkNotNull(desc); checkNotNull(sw); this.scanner = scanner; this.iterable = iterable; this.tracer = t; this.description = desc; this.sw = sw; } public static <T> CloseableIterable<T> create(ScannerBase scanner, Iterable<T> iterable, Tracer t, String desc, Stopwatch sw) { return new CloseableIterable<T>(scanner, iterable, t, desc, sw); } public static <T> CloseableIterable<T> transform(ScannerBase scanner, Function<Entry<Key, Value>, T> func, Tracer t, String desc, Stopwatch sw) { return new CloseableIterable<T>(scanner, Iterables.transform(scanner, func), t, desc, sw); } public static <T> CloseableIterable<T> filterAndTransform(ScannerBase scanner, Predicate<Entry<Key, Value>> filter, Function<Entry<Key, Value>, T> func, Tracer t, String desc, Stopwatch sw) { return new CloseableIterable<T>(scanner, Iterables.transform(Iterables.filter(scanner, filter), func), t, desc, sw); } protected ScannerBase source() { return scanner; } @Override public Iterator<T> iterator() { return new Iterator<T>() { final Iterator<T> delegate = iterable.iterator(); @Override public boolean hasNext() { boolean hasNext = delegate.hasNext(); if (!hasNext && sw.isRunning()) { sw.stop(); tracer.addTiming(description, sw.elapsed(TimeUnit.MILLISECONDS)); // TODO Is there a detriment of auto-closing this here? // It doesn't make sense for more than one client to read off of one ScannerBase // so we likely also don't have to add any synchronization scanner.close(); closed = true; } return hasNext; } @Override public T next() { return delegate.next(); } @Override public void remove() { delegate.remove(); } }; } @Override public void close() { // Client may close the Iterable before exhausting the records if (sw.isRunning()) { sw.stop(); tracer.addTiming(description, sw.elapsed(TimeUnit.MILLISECONDS)); } if (!closed) { scanner.close(); closed = true; } } }