package com.yoursway.utils.dependencies; import java.util.ArrayList; import java.util.List; import com.yoursway.utils.AutoThreadLocal; import com.yoursway.utils.bugs.Bugs; public class Tracker { private static AutoThreadLocal<DependeesRequestor> slot = AutoThreadLocal.create(); private static ThreadLocal<List<TrackingSectionListener>> listenerSlot = new ThreadLocal<List<TrackingSectionListener>>() { protected List<TrackingSectionListener> initialValue() { return new ArrayList<TrackingSectionListener>(); } }; public static void run(Runnable runnable) { runAndTrack(runnable, NopDependeesRequestor.INSTANCE); } public static void runWithFinishedListener(Runnable runnable, TrackingSectionListener listener) { List<TrackingSectionListener> list = listenerSlot.get(); int oldSize = list.size(); list.add(listener); try { runnable.run(); } finally { notifyFinishListeners(list, oldSize); } } public static void runAndTrack(Runnable runnable, DependeesRequestor requestor) { if (requestor == null) throw new NullPointerException("requestor is null"); List<TrackingSectionListener> list = listenerSlot.get(); int oldSize = list.size(); try { slot.runWith(runnable, requestor); } finally { notifyFinishListeners(list, oldSize); } } private static void notifyFinishListeners(List<TrackingSectionListener> list, int oldSize) { int newSize = list.size(); if (newSize > oldSize) { for (int i = oldSize; i < newSize; i++) { TrackingSectionListener listener = list.get(i); try { listener.trackingFinished(); } catch (Throwable e) { Bugs.listenerFailed(e, listener); } } while(list.size() > oldSize) list.remove(list.size() - 1); } } public static void dependsOn(Dependee dependee) { DependeesRequestor requestor = slot.get(); if (requestor != null) requestor.dependsOn(dependee); } public static void addFinishListener(TrackingSectionListener listener) { if (listener == null) throw new NullPointerException("listener is null"); if (slot.get() == null) throw new IllegalStateException("Cannot add a 'tracking finished' listener without an active tracking section"); listenerSlot.get().add(listener); } }