package io.pcp.parfait;
import java.util.List;
import javax.measure.Unit;
import net.jcip.annotations.ThreadSafe;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* Factory class to produce multiple sets of {@link TimeWindowCounter
* TimeWindowCounters} with a specific and consistent set of {@link TimeWindow
* TimeWindows}, and in turn produce {@link PollingMonitoredValue
* PollingMonitoredValues} which watch those TimeWindowCounters. Can either
* create the TimeWindowCounters from scratch, or 'copy' an existing
* MonitoredCounter.
*/
@ThreadSafe
public class TimeWindowCounterBuilder {
private final List<TimeWindow> timeWindows;
private final Supplier<Long> timeSource;
private final MonitorableRegistry registry;
public TimeWindowCounterBuilder(MonitorableRegistry registry,
TimeWindow... windows) {
this(new SystemTimePoller(), registry, windows);
}
TimeWindowCounterBuilder(Supplier<Long> timeSource,
MonitorableRegistry registry, TimeWindow... windows) {
this.registry = registry;
this.timeSource = timeSource;
this.timeWindows = ImmutableList.copyOf(windows);
}
/**
* Builds a new {@link CompositeCounter}, comprised of TimeWindowCounters,
* and registers {@link PollingMonitoredValue}s to detect changes in their
* values.
*
* @param baseName
* the base name of the new MonitoredValues, which will have the
* window name, e.g. ".60s", appended to it for each window
* @param baseDescription
* the base description of the new MonitoredValues, to be
* appended with e.g. " [60s]"
* @param unit
* the {@link Unit} to use for the new values
* @return a CompositeCounter wrapping a set of new TimeWindow-based
* counters
*/
public CompositeCounter build(String baseName, String baseDescription,
Unit<?> unit) {
List<Counter> counters = getSubCounters(baseName, baseDescription, unit);
return new CompositeCounter(counters);
}
private List<Counter> getSubCounters(String baseName,
String baseDescription, Unit<?> unit) {
List<Counter> counters = Lists.newArrayList();
for (TimeWindow timeWindow : timeWindows) {
final TimeWindowCounter value = new TimeWindowCounter(timeWindow,
timeSource);
String name = String
.format("%s.%s", baseName, timeWindow.getName());
String description = String.format("%s [%s]", baseDescription,
timeWindow.getName());
PollingMonitoredValue.poll(name, description, registry,
timeWindow.getResolution(), new Supplier<Long>() {
@Override
public Long get() {
return value.get();
}
}, ValueSemantics.FREE_RUNNING, unit);
counters.add(value);
}
return counters;
}
/**
* Creates a new CompositeCounter wrapping TimeWindowCounters (and creating
* PollingMonitoredValues), using the supplied counter's name,
* description, and unit as the template.
*
* @param templateCounter
* a MonitoredCounter whose name, description, and unit should be
* copied
* @return a CompositeCounter wrapping a set of new TimeWindow-based
* counters
*/
public CompositeCounter copyFrom(MonitoredCounter templateCounter) {
return build(templateCounter.getName(),
templateCounter.getDescription(),
templateCounter.getUnit());
}
/**
* Creates a new CompositeCounter wrapping TimeWindowCounters (and creating
* PollingMonitoredValues), using the supplied MonitoredCounter's name,
* description, and unit as the template. <em>Also</em> wraps the supplied
* MonitoredCounter itself (hence providing a single incrementable Counter
* which will increment both an overall total and a set of TimeWindow
* counters)
*
* @param templateCounter
* a Counter whose name, description, and unit should be copied
* @return a CompositeCounter wrapping a set of new TimeWindow-based
* counters and the supplied templateCounter
*/
public CompositeCounter wrapCounter(MonitoredCounter templateCounter) {
List<Counter> subCounters = Lists
.<Counter> newArrayList(templateCounter);
subCounters.addAll(getSubCounters(templateCounter.getName(),
templateCounter.getDescription(), templateCounter.getUnit()));
return new CompositeCounter(subCounters);
}
}