package net.varkhan.base.management.state;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
/**
* <b></b>.
* <p/>
*
* @author varkhan
* @date 1/22/11
* @time 10:57 PM
*/
public class ConcurrentStateReport<L extends Level,S extends State<L,S>> implements StateReport<L,S> {
protected final Collection<StateCheck<L,S>> checks = new CopyOnWriteArrayList<StateCheck<L,S>>();
protected final S initial;
protected final long period;
protected volatile Updater updater = null;
public ConcurrentStateReport(S initial, long period) { this.initial=initial; this.period=period; }
public void add(StateCheck<L,S> check) { checks.add(new ConcurrentStateCheck<L,S>(check)); }
public void start() {
if(updater!=null && updater.isAlive()) return;
synchronized(this) {
updater = new Updater(period);
updater.start();
}
}
public void stop() {
if(updater==null || !updater.isAlive()) return;
synchronized(this) {
updater.release();
}
}
public S state() {
S state = initial;
for(StateCheck<L,S> hc: checks) {
hc.update();
S s = hc.state();
if(s==null) continue;
if(state==null) state = s;
else state = state.aggregate(s, hc.level());
}
return state;
}
public Collection<StateCheck<L,S>> checks() { return Collections.unmodifiableCollection(checks); }
public void update() { if(updater!=null) updater.update(); }
protected class Updater extends Thread {
protected volatile boolean run = true;
protected final long period;
public Updater(long period) {
this.period=period;
this.setName(StateReport.class.getSimpleName()+Updater.class.getSimpleName()+"-"+getId());
this.setDaemon(true);
}
public void run() {
while(run) {
long time = System.currentTimeMillis();
for(StateCheck<L,S> hc: checks) try { hc.update(); } catch(Throwable t) { /* ignore */ }
long elapsed = System.currentTimeMillis()-time;
if(elapsed<period) try { Thread.sleep(period-elapsed); }
catch(InterruptedException e) { /* ignore */ }
}
}
public void update() { this.interrupt(); }
public void end() {
this.run = false;
this.interrupt();
}
public void release() {
this.run = false;
this.interrupt();
try { this.join(period); }
catch(InterruptedException e) { /* ignore */ }
}
}
/**
* <b></b>.
* <p/>
*
* @author varkhan
* @date 1/22/11
* @time 10:43 PM
*/
public static class ConcurrentStateCheck<L extends Level,S extends State<L,S>> extends WrapperStateCheck<L,S> implements StateCheck<L,S> {
protected final AtomicReference<Update<S>> update = new AtomicReference<Update<S>>(null);
public ConcurrentStateCheck(StateCheck<L,S> hc) { super(hc); }
public S state() {
Update<S> u = update.get();
if(u==null) return null;
return u.status();
}
public String reason() {
Update<S> u = update.get();
if(u==null) return null;
return u.reason();
}
public void update() {
Update<S> u;
try { u = new Update<S>(check.state(), check.reason()); }
catch(Throwable t) { u = new Update<S>(null,t.toString()); }
update.set(u);
}
protected static class Update<S> {
public final S s;
public final String r;
public Update(S s, String r) {
this.s=s;
this.r=r;
}
public S status() {
return s;
}
public String reason() {
return r;
}
}
}
}