[ONOS-3528] Log exceptions of the tasks for SharedExecutorService

This commit tries to log all the runtime exceptions of the tasks
that are executed by using submit method of SharedExecutorService.

Change-Id: I72760213a0f977096353dacd20263e5c93af5c6a
diff --git a/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java b/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java
index 9b91a1a..8806ebc 100644
--- a/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java
+++ b/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java
@@ -16,9 +16,11 @@
 package org.onlab.util;
 
 import com.codahale.metrics.Timer;
+import com.google.common.base.Throwables;
 import org.onlab.metrics.MetricsComponent;
 import org.onlab.metrics.MetricsFeature;
 import org.onlab.metrics.MetricsService;
+import org.slf4j.Logger;
 
 import java.util.Collection;
 import java.util.List;
@@ -39,6 +41,7 @@
 class SharedExecutorService implements ExecutorService {
 
     private static final String NOT_ALLOWED = "Shutdown of shared executor is not allowed";
+    private final Logger log = getLogger(getClass());
 
     private ExecutorService executor;
 
@@ -78,7 +81,6 @@
         oldExecutor.shutdown();
     }
 
-
     @Override
     public void shutdown() {
         throw new UnsupportedOperationException(NOT_ALLOWED);
@@ -138,12 +140,12 @@
 
     @Override
     public <T> Future<T> submit(Runnable task, T result) {
-        return executor.submit(task, result);
+        return executor.submit(wrap(task), result);
     }
 
     @Override
     public Future<?> submit(Runnable task) {
-        return executor.submit(task);
+        return executor.submit(wrap(task));
     }
 
     @Override
@@ -193,10 +195,36 @@
        }
     }
 
+    private Runnable wrap(Runnable command) {
+        return new LoggableRunnable(command);
+    }
+
+    /**
+     * A runnable class that allows to capture and log the exceptions.
+     */
+    private class LoggableRunnable implements Runnable {
+
+        private Runnable runnable;
+
+        public LoggableRunnable(Runnable runnable) {
+            super();
+            this.runnable = runnable;
+        }
+
+        @Override
+        public void run() {
+            try {
+                runnable.run();
+            } catch (Exception e) {
+                log.error("Uncaught exception on " + runnable.getClass().getSimpleName(), e);
+                throw Throwables.propagate(e);
+            }
+        }
+    }
+
     /**
      *  CallableExtended class is used to get Runnable Object
      *  from Callable Object.
-     *
      */
     class CallableExtended implements Callable {