`
wuce7758
  • 浏览: 177378 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
  • YTT1121: 有网络拓扑发现的源代码么?能不能发我一份学习一下,现在我正要做 ...
    java拓扑图
  • YTT1121: 大神,有网络拓扑发现的源代码么?或者您会编写么?我需要做科研改 ...
    java拓扑图
  • YTT1121: 大神,有网络拓扑发现的源代码么?或者您会编写么?我需要做科研改 ...
    java拓扑图
  • poettang: 求代码分享学习,谢谢!膜拜大神!258026921@qq.co ...
    java拓扑图
  • oiqio: 87836238@qq.com,感谢楼主,来一份~
    java拓扑图

java拓扑图

阅读更多

今天心情不错,公司终于签下了一个综合业务监控系统的大单。到底有多大我也不知道,反正连软件带硬件不算小。按照销售的说法,拿下这个项目一个重要的因素就是要提供一个吸引眼球的demo,而我们做的不错!今天和大家分享一下喜悦和经验!

 

这个项目是一个省级电信运营商的综合业务监控系统。公司跟了好长时间了。由于是一个综合的业务监控系统,涉及的管理资源非常多,又要提供大屏幕显示,所以对系统的呈现效果要求非常高(“政绩工程”么)。前前后后提了很多“无礼”要求,陆续提过的有3D电子地图、3D机房监控、场景仿真、全动画、Google Earth、全Flash等等....弄的我们晕头转向、焦头烂额。其实很多时候,用户自己也不知道想要什么,反正对厂商的要求就是一个字:“炫”,两个字“好看”,三个字:“一定好好看!”(不对,好像是四个字哦)。

 

言归正传,项目跟踪过程中,商务始终告诉我们研发一定要做好一件事:如何做好呈现,尤其是综合的业务监控和呈现,这是获得项目的关键,一定要“出彩”。这个“综合呈现”说起来容易,做起来难。作为省级的电信运营商,内部的各种软硬件系统无数,要监控从上到下、从软到硬,真是烦不胜烦:

  • 基础设施层:主要是网络上的硬件设备,包括交换机、路由器、防火墙、各种主机设备服务器等等;
  • 软件层:这一层主要是主机上面运行的操作系统和各类业务软件系统,例如操作系统(Windows、AIX/HP-UX/LINUX/SOLARIS)、各种中间件(WebLogic、JBoss、IIS、WebSphere等)、数据库(Oracle、Sybase、MySQL)等;
  • 应用层:这一层是指运行在软件层内部的一些细粒度资源,包括一些关键的软件进程、数据库表空间、业务连接、消息队列等等。这一层数量繁杂、数量众多。不过这些资源的状态直接会影响其上层支撑的业务。
  • 业务层:业务层是最顶层,由以上底层资源所共同支撑起来的面向用户的各种业务。对业务最容易理解的描述就是电信提供给客户的具体“服务”。例如视频业务、短信业务、WAP业务、专网业务等等。这些业务才是用户最终关心的东西,因为这些业务才是客户的核心资产,是拿来卖钱的最终产品。一旦出问题,将直接影响money!

此外,还有一大堆机房环境监控的要求,什么配电柜供电、开关状态、UPS、蓄电池、空调、适度温度漏水效仿通风门禁视频.........一大堆。所以,要对业务进行监控,就必须对业务所支撑的各个底层资源进行监控。另外,还要能够对这些资源的关系进行连接和定义,一旦发生故障和问题,能够从上到下迅速定位故障起源,在最短时间内发现问题、解决问题。如何呈现这些依赖关系,并对故障和告警进行纵向定位,是软件呈现的一个核心问题,也是用户最关心的一个问题。

 

用户要求我们先制作一个demo程序,看我们将如何呈现“综合监控”的效果。在充分了解了用户需求之后,经过讨论,我们想做一个完全图形化的分层、跨层的综合监控界面。界面要美观,有动画效果,能够清晰的显示资源依赖关系和告警传播定位。

需要监控和管理的资源

 


 接下来要写代码了。肯定先用我熟悉的TWaver试试。研究了一下,TWaver中有一个平行四边形的Group对象,适合做上图中的“层”的概念。先如下封装并设置属性:

Java代码 复制代码
  1. package demo;   
  2.   
  3. import java.awt.Color;   
  4. import twaver.Group;   
  5. import twaver.TWaverConst;   
  6.   
  7. public class LayerGroup extends Group {   
  8.   
  9.     public LayerGroup() {   
  10.         init();   
  11.     }   
  12.   
  13.     public LayerGroup(Object id) {   
  14.         super(id);   
  15.         init();   
  16.     }   
  17.   
  18.     private void init() {   
  19.         this.setGroupType(TWaverConst.GROUP_TYPE_PARALLELOGRAM);   
  20.         this.putGroupAngle(45);   
  21.   
  22.         this.putGroup3D(true);   
  23.         this.putGroupDeep(10);   
  24.         this.putGroupOutline(false);   
  25.         this.putGroupFillColor(Color.green.darker());   
  26.         this.putGroupGradient(true);   
  27.         this.putGroupGradientFactory(TWaverConst.GRADIENT_LINE_E);   
  28.         this.putGroupHandlerVisible(false);   
  29.         this.putGroupDoubleClickEnabled(false);   
  30.         this.putBorderColor(Color.white);   
  31.         this.putBorderInsets(3);   
  32.         this.putBorderAntialias(true);   
  33.         this.putBorderStroke(TWaverConst.STROKE_SOLID_4);   
  34.         this.putBorderVisible(false);   
  35.         this.putLabelHighlightable(false);   
  36.   
  37.         this.setEnableAlarmPropagationFromChildren(false);   
  38.     }   
  39. }  
package demo;

import java.awt.Color;
import twaver.Group;
import twaver.TWaverConst;

public class LayerGroup extends Group {

    public LayerGroup() {
        init();
    }

    public LayerGroup(Object id) {
        super(id);
        init();
    }

    private void init() {
        this.setGroupType(TWaverConst.GROUP_TYPE_PARALLELOGRAM);
        this.putGroupAngle(45);

        this.putGroup3D(true);
        this.putGroupDeep(10);
        this.putGroupOutline(false);
        this.putGroupFillColor(Color.green.darker());
        this.putGroupGradient(true);
        this.putGroupGradientFactory(TWaverConst.GRADIENT_LINE_E);
        this.putGroupHandlerVisible(false);
        this.putGroupDoubleClickEnabled(false);
        this.putBorderColor(Color.white);
        this.putBorderInsets(3);
        this.putBorderAntialias(true);
        this.putBorderStroke(TWaverConst.STROKE_SOLID_4);
        this.putBorderVisible(false);
        this.putLabelHighlightable(false);

        this.setEnableAlarmPropagationFromChildren(false);
    }
}

 通过这个简单的封装,再往Group里头放几个节点和连线,显示效果如下:

 

用Group制作的“层”效果

 

怎么样,有点意思吧?开头不错,继续改进!再依次排列4个Group,用不同颜色,试试效果:

Java代码 复制代码
  1. createLayer(Color.orange, 50010"7.png""<html><center>软件<br>业务层</center></html>");   
  2. createLayer(Color.green.darker(),18020015"8.png""<html><center>技术<br>应用层</center></html>");   
  3. createLayer(Color.magenta.darker(),2803505"5.png""<html><center>技术<br>软件层</center></html>");   
  4. createLayer(Color.cyan.darker(),4005707"1.png""<html><center>基础<br>设施层</center></html>");  
createLayer(Color.orange, 50, 0, 10, "7.png", "<html><center>软件<br>业务层</center></html>");
createLayer(Color.green.darker(),180, 200, 15, "8.png", "<html><center>技术<br>应用层</center></html>");
createLayer(Color.magenta.darker(),280, 350, 5, "5.png", "<html><center>技术<br>软件层</center></html>");
createLayer(Color.cyan.darker(),400, 570, 7, "1.png", "<html><center>基础<br>设施层</center></html>");

以上代码封装了创建一个层的函数,给定颜色、坐标位置、内部节点数量、图标、文字等等。上面代码中的HTML风格字符串是为了在TWaver中(好像Swing中也是这样的)显示换行的标签。每一个层作为容器包含了很多不同类型的资源。显示效果如下图:

 

四层拓扑图显示效果

 

注意其中的连线有下垂的弯曲效果。这是我以前在做项目封装过的一个TWaver技巧:通过重写twaver的Link的UI类,重新指定path走向实现的。其实也很简单,首先获得link的from点和to点,取值中间点,再把y纵向增加20,把这个点作为quadTo的控制点画曲线即可。对TWaver熟悉的朋友可以看一下这段代码(其实这个效果也是从TWaver Java的demo源代码中学习到的):

Java代码 复制代码
  1. package demo;   
  2.   
  3. import java.awt.Point;   
  4. import java.awt.geom.GeneralPath;   
  5. import twaver.network.TNetwork;   
  6. import twaver.network.ui.LinkUI;   
  7.   
  8. public class InnerLinkUI extends LinkUI {   
  9.   
  10.     public InnerLinkUI(TNetwork network, InnerLink link) {   
  11.         super(network, link);   
  12.     }   
  13.   
  14.     @Override  
  15.     public GeneralPath getPath() {   
  16.         GeneralPath customPath = new GeneralPath();   
  17.         Point p1 = this.getFromPoint();   
  18.         Point p2 = this.getToPoint();   
  19.         customPath.moveTo(p1.x, p1.y);   
  20.         int offset = 20;   
  21.         customPath.quadTo((p1.x + p2.x) / 2, (p1.y + p2.y) / 2 + offset, p2.x, p2.y);   
  22.         return customPath;   
  23.     }   
  24. }  
package demo;

import java.awt.Point;
import java.awt.geom.GeneralPath;
import twaver.network.TNetwork;
import twaver.network.ui.LinkUI;

public class InnerLinkUI extends LinkUI {

    public InnerLinkUI(TNetwork network, InnerLink link) {
        super(network, link);
    }

    @Override
    public GeneralPath getPath() {
        GeneralPath customPath = new GeneralPath();
        Point p1 = this.getFromPoint();
        Point p2 = this.getToPoint();
        customPath.moveTo(p1.x, p1.y);
        int offset = 20;
        customPath.quadTo((p1.x + p2.x) / 2, (p1.y + p2.y) / 2 + offset, p2.x, p2.y);
        return customPath;
    }
}

 用这种link做出的拓扑图比较生动美观。多加几个节点连线就能看出来了:

 

四层复杂拓扑图显示效果

 

不过发现平行四边形Group一个问题:当两个Layer叠加后,下面的节点会被完全覆盖,看不见了。用户说:能不能也能看见?(晕,盖住了也要看见。谁让人家是甲方呢?)于是询问TWaver的人,一个哥们说Group有透明属性。于是试了一下,效果不还错:

Java代码 复制代码
  1. this.putGroupOpaque(false);  
this.putGroupOpaque(false);

 

层的透明与覆盖

 

下一步,关键了:要增加层与层之间资源的“依赖关系”。例如一个Oracle跑在一台主机上,而Oracle中的一个关键表空间需要重点监控,它决定了上层一个视频点播业务是否能够正常。为了体现这个依赖关系,在跨层的节点中间建立link。这个link和层内部link显示上应当有所区别:

Java代码 复制代码
  1. package demo;   
  2.   
  3. import java.awt.Color;   
  4. import twaver.Link;   
  5. import twaver.Node;   
  6. import twaver.TWaverConst;   
  7. import twaver.base.OrthogonalLinkDirectionType;   
  8.   
  9. public class LayerLink extends Link {   
  10.     public LayerLink(Node from, Node to) {   
  11.         super(from, to);   
  12.         init();   
  13.     }   
  14.   
  15.     public LayerLink(Object id, Node from, Node to) {   
  16.         super(id, from, to);   
  17.         init();   
  18.     }   
  19.   
  20.     private void init() {   
  21.         this.putLink3D(true);   
  22.         this.putLinkWidth(4);   
  23.         this.putLinkOutlineWidth(0);   
  24.         this.putLinkColor(Color.lightGray);   
  25.         this.putLinkAntialias(false);   
  26.         this.setLinkType(TWaverConst.LINK_TYPE_ORTHOGONAL);   
  27.     }   
  28. }  
package demo;

import java.awt.Color;
import twaver.Link;
import twaver.Node;
import twaver.TWaverConst;
import twaver.base.OrthogonalLinkDirectionType;

public class LayerLink extends Link {
    public LayerLink(Node from, Node to) {
        super(from, to);
        init();
    }

    public LayerLink(Object id, Node from, Node to) {
        super(id, from, to);
        init();
    }

    private void init() {
        this.putLink3D(true);
        this.putLinkWidth(4);
        this.putLinkOutlineWidth(0);
        this.putLinkColor(Color.lightGray);
        this.putLinkAntialias(false);
        this.setLinkType(TWaverConst.LINK_TYPE_ORTHOGONAL);
    }
}

 显示出来后,效果并不理想,有点乱。主要是没有“跨层”的立体感。

 

跨层连线效果

 

图中跨层的link没有呈现出“穿透层”的感觉,多了以后反而破坏了整个拓扑图的立体感和生动感,需要再改进。最好能够显示“穿层而过”的效果。需求变态么?不弄点猛药还想拿单子么,程序员就是要与各种“不可能”说“不”嘛!经过反复研究和实验,终于做出了一个更好的效果,如下图:

连线的跨层穿透效果

注意观察其中穿层效果,不知大家是否喜欢?



 

连线的透明穿透

 

怎么做到的呢?其实也简单,一点就破,我就不点破了吧,卖个关子先。大家可以先猜猜看,源代码里头也能看到答案。接下来,可以增加一些跨层连线了!看看下图效果:

 

跨层连线的综合效果图

效果还不错吧?销售看过后非常满意,连说有新意。不过还有最后一个很头大的问题:需要显示告警及其传播路线,也就是告警发生后,要从底层一直沿着依赖关系传播到上层。于是开始研究TWaver的AlarmPropagator告警传播器。通过研究发现,其实告警传播也不复杂,主要原理是当告警发生后,它会根据AlarmPropagator的“指示”和定义的规则,沿着一个特定的“路径”进行告警传播。被传播过的地方,会显示一个有告警颜色的外框,标志其告警状态。

 

但是问题是,TWaver的告警传播器是按照“父子关系”进行传播的。也就是默认情况下,告警总是从孩子传给父亲,一直到没有parent为止。按照这个规则,这个demo中一个节点发生告警后,会传播给平行四边形这个层对象,这显然是没有意义的,不符合我的要求。我们需要告警沿着层的“依赖关系”进行跨层传播。于是重写AlarmPropagator!也不难,调试了几个小时,用一个递归法总算搞定了。代码如下:

Java代码 复制代码
  1. package demo;   
  2.   
  3. import java.util.Collection;   
  4. import java.util.Iterator;   
  5. import twaver.AlarmSeverity;   
  6. import twaver.Element;   
  7. import twaver.Node;   
  8.   
  9. public class DemoPropagator {   
  10.   
  11.     public void propagate(Element element) {   
  12.         AlarmSeverity severity = element.getAlarmState().getHighestNativeAlarmSeverity();   
  13.         if (element instanceof Node) {   
  14.             Node node = (Node) element;   
  15.   
  16.             Collection links = node.getAllLinks();   
  17.             if (links != null && !links.isEmpty()) {   
  18.                 Iterator it = links.iterator();   
  19.                 while (it.hasNext()) {   
  20.                     Object o = it.next();   
  21.                     if (o instanceof LayerLink) {   
  22.                         LayerLink link = (LayerLink) o;   
  23.                         if (link.getAlarmState().isEmpty()) {   
  24.                             link.getAlarmState().addAcknowledgedAlarm(severity);   
  25.   
  26.                             Node anotherNode = link.getFrom();   
  27.   
  28.                             if (anotherNode.getAlarmState().isEmpty()) {   
  29.                                 anotherNode.getAlarmState().addAcknowledgedAlarm(severity);   
  30.                                 if (anotherNode != node) {   
  31.                                     propagate(anotherNode);//这里递归!   
  32.                      }   
  33.                             }   
  34.                         }   
  35.                     }   
  36.                 }   
  37.             }   
  38.         }   
  39.     }   
  40. }  
package demo;

import java.util.Collection;
import java.util.Iterator;
import twaver.AlarmSeverity;
import twaver.Element;
import twaver.Node;

public class DemoPropagator {

    public void propagate(Element element) {
        AlarmSeverity severity = element.getAlarmState().getHighestNativeAlarmSeverity();
        if (element instanceof Node) {
            Node node = (Node) element;

            Collection links = node.getAllLinks();
            if (links != null && !links.isEmpty()) {
                Iterator it = links.iterator();
                while (it.hasNext()) {
                    Object o = it.next();
                    if (o instanceof LayerLink) {
                        LayerLink link = (LayerLink) o;
                        if (link.getAlarmState().isEmpty()) {
                            link.getAlarmState().addAcknowledgedAlarm(severity);

                            Node anotherNode = link.getFrom();

                            if (anotherNode.getAlarmState().isEmpty()) {
                                anotherNode.getAlarmState().addAcknowledgedAlarm(severity);
                                if (anotherNode != node) {
                                    propagate(anotherNode);//这里递归!
                     }
                            }
                        }
                    }
                }
            }
        }
    }
}

 

这里代码的逻辑主要是判断是不是跨层link,如果是就沿着它进行传播。噢吼!上面代码好像泄露了上面“穿透Layer”的秘密了,呵呵。最后,再来一个“告警模拟器”来模拟随机、随时发生告警,也就是用一个单独的线程在里面sleep然后生成Alarm并发送到拓扑图的节点上。直接上代码:

Java代码 复制代码
  1. package demo;   
  2.   
  3. import java.util.Iterator;   
  4. import javax.swing.SwingUtilities;   
  5. import twaver.AlarmSeverity;   
  6. import twaver.Element;   
  7. import twaver.TDataBox;   
  8. import twaver.TWaverUtil;   
  9.   
  10. public class AlarmMocker extends Thread {   
  11.   
  12.     private TDataBox box = null;   
  13.     private DemoPropagator propagator = new DemoPropagator();   
  14.   
  15.     public AlarmMocker(TDataBox box) {   
  16.         this.box = box;   
  17.     }   
  18.   
  19.     @Override  
  20.     public void run() {   
  21.         while (true) {   
  22.             try {   
  23.                 Thread.sleep(1 * 1000);   
  24.             } catch (InterruptedException ex) {   
  25.                 ex.printStackTrace();   
  26.             }   
  27.   
  28.             SwingUtilities.invokeLater(new Runnable() {   
  29.   
  30.                 public void run() {   
  31.   
  32.                     if (TWaverUtil.getRandomInt(5) == 1) {   
  33.                         //clear all alarm and propagation.   
  34.                         Iterator it = box.iterator();   
  35.                         while (it.hasNext()) {   
  36.                             Element e = (Element) it.next();   
  37.                             e.getAlarmState().clear();   
  38.                         }   
  39.                     }   
  40.   
  41.                     Element element = box.getElementByID("4." + TWaverUtil.getRandomInt(10));   
  42.                     if (element != null) {   
  43.                         element.getAlarmState().addNewAlarm(AlarmSeverity.getRandomSeverity());   
  44.                         propagator.propagate(element);   
  45.                     }   
  46.                 }   
  47.             });   
  48.         }   
  49.     }   
  50. }  
package demo;

import java.util.Iterator;
import javax.swing.SwingUtilities;
import twaver.AlarmSeverity;
import twaver.Element;
import twaver.TDataBox;
import twaver.TWaverUtil;

public class AlarmMocker extends Thread {

    private TDataBox box = null;
    private DemoPropagator propagator = new DemoPropagator();

    public AlarmMocker(TDataBox box) {
        this.box = box;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }

            SwingUtilities.invokeLater(new Runnable() {

                public void run() {

                    if (TWaverUtil.getRandomInt(5) == 1) {
                        //clear all alarm and propagation.
                        Iterator it = box.iterator();
                        while (it.hasNext()) {
                            Element e = (Element) it.next();
                            e.getAlarmState().clear();
                        }
                    }

                    Element element = box.getElementByID("4." + TWaverUtil.getRandomInt(10));
                    if (element != null) {
                        element.getAlarmState().addNewAlarm(AlarmSeverity.getRandomSeverity());
                        propagator.propagate(element);
                    }
                }
            });
        }
    }
}

 

告警模拟器把最底层的里面的节点随机产生告警,再随机的清除,模拟现实网络的监控状态。然后运行demo,观察其告警传播的路线是否符合预期,也就是沿着层进行传播。

 

注意一个细节:由于上面告警模拟器在一个单独的Thread线程中运行,在产生告警并更改界面时候,需要用SwingUtilities.invokeLater进行代码封装调用,保证它在Swing线程中执行,避免屏幕和界面“花”或不可预知的显示结果。唉,谁让Swing是单线程而且是线程不安全呢?这是个古老话题,就不罗嗦了。

 

废话不多说,直接上最终效果图:

 

 

demo最终效果图

 

双击层动画旋转并放大

 

看到告警跨层传播的效果了吗?最后,根据客户的要求,又增加了一些动画效果:双击平行四边形后,平行四边形会动画变成矩形、动画飞到屏幕中间,然后动画放大内部拓扑图,供用户查看细节;再次双击,平行四边形快速旋转缩小并回到原来位置。demo程序交付并演示后,获得客户高度评价。用我们商务人员的话来说就是:“我们的demo最出彩!”作为程序员,自己做的东西能为公司创造价值和利润就是最大的肯定和成就感!

 

由于demo掺杂了不少公司的代码,我会花一点时间整理一下,弄出一个干净的demo代码贴出来,请感兴趣的朋友留意。我这里也有可以直接运行的jar包,感兴趣的朋友可以留下邮箱。对了,以上信息仅供技术交流之用,请勿用于其它商业用途。

分享到:
评论
57 楼 YTT1121 2016-06-14  
有网络拓扑发现的源代码么?能不能发我一份学习一下,现在我正要做这方面的改进算法工作!借你的参考下!谢谢。邮箱641251443@qq.com ,可以有偿求购,电话18932900205
56 楼 YTT1121 2016-06-14  
大神,有网络拓扑发现的源代码么?或者您会编写么?我需要做科研改算法用。可以有偿获得,请联系18932900205,邮箱641251443@qq.com
55 楼 YTT1121 2016-06-14  
大神,有网络拓扑发现的源代码么?或者您会编写么?我需要做科研改算法用。可以有偿获得,请联系18932900205
54 楼 poettang 2016-02-18  
求代码分享学习,谢谢!膜拜大神!
258026921@qq.com
53 楼 oiqio 2016-01-20  
87836238@qq.com,感谢楼主,来一份~
52 楼 lyyybz 2015-12-21  
954111430@qq.com  膜拜楼主,谢谢啦!
51 楼 qingzhizi 2015-12-17  
膜拜大神。求代码分享学习,谢谢。  qingzhizijingfeng@vip.qq.com
50 楼 haisujiang 2015-08-29  
你好 我的邮箱是haisujiang@163.com 谢谢
49 楼 黑马java 2015-07-09  
969268696@qq.com  楼主求源码啊   楼主好人
48 楼 lu91888 2015-06-30  
lu9188@163.com  效果很棒 不知道现在还有没有相关的代码可以查看
47 楼 huluobo1111 2015-06-22  
目前在做该拓扑,邮箱 2104679873@qq.com
非常感谢
46 楼 kelvin1314 2015-05-21  
你好,我现在正需要这个,麻烦发我一份:
xzy_07@163.com
45 楼 zhangfeilo 2014-09-11  
谢谢分享,邮件:232263448@qq.com
44 楼 wangzj218 2014-07-25  
邮箱 wangzj218@126.com 
非常感谢
43 楼 zhaojianyun 2014-04-25  
感谢分享,请发邮箱:zhaojianyun519@163.com,谢谢
42 楼 rtgerygreyt 2014-04-13  
好炫。想学习一下。927988169@qq.com。谢谢。
41 楼 全站唯一orz 2014-03-28  
感谢楼主分享,万分感谢!!982506409@qq.com
40 楼 lirenzhong5432 2014-03-26  
楼主太给力了,这个我太喜欢了:1039201352@qq.com
39 楼 lcug0825 2013-12-06  
楼主你是怎么转载的?怎么没有下载功能?原文是有源代码提供下载的啊!下面这么多回复你没有一点反应,那些留下邮箱渴望源代码的继续等吧!我找到有源代码提供下载的了。
38 楼 ivan_2000 2013-09-24  
求楼主demo ivantan_vip@163.com

相关推荐

Global site tag (gtag.js) - Google Analytics