package cz.cuni.mff.d3s.been.cluster; import java.util.Stack; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A special thread whose purpose is to release the resources of an interrupted * {@link IClusterService}. * * @author darklight * */ public abstract class Reaper extends Thread { /** logging. */ private final Logger log; /** * A list of sub-services that need to be reaped in case the node is * terminated. */ private final Stack<Reapable> subServices; /** Creates a Reaper */ public Reaper() { super(); subServices = new Stack<>(); log = LoggerFactory.getLogger(getClass()); } @Override public final void run() { setName(getClass().getSimpleName()); super.run(); try { log.debug("Reaper is on the move."); reap(); } catch (InterruptedException e) { log.warn("Reaper was interrupted during his reaping.", e); } while (!subServices.isEmpty()) { reap(subServices.pop()); } try { shutdown(); } catch (InterruptedException e) { log.warn("{} was interrupted during shutdown.", e); } log.debug("Reaper has taken his toll."); } /** * Execute the reaping steps. The body of this method gets executed before all * pushed targets are reaped. * * @throws InterruptedException * When the reaping thread is interrupted */ protected abstract void reap() throws InterruptedException; /** * Execute shutdown steps. The body of this method gets executed after the * reaping is done and all pushed targets are reaped. * * @throws InterruptedException * When the reaping thread is interrupted */ protected void shutdown() throws InterruptedException {}; /** * Reaps a target * * @param target * target to reap */ private void reap(Reapable target) { final Reaper reaper = target.createReaper(); reaper.start(); try { reaper.join(); } catch (InterruptedException e) {} } /** * Adds target to be reaped while shutting down. * * @param target * the target to add */ public void pushTarget(Reapable target) { subServices.push(target); } @Override public String toString() { return getClass().toString(); } }