Package lcmc.crm.ui

Source Code of lcmc.crm.ui.CrmGraph

/*
* This file is part of Linux Cluster Management Console
* written by Rasto Levrinc.
*
* Copyright (C) 2012, Rastislav Levrinc
*
* LCMC 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.crm.ui;

import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.picking.PickedState;
import edu.uci.ics.jung.visualization.util.VertexShapeFactory;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.swing.ImageIcon;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;

import lcmc.common.ui.GUIData;
import lcmc.common.ui.Info;
import lcmc.common.ui.ResourceGraph;
import lcmc.crm.ui.resource.ConstraintPHInfo;
import lcmc.crm.ui.resource.GroupInfo;
import lcmc.crm.ui.resource.HbConnectionInfo;
import lcmc.crm.ui.resource.HostInfo;
import lcmc.crm.ui.resource.PcmkMultiSelectionInfo;
import lcmc.crm.ui.resource.ServiceInfo;
import lcmc.common.domain.AccessMode;
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.common.ui.utils.MenuAction;
import lcmc.common.ui.utils.MenuFactory;
import lcmc.common.ui.utils.MyMenuItem;
import lcmc.common.domain.util.Tools;

/**
* This class creates graph and provides methods to add new nodes, edges,
* remove or modify them.
*/
@Named
public class CrmGraph extends ResourceGraph {
    /** X position of a new block device. */

    private static final int BD_X_POS = 15;
    /** 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 = 230;
    /** 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;

    private static final int VERTEX_HEIGHT = 50;
    private static final ImageIcon HOST_STANDBY_ICON =
                                            Tools.createImageIcon(Tools.getDefault("CRMGraph.HostStandbyIcon"));
    private static final ImageIcon SERVICE_RUNNING_ICON =
                                       Tools.createImageIcon(Tools.getDefault("CRMGraph.ServiceRunningIcon"));
    private static final ImageIcon SERVICE_RUNNING_FAILED_ICON =
                                        Tools.createImageIcon(Tools.getDefault("CRMGraph.ServiceRunningFailedIcon"));
    /** Icon that indicates a started service (but not running). */
    private static final ImageIcon SERVICE_STARTED_ICON = Tools.createImageIcon(
                                                                Tools.getDefault("CRMGraph.ServiceStartedIcon"));
    /** Icon that indicates a stopping service (but not stopped). */
    private static final ImageIcon SERVICE_STOPPING_ICON = Tools.createImageIcon(
                                                                Tools.getDefault("CRMGraph.ServiceStoppingIcon"));
    /** Icon that indicates a not running service. */
    private static final ImageIcon SERVICE_STOPPED_ICON = Tools.createImageIcon(
                                                                Tools.getDefault("CRMGraph.ServiceStoppedIcon"));
    /** Icon that indicates a not running service that failed. */
    private static final ImageIcon SERVICE_STOPPED_FAILED_ICON =
                                        Tools.createImageIcon(Tools.getDefault("CRMGraph.ServiceStoppedFailedIcon"));
    /** Icon that indicates an unmanaged service. */
    private static final ImageIcon SERVICE_UNMANAGED_ICON =
                                     Tools.createImageIcon(Tools.getDefault("CRMGraph.ServiceUnmanagedIcon"));
    /** Icon that indicates a migrated service. */
    private static final ImageIcon SERVICE_MIGRATED_ICON =
                                     Tools.createImageIcon(Tools.getDefault("CRMGraph.ServiceMigratedIcon"));
    /** List with edges that are order constraints. */
    private final Collection<Edge> edgeIsOrderList = new HashSet<Edge>();
    /** List with edges that should be kept as order constraints. */
    private final Collection<Edge> keepEdgeIsOrderList = new HashSet<Edge>();
    /** List with edges that are colocation constraints. */
    private final Collection<Edge> edgeIsColocationList = new HashSet<Edge>();
    /** List with edges that should be kept as colocation constraints. */
    private final Collection<Edge> keepEdgeIsColocationList = new HashSet<Edge>();
    private final Lock mVertexIsPresentListLock = new ReentrantLock();
    private Set<Vertex> vertexIsPresentList = new HashSet<Vertex>();
    /** Map from vertex to 'Add service' menu. */
    private final Map<Vertex, JMenu> vertexToAddServiceMap = new HashMap<Vertex, JMenu>();
    /** Map from vertex to 'Add existing service' menu. */
    private final Map<Vertex, JMenu> vertexToAddExistingServiceMap = new HashMap<Vertex, JMenu>();
    /** Map from edge to the hb connection info of this constraint. */
    private final Map<Edge, HbConnectionInfo> edgeToHbconnectionMap = new LinkedHashMap<Edge, HbConnectionInfo>();
    /** Map from hb connection info to the edge. */
    private final Map<HbConnectionInfo, Edge> hbconnectionToEdgeMap = new LinkedHashMap<HbConnectionInfo, Edge>();
    private final ReadWriteLock mHbConnectionLock = new ReentrantReadWriteLock();
    private final Lock mHbConnectionReadLock = mHbConnectionLock.readLock();
    private final Lock mHbConnectionWriteLock = mHbConnectionLock.writeLock();
    private final Map<Vertex, HostInfo> vertexToHostMap = new LinkedHashMap<Vertex, HostInfo>();
    private final Map<Info, Vertex> hostToVertexMap = new LinkedHashMap<Info, Vertex>();
    /** Map from the vertex to the constraint placeholder. */
    private final Map<Vertex, ConstraintPHInfo> vertexToConstraintPHMap = new HashMap<Vertex, ConstraintPHInfo>();
    /** Map from the host to the vertex. */
    private final Map<Info, Vertex> constraintPHToVertexMap = new HashMap<Info, Vertex>();

    private int hostDefaultXPos = 10;
    private PcmkMultiSelectionInfo multiSelectionInfo = null;
    @Inject
    private GUIData guiData;
    @Inject
    private Provider<PcmkMultiSelectionInfo> pcmkMultiSelectionInfoProvider;
    @Inject
    private Application application;
    @Inject
    private MenuFactory menuFactory;

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

