ONOS-6258: UiTopo2Overlay et al.
- initial support for topo-2 highlighting.
Change-Id: I71c61b902047153ea420a8b2ecd89f6950daa4a9
diff --git a/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/DriverViewComponent.java b/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/DriverViewComponent.java
index b8d66de..6d8b214 100644
--- a/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/DriverViewComponent.java
+++ b/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/DriverViewComponent.java
@@ -24,6 +24,7 @@
import org.onosproject.ui.UiExtension;
import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiTopo2OverlayFactory;
import org.onosproject.ui.UiView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,11 +57,22 @@
new DriverViewMessageHandler()
);
+ // ++++ ====================================================== ++++
+ // ++++ Temporary code for testing the topology-2 overlay code ++++
+
+ private final UiTopo2OverlayFactory t2ovFactory =
+ () -> ImmutableList.of(
+ new TesterTopo2Overlay()
+ );
+
+ // ++++ ====================================================== ++++
+
// Application UI extension
protected UiExtension extension =
new UiExtension.Builder(getClass().getClassLoader(), uiViews)
.resourcePath(VIEW_ID)
.messageHandlerFactory(messageHandlerFactory)
+ .topo2OverlayFactory(t2ovFactory) // +++ TEMP +++
.build();
@Activate
diff --git a/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/TesterTopo2Overlay.java b/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/TesterTopo2Overlay.java
new file mode 100644
index 0000000..df81adf
--- /dev/null
+++ b/apps/drivermatrix/src/main/java/org/onosproject/drivermatrix/TesterTopo2Overlay.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017-present 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.drivermatrix;
+
+import org.onosproject.ui.UiTopo2Overlay;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A test implementation of UiTopo2Overlay.
+ */
+public class TesterTopo2Overlay extends UiTopo2Overlay {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ // NOTE: this must match the ID defined in dmatrixTopo2v.js
+ private static final String OVERLAY_ID = "dmatrix-test-overlay";
+ private static final String NAME = "Test D-Matrix Overlay";
+
+ /**
+ * Constructs the overlay.
+ */
+ public TesterTopo2Overlay() {
+ super(OVERLAY_ID, NAME);
+ log.debug("+++ CREATE +++ TesterTopo2Overlay");
+ }
+
+ @Override
+ public String glyphId() {
+ return "thatsNoMoon";
+ }
+
+ @Override
+ public void highlightingCallback() {
+ // TODO: figure out what API to use to set highlights....
+
+ }
+}
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 17201cb..9edcba9a 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiExtension.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiExtension.java
@@ -47,6 +47,7 @@
private final List<UiView> viewList;
private final UiMessageHandlerFactory messageHandlerFactory;
private final UiTopoOverlayFactory topoOverlayFactory;
+ private final UiTopo2OverlayFactory topo2OverlayFactory;
private final UiTopoMapFactory topoMapFactory;
private boolean isValid = true;
@@ -55,12 +56,14 @@
private UiExtension(ClassLoader cl, String path, List<UiView> views,
UiMessageHandlerFactory mhFactory,
UiTopoOverlayFactory toFactory,
+ UiTopo2OverlayFactory to2Factory,
UiTopoMapFactory tmFactory) {
classLoader = cl;
resourcePath = path;
viewList = views;
messageHandlerFactory = mhFactory;
topoOverlayFactory = toFactory;
+ topo2OverlayFactory = to2Factory;
topoMapFactory = tmFactory;
}
@@ -122,6 +125,15 @@
}
/**
+ * Returns the topology-2 overlay factory, if one was defined.
+ *
+ * @return topology-2 overlay factory
+ */
+ public UiTopo2OverlayFactory topo2OverlayFactory() {
+ return topo2OverlayFactory;
+ }
+
+ /**
* Returns the topology map factory, if one was defined.
*
* @return topology map factory
@@ -152,6 +164,7 @@
private List<UiView> viewList = new ArrayList<>();
private UiMessageHandlerFactory messageHandlerFactory = null;
private UiTopoOverlayFactory topoOverlayFactory = null;
+ private UiTopo2OverlayFactory topo2OverlayFactory = null;
private UiTopoMapFactory topoMapFactory = null;
/**
@@ -205,6 +218,17 @@
}
/**
+ * Sets the topology-2 overlay factory for this extension.
+ *
+ * @param to2Factory topology-2 overlay factory
+ * @return self, for chaining
+ */
+ public Builder topo2OverlayFactory(UiTopo2OverlayFactory to2Factory) {
+ topo2OverlayFactory = to2Factory;
+ return this;
+ }
+
+ /**
* Sets the topology map factory for this extension.
*
* @param tmFactory topology map factory
@@ -222,8 +246,8 @@
*/
public UiExtension build() {
return new UiExtension(classLoader, resourcePath, viewList,
- messageHandlerFactory, topoOverlayFactory,
- topoMapFactory);
+ messageHandlerFactory, topoOverlayFactory,
+ topo2OverlayFactory, topoMapFactory);
}
}
}
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopo2Overlay.java b/core/api/src/main/java/org/onosproject/ui/UiTopo2Overlay.java
new file mode 100644
index 0000000..940080e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopo2Overlay.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2017-present 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 a user interface topology-2 view overlay.
+ * <p>
+ * This base class does little more than provide a logger, an identifier,
+ * name, and glyph ID.
+ * Subclasses will probably want to override some or all of the base methods
+ * to do useful things during the life-cycle of the (topo-2) overlay.
+ */
+public class UiTopo2Overlay {
+
+ private static final String DEFAULT_GLYPH_ID = "m_topo";
+
+ /**
+ * Logger for this overlay.
+ */
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final String id;
+ private final String name;
+
+ private boolean isActive = false;
+
+ /**
+ * Creates a new user interface topology view overlay descriptor, with
+ * the given identifier and (human readable) name.
+ *
+ * @param id overlay identifier
+ * @param name overlay name
+ */
+ public UiTopo2Overlay(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ /**
+ * Returns the identifier for this overlay.
+ *
+ * @return the identifier
+ */
+ public String id() {
+ return id;
+ }
+
+ /**
+ * Returns the name for this overlay.
+ *
+ * @return the name
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the glyph identifier to use in the toolbar.
+ * This implementation returns a default value. Subclasses may override
+ * this to provide the identity of a custom glyph.
+ *
+ * @return glyph ID
+ */
+ public String glyphId() {
+ return DEFAULT_GLYPH_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() {
+ isActive = true;
+ }
+
+ /**
+ * Callback invoked when this overlay is deactivated.
+ */
+ public void deactivate() {
+ isActive = false;
+ }
+
+ /**
+ * Returns true if this overlay is currently active.
+ *
+ * @return true if overlay active
+ */
+ public boolean isActive() {
+ return isActive;
+ }
+
+ /**
+ * Callback invoked to destroy this instance by cleaning up any
+ * internal state ready for garbage collection.
+ * This default implementation holds no state and does nothing.
+ */
+ public void destroy() {
+ }
+
+ /**
+ * Callback invoked when the topology highlighting should be updated.
+ * It is the implementation's responsibility to update the Model
+ * Highlighter state. This implementation does nothing.
+ */
+ public void highlightingCallback(/* ref to highlight model ? */) {
+
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopo2OverlayFactory.java b/core/api/src/main/java/org/onosproject/ui/UiTopo2OverlayFactory.java
new file mode 100644
index 0000000..d6718fa
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopo2OverlayFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017-present 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-2
+ * overlay handlers specific to a given user interface connection.
+ */
+public interface UiTopo2OverlayFactory {
+
+ /**
+ * Produces a collection of new overlay handlers for topology-2 view.
+ *
+ * @return collection of new overlay handlers
+ */
+ Collection<UiTopo2Overlay> newOverlays();
+}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
index 00295c4..c302c6b 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
@@ -28,9 +28,12 @@
import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiTopo2OverlayFactory;
import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.onosproject.ui.impl.topo.Topo2Jsonifier;
+import org.onosproject.ui.impl.topo.Topo2OverlayCache;
+import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
import org.onosproject.ui.model.topo.UiTopoLayout;
@@ -50,7 +53,6 @@
private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class);
private static final String EVENT = "event";
- private static final String SID = "sid";
private static final String PAYLOAD = "payload";
private static final String UNKNOWN = "unknown";
@@ -81,6 +83,7 @@
private Map<String, UiMessageHandler> handlers;
private TopoOverlayCache overlayCache;
+ private Topo2OverlayCache overlay2Cache;
/**
* Creates a new web-socket for serving data to the Web UI.
@@ -190,7 +193,7 @@
topoSession.destroy();
destroyHandlersAndOverlays();
log.info("GUI client disconnected [close-code={}, message={}]",
- closeCode, message);
+ closeCode, message);
}
@Override
@@ -244,6 +247,7 @@
log.debug("Creating handlers and overlays...");
handlers = new HashMap<>();
overlayCache = new TopoOverlayCache();
+ overlay2Cache = new Topo2OverlayCache();
UiExtensionService service = directory.get(UiExtensionService.class);
service.getExtensions().forEach(ext -> {
@@ -255,10 +259,13 @@
handler.messageTypes().forEach(type -> handlers.put(type, handler));
// need to inject the overlay cache into topology message handler
- // TODO: code for Topo2ViewMessageHandler required here
if (handler instanceof TopologyViewMessageHandler) {
((TopologyViewMessageHandler) handler).setOverlayCache(overlayCache);
}
+
+ if (handler instanceof Topo2ViewMessageHandler) {
+ ((Topo2ViewMessageHandler) handler).setOverlayCache(overlay2Cache);
+ }
} catch (Exception e) {
log.warn("Unable to setup handler {} due to", handler, e);
}
@@ -269,9 +276,14 @@
if (overlayFactory != null) {
overlayFactory.newOverlays().forEach(overlayCache::add);
}
+
+ UiTopo2OverlayFactory overlay2Factory = ext.topo2OverlayFactory();
+ if (overlay2Factory != null) {
+ overlay2Factory.newOverlays().forEach(overlay2Cache::add);
+ }
});
log.debug("#handlers = {}, #overlays = {}", handlers.size(),
- overlayCache.size());
+ overlayCache.size());
}
// Destroys message handlers.
@@ -298,7 +310,7 @@
.put(ID, node.id().toString())
.put(IP, node.ip().toString())
.put(GlyphConstants.UI_ATTACHED,
- node.equals(service.getLocalNode()));
+ node.equals(service.getLocalNode()));
instances.add(instance);
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2OverlayCache.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2OverlayCache.java
new file mode 100644
index 0000000..1c05acf
--- /dev/null
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2OverlayCache.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2017-present 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.impl.topo;
+
+import org.onosproject.ui.UiTopo2Overlay;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * A cache of {@link org.onosproject.ui.UiTopo2Overlay}'s that were
+ * registered at the time the UI connection was established.
+ * <p>
+ * Note, for now, this is a simplified version which will only cache
+ * a single overlay. At some future point, this should be expanded to mirror
+ * the behavior of {@link org.onosproject.ui.impl.TopoOverlayCache}.
+ */
+public class Topo2OverlayCache {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String EMPTY = "";
+ private static final String NO_OVERLAY = "No Overlay";
+ private static final String UNKNOWN = "unknown";
+
+ private static final UiTopo2Overlay NONE = new NullOverlay();
+
+ private final Map<String, UiTopo2Overlay> overlays = new HashMap<>();
+ private UiTopo2Overlay current = null;
+
+ /**
+ * Constructs the overlay cache.
+ */
+ public Topo2OverlayCache() {
+ overlays.put(null, NONE);
+ }
+
+ /**
+ * Adds a topology-2 overlay to the cache.
+ *
+ * @param overlay a topology-2 overlay
+ */
+ public void add(UiTopo2Overlay overlay) {
+ overlays.put(overlay.id(), overlay);
+ log.warn("added overlay: " + overlay);
+ }
+
+ /**
+ * Invoked when the cache is no longer needed.
+ */
+ public void destroy() {
+ overlays.clear();
+ }
+
+ /**
+ * Switching currently selected overlay.
+ *
+ * @param deact identity of overlay to deactivate
+ * @param act identity of overlay to activate
+ */
+ public void switchOverlay(String deact, String act) {
+ UiTopo2Overlay toDeactivate = getOverlay(deact);
+ UiTopo2Overlay toActivate = getOverlay(act);
+
+ toDeactivate.deactivate();
+ current = toActivate;
+ current.activate();
+ }
+
+ private UiTopo2Overlay getOverlay(String id) {
+ return isNullOrEmpty(id) ? NONE : overlays.get(id);
+ }
+
+ /**
+ * Returns the current overlay instance.
+ * Note that this method always returns a reference; when there is no
+ * overlay selected the "NULL" overlay instance is returned.
+ *
+ * @return the current overlay
+ */
+ public UiTopo2Overlay currentOverlay() {
+ return current;
+ }
+
+ /**
+ * Returns the number of overlays in the cache. Remember that this
+ * includes the "NULL" overlay, representing "no overlay selected".
+ *
+ * @return number of overlays
+ */
+ public int size() {
+ return overlays.size();
+ }
+
+ /**
+ * Returns true if the identifier of the currently active overlay
+ * matches the given parameter.
+ *
+ * @param overlayId overlay identifier
+ * @return true if this matches the ID of currently active overlay
+ */
+ public boolean isActive(String overlayId) {
+ return currentOverlay().id().equals(overlayId);
+ }
+
+ /**
+ * Returns the collection of registered overlays.
+ *
+ * @return registered overlays
+ */
+ public Collection<UiTopo2Overlay> list() {
+ return overlays.values();
+ }
+
+ // overlay instance representing "no overlay selected"
+ private static class NullOverlay extends UiTopo2Overlay {
+ NullOverlay() {
+ super(EMPTY, NO_OVERLAY);
+ }
+
+ @Override
+ public String glyphId() {
+ return UNKNOWN;
+ }
+ }
+}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
index 3c93110..1763048 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
@@ -16,12 +16,14 @@
package org.onosproject.ui.impl.topo;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import org.onlab.osgi.ServiceDirectory;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiConnection;
import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.UiTopo2Overlay;
import org.onosproject.ui.impl.UiWebSocket;
import org.onosproject.ui.model.topo.UiClusterMember;
import org.onosproject.ui.model.topo.UiNode;
@@ -67,10 +69,12 @@
private static final String CURRENT_LAYOUT = "topo2CurrentLayout";
private static final String CURRENT_REGION = "topo2CurrentRegion";
private static final String PEER_REGIONS = "topo2PeerRegions";
+ private static final String OVERLAYS = "topo2Overlays";
private UiTopoSession topoSession;
private Topo2Jsonifier t2json;
+ private Topo2OverlayCache overlay2Cache;
@Override
@@ -82,6 +86,17 @@
t2json = new Topo2Jsonifier(directory, connection.userName());
}
+ /**
+ * Sets a reference to the overlay cache for interacting with registered
+ * overlays.
+ *
+ * @param overlay2Cache the overlay cache
+ */
+ public void setOverlayCache(Topo2OverlayCache overlay2Cache) {
+ this.overlay2Cache = overlay2Cache;
+ }
+
+
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
@@ -114,6 +129,25 @@
return peersPayload;
}
+ private ObjectNode mkOverlaysMessage() {
+ ArrayNode a = arrayNode();
+ for (UiTopo2Overlay ov : overlay2Cache.list()) {
+ a.add(json(ov));
+ }
+ ObjectNode payload = objectNode();
+ payload.set("overlays", a);
+ return payload;
+ }
+
+ private ObjectNode json(UiTopo2Overlay ov) {
+ return objectNode()
+ .put("id", ov.id())
+ .put("name", ov.name())
+ .put("gid", ov.glyphId());
+ }
+
+ // ==================================================================
+
private final class Topo2Start extends RequestHandler {
private Topo2Start() {
@@ -152,6 +186,9 @@
// these are the regions/devices that are siblings to this region
sendMessage(PEER_REGIONS, mkPeersMessage(currentLayout));
+
+ // these are the registered overlays
+ sendMessage(OVERLAYS, mkOverlaysMessage());
}
}