TWaver - 專注UI技術

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          小Demo帶來大項目

          Posted on 2010-09-14 18:41 TWaver 閱讀(5985) 評論(2)  編輯  收藏

          今天心情不錯,公司終于簽下了一個綜合業(yè)務監(jiān)控系統(tǒng)的大單。到底有多大我也不知道,反正連軟件帶硬件不算小。按照銷售的說法,拿下這個項目一個重要的因素就是要提供一個吸引眼球的demo,而我們做的不錯!今天和大家分享一下喜悅和經(jīng)驗!

          這個項目是一個省級電信運營商的綜合業(yè)務監(jiān)控系統(tǒng)。公司跟了好長時間了。由于是一個綜合的業(yè)務監(jiān)控系統(tǒng),涉及的管理資源非常多,又要提供大屏幕顯示,所以對系統(tǒng)的呈現(xiàn)效果要求非常高(“政績工程”么)。前前后后提了很多“無禮”要求,陸續(xù)提過的有3D電子地圖、3D機房監(jiān)控、場景仿真、全動畫、Google Earth、全Flash等等….弄的我們暈頭轉(zhuǎn)向、焦頭爛額。其實很多時候,用戶自己也不知道想要什么,反正對廠商的要求就是一個字:“炫”,兩個字“好看”,三個字:“一定好好看!”(不對,好像是四個字哦)。

          言歸正傳,項目跟蹤過程中,商務始終告訴我們研發(fā)一定要做好一件事:如何做好呈現(xiàn),尤其是綜合的業(yè)務監(jiān)控和呈現(xiàn),這是獲得項目的關鍵,一定要“出彩”。這個“綜合呈現(xiàn)”說起來容易,做起來難。作為省級的電信運營商,內(nèi)部的各種軟硬件系統(tǒng)無數(shù),要監(jiān)控從上到下、從軟到硬,真是煩不勝煩:

          • 基礎設施層:主要是網(wǎng)絡上的硬件設備,包括交換機、路由器、防火墻、各種主機設備服務器等等;
          • 軟件層:這一層主要是主機上面運行的操作系統(tǒng)和各類業(yè)務軟件系統(tǒng),例如操作系統(tǒng)(Windows、AIX/HP-UX/LINUX/SOLARIS)、各種中間件(WebLogic、JBoss、IIS、WebSphere等)、數(shù)據(jù)庫(Oracle、Sybase、MySQL)等;
          • 應用層:這一層是指運行在軟件層內(nèi)部的一些細粒度資源,包括一些關鍵的軟件進程、數(shù)據(jù)庫表空間、業(yè)務連接、消息隊列等等。這一層數(shù)量繁雜、數(shù)量眾多。不過這些資源的狀態(tài)直接會影響其上層支撐的業(yè)務。
          • 業(yè)務層:業(yè)務層是最頂層,由以上底層資源所共同支撐起來的面向用戶的各種業(yè)務。對業(yè)務最容易理解的描述就是電信提供給客戶的具體“服務”。例如視頻業(yè)務、短信業(yè)務、WAP業(yè)務、專網(wǎng)業(yè)務等等。這些業(yè)務才是用戶最終關心的東西,因為這些業(yè)務才是客戶的核心資產(chǎn),是拿來賣錢的最終產(chǎn)品。一旦出問題,將直接影響money!

          此外,還有一大堆機房環(huán)境監(jiān)控的要求,什么配電柜供電、開關狀態(tài)、UPS、蓄電池、空調(diào)、適度溫度漏水消防通風門禁視頻………一大堆。所以,要對業(yè)務進行監(jiān)控,就必須對業(yè)務所支撐的各個底層資源進行監(jiān)控。另外,還要能夠?qū)@些資源的關系進行連接和定義,一旦發(fā)生故障和問題,能夠從上到下迅速定位故障起源,在最短時間內(nèi)發(fā)現(xiàn)問題、解決問題。如何呈現(xiàn)這些依賴關系,并對故障和告警進行縱向定位,是軟件呈現(xiàn)的一個核心問題,也是用戶最關心的一個問題。

          用戶要求我們先制作一個demo程序,看我們將如何呈現(xiàn)“綜合監(jiān)控”的效果。在充分了解了用戶需求之后,經(jīng)過討論,我們想做一個完全圖形化的分層、跨層的綜合監(jiān)控界面。界面要美觀,有動畫效果,能夠清晰的顯示資源依賴關系和告警傳播定位。

          需要監(jiān)控和管理的資源
          接下來要寫代碼了。肯定先用我熟悉的TWaver試試。研究了一下,TWaver中有一個平行四邊形的Group對象,適合做上圖中的“層”的概念。先如下封裝并設置屬性:

           1package demo;
           2
           3import java.awt.Color;
           4import twaver.Group;
           5import twaver.TWaverConst;
           6
           7public 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}

          40

          通過這個簡單的封裝,再往Group里頭放幾個節(jié)點和連線,顯示效果如下:

          用Group制作的“層”效果

          怎么樣,有點意思吧?開頭不錯,繼續(xù)改進!再依次排列4個Group,用不同顏色,試試效果:

          1createLayer(Color.orange, 50010"7.png""<html><center>軟件<br>業(yè)務層</center></html>");
          2createLayer(Color.green.darker(),18020015"8.png""<html><center>技術<br>應用層</center></html>");
          3createLayer(Color.magenta.darker(),2803505"5.png""<html><center>技術<br>軟件層</center></html>");
          4createLayer(Color.cyan.darker(),4005707"1.png""<html><center>基礎<br>設施層</center></html>");
          5

          以上代碼封裝了創(chuàng)建一個層的函數(shù),給定顏色、坐標位置、內(nèi)部節(jié)點數(shù)量、圖標、文字等等。上面代碼中的HTML風格字符串是為了在TWaver中(好像Swing中也是這樣的)顯示換行的標簽。每一個層作為容器包含了很多不同類型的資源。顯示效果如下圖:

          四層拓撲圖顯示效果

          注意其中的連線有下垂的彎曲效果。這是我以前在做項目封裝過的一個TWaver技巧:通過重寫twaver的Link的UI類,重新指定path走向?qū)崿F(xiàn)的。其實也很簡單,首先獲得link的from點和to點,取值中間點,再把y縱向增加20,把這個點作為quadTo的控制點畫曲線即可。對TWaver熟悉的朋友可以看一下這段代碼(其實這個效果也是從TWaver Java的demo源代碼中學習到的):

           1package demo;
           2
           3import java.awt.Point;
           4import java.awt.geom.GeneralPath;
           5import twaver.network.TNetwork;
           6import twaver.network.ui.LinkUI;
           7
           8public 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}

          25

          用這種link做出的拓撲圖比較生動美觀。多加幾個節(jié)點連線就能看出來了:

          四層復雜拓撲圖顯示效果

          不過發(fā)現(xiàn)平行四邊形Group一個問題:當兩個Layer疊加后,下面的節(jié)點會被完全覆蓋,看不見了。用戶說:能不能也能看見?(暈,蓋住了也要看見。誰讓人家是甲方呢?)于是詢問TWaver的人,一個哥們說Group有透明屬性。于是試了一下,效果不還錯:

          1this.putGroupOpaque(false);

          層的透明與覆蓋

          下一步,關鍵了:要增加層與層之間資源的“依賴關系”。例如一個Oracle跑在一臺主機上,而Oracle中的一個關鍵表空間需要重點監(jiān)控,它決定了上層一個視頻點播業(yè)務是否能夠正常。為了體現(xiàn)這個依賴關系,在跨層的節(jié)點中間建立link。這個link和層內(nèi)部link顯示上應當有所區(qū)別:

           1package demo;
           2
           3import java.awt.Color;
           4import twaver.Link;
           5import twaver.Node;
           6import twaver.TWaverConst;
           7import twaver.base.OrthogonalLinkDirectionType;
           8
           9public 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}

          29

          顯示出來后,效果并不理想,有點亂。主要是沒有“跨層”的立體感。

          跨層連線效果

          圖中跨層的link沒有呈現(xiàn)出“穿透層”的感覺,多了以后反而破壞了整個拓撲圖的立體感和生動感,需要再改進。最好能夠顯示“穿層而過”的效果。需求變態(tài)么?不弄點猛藥還想拿單子么,程序員就是要與各種“不可能”說“不”嘛!經(jīng)過反復研究和實驗,終于做出了一個更好的效果,如下圖:

          連線的跨層穿透效果

          注意觀察其中穿層效果,不知大家是否喜歡?

          連線的透明穿透

          怎么做到的呢?其實也簡單,一點就破,我就不點破了吧,賣個關子先。大家可以先猜猜看,源代碼里頭也能看到答案。接下來,可以增加一些跨層連線了!看看下圖效果:

          跨層連線的綜合效果圖

          效果還不錯吧?銷售看過后非常滿意,連說有新意。不過還有最后一個很頭大的問題:需要顯示告警及其傳播路線,也就是告警發(fā)生后,要從底層一直沿著依賴關系傳播到上層。于是開始研究TWaver的AlarmPropagator告警傳播器。通過研究發(fā)現(xiàn),其實告警傳播也不復雜,主要原理是當告警發(fā)生后,它會根據(jù)AlarmPropagator的“指示”和定義的規(guī)則,沿著一個特定的“路徑”進行告警傳播。被傳播過的地方,會顯示一個有告警顏色的外框,標志其告警狀態(tài)。

          但是問題是,TWaver的告警傳播器是按照“父子關系”進行傳播的。也就是默認情況下,告警總是從孩子傳給父親,一直到?jīng)]有parent為止。按照這個規(guī)則,這個demo中一個節(jié)點發(fā)生告警后,會傳播給平行四邊形這個層對象,這顯然是沒有意義的,不符合我的要求。我們需要告警沿著層的“依賴關系”進行跨層傳播。于是重寫AlarmPropagator!也不難,調(diào)試了幾個小時,用一個遞歸法總算搞定了。代碼如下:

           1package demo;
           2
           3import java.util.Collection;
           4import java.util.Iterator;
           5import twaver.AlarmSeverity;
           6import twaver.Element;
           7import twaver.Node;
           8
           9public 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}

          41

          這里代碼的邏輯主要是判斷是不是跨層link,如果是就沿著它進行傳播。噢吼!上面代碼好像泄露了上面“穿透Layer”的秘密了,呵呵。最后,再來一個“告警模擬器”來模擬隨機、隨時發(fā)生告警,也就是用一個單獨的線程在里面sleep然后生成Alarm并發(fā)送到拓撲圖的節(jié)點上。直接上代碼:

           1package demo;
           2
           3import java.util.Iterator;
           4import javax.swing.SwingUtilities;
           5import twaver.AlarmSeverity;
           6import twaver.Element;
           7import twaver.TDataBox;
           8import twaver.TWaverUtil;
           9
          10public 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}

          告警模擬器把最底層的里面的節(jié)點隨機產(chǎn)生告警,再隨機的清除,模擬現(xiàn)實網(wǎng)絡的監(jiān)控狀態(tài)。然后運行demo,觀察其告警傳播的路線是否符合預期,也就是沿著層進行傳播。

          注意一個細節(jié):由于上面告警模擬器在一個單獨的Thread線程中運行,在產(chǎn)生告警并更改界面時候,需要用SwingUtilities.invokeLater進行代碼封裝調(diào)用,保證它在Swing線程中執(zhí)行,避免屏幕和界面“花”或不可預知的顯示結果。唉,誰讓Swing是單線程而且是線程不安全呢?這是個古老話題,就不羅嗦了。

          廢話不多說,直接上最終效果圖:

          demo最終運行界面

          雙擊層動畫旋轉(zhuǎn)并放大

          看到告警跨層傳播的效果了嗎?最后,根據(jù)客戶的要求,又增加了一些動畫效果:雙擊平行四邊形后,平行四邊形會動畫變成矩形、動畫飛到屏幕中間,然后動畫放大內(nèi)部拓撲圖,供用戶查看細節(jié);再次雙擊,平行四邊形快速旋轉(zhuǎn)縮小并回到原來位置。demo程序交付并演示后,獲得客戶高度評價。用我們商務人員的話來說就是:“我們的demo最出彩!”作為程序員,自己做的東西能為公司創(chuàng)造價值和利潤就是最大的肯定和成就感!

          由于demo摻雜了不少公司的代碼,我花了一點時間整理一下,弄出了一個干凈的demo代碼,請見附件,請感興趣的朋友請直接下載,歡迎留言討論。 解壓demo.zip后,中有兩個jar包和run.bat,雙擊run.bat就可以運行demo。我是用JDK6編譯的,請各位確保首先安裝了JAVA 6環(huán)境。如有任何運行問題請留言。

          demo所限內(nèi)容僅供技術交流和參考,請慎作商業(yè)用途。

          補充:

          看到留言中很多朋友都說“第一次看到用程序做demo”,也把我弄“驚詫”了。因為自己從業(yè)這些年基本上都是用程序做demo,已經(jīng)習以為常,甚至成為理所當然了。看到很多朋友說“用PPT和美工圖片”做DEMO,確實感覺自己有點out了。在電信、電力這些行業(yè)里面,項目都比較大、復雜,沒有一定的商務和技術實力以及經(jīng)驗是很難獲得項目機會的。PPT作為產(chǎn)品介紹和各種交流肯定是沒問題的;但如果說要做大項目的“系統(tǒng)演示”那可是夠“空對空”的。可以想象一下:如果我們是局方、甲方或客戶,要花幾百萬做一個項目,給各個廠商一個月的時間來準備一個技術交流和產(chǎn)品演示,我們是愿意把項目交給用精美PPT演示的廠商,還是愿意給效果同樣漂亮但用實實在的程序或DEMO來演示的廠商呢?誰家更有實力?誰家更重視項目?誰家更有技術和人才?誰家更有想法?誰家更有經(jīng)驗?這個問題幾乎不用回答。

          一個有實力的軟件公司,打大單不拿點真家伙,光靠美工弄幾個花里胡哨的圖片或者PPT就能拿下項目,那絕對是太不可思議了。我接觸的這些公司哪個不是靠多年的行業(yè)積累和系統(tǒng)經(jīng)驗,哪次面對這樣的大戰(zhàn)役不是要抽出一兩個技術好手來加班加點的做些真家伙(半真也行,老系統(tǒng)扣出一部分模塊和代碼,就算在此基礎上修修改改去運行也可)去演示?甚至有的時候去演示的幾乎就是可以上線的系統(tǒng),或在另外一個老的類似項目緊急改進出來的半成品系統(tǒng)。如果沒有這些項目和技術經(jīng)驗做沉淀和積累,一旦中標,很多時候系統(tǒng)上線只給3個月的時間,完全從頭來個瀑布式的從需求分析、從頭開發(fā)?做夢吧。現(xiàn)在行業(yè)競爭越來越慘烈,客戶要求越來越高越復雜,技術變化快,你不能做到又快又好的提供系統(tǒng)和解決方案,只能靠邊站了。

          這是一個大的監(jiān)控系統(tǒng),涉及很多子系統(tǒng)和其他業(yè)務系統(tǒng)。這里僅僅是一個簡潔的高層次全網(wǎng)監(jiān)控界面,是很小一部分,是一個小UI而已。但是這個UI會被投射到一個2*4的大型液晶屏幕墻上,讓全屋子的人抬頭就能看到全網(wǎng)的鏈接情況、告警情況;讓公司領導經(jīng)常過來看到;讓兄弟省市領導經(jīng)常參觀到。所以,它的作用不可小視(提高形象的作用不也是作用么)。這也是為什么客戶這么重視的原因。另外麻雀雖小,五臟俱全;以管窺豹也可以時見一斑。我們搞技術的就是應當多思考多創(chuàng)新多學習多交流、踏踏實實在細節(jié)上下功夫,也許才能更好的體現(xiàn)我們的價值。

          如果demo所體現(xiàn)出來的UI呈現(xiàn)思路和設計想法或者代碼中的技巧能夠給大家?guī)硪稽c點啟發(fā),本人就感到非常非常滿足了!

          謝謝各位!

          附:帶窗口的Demo運行圖


          評論

          # re: 小Demo帶來大項目[未登錄]  回復  更多評論   

          2010-09-14 18:48 by 菜鳥
          真佩服你們的技術和耐心。

          # re: 小Demo帶來大項目  回復  更多評論   

          2014-12-08 13:49 by dtya
          膜拜一下。。。

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 彭州市| 林州市| 尉犁县| 沾化县| 固原市| 正蓝旗| 封丘县| 社会| 新龙县| 商南县| 邯郸市| 紫云| 河池市| 天台县| 武平县| 武城县| 华坪县| 屏边| 泾阳县| 牟定县| 三都| 延安市| 石林| 麦盖提县| 安仁县| 阳信县| 额敏县| 合江县| 盐城市| 若羌县| 福州市| 保山市| 莱西市| 高清| 垦利县| 和龙市| 岳普湖县| 乌拉特后旗| 永和县| 襄樊市| 延安市|