Thomas Vachuska
Committed by Gerrit Code Review

Enhanced layout service and hooked-in the ui topo session.

Change-Id: I357143766deb3f0d697a3e7963a53968ccdf3bc8
......@@ -16,6 +16,7 @@
package org.onosproject.ui;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.ui.model.topo.UiTopoLayout;
/**
* Abstraction of a user interface session connection.
......@@ -30,6 +31,34 @@ public interface UiConnection {
String userName();
/**
* Returns the current layout context.
*
* @return current topology layout
*/
UiTopoLayout currentLayout();
/**
* Changes the current layout context to the specified layout.
*
* @param topoLayout new topology layout context
*/
void setCurrentLayout(UiTopoLayout topoLayout);
/**
* Returns the current view identifier.
*
* @return current view
*/
String currentView();
/**
* Sets the currently selected view.
*
* @param viewId view identifier
*/
void setCurrentView(String viewId);
/**
* Sends the specified JSON message to the user interface client.
*
* @param message message to send
......
......@@ -26,6 +26,14 @@ import java.util.Set;
public interface UiTopoLayoutService {
/**
* Returns the top-level root layout, which always exists and cannot
* be removed or associated directly with a region.
*
* @return root topology layout
*/
UiTopoLayout getRootLayout();
/**
* Returns the set of available layouts.
*
* @return set of available layouts
......@@ -40,15 +48,23 @@ public interface UiTopoLayoutService {
*/
boolean addLayout(UiTopoLayout layout);
/**
* Returns the layout with the specified identifier.
*
* @param layoutId layout identifier
* @return layout or null if no such layout is found
*/
UiTopoLayout getLayout(UiTopoLayoutId layoutId);
/**
* Returns the set of the child layouts of the specified layout.
*
* @param layoutId layout identifier
* @return set of child layouts; empty set if layout has no children
*/
Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId);
/**
* Removes a layout from the system.
*
* @param layout the layout to remove
......
......@@ -26,16 +26,19 @@ public class UiTopoLayout {
private final UiTopoLayoutId id;
private final Region region;
private final UiTopoLayoutId parent;
/**
* Created a new UI topology layout.
*
* @param id layout identifier
* @param region backing region
* @param parent identifier of the parent layout
*/
public UiTopoLayout(UiTopoLayoutId id, Region region) {
public UiTopoLayout(UiTopoLayoutId id, Region region, UiTopoLayoutId parent) {
this.id = id;
this.region = region;
this.parent = parent;
}
/**
......@@ -56,5 +59,14 @@ public class UiTopoLayout {
return region;
}
/**
* Returns the parent layout identifier.
*
* @return parent layout identifier
*/
public UiTopoLayoutId parent() {
return parent;
}
// TODO: additional properties pertinent to the layout
}
......
......@@ -27,7 +27,11 @@ import org.onosproject.ui.UiConnection;
import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.onosproject.ui.topo.TopoConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -55,6 +59,8 @@ public class UiWebSocket
private static final String USER = "user";
private static final String BOOTSTRAP = "bootstrap";
public static final String TOPO = "topo";
private static final long MAX_AGE_MS = 30_000;
private static final byte PING = 0x9;
......@@ -63,11 +69,12 @@ public class UiWebSocket
private final ObjectMapper mapper = new ObjectMapper();
private final ServiceDirectory directory;
// private final UiTopoSession topoSession;
private final UiTopoSession topoSession;
private Connection connection;
private FrameConnection control;
private String userName;
private String currentView;
private long lastActive = System.currentTimeMillis();
......@@ -83,8 +90,9 @@ public class UiWebSocket
public UiWebSocket(ServiceDirectory directory, String userName) {
this.directory = directory;
this.userName = userName;
// this.topoSession =
// new UiTopoSession(this, directory.get(UiSharedTopologyModel.class));
this.topoSession =
new UiTopoSession(this, directory.get(UiSharedTopologyModel.class),
directory.get(UiTopoLayoutService.class));
}
@Override
......@@ -92,6 +100,27 @@ public class UiWebSocket
return userName;
}
@Override
public UiTopoLayout currentLayout() {
return topoSession.currentLayout();
}
@Override
public void setCurrentLayout(UiTopoLayout topoLayout) {
topoSession.setCurrentLayout(topoLayout);
}
@Override
public String currentView() {
return currentView;
}
@Override
public void setCurrentView(String viewId) {
currentView = viewId;
topoSession.enableEvent(viewId.equals(TOPO));
}
/**
* Issues a close on the connection.
*/
......@@ -128,7 +157,7 @@ public class UiWebSocket
this.connection = connection;
this.control = (FrameConnection) connection;
try {
// topoSession.init();
topoSession.init();
createHandlersAndOverlays();
sendBootstrapData();
log.info("GUI client connected -- user <{}>", userName);
......@@ -143,10 +172,10 @@ public class UiWebSocket
@Override
public synchronized void onClose(int closeCode, String message) {
// topoSession.destroy();
topoSession.destroy();
destroyHandlersAndOverlays();
log.info("GUI client disconnected [close-code={}, message={}]",
closeCode, message);
closeCode, message);
}
@Override
......@@ -228,7 +257,7 @@ public class UiWebSocket
}
});
log.debug("#handlers = {}, #overlays = {}", handlers.size(),
overlayCache.size());
overlayCache.size());
}
// Destroys message handlers.
......@@ -255,7 +284,7 @@ public class UiWebSocket
.put(ID, node.id().toString())
.put(IP, node.ip().toString())
.put(TopoConstants.Glyphs.UI_ATTACHED,
node.equals(service.getLocalNode()));
node.equals(service.getLocalNode()));
instances.add(instance);
}
......
......@@ -35,7 +35,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Manages the user interface topology layouts.
......@@ -47,6 +51,11 @@ public class UiTopoLayoutManager implements UiTopoLayoutService {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String ID_NULL = "Layout ID cannot be null";
private static final String LAYOUT_NULL = "Layout cannot be null";
private static final UiTopoLayoutId DEFAULT_ID = UiTopoLayoutId.layoutId("_default_");
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
......@@ -57,6 +66,7 @@ public class UiTopoLayoutManager implements UiTopoLayoutService {
public void activate() {
KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
.register(KryoNamespaces.API)
.register(UiTopoLayoutId.class)
.register(UiTopoLayout.class);
layouts = storageService.<UiTopoLayoutId, UiTopoLayout>consistentMapBuilder()
......@@ -66,6 +76,9 @@ public class UiTopoLayoutManager implements UiTopoLayoutService {
.build();
layoutMap = layouts.asJavaMap();
// Create and add the default layout, if needed.
layoutMap.computeIfAbsent(DEFAULT_ID, k -> new UiTopoLayout(k, null, null));
log.info("Started");
}
......@@ -76,22 +89,38 @@ public class UiTopoLayoutManager implements UiTopoLayoutService {
@Override
public UiTopoLayout getRootLayout() {
return getLayout(DEFAULT_ID);
}
@Override
public Set<UiTopoLayout> getLayouts() {
return ImmutableSet.copyOf(layoutMap.values());
}
@Override
public boolean addLayout(UiTopoLayout layout) {
checkNotNull(layout, LAYOUT_NULL);
return layouts.put(layout.id(), layout) == null;
}
@Override
public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
checkNotNull(layoutId, ID_NULL);
return layoutMap.get(layoutId);
}
@Override
public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
checkNotNull(layoutId, ID_NULL);
return layoutMap.values().stream()
.filter(l -> Objects.equals(l.parent(), layoutId))
.collect(Collectors.toSet());
}
@Override
public boolean removeLayout(UiTopoLayout layout) {
checkNotNull(layout, LAYOUT_NULL);
return layouts.remove(layout.id()) != null;
}
......
......@@ -45,19 +45,24 @@ public class UiTopoSession implements UiModelListener {
private boolean registered = false;
private UiTopoLayoutService service;
private UiTopoLayoutService layoutService;
private UiTopoLayout currentLayout;
private boolean messagesEnabled;
/**
* Creates a new topology session for the specified web socket connection.
*
* @param webSocket web socket
* @param model share topology model
* @param webSocket web socket
* @param model share topology model
* @param layoutService topology layout service
*/
public UiTopoSession(UiWebSocket webSocket, UiSharedTopologyModel model) {
public UiTopoSession(UiWebSocket webSocket,
UiSharedTopologyModel model,
UiTopoLayoutService layoutService) {
this.webSocket = webSocket;
this.username = webSocket.userName();
this.sharedModel = model;
this.layoutService = layoutService;
}
/**
......@@ -67,6 +72,7 @@ public class UiTopoSession implements UiModelListener {
if (!registered) {
log.debug("{} : Registering with shared model", this);
sharedModel.register(this);
currentLayout = layoutService.getRootLayout();
registered = true;
} else {
log.warn("already registered");
......@@ -96,4 +102,31 @@ public class UiTopoSession implements UiModelListener {
log.info("Event received: {}", event);
// TODO: handle model events from the cache...
}
/**
* Returns the current layout context.
*
* @return current topology layout
*/
public UiTopoLayout currentLayout() {
return currentLayout;
}
/**
* Changes the current layout context to the specified layout.
*
* @param topoLayout new topology layout context
*/
public void setCurrentLayout(UiTopoLayout topoLayout) {
currentLayout = topoLayout;
}
/**
* Enables or disables the transmission of topology event update messages.
*
* @param enabled true if messages should be sent
*/
public void enableEvent(boolean enabled) {
messagesEnabled = enabled;
}
}
......
......@@ -224,7 +224,10 @@ class ModelCache {
}
private void updateDevice(UiDevice device) {
device.setRegionId(services.region().getRegionForDevice(device.id()).id());
Region regionForDevice = services.region().getRegionForDevice(device.id());
if (regionForDevice != null) {
device.setRegionId(regionForDevice.id());
}
}
private void loadDevices() {
......
......@@ -66,7 +66,7 @@ import org.slf4j.LoggerFactory;
/**
* Service that creates and maintains the UI-model of the network topology.
*/
@Component(immediate = true, enabled = false)
@Component(immediate = true, enabled = true)
@Service(value = UiSharedTopologyModel.class)
public final class UiSharedTopologyModel
extends AbstractListenerManager<UiModelEvent, UiModelListener> {
......
......@@ -40,11 +40,11 @@ public class UiTopoLayoutManagerTest {
private static final UiTopoLayout L1 =
new UiTopoLayout(UiTopoLayoutId.layoutId("l1"),
new DefaultRegion(RegionId.regionId("r1"), "R1",
Region.Type.CAMPUS, null));
Region.Type.CAMPUS, null), null);
private static final UiTopoLayout L2 =
new UiTopoLayout(UiTopoLayoutId.layoutId("l2"),
new DefaultRegion(RegionId.regionId("r2"), "R2",
Region.Type.CAMPUS, null));
Region.Type.CAMPUS, null), null);
@Before
public void setUp() {
......@@ -62,14 +62,14 @@ public class UiTopoLayoutManagerTest {
@Test
public void basics() {
assertTrue("should be no layout", svc.getLayouts().isEmpty());
assertEquals("should be just default layout", 1, svc.getLayouts().size());
svc.addLayout(L1);
svc.addLayout(L2);
assertEquals("incorrect number of layouts", 2, svc.getLayouts().size());
assertEquals("incorrect number of layouts", 3, svc.getLayouts().size());
assertEquals("incorrect layout", L1.id(), svc.getLayout(L1.id()).id());
assertEquals("incorrect layout", L2.id(), svc.getLayout(L2.id()).id());
svc.removeLayout(L1);
assertEquals("incorrect number of layouts", 1, svc.getLayouts().size());
assertEquals("incorrect number of layouts", 2, svc.getLayouts().size());
assertNull("layout should be gone", svc.getLayout(L1.id()));
assertEquals("incorrect layout", L2.id(), svc.getLayout(L2.id()).id());
}
......