| package net.floodlightcontroller.debugcounter; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.List; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import java.util.concurrent.atomic.AtomicLong; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.collect.Sets; |
| |
| import net.floodlightcontroller.core.module.FloodlightModuleContext; |
| import net.floodlightcontroller.core.module.FloodlightModuleException; |
| import net.floodlightcontroller.core.module.IFloodlightModule; |
| import net.floodlightcontroller.core.module.IFloodlightService; |
| import net.floodlightcontroller.debugcounter.web.DebugCounterRoutable; |
| import net.floodlightcontroller.restserver.IRestApiService; |
| |
| /** |
| * This class implements a central store for all counters used for debugging the |
| * system. For counters based on traffic-type, see ICounterStoreService. |
| * |
| * @author saurav |
| */ |
| public class DebugCounter implements IFloodlightModule, IDebugCounterService { |
| protected static Logger log = LoggerFactory.getLogger(DebugCounter.class); |
| |
| /** |
| * registered counters need a counter id |
| */ |
| protected AtomicInteger counterIdCounter = new AtomicInteger(); |
| |
| /** |
| * The counter value |
| */ |
| protected class MutableLong { |
| long value = 0; |
| public void increment() { value += 1; } |
| public void increment(long incr) { value += incr; } |
| public long get() { return value; } |
| public void set(long val) { value = val; } |
| } |
| |
| /** |
| * protected class to store counter information |
| */ |
| public static class CounterInfo { |
| String moduleCounterHierarchy; |
| String counterDesc; |
| CounterType ctype; |
| String moduleName; |
| String counterHierarchy; |
| int counterId; |
| boolean enabled; |
| String[] metaData; |
| |
| public CounterInfo(int counterId, boolean enabled, |
| String moduleName, String counterHierarchy, |
| String desc, CounterType ctype, String... metaData) { |
| this.moduleCounterHierarchy = moduleName + "/" + counterHierarchy; |
| this.moduleName = moduleName; |
| this.counterHierarchy = counterHierarchy; |
| this.counterDesc = desc; |
| this.ctype = ctype; |
| this.counterId = counterId; |
| this.enabled = enabled; |
| this.metaData = metaData; |
| } |
| |
| public String getModuleCounterHierarchy() { return moduleCounterHierarchy; } |
| public String getCounterDesc() { return counterDesc; } |
| public CounterType getCtype() { return ctype; } |
| public String getModuleName() { return moduleName; } |
| public String getCounterHierarchy() { return counterHierarchy; } |
| public int getCounterId() { return counterId; } |
| public boolean isEnabled() { return enabled; } |
| public String[] getMetaData() { return metaData; } |
| } |
| |
| //****************** |
| // Global stores |
| //****************** |
| |
| /** |
| * Counter info for a debug counter |
| */ |
| public class DebugCounterInfo { |
| CounterInfo cinfo; |
| AtomicLong cvalue; |
| |
| public DebugCounterInfo(CounterInfo cinfo) { |
| this.cinfo = cinfo; |
| this.cvalue = new AtomicLong(); |
| } |
| public CounterInfo getCounterInfo() { |
| return cinfo; |
| } |
| public Long getCounterValue() { |
| return cvalue.get(); |
| } |
| } |
| |
| /** |
| * Global debug-counter storage across all threads. These are |
| * updated from the local per thread counters by the flush counters method. |
| */ |
| protected static DebugCounterInfo[] allCounters = |
| new DebugCounterInfo[MAX_COUNTERS]; |
| |
| |
| /** |
| * per module counters, indexed by the module name and storing three levels |
| * of Counter information in the form of CounterIndexStore |
| */ |
| protected ConcurrentHashMap<String, ConcurrentHashMap<String, CounterIndexStore>> |
| moduleCounters = new ConcurrentHashMap<String, |
| ConcurrentHashMap<String, |
| CounterIndexStore>>(); |
| |
| protected class CounterIndexStore { |
| int index; |
| Map<String, CounterIndexStore> nextLevel; |
| |
| public CounterIndexStore(int index, Map<String,CounterIndexStore> cis) { |
| this.index = index; |
| this.nextLevel = cis; |
| } |
| } |
| |
| /** |
| * fast global cache for counter ids that are currently active |
| */ |
| protected Set<Integer> currentCounters = Collections.newSetFromMap( |
| new ConcurrentHashMap<Integer,Boolean>()); |
| |
| //****************** |
| // Thread local stores |
| //****************** |
| |
| /** |
| * Thread local storage of counter info |
| */ |
| protected class LocalCounterInfo { |
| boolean enabled; |
| MutableLong cvalue; |
| |
| public LocalCounterInfo(boolean enabled) { |
| this.enabled = enabled; |
| this.cvalue = new MutableLong(); |
| } |
| } |
| |
| /** |
| * Thread local debug counters used for maintaining counters local to a thread. |
| */ |
| protected final ThreadLocal<LocalCounterInfo[]> threadlocalCounters = |
| new ThreadLocal<LocalCounterInfo[]>() { |
| @Override |
| protected LocalCounterInfo[] initialValue() { |
| return new LocalCounterInfo[MAX_COUNTERS]; |
| } |
| }; |
| |
| /** |
| * Thread local cache for counter ids that are currently active. |
| */ |
| protected final ThreadLocal<Set<Integer>> threadlocalCurrentCounters = |
| new ThreadLocal<Set<Integer>>() { |
| @Override |
| protected Set<Integer> initialValue() { |
| return new HashSet<Integer>(); |
| } |
| }; |
| |
| //******************************* |
| // IDebugCounter |
| //******************************* |
| |
| protected class CounterImpl implements IDebugCounter { |
| private final int counterId; |
| |
| public CounterImpl(int counterId) { |
| this.counterId = counterId; |
| } |
| |
| @Override |
| public void updateCounterWithFlush() { |
| if (!validCounterId()) return; |
| updateCounter(counterId, 1, true); |
| } |
| |
| @Override |
| public void updateCounterNoFlush() { |
| if (!validCounterId()) return; |
| updateCounter(counterId, 1, false); |
| } |
| |
| @Override |
| public void updateCounterWithFlush(int incr) { |
| if (!validCounterId()) return; |
| updateCounter(counterId, incr, true); |
| } |
| |
| @Override |
| public void updateCounterNoFlush(int incr) { |
| if (!validCounterId()) return; |
| updateCounter(counterId, incr, false); |
| } |
| |
| @Override |
| public long getCounterValue() { |
| if (!validCounterId()) return -1; |
| return allCounters[counterId].cvalue.get(); |
| } |
| |
| private boolean validCounterId() { |
| if (counterId < 0 || counterId >= MAX_COUNTERS) { |
| log.error("Invalid counterId invoked"); |
| return false; |
| } |
| return true; |
| } |
| |
| } |
| |
| //******************************* |
| // IDebugCounterService |
| //******************************* |
| |
| @Override |
| public IDebugCounter registerCounter(String moduleName, String counterHierarchy, |
| String counterDescription, CounterType counterType, |
| String... metaData) |
| throws MaxCountersRegistered, MaxHierarchyRegistered, |
| MissingHierarchicalLevel { |
| // check if counter already exists |
| if (!moduleCounters.containsKey(moduleName)) { |
| moduleCounters.putIfAbsent(moduleName, |
| new ConcurrentHashMap<String, CounterIndexStore>()); |
| } |
| RetCtrInfo rci = getCounterId(moduleName, counterHierarchy); |
| if (rci.allLevelsFound) { |
| // counter exists |
| log.info("Counter exists for {}/{} -- resetting counters", moduleName, |
| counterHierarchy); |
| resetCounterHierarchy(moduleName, counterHierarchy); |
| return new CounterImpl(rci.ctrIds[rci.foundUptoLevel-1]); |
| } |
| // check for validity of counter |
| if (rci.levels.length > MAX_HIERARCHY) { |
| String err = "Registry of counterHierarchy " + counterHierarchy + |
| " exceeds max hierachy " + MAX_HIERARCHY + ".. aborting"; |
| throw new MaxHierarchyRegistered(err); |
| } |
| if (rci.foundUptoLevel < rci.levels.length-1) { |
| String needToRegister = ""; |
| for (int i=0; i<=rci.foundUptoLevel; i++) { |
| needToRegister += rci.levels[i]; |
| } |
| String err = "Attempting to register hierarchical counterHierarchy " + |
| counterHierarchy + " but parts of hierarchy missing. " + |
| "Please register " + needToRegister + " first"; |
| throw new MissingHierarchicalLevel(err); |
| } |
| |
| // get a new counter id |
| int counterId = counterIdCounter.getAndIncrement(); |
| if (counterId >= MAX_COUNTERS) { |
| throw new MaxCountersRegistered("max counters reached"); |
| } |
| // create storage for counter |
| boolean enabled = (counterType == CounterType.ALWAYS_COUNT) ? true : false; |
| CounterInfo ci = new CounterInfo(counterId, enabled, moduleName, |
| counterHierarchy, counterDescription, |
| counterType, metaData); |
| allCounters[counterId] = new DebugCounterInfo(ci); |
| |
| // account for the new counter in the module counter hierarchy |
| addToModuleCounterHierarchy(moduleName, counterId, rci); |
| |
| // finally add to active counters |
| if (enabled) { |
| currentCounters.add(counterId); |
| } |
| return new CounterImpl(counterId); |
| } |
| |
| private void updateCounter(int counterId, int incr, boolean flushNow) { |
| if (counterId < 0 || counterId >= MAX_COUNTERS) return; |
| |
| LocalCounterInfo[] thiscounters = this.threadlocalCounters.get(); |
| if (thiscounters[counterId] == null) { |
| // seeing this counter for the first time in this thread - create local |
| // store by consulting global store |
| DebugCounterInfo dc = allCounters[counterId]; |
| if (dc != null) { |
| thiscounters[counterId] = new LocalCounterInfo(dc.cinfo.enabled); |
| if (dc.cinfo.enabled) { |
| Set<Integer> thisset = this.threadlocalCurrentCounters.get(); |
| thisset.add(counterId); |
| } |
| } else { |
| log.error("updateCounter seen locally for counter {} but no global" |
| + "storage exists for it yet .. not updating", counterId); |
| return; |
| } |
| } |
| |
| // update local store if enabled locally for updating |
| LocalCounterInfo lc = thiscounters[counterId]; |
| if (lc.enabled) { |
| lc.cvalue.increment(incr); |
| if (flushNow) { |
| DebugCounterInfo dc = allCounters[counterId]; |
| if (dc.cinfo.enabled) { |
| // globally enabled - flush now |
| dc.cvalue.addAndGet(lc.cvalue.get()); |
| lc.cvalue.set(0); |
| } else { |
| // global counter is disabled - don't flush, disable locally |
| lc.enabled = false; |
| Set<Integer> thisset = this.threadlocalCurrentCounters.get(); |
| thisset.remove(counterId); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void flushCounters() { |
| LocalCounterInfo[] thiscounters = this.threadlocalCounters.get(); |
| Set<Integer> thisset = this.threadlocalCurrentCounters.get(); |
| ArrayList<Integer> temp = new ArrayList<Integer>(); |
| |
| for (int counterId : thisset) { |
| LocalCounterInfo lc = thiscounters[counterId]; |
| if (lc.cvalue.get() > 0) { |
| DebugCounterInfo dc = allCounters[counterId]; |
| if (dc.cinfo.enabled) { |
| // globally enabled - flush now |
| dc.cvalue.addAndGet(lc.cvalue.get()); |
| lc.cvalue.set(0); |
| } else { |
| // global counter is disabled - don't flush, disable locally |
| lc.enabled = false; |
| temp.add(counterId); |
| } |
| } |
| } |
| for (int cId : temp) { |
| thisset.remove(cId); |
| } |
| |
| // At this point it is possible that the thread-local set does not |
| // include a counter that has been enabled and is present in the global set. |
| // We need to sync thread-local currently enabled set of counterIds with |
| // the global set. |
| Sets.SetView<Integer> sv = Sets.difference(currentCounters, thisset); |
| for (int counterId : sv) { |
| if (thiscounters[counterId] != null) { |
| thiscounters[counterId].enabled = true; |
| thisset.add(counterId); |
| } |
| } |
| } |
| |
| @Override |
| public void resetCounterHierarchy(String moduleName, String counterHierarchy) { |
| RetCtrInfo rci = getCounterId(moduleName, counterHierarchy); |
| if (!rci.allLevelsFound) { |
| String missing = rci.levels[rci.foundUptoLevel]; |
| log.error("Cannot reset counter hierarchy - missing counter {}", missing); |
| return; |
| } |
| // reset at this level |
| allCounters[rci.ctrIds[rci.foundUptoLevel-1]].cvalue.set(0); |
| // reset all levels below |
| ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci); |
| for (int index : resetIds) { |
| allCounters[index].cvalue.set(0); |
| } |
| } |
| |
| @Override |
| public void resetAllCounters() { |
| RetCtrInfo rci = new RetCtrInfo(); |
| rci.levels = "".split("/"); |
| for (String moduleName : moduleCounters.keySet()) { |
| ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci); |
| for (int index : resetIds) { |
| allCounters[index].cvalue.set(0); |
| } |
| } |
| } |
| |
| @Override |
| public void resetAllModuleCounters(String moduleName) { |
| Map<String, CounterIndexStore> target = moduleCounters.get(moduleName); |
| RetCtrInfo rci = new RetCtrInfo(); |
| rci.levels = "".split("/"); |
| |
| if (target != null) { |
| ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci); |
| for (int index : resetIds) { |
| allCounters[index].cvalue.set(0); |
| } |
| } else { |
| if (log.isDebugEnabled()) |
| log.debug("No module found with name {}", moduleName); |
| } |
| } |
| |
| @Override |
| public void enableCtrOnDemand(String moduleName, String counterHierarchy) { |
| RetCtrInfo rci = getCounterId(moduleName, counterHierarchy); |
| if (!rci.allLevelsFound) { |
| String missing = rci.levels[rci.foundUptoLevel]; |
| log.error("Cannot enable counter - counter not found {}", missing); |
| return; |
| } |
| // enable specific counter |
| DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]]; |
| dc.cinfo.enabled = true; |
| currentCounters.add(dc.cinfo.counterId); |
| } |
| |
| @Override |
| public void disableCtrOnDemand(String moduleName, String counterHierarchy) { |
| RetCtrInfo rci = getCounterId(moduleName, counterHierarchy); |
| if (!rci.allLevelsFound) { |
| String missing = rci.levels[rci.foundUptoLevel]; |
| log.error("Cannot disable counter - counter not found {}", missing); |
| return; |
| } |
| // disable specific counter |
| DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]]; |
| if (dc.cinfo.ctype == CounterType.COUNT_ON_DEMAND) { |
| dc.cinfo.enabled = false; |
| dc.cvalue.set(0); |
| currentCounters.remove(dc.cinfo.counterId); |
| } |
| } |
| |
| @Override |
| public List<DebugCounterInfo> getCounterHierarchy(String moduleName, |
| String counterHierarchy) { |
| RetCtrInfo rci = getCounterId(moduleName, counterHierarchy); |
| if (!rci.allLevelsFound) { |
| String missing = rci.levels[rci.foundUptoLevel]; |
| log.error("Cannot fetch counter - counter not found {}", missing); |
| return Collections.emptyList(); |
| } |
| ArrayList<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); |
| // get counter and all below it |
| DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]]; |
| dcilist.add(dc); |
| ArrayList<Integer> belowIds = getHierarchyBelow(moduleName, rci); |
| for (int index : belowIds) { |
| dcilist.add(allCounters[index]); |
| } |
| return dcilist; |
| } |
| |
| @Override |
| public List<DebugCounterInfo> getAllCounterValues() { |
| List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); |
| RetCtrInfo rci = new RetCtrInfo(); |
| rci.levels = "".split("/"); |
| |
| for (String moduleName : moduleCounters.keySet()) { |
| ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci); |
| for (int index : resetIds) { |
| dcilist.add(allCounters[index]); |
| } |
| } |
| return dcilist; |
| } |
| |
| @Override |
| public List<DebugCounterInfo> getModuleCounterValues(String moduleName) { |
| List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); |
| RetCtrInfo rci = new RetCtrInfo(); |
| rci.levels = "".split("/"); |
| |
| if (moduleCounters.containsKey(moduleName)) { |
| ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci); |
| for (int index : resetIds) { |
| dcilist.add(allCounters[index]); |
| } |
| } |
| return dcilist; |
| } |
| |
| @Override |
| public boolean containsModuleCounterHierarchy(String moduleName, |
| String counterHierarchy) { |
| if (!moduleCounters.containsKey(moduleName)) return false; |
| RetCtrInfo rci = getCounterId(moduleName, counterHierarchy); |
| return rci.allLevelsFound; |
| } |
| |
| @Override |
| public boolean containsModuleName(String moduleName) { |
| return (moduleCounters.containsKey(moduleName)) ? true : false; |
| } |
| |
| @Override |
| public List<String> getModuleList() { |
| List<String> retval = new ArrayList<String>(); |
| retval.addAll(moduleCounters.keySet()); |
| return retval; |
| } |
| |
| @Override |
| public List<String> getModuleCounterList(String moduleName) { |
| if (!moduleCounters.containsKey(moduleName)) |
| return Collections.emptyList(); |
| |
| List<String> retval = new ArrayList<String>(); |
| RetCtrInfo rci = new RetCtrInfo(); |
| rci.levels = "".split("/"); |
| |
| ArrayList<Integer> cids = getHierarchyBelow(moduleName, rci); |
| for (int index : cids) { |
| retval.add(allCounters[index].cinfo.counterHierarchy); |
| } |
| return retval; |
| } |
| |
| //******************************* |
| // Internal Methods |
| //******************************* |
| |
| protected class RetCtrInfo { |
| boolean allLevelsFound; // counter indices found all the way down the hierarchy |
| boolean hierarchical; // true if counterHierarchy is hierarchical |
| int foundUptoLevel; |
| int[] ctrIds; |
| String[] levels; |
| |
| public RetCtrInfo() { |
| ctrIds = new int[MAX_HIERARCHY]; |
| for (int i=0; i<MAX_HIERARCHY; i++) { |
| ctrIds[i] = -1; |
| } |
| } |
| |
| @Override |
| public boolean equals(Object oth) { |
| if (!(oth instanceof RetCtrInfo)) return false; |
| RetCtrInfo other = (RetCtrInfo)oth; |
| if (other.allLevelsFound != this.allLevelsFound) return false; |
| if (other.hierarchical != this.hierarchical) return false; |
| if (other.foundUptoLevel != this.foundUptoLevel) return false; |
| if (!Arrays.equals(other.ctrIds, this.ctrIds)) return false; |
| if (!Arrays.equals(other.levels, this.levels)) return false; |
| return true; |
| } |
| |
| } |
| |
| protected RetCtrInfo getCounterId(String moduleName, String counterHierarchy) { |
| RetCtrInfo rci = new RetCtrInfo(); |
| Map<String, CounterIndexStore> templevel = moduleCounters.get(moduleName); |
| rci.levels = counterHierarchy.split("/"); |
| if (rci.levels.length > 1) rci.hierarchical = true; |
| if (templevel == null) { |
| log.error("moduleName {} does not exist in debugCounters", moduleName); |
| return rci; |
| } |
| |
| /* |
| if (rci.levels.length > MAX_HIERARCHY) { |
| // chop off all array elems greater that MAX_HIERARCHY |
| String[] temp = new String[MAX_HIERARCHY]; |
| System.arraycopy(rci.levels, 0, temp, 0, MAX_HIERARCHY); |
| rci.levels = temp; |
| } |
| */ |
| for (int i=0; i<rci.levels.length; i++) { |
| if (templevel != null) { |
| CounterIndexStore cis = templevel.get(rci.levels[i]) ; |
| if (cis == null) { |
| // could not find counterHierarchy part at this level |
| break; |
| } else { |
| rci.ctrIds[i] = cis.index; |
| templevel = cis.nextLevel; |
| rci.foundUptoLevel++; |
| if (i == rci.levels.length-1) { |
| rci.allLevelsFound = true; |
| } |
| } |
| } else { |
| // there are no more levels, which means that some part of the |
| // counterHierarchy has no corresponding map |
| break; |
| } |
| } |
| return rci; |
| } |
| |
| protected void addToModuleCounterHierarchy(String moduleName, int counterId, |
| RetCtrInfo rci) { |
| Map<String, CounterIndexStore> target = moduleCounters.get(moduleName); |
| if (target == null) return; |
| CounterIndexStore cis = null; |
| |
| for (int i=0; i<rci.foundUptoLevel; i++) { |
| cis = target.get(rci.levels[i]); |
| target = cis.nextLevel; |
| } |
| if (cis != null) { |
| if (cis.nextLevel == null) |
| cis.nextLevel = new ConcurrentHashMap<String, CounterIndexStore>(); |
| cis.nextLevel.put(rci.levels[rci.foundUptoLevel], |
| new CounterIndexStore(counterId, null)); |
| } else { |
| target.put(rci.levels[rci.foundUptoLevel], |
| new CounterIndexStore(counterId, null)); |
| } |
| } |
| |
| // given a partial hierarchical counter, return the rest of the hierarchy |
| protected ArrayList<Integer> getHierarchyBelow(String moduleName, RetCtrInfo rci) { |
| Map<String, CounterIndexStore> target = moduleCounters.get(moduleName); |
| CounterIndexStore cis = null; |
| ArrayList<Integer> retval = new ArrayList<Integer>(); |
| if (target == null) return retval; |
| |
| // get to the level given |
| for (int i=0; i<rci.foundUptoLevel; i++) { |
| cis = target.get(rci.levels[i]); |
| target = cis.nextLevel; |
| } |
| |
| if (target == null || rci.foundUptoLevel == MAX_HIERARCHY) { |
| // no more levels |
| return retval; |
| } else { |
| // recursively get all ids |
| getIdsAtLevel(target, retval, rci.foundUptoLevel+1); |
| } |
| |
| return retval; |
| } |
| |
| protected void getIdsAtLevel(Map<String, CounterIndexStore> hcy, |
| ArrayList<Integer> retval, int level) { |
| if (level > MAX_HIERARCHY) return; |
| if (hcy == null || retval == null) return; |
| |
| // Can return the counter names as well but for now ids are enough. |
| for (CounterIndexStore cistemp : hcy.values()) { |
| retval.add(cistemp.index); // value at this level |
| if (cistemp.nextLevel != null) { |
| getIdsAtLevel(cistemp.nextLevel, retval, level+1); |
| } |
| } |
| } |
| |
| protected void printAllCounterIds() { |
| log.info("<moduleCounterHierarchy>"); |
| Set<String> keys = moduleCounters.keySet(); |
| for (String key : keys) { |
| log.info("ModuleName: {}", key); |
| Map<String, CounterIndexStore> lev1 = moduleCounters.get(key); |
| for (String key1 : lev1.keySet()) { |
| CounterIndexStore cis1 = lev1.get(key1); |
| log.info(" L1 {}:{}", key1, new Object[] {cis1.index, cis1.nextLevel}); |
| if (cis1.nextLevel != null) { |
| Map<String, CounterIndexStore> lev2 = cis1.nextLevel; |
| for (String key2 : lev2.keySet()) { |
| CounterIndexStore cis2 = lev2.get(key2); |
| log.info(" L2 {}:{}", key2, new Object[] {cis2.index, |
| cis2.nextLevel}); |
| if (cis2.nextLevel != null) { |
| Map<String, CounterIndexStore> lev3 = cis2.nextLevel; |
| for (String key3 : lev3.keySet()) { |
| CounterIndexStore cis3 = lev3.get(key3); |
| log.info(" L3 {}:{}", key3, new Object[] {cis3.index, |
| cis3.nextLevel}); |
| } |
| } |
| } |
| } |
| } |
| } |
| log.info("<\\moduleCounterHierarchy>"); |
| } |
| |
| //******************************* |
| // IFloodlightModule |
| //******************************* |
| |
| @Override |
| public Collection<Class<? extends IFloodlightService>> getModuleServices() { |
| Collection<Class<? extends IFloodlightService>> l = |
| new ArrayList<Class<? extends IFloodlightService>>(); |
| l.add(IDebugCounterService.class); |
| return l; |
| } |
| |
| @Override |
| public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { |
| Map<Class<? extends IFloodlightService>, IFloodlightService> m = |
| new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); |
| m.put(IDebugCounterService.class, this); |
| return m; |
| } |
| |
| @Override |
| public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { |
| ArrayList<Class<? extends IFloodlightService>> deps = |
| new ArrayList<Class<? extends IFloodlightService>>(); |
| deps.add(IRestApiService.class); |
| return deps; |
| } |
| |
| @Override |
| public void init(FloodlightModuleContext context) throws FloodlightModuleException { |
| |
| } |
| |
| @Override |
| public void startUp(FloodlightModuleContext context) { |
| IRestApiService restService = |
| context.getServiceImpl(IRestApiService.class); |
| restService.addRestletRoutable(new DebugCounterRoutable()); |
| } |
| |
| } |