Simon Hunt

Converted UiSharedTopologyModel to be a @Service.

Change-Id: Idc8df1b9c0a52db01ac545567dacc0e1c770f84a
......@@ -16,6 +16,7 @@
package org.onosproject.net.region;
import org.onosproject.event.ListenerService;
import org.onosproject.net.DeviceId;
import java.util.Set;
......@@ -23,7 +24,7 @@ import java.util.Set;
/**
* Service for interacting with inventory of network control regions.
*/
public interface RegionService {
public interface RegionService extends ListenerService<RegionEvent, RegionListener> {
/**
* Returns set of all regions.
......
......@@ -19,5 +19,5 @@ package org.onosproject.ui.model.topo;
/**
* Encapsulates the notion of the ONOS cluster.
*/
public class UiCluster {
public class UiCluster extends UiElement {
}
......
......@@ -19,5 +19,5 @@ package org.onosproject.ui.model.topo;
/**
* Represents an individual member of the cluster (ONOS instance).
*/
public class UiClusterMember {
public class UiClusterMember extends UiElement {
}
......
/*
* Copyright 2016 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.model.topo;
/**
* Abstract base class of all elements in the UI topology model.
*/
public class UiElement {
}
......@@ -19,5 +19,5 @@ package org.onosproject.ui.model.topo;
/**
* Represents a bi-directional link backed by two uni-directional links.
*/
public class UiLink {
public class UiLink extends UiElement {
}
......
......@@ -19,5 +19,5 @@ package org.onosproject.ui.model.topo;
/**
* Represents a node drawn on the topology view (region, device, host).
*/
public abstract class UiNode {
public abstract class UiNode extends UiElement {
}
......
......@@ -19,5 +19,5 @@ package org.onosproject.ui.model.topo;
/**
* Represents the overall network topology.
*/
public class UiTopology {
public class UiTopology extends UiElement {
}
......
......@@ -29,6 +29,7 @@ import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
import org.onosproject.ui.topo.TopoConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -65,7 +66,7 @@ public class UiWebSocket
private TopoOverlayCache overlayCache;
/**
* Creates a new web-socket for serving data to GUI.
* Creates a new web-socket for serving data to the Web UI.
*
* @param directory service directory
* @param userName user name of the logged-in user
......@@ -73,7 +74,8 @@ public class UiWebSocket
public UiWebSocket(ServiceDirectory directory, String userName) {
this.directory = directory;
this.userName = userName;
this.topoSession = new UiTopoSession(this);
this.topoSession =
new UiTopoSession(this, directory.get(UiSharedTopologyModel.class));
}
@Override
......
......@@ -18,6 +18,8 @@ package org.onosproject.ui.impl.topo;
import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.impl.UiWebSocket;
import org.onosproject.ui.impl.topo.model.UiModelEvent;
import org.onosproject.ui.impl.topo.model.UiModelListener;
import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.slf4j.Logger;
......@@ -26,14 +28,14 @@ import org.slf4j.LoggerFactory;
/**
* Coordinates with the {@link UiTopoLayoutService} to access
* {@link UiTopoLayout}s, and with the {@link UiSharedTopologyModel} which
* maintains a local model of the network entities,
* tailored specifically for displaying on the UI.
* maintains a local model of the network entities, tailored specifically
* for displaying on the UI.
* <p>
* Note that an instance of this class will be created for each
* {@link UiWebSocket} connection, and will contain
* the state of how the topology is laid out for the logged-in user.
*/
public class UiTopoSession {
public class UiTopoSession implements UiModelListener {
private final Logger log = LoggerFactory.getLogger(getClass());
private final UiWebSocket webSocket;
......@@ -50,11 +52,12 @@ public class UiTopoSession {
* Creates a new topology session for the specified web socket connection.
*
* @param webSocket web socket
* @param model share topology model
*/
public UiTopoSession(UiWebSocket webSocket) {
public UiTopoSession(UiWebSocket webSocket, UiSharedTopologyModel model) {
this.webSocket = webSocket;
this.username = webSocket.userName();
this.sharedModel = UiSharedTopologyModel.instance();
this.sharedModel = model;
}
/**
......@@ -87,4 +90,10 @@ public class UiTopoSession {
public String toString() {
return String.format("{UiTopoSession for user <%s>}", username);
}
@Override
public void event(UiModelEvent event) {
log.info("Event received: {}", event);
// TODO: handle model events from the cache...
}
}
......
/*
* Copyright 2016 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.model;
import org.onosproject.event.EventDispatcher;
import org.onosproject.net.Device;
import org.onosproject.ui.model.topo.UiDevice;
/**
* UI Topology Model cache.
*/
class ModelCache {
private final EventDispatcher dispatcher;
ModelCache(EventDispatcher eventDispatcher) {
this.dispatcher = eventDispatcher;
}
/**
* Clear our model.
*/
void clear() {
// TODO: clear our internal state
}
/**
* Create our internal model of the global topology.
*/
void load() {
// loadClusterMembers();
// loadRegions();
// loadDevices();
// loadHosts();
// loadLinks();
}
// add or update device
void addOrUpdateDevice(Device device) {
// fetch UiDevice
UiDevice uiDevice = new UiDevice();
dispatcher.post(
new UiModelEvent(UiModelEvent.Type.DEVICE_ADDED, uiDevice)
);
}
void removeDevice(Device device) {
UiDevice uiDevice = new UiDevice();
dispatcher.post(
new UiModelEvent(UiModelEvent.Type.DEVICE_REMOVED, uiDevice)
);
}
// TODO remaining model objects
}
/*
* Copyright 2016 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.model;
import org.onosproject.event.AbstractEvent;
import org.onosproject.ui.model.topo.UiElement;
/**
* UI Topology model events.
*/
public class UiModelEvent extends AbstractEvent<UiModelEvent.Type, UiElement> {
protected UiModelEvent(Type type, UiElement subject) {
super(type, subject);
}
enum Type {
DEVICE_ADDED,
DEVICE_REMOVED,
// TODO...
}
}
/*
* Copyright 2016 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.model;
import org.onosproject.event.EventListener;
/**
* Can receive {@link UiModelEvent}s.
*/
public interface UiModelListener extends EventListener<UiModelEvent> {
}
......@@ -16,16 +16,22 @@
package org.onosproject.ui.impl.topo.model;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onosproject.cluster.ClusterEvent;
import org.onosproject.cluster.ClusterEventListener;
import org.onosproject.cluster.ClusterService;
import org.onosproject.event.AbstractListenerManager;
import org.onosproject.incubator.net.PortStatisticsService;
import org.onosproject.incubator.net.tunnel.TunnelService;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
......@@ -50,30 +56,104 @@ import org.onosproject.ui.impl.topo.UiTopoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
/**
* A lazily-initialized Singleton that creates and maintains the UI-model
* of the network topology.
* Service that creates and maintains the UI-model of the network topology.
*/
public final class UiSharedTopologyModel {
@Component(immediate = true)
@Service(value = UiSharedTopologyModel.class)
public final class UiSharedTopologyModel
extends AbstractListenerManager<UiModelEvent, UiModelListener> {
private static final Logger log =
LoggerFactory.getLogger(UiSharedTopologyModel.class);
private final ModelEventListener modelEventListener;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private MastershipService mastershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private RegionService regionService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private IntentService intentService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private FlowRuleService flowService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private StatisticService flowStatsService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private PortStatisticsService portStatsService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private TunnelService tunnelService;
private final ClusterEventListener clusterListener =
new InternalClusterListener();
private final MastershipListener mastershipListener =
new InternalMastershipListener();
private final RegionListener regionListener =
new InternalRegionListener();
private final DeviceListener deviceListener =
new InternalDeviceListener();
private final LinkListener linkListener =
new InternalLinkListener();
private final HostListener hostListener =
new InternalHostListener();
private final IntentListener intentListener =
new InternalIntentListener();
private final FlowRuleListener flowRuleListener =
new InternalFlowRuleListener();
private ModelCache cache;
@Activate
protected void activate() {
cache = new ModelCache(eventDispatcher);
eventDispatcher.addSink(UiModelEvent.class, listenerRegistry);
clusterService.addListener(clusterListener);
mastershipService.addListener(mastershipListener);
regionService.addListener(regionListener);
deviceService.addListener(deviceListener);
linkService.addListener(linkListener);
hostService.addListener(hostListener);
intentService.addListener(intentListener);
flowService.addListener(flowRuleListener);
cache.load();
log.info("Started");
}
@Deactivate
protected void deactivate() {
eventDispatcher.removeSink(UiModelEvent.class);
private final Set<UiTopoSession> sessions = new HashSet<>();
clusterService.removeListener(clusterListener);
mastershipService.removeListener(mastershipListener);
regionService.removeListener(regionListener);
deviceService.removeListener(deviceListener);
linkService.removeListener(linkListener);
hostService.removeListener(hostListener);
intentService.removeListener(intentListener);
flowService.removeListener(flowRuleListener);
private UiSharedTopologyModel() {
modelEventListener = new ModelEventListener().init();
cache.clear();
cache = null;
// TODO: build and maintain the state of the model
// (1) query model for current state
// (2) update state as model events arrive
log.info("Stopped");
}
/**
* Registers a UI topology session with the topology model.
*
......@@ -81,7 +161,7 @@ public final class UiSharedTopologyModel {
*/
public void register(UiTopoSession session) {
log.info("Registering topology session {}", session);
sessions.add(session);
addListener(session);
}
/**
......@@ -91,138 +171,82 @@ public final class UiSharedTopologyModel {
*/
public void unregister(UiTopoSession session) {
log.info("Unregistering topology session {}", session);
sessions.remove(session);
removeListener(session);
}
// TODO: notify registered sessions when changes happen to the model
// ----------
// inner class to encapsulate the model listeners
private final class ModelEventListener {
// TODO: Review - is this good enough? couldn't otherwise see how to inject
private final ServiceDirectory directory = new DefaultServiceDirectory();
private ClusterService clusterService;
private MastershipService mastershipService;
private RegionService regionService;
private DeviceService deviceService;
private LinkService linkService;
private HostService hostService;
private IntentService intentService;
private FlowRuleService flowService;
private StatisticService flowStatsService;
private PortStatisticsService portStatsService;
private TopologyService topologyService;
private TunnelService tunnelService;
private ModelEventListener init() {
clusterService = directory.get(ClusterService.class);
mastershipService = directory.get(MastershipService.class);
regionService = directory.get(RegionService.class);
deviceService = directory.get(DeviceService.class);
linkService = directory.get(LinkService.class);
hostService = directory.get(HostService.class);
intentService = directory.get(IntentService.class);
flowService = directory.get(FlowRuleService.class);
// passive services (?) to whom we are not listening...
flowStatsService = directory.get(StatisticService.class);
portStatsService = directory.get(PortStatisticsService.class);
topologyService = directory.get(TopologyService.class);
tunnelService = directory.get(TunnelService.class);
return this;
private class InternalClusterListener implements ClusterEventListener {
@Override
public void event(ClusterEvent event) {
// TODO: handle cluster event
}
}
private class InternalClusterListener implements ClusterEventListener {
@Override
public void event(ClusterEvent event) {
// TODO: handle cluster event
// (1) emit cluster member event
}
private class InternalMastershipListener implements MastershipListener {
@Override
public void event(MastershipEvent event) {
// TODO: handle mastership event
}
}
private class InternalMastershipListener implements MastershipListener {
@Override
public void event(MastershipEvent event) {
// TODO: handle mastership event
// (1) emit cluster member update for all members
// (2) emit update device event for he whose mastership changed
}
private class InternalRegionListener implements RegionListener {
@Override
public void event(RegionEvent event) {
// TODO: handle region event
}
}
private class InternalRegionListener implements RegionListener {
@Override
public void event(RegionEvent event) {
// TODO: handle region event
// (1) emit region event
}
}
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
// TODO: handle device event
// (1) emit device event
}
}
Device device = event.subject();
private class InternalLinkListener implements LinkListener {
@Override
public void event(LinkEvent event) {
// TODO: handle link event
// (1) consolidate infrastructure links -> UiLink (?)
// (2) emit link event
}
}
switch (event.type()) {
private class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
// TODO: handle host event
// (1) emit host event
}
}
case DEVICE_ADDED:
case DEVICE_UPDATED:
case DEVICE_AVAILABILITY_CHANGED:
case DEVICE_SUSPENDED:
cache.addOrUpdateDevice(device);
break;
case DEVICE_REMOVED:
cache.removeDevice(device);
break;
private class InternalIntentListener implements IntentListener {
@Override
public void event(IntentEvent event) {
// TODO: handle intent event
// (1) update cache of intent counts?
default:
break;
}
}
}
private class InternalFlowRuleListener implements FlowRuleListener {
@Override
public void event(FlowRuleEvent event) {
// TODO: handle flowrule event
// (1) update cache of flow counts?
}
private class InternalLinkListener implements LinkListener {
@Override
public void event(LinkEvent event) {
// TODO: handle link event
}
}
// ----------
private class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
// TODO: handle host event
}
}
/**
* Bill Pugh Singleton pattern. INSTANCE won't be instantiated until the
* LazyHolder class is loaded via a call to the instance() method below.
*/
private static class LazyHolder {
private static final UiSharedTopologyModel INSTANCE =
new UiSharedTopologyModel();
private class InternalIntentListener implements IntentListener {
@Override
public void event(IntentEvent event) {
// TODO: handle intent event
}
}
/**
* Returns a reference to the Singleton UI network topology model.
*
* @return the singleton topology model
*/
public static UiSharedTopologyModel instance() {
return LazyHolder.INSTANCE;
private class InternalFlowRuleListener implements FlowRuleListener {
@Override
public void event(FlowRuleEvent event) {
// TODO: handle flowrule event
}
}
}
......