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 b8d66de144..6d8b214132 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.apache.felix.scr.annotations.ReferenceCardinality; 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 @@ public class DriverViewComponent { 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 0000000000..df81adf9e2 --- /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 17201cbf35..9edcba9a96 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 @@ public final class UiExtension { private final List 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 @@ public final class UiExtension { private UiExtension(ClassLoader cl, String path, List views, UiMessageHandlerFactory mhFactory, UiTopoOverlayFactory toFactory, + UiTopo2OverlayFactory to2Factory, UiTopoMapFactory tmFactory) { classLoader = cl; resourcePath = path; viewList = views; messageHandlerFactory = mhFactory; topoOverlayFactory = toFactory; + topo2OverlayFactory = to2Factory; topoMapFactory = tmFactory; } @@ -121,6 +124,15 @@ public final class UiExtension { return topoOverlayFactory; } + /** + * 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. * @@ -152,6 +164,7 @@ public final class UiExtension { private List viewList = new ArrayList<>(); private UiMessageHandlerFactory messageHandlerFactory = null; private UiTopoOverlayFactory topoOverlayFactory = null; + private UiTopo2OverlayFactory topo2OverlayFactory = null; private UiTopoMapFactory topoMapFactory = null; /** @@ -204,6 +217,17 @@ public final class UiExtension { return this; } + /** + * 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. * @@ -222,8 +246,8 @@ public final class UiExtension { */ 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 0000000000..940080e75e --- /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. + *

+ * 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 0000000000..d6718fae21 --- /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 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 00295c4e65..c302c6b998 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.UiConnection; 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 @@ public class UiWebSocket 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 @@ public class UiWebSocket private Map handlers; private TopoOverlayCache overlayCache; + private Topo2OverlayCache overlay2Cache; /** * Creates a new web-socket for serving data to the Web UI. @@ -190,7 +193,7 @@ public class UiWebSocket topoSession.destroy(); destroyHandlersAndOverlays(); log.info("GUI client disconnected [close-code={}, message={}]", - closeCode, message); + closeCode, message); } @Override @@ -244,6 +247,7 @@ public class UiWebSocket 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 @@ public class UiWebSocket 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 @@ public class UiWebSocket 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 @@ public class UiWebSocket .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 0000000000..1c05acfc31 --- /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. + *

+ * 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 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 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 3c93110151..1763048dbb 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 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { 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 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { 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 createRequestHandlers() { return ImmutableSet.of( @@ -114,6 +129,25 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { 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 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { // these are the regions/devices that are siblings to this region sendMessage(PEER_REGIONS, mkPeersMessage(currentLayout)); + + // these are the registered overlays + sendMessage(OVERLAYS, mkOverlaysMessage()); } }