Package lcmc.drbd.ui

Source Code of lcmc.drbd.ui.DrbdGraph

/*
* This file is part of DRBD Management Console by LINBIT HA-Solutions GmbH
* written by Rasto Levrinc.
*
* Copyright (C) 2009, LINBIT HA-Solutions GmbH.
* Copyright (C) 2011-2012, Rastislav Levrinc.
*
* DRBD Management Console is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* DRBD Management Console is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with drbd; see the file COPYING.  If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package lcmc.drbd.ui;

import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.visualization.util.VertexShapeFactory;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.swing.ImageIcon;
import javax.swing.JPopupMenu;

import lcmc.common.ui.GUIData;
import lcmc.common.ui.ResourceGraph;
import lcmc.drbd.ui.resource.BlockDevInfo;
import lcmc.drbd.ui.resource.HostDrbdInfo;
import lcmc.drbd.ui.resource.MultiSelectionInfo;
import lcmc.drbd.ui.resource.VolumeInfo;
import lcmc.common.domain.Application;
import lcmc.common.domain.ColorText;
import lcmc.cluster.ui.ClusterBrowser;
import lcmc.host.ui.HostBrowser;
import lcmc.host.domain.Host;
import lcmc.drbd.domain.BlockDevice;
import lcmc.common.ui.Info;
import lcmc.common.domain.util.Tools;

/**
* This class creates graph and provides methods to add new block device
* vertices and drbd volume edges, remove or modify them.
*/
@Named
public class DrbdGraph extends ResourceGraph {
    /** Horizontal step in pixels by which the block devices are drawn in the graph. */
    private static final int BD_STEP_Y = 60;
    /** Y position of the host. */
    private static final int HOST_Y_POS = 40;
    /** Vertical step in pixels by which the hosts are drawn in the graph. */
    private static final int HOST_STEP_X = 280;
    private static final int VERTEX_SIZE_BD = 200;
    private static final int VERTEX_SIZE_HOST = 150;
    private static final int HOST_VERTEX_HEIGHT = 50;
    /** Height of the block device vertices. */
    private static final int VERTEX_HEIGHT = 50;

    /** Maximum length of the label in the vertex, after which the string will be cut. */
    private static final int MAX_VERTEX_STRING_LENGTH = 18;
    /** Postion offset of block devices from the host x position. */
    private static final int BD_X_OFFSET = 15;
    /** Minimum vertical position. */
    private static final int MIN_Y_POS = 20;
    /** Maximum horizontal position. */
    private static final int MAX_X_POS = 2600;
    /** Maximum vertical position. */
    private static final int MAX_Y_POS = 2600;
    /** Map from vertex to host. */
    private final Map<Vertex, HostDrbdInfo> vertexToHostMap = new LinkedHashMap<Vertex, HostDrbdInfo>();
    /** Map from host to vertex. */
    private final Map<HostDrbdInfo, Vertex> hostToVertexMap = new LinkedHashMap<HostDrbdInfo, Vertex>();
    /** Map from block device info object to vertex. */
    private final Map<BlockDevInfo, Vertex> bdiToVertexMap = new LinkedHashMap<BlockDevInfo, Vertex>();
    /** Map from block device to vertex. */
    private final Map<BlockDevice, Vertex> blockDeviceToVertexMap = new LinkedHashMap<BlockDevice, Vertex>();
    /** Map from host to the list of block devices. */
    private final Map<HostDrbdInfo, List<Vertex>> hostBDVerticesMap = new LinkedHashMap<HostDrbdInfo, List<Vertex>>();
    /** Map from graph edge to the drbd volume info object. */
    private final Map<Edge, VolumeInfo> edgeToDrbdVolumeMap = new LinkedHashMap<Edge, VolumeInfo>();
    /** Map from drbd volume info object to the graph edge. */
    private final Map<VolumeInfo, Edge> drbdVolumeToEdgeMap = new LinkedHashMap<VolumeInfo, Edge>();

    @Inject
    private MultiSelectionInfo multiSelectionInfo = null;

    /** The first X position of the host. */
    private int hostDefaultXPos = 10;
    @Inject
    private GUIData guiData;
    @Inject
    private Application application;

    @Override
    public void initGraph(final ClusterBrowser clusterBrowser) {
        super.initGraph(clusterBrowser);
        super.initGraph(new DirectedSparseGraph<Vertex, Edge>());
    }

