org.onosproject.uiref.UiRefTopoOverlayMessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.onosproject.uiref.UiRefTopoOverlayMessageHandler.java

Source

/*
 * Copyright 2015 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.uiref;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import org.onlab.osgi.ServiceDirectory;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Element;
import org.onosproject.net.HostId;
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.link.LinkService;
import org.onosproject.ui.JsonUtils;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiConnection;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.topo.DeviceHighlight;
import org.onosproject.ui.topo.Highlights;
import org.onosproject.ui.topo.NodeBadge;
import org.onosproject.ui.topo.TopoJson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Message handler for Topology overlay events.
 */
public class UiRefTopoOverlayMessageHandler extends UiMessageHandler {

    private static final String UI_REF_TOPOV_DISPLAY_START = "uiRefTopovDisplayStart";
    private static final String UI_REF_TOPOV_DISPLAY_UPDATE = "uiRefTopovDisplayUpdate";
    private static final String UI_REF_TOPOV_DISPLAY_STOP = "uiRefTopovDisplayStop";
    private static final String UI_REF_TOPOV_DEV_PORTS_REQ = "uiRefTopovDevicePortsReq";
    private static final String UI_REF_TOPOV_DEV_PORTS_RESP = "uiRefTopovDevicePortsResp";
    private static final String UI_REF_TOPOV_DEV_PORTS_OP = "uiRefTopovDevicePortFakeOp";

    private static final String ID = "id";

    private static final String PORTS = "ports";
    private static final String SPEED = "speed";
    private static final String TYPE = "type";
    private static final String MODE = "mode";

    private static final String DEVICE = "device";
    private static final String PORT = "port";
    private static final String FOO = "foo";
    private static final String BAR = "bar";

    private static final long UPDATE_PERIOD_MS = 1000;

    private static final Link[] EMPTY_LINK_SET = new Link[0];

    private enum Mode {
        IDLE, MOUSE, LINK
    }

    private final Logger log = LoggerFactory.getLogger(getClass());

    private DeviceService deviceService;
    private HostService hostService;
    private LinkService linkService;

    private final Timer timer = new Timer("ui-ref-overlay");
    private TimerTask demoTask = null;
    private Mode currentMode = Mode.IDLE;
    private Element elementOfNote;
    private Link[] linkSet = EMPTY_LINK_SET;
    private int linkIndex;

    // ===============-=-=-=-=-=-======================-=-=-=-=-=-=-================================

    @Override
    public void init(UiConnection connection, ServiceDirectory directory) {
        super.init(connection, directory);
        deviceService = directory.get(DeviceService.class);
        hostService = directory.get(HostService.class);
        linkService = directory.get(LinkService.class);
    }

    @Override
    protected Collection<RequestHandler> createRequestHandlers() {
        return ImmutableSet.of(new DisplayStartHandler(), new DisplayUpdateHandler(), new DisplayStopHandler(),
                new DevicePortHandler(), new PortFakeOpHandler());
    }

    // === -------------------------
    // === Handler classes

    private final class DisplayStartHandler extends RequestHandler {
        DisplayStartHandler() {
            super(UI_REF_TOPOV_DISPLAY_START);
        }

        @Override
        public void process(ObjectNode payload) {
            String mode = string(payload, MODE);

            log.debug("Start Display: mode [{}]", mode);
            clearState();
            clearForMode();

            switch (mode) {
            case "mouse":
                currentMode = Mode.MOUSE;
                cancelTask();
                sendMouseData();
                break;

            case "link":
                currentMode = Mode.LINK;
                scheduleTask();
                initLinkSet();
                sendLinkData();
                break;

            default:
                currentMode = Mode.IDLE;
                cancelTask();
                break;
            }
        }
    }

    private final class DisplayUpdateHandler extends RequestHandler {
        DisplayUpdateHandler() {
            super(UI_REF_TOPOV_DISPLAY_UPDATE);
        }

        @Override
        public void process(ObjectNode payload) {
            String id = string(payload, ID);
            log.debug("Update Display: id [{}]", id);
            if (!Strings.isNullOrEmpty(id)) {
                updateForMode(id);
            } else {
                clearForMode();
            }
        }
    }

    private final class DisplayStopHandler extends RequestHandler {
        DisplayStopHandler() {
            super(UI_REF_TOPOV_DISPLAY_STOP);
        }

        @Override
        public void process(ObjectNode payload) {
            log.debug("Stop Display");
            cancelTask();
            clearState();
            clearForMode();
        }
    }

    private final class DevicePortHandler extends RequestHandler {
        DevicePortHandler() {
            super(UI_REF_TOPOV_DEV_PORTS_REQ);
        }

        @Override
        public void process(ObjectNode payload) {
            String id = string(payload, ID);
            log.debug("Request ports for device [{}]", id);
            sendPortDataForDevice(id);
        }
    }

    private final class PortFakeOpHandler extends RequestHandler {
        PortFakeOpHandler() {
            super(UI_REF_TOPOV_DEV_PORTS_OP);
        }

        @Override
        public void process(ObjectNode payload) {
            String device = string(payload, DEVICE);
            String port = string(payload, PORT);

            // TODO: re-instate boolean results once onos-app-samples -> onos dep. fixed
            //            boolean foo = bool(payload, FOO);
            //            boolean bar = bool(payload, BAR);

            // NOTE: we won't go any further with this example, but obviously
            //       we could initiate some action on the device and port
            //       selected by the user from the Topology view in the Web UI.
            log.info("FAKE-op request device {} port {}", device, port);
            //            log.info("    options FOO={}, BAR={}", foo, bar);
        }
    }

    // === ------------