    /**
     * Returns true if vertex v is one of the ancestors or the same as
     * vertex p. The vertex and edge lists must be locked when called.
     */
    private boolean isAncestor(final Vertex v, final Vertex p, final List<Vertex> list) {
        if (p.equals(v)) {
            return true;
        }
        for (final Vertex pre : getGraph().getPredecessors(p)) {
            if (list.contains(pre)) {
                return false;
            }
            list.add(pre);
            if (isAncestor(v, pre, list)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if service exists already in the parent ancestor line
     * or parent already has this service as a child.
     */
    public boolean existsInThePath(final ServiceInfo si, final ServiceInfo parent) {
        if (parent == null) {
            return true;
        }
        if (si.equals(parent)) {
            return true;
        }
        lockGraph();
        final Vertex v = getVertex(si);
        if (v == null) {
            unlockGraph();
            return false;
        }
        final Vertex pv = getVertex(parent);
        if (pv == null) {
            unlockGraph();
            return false;
        }
        if (getGraph().isSuccessor(pv, v) || isAncestor(v, pv, new ArrayList<Vertex>())) {
            unlockGraph();
            return true;
        }
        unlockGraph();
        return false;
    }

    /** Returns heartbeat ids from this service info's parents. */
    public Set<ServiceInfo> getParents(final ServiceInfo si) {
        final Set<ServiceInfo> parents = new TreeSet<ServiceInfo>();
        final Vertex v = getVertex(si);
        if (v != null) {
            lockGraph();
            for (final Vertex pV : getGraph().getPredecessors(v)) {
                final ServiceInfo psi = (ServiceInfo) getInfo(pV);
                if (psi != null) {
                    parents.add(psi);
                }
            }
            unlockGraph();
        }
        return parents;
    }

    /** Returns children of the service. */
    public Set<ServiceInfo> getChildren(final ServiceInfo si) {
        final Set<ServiceInfo> children = new TreeSet<ServiceInfo>();
        final Vertex v = getVertex(si);
        if (v != null) {
            lockGraph();
            for (final Vertex pV : getGraph().getSuccessors(v)) {
                final ServiceInfo psi = (ServiceInfo) getInfo(pV);
                if (psi != null) {
                    children.add(psi);
                }
            }
            unlockGraph();
        }
        return children;
    }

    /** Returns children and parents of the service. */
    public Collection<ServiceInfo> getChildrenAndParents(final ServiceInfo si) {
        final Collection<ServiceInfo> chAndP = new TreeSet<ServiceInfo>();
        chAndP.addAll(getChildren(si));
        chAndP.addAll(getParents(si));
        return chAndP;
    }

    /** Returns all connections from this service. */
    public HbConnectionInfo[] getHbConnections(final ServiceInfo si) {
        final List<HbConnectionInfo> infos = new ArrayList<HbConnectionInfo>();
        final Vertex v = getVertex(si);
        if (v != null) {
            mHbConnectionReadLock.lock();
            try {
                lockGraph();
                final Collection<Vertex> predecessors = getGraph().getPredecessors(v);
                if (predecessors != null) {
                    for (final Vertex pV : predecessors) {
                        Edge edge = getGraph().findEdge(pV, v);
                        if (edge == null) {
                            edge = getGraph().findEdge(v, pV);
                        }
                        if (edge != null) {
                            final HbConnectionInfo hbci = edgeToHbconnectionMap.get(edge);
                            if (hbci != null) {
                                infos.add(hbci);
                            }
                        }
                    }
                }
                final Collection<Vertex> successors = getGraph().getPredecessors(v);
                if (successors != null) {
                    for (final Vertex sV : successors) {
                        Edge edge = getGraph().findEdge(v, sV);
                        if (edge == null) {
                            edge = getGraph().findEdge(sV, v);
                        }
                        if (edge != null) {
                            final HbConnectionInfo hbci = edgeToHbconnectionMap.get(edge);
                            if (hbci != null) {
                                infos.add(hbci);
                            }
                        }
                    }
                }
                unlockGraph();
            } finally {
                mHbConnectionReadLock.unlock();
            }
        }
        return infos.toArray(new HbConnectionInfo[infos.size()]);
    }

    /** Returns id that is used for saving of the vertex positions to a file. */
    @Override
    protected String getId(final Info i) {
        final String id = i.getId();
        if (id == null) {
            return null;
        }
        return "hb=" + i.getId();
    }

    /**
     * Exchanges object in vertex, e.g., wenn ra changes to/from m/s resource.
     */
    public void exchangeObjectInTheVertex(final ServiceInfo newSI, final ServiceInfo oldSI) {
        final Vertex v = getVertex(oldSI);
        removeVertex(oldSI);
        putInfoToVertex(newSI, v);
        putVertexToInfo(v, newSI);
        somethingChanged();
    }

    /**
     * adds resource/service to the graph. Adds also edge from the parent.
     * If vertex exists add only the edge. If parent is null add only vertex
     * without edge. Return true if vertex existed in the graph before.
     */
    public boolean addResource(final ServiceInfo serviceInfo,
                               final ServiceInfo parent,
                               final Point2D pos,
                               final boolean colocation,
                               final boolean order,
                               final Application.RunMode runMode) {
        boolean vertexExists = true;
        Vertex v = getVertex(serviceInfo);
        if (v == null) {
            v = new Vertex();
            if (pos == null) {
                final Point2D newPos = getSavedPosition(serviceInfo);
                if (newPos == null) {
                    final Point2D max = getLastPosition();
                    final float maxYPos = (float) max.getY();
                    getVertexLocations().put(v, new Point2D.Float(BD_X_POS, maxYPos + 40));
                    putVertexLocations();
                } else {
                    getVertexLocations().put(v, newPos);
                    putVertexLocations();
                }
            } else {
                final Point2D p = getVisualizationViewer().getRenderContext().getMultiLayerTransformer()
                                                                             .inverseTransform(Layer.VIEW, pos);
                getVertexLocations().put(v, posWithScrollbar(p));
                putVertexLocations();
            }

            lockGraph();
            getGraph().addVertex(v);
            unlockGraph();
            somethingChanged();
            putInfoToVertex(serviceInfo, v);
            putVertexToInfo(v, serviceInfo);
            vertexExists = false;
        } else if (Application.isTest(runMode)) {
            addTestEdge(getVertex(parent), getVertex(serviceInfo));
        }

        if (parent != null && Application.isLive(runMode)) {
            if (colocation) {
                addColocation(null, serviceInfo, parent);
            }
            if (order) {
                addOrder(null, parent, serviceInfo);
            }
        }
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                repaint();
            }
        });
        return vertexExists;
    }

