All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onosproject.ui.topo.TopoUtils Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
/*
 * 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.
 */

package org.onosproject.ui.topo;

import org.onosproject.net.Link;
import org.onosproject.net.LinkKey;

import java.text.DecimalFormat;

import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.net.LinkKey.linkKey;

/**
 * Utility methods for helping out with formatting data for the Topology View
 * in the web client.
 */
public final class TopoUtils {

    // explicit decision made to not 'javadoc' these constants
    public static final double N_KILO = 1024;
    public static final double N_MEGA = 1024 * N_KILO;
    public static final double N_GIGA = 1024 * N_MEGA;

    public static final String BITS_UNIT = "b";
    public static final String BYTES_UNIT = "B";
    public static final String PACKETS_UNIT = "p";

    private static final DecimalFormat DF2 = new DecimalFormat("#,###.##");

    private static final String COMPACT = "%s/%s-%s/%s";
    private static final String EMPTY = "";
    private static final String SPACE = " ";
    private static final String FLOW = "flow";
    private static final String FLOWS = "flows";

    // non-instantiable
    private TopoUtils() { }

    /**
     * Returns a compact identity for the given link, in the form
     * used to identify links in the Topology View on the client.
     *
     * @param link link
     * @return compact link identity
     */
    public static String compactLinkString(Link link) {
        return String.format(COMPACT, link.src().elementId(), link.src().port(),
                link.dst().elementId(), link.dst().port());
    }

    /**
     * Produces a canonical link key, that is, one that will match both a link
     * and its inverse.
     *
     * @param link the link
     * @return canonical key
     */
    public static LinkKey canonicalLinkKey(Link link) {
        String sn = link.src().elementId().toString();
        String dn = link.dst().elementId().toString();
        return sn.compareTo(dn) < 0 ?
                linkKey(link.src(), link.dst()) : linkKey(link.dst(), link.src());
    }

    /**
     * Returns a value representing a count of bytes.
     *
     * @param bytes number of bytes
     * @return value representing bytes
     */
    public static ValueLabel formatBytes(long bytes) {
        return new ValueLabel(bytes, BYTES_UNIT);
    }

    /**
     * Returns a value representing a count of packets per second.
     *
     * @param packets number of packets (per second)
     * @return value representing packets per second
     */
    public static ValueLabel formatPacketRate(long packets) {
        return new ValueLabel(packets, PACKETS_UNIT).perSec();
    }


    /**
     * Returns a value representing a count of bits per second,
     * (clipped to a maximum of 100 Gbps).
     * Note that the input is bytes per second.
     *
     * @param bytes bytes per second
     * @return value representing bits per second
     */
    public static ValueLabel formatClippedBitRate(long bytes) {
        return new ValueLabel(bytes * 8, BITS_UNIT).perSec().clipG(100.0);
    }

    /**
     * Returns human readable flow count, to be displayed as a label.
     *
     * @param flows number of flows
     * @return formatted flow count
     */
    public static String formatFlows(long flows) {
        if (flows < 1) {
            return EMPTY;
        }
        return String.valueOf(flows) + SPACE + (flows > 1 ? FLOWS : FLOW);
    }


    /**
     * Enumeration of magnitudes.
     */
    public enum Magnitude {
        ONE("", 1),
        KILO("K", N_KILO),
        MEGA("M", N_MEGA),
        GIGA("G", N_GIGA);

        private final String label;
        private final double mult;

        Magnitude(String label, double mult) {
            this.label = label;
            this.mult = mult;
        }

        @Override
        public String toString() {
            return label;
        }

        private double mult() {
            return mult;
        }
    }


    /**
     * Encapsulates a value to be used as a label.
     */
    public static class ValueLabel {
        private final long value;
        private final String unit;

        private double divDown;
        private Magnitude mag;

        private boolean perSec = false;
        private boolean clipped = false;

        /**
         * Creates a value label with the given base value and unit. For
         * example:
         * 
         * ValueLabel bits = new ValueLabel(2_050, "b");
         * ValueLabel bytesPs = new ValueLabel(3_000_000, "B").perSec();
         * 
* Generating labels: *
         *   bits.toString()     ...  "2.00 Kb"
         *   bytesPs.toString()  ...  "2.86 MBps"
         * 
* * @param value the base value * @param unit the value unit */ public ValueLabel(long value, String unit) { this.value = value; this.unit = unit; computeAdjusted(); } private void computeAdjusted() { if (value >= N_GIGA) { divDown = value / N_GIGA; mag = Magnitude.GIGA; } else if (value >= N_MEGA) { divDown = value / N_MEGA; mag = Magnitude.MEGA; } else if (value >= N_KILO) { divDown = value / N_KILO; mag = Magnitude.KILO; } else { divDown = value; mag = Magnitude.ONE; } } /** * Mark this value to be expressed as a rate. That is, "ps" (per sec) * will be appended in the string representation. * * @return self, for chaining */ public ValueLabel perSec() { perSec = true; return this; } /** * Clips the (adjusted) value to the given threshold expressed in * Giga units. That is, if the adjusted value exceeds the threshold, * it will be set to the threshold value and the clipped flag * will be set. For example, *
         * ValueLabel tooMuch = new ValueLabel(12_000_000_000, "b")
         *      .perSec().clipG(10.0);
         *
         * tooMuch.toString()    ...  "10.00 Gbps"
         * tooMuch.clipped()     ...  true
         * 
* * @param threshold the clip threshold (Giga) * @return self, for chaining */ public ValueLabel clipG(double threshold) { return clip(threshold, Magnitude.GIGA); } private ValueLabel clip(double threshold, Magnitude m) { checkArgument(threshold >= 1.0, "threshold must be 1.0 or more"); double clipAt = threshold * m.mult(); if (value > clipAt) { divDown = threshold; mag = m; clipped = true; } return this; } /** * Returns true if this value was clipped to a maximum threshold. * * @return true if value was clipped */ public boolean clipped() { return clipped; } /** * Returns the magnitude value. * * @return the magnitude */ public Magnitude magnitude() { return mag; } @Override public String toString() { return DF2.format(divDown) + SPACE + mag + unit + (perSec ? "ps" : ""); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy