diff --git a/apps/layout/BUCK b/apps/layout/BUCK index 87e21e34f1..5d249c4769 100644 --- a/apps/layout/BUCK +++ b/apps/layout/BUCK @@ -1,5 +1,6 @@ COMPILE_DEPS = [ '//lib:CORE_DEPS', + '//lib:JACKSON', '//lib:org.apache.karaf.shell.console', '//core/common:onos-core-common', '//cli:onos-cli', diff --git a/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java b/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java index 02917f1b8e..9f4f39d9f9 100644 --- a/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java +++ b/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java @@ -27,6 +27,7 @@ import org.onosproject.net.HostId; import org.onosproject.utils.Comparators; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -35,31 +36,62 @@ import java.util.stream.Collectors; */ public class AccessNetworkLayout extends LayoutAlgorithm { - private static final double COMPUTE_Y = -400.0; - private static final double SERVICE_Y = -200.0; - private static final double SPINE_Y = 0.0; - private static final double AGGREGATION_Y = +200.0; - private static final double ACCESS_Y = +400.0; - private static final double HOSTS_Y = +700.0; - private static final double GATEWAY_X = 900.0; + private double computeY = -350.0; + private double serviceY = -200.0; + private double spineY = 0.0; + private double aggregationY = +200.0; + private double accessY = +400.0; + private double hostsY = +550.0; - private static final double ROW_GAP = 70; - private static final double COMPUTE_ROW_GAP = -120; - private static final double COL_GAP = 54; - private static final double COMPUTE_OFFSET = 800.0; - private static final double GATEWAY_GAP = 200.0; - private static final double GATEWAY_OFFSET = -200.0; - - private static final double SERVICE_GAP = 800; - private static final int COMPUTE_PER_ROW = 25; - - private static final double SPINES_GAP = 800; - private static final double AGGREGATION_GAP = 400; - private static final double ACCESS_GAP = 400; - private static final int HOSTS_PER_ROW = 6; + private double gatewayX = 900.0; + private double rowGap = 70; + private double computeRowGap = -120; + private double colGap = 54; + private double computeOffset = 800.0; + private double gatewayGap = 200.0; + private double gatewayOffset = -200.0; + private double serviceGap = 800; + private int computePerRow = 25; + private double spinesGap = 800; + private double aggregationGap = 400; + private double accessGap = 400; + private int hostsPerRow = 6; private int spine, aggregation, accessLeaf, serviceLeaf, gateway; + /** + * Creates the network layout using default layout options. + */ + public AccessNetworkLayout() { + } + + /** + * Creates the network layout using the specified layout property overrides. + * + * @param custom overrides of the default layout properties + */ + public AccessNetworkLayout(Map custom) { + computeY = (double) custom.getOrDefault("computeY", computeY); + serviceY = (double) custom.getOrDefault("serviceY", serviceY); + spineY = (double) custom.getOrDefault("spineY", spineY); + aggregationY = (double) custom.getOrDefault("aggregationY", aggregationY); + accessY = (double) custom.getOrDefault("accessY", accessY); + hostsY = (double) custom.getOrDefault("hostsY", hostsY); + gatewayX = (double) custom.getOrDefault("gatewayX", gatewayX); + rowGap = (double) custom.getOrDefault("rowGap", rowGap); + computeRowGap = (double) custom.getOrDefault("computeRowGap", computeRowGap); + colGap = (double) custom.getOrDefault("colGap", colGap); + computeOffset = (double) custom.getOrDefault("computeOffset", computeOffset); + gatewayGap = (double) custom.getOrDefault("gatewayGap", gatewayGap); + gatewayOffset = (double) custom.getOrDefault("gatewayOffset", gatewayOffset); + serviceGap = (double) custom.getOrDefault("serviceGap", serviceGap); + computePerRow = (int) custom.getOrDefault("computePerRow", computePerRow); + spinesGap = (double) custom.getOrDefault("spinesGap", spinesGap); + aggregationGap = (double) custom.getOrDefault("aggregationGap", aggregationGap); + accessGap = (double) custom.getOrDefault("accessGap", accessGap); + hostsPerRow = (int) custom.getOrDefault("hostsPerRow", hostsPerRow); + } + @Override protected boolean classify(Device device) { if (!super.classify(device)) { @@ -112,7 +144,7 @@ public class AccessNetworkLayout extends LayoutAlgorithm { spine = 1; List spines = deviceCategories.get(SPINE); spines.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR) - .forEach(d -> place(d, c(spine++, spines.size(), SPINES_GAP), SPINE_Y)); + .forEach(d -> place(d, c(spine++, spines.size(), spinesGap), spineY)); } private void placeServiceLeavesAndHosts() { @@ -124,7 +156,7 @@ public class AccessNetworkLayout extends LayoutAlgorithm { serviceLeaf = 1; leaves.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR).forEach(id -> { gateway = 1; - place(id, c(serviceLeaf++, leaves.size(), SERVICE_GAP), SERVICE_Y); + place(id, c(serviceLeaf++, leaves.size(), serviceGap), serviceY); List gwHosts = hostService.getConnectedHosts(id).stream() .map(Host::id) @@ -134,8 +166,8 @@ public class AccessNetworkLayout extends LayoutAlgorithm { .collect(Collectors.toList()); gwHosts.forEach(hid -> { - place(hid, serviceLeaf <= 2 ? -GATEWAY_X : GATEWAY_X, - c(gateway++, gwHosts.size(), GATEWAY_GAP, GATEWAY_OFFSET)); + place(hid, serviceLeaf <= 2 ? -gatewayX : gatewayX, + c(gateway++, gwHosts.size(), gatewayGap, gatewayOffset)); placed.add(hid); }); @@ -146,9 +178,9 @@ public class AccessNetworkLayout extends LayoutAlgorithm { .sorted(Comparators.ELEMENT_ID_COMPARATOR) .collect(Collectors.toList()); - placeHostBlock(hosts, serviceLeaf <= 2 ? -COMPUTE_OFFSET : COMPUTE_OFFSET, - COMPUTE_Y, COMPUTE_PER_ROW, COMPUTE_ROW_GAP, - serviceLeaf <= 2 ? -COL_GAP : COL_GAP); + placeHostBlock(hosts, serviceLeaf <= 2 ? -computeOffset : computeOffset, + computeY, computePerRow, computeRowGap, + serviceLeaf <= 2 ? -colGap : colGap); placed.addAll(hosts); }); } @@ -165,7 +197,7 @@ public class AccessNetworkLayout extends LayoutAlgorithm { .forEach(lid -> placeAccessLeafAndHosts(lid, leaves.size(), placed)); } else { spines.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR).forEach(id -> { - place(id, c(aggregation++, spines.size(), AGGREGATION_GAP), AGGREGATION_Y); + place(id, c(aggregation++, spines.size(), aggregationGap), aggregationY); linkService.getDeviceEgressLinks(id).stream() .map(l -> l.dst().deviceId()) .filter(leaves::contains) @@ -177,14 +209,14 @@ public class AccessNetworkLayout extends LayoutAlgorithm { } private void placeAccessLeafAndHosts(DeviceId leafId, int leafCount, Set placed) { - double x = c(accessLeaf++, leafCount, ACCESS_GAP); - place(leafId, x, ACCESS_Y); + double x = c(accessLeaf++, leafCount, accessGap); + place(leafId, x, accessY); placed.add(leafId); placeHostBlock(hostService.getConnectedHosts(leafId).stream() .map(Host::id) .sorted(Comparators.ELEMENT_ID_COMPARATOR) - .collect(Collectors.toList()), x, HOSTS_Y, - HOSTS_PER_ROW, ROW_GAP, COL_GAP); + .collect(Collectors.toList()), x, hostsY, + hostsPerRow, rowGap, colGap); } } diff --git a/apps/layout/src/main/java/org/onosproject/layout/LayoutOverlayMessageHandler.java b/apps/layout/src/main/java/org/onosproject/layout/LayoutOverlayMessageHandler.java new file mode 100644 index 0000000000..f66f1bd406 --- /dev/null +++ b/apps/layout/src/main/java/org/onosproject/layout/LayoutOverlayMessageHandler.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.layout; + +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +/** + * ONOS UI Layout Topology-Overlay message handler. + */ +public class LayoutOverlayMessageHandler extends UiMessageHandler { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String DO_LAYOUT = "doLayout"; + private static final String TYPE = "type"; + + RoleBasedLayoutManager layoutManager; + + @Override + public void init(UiConnection connection, ServiceDirectory directory) { + super.init(connection, directory); + layoutManager = directory.get(RoleBasedLayoutManager.class); + } + + @Override + protected Collection createRequestHandlers() { + return ImmutableSet.of( + new LayoutHandler() + ); + } + + private final class LayoutHandler extends RequestHandler { + + public LayoutHandler() { + super(DO_LAYOUT); + } + + @Override + public void process(ObjectNode payload) { + String algorithm = string(payload, TYPE); + switch (algorithm) { + case "access": + layoutManager.layout(new AccessNetworkLayout()); + break; + default: + layoutManager.layout(new DefaultForceLayout()); + break; + } + } + } + +} \ No newline at end of file diff --git a/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java b/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java index 0340c7c6fb..932e62601e 100644 --- a/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java +++ b/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java @@ -16,6 +16,7 @@ package org.onosproject.layout; +import com.google.common.collect.ImmutableList; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -26,9 +27,18 @@ import org.onosproject.net.config.NetworkConfigService; import org.onosproject.net.device.DeviceService; import org.onosproject.net.host.HostService; import org.onosproject.net.link.LinkService; +import org.onosproject.ui.UiExtension; +import org.onosproject.ui.UiExtensionService; +import org.onosproject.ui.UiMessageHandlerFactory; +import org.onosproject.ui.UiTopoOverlay; +import org.onosproject.ui.UiTopoOverlayFactory; +import org.onosproject.ui.UiView; +import org.onosproject.ui.UiViewHidden; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + /** * Manages automatic layout of the current network elements into one of several * supported layout variants using roles assigned to network elements using @@ -40,6 +50,30 @@ public class RoleBasedLayoutManager { private Logger log = LoggerFactory.getLogger(getClass()); + private static final String VIEW_ID = "tlTopov"; + private static final String OVERLAY_ID = "tl-overlay"; + + // List of application views + private final List uiViews = ImmutableList.of( + new UiViewHidden(VIEW_ID) + ); + + // Factory for UI message handlers + private final UiMessageHandlerFactory messageHandlerFactory = + () -> ImmutableList.of(new LayoutOverlayMessageHandler()); + + // Factory for UI topology overlays + private final UiTopoOverlayFactory topoOverlayFactory = + () -> ImmutableList.of(new UiTopoOverlay(OVERLAY_ID)); + + // Application UI extension + protected UiExtension extension = + new UiExtension.Builder(getClass().getClassLoader(), uiViews) + .resourcePath(VIEW_ID) + .messageHandlerFactory(messageHandlerFactory) + .topoOverlayFactory(topoOverlayFactory) + .build(); + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected NetworkConfigService networkConfigService; @@ -52,17 +86,21 @@ public class RoleBasedLayoutManager { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected LinkService linkService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected UiExtensionService uiExtensionService; + @Activate protected void activate() { + uiExtensionService.register(extension); log.info("Started"); } @Deactivate protected void deactivate() { + uiExtensionService.unregister(extension); log.info("Stopped"); } - /** * Executes the specified layout algorithm. * diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.css b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.css new file mode 100644 index 0000000000..8aa18f66b9 --- /dev/null +++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.css @@ -0,0 +1,2 @@ +/* css for layout topology overlay */ + diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.html b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.html new file mode 100644 index 0000000000..1f762253e5 --- /dev/null +++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.html @@ -0,0 +1,4 @@ + +
+

This is a hidden view .. just a placeholder to house the javascript

+
diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.js b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.js new file mode 100644 index 0000000000..729d1178cc --- /dev/null +++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.js @@ -0,0 +1,47 @@ +/* + * Copyright 2015-present Open Networking Foundation + * + * 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. + */ + +/* + Module containing the "business logic" for the layout topology overlay. + */ + +(function () { + 'use strict'; + + // injected refs + var $log, flash, wss; + + function doLayout(type, description) { + flash.flash(description); + wss.sendEvent('doLayout', { + type: type + }); + } + + angular.module('ovTlTopov', []) + .factory('LayoutTopovService', + ['$log', 'FlashService', 'WebSocketService', + + function (_$log_, _flash_, _wss_) { + $log = _$log_; + flash = _flash_; + wss = _wss_; + + return { + doLayout: doLayout + }; + }]); +}()); diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopovOverlay.js b/apps/layout/src/main/resources/app/view/tlTopov/tlTopovOverlay.js new file mode 100644 index 0000000000..aba7d141b7 --- /dev/null +++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopovOverlay.js @@ -0,0 +1,58 @@ +// path painter topology overlay - client side +// +// This is the glue that binds our business logic (in ppTopov.js) +// to the overlay framework. + +(function () { + 'use strict'; + + // injected refs + var $log, tov, lts; + + // our overlay definition + var overlay = { + overlayId: 'tl-overlay', + glyphId: 'm_disjointPaths', + tooltip: 'Algorithmic Layout Overlay', + + activate: function () { + $log.debug("Layout topology overlay ACTIVATED"); + }, + deactivate: function () { + lts.clear(); + $log.debug("Layout topology overlay DEACTIVATED"); + }, + + keyBindings: { + 0: { + cb: function () { + lts.doLayout('default', 'Default (force-based) Layout'); + }, + tt: 'Default (force-based) layout', + gid: 'm_fiberSwitch' + }, + 1: { + cb: function () { + lts.doLayout('access', 'Access Network Layout - separate service leafs'); + }, + tt: 'Access layout - separate service leafs', + gid: 'm_disjointPaths' + }, + + _keyOrder: [ + '0', '1' + ] + } + }; + + // invoke code to register with the overlay service + angular.module('ovTlTopov') + .run(['$log', 'TopoOverlayService', 'LayoutTopovService', + + function (_$log_, _tov_, _lts_) { + $log = _$log_; + tov = _tov_; + lts = _lts_; + tov.register(overlay); + }]); +}()); diff --git a/apps/layout/src/main/resources/tlTopov/css.html b/apps/layout/src/main/resources/tlTopov/css.html new file mode 100644 index 0000000000..12810e7267 --- /dev/null +++ b/apps/layout/src/main/resources/tlTopov/css.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/layout/src/main/resources/tlTopov/js.html b/apps/layout/src/main/resources/tlTopov/js.html new file mode 100644 index 0000000000..85afb32f7f --- /dev/null +++ b/apps/layout/src/main/resources/tlTopov/js.html @@ -0,0 +1,2 @@ + + \ No newline at end of file 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 4d01f8c22f..61f8015239 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 @@ -251,18 +251,18 @@ public class UiWebSocket ObjectNode message = (ObjectNode) mapper.reader().readTree(data); String type = message.path(EVENT).asText(UNKNOWN); - if (sessionToken == null) { - authenticate(type, message); - +// if (sessionToken == null) { +// authenticate(type, message); +// +// } else { + UiMessageHandler handler = handlers.get(type); + if (handler != null) { + log.debug("RX message: {}", message); + handler.process(message); } else { - UiMessageHandler handler = handlers.get(type); - if (handler != null) { - log.debug("RX message: {}", message); - handler.process(message); - } else { - log.warn("No GUI message handler for type {}", type); - } + log.warn("No GUI message handler for type {}", type); } +// } } catch (Exception e) { log.warn("Unable to parse GUI message {} due to {}", data, e);