/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.github.geophile.erdo.util;
import com.github.geophile.erdo.UsageError;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.IdentityHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class Tracker<T>
{
public static <T> Tracker<T> trackCount(String label)
{
return new CountTracker<T>(label);
}
public static <T> Tracker<T> trackDetail(String label)
{
return new DetailTracker<T>(label);
}
public abstract void register(T t);
public abstract void unregister(T t);
public abstract void checkCount(int expectedCount);
protected Tracker(String label)
{
this.label = label;
}
protected String label;
public static class CountTracker<T> extends Tracker<T>
{
@Override
public void register(T t)
{
count.incrementAndGet();
}
@Override
public void unregister(T t)
{
count.decrementAndGet();
}
@Override
public void checkCount(int expectedCount)
{
int n = count.get();
if (n != expectedCount) {
throw new RuntimeException(String.format("%s: count is %s, expected %s", label, n, expectedCount));
}
}
public CountTracker(String label)
{
super(label);
}
private final AtomicInteger count = new AtomicInteger(0);
}
public static class DetailTracker<T> extends Tracker<T>
{
@Override
public void register(T t)
{
registrations.put(t, new Throwable());
}
@Override
public void unregister(T t)
{
registrations.remove(t);
}
@Override
public void checkCount(int expectedCount)
{
int n = registrations.size();
if (n != expectedCount) {
StringBuilder buffer = new StringBuilder();
for (Throwable throwable : registrations.values()) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
throwable.printStackTrace(printWriter);
buffer.append('\n');
buffer.append(stringWriter.toString());
}
throw new RuntimeException(String.format("%s: count is %s, expected %s. Stacks: %s",
label, n, expectedCount, buffer.toString()));
}
}
public DetailTracker(String label)
{
super(label);
}
private final IdentityHashMap<T, Throwable> registrations = new IdentityHashMap<T, Throwable>();
}
public static class RuntimeException extends UsageError
{
public RuntimeException(String message)
{
super(message);
}
}
}