package org.dcache.webadmin.model.dataaccess.communication.collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import org.dcache.cells.CellStub; import org.dcache.util.backoff.BackoffController; import org.dcache.util.backoff.IBackoffAlgorithm; import org.dcache.util.backoff.IBackoffAlgorithm.Status; import org.dcache.util.backoff.IBackoffAlgorithmFactory; /** * A collector is a runnable that can be run to collect information with cell- * communication via its cellstub and put it into its pagecache to later deliver * information to a webpage via DAOs. Each implementation should use a * ContextPath of the corresponding constant-interface ContextPaths as key to * this information. * * @author jans */ public abstract class Collector implements Runnable, Callable<IBackoffAlgorithm.Status> { private final Logger logger = LoggerFactory.getLogger(this.getClass()); protected String _name = ""; protected ConcurrentMap<String, Object> _pageCache; protected CellStub _cellStub; protected long sleepInterval; protected TimeUnit sleepIntervalUnit; private boolean enabled = true; private IBackoffAlgorithmFactory factory; private BackoffController controller; public String getName() { return _name; } public Map<String, Object> getPageCache() { return _pageCache; } public void initialize() { controller = new BackoffController(factory); } public synchronized boolean isEnabled() { return enabled; } @Override public void run() { Status status = Status.SUCCESS; long timeout = sleepIntervalUnit.toMillis(sleepInterval); try { while (isEnabled()) { logger.debug("collector {} calling controller.call", this); status = controller.call(this); if (status == Status.FAILURE) { logger.error("call returned failure status; exiting collection loop"); break; } synchronized (this) { wait(timeout); } } /* * BackoffController preserves the generic Exception * contract on Callable, so we have to deal with * RuntimeExceptions as a subset of Exception first */ } catch (RuntimeException t) { throw t; } catch (InterruptedException t) { logger.debug("controller.call() was interrupted; exiting"); } catch (Exception t) { logger.error("unexpected exception: {}; exiting collection loop", t.getMessage()); logger.debug("controller.call()", t); } } @Required public void setAlgorithmFactory(IBackoffAlgorithmFactory factory) { this.factory = factory; } public void setCellStub(CellStub cellstub) { _cellStub = cellstub; } @Required public void setName(String name) { _name = name; } public void setPageCache(ConcurrentMap<String, Object> pageCache) { _pageCache = pageCache; } @Required public void setSleepInterval(long sleepInterval) { this.sleepInterval = sleepInterval; } @Required public void setSleepIntervalUnit(TimeUnit sleepIntervalUnit) { this.sleepIntervalUnit = sleepIntervalUnit; } protected synchronized void setEnabled(boolean enabled) { this.enabled = enabled; } }