ONOS-1479 - GUI Topology Overlay Work - (WIP)
- UiExtension now uses Builder Pattern; added topology overlay factory.
- Refactored UiExtensionTest (and other classes) to use builder.
- Created UiTopoOverlayFactory, UiTopoOverlay, and TopoOverlayCache.
- Started implementation of TrafficOverlay.
- Inject TopoOverlayCache into TopologyViewMessageHandler; added TopoSelectOverlay request handler.
- Modified UiExtensionManager to create traffic overlay.
- Augmented UiWebSocket to create overlays on demand, and inject overlay cache into topo view message handler.
- added client side wiring to switch overlays.

Change-Id: I6f99596aefb3b87382517ce929d268a2447545ee
diff --git a/core/api/src/main/java/org/onosproject/ui/UiExtension.java b/core/api/src/main/java/org/onosproject/ui/UiExtension.java
index cc10506..c310858 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiExtension.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiExtension.java
@@ -15,61 +15,47 @@
  */
 package org.onosproject.ui;
 
-import com.google.common.collect.ImmutableList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * User interface extension.
  */
-public class UiExtension {
+public final class UiExtension {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private static final String VIEW_PREFIX = "app/view/";
+    private static final String EMPTY = "";
+    private static final String SLASH = "/";
+    private static final String CSS_HTML = "css.html";
+    private static final String JS_HTML = "js.html";
 
-    private final String prefix;
     private final ClassLoader classLoader;
+    private final String resourcePath;
     private final List<UiView> views;
     private final UiMessageHandlerFactory messageHandlerFactory;
+    private final UiTopoOverlayFactory topoOverlayFactory;
 
-    /**
-     * Creates a user interface extension for loading CSS and JS injections
-     * from {@code css.html} and {@code js.html} resources, respectively.
-     *
-     * @param views                 list of contributed views
-     * @param messageHandlerFactory optional message handler factory
-     * @param classLoader           class-loader for user interface resources
-     */
-    public UiExtension(List<UiView> views,
-                       UiMessageHandlerFactory messageHandlerFactory,
-                       ClassLoader classLoader) {
-        this(views, messageHandlerFactory, null, classLoader);
+
+    // private constructor - only the builder calls this
+    private UiExtension(ClassLoader cl, String path, List<UiView> views,
+                        UiMessageHandlerFactory mhFactory,
+                        UiTopoOverlayFactory toFactory) {
+        this.classLoader = cl;
+        this.resourcePath = path;
+        this.views = views;
+        this.messageHandlerFactory = mhFactory;
+        this.topoOverlayFactory = toFactory;
     }
 
-    /**
-     * Creates a user interface extension using custom resource prefix. It
-     * loads CSS and JS injections from {@code path/css.html} and
-     * {@code prefix/js.html} resources, respectively.
-     *
-     * @param views                 list of user interface views
-     * @param messageHandlerFactory optional message handler factory
-     * @param path                  resource path prefix
-     * @param classLoader           class-loader for user interface resources
-     */
-    public UiExtension(List<UiView> views,
-                       UiMessageHandlerFactory messageHandlerFactory,
-                       String path, ClassLoader classLoader) {
-        this.views = checkNotNull(ImmutableList.copyOf(views), "Views cannot be null");
-        this.messageHandlerFactory = messageHandlerFactory;
-        this.prefix = path != null ? (path + "/") : "";
-        this.classLoader = checkNotNull(classLoader, "Class loader must be specified");
-    }
 
     /**
      * Returns input stream containing CSS inclusion statements.
@@ -77,7 +63,7 @@
      * @return CSS inclusion statements
      */
     public InputStream css() {
-        return getStream(prefix + "css.html");
+        return getStream(resourcePath + CSS_HTML);
     }
 
     /**
@@ -86,7 +72,7 @@
      * @return JavaScript inclusion statements
      */
     public InputStream js() {
-       return getStream(prefix + "js.html");
+       return getStream(resourcePath + JS_HTML);
     }
 
     /**
@@ -106,18 +92,28 @@
      * @return resource input stream
      */
     public InputStream resource(String viewId, String path) {
-        return getStream(VIEW_PREFIX + viewId + "/" + path);
+        return getStream(VIEW_PREFIX + viewId + SLASH + path);
     }
 
     /**
-     * Returns message handler factory.
+     * Returns message handler factory, if one was defined.
      *
-     * @return message handlers
+     * @return message handler factory
      */
     public UiMessageHandlerFactory messageHandlerFactory() {
         return messageHandlerFactory;
     }
 
+    /**
+     * Returns the topology overlay factory, if one was defined.
+     *
+     * @return topology overlay factory
+     */
+    public UiTopoOverlayFactory topoOverlayFactory() {
+        return topoOverlayFactory;
+    }
+
+
     // Returns the resource input stream from the specified class-loader.
     private InputStream getStream(String path) {
         InputStream stream = classLoader.getResourceAsStream(path);
@@ -128,4 +124,76 @@
     }
 
 
+    /**
+     * UI Extension Builder.
+     */
+    public static class Builder {
+        private ClassLoader classLoader;
+
+        private String resourcePath = EMPTY;
+        private List<UiView> views = new ArrayList<>();
+        private UiMessageHandlerFactory messageHandlerFactory = null;
+        private UiTopoOverlayFactory topoOverlayFactory = null;
+
+        /**
+         * Create a builder with the given class loader.
+         * Resource path defaults to "".
+         * Views defaults to an empty list.
+         * Both Message and TopoOverlay factories default to null.
+         *
+         * @param cl the classloader
+         */
+        public Builder(ClassLoader cl, List<UiView> views) {
+            checkNotNull(cl, "Must provide a class loader");
+            checkArgument(views.size() > 0, "Must provide at least one view");
+            this.classLoader = cl;
+            this.views = views;
+        }
+
+        /**
+         * Set the resource path. That is, path to where the CSS and JS
+         * files are located. This value should
+         *
+         * @param path resource path
+         * @return self, for chaining
+         */
+        public Builder resourcePath(String path) {
+            this.resourcePath = path == null ? EMPTY : path + SLASH;
+            return this;
+        }
+
+        /**
+         * Sets the message handler factory for this extension.
+         *
+         * @param mhFactory message handler factory
+         * @return self, for chaining
+         */
+        public Builder messageHandlerFactory(UiMessageHandlerFactory mhFactory) {
+            this.messageHandlerFactory = mhFactory;
+            return this;
+        }
+
+        /**
+         * Sets the topology overlay factory for this extension.
+         *
+         * @param toFactory topology overlay factory
+         * @return self, for chaining
+         */
+        public Builder topoOverlayFactory(UiTopoOverlayFactory toFactory) {
+            this.topoOverlayFactory = toFactory;
+            return this;
+        }
+
+        /**
+         * Builds the UI extension.
+         *
+         * @return UI extension instance
+         */
+        public UiExtension build() {
+            return new UiExtension(classLoader, resourcePath, views,
+                                   messageHandlerFactory, topoOverlayFactory);
+        }
+
+    }
+
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java b/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java
index b3782a2..e27f5d9 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java
@@ -107,8 +107,9 @@
     void exec(String eventType, long sid, ObjectNode payload) {
         RequestHandler requestHandler = handlerMap.get(eventType);
         if (requestHandler != null) {
-            log.debug("process {} event...", eventType);
             requestHandler.process(sid, payload);
+        } else {
+            log.warn("no request handler for event type {}", eventType);
         }
     }
 
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java b/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java
new file mode 100644
index 0000000..999067a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.onosproject.ui;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents user interface topology view overlay.
+ */
+public class UiTopoOverlay {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private final String id;
+
+    /**
+     * Creates a new user interface topology view overlay descriptor.
+     *
+     * @param id overlay identifier
+     */
+    public UiTopoOverlay(String id) {
+        this.id = id;
+    }
+
+    /**
+     * Returns the identifier for this overlay.
+     *
+     * @return the identifier
+     */
+    public String id() {
+        return id;
+    }
+
+    /**
+     * Callback invoked to initialize this overlay, soon after creation.
+     * This default implementation does nothing.
+     */
+    public void init() {
+    }
+
+    /**
+     * Callback invoked when this overlay is activated.
+     */
+    public void activate() {
+        log.debug("Overlay '{}' Activated", id);
+    }
+
+    /**
+     * Callback invoked when this overlay is deactivated.
+     */
+    public void deactivate() {
+        log.debug("Overlay '{}' Deactivated", id);
+    }
+
+    /**
+     * Callback invoked to destroy this instance by cleaning up any
+     * internal state ready for garbage collection.
+     * This default implementation does nothing.
+     */
+    public void destroy() {
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.java b/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.java
new file mode 100644
index 0000000..bd2f2fe
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.onosproject.ui;
+
+import java.util.Collection;
+
+/**
+ * Abstraction of an entity capable of producing one or more topology
+ * overlay handlers specific to a given user interface connection.
+ */
+public interface UiTopoOverlayFactory {
+
+    /**
+     * Produces a collection of new overlay handlers.
+     *
+     * @return collection of new overlay handlers
+     */
+    Collection<UiTopoOverlay> newOverlays();
+}