package edu.uw.zookeeper.common;
import static com.google.common.base.Preconditions.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.base.Function;
import com.google.common.collect.AbstractIterator;
import com.typesafe.config.ConfigValueType;
import edu.uw.zookeeper.common.Configurable;
import edu.uw.zookeeper.common.Configuration;
/**
* Not thread-safe.
*/
public final class CountingGenerator<V> extends AbstractIterator<V> {
public static <V> CountingGenerator<V> fromConfiguration(
Configuration configuration,
Generator<? extends V> callable) {
int limit = ConfigurableIterations.get(configuration);
int logIterations = ConfigurableLogIterations.get(configuration);
int logInterval;
if (logIterations > 0) {
logInterval = limit / logIterations;
} else {
logInterval = 0;
}
return create(limit, logInterval, callable, LogManager.getLogger(CountingGenerator.class));
}
public static <V> CountingGenerator<V> create(
int limit,
int logInterval,
Generator<? extends V> callable,
Logger logger) {
checkArgument((limit >= 0) || (limit == INFINITE_ITERATIONS), limit);
return new CountingGenerator<V>(
limit, logInterval, callable, logger);
}
public static abstract class ConfigurableInt implements Function<Configuration, Integer> {
@Override
public Integer apply(Configuration configuration) {
Configurable configurable = getClass().getAnnotation(Configurable.class);
return configuration.withConfigurable(configurable)
.getConfigOrEmpty(configurable.path())
.getInt(configurable.arg());
}
}
@Configurable(arg="iterations", value="10", type=ConfigValueType.NUMBER)
public static class ConfigurableIterations extends ConfigurableInt {
public static Integer get(Configuration configuration) {
return new ConfigurableIterations().apply(configuration);
}
}
@Configurable(arg="logIterations", value="10", type=ConfigValueType.NUMBER)
public static class ConfigurableLogIterations extends ConfigurableInt {
public static Integer get(Configuration configuration) {
return new ConfigurableLogIterations().apply(configuration);
}
}
public static final int INFINITE_ITERATIONS = -1;
private final Logger logger;
private final int logInterval;
private final int limit;
private final Generator<? extends V> callable;
private int count;
protected CountingGenerator(
int limit,
int logInterval,
Generator<? extends V> callable,
Logger logger) {
this.logger = logger;
this.logInterval = logInterval;
this.limit = limit;
this.callable = callable;
this.count = 0;
}
public int getLimit() {
return limit;
}
public int getCount() {
return count;
}
@Override
protected V computeNext() {
if ((limit != INFINITE_ITERATIONS) && (count >= limit)) {
return endOfData();
}
this.count++;
if ((logInterval != 0) && ((count == 1) || (count == limit) || (count % logInterval == 0))) {
logger.info("Iteration {}", count);
}
return callable.next();
}
}