Remove trailing whitespace
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / statistics / StatisticsCounters.java
index 5b666e997ad7fbd22cf938c135efb07a4d45f4cb..1f4d7ca34b4669c4d9b752271ddb2701ac7a9461 100644 (file)
 package org.opendaylight.openflowjava.statistics;
 
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.opendaylight.openflowjava.protocol.spi.statistics.StatisticsHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
+ * Singleton class to hold and process counters
  * @author madamjak
  *
  */
-public final class StatisticsCounters {
+public final class StatisticsCounters implements StatisticsHandler {
 
+    /**
+     * Default delay between two writings into log (milliseconds)
+     */
+    public static final int DEFAULT_LOG_REPORT_PERIOD = 10000;
+    /**
+     * Minimal delay between two writings into log (milliseconds)
+     */
+    public static final int MINIMAL_LOG_REPORT_PERIOD = 500;
     private static StatisticsCounters instanceHolder;
     private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsCounters.class);
 
-    private final Counter cntDSEncodeFail;
-    private final Counter cntDSEncodeSuccess;
-    private final Counter cntDSEnteredOFJava;
-    private final Counter cntUSDecodeFail;
-    private final Counter cntUSDecodeSuccess;
-    private final Counter cntUSMessagePass;
-    private final Counter cntUSReceivedOFJava;
-    //private Map<CounterEventTypes,Counter> countersMap;
-
-    public static StatisticsCounters  getInstance(){
-        if (instanceHolder == null){
+    private Timer logReporter;
+    private int logReportPeriod;
+    private boolean runLogReport;
+    private Map<CounterEventTypes, Counter> countersMap;
+    private boolean runCounting;
+    // array to hold enabled counter types
+    private CounterEventTypes[] enabledCounters = {
+                    CounterEventTypes.DS_ENCODE_FAIL,
+                    CounterEventTypes.DS_ENCODE_SUCCESS,
+                    CounterEventTypes.DS_ENTERED_OFJAVA,
+                    CounterEventTypes.DS_FLOW_MODS_ENTERED,
+                    CounterEventTypes.DS_FLOW_MODS_SENT,
+                    CounterEventTypes.US_DECODE_FAIL,
+                    CounterEventTypes.US_DECODE_SUCCESS,
+                    CounterEventTypes.US_MESSAGE_PASS,
+                    CounterEventTypes.US_RECEIVED_IN_OFJAVA};
+
+    /**
+     * Get instance of statistics counters, first created object does not start counting and log reporting
+     * @return an instance
+     */
+    public synchronized static StatisticsCounters getInstance() {
+        if (instanceHolder == null) {
             instanceHolder = new StatisticsCounters();
         }
         return instanceHolder;
     }
 
     private StatisticsCounters() {
-        cntDSEncodeFail = new Counter();
-        cntDSEncodeSuccess = new Counter();
-        cntDSEnteredOFJava = new Counter();
-        cntUSDecodeFail = new Counter();
-        cntUSDecodeSuccess = new Counter();
-        cntUSMessagePass = new Counter();
-        cntUSReceivedOFJava = new Counter();
-        LOGGER.debug("StaticsCounters (without Map) has been created");
-//        countersMap = new ConcurrentHashMap<>();
-//        countersMap.put(CounterEventTypes.DS_ENCODE_FAIL, new Counter());
-//        countersMap.put(CounterEventTypes.DS_ENCODE_SUCCESS, new Counter());
-//        countersMap.put(CounterEventTypes.DS_ENTERED_OFJAVA, new Counter());
-//        countersMap.put(CounterEventTypes.US_DECODE_FAIL, new Counter());
-//        countersMap.put(CounterEventTypes.US_DECODE_SUCCESS, new Counter());
-//        countersMap.put(CounterEventTypes.US_MESSAGE_PASS, new Counter());
-//        countersMap.put(CounterEventTypes.US_RECEIVED_IN_OFJAVA, new Counter());
-//        LOGGER.debug("StaticsCounters (with Map) has been created");
-    }
-
-    /**
-     * Get given counter
-     * @param counterEventKey - key to identify counter
-     * @return
-     */
-    public Counter getCounter(CounterEventTypes counterEventKey){
-        if(counterEventKey == null){
-            throw new IllegalArgumentException("counterEventKey can not be null");
+        countersMap = new ConcurrentHashMap<>();
+        for(CounterEventTypes cet : enabledCounters){
+            countersMap.put(cet, new Counter());
+        }
+        runCounting = false;
+        this.logReportPeriod = 0;
+        this.runLogReport = false;
+        LOGGER.debug("StaticsCounters has been created");
+    }
+
+    /**
+     * Start counting (counters are set to 0 before counting starts)
+     * @param reportToLogs - true = statistic counters will periodically log
+     * @param logReportDelay - delay between two logs (in milliseconds)
+     */
+    public void startCounting(boolean reportToLogs, int logReportDelay){
+        if (runCounting) {
+            return;
+        }
+        resetCounters();
+        LOGGER.debug("Counting started...");
+        if(reportToLogs){
+            startLogReport(logReportDelay);
+        }
+        runCounting = true;
+    }
+
+    /**
+     * Stop counting, values in counters are untouched, log reporter is stopped
+     */
+    public void stopCounting(){
+        runCounting = false;
+        LOGGER.debug("Stop counting...");
+        stopLogReport();
+    }
+
+    /**
+     * Give an information if counting is running
+     * @return true, if counting is running, otherwise false
+     */
+    public boolean isRunCounting(){
+        return runCounting;
+    }
+
+    /**
+     * Prints statistics with given delay between logs
+     * @param logReportDelay - delay between two logs (in milliseconds)
+     * @exception IllegalArgumentException if logReportDelay is less than 0
+     */
+    public void startLogReport(int logReportDelay){
+        if(runLogReport){
+            return;
         }
-        switch (counterEventKey){
-            case DS_ENCODE_FAIL:
-                return cntDSEncodeFail;
-            case DS_ENCODE_SUCCESS:
-                return cntDSEncodeSuccess;
-            case DS_ENTERED_OFJAVA:
-                return cntDSEnteredOFJava;
-            case US_DECODE_FAIL:
-                return cntUSDecodeFail;
-            case US_DECODE_SUCCESS:
-                return cntUSDecodeSuccess;
-            case US_MESSAGE_PASS:
-                return cntUSMessagePass;
-            case US_RECEIVED_IN_OFJAVA:
-                return cntUSReceivedOFJava;
-            default:
-                throw new IllegalArgumentException("unknown counterEventKey");
+        if(logReportDelay <= 0){
+            throw new IllegalArgumentException("logReportDelay has to be greater than 0");
         }
-//        return countersMap.get(counterEventKey);
+        if(logReportDelay < MINIMAL_LOG_REPORT_PERIOD){
+            this.logReportPeriod = MINIMAL_LOG_REPORT_PERIOD;
+        } else {
+            this.logReportPeriod = logReportDelay;
+        }
+        logReporter = new Timer("SC_Timer");
+        logReporter.schedule(new LogReporterTask(this), this.logReportPeriod, this.logReportPeriod);
+        runLogReport = true;
+        LOGGER.debug("Statistics log reporter has been scheduled with period {} ms", this.logReportPeriod);
+    }
+
+    /**
+     * Stops logging, counting continues
+     */
+    public void stopLogReport(){
+        if(runLogReport){
+            if(logReporter != null){
+                logReporter.cancel();
+                LOGGER.debug("Statistics log reporter has been canceled");
+            }
+            runLogReport = false;
+        }
+    }
+
+    /**
+     * Give an information if log reporter is running (statistics are write into logs).
+     * @return true if log reporter writes statistics into log, otherwise false
+     */
+    public boolean isRunLogReport(){
+        return runLogReport;
+    }
+
+    /**
+     * @return the current delay between two writings into logs
+     */
+    public int getLogReportPeriod() {
+        return logReportPeriod;
+    }
+
+    /**
+     * @return the enabled counters
+     */
+    protected CounterEventTypes[] getEnabledCounters() {
+        return enabledCounters;
+    }
+    /**
+     * @return the countersMap
+     */
+    protected Map<CounterEventTypes, Counter> getCountersMap() {
+        return countersMap;
+    }
+
+    /**
+     * Give an information if is given counter is enabled
+     * @param counterEventKey
+     * @return true if counter has been Enabled, otherwise false
+     */
+    public boolean isCounterEnabled(CounterEventTypes counterEventKey){
+        if (counterEventKey == null) {
+            return false;
+        }
+        return countersMap.containsKey(counterEventKey);
+    }
+
+    /**
+     * Get counter by CounterEventType
+     * @param counterEventKey key to identify counter (can not be null)
+     * @return - Counter object or null if counter has not been enabled
+     * @exception - IllegalArgumentException if counterEventKey is null
+     */
+    public Counter getCounter(CounterEventTypes counterEventKey) {
+        if (counterEventKey == null) {
+            throw new IllegalArgumentException("counterEventKey can not be null");
+        }
+        return countersMap.get(counterEventKey);
     }
 
     /**
      * Increment value of given counter
-     * @param counterEventKey - key to identify counter
-     * @return
-     */
-    public void incrementCounter(CounterEventTypes counterEventKey){
-        getCounter(counterEventKey).incrementCounter();
-    }
-
-    /**
-     * Set values of all counter to 0 (zero)
-     */
-    public void resetCounters(){
-        cntDSEncodeFail.reset(); ;
-        cntDSEncodeSuccess.reset();
-        cntDSEnteredOFJava.reset();
-        cntUSDecodeFail.reset();
-        cntUSDecodeSuccess.reset();
-        cntUSMessagePass.reset();
-        cntUSReceivedOFJava.reset();
-//        countersMap.get(CounterEventTypes.DS_ENCODE_FAIL).reset();
-//        countersMap.get(CounterEventTypes.DS_ENCODE_SUCCESS).reset();
-//        countersMap.get(CounterEventTypes.DS_ENTERED_OFJAVA).reset();
-//        countersMap.get(CounterEventTypes.US_DECODE_FAIL).reset();
-//        countersMap.get(CounterEventTypes.US_DECODE_SUCCESS).reset();
-//        countersMap.get(CounterEventTypes.US_MESSAGE_PASS).reset();
-//        countersMap.get(CounterEventTypes.US_RECEIVED_IN_OFJAVA).reset();
+     * @param counterEventKey key to identify counter
+     */
+    public void incrementCounter(CounterEventTypes counterEventKey) {
+        if(runCounting){
+            if (isCounterEnabled(counterEventKey)){
+                countersMap.get(counterEventKey).incrementCounter();
+            }
+        }
+    }
+
+    @Override
+    public void resetCounters() {
+        for(CounterEventTypes cet : enabledCounters){
+            countersMap.get(cet).reset();
+        }
         LOGGER.debug("StaticsCounters has been reset");
     }
-}
+
+    @Override
+    public String printStatistics() {
+        StringBuilder strBuilder = new StringBuilder();
+        for(CounterEventTypes cet : getEnabledCounters()){
+            strBuilder.append(cet.name() + ": " + getCountersMap().get(cet).getStat() + "\n");
+        }
+        return strBuilder.toString();
+    }
+
+    /**
+     * internal class to process logReporter
+     * @author madamjak
+     *
+     */
+    private static class LogReporterTask extends TimerTask {
+        private static final Logger LOG = LoggerFactory.getLogger(LogReporterTask.class);
+
+        private StatisticsCounters sc;
+        public LogReporterTask(StatisticsCounters sc) {
+            this.sc = sc;
+        }
+
+        @Override
+        public void run() {
+            for(CounterEventTypes cet : sc.getEnabledCounters()){
+                LOG.debug(cet.name() + ": " + sc.getCountersMap().get(cet).getStat());
+            }
+        }
+    }
+}
\ No newline at end of file