blob: b7c17b271932449d712193b38d1b3794f310657c [file] [log] [blame]
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001package net.floodlightcontroller.debugcounter;
2
3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.Map;
10import java.util.Set;
11import java.util.List;
12import java.util.concurrent.ConcurrentHashMap;
13import java.util.concurrent.atomic.AtomicInteger;
14import java.util.concurrent.atomic.AtomicLong;
15
16import org.slf4j.Logger;
17import org.slf4j.LoggerFactory;
18
19import com.google.common.collect.Sets;
20
21import net.floodlightcontroller.core.module.FloodlightModuleContext;
22import net.floodlightcontroller.core.module.FloodlightModuleException;
23import net.floodlightcontroller.core.module.IFloodlightModule;
24import net.floodlightcontroller.core.module.IFloodlightService;
25import net.floodlightcontroller.debugcounter.web.DebugCounterRoutable;
26import net.floodlightcontroller.restserver.IRestApiService;
27
28/**
29 * This class implements a central store for all counters used for debugging the
30 * system. For counters based on traffic-type, see ICounterStoreService.
31 *
32 * @author saurav
33 */
34public class DebugCounter implements IFloodlightModule, IDebugCounterService {
35 protected static Logger log = LoggerFactory.getLogger(DebugCounter.class);
36
37 /**
38 * registered counters need a counter id
39 */
40 protected AtomicInteger counterIdCounter = new AtomicInteger();
41
42 /**
43 * The counter value
44 */
45 protected class MutableLong {
46 long value = 0;
47 public void increment() { value += 1; }
48 public void increment(long incr) { value += incr; }
49 public long get() { return value; }
50 public void set(long val) { value = val; }
51 }
52
53 /**
54 * protected class to store counter information
55 */
56 public static class CounterInfo {
57 String moduleCounterHierarchy;
58 String counterDesc;
59 CounterType ctype;
60 String moduleName;
61 String counterHierarchy;
62 int counterId;
63 boolean enabled;
64 String[] metaData;
65
66 public CounterInfo(int counterId, boolean enabled,
67 String moduleName, String counterHierarchy,
68 String desc, CounterType ctype, String... metaData) {
69 this.moduleCounterHierarchy = moduleName + "/" + counterHierarchy;
70 this.moduleName = moduleName;
71 this.counterHierarchy = counterHierarchy;
72 this.counterDesc = desc;
73 this.ctype = ctype;
74 this.counterId = counterId;
75 this.enabled = enabled;
76 this.metaData = metaData;
77 }
78
79 public String getModuleCounterHierarchy() { return moduleCounterHierarchy; }
80 public String getCounterDesc() { return counterDesc; }
81 public CounterType getCtype() { return ctype; }
82 public String getModuleName() { return moduleName; }
83 public String getCounterHierarchy() { return counterHierarchy; }
84 public int getCounterId() { return counterId; }
85 public boolean isEnabled() { return enabled; }
86 public String[] getMetaData() { return metaData; }
87 }
88
89 //******************
90 // Global stores
91 //******************
92
93 /**
94 * Counter info for a debug counter
95 */
96 public class DebugCounterInfo {
97 CounterInfo cinfo;
98 AtomicLong cvalue;
99
100 public DebugCounterInfo(CounterInfo cinfo) {
101 this.cinfo = cinfo;
102 this.cvalue = new AtomicLong();
103 }
104 public CounterInfo getCounterInfo() {
105 return cinfo;
106 }
107 public Long getCounterValue() {
108 return cvalue.get();
109 }
110 }
111
112 /**
113 * Global debug-counter storage across all threads. These are
114 * updated from the local per thread counters by the flush counters method.
115 */
116 protected static DebugCounterInfo[] allCounters =
117 new DebugCounterInfo[MAX_COUNTERS];
118
119
120 /**
121 * per module counters, indexed by the module name and storing three levels
122 * of Counter information in the form of CounterIndexStore
123 */
124 protected ConcurrentHashMap<String, ConcurrentHashMap<String, CounterIndexStore>>
125 moduleCounters = new ConcurrentHashMap<String,
126 ConcurrentHashMap<String,
127 CounterIndexStore>>();
128
129 protected class CounterIndexStore {
130 int index;
131 Map<String, CounterIndexStore> nextLevel;
132
133 public CounterIndexStore(int index, Map<String,CounterIndexStore> cis) {
134 this.index = index;
135 this.nextLevel = cis;
136 }
137 }
138
139 /**
140 * fast global cache for counter ids that are currently active
141 */
142 protected Set<Integer> currentCounters = Collections.newSetFromMap(
143 new ConcurrentHashMap<Integer,Boolean>());
144
145 //******************
146 // Thread local stores
147 //******************
148
149 /**
150 * Thread local storage of counter info
151 */
152 protected class LocalCounterInfo {
153 boolean enabled;
154 MutableLong cvalue;
155
156 public LocalCounterInfo(boolean enabled) {
157 this.enabled = enabled;
158 this.cvalue = new MutableLong();
159 }
160 }
161
162 /**
163 * Thread local debug counters used for maintaining counters local to a thread.
164 */
165 protected final ThreadLocal<LocalCounterInfo[]> threadlocalCounters =
166 new ThreadLocal<LocalCounterInfo[]>() {
167 @Override
168 protected LocalCounterInfo[] initialValue() {
169 return new LocalCounterInfo[MAX_COUNTERS];
170 }
171 };
172
173 /**
174 * Thread local cache for counter ids that are currently active.
175 */
176 protected final ThreadLocal<Set<Integer>> threadlocalCurrentCounters =
177 new ThreadLocal<Set<Integer>>() {
178 @Override
179 protected Set<Integer> initialValue() {
180 return new HashSet<Integer>();
181 }
182 };
183
184 //*******************************
185 // IDebugCounter
186 //*******************************
187
188 protected class CounterImpl implements IDebugCounter {
189 private final int counterId;
190
191 public CounterImpl(int counterId) {
192 this.counterId = counterId;
193 }
194
195 @Override
196 public void updateCounterWithFlush() {
197 if (!validCounterId()) return;
198 updateCounter(counterId, 1, true);
199 }
200
201 @Override
202 public void updateCounterNoFlush() {
203 if (!validCounterId()) return;
204 updateCounter(counterId, 1, false);
205 }
206
207 @Override
208 public void updateCounterWithFlush(int incr) {
209 if (!validCounterId()) return;
210 updateCounter(counterId, incr, true);
211 }
212
213 @Override
214 public void updateCounterNoFlush(int incr) {
215 if (!validCounterId()) return;
216 updateCounter(counterId, incr, false);
217 }
218
219 @Override
220 public long getCounterValue() {
221 if (!validCounterId()) return -1;
222 return allCounters[counterId].cvalue.get();
223 }
224
225 private boolean validCounterId() {
226 if (counterId < 0 || counterId >= MAX_COUNTERS) {
227 log.error("Invalid counterId invoked");
228 return false;
229 }
230 return true;
231 }
232
233 }
234
235 //*******************************
236 // IDebugCounterService
237 //*******************************
238
239 @Override
240 public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
241 String counterDescription, CounterType counterType,
242 String... metaData)
243 throws MaxCountersRegistered, MaxHierarchyRegistered,
244 MissingHierarchicalLevel {
245 // check if counter already exists
246 if (!moduleCounters.containsKey(moduleName)) {
247 moduleCounters.putIfAbsent(moduleName,
248 new ConcurrentHashMap<String, CounterIndexStore>());
249 }
250 RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
251 if (rci.allLevelsFound) {
252 // counter exists
253 log.info("Counter exists for {}/{} -- resetting counters", moduleName,
254 counterHierarchy);
255 resetCounterHierarchy(moduleName, counterHierarchy);
256 return new CounterImpl(rci.ctrIds[rci.foundUptoLevel-1]);
257 }
258 // check for validity of counter
259 if (rci.levels.length > MAX_HIERARCHY) {
260 String err = "Registry of counterHierarchy " + counterHierarchy +
261 " exceeds max hierachy " + MAX_HIERARCHY + ".. aborting";
262 throw new MaxHierarchyRegistered(err);
263 }
264 if (rci.foundUptoLevel < rci.levels.length-1) {
265 String needToRegister = "";
266 for (int i=0; i<=rci.foundUptoLevel; i++) {
267 needToRegister += rci.levels[i];
268 }
269 String err = "Attempting to register hierarchical counterHierarchy " +
270 counterHierarchy + " but parts of hierarchy missing. " +
271 "Please register " + needToRegister + " first";
272 throw new MissingHierarchicalLevel(err);
273 }
274
275 // get a new counter id
276 int counterId = counterIdCounter.getAndIncrement();
277 if (counterId >= MAX_COUNTERS) {
278 throw new MaxCountersRegistered("max counters reached");
279 }
280 // create storage for counter
281 boolean enabled = (counterType == CounterType.ALWAYS_COUNT) ? true : false;
282 CounterInfo ci = new CounterInfo(counterId, enabled, moduleName,
283 counterHierarchy, counterDescription,
284 counterType, metaData);
285 allCounters[counterId] = new DebugCounterInfo(ci);
286
287 // account for the new counter in the module counter hierarchy
288 addToModuleCounterHierarchy(moduleName, counterId, rci);
289
290 // finally add to active counters
291 if (enabled) {
292 currentCounters.add(counterId);
293 }
294 return new CounterImpl(counterId);
295 }
296
297 private void updateCounter(int counterId, int incr, boolean flushNow) {
298 if (counterId < 0 || counterId >= MAX_COUNTERS) return;
299
300 LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
301 if (thiscounters[counterId] == null) {
302 // seeing this counter for the first time in this thread - create local
303 // store by consulting global store
304 DebugCounterInfo dc = allCounters[counterId];
305 if (dc != null) {
306 thiscounters[counterId] = new LocalCounterInfo(dc.cinfo.enabled);
307 if (dc.cinfo.enabled) {
308 Set<Integer> thisset = this.threadlocalCurrentCounters.get();
309 thisset.add(counterId);
310 }
311 } else {
312 log.error("updateCounter seen locally for counter {} but no global"
313 + "storage exists for it yet .. not updating", counterId);
314 return;
315 }
316 }
317
318 // update local store if enabled locally for updating
319 LocalCounterInfo lc = thiscounters[counterId];
320 if (lc.enabled) {
321 lc.cvalue.increment(incr);
322 if (flushNow) {
323 DebugCounterInfo dc = allCounters[counterId];
324 if (dc.cinfo.enabled) {
325 // globally enabled - flush now
326 dc.cvalue.addAndGet(lc.cvalue.get());
327 lc.cvalue.set(0);
328 } else {
329 // global counter is disabled - don't flush, disable locally
330 lc.enabled = false;
331 Set<Integer> thisset = this.threadlocalCurrentCounters.get();
332 thisset.remove(counterId);
333 }
334 }
335 }
336 }
337
338 @Override
339 public void flushCounters() {
340 LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
341 Set<Integer> thisset = this.threadlocalCurrentCounters.get();
342 ArrayList<Integer> temp = new ArrayList<Integer>();
343
344 for (int counterId : thisset) {
345 LocalCounterInfo lc = thiscounters[counterId];
346 if (lc.cvalue.get() > 0) {
347 DebugCounterInfo dc = allCounters[counterId];
348 if (dc.cinfo.enabled) {
349 // globally enabled - flush now
350 dc.cvalue.addAndGet(lc.cvalue.get());
351 lc.cvalue.set(0);
352 } else {
353 // global counter is disabled - don't flush, disable locally
354 lc.enabled = false;
355 temp.add(counterId);
356 }
357 }
358 }
359 for (int cId : temp) {
360 thisset.remove(cId);
361 }
362
363 // At this point it is possible that the thread-local set does not
364 // include a counter that has been enabled and is present in the global set.
365 // We need to sync thread-local currently enabled set of counterIds with
366 // the global set.
367 Sets.SetView<Integer> sv = Sets.difference(currentCounters, thisset);
368 for (int counterId : sv) {
369 if (thiscounters[counterId] != null) {
370 thiscounters[counterId].enabled = true;
371 thisset.add(counterId);
372 }
373 }
374 }
375
376 @Override
377 public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
378 RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
379 if (!rci.allLevelsFound) {
380 String missing = rci.levels[rci.foundUptoLevel];
381 log.error("Cannot reset counter hierarchy - missing counter {}", missing);
382 return;
383 }
384 // reset at this level
385 allCounters[rci.ctrIds[rci.foundUptoLevel-1]].cvalue.set(0);
386 // reset all levels below
387 ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
388 for (int index : resetIds) {
389 allCounters[index].cvalue.set(0);
390 }
391 }
392
393 @Override
394 public void resetAllCounters() {
395 RetCtrInfo rci = new RetCtrInfo();
396 rci.levels = "".split("/");
397 for (String moduleName : moduleCounters.keySet()) {
398 ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
399 for (int index : resetIds) {
400 allCounters[index].cvalue.set(0);
401 }
402 }
403 }
404
405 @Override
406 public void resetAllModuleCounters(String moduleName) {
407 Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
408 RetCtrInfo rci = new RetCtrInfo();
409 rci.levels = "".split("/");
410
411 if (target != null) {
412 ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
413 for (int index : resetIds) {
414 allCounters[index].cvalue.set(0);
415 }
416 } else {
417 if (log.isDebugEnabled())
418 log.debug("No module found with name {}", moduleName);
419 }
420 }
421
422 @Override
423 public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
424 RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
425 if (!rci.allLevelsFound) {
426 String missing = rci.levels[rci.foundUptoLevel];
427 log.error("Cannot enable counter - counter not found {}", missing);
428 return;
429 }
430 // enable specific counter
431 DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]];
432 dc.cinfo.enabled = true;
433 currentCounters.add(dc.cinfo.counterId);
434 }
435
436 @Override
437 public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
438 RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
439 if (!rci.allLevelsFound) {
440 String missing = rci.levels[rci.foundUptoLevel];
441 log.error("Cannot disable counter - counter not found {}", missing);
442 return;
443 }
444 // disable specific counter
445 DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]];
446 if (dc.cinfo.ctype == CounterType.COUNT_ON_DEMAND) {
447 dc.cinfo.enabled = false;
448 dc.cvalue.set(0);
449 currentCounters.remove(dc.cinfo.counterId);
450 }
451 }
452
453 @Override
454 public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
455 String counterHierarchy) {
456 RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
457 if (!rci.allLevelsFound) {
458 String missing = rci.levels[rci.foundUptoLevel];
459 log.error("Cannot fetch counter - counter not found {}", missing);
460 return Collections.emptyList();
461 }
462 ArrayList<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
463 // get counter and all below it
464 DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]];
465 dcilist.add(dc);
466 ArrayList<Integer> belowIds = getHierarchyBelow(moduleName, rci);
467 for (int index : belowIds) {
468 dcilist.add(allCounters[index]);
469 }
470 return dcilist;
471 }
472
473 @Override
474 public List<DebugCounterInfo> getAllCounterValues() {
475 List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
476 RetCtrInfo rci = new RetCtrInfo();
477 rci.levels = "".split("/");
478
479 for (String moduleName : moduleCounters.keySet()) {
480 ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
481 for (int index : resetIds) {
482 dcilist.add(allCounters[index]);
483 }
484 }
485 return dcilist;
486 }
487
488 @Override
489 public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
490 List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
491 RetCtrInfo rci = new RetCtrInfo();
492 rci.levels = "".split("/");
493
494 if (moduleCounters.containsKey(moduleName)) {
495 ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
496 for (int index : resetIds) {
497 dcilist.add(allCounters[index]);
498 }
499 }
500 return dcilist;
501 }
502
503 @Override
504 public boolean containsModuleCounterHierarchy(String moduleName,
505 String counterHierarchy) {
506 if (!moduleCounters.containsKey(moduleName)) return false;
507 RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
508 return rci.allLevelsFound;
509 }
510
511 @Override
512 public boolean containsModuleName(String moduleName) {
513 return (moduleCounters.containsKey(moduleName)) ? true : false;
514 }
515
516 @Override
517 public List<String> getModuleList() {
518 List<String> retval = new ArrayList<String>();
519 retval.addAll(moduleCounters.keySet());
520 return retval;
521 }
522
523 @Override
524 public List<String> getModuleCounterList(String moduleName) {
525 if (!moduleCounters.containsKey(moduleName))
526 return Collections.emptyList();
527
528 List<String> retval = new ArrayList<String>();
529 RetCtrInfo rci = new RetCtrInfo();
530 rci.levels = "".split("/");
531
532 ArrayList<Integer> cids = getHierarchyBelow(moduleName, rci);
533 for (int index : cids) {
534 retval.add(allCounters[index].cinfo.counterHierarchy);
535 }
536 return retval;
537 }
538
539 //*******************************
540 // Internal Methods
541 //*******************************
542
543 protected class RetCtrInfo {
544 boolean allLevelsFound; // counter indices found all the way down the hierarchy
545 boolean hierarchical; // true if counterHierarchy is hierarchical
546 int foundUptoLevel;
547 int[] ctrIds;
548 String[] levels;
549
550 public RetCtrInfo() {
551 ctrIds = new int[MAX_HIERARCHY];
552 for (int i=0; i<MAX_HIERARCHY; i++) {
553 ctrIds[i] = -1;
554 }
555 }
556
557 @Override
558 public boolean equals(Object oth) {
559 if (!(oth instanceof RetCtrInfo)) return false;
560 RetCtrInfo other = (RetCtrInfo)oth;
561 if (other.allLevelsFound != this.allLevelsFound) return false;
562 if (other.hierarchical != this.hierarchical) return false;
563 if (other.foundUptoLevel != this.foundUptoLevel) return false;
564 if (!Arrays.equals(other.ctrIds, this.ctrIds)) return false;
565 if (!Arrays.equals(other.levels, this.levels)) return false;
566 return true;
567 }
568
569 }
570
571 protected RetCtrInfo getCounterId(String moduleName, String counterHierarchy) {
572 RetCtrInfo rci = new RetCtrInfo();
573 Map<String, CounterIndexStore> templevel = moduleCounters.get(moduleName);
574 rci.levels = counterHierarchy.split("/");
575 if (rci.levels.length > 1) rci.hierarchical = true;
576 if (templevel == null) {
577 log.error("moduleName {} does not exist in debugCounters", moduleName);
578 return rci;
579 }
580
581 /*
582 if (rci.levels.length > MAX_HIERARCHY) {
583 // chop off all array elems greater that MAX_HIERARCHY
584 String[] temp = new String[MAX_HIERARCHY];
585 System.arraycopy(rci.levels, 0, temp, 0, MAX_HIERARCHY);
586 rci.levels = temp;
587 }
588 */
589 for (int i=0; i<rci.levels.length; i++) {
590 if (templevel != null) {
591 CounterIndexStore cis = templevel.get(rci.levels[i]) ;
592 if (cis == null) {
593 // could not find counterHierarchy part at this level
594 break;
595 } else {
596 rci.ctrIds[i] = cis.index;
597 templevel = cis.nextLevel;
598 rci.foundUptoLevel++;
599 if (i == rci.levels.length-1) {
600 rci.allLevelsFound = true;
601 }
602 }
603 } else {
604 // there are no more levels, which means that some part of the
605 // counterHierarchy has no corresponding map
606 break;
607 }
608 }
609 return rci;
610 }
611
612 protected void addToModuleCounterHierarchy(String moduleName, int counterId,
613 RetCtrInfo rci) {
614 Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
615 if (target == null) return;
616 CounterIndexStore cis = null;
617
618 for (int i=0; i<rci.foundUptoLevel; i++) {
619 cis = target.get(rci.levels[i]);
620 target = cis.nextLevel;
621 }
622 if (cis != null) {
623 if (cis.nextLevel == null)
624 cis.nextLevel = new ConcurrentHashMap<String, CounterIndexStore>();
625 cis.nextLevel.put(rci.levels[rci.foundUptoLevel],
626 new CounterIndexStore(counterId, null));
627 } else {
628 target.put(rci.levels[rci.foundUptoLevel],
629 new CounterIndexStore(counterId, null));
630 }
631 }
632
633 // given a partial hierarchical counter, return the rest of the hierarchy
634 protected ArrayList<Integer> getHierarchyBelow(String moduleName, RetCtrInfo rci) {
635 Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
636 CounterIndexStore cis = null;
637 ArrayList<Integer> retval = new ArrayList<Integer>();
638 if (target == null) return retval;
639
640 // get to the level given
641 for (int i=0; i<rci.foundUptoLevel; i++) {
642 cis = target.get(rci.levels[i]);
643 target = cis.nextLevel;
644 }
645
646 if (target == null || rci.foundUptoLevel == MAX_HIERARCHY) {
647 // no more levels
648 return retval;
649 } else {
650 // recursively get all ids
651 getIdsAtLevel(target, retval, rci.foundUptoLevel+1);
652 }
653
654 return retval;
655 }
656
657 protected void getIdsAtLevel(Map<String, CounterIndexStore> hcy,
658 ArrayList<Integer> retval, int level) {
659 if (level > MAX_HIERARCHY) return;
660 if (hcy == null || retval == null) return;
661
662 // Can return the counter names as well but for now ids are enough.
663 for (CounterIndexStore cistemp : hcy.values()) {
664 retval.add(cistemp.index); // value at this level
665 if (cistemp.nextLevel != null) {
666 getIdsAtLevel(cistemp.nextLevel, retval, level+1);
667 }
668 }
669 }
670
671 protected void printAllCounterIds() {
672 log.info("<moduleCounterHierarchy>");
673 Set<String> keys = moduleCounters.keySet();
674 for (String key : keys) {
675 log.info("ModuleName: {}", key);
676 Map<String, CounterIndexStore> lev1 = moduleCounters.get(key);
677 for (String key1 : lev1.keySet()) {
678 CounterIndexStore cis1 = lev1.get(key1);
679 log.info(" L1 {}:{}", key1, new Object[] {cis1.index, cis1.nextLevel});
680 if (cis1.nextLevel != null) {
681 Map<String, CounterIndexStore> lev2 = cis1.nextLevel;
682 for (String key2 : lev2.keySet()) {
683 CounterIndexStore cis2 = lev2.get(key2);
684 log.info(" L2 {}:{}", key2, new Object[] {cis2.index,
685 cis2.nextLevel});
686 if (cis2.nextLevel != null) {
687 Map<String, CounterIndexStore> lev3 = cis2.nextLevel;
688 for (String key3 : lev3.keySet()) {
689 CounterIndexStore cis3 = lev3.get(key3);
690 log.info(" L3 {}:{}", key3, new Object[] {cis3.index,
691 cis3.nextLevel});
692 }
693 }
694 }
695 }
696 }
697 }
698 log.info("<\\moduleCounterHierarchy>");
699 }
700
701 //*******************************
702 // IFloodlightModule
703 //*******************************
704
705 @Override
706 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
707 Collection<Class<? extends IFloodlightService>> l =
708 new ArrayList<Class<? extends IFloodlightService>>();
709 l.add(IDebugCounterService.class);
710 return l;
711 }
712
713 @Override
714 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
715 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
716 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
717 m.put(IDebugCounterService.class, this);
718 return m;
719 }
720
721 @Override
722 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
723 ArrayList<Class<? extends IFloodlightService>> deps =
724 new ArrayList<Class<? extends IFloodlightService>>();
725 deps.add(IRestApiService.class);
726 return deps;
727 }
728
729 @Override
730 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
731
732 }
733
734 @Override
735 public void startUp(FloodlightModuleContext context) {
736 IRestApiService restService =
737 context.getServiceImpl(IRestApiService.class);
738 restService.addRestletRoutable(new DebugCounterRoutable());
739 }
740
741}