/* ************************************************************************ # # DivConq # # http://divconq.com/ # # Copyright: # Copyright 2014 eTimeline, LLC. All rights reserved. # # License: # See the license.txt file in the project's top-level directory for details. # # Authors: # * Andy White # ************************************************************************ */ package divconq.count; import java.math.BigDecimal; import java.util.Collection; import java.util.Observable; import java.util.Observer; import java.util.concurrent.ConcurrentHashMap; import divconq.lang.op.OperationResult; import divconq.util.StringUtil; import divconq.xml.XElement; public class CountManager implements Observer { protected ConcurrentHashMap<String, Counter> counters = new ConcurrentHashMap<>(); public void init(OperationResult or, XElement find) { // configure events and tasks as a result of conditions of counters } public void stop(OperationResult or) { } public Counter removeCounter(String name) { Counter c = this.counters.remove(name); if (c != null) c.deleteObserver(this); return c; } public Counter getCounter(String name) { return this.counters.get(name); } public Collection<Counter> getCounters() { return this.counters.values(); } public NumberCounter allocateNumberCounter(String name) { if (StringUtil.isEmpty(name)) return null; Counter c = this.counters.get(name); if (c == null) { c = new NumberCounter(name); c.addObserver(this); this.counters.put(name, c); } if (! (c instanceof NumberCounter)) return null; return (NumberCounter)c; } public NumberCounter allocateSetNumberCounter(String name, long value) { NumberCounter nc = this.allocateNumberCounter(name); if (nc != null) nc.setValue(value); return nc; } public NumberCounter countObjects(String name, Object obj) { NumberCounter nc = this.allocateNumberCounter(name); if (nc != null) { // TODO - find a better way for memory and GC - nc.setCurrentObject(obj); -- we used to get Task or Session or such in here!! and hold it for indefinite periods nc.increment(); } return nc; } public NumberCounter allocateSetNumberCounter(String name, double value) { NumberCounter nc = this.allocateNumberCounter(name); if (nc != null) nc.setValue(value); return nc; } public NumberCounter allocateSetNumberCounter(String name, BigDecimal value) { NumberCounter nc = this.allocateNumberCounter(name); if (nc != null) nc.setValue(value); return nc; } public StringCounter allocateStringCounter(String name) { if (StringUtil.isEmpty(name)) return null; Counter c = this.counters.get(name); if (c == null) { c = new StringCounter(name); c.addObserver(this); this.counters.put(name, c); } if (! (c instanceof StringCounter)) return null; return (StringCounter)c; } public StringCounter allocateSetStringCounter(String name, String value) { StringCounter sc = this.allocateStringCounter(name); if (sc != null) sc.setValue(value); return sc; } public BooleanCounter allocateBooleanCounter(String name) { if (StringUtil.isEmpty(name)) return null; Counter c = this.counters.get(name); if (c == null) { c = new BooleanCounter(name); c.addObserver(this); this.counters.put(name, c); } if (! (c instanceof BooleanCounter)) return null; return (BooleanCounter)c; } public BooleanCounter allocateSetBooleanCounter(String name, Boolean value) { BooleanCounter bc = this.allocateBooleanCounter(name); if (bc != null) bc.setValue(value); return bc; } @Override public void update(Observable o, Object arg) { if (!(o instanceof Counter)) return; // TODO we won't get here anymore because Counter's setChanged now always sends in a null Counter c = (Counter)o; // TODO future add conditional logic checks so configure to watch for certain conditions // this is an example of throwing the evaluation out into another thread - this is so we don't hold the lock on the counter too long // improve on this design if ("dcBusMessageSent".equals(c.getName())) { // assuming dcBusMessageSent is a number counter // when we hit 15 if (BigDecimal.valueOf(15).compareTo(((NumberCounter)c).getValue()) == 0) { // then a tigger has happened, copy the counter to keep the state intact /* final Counter fc = c.clone(); // then off load the work of processing the event // TODO maybe the event's system will always offload internally so we don't need to here Hub.instance.getWorkPool().submit(new IWork() { @Override public void run(Task task) { System.out.println("event x: " + fc); // trigger an alert task.complete(); } }); */ //System.out.println("dcBusMessageSent test event :)"); } } // we leave right after the clone so no major overhead incurred } }