    private void sendPortDataForDevice(String id) {
        try {
            DeviceId did = DeviceId.deviceId(id);
            List<Port> ports = deviceService.getPorts(did);
            log.debug("Sending port data for device {} (#ports: {})", did, ports.size());
            ArrayNode portArray = arrayNode();
            for (Port p : ports) {
                // don't bother to send logical ports
                if (p.number().isLogical()) {
                    continue;
                }
                // NOTE: we could just add the port numbers (as longs) to the
                //       array and have done, but let's demonstrate how we
                //       might build more complex record types...
                portArray.add(portData(p));
            }

            ObjectNode payload = objectNode();
            payload.set(PORTS, portArray);
            payload.put(ID, id);
            sendMessage(JsonUtils.envelope(UI_REF_TOPOV_DEV_PORTS_RESP, payload));

        } catch (Exception e) {
            log.warn("[port data] Unable to process ID [{}]", id);
        }
    }

    private ObjectNode portData(Port p) {
        ObjectNode node = objectNode();
        node.put(ID, p.number().toLong());
        node.put(SPEED, p.portSpeed());
        node.put(TYPE, p.type().name());
        return node;
    }

    private void clearState() {
        currentMode = Mode.IDLE;
        elementOfNote = null;
        linkSet = EMPTY_LINK_SET;
    }

    private void updateForMode(String id) {
        log.debug("host service: {}", hostService);
        log.debug("device service: {}", deviceService);

        try {
            HostId hid = HostId.hostId(id);
            log.debug("host id {}", hid);
            elementOfNote = hostService.getHost(hid);
            log.debug("host element {}", elementOfNote);

        } catch (Exception e) {
            try {
                DeviceId did = DeviceId.deviceId(id);
                log.debug("device id {}", did);
                elementOfNote = deviceService.getDevice(did);
                log.debug("device element {}", elementOfNote);

            } catch (Exception e2) {
                log.warn("Unable to process ID [{}]", id);
                elementOfNote = null;
            }
        }

        switch (currentMode) {
        case MOUSE:
            sendMouseData();
            break;

        case LINK:
            sendLinkData();
            break;

        default:
            break;
        }

    }

    private void clearForMode() {
        sendHighlights(new Highlights());
    }

    private void sendHighlights(Highlights highlights) {
        sendMessage(TopoJson.highlightsMessage(highlights));
    }

    private void sendMouseData() {
        if (elementOfNote != null && elementOfNote instanceof Device) {
            DeviceId devId = (DeviceId) elementOfNote.id();
            Set<Link> links = linkService.getDeviceEgressLinks(devId);
            Highlights highlights = fromLinks(links, devId);
            addDeviceBadge(highlights, devId, links.size());
            sendHighlights(highlights);
        }
        // Note: could also process Host, if available
    }

    private void addDeviceBadge(Highlights h, DeviceId devId, int n) {
        DeviceHighlight dh = new DeviceHighlight(devId.toString());
        dh.setBadge(createBadge(n));
        h.add(dh);
    }

    private NodeBadge createBadge(int n) {
        NodeBadge.Status status = n > 3 ? NodeBadge.Status.ERROR : NodeBadge.Status.WARN;
        String noun = n > 3 ? "(critical)" : "(problematic)";
        String msg = "Egress links: " + n + " " + noun;
        return NodeBadge.number(status, n, msg);
    }

    private Highlights fromLinks(Set<Link> links, DeviceId devId) {
        DemoLinkMap linkMap = new DemoLinkMap();
        if (links != null) {
            log.debug("Processing {} links", links.size());
            links.forEach(linkMap::add);
        } else {
            log.debug("No egress links found for device {}", devId);
        }

        Highlights highlights = new Highlights();

        for (DemoLink dlink : linkMap.biLinks()) {
            dlink.makeImportant().setLabel("Yo!");
            highlights.add(dlink.highlight(null));
        }
        return highlights;
    }

    private void initLinkSet() {
        Set<Link> links = new HashSet<>();
        for (Link link : linkService.getActiveLinks()) {
            links.add(link);
        }
        linkSet = links.toArray(new Link[links.size()]);
        linkIndex = 0;
        log.debug("initialized link set to {}", linkSet.length);
    }

    private void sendLinkData() {
        DemoLinkMap linkMap = new DemoLinkMap();
        for (Link link : linkSet) {
            linkMap.add(link);
        }
        DemoLink dl = linkMap.add(linkSet[linkIndex]);
        dl.makeImportant().setLabel(Integer.toString(linkIndex));
        log.debug("sending link data (index {})", linkIndex);

        linkIndex += 1;
        if (linkIndex >= linkSet.length) {
            linkIndex = 0;
        }

        Highlights highlights = new Highlights();
        for (DemoLink dlink : linkMap.biLinks()) {
            highlights.add(dlink.highlight(null));
        }

        sendHighlights(highlights);
    }

    private synchronized void scheduleTask() {
        if (demoTask == null) {
            log.debug("Starting up demo task...");
            demoTask = new DisplayUpdateTask();
            timer.schedule(demoTask, UPDATE_PERIOD_MS, UPDATE_PERIOD_MS);
        } else {
            log.debug("(demo task already running");
        }
    }

    private synchronized void cancelTask() {
        if (demoTask != null) {
            demoTask.cancel();
            demoTask = null;
        }
    }

    private class DisplayUpdateTask extends TimerTask {
        @Override
        public void run() {
            try {
                switch (currentMode) {
                case LINK:
                    sendLinkData();
                    break;

                default:
                    break;
                }
            } catch (Exception e) {
                log.warn("Unable to process demo task: {}", e.getMessage());
                log.debug("Oops", e);
            }
        }
    }
}