    private boolean isVertexBlockDevice(final Vertex v) {
        return vertexToHostMap.get(v) != getInfo(v);
    }

    /** Adds host with all its block devices to the graph. If it is there
     * already fix the positions of the block devices. */
    public void addHost(final HostDrbdInfo hostDrbdInfo) {
        Vertex v = getVertex(hostDrbdInfo);
        if (v == null) {
            /* add host vertex */
            v = new Vertex();
            somethingChanged();
            putInfoToVertex(hostDrbdInfo, v);
            vertexToHostMap.put(v, hostDrbdInfo);
            hostToVertexMap.put(hostDrbdInfo, v);
            putVertexToInfo(v, hostDrbdInfo);
            Point2D hostPos = getSavedPosition(hostDrbdInfo);

            if (hostPos == null) {
                hostPos = new Point2D.Double(hostDefaultXPos + VERTEX_SIZE_HOST / 2, HOST_Y_POS);
                hostDefaultXPos += HOST_STEP_X;
            }
            getVertexLocations().put(v, hostPos);
            putVertexLocations();
            lockGraph();
            getGraph().addVertex(v);
            unlockGraph();
        }
        /* add block devices vertices */
        final Host host = hostDrbdInfo.getHost();
        final Point2D hostPos = getVertexLocations().get(v);
        putVertexLocations();
        final double hostXPos = hostPos.getX() - VERTEX_SIZE_HOST / 2;
        final double hostYPos = hostPos.getY();
        int devYPos = (int) hostYPos + BD_STEP_Y;
        List<Vertex> vertexList = hostBDVerticesMap.get(hostDrbdInfo);
        List<Vertex> oldVertexList = null;
        if (vertexList == null) {
            vertexList = new ArrayList<Vertex>();
            hostBDVerticesMap.put(hostDrbdInfo, vertexList);
        } else {
            oldVertexList = new ArrayList<Vertex>(vertexList);
        }
        final Set<BlockDevInfo> blockDevInfos = host.getBrowser().getSortedBlockDevInfos();
        if (oldVertexList != null) {
            for (final Vertex vertex : oldVertexList) {
                final BlockDevInfo bdi = (BlockDevInfo) getInfo(vertex);
                if (bdi == null) {
                    continue;
                }
                if (!blockDevInfos.contains(bdi)) {
                    /* removing */
                    final Vertex bdv = bdiToVertexMap.get(bdi);
                    final VolumeInfo dvi = bdi.getDrbdVolumeInfo();
                    if (dvi != null) {
                        removeDrbdVolume(dvi);
                        dvi.getDrbdResourceInfo().removeDrbdVolumeFromHashes(dvi);
                    }
                    application.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            lockGraph();
                            getGraph().removeVertex(bdv);
                            unlockGraph();
                        }
                    });
                    removeInfo(bdv);
                    removeVertex(bdi);
                    getVertexToMenus().remove(bdv);
                    bdiToVertexMap.remove(bdi);
                    blockDeviceToVertexMap.remove(bdi.getBlockDevice());
                    vertexToHostMap.remove(bdv);
                    vertexList.remove(bdv);
                    somethingChanged();
                }
            }
        }
        BlockDevInfo prevBdi = null;
        for (final BlockDevInfo bdi : blockDevInfos) {
            stopAnimation(bdi);
            Vertex bdv = null;
            if (!blockDeviceToVertexMap.containsKey(bdi.getBlockDevice())) {
                bdv = new Vertex();
                somethingChanged();
                bdiToVertexMap.put(bdi, bdv);
                blockDeviceToVertexMap.put(bdi.getBlockDevice(), bdv);
                putVertexToInfo(bdv, bdi);
                putInfoToVertex(bdi, bdv);
                vertexToHostMap.put(bdv, hostDrbdInfo);
                vertexList.add(bdv);
                // TODO: get saved position is disabled at the moment,
                // because it does more harm than good at the moment.
            }
            if (bdv == null) {
                bdv = blockDeviceToVertexMap.get(bdi.getBlockDevice());
            }
            if (prevBdi != null
                && bdi.getBlockDevice().isVolumeGroupOnPhysicalVolume()
                && bdi.getBlockDevice().getVgOnPhysicalVolume().equals(
                                               prevBdi.getBlockDevice().getVgOnPhysicalVolume())) {
                devYPos -= 8;
            } else if (prevBdi != null
                && (!bdi.getBlockDevice().isDrbd() || !prevBdi.getBlockDevice().isDrbd())) {
                devYPos -= 4;
            } else if (prevBdi != null
                      && bdi.getBlockDevice().isDrbd()
                      && prevBdi.getBlockDevice().isDrbd()
                      && bdi.getDrbdVolumeInfo().getDrbdResourceInfo()
                         == prevBdi.getDrbdVolumeInfo().getDrbdResourceInfo()) {
                devYPos -= 6;
            }
            final Point2D pos = new Point2D.Double(hostXPos + BD_X_OFFSET + VERTEX_SIZE_BD / 2, devYPos);
            devYPos += BD_STEP_Y;
            getVertexLocations().put(bdv, pos);
            putVertexLocations();
            getLayout().setLocation(bdv, pos);
            if (bdv != null) {
                lockGraph();
                getGraph().addVertex(bdv);
                unlockGraph();
            }
            prevBdi = bdi;
        }
    }

    /** Scale and add hosts if they appeared. */
    @Override
    public void scale() {
        for (final HostDrbdInfo hostDrbdInfo : hostBDVerticesMap.keySet()) {
            addHost(hostDrbdInfo);
        }
        super.scale();
    }

    /** Removes drbd volume from the graph. */
    public void removeDrbdVolume(final VolumeInfo dvi) {
        final Edge e = drbdVolumeToEdgeMap.get(dvi);
        if (e == null) {
            return;
        }
        e.reset();
        edgeToDrbdVolumeMap.remove(e);
        drbdVolumeToEdgeMap.remove(dvi);
        try {
            lockGraph();
            getGraph().removeEdge(e);
            unlockGraph();
        } catch (final Exception ignore) {
            unlockGraph();
            /* ignore */
        }
    }

    /**
     * Returns an icon for vertex, depending on if it is host or block device,
     * if it is started or stopped and so on.
     */
    @Override
    protected List<ImageIcon> getIconsForVertex(final Vertex v, final Application.RunMode runMode) {
        final List<ImageIcon> icons = new ArrayList<ImageIcon>();
        if (isVertexBlockDevice(v)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi == null) {
                return icons;
            }
            if (bdi.getBlockDevice().isDrbd()) {
                icons.add(BlockDevInfo.HARDDISK_DRBD_ICON_LARGE);
            } else {
                icons.add(BlockDevInfo.HARDDISK_ICON_LARGE);
            }
            if (bdi.isDiskless(runMode)) {
                icons.add(BlockDevInfo.NO_HARDDISK_ICON_LARGE);
                return icons;
            } else {
                return icons;
            }
        } else {
            final HostDrbdInfo hi = vertexToHostMap.get(v);
            if (hi == null) {
                return null;
            }
            if (hi.getHost().isDrbdStatusOk() && hi.getHost().isDrbdLoaded()) {
                icons.add(HostBrowser.HOST_ON_ICON_LARGE);
            } else {
                icons.add(HostBrowser.HOST_ICON_LARGE);
            }
            return icons;
        }
    }

    /**
     * Returns label for drbd volume edge. If it is longer than 10
     * characters, it is shortened.
     */
    @Override
    protected String getLabelForEdgeStringer(final Edge edge) {
        final VolumeInfo dvi = edgeToDrbdVolumeMap.get(edge);
        if (dvi != null
            && dvi.getName() != null
            && dvi.getDrbdResourceInfo() != null) {
            final Vertex source = edge.getSource();
            final Vertex dest = edge.getDest();
            final BlockDevInfo sourceBDI = (BlockDevInfo) getInfo(source);
            if (sourceBDI == null) {
                return "";
            }
            final BlockDevInfo destBDI = (BlockDevInfo) getInfo(dest);
            if (destBDI == null) {
                return "";
            }
            final BlockDevice sourceBD = sourceBDI.getBlockDevice();
            final BlockDevice destBD = destBDI.getBlockDevice();
            final Application.RunMode runMode = getRunMode();
            if (!destBDI.isConnected(runMode)) {
                if (sourceBDI.isWFConnection(runMode)
                    && !destBDI.isWFConnection(runMode)) {
                    edge.setDirection(dest, source);
                    application.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            repaint();
                        }
                    });

                }
            } else if (!sourceBD.isPrimary() && destBD.isPrimary()) {
                edge.setDirection(dest, source);
                application.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        repaint();
                    }
                });
            }
            final StringBuilder l = new StringBuilder(dvi.getNameForGraph());
            final Map<Vertex, Point2D> vl = getVertexLocations();
            final Point2D sp = vl.get(source);
            final Point2D dp = vl.get(dest);
            putVertexLocations();
            final int len = (int) Math.sqrt(Math.pow(sp.getX() - dp.getX(), 2) + Math.pow(sp.getY() - dp.getY(), 2));
            final int maxLen = (len - 200) / 7;
            if (l.length() > maxLen) {
                l.delete(0, l.length() - maxLen + 3);
                l.insert(0, "...");
            }
            if (dvi.isSyncing()) {
                String syncedProgress = dvi.getSyncedProgress();
                if (syncedProgress == null) {
                    syncedProgress = "?.?";
                }
                final double sourceX = getLayout().transform(source).getX();
                final double destX = getLayout().transform(dest).getX();
                if (sourceBD.isPausedSync() || destBD.isPausedSync()) {
                    l.append(" (").append(syncedProgress).append("% paused)");
                } else if (sourceBD.isSyncSource() && sourceX < destX
                           || destBD.isSyncSource() && sourceX > destX) {
                    l.append(" (").append(syncedProgress).append("% \u2192)"); /* -> */
                } else {
                    l.append(" (\u2190 ").append(syncedProgress).append("%)"); /* <- */
                }
            } else if (dvi.isSplitBrain()) {
                l.append(" (split-brain)");
            } else if (!dvi.isConnected(runMode)) {
                l.append(" (disconnected)");
            } else if (dvi.isVerifying()) {
                l.append(" (verify)");
            }
            return l.toString();
        }
        return null;
    }

    /** Small text that appears above the icon. */
    @Override
    protected String getIconText(final Vertex v, final Application.RunMode runMode) {
        if (isVertexBlockDevice(v)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi != null) {
                return bdi.getIconTextForGraph(runMode);
            }
        } else {
            final HostDrbdInfo hi = vertexToHostMap.get(v);
            if (hi != null) {
                return hi.getIconTextForDrbdGraph(runMode);
            }
        }
        return null;
    }

    /** Small text that appears in the right corner. */
    @Override
    protected ColorText getRightCornerText(final Vertex v, final Application.RunMode runMode) {
        if (isVertexBlockDevice(v)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi != null) {
                return bdi.getRightCornerTextForDrbdGraph(runMode);

            }
        } else {
            final HostDrbdInfo hi = vertexToHostMap.get(v);
            if (hi != null) {
                return hi.getRightCornerTextForDrbdGraph(runMode);
            }
        }
        return null;
    }

    /** Small text that appears down. */
    @Override
    protected ColorText[] getSubtexts(final Vertex v, final Application.RunMode runMode) {
        if (isVertexBlockDevice(v)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi != null && bdi.getBlockDevice().isDrbd()
                && bdi.getBlockDevice().getConnectionState() != null
                && bdi.getBlockDevice().getDiskState() != null) {
                final String connState = bdi.getBlockDevice().getConnectionState();
                final String diskState = bdi.getBlockDevice().getDiskState();
                String diskStateOther = null;
                final BlockDevInfo oBdi = bdi.getOtherBlockDevInfo();
                if (oBdi != null
                    && !diskState.equals(oBdi.getBlockDevice().getDiskStateOther())) {
                    diskStateOther = oBdi.getBlockDevice().getDiskStateOther();
                }

                Color color = null;
                Color textColor = Color.BLACK;
                final String proxyState = bdi.getProxyStateForGraph(runMode);
                if ("StandAlone".equals(connState)
                    || !"UpToDate".equals(diskState)
                    || (proxyState != null && !BlockDevInfo.PROXY_UP.equals(proxyState))) {
                    color = Color.RED;
                    textColor = Color.WHITE;
                }
                return new ColorText[]{
                    new ColorText(Tools.join(" / ", new String[]{connState, diskState, diskStateOther, proxyState}),
                                color,
                                textColor)};
            }
        } else {
            final HostDrbdInfo hi = vertexToHostMap.get(v);
            if (hi != null) {
                return hi.getSubtextsForDrbdGraph(runMode);
            }
        }
        return null;
    }

    /**
     * Returns label for block device vertex. If it is longer than 23
     * characters, it is shortened.
     */
    @Override
    public String getMainText(final Vertex v, final Application.RunMode runMode) {
        if (isVertexBlockDevice(v)) {
            String l;
            if (isVertexDrbd(v)) {
                final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
                if (bdi == null) {
                    return "";
                }
                l = bdi.getDrbdVolumeInfo().getDevice();
            } else {
                final Info info = getInfo(v);
                if (info == null) {
                    return "";
                }
                l = info.getMainTextForGraph();
            }
            if (l.length() > MAX_VERTEX_STRING_LENGTH) {
                l = "..." + l.substring(l.length() - MAX_VERTEX_STRING_LENGTH + 3, l.length());
            }
            return l;
        } else if (vertexToHostMap.containsKey(v)) {
            return vertexToHostMap.get(v).toString();
        } else {
            return "";
        }
    }

    /** Returns shape of the block device vertex. */
    @Override
    protected Shape getVertexShape(final Vertex v, final VertexShapeFactory<Vertex> factory) {
        return factory.getRectangle(v);
    }

    /** Handles popup in when block device vertex is clicked. */
    @Override
    protected void handlePopupVertex(final Vertex v, final List<Vertex> pickedV, final Point2D pos) {
        final Info info;
        if (pickedV.size() > 1) {
            info = multiSelectionInfo;
        } else if (isVertexBlockDevice(v)) {
            info = getInfo(v);
        } else {
            /* host */
            info = getInfo(v);
        }
        if (info != null) {
            final JPopupMenu p = info.getPopup();
            info.updateMenus(pos);
            showPopup(p, pos);
        }
    }

    /** Adds drbd volume edge to the graph. */
    public void addDrbdVolume(final VolumeInfo dvi, final BlockDevInfo bdi1, final BlockDevInfo bdi2) {
        if (bdi1 != null && bdi2 != null) {
            final Vertex v1 = bdiToVertexMap.get(bdi1);
            final Vertex v2 = bdiToVertexMap.get(bdi2);
            lockGraph();
            if (getGraph().findEdge(v1, v2) != null
                || getGraph().findEdge(v2, v1) != null) {
                unlockGraph();
                return;
            }
            final Edge e = new Edge(v1, v2);
            getGraph().addEdge(e, v1, v2);
            unlockGraph();
            edgeToDrbdVolumeMap.put(e, dvi);
            drbdVolumeToEdgeMap.put(dvi, e);
        }
    }

    /** Returns the source block device in a drbd connection. */
    public BlockDevInfo getSource(final VolumeInfo dvi) {
        final Edge edge = drbdVolumeToEdgeMap.get(dvi);
        if (edge == null) {
            return null;
        }
        final Vertex source = edge.getSource();
        return (BlockDevInfo) getInfo(source);
    }

    /** Returns the destination block device in a drbd connection. */
    public BlockDevInfo getDest(final VolumeInfo dvi) {
        final Edge edge = drbdVolumeToEdgeMap.get(dvi);
        if (edge == null) {
            return null;
        }
        final Vertex dest = edge.getDest();
        return (BlockDevInfo) getInfo(dest);
    }

    /** Picks vertex, that is associated with the specified info object. */
    @Override
    public void pickInfo(final Info i) {
        final Edge e = drbdVolumeToEdgeMap.get(i);
        if (e == null) {
            super.pickInfo(i);
        } else {
            pickEdge(e);
        }
    }

    /** Is called after right click on the resource edge. */
    @Override
    protected void handlePopupEdge(final Edge edge, final Point2D pos) {
        final VolumeInfo info = edgeToDrbdVolumeMap.get(edge);
        final JPopupMenu p = info.getPopup();
        info.updateMenus(pos);
        showPopup(p, pos);
    }

    /**
     * Is called after right click on the background and it returns
     * background popup menu.
     */
    @Override
    protected void handlePopupBackground(final Point2D pos) {
        final JPopupMenu p = getClusterBrowser().getGlobalInfo().getPopup();
        getClusterBrowser().getGlobalInfo().updateMenus(pos);
        showPopup(p, pos);
    }

    /**
     * Picks vertex representig specified block device info object in the
     * graph.
     */
    public void pickBlockDevice(final BlockDevInfo bdi) {
        final Vertex v = bdiToVertexMap.get(bdi);
        pickVertex(v);
    }

    /** Is called of a host is picked. Its terminal panel is set to view. */
    private void pickHost(final Vertex v) {
        pickVertex(v);
        final HostDrbdInfo hi = vertexToHostMap.get(v);
        if (hi == null) {
            return;
        }
        guiData.setTerminalPanel(hi.getHost().getTerminalPanel());
    }

    /** Is called when one block device vertex was pressed. */
    @Override
    protected void oneVertexPressed(final Vertex v) {
        if (isVertexBlockDevice(v)) {
            pickHost(v);
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi == null) {
                return;
            }
            getClusterBrowser().getGlobalInfo().setSelectedNode(bdi);
            getClusterBrowser().getGlobalInfo().selectMyself();
            getClusterBrowser().setRightComponentInView(bdi);
        } else {
            pickHost(v);
            final HostDrbdInfo hi = vertexToHostMap.get(v);
            if (hi == null) {
                return;
            }
            getClusterBrowser().setRightComponentInView(hi);
        }
    }

    /** Is called when block device vertex is released. */
    @Override
    protected void vertexReleased(final Vertex v, final Point2D pos) {
        double x = pos.getX();
        double y = pos.getY();
        final double minPos = (getVertexWidth(v) - getDefaultVertexWidth(v)) / 2;
        x = x < minPos ? minPos : x;
        x = x > MAX_X_POS ? MAX_X_POS : x;
        y = y < MIN_Y_POS ? MIN_Y_POS : y;
        y = y > MAX_Y_POS ? MAX_Y_POS : y;
        pos.setLocation(x + (getDefaultVertexWidth(v) - getVertexWidth(v)) / 2, y);
        final Point2D loc = new Point2D.Double(x, y);
        getVertexLocations().put(v, pos);
        putVertexLocations();
        getLayout().setLocation(v, loc);
    }

    /**
     * Returns whether block device belonging to this vertex is available for
     * drbd or not. Returns false if this is not a block device.
     */
    private boolean isVertexAvailable(final Vertex v) {
        final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
        if (bdi != null) {
            return bdi.getBlockDevice().isAvailable();
        }
        return false;
    }

    /**
     * Returns true if block device represented by specified vertex is
     * drbd device.
     */
    private boolean isVertexDrbd(final Vertex v) {
        final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
        if (bdi != null) {
            return bdi.getBlockDevice().isDrbd();
        }
        return false;
    }

    /**
     * Returns true if block device represented by specified vertex is
     * primary.
     */
    private boolean isVertexPrimary(final Vertex v) {
        final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
        if (bdi != null) {
            return bdi.getBlockDevice().isPrimary();
        }
        return false;
    }

    /**
     * Returns true if block device represented by specified vertex is
     * secondary.
     */
    private boolean isVertexSecondary(final Vertex v) {
        final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
        if (bdi != null) {
            return bdi.getBlockDevice().isSecondary();
        }
        return false;
    }

    /**
     * Is called when resource edge is pressed. It selects the asspociated
     * resource.
     */
    @Override
    protected void oneEdgePressed(final Edge e) {
        final VolumeInfo dvi = edgeToDrbdVolumeMap.get(e);
        if (dvi != null) {
            dvi.selectMyself();
        }
    }

    /**
     * Is called, when background of the graph is clicked. It deselects
     * selected node.
     */
    @Override
    protected void backgroundClicked() {
        getClusterBrowser().getGlobalInfo().setSelectedNode(null);
        getClusterBrowser().getGlobalInfo().selectMyself();
    }

    /**
     * Returns fill color as paint object for for specified block device
     * vertex.
     */
    @Override
    protected Color getVertexFillColor(final Vertex v) {
        final HostDrbdInfo hi = vertexToHostMap.get(v);
        final Vertex hostVertex = getVertex(hi);
        if (v.equals(hostVertex)) {
            return hi.getHost().getDrbdColors()[0];
        } else if (hi != null &&
                   (hi.getHost() == null || (!hi.getHost().isDrbdStatusOk() && hi.getHost().isDrbdLoaded()))) {
            return Tools.getDefaultColor("DrbdGraph.FillPaintUnknown");
        } else {
            if (!isVertexDrbd(v)) {
                if (isVertexAvailable(v)) {
                    return super.getVertexFillColor(v);
                } else {
                    return Tools.getDefaultColor("DrbdGraph.FillPaintNotAvailable");
                }
            }
            if (isVertexPrimary(v)) {
                return Tools.getDefaultColor("DrbdGraph.FillPaintPrimary");
            } else if (isVertexSecondary(v)) {
                return Tools.getDefaultColor("DrbdGraph.FillPaintSecondary");
            } else {
                return Tools.getDefaultColor("DrbdGraph.FillPaintUnknown");
            }
        }
    }

    /**
     * Returns secondary gradient fill paint color for vertex v. If it is
     * a volume and there is previous volume don't show gradient.
     */
    @Override
    protected Color getVertexFillSecondaryColor(final Vertex v) {
        if (!isVertexBlockDevice(v)) {
            return Color.WHITE;
        }
        final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
        if (bdi == null) {
            return Color.WHITE;
        }
        if (bdi.isFirstDrbdVolume()) {
            return Color.WHITE;
        } else {
            return getVertexFillColor(v);
        }
    }

    /**
     * Finds BlockDevice object on the specified host for block device
     * represented as a string and returns it.
     */
    BlockDevice findBlockDevice(final String hostName, final String disk) {
        final BlockDevInfo bdi = findBlockDevInfo(hostName, disk);
        if (bdi == null) {
            return null;
        }
        return bdi.getBlockDevice();
    }

    /**
     * Finds BlockDevInfo object on the specified host for block device
     * represented as a string and returns it.
     * TODO: move it to BlockDevInfo
     */
    public BlockDevInfo findBlockDevInfo(final String hostName,
                                         final String disk) {
        HostDrbdInfo hi = null;
        for (final HostDrbdInfo h : hostBDVerticesMap.keySet()) {
            hi = h;
            if (hi.toString().equals(hostName)) {
                break;
            }
        }
        if (hi == null) {
            return null;
        }
        for (final Vertex v : hostBDVerticesMap.get(hi)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi == null) {
                continue;
            }
            if (disk.equals(bdi.getName())
                || disk.equals(bdi.getBlockDevice().getDiskUuid())
                || bdi.getBlockDevice().getDiskIds().contains(disk)) {
                return bdi;
            }
        }
        return null;
    }

    /** Returns tool tip when mouse is over a block device vertex. */
    @Override
    public String getVertexToolTip(final Vertex v) {
        final Info i = getInfo(v);
        if (i == null) {
            return null;
        }
        return i.getToolTipForGraph(getRunMode());
    }

    /** Returns tool tip when mouse is over a resource edge. */
    @Override
    public String getEdgeToolTip(final Edge edge) {
        final VolumeInfo dvi = edgeToDrbdVolumeMap.get(edge);
        return dvi.getToolTipForGraph(getRunMode());
    }

    /**
     * Returns whether arrow shoud be shown. It is shown on the edge from
     * primary to secondory, or from connected node to the disconnected or
     * none at all.
     */
    @Override
    protected boolean showEdgeArrow(final Edge edge) {
        final BlockDevInfo sourceBDI = (BlockDevInfo) getInfo(edge.getSource());
        final BlockDevInfo destBDI = (BlockDevInfo) getInfo(edge.getDest());
        if (sourceBDI == null || destBDI == null) {
            return false;
        }
        final BlockDevice sourceBD = sourceBDI.getBlockDevice();
        final BlockDevice destBD = destBDI.getBlockDevice();
        final Application.RunMode runMode = getRunMode();
        if (sourceBDI.isConnected(runMode)
            && sourceBD.isPrimary() != destBD.isPrimary()) {
            return true;
        } else if (sourceBDI.isWFConnection(runMode) ^ destBDI.isWFConnection(runMode)) {
            /* show arrow from wf connection */
            return true;
        }
        return false;
    }

    /**
     * Returns the color of the edge, depending on if the drbds are connected
     * and so on.
     */
    @Override
    protected Paint getEdgeDrawPaint(final Edge edge) {
        final VolumeInfo dvi = edgeToDrbdVolumeMap.get(edge);
        if (dvi != null
            && dvi.isConnected(getRunMode())
            && !dvi.isSplitBrain()) {
            return super.getEdgeDrawPaint(edge);
        } else {
            return Tools.getDefaultColor("DrbdGraph.EdgeDrawPaintDisconnected");
        }

    }

    /**
     * Returns paint for picked edge. It returns different colors if drbd is
     * disconnected.
     */
    @Override
    protected Paint getEdgePickedPaint(final Edge edge) {
        final VolumeInfo dvi = edgeToDrbdVolumeMap.get(edge);
        if (dvi != null && dvi.isConnected(getRunMode()) && !dvi.isSplitBrain()) {
            return super.getEdgePickedPaint(edge);
        } else {
            return Tools.getDefaultColor("DrbdGraph.EdgeDrawPaintDisconnectedBrighter");
        }
    }

    /** Returns id that is used for saving of the vertex positions to a file. */
    @Override
    protected String getId(final Info i) {
        final Vertex v = getVertex(i);
        String hiId = "";
        if (v != null) {
            final HostDrbdInfo hi = vertexToHostMap.get(v);
            if (hi != null) {
                hiId = hi.getId();
            }
        }
        return "dr=" + hiId + i.getId();
    }

    @Override
    protected int getDefaultVertexWidth(final Vertex v) {
        if (isVertexBlockDevice(v)) {
            return VERTEX_SIZE_BD;
        } else {
            return VERTEX_SIZE_HOST;
        }
    }

    @Override
    protected int getDefaultVertexHeight(final Vertex v) {
        if (isVertexBlockDevice(v)) {
            return VERTEX_HEIGHT;
        } else {
            return HOST_VERTEX_HEIGHT;
        }
    }


    /**
     * Returns how much of the disk is used.
     * -1 for not used or not applicable.
     */
    protected int getUsed(final Vertex v) {
        if (isVertexBlockDevice(v)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi == null) {
                return 0;
            }
            return bdi.getUsed();
        }
        final HostDrbdInfo hi = vertexToHostMap.get(v);
        if (hi == null) {
            return 0;
        } else {
            return hi.getUsed();
        }
    }

    /** This method draws how much of the vertex is used for something. */
    @Override
    protected void drawInside(final Vertex v,
                              final Graphics2D g2d,
                              final double x,
                              final double y,
                              final Shape shape) {
        final double used = getUsed(v);
        final float height = (float) shape.getBounds().getHeight();
        final float width = (float) shape.getBounds().getWidth();
        if (isVertexBlockDevice(v)) {
            final BlockDevInfo bdi = (BlockDevInfo) getInfo(v);
            if (bdi != null && bdi.getBlockDevice().isDrbdMetaDisk()) {
                final Color[] colors = {null, null};
                colors[1] = getVertexFillColor(blockDeviceToVertexMap.get(
                                                 bdi.getBlockDevice().getMetaDiskOfBlockDevices().get(0)));
                drawInsideVertex(g2d, v, colors, x, y, height, width);
            }
        } else {
            final HostDrbdInfo hi = (HostDrbdInfo) getInfo(v);
            if (hi != null) {
                drawInsideVertex(g2d, v, hi.getHost().getDrbdColors(), x, y, height, width);
            }
        }
        final Application.RunMode runMode = getRunMode();
        if (used > 0) {
            /** Show how much is used. */
            final double freeWidth = width * (100 - used) / 100;
            g2d.setColor(new Color(255, 255, 255, 220));
            g2d.fillRect((int) (x + width - freeWidth), (int) (y), (int) (freeWidth), (int) (height));
        }
        if (isPicked(v)) {
            if (Application.isTest(runMode)) {
                g2d.setColor(Color.RED);
            } else {
                g2d.setColor(Color.BLACK);
            }
        } else {
            boolean pickedResource = false;
            if (Application.isTest(runMode)) {
                lockGraph();
                for (final Edge e : getGraph().getInEdges(v)) {
                    if (isPicked(e)) {
                        pickedResource = true;
                        break;
                    }
                }
                if (!pickedResource) {
                    for (final Edge e : getGraph().getOutEdges(v)) {
                        if (isPicked(e)) {
                            pickedResource = true;
                            break;
                        }
                    }
                }
                unlockGraph();
            }
            if (pickedResource) {
                g2d.setColor(Color.RED);
            } else {
                g2d.setColor(Color.WHITE);
            }
        }
        g2d.setStroke(new BasicStroke(1.5f));
        g2d.draw(shape);
    }

    @Override
    protected boolean showHollowArrow(final Edge e) {
        final VolumeInfo dvi = edgeToDrbdVolumeMap.get(e);
        if (dvi == null) {
            return false;
        }
        return !dvi.isConnected(getRunMode());
    }

    /** Select multiple elements. */
    @Override
    protected void multiSelection() {
        final List<Info> selectedInfos = new ArrayList<Info>();
        for (final Vertex v : getPickedVertices()) {
            final Info i = getInfo(v);
            if (i != null) {
                selectedInfos.add(i);
            }
        }
        multiSelectionInfo.init(selectedInfos, getClusterBrowser());
        getClusterBrowser().setRightComponentInView(multiSelectionInfo);
    }

    public Map<VolumeInfo, Edge> getDrbdVolumeToEdgeMap() {
        return drbdVolumeToEdgeMap;
    }
}
TOP

Related Classes of lcmc.drbd.ui.DrbdGraph

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.