    /** Adds order constraint from parent to the service. */
    public void addOrder(final String ordId, final ServiceInfo parent, final ServiceInfo serviceInfo) {
        if (parent == null || serviceInfo == null) {
            return;
        }
        Vertex vP = getVertex(parent);
        Vertex v = getVertex(serviceInfo);
        if (vP == v) {
            return;
        }
        if (parent.isConstraintPlaceholder() || serviceInfo.isConstraintPlaceholder()) {
            /* if it is sequential rsc set change it to show to the resource
             * instead on placeholder. */

            final ConstraintPHInfo cphi;
            if (parent.isConstraintPlaceholder()) {
                cphi = (ConstraintPHInfo) parent;
                final ServiceInfo si = cphi.prevInSequence(serviceInfo, false);
                if (si != null) {
                    vP = getVertex(si);
                }
            } else {
                cphi = (ConstraintPHInfo) serviceInfo;
                final ServiceInfo si = cphi.nextInSequence(parent, false);
                if (si != null) {
                    v = getVertex(si);
                }
            }
        }
        if (v == null || vP == null) {
            return;
        }
        final Vertex vP0 = vP;
        final Vertex v0 = v;

        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                mHbConnectionWriteLock.lock();
                Edge edge = null;
                try {
                    lockGraph();
                    edge = getGraph().findEdge(vP0, v0);
                    if (edge == null) {
                        edge = getGraph().findEdge(v0, vP0);
                        unlockGraph();
                        if (edge != null) {
                            edge.reverse();
                            if (edgeIsOrderList.contains(edge)) {
                                edge.setWrongColocation(true);
                            } else {
                                edge.setWrongColocation(false);
                            }
                        }
                    } else {
                        if (!edgeIsOrderList.contains(edge)) {
                            edge.setWrongColocation(false);
                        }
                        unlockGraph();
                    }
                } catch (final RuntimeException e) {
                    unlockGraph();
                }
                final HbConnectionInfo hbci;
                if (edge == null) {
                    hbci = getClusterBrowser().getNewHbConnectionInfo();
                    edge = new Edge(vP0, v0);
                    lockGraph();
                    getGraph().addEdge(edge, vP0, v0);
                    unlockGraph();
                    edgeToHbconnectionMap.put(edge, hbci);
                    hbconnectionToEdgeMap.put(hbci, edge);
                } else {
                    hbci = edgeToHbconnectionMap.get(edge);
                }
                mHbConnectionWriteLock.unlock();
                if (hbci != null) {
                    hbci.addOrder(ordId, parent, serviceInfo);
                    edgeIsOrderList.add(edge);
                    keepEdgeIsOrderList.add(edge);
                }
            }
        });
    }

    /** Returns whether these two services are colocated. */
    public boolean isColocation(final ServiceInfo parent, final ServiceInfo serviceInfo) {
        final Vertex vP = getVertex(parent);
        final Vertex v = getVertex(serviceInfo);
        if (vP == null || v == null) {
            return false;
        }

        lockGraph();
        Edge edge = getGraph().findEdge(vP, v);
        if (edge == null) {
            edge = getGraph().findEdge(v, vP);
        }
        unlockGraph();
        return edge != null && edgeIsColocationList.contains(edge);
    }

    /** Returns whether these two services are ordered. */
    public boolean isOrder(final ServiceInfo parent, final ServiceInfo serviceInfo) {
        final Vertex vP = getVertex(parent);
        final Vertex v = getVertex(serviceInfo);
        if (vP == null || v == null) {
            return false;
        }

        lockGraph();
        Edge edge = getGraph().findEdge(vP, v);
        if (edge == null) {
            edge = getGraph().findEdge(v, vP);
        }
        unlockGraph();
        return edge != null && edgeIsOrderList.contains(edge);
    }

    /** Adds colocation constraint from parent to the service. */
    public void addColocation(final String colId, final ServiceInfo rsc, final ServiceInfo withRsc) {
        if (rsc == null || withRsc == null) {
            return;
        }
        Vertex vRsc = getVertex(rsc);
        Vertex vWithRsc = getVertex(withRsc);
        if (vRsc == vWithRsc) {
            return;
        }
        if (rsc.isConstraintPlaceholder() || withRsc.isConstraintPlaceholder()) {
            /* if it is sequential rsc set change it to show to the resource
             * instead on placeholder. */

            final ConstraintPHInfo cphi;
            if (rsc.isConstraintPlaceholder()) {
                cphi = (ConstraintPHInfo) rsc;
                final ServiceInfo si = cphi.nextInSequence(withRsc, true);
                if (si != null) {
                    vRsc = getVertex(si);
                }
            } else {
                cphi = (ConstraintPHInfo) withRsc;
                final ServiceInfo si = cphi.prevInSequence(rsc, true);
                if (si != null) {
                    vWithRsc = getVertex(si);
                }
            }
        }
        if (vWithRsc == null || vRsc == null) {
            return;
        }
        final Vertex vWithRsc0 = vWithRsc;
        final Vertex vRsc0 = vRsc;
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                mHbConnectionWriteLock.lock();
                Edge edge = null;
                try {
                    lockGraph();
                    edge = getGraph().findEdge(vWithRsc0, vRsc0);
                    if (edge == null) {
                        edge = getGraph().findEdge(vRsc0, vWithRsc0);
                        if (edge != null) {
                            edge.setWrongColocation(true);
                        }
                    } else {
                        edge.setWrongColocation(false);
                    }
                    unlockGraph();
                } catch (final RuntimeException e) {
                    /* ignore */
                }
                final HbConnectionInfo hbci;
                if (edge == null) {
                    hbci = getClusterBrowser().getNewHbConnectionInfo();
                    edge = new Edge(vWithRsc0, vRsc0);
                    lockGraph();
                    getGraph().addEdge(edge, vWithRsc0, vRsc0);
                    unlockGraph();
                    edgeToHbconnectionMap.put(edge, hbci);
                    hbconnectionToEdgeMap.put(hbci, edge);
                } else {
                    hbci = edgeToHbconnectionMap.get(edge);
                }
                mHbConnectionWriteLock.unlock();
                if (hbci != null) {
                    hbci.addColocation(colId, rsc, withRsc);
                    edgeIsColocationList.add(edge);
                    keepEdgeIsColocationList.add(edge);
                }
            }
        });
    }

    /** Removes items from order list. */
    public void clearKeepOrderList() {
        mHbConnectionReadLock.lock();
        try {
            lockGraph();
            for (final Edge edge : getGraph().getEdges()) {
                final HbConnectionInfo hbci = edgeToHbconnectionMap.get(edge);
                if (hbci != null && !hbci.isNew()) {
                    /* don't remove the new ones. */
                    keepEdgeIsOrderList.remove(edge);
                }
            }
            unlockGraph();
        } finally {
            mHbConnectionReadLock.unlock();
        }
    }

    /** Removes items from colocation list. */
    public void clearKeepColocationList() {
        mHbConnectionReadLock.lock();
        try {
            lockGraph();
            for (final Edge edge : getGraph().getEdges()) {
                final HbConnectionInfo hbci = edgeToHbconnectionMap.get(edge);
                if (hbci != null && !hbci.isNew()) {
                    /* don't remove the new ones. */
                    keepEdgeIsColocationList.remove(edge);
                }
            }
            unlockGraph();
        } finally {
            mHbConnectionReadLock.unlock();
        }
    }

    /** Returns label for service vertex. */
    @Override
    protected String getMainText(final Vertex v, final Application.RunMode runMode) {
        final String str;
        if (vertexToHostMap.containsKey(v)) {
            str = vertexToHostMap.get(v).toString();
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            str = vertexToConstraintPHMap.get(v).getMainTextForGraph();
        } else {
            final ServiceInfo si = (ServiceInfo) getInfo(v);
            if (si == null) {
                return "";
            }
            final Set<Vertex> vipl = getVertexIsPresentList();
            putVertexIsPresentList();
            if (si.getService().isRemoved()) {
                str = Tools.getString("CRMGraph.Removing");
            } else if (vipl.contains(v)) {
                str = si.getMainTextForGraph();
            } else {
                if (si.getService().isNew()) {
                    str = si.getMainTextForGraph();
                } else {
                    str = Tools.getString("CRMGraph.Unconfigured");
                }
            }
        }
        return str;
    }

    /** Returns shape of the service vertex. */
    @Override
    protected Shape getVertexShape(final Vertex v, final VertexShapeFactory<Vertex> factory) {
        if (vertexToHostMap.containsKey(v)) {
            return factory.getRectangle(v);
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            return factory.getEllipse(v);
        } else {
            final RoundRectangle2D r = factory.getRoundRectangle(v);

            return new RoundRectangle2D.Double(r.getX(), r.getY(), r.getWidth(), r.getHeight(), 20, 20);
        }
    }

    @Override
    public void pickInfo(final Info i) {
        final GroupInfo groupInfo = ((ServiceInfo) i).getGroupInfo();
        if (groupInfo == null) {
            super.pickInfo(i);
        } else {
            /* group is picked in the graph, if group service was selected. */
            final Vertex v = getVertex(groupInfo);
            final PickedState<Edge> psEdge = getVisualizationViewer().getRenderContext().getPickedEdgeState();
            final PickedState<Vertex> psVertex = getVisualizationViewer().getRenderContext().getPickedVertexState();
            psEdge.clear();
            psVertex.clear();
            psVertex.pick(v, true);
        }
    }

    /** Handles right click on the service vertex and creates popup menu. */
    @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 (vertexToHostMap.containsKey(v)) {
            info = getInfo(v);
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            info = vertexToConstraintPHMap.get(v);
        } else {
            info = getInfo(v);
        }
        if (info != null) {
            final JPopupMenu p = info.getPopup();
            info.updateMenus(pos);
            showPopup(p, pos);
        }
    }

    /**
     * Recreates the add existing service popup, since it can change in
     * very unlikely event.
     */
    private void reloadAddExistingServicePopup(final JMenu addServiceMenuItem, final Vertex v) {
        if (addServiceMenuItem == null) {
            return;
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        addServiceMenuItem.removeAll();
        if (si == null) {
            return;
        }
        boolean separatorAdded = false;
        final Application.RunMode runMode = getRunMode();
        for (final ServiceInfo asi : getClusterBrowser().getExistingServiceList(si)) {
            final MyMenuItem mmi = menuFactory.createMenuItem(asi.toString(),
                                                  null,
                                                  null,
                                                  new AccessMode(AccessMode.ADMIN, AccessMode.NORMAL),
                                                  new AccessMode(AccessMode.OP, AccessMode.NORMAL))
                .addAction(new MenuAction() {
                    @Override
                    public void run(final String text) {
                        si.addServicePanel(asi,
                                null,
                                false, /* TODO: colocation only */
                                false, /* order only */
                                true,
                                getClusterBrowser().getDCHost(),
                                runMode);
                        repaint();
                    }
                });
            if ("Filesystem".equals(asi.getInternalValue()) || "IPaddr2".equals(asi.getInternalValue())) {

                mmi.setSpecialFont();
                addServiceMenuItem.add(mmi);
            } else {
                if (!separatorAdded) {
                    addServiceMenuItem.addSeparator();
                    separatorAdded = true;
                }
                addServiceMenuItem.add(mmi);
            }
        }
    }

    /** Handles right click on the edge and creates popup menu. */
    @Override
    protected void handlePopupEdge(final Edge edge, final Point2D pos) {
        mHbConnectionReadLock.lock();
        final HbConnectionInfo info;
        try {
            info = edgeToHbconnectionMap.get(edge);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (info != null) {
            final JPopupMenu p = info.getPopup();
            info.updateMenus(pos);
            showPopup(p, pos);
        }
    }

    /** Handles right click on the background and creates popup menu. */
    @Override
    protected void handlePopupBackground(final Point2D pos) {
        final Info info = getClusterBrowser().getServicesInfo();
        final JPopupMenu p = info.getPopup();
        info.updateMenus(pos);
        showPopup(p, pos);
    }

    /**
     * After service vertex v was released in position pos, set its location
     * there, so that it doesn't jump back. If position is outside of the view,
     * bring the vertex back in the view.
     */
    @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, y);
        getVertexLocations().put(v, pos);
        putVertexLocations();
        getLayout().setLocation(v, pos);
    }

    /**
     * Selects Info in the view if a service vertex was pressed. If more
     * vertices were selected, it does not do anything.
     */
    @Override
    protected void oneVertexPressed(final Vertex v) {
        pickVertex(v);
        if (vertexToHostMap.containsKey(v)) {
            final HostInfo hi = vertexToHostMap.get(v);
            if (hi != null) {
                guiData.setTerminalPanel(hi.getHost().getTerminalPanel());
                getClusterBrowser().setRightComponentInView(hi);
            }
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            final ConstraintPHInfo cphi = vertexToConstraintPHMap.get(v);
            if (cphi != null) {
                getClusterBrowser().setRightComponentInView(cphi);
            }
        } else {
            final ServiceInfo si = (ServiceInfo) getInfo(v);
            if (si != null) {
                si.selectMyself();
            }
        }
    }

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

    /** Returns tool tip when mouse is over a service vertex. */
    @Override
    public String getVertexToolTip(final Vertex v) {
        final Application.RunMode runMode = getRunMode();

        if (vertexToHostMap.containsKey(v)) {
            return vertexToHostMap.get(v).getToolTipForGraph(runMode);
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            return vertexToConstraintPHMap.get(v).getToolTipForGraph(runMode);
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return null;
        }
        return si.getToolTipText(runMode);
    }

    /** Returns the tool tip for the edge. */
    @Override
    public String getEdgeToolTip(final Edge edge) {
        // TODO: move this to the clusterbrowser
        final Pair<Vertex> p = getGraph().getEndpoints(edge);
        final boolean edgeIsOrder = edgeIsOrderList.contains(edge);
        final boolean edgeIsColocation = edgeIsColocationList.contains(edge);

        final Vertex v = p.getSecond();
        final Vertex parent = p.getFirst();
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return null;
        }
        final ServiceInfo siP = (ServiceInfo) getInfo(parent);
        if (siP == null) {
            return null;
        }
        final StringBuilder s = new StringBuilder(100);
        s.append(siP);
        mHbConnectionReadLock.lock();
        final HbConnectionInfo hbci;
        try {
            hbci = edgeToHbconnectionMap.get(edge);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (edgeIsOrder && hbci != null && !hbci.isOrdScoreNull(null, null)) {
            s.append(" is started before ");
        } else {
            s.append(" and ");
        }
        s.append(si);
        if (!edgeIsOrder) {
            s.append(" are located");
        }
        if (edgeIsColocation) {
            final HbConnectionInfo.ColScoreType colSType = hbci.getColocationScoreType(null, null);
            if (colSType == HbConnectionInfo.ColScoreType.NEGATIVE
                || colSType == HbConnectionInfo.ColScoreType.MINUS_INFINITY) {
                s.append(" not on the same host");
            } else {
                s.append(" on the same host");
            }
        } else {
            s.append(" not necessarily on the same host");
        }

        return s.toString();
    }

    /**
     * Returns color of the vertex, depending if the service is configured,
     * removed or color of the host.
     */
    @Override
    protected Color getVertexFillColor(final Vertex v) {
        final Application.RunMode runMode = getRunMode();
        if (vertexToHostMap.containsKey(v)) {
            return vertexToHostMap.get(v).getHost().getPmColors()[0];
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            if (vertexToConstraintPHMap.get(v).getService().isNew()) {
                return Tools.getDefaultColor("CRMGraph.FillPaintUnconfigured");
            } else {
                // TODO fillpaint.placeholder
                return Tools.getDefaultColor("CRMGraph.FillPaintPlaceHolder");
            }
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return null;
        }
        final Set<Vertex> vipl = getVertexIsPresentList();
        putVertexIsPresentList();
        if (getClusterBrowser().allHostsWithoutClusterStatus()) {
            return Tools.getDefaultColor("CRMGraph.FillPaintUnknown");
        } else if (si.getService().isOrphaned()) {
            return Tools.getDefaultColor("CRMGraph.FillPaintUnknown");
        } else if (si.isFailed(runMode)) {
            return Tools.getDefaultColor("CRMGraph.FillPaintFailed");
        } else if (!si.isRunning(runMode)) {
            return getClusterBrowser().SERVICE_STOPPED_FILL_PAINT;
        } else if (getClusterBrowser().crmStatusFailed()) {
            return Tools.getDefaultColor("CRMGraph.FillPaintUnknown");
        } else if (vipl.contains(v) || Application.isTest(runMode)) {
            final List<Color> colors = si.getHostColors(runMode);
            if (colors.size() >= 1) {
                return colors.get(0);
            } else {
                return Color.WHITE; /* more colors */
            }
        } else if (!si.getService().isNew()) {
            return Tools.getDefaultColor("CRMGraph.FillPaintRemoved");
        } else {
            return Tools.getDefaultColor("CRMGraph.FillPaintUnconfigured");
        }
    }

    /** Returns label that describes the edge. */
    @Override
    protected String getLabelForEdgeStringer(final Edge e) {
        if (isTestEdge(e)) {
            return Tools.getString("CRMGraph.Simulate");
        }
        final boolean edgeIsOrder = edgeIsOrderList.contains(e);
        final boolean edgeIsColocation = edgeIsColocationList.contains(e);
        final Pair<Vertex> p = getGraph().getEndpoints(e);
        if (p == null) {
            return "";
        }
        final ServiceInfo s1 = (ServiceInfo) getInfo(p.getSecond());
        if (s1 == null) {
            return "";
        }
        final ServiceInfo s2 = (ServiceInfo) getInfo(p.getFirst());
        if (s2 == null) {
            return "";
        }
        mHbConnectionReadLock.lock();
        final HbConnectionInfo hbci;
        try {
            hbci = edgeToHbconnectionMap.get(e);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (hbci == null) {
            return "";
        }
        String leftArrow = "\u2190 "; /* <- */
        String rightArrow = " \u2192"; /* -> */
        final HbConnectionInfo.ColScoreType colSType = hbci.getColocationScoreType(null, null);
        if (edgeIsColocation) {
            if (hbci.isColocationTwoDirections()) {
                leftArrow = "\u21AE "; /* </> */
                rightArrow = "\u21AE "; /* </> */
            } else if (colSType == HbConnectionInfo.ColScoreType.NEGATIVE
                || colSType == HbConnectionInfo.ColScoreType.MINUS_INFINITY) {
            } else if (colSType == HbConnectionInfo.ColScoreType.IS_NULL) {
                leftArrow = "\u21E0 "; /* < - - */
                rightArrow = " \u21E2"; /* - - > */
            } else if (colSType == HbConnectionInfo.ColScoreType.MIXED) {
                leftArrow = "\u219A "; /* </- */
                rightArrow = " \u219B"; /* -/> */
            }
        }
        String colScore = "";
        if (edgeIsColocation
            && colSType == HbConnectionInfo.ColScoreType.IS_NULL) {
            colScore = "0";
        }
        String ordScore = "";
        if (edgeIsOrder && hbci.isOrdScoreNull(null, null)) {
            ordScore = "0";
        }

        String colDesc = null;
        String ordDesc = null;
        String desc = null;
        if (edgeIsOrder && edgeIsColocation) {
            if (colSType == HbConnectionInfo.ColScoreType.NEGATIVE
                || colSType == HbConnectionInfo.ColScoreType.MINUS_INFINITY) {
                colDesc = "repelled";
            } else {
                colDesc = "col";
            }
            ordDesc = "ord";
        } else if (edgeIsOrder) {
            ordDesc = "ordered";
        } else if (edgeIsColocation) {
            if (colSType == HbConnectionInfo.ColScoreType.NEGATIVE
                || colSType == HbConnectionInfo.ColScoreType.MINUS_INFINITY) {
                colDesc = "repelled";
            } else {
                colDesc = "colocated";
            }
        } else if (s1.getService().isNew() || s2.getService().isNew()) {
            desc = Tools.getString("CRMGraph.Unconfigured");
        } else {
            desc = Tools.getString("CRMGraph.Removing");
        }
        if (desc != null) {
            return desc;
        }
        final Vertex v1 = p.getSecond();
        final Vertex v2 = p.getFirst();
        double s1X = 0;
        final Point2D loc1 = getLayout().transform(v1);
        if (loc1 != null) {
            s1X = loc1.getX();
        }
        final Point2D loc2 = getLayout().transform(v2);
        double s2X = 0;
        if (loc2 != null) {
            s2X = loc2.getX();
        }
        final StringBuilder sb = new StringBuilder(15);
        final boolean upsideDown = s1X < s2X;
        final boolean left = hbci.isWithRsc(s2) && !e.isWrongColocation();
        if (edgeIsColocation) {
            if ((left && !upsideDown) || (!left && upsideDown)) {
                sb.append(leftArrow); /* <- */
                sb.append(colScore);
                sb.append(' ');
                sb.append(colDesc);
                if (edgeIsOrder) {
                    sb.append('/');
                    sb.append(ordDesc);
                    sb.append(' ');
                    sb.append(ordScore);
                }
            } else if ((!left && !upsideDown) || (left && upsideDown)) {
                if (edgeIsOrder) {
                    sb.append(ordScore);
                    sb.append(' ');
                    sb.append(ordDesc);
                    sb.append('/');
                }
                sb.append(colDesc);
                sb.append(' ');
                sb.append(colScore);
                sb.append(rightArrow); /* -> */
            }
        } else if (edgeIsOrder) {
            if (left && !upsideDown) {
                sb.append(ordDesc);
                sb.append(' ');
                sb.append(ordScore);
            } else {
                sb.append(ordScore);
                sb.append(' ');
                sb.append(ordDesc);
            }
        }
        return sb.toString();
    }

    /** Returns paint of the edge. */
    @Override
    protected Paint getEdgeDrawPaint(final Edge e) {
        mHbConnectionReadLock.lock();
        final HbConnectionInfo hbci;
        try {
            hbci = edgeToHbconnectionMap.get(e);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (hbci != null && hbci.isNew()) {
            return Tools.getDefaultColor("ResourceGraph.EdgeDrawPaintNew");
        } else if (edgeIsOrderList.contains(e) && edgeIsColocationList.contains(e)) {
            return super.getEdgeDrawPaint(e);
        } else if (edgeIsOrderList.contains(e) || edgeIsColocationList.contains(e)) {
            return Tools.getDefaultColor("ResourceGraph.EdgeDrawPaintBrighter");
        } else {
            return Tools.getDefaultColor("ResourceGraph.EdgeDrawPaintRemoved");
        }
    }

    /** Returns paint of the picked edge. */
    @Override
    protected Paint getEdgePickedPaint(final Edge e) {
        mHbConnectionReadLock.lock();
        final HbConnectionInfo hbci;
        try {
            hbci = edgeToHbconnectionMap.get(e);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (hbci != null && hbci.isNew()) {
            return Tools.getDefaultColor("ResourceGraph.EdgePickedPaintNew");
        } else if (edgeIsOrderList.contains(e) && edgeIsColocationList.contains(e)) {
            return super.getEdgePickedPaint(e);
        } else if (edgeIsOrderList.contains(e) || edgeIsColocationList.contains(e)) {
            return Tools.getDefaultColor("ResourceGraph.EdgePickedPaintBrighter");
        } else {
            return Tools.getDefaultColor("ResourceGraph.EdgePickedPaintRemoved");
        }
    }

    /**
     * Remove edges that were marked as not present, meaning there are no
     * colocation nor order constraints.
     */
    public void killRemovedEdges() {
        lockGraph();
        final Collection<Edge> edges = new ArrayList<Edge>(getGraph().getEdges().size());
        for (final Edge e : getGraph().getEdges()) {
            edges.add(e);
        }
        unlockGraph();

        for (final Edge e : edges) {
            final Pair<Vertex> p = getGraph().getEndpoints(e);
            final ServiceInfo s1 = (ServiceInfo) getInfo(p.getSecond());
            if (s1 == null) {
                continue;
            }
            final ServiceInfo s2 = (ServiceInfo) getInfo(p.getFirst());
            if (s2 == null) {
                continue;
            }
            if (!keepEdgeIsOrderList.contains(e)) {
                edgeIsOrderList.remove(e);
            }
            if (!keepEdgeIsColocationList.contains(e)) {
                edgeIsColocationList.remove(e);
            }
            if (s1.getService().isNew() && !s1.getService().isRemoved()
                || (s2.getService().isNew() && !s2.getService().isRemoved())) {
                continue;
            }
            if (!keepEdgeIsOrderList.contains(e)) {
                mHbConnectionReadLock.lock();
                final HbConnectionInfo hbci;
                try {
                    hbci = edgeToHbconnectionMap.get(e);
                } finally {
                    mHbConnectionReadLock.unlock();
                }
                if (hbci != null) {
                    hbci.removeOrders();
                }
            }

            if (!keepEdgeIsColocationList.contains(e)) {
                mHbConnectionReadLock.lock();
                final HbConnectionInfo hbci;
                try {
                    hbci = edgeToHbconnectionMap.get(e);
                } finally {
                    mHbConnectionReadLock.unlock();
                }
                if (hbci != null) {
                    hbci.removeColocations();
                }
            }
            if (!keepEdgeIsOrderList.contains(e) && !keepEdgeIsColocationList.contains(e)) {
                removeEdge(e, Application.RunMode.LIVE);
            }
        }
    }

    /** Removes edge if it is not in the list of constraints. */
    private void removeEdge(final Edge e, final Application.RunMode runMode) {
        if (e == null) {
            return;
        }
        if (!edgeIsOrderList.contains(e)
            && !edgeIsColocationList.contains(e)) {
            e.reset();
            lockGraph();
            getGraph().removeEdge(e);
            unlockGraph();
            mHbConnectionWriteLock.lock();
            try {
                final HbConnectionInfo hbci = edgeToHbconnectionMap.get(e);
                edgeToHbconnectionMap.remove(e);
                if (hbci != null) {
                    hbconnectionToEdgeMap.remove(hbci);
                    hbci.removeMyself(runMode);
                }
            } finally {
                mHbConnectionWriteLock.unlock();
            }
        }
    }

    /** Remove vertices that were marked as not present. */
    public void killRemovedVertices() {
        /* Make copy first. */
        final Collection<Vertex> vertices = new ArrayList<Vertex>();
        lockGraph();
        for (final Vertex vo : getGraph().getVertices()) {
            vertices.add(vo);
        }
        unlockGraph();
        for (final Vertex v : vertices) {
            if (vertexToHostMap.containsKey(v)) {
                continue;
            }
            lockGraph();
            if (!getGraph().getInEdges(v).isEmpty() || !getGraph().getOutEdges(v).isEmpty()) {
                unlockGraph();
                continue;
            }
            unlockGraph();
            final Set<Vertex> vipl = getVertexIsPresentList();
            putVertexIsPresentList();
            if (vertexToConstraintPHMap.containsKey(v)) {
                final ConstraintPHInfo cphi = (ConstraintPHInfo) getInfo(v);
                if (cphi == null) {
                    continue;
                }
                if (!vipl.contains(v)) {
                    cphi.setUpdated(false);
                    if (!getClusterBrowser().crmStatusFailed()
                        && cphi.getService().isRemoved()) {
                        getVertexLocations().put(v, null);
                        putVertexLocations();
                        lockGraph();
                        getGraph().removeVertex(v);
                        removeInfo(v);
                        removeVertex(cphi);
                        unlockGraph();
                        cphi.removeInfo();
                        getVertexToMenus().remove(v);
                        vertexToConstraintPHMap.remove(v);
                        constraintPHToVertexMap.remove(cphi);
                        somethingChanged();
                    } else {
                        cphi.getService().setNew(true);
                    }
                }
                cphi.resetRscSetConnectionData();
            } else {
                if (!vipl.contains(v)) {
                    final ServiceInfo si = (ServiceInfo) getInfo(v);
                    if (si != null && !si.getService().isNew() && !getClusterBrowser().crmStatusFailed()) {
                        si.setUpdated(false);
                        getVertexLocations().put(v, null);
                        putVertexLocations();
                        lockGraph();
                        getGraph().removeVertex(v);
                        removeInfo(v);
                        removeVertex(si);
                        unlockGraph();
                        si.removeInfo();
                        //TODO: unregister removePopup(v);
                        getVertexToMenus().remove(v);
                        vertexToAddServiceMap.remove(v);
                        vertexToAddExistingServiceMap.remove(v);
                        //TODO: positions are still there
                        somethingChanged();
                    }
                }
            }
        }
    }

    /** Mark vertex and its edges to be removed later. */
    @Override
    protected void removeInfo(final Info i) {
        final Vertex v = getVertex(i);
        /* remove edges */

        lockGraph();
        for (final Edge e : getGraph().getInEdges(v)) {
            edgeIsOrderList.remove(e);
            edgeIsColocationList.remove(e);
            keepEdgeIsOrderList.remove(e);
            keepEdgeIsColocationList.remove(e);
        }

        for (final Edge e : getGraph().getOutEdges(v)) {
            edgeIsOrderList.remove(e);
            edgeIsColocationList.remove(e);
            keepEdgeIsOrderList.remove(e);
            keepEdgeIsColocationList.remove(e);
        }
        unlockGraph();

        /* remove vertex */
        getVertexIsPresentList().remove(v);
        putVertexIsPresentList();
        ((ServiceInfo) i).getService().setNew(false);
        resetSavedPosition(i);
    }

    /**
     * Returns vertex location list, it acquires mVertexIsPresentListLock and
     * must be followed by putVertexIsPresentList.
     */
    Set<Vertex> getVertexIsPresentList() {
        mVertexIsPresentListLock.lock();
        return vertexIsPresentList;
    }

    void putVertexIsPresentList() {
        mVertexIsPresentListLock.unlock();
    }

    /** Set vertex-is-present list. */
    public void setServiceIsPresentList(final Iterable<ServiceInfo> sis) {
        final Set<Vertex> vipl = new HashSet<Vertex>();
        for (final ServiceInfo si : sis) {
            final Vertex v = getVertex(si);
            if (v == null) {
                /* e.g. group vertices */
                continue;
            }
            vipl.add(v);
        }
        mVertexIsPresentListLock.lock();
        try {
            vertexIsPresentList = vipl;
        } finally {
            mVertexIsPresentListLock.unlock();
        }
    }

    /** Returns an icon for the vertex. */
    @Override
    protected List<ImageIcon> getIconsForVertex(final Vertex v, final Application.RunMode runMode) {
        final List<ImageIcon> icons = new ArrayList<ImageIcon>();
        final HostInfo hi = vertexToHostMap.get(v);
        if (hi != null) {
            if (hi.getHost().isCrmStatusOk()) {
                icons.add(HostBrowser.HOST_ON_ICON_LARGE);
            } else {
                icons.add(HostBrowser.HOST_ICON_LARGE);
            }
            if (hi.isStandby(runMode)) {
                icons.add(HOST_STANDBY_ICON);
            }
            return icons;
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            return null;
        }

        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return null;
        }
        if (si.isFailed(runMode)) {
            if (si.isRunning(runMode)) {
                icons.add(SERVICE_RUNNING_FAILED_ICON);
            } else {
                icons.add(SERVICE_STOPPED_FAILED_ICON);
            }
        } else if (si.isStopped(runMode) || getClusterBrowser().allHostsWithoutClusterStatus()) {
            if (si.isRunning(runMode)) {
                icons.add(SERVICE_STOPPING_ICON);
            } else {
                icons.add(SERVICE_STOPPED_ICON);
            }
        } else {
            if (si.isRunning(runMode)) {
                icons.add(SERVICE_RUNNING_ICON);
            } else {
                icons.add(SERVICE_STARTED_ICON);
            }
        }
        if (!si.isManaged(runMode) || si.getService().isOrphaned()) {
            icons.add(SERVICE_UNMANAGED_ICON);
        }
        if (si.getMigratedTo(runMode) != null || si.getMigratedFrom(runMode) != null) {
            icons.add(SERVICE_MIGRATED_ICON);
        }
        return icons;
    }

    /** Returns whether to show an edge arrow. */
    @Override
    protected boolean showEdgeArrow(final Edge e) {
        if (edgeIsOrderList.contains(e)) {
            mHbConnectionReadLock.lock();
            final HbConnectionInfo hbci;
            try {
                hbci = edgeToHbconnectionMap.get(e);
            } finally {
                mHbConnectionReadLock.unlock();
            }
            return hbci != null && !hbci.isOrderTwoDirections();
        }
        return false;
    }

    /** Returns whether to show a hollow arrow. */
    @Override
    protected boolean showHollowArrow(final Edge e) {
        if (edgeIsOrderList.contains(e)) {
            mHbConnectionReadLock.lock();
            final HbConnectionInfo hbci;
            try {
                hbci = edgeToHbconnectionMap.get(e);
            } finally {
                mHbConnectionReadLock.unlock();
            }
            return hbci != null && hbci.isOrdScoreNull(null, null);
        }
        return false;
    }

    /** Reloads popup menus for all services. */
    public void reloadServiceMenus() {
        lockGraph();
        for (final Vertex v : getGraph().getVertices()) {
            final JMenu existingServiceMenuItem = vertexToAddExistingServiceMap.get(v);
            reloadAddExistingServicePopup(existingServiceMenuItem, v);
        }
        unlockGraph();
    }

    /** Is called after an edge was pressed. */
    @Override
    protected void oneEdgePressed(final Edge e) {
        mHbConnectionReadLock.lock();
        final HbConnectionInfo hbci;
        try {
            hbci = edgeToHbconnectionMap.get(e);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (hbci != null) {
            getClusterBrowser().setRightComponentInView(hbci);
        }
    }

    /** Removes the connection, the order, the colocation or both. */
    public void removeConnection(final HbConnectionInfo hbci, final Host dcHost, final Application.RunMode runMode) {
        final ServiceInfo siP = hbci.getLastServiceInfoParent();
        final ServiceInfo siC = hbci.getLastServiceInfoChild();
        mHbConnectionReadLock.lock();
        final Edge edge;
        try {
            edge = hbconnectionToEdgeMap.get(hbci);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (edgeIsOrderList.contains(edge)) {
            siC.removeOrder(siP, dcHost, runMode);
        }
        final ServiceInfo siRsc = hbci.getLastServiceInfoRsc();
        final ServiceInfo siWithRsc = hbci.getLastServiceInfoWithRsc();
        if (edgeIsColocationList.contains(edge)) {
            if (Application.isLive(runMode)) {
                edgeIsOrderList.remove(edge);
                edgeIsColocationList.remove(edge);
                keepEdgeIsOrderList.remove(edge);
                keepEdgeIsColocationList.remove(edge);
            }
            siRsc.removeColocation(siWithRsc, dcHost, runMode);
        } else {
            if (Application.isLive(runMode)) {
                edgeIsOrderList.remove(edge);
                edgeIsColocationList.remove(edge);
                keepEdgeIsOrderList.remove(edge);
                keepEdgeIsColocationList.remove(edge);
            }
        }
        if (Application.isTest(runMode)) {
            addExistingTestEdge(edge);
        } else {
            if (hbci.isNew()) {
                application.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        removeEdge(edge, runMode);
                    }
                });
            }
        }
    }

    public void removeOrder(final HbConnectionInfo hbci, final Host dcHost, final Application.RunMode runMode) {
        if (hbci == null) {
            return;
        }
        final ServiceInfo siP = hbci.getLastServiceInfoParent();
        final ServiceInfo siC = hbci.getLastServiceInfoChild();
        mHbConnectionReadLock.lock();
        final Edge edge;
        try {
            edge = hbconnectionToEdgeMap.get(hbci);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (edgeIsOrderList.contains(edge)) {
            if (Application.isLive(runMode)) {
                edgeIsOrderList.remove(edge);
                keepEdgeIsOrderList.remove(edge);
            }
            siC.removeOrder(siP, dcHost, runMode);
        }
        if (Application.isTest(runMode)) {
            addExistingTestEdge(edge);
        } else {
            if (hbci.isNew()) {
                application.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        removeEdge(edge, runMode);
                    }
                });
            }
        }
    }

    public void addOrder(final HbConnectionInfo hbConnectionInfo,
                         final Host dcHost,
                         final Application.RunMode runMode) {
        final ServiceInfo siRsc = hbConnectionInfo.getLastServiceInfoRsc();
        final ServiceInfo siWithRsc = hbConnectionInfo.getLastServiceInfoWithRsc();
        if ((siWithRsc != null && siWithRsc.getService() != null && siWithRsc.getService().isNew())
            || (siRsc != null && siRsc.getService() != null && siRsc.getService().isNew())) {
            addOrder(null, siRsc, siWithRsc);
        } else {
            siWithRsc.addOrder(siRsc, dcHost, runMode);
        }
        if (Application.isTest(runMode)) {
            mHbConnectionReadLock.lock();
            final Edge edge;
            try {
                edge = hbconnectionToEdgeMap.get(hbConnectionInfo);
            } finally {
                mHbConnectionReadLock.unlock();
            }
            addExistingTestEdge(edge);
        }
    }

    public void removeColocation(final HbConnectionInfo hbci, final Host dcHost, final Application.RunMode runMode) {
        final ServiceInfo siRsc = hbci.getLastServiceInfoRsc();
        final ServiceInfo siWithRsc = hbci.getLastServiceInfoWithRsc();
        mHbConnectionReadLock.lock();
        final Edge edge;
        try {
            edge = hbconnectionToEdgeMap.get(hbci);
            if (edge == null) {
                return;
            }
        } finally {
            mHbConnectionReadLock.unlock();
        }
        if (edgeIsColocationList.contains(edge)) {
            if (Application.isLive(runMode)) {
                edgeIsColocationList.remove(edge);
                keepEdgeIsColocationList.remove(edge);
            }
            siRsc.removeColocation(siWithRsc, dcHost, runMode);
        }
        if (Application.isTest(runMode)) {
            addExistingTestEdge(edge);
        } else {
            if (hbci.isNew()) {
                application.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        removeEdge(edge, runMode);
                    }
                });
            }
        }
    }

    /** Adds colocation. */
    public void addColocation(final HbConnectionInfo hbConnectionInfo,
                              final Host dcHost,
                              final Application.RunMode runMode) {
        final ServiceInfo siP = hbConnectionInfo.getLastServiceInfoParent();
        final ServiceInfo siC = hbConnectionInfo.getLastServiceInfoChild();
        if (siC != null
            && siC.getService() != null
            && siC.getService().isNew()) {
            addColocation(null, siP, siC);
        } else {
            siP.addColocation(siC, dcHost, runMode);
        }
        if (Application.isTest(runMode)) {
            mHbConnectionReadLock.lock();
            final Edge edge;
            try {
                edge = hbconnectionToEdgeMap.get(hbConnectionInfo);
            } finally {
                mHbConnectionReadLock.unlock();
            }
            addExistingTestEdge(edge);
        }
    }

    /** Returns whether this hb connection is order. */
    public boolean isOrder(final HbConnectionInfo hbConnectionInfo) {
        mHbConnectionReadLock.lock();
        final Edge edge;
        try {
            edge = hbconnectionToEdgeMap.get(hbConnectionInfo);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        return edgeIsOrderList.contains(edge);
    }

    /** Returns whether this hb connection is colocation. */
    public boolean isColocation(final HbConnectionInfo hbConnectionInfo) {
        mHbConnectionReadLock.lock();
        final Edge edge;
        try {
            edge = hbconnectionToEdgeMap.get(hbConnectionInfo);
        } finally {
            mHbConnectionReadLock.unlock();
        }
        return edgeIsColocationList.contains(edge);
    }

    /** Adds host to the graph. */
    public void addHost(final HostInfo hostInfo) {
        Vertex v = super.getVertex(hostInfo);
        if (v == null) {
            /* add host vertex */
            v = new Vertex();
            lockGraph();
            getGraph().addVertex(v);
            unlockGraph();
            somethingChanged();
            putInfoToVertex(hostInfo, v);
            vertexToHostMap.put(v, hostInfo);
            hostToVertexMap.put(hostInfo, v);
            putVertexToInfo(v, hostInfo);
            Point2D hostPos = getSavedPosition(hostInfo);
            if (hostPos == null) {
                hostPos = new Point2D.Double(hostDefaultXPos, HOST_Y_POS);
                hostDefaultXPos += HOST_STEP_X;
            }
            getVertexLocations().put(v, hostPos);
            putVertexLocations();
        }
    }

    /** Small text that appears above the icon. */
    @Override
    protected String getIconText(final Vertex v, final Application.RunMode runMode) {
        if (isRunModeTestAnimation()) {
            return Tools.getString("CRMGraph.Simulate");
        }
        if (vertexToHostMap.containsKey(v)) {
            return vertexToHostMap.get(v).getIconTextForGraph(runMode);
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            return vertexToConstraintPHMap.get(v).getIconTextForGraph(runMode);
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return null;
        }
        return si.getIconTextForGraph(runMode);
    }

    /** Small text that appears in the right corner. */
    @Override
    protected ColorText getRightCornerText(final Vertex v, final Application.RunMode runMode) {
        if (vertexToHostMap.containsKey(v)) {
            final HostInfo hi = vertexToHostMap.get(v);
            return hi.getRightCornerTextForGraph(runMode);
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            return null;
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si != null) {
            return si.getRightCornerTextForGraph(runMode);
        }
        return null;
    }

    /** Small text that appears down. */
    @Override
    protected ColorText[] getSubtexts(final Vertex v, final Application.RunMode runMode) {
        if (vertexToHostMap.containsKey(v)) {
            return vertexToHostMap.get(v).getSubtextsForGraph(runMode);
        } else if (vertexToConstraintPHMap.containsKey(v)) {
            return vertexToConstraintPHMap.get(v).getSubtextsForGraph(runMode);
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return null;
        }
        return si.getSubtextsForGraph(runMode);
    }

    /**
     * Returns how much of the disk is used. Probably useful only for disks.
     * -1 for not used or not applicable.
     */
    protected int getUsed(final Vertex v) {
        if (vertexToHostMap.containsKey(v)) {
            final HostInfo hi = (HostInfo) getInfo(v);
            if (hi == null) {
                return 0;
            }
            return hi.getUsed();
        }
        final ServiceInfo si = (ServiceInfo) getInfo(v);
        if (si == null) {
            return 0;
        }
        return si.getUsed();
    }

    /**
     * This method draws how much of the vertex is used for something.
     * It draws more colors for verteces that have more background colors.
     */
    @Override
    protected void drawInside(final Vertex v,
                              final Graphics2D g2d,
                              final double x,
                              final double y,
                              final Shape shape) {
        final Application.RunMode runMode = getRunMode();
        final float height = (float) shape.getBounds().getHeight();
        final float width = (float) shape.getBounds().getWidth();
        if (vertexToHostMap.containsKey(v)) {
            final HostInfo hi = (HostInfo) getInfo(v);
            if (hi != null) {
                drawInsideVertex(g2d,
                                 v,
                                 hi.getHost().getPmColors(),
                                 x,
                                 y,
                                 height,
                                 width);
            }
        } else if (vertexToConstraintPHMap.containsKey(v)) {
        } else {
            final ServiceInfo si = (ServiceInfo) getInfo(v);
            if (si == null) {
                return;
            }
            final List<Color> colors = si.getHostColors(runMode);
            final int number = colors.size();
            if (number > 1) {
                for (int i = 1; i < number; i++) {
                    final Paint p = new GradientPaint((float) x + width / number,
                                                      (float) y,
                                                      getVertexFillSecondaryColor(v),
                                                      (float) x + width / number,
                                                      (float) y + height,
                                                      colors.get(i),
                                                      false);
                    g2d.setPaint(p);
                    final Shape s = new RoundRectangle2D.Double(x + (width / number) * i - 5,
                                                                y,
                                                                width / number + (i < number - 1 ? 20 : 5),
                                                                height,
                                                                20,
                                                                20);
                    g2d.fill(s);
                }
            }
            final double used = getUsed(v);
            if (used > 0) {
                /** Show how much is used. */
                final double freeWidth = width * (100 - used) / 100;
                final Shape freeShape =
                   new RoundRectangle2D.Double(x + width - freeWidth, y, freeWidth, height, 20, 20);
                g2d.setColor(new Color(255, 255, 255, 180));
                g2d.fill(freeShape);
            }
        }
        if (isPicked(v)) {
            if (Application.isTest(runMode)) {
                g2d.setColor(Color.RED);
            } else {
                g2d.setColor(Color.BLACK);
            }
        } else {
            g2d.setColor(Color.WHITE);
        }
        g2d.setStroke(new BasicStroke(1.5f));
        g2d.draw(shape);
    }

    /** Returns all crm connections. */
    public Iterable<HbConnectionInfo> getAllHbConnections() {
        final Collection<HbConnectionInfo> allConnections = new ArrayList<HbConnectionInfo>();
        mHbConnectionReadLock.lock();
        try {
            for (final HbConnectionInfo hbci : hbconnectionToEdgeMap.keySet()) {
                allConnections.add(hbci);
            }
        } finally {
            mHbConnectionReadLock.unlock();
        }
        return allConnections;
    }

    /**
     * Returns the vertex that represents the specified resource or its group.
     */
    @Override
    public Vertex getVertex(final Info i) {
        if (i == null) {
            return null;
        }
        if (hostToVertexMap.containsKey(i)) {
            return super.getVertex(i);
        }
        final GroupInfo gi = ((ServiceInfo) i).getGroupInfo();
        if (gi == null) {
            return super.getVertex(i);
        } else {
            return super.getVertex(gi);
        }
    }

    /** Adds placeholder that is used to create resource sets. */
    public void addConstraintPlaceholder(final ConstraintPHInfo rsoi,
                                         final Point2D pos,
                                         final Application.RunMode runMode) {
        if (Application.isTest(runMode)) {
            return;
        }
        final Vertex v = new Vertex();
        if (pos == null) {
            final Point2D newPos = getSavedPosition(rsoi);
            if (newPos == null) {
                final Point2D max = getLastPosition();
                final float maxYPos = (float) max.getY();
                getVertexLocations().put(v, new Point2D.Float(BD_X_POS, maxYPos + 40));
                putVertexLocations();
            } else {
                getVertexLocations().put(v, newPos);
                putVertexLocations();
            }
        } else {
            getVertexLocations().put(v, pos);
            putVertexLocations();
        }

        lockGraph();
        getGraph().addVertex(v);
        unlockGraph();
        putInfoToVertex(rsoi, v);
        putVertexToInfo(v, rsoi);
        constraintPHToVertexMap.put(rsoi, v);
        vertexToConstraintPHMap.put(v, rsoi);
        somethingChanged();
    }

    @Override
    protected int getDefaultVertexHeight(final Vertex v) {
        if (vertexToConstraintPHMap.containsKey(v)) {
            return 50;
        } else {
            return VERTEX_HEIGHT;
        }
    }


    @Override
    protected int getDefaultVertexWidth(final Vertex v) {
        if (vertexToConstraintPHMap.containsKey(v)) {
            return 50;
        } else {
            return super.getDefaultVertexWidth(v);
        }
    }

    @Override
    protected void setVertexWidth(final Vertex v, final int size) {
        super.setVertexWidth(v, size);
    }

    @Override
    protected void setVertexHeight(final Vertex v, final int size) {
        super.setVertexHeight(v, size);
    }

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

Related Classes of lcmc.crm.ui.CrmGraph

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.