package com.framsticks.util.dispatching; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import com.framsticks.util.dispatching.Dispatching; import java.lang.Thread; import java.util.concurrent.atomic.AtomicBoolean; public class Monitor implements JoinableParent { private static final Logger log = LogManager.getLogger(Monitor.class); protected final Joinable joinable; protected final Thread shutdownHook; protected final AtomicBoolean dropped = new AtomicBoolean(false); protected final AtomicBoolean joining = new AtomicBoolean(false); /** * @param joinable */ public Monitor(Joinable joinable) { this.joinable = joinable; shutdownHook = new Thread(new Runnable() { @Override public void run() { log.debug("droping and joining"); Monitor.this.drop().join(); log.debug("droped and joined"); AbstractJoinable.report(); } }); } public Monitor use() { Runtime.getRuntime().addShutdownHook(shutdownHook); log.debug("{} is using", this); Dispatching.use(joinable, this); return this; } public Monitor useFor(double seconds) { Dispatching.sleep(seconds); return this; } public Monitor waitFor() { log.debug("{} is waiting", this); synchronized (this) { while (joinable.getState().ordinal() < JoinableState.FINISHING.ordinal()) { Dispatching.wait(this, 100); } } log.debug("{} ended waiting", this); return this; } public Monitor drop() { if (!dropped.compareAndSet(false, true)) { return this; } log.debug("{} is droping", this); Dispatching.drop(joinable, this); return this; } public Monitor join() { if (!joining.compareAndSet(false, true)) { log.debug("not joining"); return this; } log.debug("{} is joining", this); Dispatching.joinAbsolutely(joinable); log.debug("{} is joined", this); try { Runtime.getRuntime().removeShutdownHook(shutdownHook); } catch (IllegalStateException e) { /** In case IllegalStateException is caught, it means that JVM is in finalization stage */ } return this; } @Override // @SuppressWarnings("NN_NAKED_NOTIFY") public void childChangedState(Joinable joinable, JoinableState state) { synchronized (this) { this.notify(); } log.debug("{} received notification about transition to {}", this, state); } @Override public String toString() { return "monitor for " + joinable; } @Override public Monitor getMonitor() { return this; } protected ExceptionDispatcherHandler taskExceptionHandler; /** * @return the taskExceptionHandler */ public ExceptionDispatcherHandler getTaskExceptionHandler() { return taskExceptionHandler; } /** * @param taskExceptionHandler the taskExceptionHandler to set */ public void setTaskExceptionHandler(ExceptionDispatcherHandler taskExceptionHandler) { this.taskExceptionHandler = taskExceptionHandler; } }