随笔 - 59, 文章 - 4, 评论 - 184, 引用 - 7
数据加载中……

2005年11月15日

一切都在变

blog也搬迁了:http://blog.sina.com.cn/liuwendao

来武汉快三年了,留在北京的最后一件物件-电吉它,也被我拿到武汉来了

我们这么混,能成功吗?
立帖为证

posted @ 2007-09-16 23:21 fisher 阅读(1434) | 评论 (0)编辑 收藏

来自苏联的笑话

  军事演习区,一位妇女驾车在大桥前被一名军官拦住:“对不起,公民,您现在不能过去。”“为什么?”“这座桥在一小时前被炸毁了。”“您能告诉我这究竟是怎么回事吗?”“很抱歉,不行。我本人已于2小时前阵亡。”
  
  
  伊万看电视,是勃在演讲。伊万觉得无聊,换了一个,还是勃在演讲,又换一个,还是他。伊万一连拨了几十个台,最后累了,准备关电视。这时候电视画面变成一个KGB,怒气冲冲地叫:“你再敢换?再敢换?再换判你10年大牢!”
  
  
  某日苏联举行国庆**,沿着大街开来了炮兵、机械化步兵、坦克、自行火炮、战术导弹、战略核导弹,破坏力一个比一个大;队列末尾却是两个带公文包的矮子。在看台上勃列日涅夫惊讶地说:“这两个人破坏力比核导弹还大!他们是什么人?”
  KGB头子说:“不是我的人。”
  国防部长说:“没见过他们。”
  苏联总理说:“他们是国家计委的...”
  
  
  戈尔巴乔夫视察农场,看到猪儿乖乖,一时兴起站在猪中间照了张像。
  待到报纸准备发表时,编辑为照片的标题犯了难??
  “戈尔巴乔夫同志和猪在一起”不好。
  “猪和戈尔巴乔夫同志在一起”也不好。
  报纸出版后,照片下的说明文字是??
  “左起第三位是戈尔巴乔夫同志”
  
  
  勃列日涅夫和美国总统卡特在瑞士开会,休息时间两个人很无聊,就开始比谁的保膘更忠诚。卡特先来,他把自己的报膘叫进来,推开窗(外面是20层楼)说:“约翰,从这里跳下去!”
  约翰哭着说:“你着么能这样呢,总统先生,我还有老婆孩子呐。”
  卡特被感动了,流着泪说是自己不对,叫约翰走了,然后抡到勃列日涅夫,他也大声叫自己的保膘伊万。
  “伊万,从这里跳下去!”
  伊万二话不说就要往下跳,卡特一把抱住他说:“你疯了?跳下去会死的!”
  伊万一边挣扎着要跳下去一边说:“放开我,混蛋,我还有老婆孩子呐。”
  
  
  早年莫斯科修地铁,工程师将方案上报斯大林审批。不久,方案发下来,上面有斯大林的签字。
  细心的工程师发现图纸上多了一个圆型的茶杯印,于是莫斯科地铁就多了一条环形线。
  
  
  斯大林肃反时期的苏联。一位内务人民委员部审判员结束一天的审判工作,回到办公室,突然一个人大笑起来。对面办公桌的同事奇怪的问道:“有什么好笑的事吗?”“是啊,”审判员用手帕擦着笑出来的眼泪:“一个很好笑的笑话……”“哦?说来听听?”“你疯了吗?!我刚判了说这笑话的家伙五年苦役!”
  
  
  苏联30年代肃反扩大化时期。内务人民委员部的一间牢房里关了三个人,彼此间谈起坐牢的原因。
  第一个人说,我因为反对了党书记彼得罗夫;
  第二个人说,我因为支持了彼得罗夫;
  第三个人说,我就是彼得罗夫。
  
  
  戈尔巴乔夫和他的司机开着车在路上,戈尔巴乔夫突发异想,说:让开!我来开。一个老警察和一个新警察在路上值勤,见一辆车歪歪扭扭的开得疯快,老警察就对新警察说:去!好好收拾一下。新警察将车拦住之后,又没趣没趣地回来了。老警察问:怎么?里面是谁?新警察回答说:我也不知道里面是谁,反正给他开车的是戈尔巴乔夫。
  
  
  美国外交代表团到苏联访问,苏联接待官员陪他们参观“建设的伟大成就”,并且得意的说:“到了下一个五年计划,每个苏联家庭都可以拥有一架私人飞机!”美国人惊讶的问:“ 他们要飞机干什么呢?”苏联官员说:“当然有用啊……譬如你在莫斯科听说列宁格勒开始供应面包了,你可以马上开着飞机赶去排上队。”
  
  
  一位公民打电话到基辅电台问主持人:“共产主义到底是艺术还是科学?” 主持人说:“我也不清楚,但我肯定不是科学” “为什么?” “如果是科学的话,他们应该拿狗做试验。”
  
  
  斯大林在大会上引经据典地说:“马克思和列宁说1+1=2,而托洛茨基和布哈林说1+1不等于3。是托洛茨基和布哈林说的对呢?还是马克思和列宁说得对呢?”下面听众一脸疑惑,“毫无疑问,是马克思和列宁说的对!”底下热烈鼓掌,“托洛茨基和布哈林是帝国主义派来的间谍,说1+1不等于3的人罪不容赦……”
  
  
  列宁快去世了,叫赶快把继承人斯大林召进克里姆林宫来,临终有几句话要嘱托。“不瞒你说,我还有一个隐忧啊,斯大林。”“说吧,亲爱的伊里奇。”斯大林专心地听着。“那就是,人们会跟你走吗?不知你想过了没有?”“他们一定会跟我走的。”斯大林强调说,“一定会!” “但愿如此。”列宁说,“我只是担心,万一他们不跟你走,你怎么办?”“没问题!”斯大林答道:“那他们就得跟你走!”
  
  
  集体农庄庄员伊万在河里捉到一条大鱼,高兴的回到家里和老婆说:“看,我们有炸鱼吃了!”
  “没有油啊。”
  “那就煮!”
  “没锅。”
  “烤鱼!”
  “没柴。”
  伊万气死了,走到河边把鱼扔了回去。那鱼在水里划了一个半圆,上身出水,举起右鳍激动地高呼:“斯大林万岁!”
  
  
  “瑞典能否建立共产主义”?
  “不能。”
  “为何?”
  “列宁同志说了:共产主义不在山那边。”
  
  
  一个苏联KGB特工和一个美国CIA特工互相吹嘘各自的机构是如何的杰出。
  那个KGB特工首先发言说,“我们拥有你们美国过去15年里所有导弹发射的详细数据。”
  CIA特工说:“这不算什么。我们CIA掌握着你们苏联未来15年里所有当选的中央委员名单。”
  
  
  一艘航行在大海上的轮船快要沉了,船长叫乘客赶紧跳海,但他喊了半天没有一个人跳,一个社会学家说我来喊,他去喊过之后所有的人都跳下海去了。船长觉得奇怪,问他是怎么喊的,社会学家回答说:我对法国人说这样跳下去很浪漫,我对西班牙人说这样跳下去很潇洒,我对英国人说这样跳下去是一种体育运动,我对美国人说这样跳下去有利可图,我对苏联人说这样跳下去是革命行动。
  
  
  在苏联的一趟公交车,一个男的非常谦恭地问站在他身旁的另一个男的:“同志,请问您是克格勃吗?”
  那人答道:“不是。”
  又问:“那您有没有亲戚或朋友是克格勃呢?”
  答:“没有。”
  还问:“那您是否跟克格勃有些交往或联系?”
  答:“没有,你要干嘛啊!”
  该男生气地说:“干嘛,他妈的,你踩着我的脚了!”
  
  
  赫鲁晓夫作报告,批判斯大林。忽然,有人从台下递了个纸条,写道:当他做坏事的时候,你在哪里?赫鲁晓夫一看这个条子,大声怒喝道:“是谁写的,给我站出来。”台下雅雀无声,没有人站出来。赫鲁晓夫接着说道:“同志们,我当时就和你们现在一样,你们知道我当时为什么不敢站出来了吧”
  
  
  勃列日涅夫:同志们,美国人登上了月球,我们不能再等了,党决定让你们上太阳。
  宇航员:总书记同志,我们会被烧死的。
  勃列日涅夫:没关系,同志们,党都替你们想好了,你们晚上去。
  
  
  电影《这里的黎明静悄悄》试映时,由于其中有部分裸体镜头,因此主管电影审核的官员曾试图把这部电影禁演,幸亏勃列日涅夫内部观看时感动得热泪盈眶,这部优秀的电影才有幸与观众见面,成为世界电影史上不朽的篇章。而另一部电影由于其中有主人公走到教堂时跪地痛哭的镜头,被电影审核官员认为是宣扬宗教而准备勒令裁掉这部分内容,恰恰勃列日涅夫看到这里时动了感情,因此这个镜头得以幸存下来。
  
  
  当年的捷克斯洛伐克政府中,设立了一个“海军部”,结果,苏联老大哥就对捷克人说:你们是内陆国家,设什么海军部?
  捷克人回答说:那你们不是也设了文化部吗?

posted @ 2007-01-20 15:15 fisher 阅读(2175) | 评论 (0)编辑 收藏

[调查]国内有多少人使用MINA?

最近看到越来越多的人使用mina,甚至在线下也碰到合作公司的库中使用MINA,出于好奇,尝试一下用自己的blog做一下调查,访问本blog的兄弟,如果您使用MINA作为自己的通讯基础件,请留言介绍一下自己

posted @ 2006-12-27 13:00 fisher 阅读(4492) | 评论 (20)编辑 收藏

随想

软件开发的世界里充满了不理解,客户不理解软件是怎样开发的、经理不理解开发人员、开发人员不理解指挥者。

问题在于软件开发惊人的困难,造成很少有开发人员能够说出软件自始至终是怎样开发的,并能够对这个过程中会遇到的不同选择所隐含的结果表现出适度的理解。

在软件开发人员还很年轻的时候(十几岁或二十出头),他们通常集中精力学习和使用技术,称自己为perl程序员、Linux专家、EJB开发人员、.NET开发人员等。对他们来说技术是最重要的事情。因为技术在不断的变化,年轻的程序员倾向于大致学习一个技术,在一到两个项目中使用,然后重新开始学习新技术或者是学习以前使用过的技术的最新发展。这里的问题是,他们一遍又一遍的重复的学习的不过是同样的低层次基本技能的不同风味。

幸运的是,很多开发人员在经过了几轮技术学习之后逐渐意识到:一旦用COBOLJavaC#等语言为事务控制编写过代码,就会开始认识到基本的、本质的东西是不变的。不同环境下的数据库访问、用户界面设计等领域也是同样的情况。不久以后,开发人员逐渐认识到无论具体的技术怎样,很多基础性的东西是保持不变的,这些基础性的东西有的在学校里讲过,有的没有。
这种认识经常发生在开发人员接近三十岁或刚过三十岁的时候,通常是人们开始稳定下来,结婚、买房的时候。这是比较幸运的情况,因为上面提到的这些新的个人需求意味着他们不可能再投入大量的时间去学习新的技术,他们需要用这些时间和家庭成员在一起。突然的,高层次的角色如项目负责人、项目经理、(非敏捷的)建模人员等对他们变得非常有吸引力,因为这些角色不需要持续花费大量的时间和精力去学习新技术。于是,等到开发人员开始真正学到技艺的时候,他们已经处于离开开发人员角色的转变过程中了。所幸的是,新的“小年轻”不断的跟上来,这个过程在不断的循环重复。最终的结果是:大部分最活跃的正在开发软件的人通常不是最称职的做这件事的人,而他们自己甚至还不知道。

posted @ 2006-07-24 11:31 fisher 阅读(2236) | 评论 (6)编辑 收藏

今天学会一个新名词 - Troll

来自pythoncn的maillist,呵呵,挺有意思
-------------
像Chris Qie <longroad1999@gmail.com>这样的在公共论坛用侮辱性言语挑起骂战并从中获取某种不知名快感的人,在Usenet文化中有一个名称:

  • Troll

  • Troll作动词是钓鱼的意思,指那些人发表某种言论后等待别人的攻击性回复,从而获得快感。Troll还有一个意思是斯堪的纳维亚神话中一种长相丑陋、爱恶作 剧、令人讨厌的巨人,和那些找骂的人有相似之处,因此也被引申过来形容那些 人,做名词使用。回troll的贴则被称为feed the trolls,即给trolls喂食。
  • Trolls有很多种,像Chris Qie只是其中一种,即使用种族歧视性语言激怒别人,好让别人回帖骂他。comp.lang.python上著名的troll: Xah Lee则是长年在各个 script语言讨论组上交叉张贴无关内容或用错误百出的话语对某种语言或者文化进 行攻击。但无论那种troll,他们的目的都是一样的:想通过怪诞的举动引起别人 的注意。这是一种病态心理,是一种未成熟,类似小孩“人来疯”似的举动。
  • Trolls的存在对公共空间是破坏性的。它们的post会引起很多人回帖,甚至会有情绪激动者采用谩骂的方式回敬,这些人被称为trollhunter。这些行为正中trolls 的下怀,使他们获得被骂的快乐,从而更加积极的trolling。而且即使 trollhunter的动机是好的,也会给论坛带来不好影响,使其他用户接收到大量无 关信息和攻击性信息,成为受害者。公共空间的和谐性被破坏。
  • Trolls最愿意看到别人回他的贴,无论是正儿八经指出他的错误还是义愤填膺的对他谩骂。对一个troll来说,最能让他感到沮丧的则是没有人理他。而我们,正是 应该让他们沮丧,失去trolling的动力。
  • 对待trolls的方法,一方面要靠大家自觉,克制自己回帖的冲动,不给他们喂食。

另一方面,在邮件列表这种有管理员的公共空间,可以向管理员提出封禁trolls的 提案。

  • 下图是我从c.l.python上Keith Thompson对Xah Lee的trolling行为提醒公众的帖子中拷贝过来的图片(请使用等宽字体观看)
        +-------------------+             .:\:\:/:/:.
       |   PLEASE DO NOT   |            :.:\:\:/:/:.:
       |  FEED THE TROLLS  |           :=.' -   - '.=:
       |                   |           '=(\ 9   9 /)='
       |   Thank you,      |              (  (_)  )
       |       Management  |              /`-vvv-'\
       +-------------------+             /         \
               |  |        @@@          / /|,,,,,|\ \
               |  |        @@@         /_//  /^\  \\_\
 @x@@x@        |  |         |/         WW(  (   )  )WW
 \||||/        |  |        \|           __\,,\ /,,/__
  \||/         |  |         |      jgs (______Y______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
  • 历年python-cn 各种列表著名 Troll 案例:

    1. 051106-RE:python的无奈

      唉,没想到这里乡下贱农(的贱崽)还真不少,
      说城市人酒囊饭袋是农村人聊以自慰的一点点资本,
      就象美国黑人在奥运会夺得金牌时获得的快乐一样,
      我就是酒囊饭袋怎么样?
      可惜就是你爸在田间地头为我流汗流泪的劳作养活的我,
      哈哈?心理不平衡了?谁让你爹是农民!
      还"龙村",真够恶心的,一辈子你都是低贱的乡下人 ,
      低贱!哈哈!就是血染你家老母老爹,然后发迹的,你能怎样?HOHO~
      
      -- 是标准的运用城市差异来挑起回复的实例,在中国这样的发展中国家尤其奏效
  • 060112-RE:Web开发有必要选Python(或者是ruby)么?        

  •              -- 开始,仅仅是比较典型的"是否最优"探讨,后来立即转向人身攻击,是经典的通过技术争论引发回复的实例

posted @ 2006-06-13 10:27 fisher 阅读(13579) | 评论 (9)编辑 收藏

程序员的进化——从学生到首席执行官(转)


/*-------------------------------------------

  程序员的进化——从学生到首席执行官

翻译 2002 王咏刚
http://www.contextfree.net/
转译自 Omri's Computer Humor Page
http://www.cs.bgu.ac.il/~omri/Humor/
-------------------------------------------*/


--------------------------------------------------------------------------------
中学阶段

      10 PRINT "HELLO WORLD"
      20 END
--------------------------------------------------------------------------------
大学一年级

      program Hello(input, output)
        begin
        writeln('Hello World')
        end.
--------------------------------------------------------------------------------
大学高年级

      (defun hello
        (print
        (cons 'Hello (list 'World))))
--------------------------------------------------------------------------------
初级程序员

      #include <stdio.h>
      void main(void)
      {
        char *message[] = {"Hello ", "World"};
        int i;

        for(i = 0; i < 2; ++i)
        printf("%s", message
);
        printf("\n");
      }
--------------------------------------------------------------------------------
编程老鸟

      #include <iostream.h>
      #include <string.h>

      class string
      {
      private:
        int size;
        char *ptr;

      public:
        string() : size(0), ptr(new char('\0')) {}

        string(const string &s) : size(s.size)
        {
        ptr = new char[size + 1];
        strcpy(ptr, s.ptr);
        }

        ~string()
        {
        delete [] ptr;
        }

        friend ostream &operator <<(ostream &, const string &);
        string &operator=(const char *);
      };

      ostream &operator<<(ostream &stream, const string &s)
      {
        return(stream << s.ptr);
      }

      string &string::operator=(const char *chrs)
      {
        if (this != &chrs)
        {
        delete [] ptr;
        size = strlen(chrs);
        ptr = new char[size + 1];
        strcpy(ptr, chrs);
        }
        return(*this);
      }

      int main()
      {
        string str;

        str = "Hello World";
        cout << str << end

        return(0);
      }
--------------------------------------------------------------------------------
编程高手

      [
      uuid(2573F8F4-CFEE-101A-9A9F-00AA00342820)
      ]
      library LHello
      {
        // bring in the master library
        importlib("actimp.tlb");
        importlib("actexp.tlb");

        // bring in my interfaces
        #include "pshlo.idl"

        [
        uuid(2573F8F5-CFEE-101A-9A9F-00AA00342820)
        ]
        cotype THello
      {
      interface IHello;
      interface IPersistFile;
      };
      };

      [
      exe,
      uuid(2573F890-CFEE-101A-9A9F-00AA00342820)
      ]
      module CHelloLib
      {

        // some code related header files
        importheader(<windows.h>);
        importheader(<ole2.h>);
        importheader(<except.hxx>);
        importheader("pshlo.h");
        importheader("shlo.hxx");
        importheader("mycls.hxx");

        // needed typelibs
        importlib("actimp.tlb");
        importlib("actexp.tlb");
        importlib("thlo.tlb");

        [
        uuid(2573F891-CFEE-101A-9A9F-00AA00342820),
        aggregatable
        ]
        coclass CHello
      {
      cotype THello;
      };
      };

      #include "ipfix.hxx"

      extern HANDLE hEvent;

      class CHello : public CHelloBase
      {
      public:
        IPFIX(CLSID_CHello);

        CHello(IUnknown *pUnk);
        ~CHello();

        HRESULT __stdcall PrintSz(LPWSTR pwszString);

      private:
        static int cObjRef;
      };

      #include <windows.h>
      #include <ole2.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include "thlo.h"
      #include "pshlo.h"
      #include "shlo.hxx"
      #include "mycls.hxx"

      int CHello::cObjRef = 0;

      CHello::CHello(IUnknown *pUnk) : CHelloBase(pUnk)
      {
        cObjRef++;
        return;
      }

      HRESULT __stdcall CHello::PrintSz(LPWSTR pwszString)
      {
        printf("%ws\n", pwszString);
        return(ResultFromScode(S_OK));
      }

      CHello::~CHello(void)
      {

      // when the object count goes to zero, stop the server
      cObjRef--;
      if( cObjRef == 0 )
        PulseEvent(hEvent);

      return;
      }

      #include <windows.h>
      #include <ole2.h>
      #include "pshlo.h"
      #include "shlo.hxx"
      #include "mycls.hxx"

      HANDLE hEvent;

      int _cdecl main(
      int argc,
      char * argv[]
      ) {
      ULONG ulRef;
      DWORD dwRegistration;
      CHelloCF *pCF = new CHelloCF();

      hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

      // Initialize the OLE libraries
      CoInitializeEx(NULL, COINIT_MULTITHREADED);

      CoRegisterClassObject(CLSID_CHello, pCF, CLSCTX_LOCAL_SERVER,
        REGCLS_MULTIPLEUSE, &dwRegistration);

      // wait on an event to stop
      WaitForSingleObject(hEvent, INFINITE);

      // revoke and release the class object
      CoRevokeClassObject(dwRegistration);
      ulRef = pCF->Release();

      // Tell OLE we are going away.
      CoUninitialize();

      return(0);
      }

      extern CLSID CLSID_CHello;
      extern UUID LIBID_CHelloLib;

      CLSID CLSID_CHello = { /* 2573F891-CFEE-101A-9A9F-00AA00342820 */
        0x2573F891,
        0xCFEE,
        0x101A,
        { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
      };

      UUID LIBID_CHelloLib = { /* 2573F890-CFEE-101A-9A9F-00AA00342820 */
        0x2573F890,
        0xCFEE,
        0x101A,
        { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
      };

      #include <windows.h>
      #include <ole2.h>
      #include <stdlib.h>
      #include <string.h>
      #include <stdio.h>
      #include "pshlo.h"
      #include "shlo.hxx"
      #include "clsid.h"

      int _cdecl main(
      int argc,
      char * argv[]
      ) {
      HRESULT hRslt;
      IHello     *pHello;
      ULONG ulCnt;
      IMoniker * pmk;
      WCHAR wcsT[_MAX_PATH];
      WCHAR wcsPath[2 * _MAX_PATH];

      // get object path
      wcsPath[0] = '\0';
      wcsT[0] = '\0';
      if( argc > 1) {
        mbstowcs(wcsPath, argv[1], strlen(argv[1]) + 1);
        wcsupr(wcsPath);
        }
      else {
        fprintf(stderr, "Object path must be specified\n");
        return(1);
        }

      // get print string
      if(argc > 2)
        mbstowcs(wcsT, argv[2], strlen(argv[2]) + 1);
      else
        wcscpy(wcsT, L"Hello World");

      printf("Linking to object %ws\n", wcsPath);
      printf("Text String %ws\n", wcsT);

      // Initialize the OLE libraries
      hRslt = CoInitializeEx(NULL, COINIT_MULTITHREADED);

      if(SUCCEEDED(hRslt)) {

        hRslt = CreateFileMoniker(wcsPath, &pmk);
        if(SUCCEEDED(hRslt))
      hRslt = BindMoniker(pmk, 0, IID_IHello, (void **)&pHello);

        if(SUCCEEDED(hRslt)) {

      // print a string out
      pHello->PrintSz(wcsT);

      Sleep(2000);
      ulCnt = pHello->Release();
      }
        else
      printf("Failure to connect, status: %lx", hRslt);

        // Tell OLE we are going away.
        CoUninitialize();
        }

      return(0);
      }
--------------------------------------------------------------------------------
黑客初阶

      #!/usr/local/bin/perl
      $msg="Hello, world.\n";
      if ($#ARGV >= 0) {
        while(defined($arg=shift(@ARGV))) {
        $outfilename = $arg;
        open(FILE, ">" . $outfilename) || die "Can't write $arg: $!\n";
        print (FILE $msg);
        close(FILE) || die "Can't close $arg: $!\n";
        }
      } else {
        print ($msg);
      }
      1;
--------------------------------------------------------------------------------
黑客有成

      #include <stdio.h>
      #define S "Hello, World\n"
      main(){exit(printf(S) == strlen(S) ? 0 : 1);}
--------------------------------------------------------------------------------
黑客高手

      % cc -o a.out ~/src/misc/hw/hw.c
      % a.out
--------------------------------------------------------------------------------
黑客大虾

      % cat
      Hello, world.
      ^D
--------------------------------------------------------------------------------
初级经理

      10 PRINT "HELLO WORLD"
      20 END
--------------------------------------------------------------------------------
中级经理

      mail -s "Hello, world." bob@b12
      Bob, could you please write me a program that prints "Hello, world."?
      I need it by tomorrow.
      ^D
--------------------------------------------------------------------------------
高级经理

      % zmail jim
      I need a "Hello, world." program by this afternoon.
--------------------------------------------------------------------------------
首席执行官

      % letter
      letter: Command not found.
      % mail
      To: ^X ^F ^C
      % help mail
      help: Command not found.
      % damn!
      !: Event unrecognized
      % logout
--------------------------------------------------------------------------------

posted @ 2006-05-18 17:14 fisher 阅读(1055) | 评论 (0)编辑 收藏

Hello World的196种写法

还记得孔乙己说:茴香豆的‘茴’字有四种写法吗?现在我们的知识份子已经进步了,看看Hello World的196种写法:)

http://man.lupaworld.com/content/develop/hello/HelloWorld.shtml

posted @ 2006-05-18 16:58 fisher 阅读(867) | 评论 (0)编辑 收藏

趴在窗户上看长江

下午写完设计,趴在武汉办公室的窗户上看风景,天气好的时候,左面长江右边东湖都可以看到,其实想想在武汉出差也挺不错的,呵呵

posted @ 2006-05-17 18:03 fisher 阅读(582) | 评论 (0)编辑 收藏

关于人.....

彼得·德鲁克在他的《卓有成效的管理者 》当中,阐述了知识工作者管理的秘诀,那就是知识工作者的工作效率来自于对其工作的有效性以及他的工作是否有所成就。这本1966年出版的管理学书籍经过近50年的时间,反而越发显得适应潮流。
而卓有成效的知识工作管理者现在显得比过去任何时候都要短缺,也比现时任何人才都要短缺。在现时这个信息爆炸,案例丰富的年代,战略眼光与部署格局对于一个企业人才不再如此重要,对于企业战略,任何有管理常识、了解企业实情的人大都可以分析得很到位,关键是要找到合适的人去实施。知道什么样的人合适,以及找到这个合适的人,成为企业家最需要做的事情。而成为那个合适的人,则成为草根阶层走入舞台中央的必备能力。

附一篇来自经济观察报刘军的《笨蛋,最重要的是人!
---------------------------------

      2005年10月8日管理大师彼得·德鲁克曾经讲过一个他和《时代》《财富》等杂志的出版人亨利·鲁斯交往的故事。鲁斯有个很好的新杂志方案——试图创办“从美国人思考角度出发”的高格调文化杂志,他去向德鲁克求教。德鲁克分析了一番说,“这份企划案很棒,不过晚了50年。”接着,他对鲁斯说出了最重要的话:“此外,《时代》的人也无法胜任。我猜,你想鼓励一些外面的作家来为这本杂志执笔,并以一般大众为读者群。但是你的专长却是叫自己手下人搞定,因此大有不同。” 
      鲁斯回答说,“我来向你请教,正因为我猜想你会这么说。”他因而放弃了这个计划,因为他深知人的重要性。经过十多年的西方管理教育和知识传播,中国企业管理者已经熟知战略的理性分析,与重视人比起来更重视事,另外先建立制度、而不是依靠人的观念也被广泛接受。不过,我却逐渐感觉到,在这些问题上我们可能有点矫枉过正,对于知识型工作、对于管理,或许人更重要,是应该优先考虑的。 
      9月底,索尼新任CEO、美国人霍华德·斯特林格(Howard Stringer)宣布索尼的战略调整计划:全球裁员一万人,缩减工厂数目,出售1200亿日元的不动产与股票等非核心资产,对消费电子业务进行架构调整、将权力集中到这一业务的最高主管手中。在过去五年中,索尼逐渐失去消费电子霸主地位,业绩很不理想,这背后的根本原因正是这些战略调整所触及的问题。对于这一点,大概稍微有点管理常识的人都知道,我想索尼前CEO出井伸之自然了然于心,他之下的索尼高管也清楚。不过,大概只有霍华德·斯特林格、索尼历史上第一个外国人CEO、这个日本文化的局外人才能推行上述改革。 
     战略,有管理常识、了解企业实情的人大都可以分析得很到位,但真正去做,就需要“合适的人”。我一直相信,选择霍华德·斯特林格作为继任者,是出井伸之的最重要的决策,体现这个亚洲最优秀的商业领袖的领导才能。卡洛斯·戈恩已经因成功在日产汽车(Nissan)实现大逆转而成为全球最知名的管理者之一,他当初所做的关闭工厂与裁员、破除日本式企业联盟等措施,都是众所周知的弊端,但惟有他这个合适的人才能推动变革。斯特林格和戈恩都是在这种情境下最合适的人,只是恰巧他们都是外国人。 
      Google、微软和李开复之间的纷争一直没有停息的迹象。在这个过程中李开复把自己再次塑造成了最优秀的技术专家形象,但如果相信这一点,我们就错误理解了Google的智慧。如果要一流的中文搜索研发人才,Google的最佳人选绝对不是李开复,而可能是李彦宏。如果它的战略诉求点是这个,它可以百度买下,从而得到李彦宏。但是,Google在中国,需要的哪里是什么技术专家、研发中心?现在Google中国战略要的合适的人是据称是“技术专家”的李开复,但他在公众心目中的号召力和政府公关能力才是Google所看重的。 
      我们也可以循同样的视角来看待雅虎和阿里巴巴之间的联姻。这一次是把雅虎中国的业务交道马云手中去让他照料,因为对于谁了解中国市场和能够帮助雅虎发现中国市场潜力这个问题,马云是最佳答案。雅虎在中国的最近两次战略行动目标都首先是为了“人”。上一次是雅虎在中国收购3721,反而让其老板周鸿一担任中国区总裁,从而让雅虎中国从跨国公司在华分支机构这样的角色变成勇猛的中国本土企业。但在经历一段发展时期之后,雅虎中国就需要更合适的人。我们可以认为,这是雅虎、阿里巴巴联姻的主要原因之一。 
      先建立制度、体系,而不是“因人设事”这样的观点被广泛接受,可是,我们忘记了这个观念背后的工业化背景:所有人的都被当成了可替换的零件,所以制度体系最重要。但是,对于知识型工作来说,特别是非重复的创造性工作,每个人的工作方式、结果都截然不同。 
      我们所设计的制度体系,在当前的人员安排下也似乎运转正常。但是,由于这些人是无法替换的,人走了,看似精妙的体系也就出现出现问题了。这个时候,是去做不可能完成的任务:寻找适合制度体系的一摸一样的人?还是更改体系?或者看得更远点,在现在的情境下,我们根本就不该把制度体系的重要性神话到这种程度?针对知识型工作的讨论,和上文对最高管理者的讨论并非没有联系,因为在我看来,管理工作是最重要的、最具创造性的知识工作。 
      吉姆·柯林斯在《从优秀到卓越》说卓越公司是“先人后事”:这些公司的主管不是先确定目的地(先有方向、愿景、战略),然后才把人们引向那里;他们首先让合适的人上车(不合适的人自然请下车),然后才决定去向何处。他所说的虽是方向、远景,但大体上和制度是同一类型的事物。我们都应该了解,合适的人更重要,那些看似严密的战略分析和完善的制度体系有时候会变成令人难以忍受的障碍,因为它们和“合适的人”可能是完全矛盾的,这些人通常都难以放到一个既定的模子中去。 

posted @ 2006-04-25 23:19 fisher 阅读(1037) | 评论 (0)编辑 收藏

webwork2.2.2的dtd解析问题(感谢飞云小侠)

今天将webwork2.2.1更换成webwork2.2.2,出现了一个奇怪的异常,每次启动后,都会报出:
org.xml.sax.SAXParseException: Element type "global-exception-mappings" must be declared.
com.opensymphony.xwork.config.ConfigurationException: Caught exception 
while loading file xwork.xml
    with nested exception 
org.xml.sax.SAXParseException: Element type 
"global-exception-mappings" must be declared.
如果将xwork.xml中的global-exception-mappings注释掉便好

头疼了几个小时解决不了,不得不求助飞云小侠
飞云小侠一出手果然不同,马上定位了问题所在
就是这句:
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">

原来虽然几次升级webwork.jar,但是xwork.xml的DTD解析还是用的原来的DTD,顶多就是改了DTD的地址,也就是将这句
 "http://www.opensymphony.com/xwork/xwork-1.1.dtd">
改为这样
 "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">

而实际上解析DTD是靠的前面那句
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" >
原来一直是
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" >
于是就出现了上面的问题
多谢飞云小侠的帮助^_^

posted @ 2006-04-21 15:07 fisher 阅读(1267) | 评论 (0)编辑 收藏

重读温博格

自工作以来,我就养成了睡前读书的习惯,这一年在武汉,实在买不到一些好书,每次回北京总要带很多书过来,最近再次面临回京购书的局面,在回京之前总不能闲着,于是从去年看过的书中乱翻,以第一感觉来决定自己最想重读那本书,结果选中了温博格的《成为技术领导者-解决问题的有机方法》
两年前,当一位同窗好友集齐全套的温博格系列的时候,我曾很不屑的说他:一个人写那么多书,质量显然没保证,买他作甚?现在看来,当时确是井底之蛙了,温博格的书中少有瑕疵,尤其是后期作品,读来总是让人意犹未尽。
过去的几年里,我看过很多书,无论是早期GOF的设计模式,Martin Fowler的企业架构系列,还是Rod的J2EE开发厚厚的两卷本,甚至我最喜欢的POSA系列,虽然都会给人技术方面成长的感觉,但最好情况下也只是让我感觉到技艺的变化。
而管理方面的书籍,则大多走入两个极端,要么是学院式的分析解构,要么是江湖术士式的技巧集合。就像过去我曾很喜欢DEBORAH G. ANCONA的那本组织行为学和曾士强的中国式管理,但现在看来,DEBORAH关注组织多过于关注团队,而曾士强则过于强调中国人的心理情结,实用归实用,但可能不太适合技术人员的口味,读他的书让人感觉有些厚黑,让我常常想到一句俗语:人老精,鬼老灵。

而温博格的写作方式,如同Ken在英文版序中所说,会引起大量的思考,对温博格的文字的思考,思考对温博格文字的思考,以及对自身思考的思考....通过温博格的书,让我体会到的事是,读书,有时候是为了实用,而的有时候,则纯粹是为了过瘾。
本书中温博格的MOI模型,实际上不是一个行为指导手册,而是带来了更加宏观和可思考的空间,让你对自己在团队中的行为更加有目的性,也更加有效。我仍然记得两年前,上述同窗好友在某技术论坛发表的一篇名为《任务分解和任务分配》的帖子,现在看来,在该贴中提出的Effective Communication仍然太过于关注技术视角了,而现在,我则更加注重人文关怀,包括对技术架构。这一点,在本书第十章得到了精彩的阐述。

下面的内容,来自于本书第三章摘录

各种各样的想法是解决问题的核心,没有想法就不可能找到解决方案,但想法太多又会杂乱无章,领导者需要对想法的交流进行有效的管理。以下是领导者常用的12种典型的管理想法交流的方法以及点评。
    >  为团队提供一个聪明的想法。尽管这是最显而易见的领导者行为,而且有时新的想法的确会起到关键性作用,但事实上真正全新的想法是非常罕见的。比发掘一个新的聪明想法更重要的是创建一个合适的环境,是能够解决问题的想法一旦提出就能被大家意识到。
    >  鼓励和借鉴有用的旧想法。尽管有些领导者不愿意承认,但他们实际上是根深蒂固的模仿者。最优秀的领导者不仅承认这一点,而且将其视为一门艺术而精心培育。
    >  认真完善团队成员提出的想法。大部分解决问题型领导者在完善一个想法上花费的时间比提出这个想法多上百倍的精力。
    >  放弃自己的想法并支持团队采纳的想法,但只有当每个成员都充分了解你的想法时才予以放弃。放弃或保留你的想法是相当简单的,难的是要做到理智和公正。
    >  尽管时间压力很大,仍然不要吝啬花时间听其他人解释他们的想法。迫于时间压力,大部分想法没有经过充分理解就被否决了,事实上,其中一些想法可以为我们节省的时间是花在了解错误想法上时间的上百倍。
    >  检验别人提出的想法。在任何给定的环境中,绝大部分的想法都是没用的,但到底哪些才是有用的呢?领导者要做的就是分析和检验这些想法。
    >  为了保持想法的交流,不要轻易否定团队成员的想法。尽管检验这些想法是非常重要的,但几乎没有什么想法会危险到使我们来不及重新考虑一下我们的第一反应,就必须立刻否定。
    >  如果你不得不否定一个想法,那么一定要明确,你所否定的只是这个想法,而不是提出这个想法的人。解决问题型领导者一直清楚地知道,并不是所有的想法对每个问题都有帮助,但他们更知道,团队中的每一个成员都是有用的。
    >  在给出你的想法之前要先对它进行检验。没有人可以聪明到提出所有建设性的想法,而一个喋喋不休地发表自己未经仔细考虑的想法的人却能有效地阻止其他人给出自己的想法。
    >  当时间和人力吃紧时,不要再考虑新的想法而应该专注于现有的想法。
    >  鼓励团队成员放弃以前曾经成功过,但并不适用于现在情况的想法。
    >  如果一个已被否定的想法对问题的其他部分有价值,就应该重新采纳它。其实没有绝对不好的想法,之所以“不好”只是因为它们出现在不适当的地点或时间。

posted @ 2006-03-18 06:44 fisher 阅读(1340) | 评论 (1)编辑 收藏

欢迎加入“osgi观察者”googlegroup

去年年底,osgi R4发布,eclipse建立equinox项目,标志着以osgi为核心的组件管理模型正式进入使用阶段,鉴于今年年初jsr291的推出,osgi正式走向java世界的前端,遂建立osgi观察者group,希望能同所有关心和喜爱osgi的国内技术人员共同进步。

加入osgi观察者:

Google Groups Subscribe to osgi观察者
Email:
Browse Archives at groups.google.com

posted @ 2006-03-06 13:37 fisher 阅读(1014) | 评论 (1)编辑 收藏

善待自己每一天

最近的忙碌加上精神压力,让我患上了胃病,每天吃完饭都会难受好一阵子,给自己学医的儿时好友打电话,被劝之:“人生苦短,要学会善待自己每一天”。遂发此文为戒。

附一篇BJUG中Tin发的文章《白天纽约黑夜巴黎》
-------------------------------
白天纽约黑夜巴黎
-------------------------------
【王文华/文】

我在赶些什么?我耗尽青春用尽全力,拼命追求身外之物,结果我真的比别人有钱、有名吗?更重要的,我真的因此而快乐吗?远方有广阔的地平线,为何我还在原地摇过时的呼拉圈?

纽约和巴黎,代表了我人生的两个面向。纽约是白天,巴黎是黑夜。纽约是前半生,巴黎是下半场。

三十五岁之前,我认定纽约是世上最棒的城市。我在加州念研究所,毕业后迫不及待地去纽约工作。一做五年,快乐似神仙。我爱纽约的原因跟很多人一样:她是二十世纪以来世界文化的中心。丰富、方便。靠着地铁和出租车,你可以穿越时间,前后各跑数百年。人类最新和最旧、最好和最坏的东西,纽约都看得见。

所以在纽约时,我把握每分每秒去体会。白天,我在金融机构做事,一天十小时。晚上下了班,去NYU学电影,一坐四小时。在那二十多岁的年纪,忙碌是唯一有意义的生活方式。活着,就是要把自己榨干,把自己居住的城市,内外翻转过来。

这种想法并不是到纽约才有的。其实从小开始,台湾人就过着纽约生活。纽约生活,充满新教徒的打拚精神和资本主义的求胜意志。相信人要借着不断努力,克服万难、打败竞争。活着的目的,是更大、更多、更富裕、更有名。权力与财富,是纽约人的两个上帝。而能帮你走进天堂的鞋,就是事业、事业、事业。

在这种弱肉强食的生活方式,为了保持领先,每个人都在赶时间、抢资源。进了电梯,明明已经按了楼层的钮,那灯也亮了,偏偏还要再按几下,彷佛这样就可以快一点。出了公司,明明已经下班了,却还要不停讲手机,摇控每一个环节。在纽约,为达目的,可以不择手段,甚至赶尽杀绝。在纽约,没有坏人,只有失败者。

台湾,是不是也变成这样?

每一件事,都变成工作。上班当然是工作,下班后的应酬也是工作。有人谈恋爱是在工作,甚至到酒店喝酒、KTV狂欢,脸上都杀气腾腾,准备拚个你死我活。

我曾热烈拥抱这种生活,并着迷于这种因为烧烤成功而冒出的焦虑。这种焦虑让我坐在椅子边缘,以便迅速地跳起来闪躲明枪暗箭。这种警觉性让我练就了酒量和胆量、抗压性和厚脸皮。但也养成了偏执和倔强、优越感和势利眼。在纽约时我深信:能在这里活下来的,都是可敬的对手。黯然离开的,统统是输家。人生任何事,绝对要坚持到底。半途而废的,必定有隐疾。在这不睡的城市,每天我醒来,带着人定胜天的活力,跟着法兰克辛纳屈唱〈纽约?纽约〉:「如果你能在纽约成功,你可以在任何地方成功!」是的,在纽约,现代的罗马竞技场,我要和别人,以及自己,比出高低。

这套想法,在我三十五岁以后,慢慢改变。

第一件动摇我想法的,是父亲的过世。我父亲一生奉公守法、与人为善。毫无不良嗜好,身体健康地像城堡。七十二岁时,他得了癌症、引发中风,经历了所有的痛苦和羞辱。他一生辛勤工作、努力存钱、坚信现在的苦可以换得更好的明天。我们也相信一分耕耘、一分收获,用在纽约拚事业的精神照顾他。但两年的治疗兵败如山倒,最后他还是走了。父亲逝世的那天,我的价值系统崩溃了。我一路走来引以为傲的「纽约精神」,没想到这么脆弱。

不止在病床,也在职场。当我在企业越爬越高,才发现「资本主义」在职场中也未必灵验。上过班的都知道,很少公司真的是「开放市场」、「公平竞争」。大部分的同事都觉得你不是朋友、就是敌人。职场上伟大的,未必会成功。成功的,有时很渺小。很多人一辈子为公司鞠躬尽瘁,最后得到一支纪念笔。那些卷款潜逃的,反而变成传奇。

慢慢的,我体会到:世上有一种比「善有善报、恶有恶报」更高、更复杂的公平。人生有另一种比「功成名就」更幽微、更持久的乐趣。那是冲冲冲的美式资本主义,所无法解释的。

我能在哪里找到那种公平和乐趣呢?我想过西藏、不丹、非洲、纽西兰。然后,我注意到法国。

住纽约时,法国是嘲讽的对象。身为经济、科技、和军事强权的美国,谈起法国总是忍不住调侃一番。法国是没落的贵族,值得崇拜的人都已作古。法国人傲慢,高税率让每个人都很慵懒。动不动就罢工,连酒庄主人都要走上街头。

搬回台湾后,普罗旺斯、托斯卡尼突然流行。我看了弗朗西斯?梅思的《美丽的托斯卡尼》,其中一句话打动了我:「在加州,时间像呼拉圈。我扭个不停,却停在原地。在托斯卡尼,我可以在地中海的阳光下,提着一篮李子,逍遥地走一整天。」

是啊!我在赶些什么?我耗尽青春用尽全力,拚命追求身外之物,结果我真的比别人有钱、有名吗?更重要的,我真的因此而快乐吗?远方有广阔的地平线,为何我还在原地摇过时的呼拉圈?

当我重新学习法国,我发现法国和美国代表两种截然不同的生活方式。美国人追求人定胜天,凡事要逆流而上。法国人讲究和平共存,凡事顺势而为。纽约有很多一百层的摩天大楼,巴黎的房子都是三百年的古迹。纽约不断创新,巴黎永远有怀旧的气息。巴黎人在咖啡厅聊天,纽约人在咖啡厅用计算机。纽约有人潮,巴黎有味道。纽约有钞票,巴黎有蛋糕。

不论是政府或个人,法国人都把精神投注在食、衣、住、行等「身内之物」。就让美国去做老大哥吧。要征服太空、要打伊拉克、要调高利率、要发明新科技,都随他去。法国人甘愿偏安大西洋,抽烟、喝酒、看足球、搞时尚。当美国人忙出了胃溃疡,法国人又吃了一罐鹅肝酱。

讲到吃,法国有三百种起司、光是波尔多就有五十七个酒的产区。晚上六点朝咖啡厅门口一坐,一杯红酒就可以聊三个小时。九点再去吃晚餐,一直吃到隔天凌晨。他们在吃上所花的时间,跟我们上班时数一样。但讽刺的是:他们没有「All
You Can Eat」。

吃很重要,但也要会挑时间,朋友介绍我去试一家法国餐厅,提醒我他们礼拜二、四晚上休息。「为什么?」我问。他说:「因为主厨要回家看足球。」

聪明的主厨懂法律。法国法律规定一周工作最多三十五小时,大部分的人一年有五周的假期。而美国人把加班当作自己有价值的表示,度假时还拿着手机回E-mail。法国人比美国人会玩。每年六月的巴黎音乐节,从午后到深夜,几百场露天音乐会在各处同时举行,人多到地铁都暂停收费。每年十月的「白夜」,平日入夜就打烊的店面,彻夜营业到清晨七点。每年夏天,巴黎市政府在塞纳-马恩省河右岸布置了三段、总长一.八公里的人工海滩。细砂、吊床、躺椅、棕榈树,自然海滩有的景致这里都有,让没有钱去海边度假的民众,也可以享受到海滩风光。

当然,法国这么深厚的文化,不可能只从吃喝玩乐而来。美国人读书,为了考证照。法国人读书,为了搞情调。每年十月的读书节,大城市的火车站内,民众轮流上台朗诵诗句。书店营业到天明,整晚有现场演奏的乐曲。「美食书展」选在铜臭味最重的证券交易所举办。小镇书展的书直接「长」在树上,读者必须爬到树上,把书摘下来品尝。

一直跟着美国走的台湾人,会心动吗?

我心动了。十一月我到巴黎,一位法国朋友来接待我。临走前我问他:「明天你要干嘛?」

「我要去银行。」

「然后呢?」我问。

「我不懂你的意思......」

对我来说,「去银行」是吃完午饭后跑去办的小事。对法国人来说,这是他一天全部的行程。法国人总是专心而缓慢的,每天把一件小事做好。

这样的生活,对美国或台湾人来说,实在是太颓废了。的确也是。法国失业率接近10%,高税率让雇主宁愿打烊休息,免得帮员工缴税。巴黎闹区纸醉金迷,但郊区的少数民族却没有工作机会。这些都是黑暗面,但对于每日被强光烤焦的台湾人,阴暗也许提供了喘息空间。生命的终点都一样,有钱人的丧礼只是比较多人上香。不断的追赶只是提前冲向谢幕,为什么不把时间花在慢慢为生命暖场?你不需要一辈子鞠躬尽瘁、死而后已。你可以偶尔伸伸懒腰、安步当车。

我从巴黎回来,台北并没有改变。关了两周的手机再度响起,一通电话找不到我的人会连续狂call十通。和朋友见面,他很关心地问我:「好了,你现在工作也辞了、欧洲也去了,接下来有什么projects?」

「Projects」?多么纽约的字眼。

我真想说:「好好生活,不就是人生最大的project?」但我知道在熙来攘往的台北街头,在不到四十岁的年纪,这样说太矫情了。况且,我今天之所以有钱有闲享受法式生活,不也正因为我曾在美式生活中得到很多利益?我仍热爱工作、热爱纽约,但已不用像二十岁时一样亦步亦趋、寸步不离。

所以我说:「我还是会早起,白天努力写作。但到了晚上,我想关掉手机。」

世界少了我,其实无所谓。但我少了我,还剩什么?

他笑一笑:「你这是用纽约来过白天,用巴黎来过黑夜。」

唉,他讲得真好!这应该是一个完美的妥协吧。也许有一天,我能创造自己的「白夜」,让白天和黑夜融合在一起。但我还没到那个境界。

「明天星期一,你要干嘛?」他问。

「我要去银行。」

「然后呢?」

我张大眼睛,停顿了一下。

「然后呢?」他追问。

「然后我会摩拳擦掌,认真地写一篇文章。」


我们是不是也应该学一学法国人呢?提高些生活质量,注意身体。

posted @ 2006-02-28 11:04 fisher 阅读(1005) | 评论 (4)编辑 收藏

MINA vs. QuickServer

很久没更新blog了,实在太忙,今天看到有朋友在我去年的blog《MINA is a good framwork 》中回复提到比较一下MNA和QuickServer,遂写一篇小文:

First for all, QuickServer is licensed as LGPL, and MINA as ASL

从我个人角度而言,去年看过QuickServer的源码,我在项目中采用的每一个框架或类库都会做综合评价,通常不会是一个原因导致我采用或没有采用某个库或框架,具体最后没有采用QuickServer的原因忘记了,但是当时给我的总体感觉是,QuickServer虽然很方便,但不会让我在架构上得到新的好处。而它最大的优点则是,支持JDK1.3(如果没记错的话),另外就是License的问题

下面看一看来自TrusinLee的评论:

Thank for the information about another network application framework.  I found a few differences:

* QuickServer supports blocking mode.  (MINA supports only non-blocking mode, but you can make your operation block at your will.)
* QuickServer provides GUI-based admin.  (MINA doesn't have one yet, but will have full JMX support soon, which is a standard.)
* QuickServer uses java.util.logging.  (MINA uses SLF4J, which is a safe replacement of commons-logging.)
* QuickServer uses its own XML settings.  (MINA provides Spring framework integration instead.)
* QuickServer can specify maximum number of clients allowed.  (MINA can do this using a filter, but not implemented by default.  Of course, this will be implemented as an overload prevention filter.)
* QuickServer team has one crew.  (MINA has three crews.)
* QuickServer project started in 2003.  (MINA started in 2005.)
* QuickServer has a difference event handler interface from MINA.  (You'll have to compare it by yourself.  IMHO, MINA has one simple enough handler which covers all QuickServer provides.)
* QuickServer doesn't support UDP at all.  (MINA does)
* QuickServer doesn't support client-side API at all.  (MINA does)
* QuickServer integrated authentication and text protocol in its core.  (MINA didn't and they are considered as a cross-cutting concern that a filter should take care of.  IMHO, MINA is more extensible here.)


至于对MINA更详细的介绍,可以看看我去年翻译的MINA的Tutorial

MinaTutorialInChinese

MINA的应用,在MINA的Testimonials中有两个项目:
开源Flash server:red5
http://ludonet.leonardo.it/的game server
还有,就是MINA所在的项目,Apache的LDAP

posted @ 2006-02-24 21:58 fisher 阅读(6227) | 评论 (18)编辑 收藏

一个SWT Application如何转职成为RCP Appliactioin

昨天david问到如何将旧的swt应用转成一个RCP应用,昨晚胃疼难忍,于是草草说了一下,就早早上床休息了,早上起来又想起这件事情,遂在这里说一下思路
下面说一下我的思路
(注:以下观点未经证实,请自行斟酌使用)

一个旧的SWT应用,应该都是有一个main函数里初始化一些UI组件,然后run一个事件循环

在RCP中,由于是基于Eclipse的插件体系,也就是说,使用我前面那篇文章发布的RCP Application,是可以直接发布成Eclipse插件的
所以,对于UI组件的控制也要遵循Eclipse的插件体系的代码要求,看看Hello RCP模板中的几个类:ApplicationActionBarAdvisor、ApplicationWorkbenchAdvisor、ApplicationWorkbenchWindowAdvisor以及RCPPlugin,想起了什么?对,OSGI

我们只要将原swt的main函数中初始化的ui组件,放入到这几个Advisor中进行初始化

将下拉菜单项的ui组件的初始化工作放入到ApplicationActionBarAdvisor的如下方法:

    protected void makeActions(IWorkbenchWindow window) {
    }



    
protected void fillMenuBar(IMenuManager menuBar) {
    }


将其他UI组件初始化工作放入到ApplicationWorkbenchWindowAdvisor的如下方法:

    public void preWindowOpen() {

        IWorkbenchWindowConfigurer configurer 
= getWindowConfigurer();

        configurer.setInitialSize(
new Point(400300));

        configurer.setShowCoolBar(
false);

        configurer.setShowStatusLine(
false);

        configurer.setTitle(
"Hello RCP");

    }


至于ApplicationWorkbenchAdvisor这个类,我想你一定想起了Eclipse中的Workbench概念
在这里,可以定义当这个RCP作为plugin的时候的Worbench的透视图的一些属性。

-----------------------------------

最后,基于Eclipse3.1的product方式的RCP程序将获得同Eclipse相同的插件体系支持
也就是说:你的应用本身就是基于Eclipse Platform的,这样,你的程序也可以接受插件插入了(如果你设计的好的话^_^)
另外,还有其他很多好处,比如在线升级功能的自动绑定啊,帮助功能的使用啊等等
想一想,你的程序将既能作为单独的程序运行,又能作为Eclipse的插件运行,而且还跨平台,think about it...
So....try it now, you will get more

posted @ 2006-01-17 11:02 fisher 阅读(1738) | 评论 (0)编辑 收藏

使用Eclipse3.1的新特性方便的发布你的RCP Product

     摘要: Eclipse3.1刚刚release的时候,它的RCP发布功能就很吸引我,当时正好有个小东西要做,就用了这个功能发布了一个小程序,似乎很多人推荐用NSIS,但是我觉得Eclipse的这个功能似乎更方便,几乎不用担心任何部署的问题。
  阅读全文

posted @ 2006-01-16 23:16 fisher 阅读(3710) | 评论 (4)编辑 收藏

N久没有更新了-大杂烩-blogjava年终看点

Blog有一个多月没有更新了,今年8个月的忙碌生活,以及最后两个月的突击使我彻底失去了热情,无论是工作还是写blog,目前只想每天休息休息,看看书。
12月底回了一趟北京,然后又顺路回大连家中办了点事情,待了三天,又飞回武汉着手招人和培训的工作,为明年的工作做准备,技术上有些事情还得自己动手,不知道这忙碌的生活什么时候可以停歇.....

在妖精群里还跟非鱼说要写一篇关于架构师职责的Blog,暂时还是没心情写,不过自从那次在群里讨论过架构师的职责之后,似乎已经有很多人写了这方面的文章,在blogjava中就有很多了,架构师之家的文章数目也一下激增起来。

近期blogjava也是好戏连台,虽然不写,看着也是过足瘾了。

canonical是个很好的写手,学理论物理出身的思维缜密果然不同凡响,关于架构师的职责那篇,已经把能写的都写尽了。江南白衣 搞的springside.org.cn看起来也很吸引人,有理想的好青年的典范。非鱼的几篇关于架构的文章也写的很扎实,预备役架构师是有些谦虚了,呵呵。Jerry在经过一段时间的忙碌之后,似乎又再次复活了,以每天一到两篇的速度持续更新blog,让我着实佩服他的精力,几篇blog的涉猎范围so广,足见积累之深。老庄最近似乎也是琐事缠身,除了在上月底被Rx反敲丧钟的时候露了几次脸,就没怎么出现过,看来年底了哪里都是忙碌的时候。Raimundox近期多次出手,除了对老庄的《丧钟》系列的再次释疑之外,还为我们贡献了Smalltalk的入门手册,实为近期技术blog中风头最劲的一个了。飞云小侠也更新渐少了,除了今天预告了WebWork2.2的发布,已经10天没更新了。近期weide技术架构评估也是颇为扎眼,算是近期最全面完整的一篇技术文章了,显然是花了精力了,难怪达到14709的访问量 :)

2005年让我感觉到人的精力毕竟有限,以及,一个纯技术人员能发挥的能量实在太小了,虽然不情愿,但这可能促使我更早的脱离纯技术岗位,真是凌乱的一年......

posted @ 2006-01-11 00:36 fisher 阅读(718) | 评论 (4)编辑 收藏

【ESB专题】之六 - System Management及其相关模式

 

开发一个基于消息的解决方案是不容易的事情,在生产中操作这样一个产品同样也是一个挑战:一个基于消息的集成解决方案一天可以产生、路由和转换成千上万的消息。我们不得不处理异常、效率瓶颈或改变合作系统。而为了使事情变得更加有挑战性,组件经常被分布在不同的平台和机器上,甚至位于不同的地理位置。

 

System Management包含以下几种模式

l         Control Bus

l         Detour

l         Wire Tap

l         Message History

l         Message Store      

l         Smart Proxy

l         Test Message

l         Channel Purger

 

 

除了与生据来的复杂性、分布式集成的规模以及个性化的应用之外,低耦合的架构使得测试和debug变得更加困难。Martin Fowler将这个症状称为“架构师的梦想,开发者的梦魇”。低耦合的架构原则以及间接的依赖于外部系统提供了灵活性。然而,测试一个消息生产者不了解消息消费者的系统可能会是一个挑战。另外异步的和时间相关的消息使得事情变的更加复杂。举例来说,消息方案可能被设计没有被成消息生产者者必须从接受者那里得到一个回应。同样的消息基础设施通常保证传输消息,但不能保证传输时间。这是的开发基于消息传送结果的测试用例变得困难。

 

当监控一个消息解决方案,我们可以在两个抽象层面上跟踪消息流。一个典型的系统管理方案监控多少消息被发送或者它多长时间得到一个被处理的消息。这些监控方案不检查消息数据,除了可能会检查消息头中的几个字段(比如消息标识或者消息历史)。与之相对的,BAMbusiness activity monitoring)方案聚焦于包含在消息中的有效数据,举例来说,发生在过去一小时的所有订单的金额。System Management中的很多模式都足够通用并可以用在以上两个目的中(监控消息头或者消息内容)。然而,由于BAM本身就是一个新领域,并且需要从数据仓库中获得很多数据(有些我们根本就没有涉及到),我们决定在系统管理的内容中讨论这些模式。

 

系统管理模式被设计用于为保持一个基于消息的复杂系统的运转所提出的需求并提供工具。System Management的模式涉及三个种类:监控和控制,观察和分析消息流量,测试和调试

 

监控和控制

 

一个Control Bus提供一个单独的控制点来对一个分布式方案进行监控和管理。它将多个组件连接到一个中心管理控制台,这里可以显示每个组件的状态并且监控通过每个组件的消息流量。控制台同时也可以用于发送控制命令给组件,比如,转变消息流。

我们可能想要在路由消息时添加附加的步骤,比如验证或者日志。由于这些步骤可能使效率降低,所以我们可以通过Control Bus来控制他们开关。一个Detour为我们提供这种能力。

 

观察和分析消息流量

 

有时我们想要在不影响主要消息流的情况下观察消息的内容。一个Wire Tap允许我们接入到消息流中。

当我们调试一个基于消息的系统,知道一个特定的消息在哪使很有帮助的。Message History保留一个消息访问过的所有组件的日志,而不需要增加组件间的依赖。

然而Message History依赖于单独的消息,一个中心的Message Store可以提供一个穿越系统的每个消息的完整记录。结合Message HistoryMessage Store可以分析所有消息穿过系统的可能路径。

Wire Tap, Message History, Message Store帮助我们分析异步的消息流。为了跟踪发送到请求-应答service的消息,我们需要在消息流中插入一个Smart Proxy

 

测试和调试

 

在部署前测试一个消息系统是一个非常好的注意。但是测试不应该停止在部署前。你应该有能力验证正在运行的消息系统运行持续的运行正常。你可以周期性的发送一个Test Message到系统中并验证结果。

当一个组件失败或者运行不正常,它可以简单的终止,并放弃一个channel中的剩余消息。在测试期间这是很有用的。一个Channel Purger可以为我们做这些。

 

posted @ 2005-11-23 20:20 fisher 阅读(1638) | 评论 (7)编辑 收藏

【过劳死】27个危险信号,在你身上发生几个了? (zt)

最近身体不太好,转贴一则文章,提醒自己多多休息和锻炼。

------------------------

 只要踏入在我们IT这个行业, 过不了几年身体就是亚健康状态,过渡的话就可能会“过劳死”,要想防止“过劳死”,就必须了解身体为我们发出的“过劳死”信号。

    研究者认为:在这27项症状和因素中占有7项以上,即是有过度疲劳危险者,占10项以上就可能在任何时候发生“过劳死”。同时,在第1项到第9项中占两项以上或者在第10项到18项中占3项以上者也要特别注意,这27项症状和因素分别是:

  1.经常感到疲倦,忘性大;

  2.酒量突然下降,即使饮酒也不感到有滋味;

  3.突然觉得有衰老感;

  
4.肩部和颈部发木发僵;

  
5.因为疲劳和苦闷失眠;

  
6.有一点小事也烦躁和生气;

  7.经常头痛和胸闷;

  8.发生高血压、糖尿病,心电图测试结果不正常;

  9.体重突然变化大,出现“将军肚”;

  10.几乎每天晚上聚餐饮酒;

  11.一天喝5杯以上咖啡;

  12.经常不吃早饭或吃饭时间不固定;

  13.喜欢吃油炸食品;

  14.一天吸烟30支以上;

  15.晚上10时也不回家或者12时以后回家占一半以上;

  16.上下班单程占2小时以上;

  17.最近几年运动也不流汗;

  18.自我感觉身体良好而不看病;

  19.一天工作10小时以上;

  20.星期天也上班;

  21.经常出差,每周只在家住两三天;

  22.夜班多,工作时间不规则;

  23.最近有工作调动或工作变化;

  24.升职或者工作量增多;

  25.最近以来加班时间突然增加;

  26.人际关系突然变坏;

  27.最近工作失误或者发生不和。

  针对如何摆脱过度疲劳,何永成博士开出如下处方:

  消除脑力疲劳法:适当参加体育锻炼和文娱活动,积极休息。如果是心理疲劳,千万不要滥用镇静剂、安眠药等,应找出引起感情忧郁的原因,并求得解脱。病理性疲劳,应及时找医生检查和治疗。

  饮食补充法:注意饮食营养的搭配。多吃含蛋白质、脂肪和丰富的B族维生素食物,如豆腐、牛奶、鱼肉类,多吃水果、蔬菜,适量饮水。

  休息恢复法:每天都要留出一定的休息时间。听音乐、绘画、散步等有助解除生理疲劳。

  科学健身方法:一是有氧运动,如跑步、打球、打拳、骑车、爬山等;二是腹式呼吸,全身放松后深呼吸,鼓足腹部,憋一会儿再慢慢呼出;三是做保健操;四是点穴按摩。

    哥们, 上面27条在你身上出现几条症状了?  怕怕吧? 

  建议哥们们每天早上和傍晚各抽出一小时锻炼身体,毕竟身体是革命的本钱!

转自: 电子商务论坛 http://bbs.eczn.com/

上面下划线的是我有的问题,你都有哪些?

posted @ 2005-11-23 13:38 fisher 阅读(699) | 评论 (0)编辑 收藏

WTP1.0已经到达M9

经过这半年的使用,WTP在我们组内已经从只用于开发Web Service的工具变成web开发的首选插件
虽然只是0.7版,但WTP的设计确实很好,目前WTP1.0已经release到了M9,还有20几天就到达release date了,热烈期待中....

posted @ 2005-11-23 13:29 fisher 阅读(625) | 评论 (0)编辑 收藏

【ESB专题】之五 - Message Endpoint及其相关模式


ESB中另外一个重要的课题就是Message Endpoint,这是关于一个应用程序如何连接到一个消息系统,并通过它来发送和接收消息。如果你在面向一个消息API编程,则你就正在开发一个endpoint代码。商业中间件通常都提供了这些工具。

 

l         Messaging Gateway

l         Messaging Mapper

l         Transactional Client

l         Polling Consumer

l         Event-Driven Consumer

l         Competing Consumers

l         Message Dispatcher

l         Selective Consumer

l         Durable Subscriber

l         Idempotent Receiver

l         Service Activator

 

发送和接收模式

 

有些endpoint模式既可以使用在发送方也可以使用在接受方。它们描述一个应用连接一个消息系统的一般情况。

 

包装消息代码 一个应用不应该意识到正在使用消息同另外一个应用程序通讯,大多数应用代码应该在不知道message的情况下被编写。在应用集成的地方,应该有一个薄薄的一层代码来执行应用的集成部分。当集成是由消息实现的,这层将应用连接到消息系统的代码称为一个Message Gateway

 

数据转换 当发送者和接受者使用不同的数据格式,或者不同的消息格式(支持不同的发送和接收者),在这种情况下,使用一个Message Mapper来在应用格式和消息格式之间转换数据。

 

外部控制的事务 消息系统在内部和外部使用事务,默认的,每个发送和接收方法在他们自己的事务中运行。Message生产者和消费者应可选的使用一个Transactional Client来控制事务,当你需要将几个消息一起发送伙通过其他事务服务整理消息时是很有用的。

 

消息消费者模式

 

其他endpoint模式只适用于消息消费者,发送消息是简单的。棘手的问题是决定一个消息应该何时发送,它应包含什么,以及怎样将它送到接受者 这是为什么我们有很多消息结构模式 但是一旦消息被构建,发送它是很容易的。另一方面,接收消息 很麻烦。因此许多endpoint模式是关于接收消息的。

 

接收消息的一个最重要的主题就是流量控制:一个应用控制,或者调节它消费消息的速度。一个潜在的问题是任何server都面临着大量的客户端请求会使其超载。通过远程过程调用(RPI),server几乎受到客户端调用的支配。同样的,通过消息,server不能控制客户端发送请求的速度 但是server可是控制它处理这些请求的速度。应用不必像消息系统传送消息那么快的接收并处理消息;使用一个Message Channel可以使它在一个可接收的速率上处理消息。然而,当消息积累太多,而server还有资源可以处理的更快,它可以使用同步message消费者来加快速度。所以使用这些消息消费者模式可以让你的应用将速度控制在它可以承受的范围。

 

许多消息消费者模式都是成对出现的,你可以任选一个使用。

 

同步或异步接受者 可以使用轮询消费者或一个事件驱动消费者。轮询提供最好的流量控制,因为如果server忙,则它不再继续轮询消息,所以message将阻塞在队列。事件驱动的消费者倾向于消息到达便触发处理,所以有可能会使server超载,但是每个消费者每次只处理一个消息,所以限制消费者的数量可以有效的控制消费速度。

 

消息分派 vs 消息获取 另外一个二选一的模式是一堆消费者如何处理一堆消息。如果每个消费者获得一个消息,他们可以并行的处理消息。最简单的方法是Competing Consumers,也就是一个点对点的channel有多个消费者。每个都可能获得任何消息;消息系统的实现决定那个消费者获得消息。如果你想控制消息到消费者的匹配过程,使用Message Dispatcher这时只有一个消费者接收消息,但是将委派消息到一个执行者去处理。一个应用程序可以通过限制消费者或执行者的数量来控制流量。当然,分派者Message Dispatcher也可以实现一个流量控制行为。

 

接收所有消息或者过滤 默认的,任何到达一个Message Channel的消息对于监听着这个channelMessage Endpoint都是可用的。然而有些消费者并不打算处理channel上的任何消息,而是希望只处理其中几种。这样一个识别的消费者可以使用一个Selective Consumer来描述它将接收什么类型的消息。然后消息系统将只将匹配的消息对该接受者描述为可用。

 

当断开连接的时候订阅消息 Publish-Subscribe Channels带来的问题是,如果一个消费者感兴趣一个channel,但是现在网络是断开的怎么办?是不是一个未连接的应用将错过发布的消息,即使它已经订阅过该消息?默认的,是的,订阅只对连接的订阅者有效,为了使应用不会因为连接而错过订阅的消息,要使用Durable Subscriber

 

等幂 有时一个消息可能被传输不只一次,可能因为消息系统不确定该消息是否已经被成功的传递过,或者可能因为Message ChannelQoS被设置较低来提高效率。另一面的,消息接受者认为每个消息只会被传输一次,并且当它们重复处理相同的消息,它们会出错。一个Idempotent Receiver可以优雅的处理重复的消息,并且阻止它们引起接收者应用的发生错误。

 

同步或异步服务 另外一个选择是一个应用应该暴露它的service为同步(RPI)还是异步的(Messaging)。不同的客户端可能喜欢不同的方式;不同的环境可能需要不同的方式。既然很难选择,就一起使用。一个Service Activator连接一个Message Channel到一个应用的同步服务以便当一个消息被接收,service就被调用。同步客户端可以简单的直接调用service;异步客户端可以通过发送消息调用service

 

Message Endpoint的相关主题

 

Message Endpoint的另外一个重要主题是很难同其他模式共同应用Transactional ClientEvent-Driven Consumer通常不能适当的在外部控制事务,Message Dispatcher也必须小心的设计这个问题,Competing Consumers的事务也是个重大问题。最安全的使用Transactional Client是使用一个单独的Polling Consumer,但是这不会是一个令人满意的解决方案。

 

这里特别要提到应该会保证成功的JMS风格的MDBEJB的一种。一个MDB是一个消息消费者,它即使一个Event-Driven Consumer又是一个支持J2EE分布式事务的Transactional Client,并且它可以作为Competing Consumers动态的池化,甚至作为一个Publish-Subscribe Channel。这是在一个自由的应用中实现这些是一个困难且乏味的组合,但是这个功能作为一个EJB容器的内建的功能被提供。(MDB框架如何实现的?本质上,容器通过一个动态改变大小的可重用的执行者的线程池来实现了一个Message Dispatcher,在那里每个执行者自己使用自己的session和事务来消费消息。)

 

最后,紧记一个单独的Message Endpoint可以很好结合几个不同的模式。一组Competing Consumers可以被作为Polling Consumers实现,同时也可以是一个Selective Consumers并且可以作为一个Service Activator调用一个应用的service

一个Message Dispatcher可以是一个Event-Driven Consumer和一个使用Messaging Mapper的一个Durable Subscriber。无论一个endpoint实现什么模式,它总是一个Messaging Gateway。所以,不要考虑使用哪种模式 而要考虑如何结合他们。这是使用模式解决问题的魅力所在。

 

要实现一个Message Endpoint有很多选择。Message Endpoint模式用于解释这些选择是什么以及如何最好的使用它们。

 

 

posted @ 2005-11-22 21:40 fisher 阅读(2080) | 评论 (2)编辑 收藏

【ESB专题】之四 - Message Transformation及其相关模式

 

 

 

通常,通过消息系统集成的应用很少有同样的消息格式。比如说,一个帐务系统同一个CRM系统对客户对象是有着不同的概念的。基于这个,一个系统可能将消息存储在关系表中,另一个可能存储在文件中。集成已存在的系统通常意味着我们没有修改系统以便使他们更好的一起工作的自由。然而,集成方案不得不协调和解决各种系统之间的不同。Message Translator模式提供了一个通用的解决方案。这里解释几种特定的Message Translator

 

Message Transformation包含以下几种模式:

l         Envelope Wrapper

l         Content Enricher

l         Content Filter

l         Claim Check

l         Normalizer

l         Canonical Data Model

 

大多数消息系统放置特定的需求在消息头的格式和内容中。我们包装有效数据到一个Envelope Wrapper中以适应消息基础设施的需求。如果消息需要穿过不同的消息基础设施,可以结合多个Envelope Wrapper

如果原始系统不能提供目标系统需要的数据域,可以使用一个Content Enricher。它可以查找缺少的信息并从已有数据中计算出它。Content Filter正好相反,它从消息中删除不需要的数据。Claim Check也从消息中删除数据,但是它将存储他们以便以后取回。Normalizer将多个不同格式的消息翻译成统一格式。

 

消除依赖

 

消息转换在集成中是一个很深的话题。Message ChannelsMessage Routers可以通过消除应用必须知道另外一个应用的位置的需求从而解除应用间的基本依赖。

一个应用可以发送一个消息到Message Channel而不必担心谁来取出消息。然而消息格式增加了另外一种依赖。如果一个应用不得不将消息格式化成另外一个应用的数据格式,通过Message Channel解耦的说法就像一个幻想。接收系统的任何改变或切换到另外一个接收系统都需要对发送应用进行改变。Message Translators可以帮助除去这种依赖。

 

元数据管理

 

将消息从一个消息格式转换到另一个格式需要操作元数据 描述数据格式的数据。

元数据在两个并行系统之间的集成中扮演着非常重要的角色。一个处理实际的消息数据,另外一个处理元数据。许多用于处理消息数据的模式也同样可以管理元数据。比如说,Channel Adapter不仅可以从一个系统中移进和移出消息,还可以从一个外部应用中获取元数据,并将其加载到一个元数据仓库中。使用这个仓库,集成开发者可以定义应用元数据与Canonical Data Model.之间的转换。

 

 

元数据集成

 

o_MT1.JPG

举例来说,上面的图描述了两个需要交换客户信息的应用的集成。每个系统的客户数据的定义稍有不同。从
AB的消息需要转换一下才能被B接收。如果Channel Adapters可以抽取元数据的话,创建一个转换将非常简单。然后这个元数据可以被放入一个仓库,大大的简化了Message Translator的配置和验证。元数据可以被存储成不同的格式。通常XML消息使用XSD格式。其他EAI工具实现所有元数据格式,但是允许管理员导入或导出到其他格式。

 

消息系统外的数据转换

 

这些转换模式组成的很多原则可以被应用于非消息集成。比如说,File Transfer可以执行系统间的转换工作。类似的,Remote Procedure Invocation必须使请求使用要调用的service的格式,即使应用本身的格式可能不同。典型的,需要调用程序来执行转换。一些最成熟的转换引擎组成了ETL工具,比如Informatica或者DataMirror。这些工具一般都一次转换大量的数据,而不是转换单个消息。

Message System应专注于几种基本的Message Translator模式。而不应该关心实体间结构转换的细节(不同的数据模型之间的转换,比如ER模型不支持多对多关系而其他的支持这种)。关于这个主题最老也使最相关的书是Kent的《Data and Reality》。

 

posted @ 2005-11-21 21:40 fisher 阅读(1607) | 评论 (1)编辑 收藏

【ESB专题】之三 - Message Construction及其相关模式


在前面的关键组件中我们提到了Messages。当两个应用想要交换数据,他们将数据包装在一个message中。但是一个Message Channel不能传输原始数据,它只能传输包含在一个message中的数据(即传输特定格式的数据)。

 

Message在消息系统中处于信息载体的位置,而在ESB中,还消息识别、序列以及生存周期等职责。

 

Message的结构涉及以下几个模式:

l         Command Message      

l         Document Message      

l         Event Message

l         Request-Reply

l         Return Address

l         Correlation Identifier

l         Message Sequence

l         Message Expiration

l         Format Indicator

 

创建和发送一个Message产生以下几个问题:

 

消息意图 Message最终是为了运送一些数据,但是发送者可能有其他目的,比如它希望接受者使用消息做些事情。它可以发送一个Command Message,指定它希望调用的接受者上的函数或方法。发送者告诉接受者运行那些代码。发送者可以发送一个Document Message来传送它的数据结构到接受者。发送者发送数据到接受者,但是不指定接受者应该做什么。

或者它可以发送一个Event Message,通知接受者发送者那里有一个改变。发送者不应告诉接受者应该怎样适应这个改变,而只应提供通知。

 

返回一个应答 当一个应用发送一个消息,它通常期望得到一个回应来确定消息被处理并提供一个结果。这是一个Request-Reply场景。Request通常是一个Command Message,而应答是一个包含返回值或异常的Document Message。请求者应该在请求中指定一个Return Address来告诉应答者使用哪个通道来传回应答。请求者可能在一个处理过程中发送多个请求,所以应答应该包含一个Correlation Identifier来指出这个应答对应哪个请求。

有两个Request-Reply场景需要注意;它们都包含了一个Command Message请求和一个对应的Document Message应答。在第一个场景中,Message RPC,请求不但要调用应答者的函数,而且期望一个返回值。这是RPC。另一个场景中,Message Query,请求者执行一个查询;应答者执行查询并在应答中返回结果。这是远程查询。

 

大量的数据 有时应用想要传送大量的数据结构,放入一个单独的message里面不是很合适。在这种情况下,将他们分解成可管理的消息块并将他们作为Message Sequence发送。这些消息必须按顺序发送,以便接受者能够充足原始数据结构。

 

慢速消息 消息系统的一个问题是发送者通常不知道接受者要多久才能接受到消息。然而,消息的内容可能是时间敏感的,所以如果消息在某一时间内没有被接受,它将被忽略并取消。在这种情况下,sender应该使用Message Expiration来指定一个到期时间。如果消息系统在规定时间内无法传输一个消息,应该将它取消并删除到Dead Letter Channel中。同样的一个receiver接受到一个超出该时间点的消息,也要取消该消息。

 

总之,只选择使用消息是不够的。使一个消息工作的其他决定性因素来自于消息所要完成的任务。

 

posted @ 2005-11-19 20:31 fisher 阅读(1405) | 评论 (6)编辑 收藏

【ESB专题】之二 - Message Channel及其相关模式

 

 

在前面一个专题中,我们列出了一个ESB系统所需要关心的所有方面的关键组件,这里介绍其中的Message Channels所关注的问题及相关的模式。

 

Message Channel主题之下包含以下模式,分别用于解决channel中不同方面的问题:

 

l         Point-to-Point Channel  

l         Publish-Subscribe Channel   

l         Datatype Channel  

l         Invalid Message Channel      

l         Dead Letter Channel     

l         Guaranteed Delivery     

l         Channel Adapter    

l         Messaging Bridge  

l         Message Bus  

 

 

当两个应用需要交换数据,它们通过连接两端的channel来发送数据。发送的应用可能不知道哪个应用将接受数据。然而,通过选择特定的channel来发送,发送者知道接受者将是守候在channel另一端等待数据的应用之一。通过这种方式,生产数据的应用有了一个同数据消费者通讯的途径。

 

Message Channels面对的各个主要问题:

 

如果一个应用要传输或接受数据,它一定会用到一个channel。问题是你的应用要知道要使用什么样的channel,以及用它来做什么。

 

固定的channel集合 Channel中讨论的一个主题是,一个应用可用的Message Channel集合一般是固定的。设计一个应用时,一个开发者必须知道将某种类型的数据放到哪里可以同其他应用共享该数据,以及从什么地方可以找到其他应用的特定数据。这些通讯路径不会在运行期动态的创建和发现;它们需要在设计期间就确定下来,以便应用知道它的数据从哪里来以及数据将去哪里。( 虽然大多数channel必须被静态定义使正确的,但是也有例外,有些情况下动态channel是很好用的。一个例外就是Request-Reply模式中的reply channel。请求者可以创建或者获得一个应答者不知道的新的channel,并在请求消息中指定该channelReturn Address,应答者就可以使用它。另外一个例外是支持集成channels的消息系统实现。一个接受者可以订阅一个集成体系的根channel,然后发送者可以发布消息到一个子channel,而接受者不需要知道子channel,仍然会收到消息。这些都是不常见的情况,channel通常仍然是在部署之前被定义,并且应用被设计连接到一个已知的channel集合 )。

 

决定channel的集合 一个相关的主题是,谁决定那些Message Channel是可用的 message系统还是应用程序?换句话说,是由消息系统确定一些channel,然后要求应用程序使用它们?还是应用决定它们需要什么channel,然后要求消息系统提供它们?这个问题没有一个简单的答案,设计必须的channel集合是迭代的。首先,应用要决定消息系统提供哪些channel。然后应用将围绕这些channel设计它们的通讯,但是如果这样是不可行的,它们将需要添加额外的channel。当一些应用已经使用了一个确定的channel集合,当加入新的应用,它们将使用已存在的channel。当为应用添加新的功能,它们需要新的channel

 

单向channel 另外一个经常引起混淆的是一个Message channel是单向的还是双向的。技术上来说,两者都不是,一个channel更像是一个桶,一个应用放入数据,另外一个应用从中取出数据。但是由于数据是放在消息中从一个应用传到另一个,这使得channel具有方向性,使它变成单向的。如果一个channel是双向的,应用将从中发送和接受数据,虽然技术上是可行的,但是会有小小的问题,应用将有可能持续的取出自己放进去的希望发送给其他应用的消息。所以,为了实践性的目的,channel是单向的。作为结论,两个应用如果有双向通讯,它们需要两个channel,每个方向一个

 

如何使用Message channels

 

现在我们来讨论以下如何使用channel

 

一对一或者一对多 当你的应用共享一些数据,你希望只将它共享给一个应用还是对它感兴趣的所有应用?要传送数据到一个单独的应用,使用Point-to-Point Channel。这并不意味着发送到这个channel的每个数据都发送给同样的接受者,因为一个channel可能有多个接受者。它意味着,实际上,保证每个数据都被同一个应用接收。如果你想让所有接收应用都能接收数据,使用Publish-Subscribe Channel。当你通过这种方式发送数据,channel将高效的复制数据到每一个接收者。

 

什么类型的数据 任何内存中的数据都有一个类型。另一方面,所有数据都是一些bytes集合。消息系统工作同这类似,消息内容必须符合某些类型以便接受者了解数据的结构。Datatype Channel认为在一个channel中的数据必须拥有同样的类型。这也是为什么消息系统需要很多channel的主要原因(每个channel一种格式)。如果数据可以是任意的格式,那么消息系统在两个应用之间只需要两条channel

 

无效的和过期的消息 消息系统可以确定消息被正确的传输,但是它不能保证接受者知道如何处理它。接收者对数据格式和意义存在期望。当它接收到一个不符合期望的消息,它什么也不能做。它们能作的,就是将这个陌生的消息放入到一个特别设计的Invalid Message Channel并希望某些监控这个channel的工具能够取出这个消息,并指出该如何处置它们。许多消息系统有一个类似的内建特征,一个Dead Letter Channel,用来存放成功送出但却无法成功投递的消息。另外,一个系统管理工具应该监视Dead Letter Channel并且决定如何处置这些无法投递的消息。

 

故障检测 如果一个消息系统发生故障或停机维护,它的消息会怎样?当它重启并重新运行,它的消息能否还在它的channel中?默认的:不会;channel将消息存储在内存中。然而,Guaranteed Deliverychannel持久化以便将它们的消息存储到硬盘上。这会影响效率,但会使消息更加可靠,即使消息系统是不可靠的。

 

非消息客户端 如果一个应用不能连接到一个消息系统但是仍然想要参与消息怎么办?通常它只能自认倒霉了,但是如果消息系统可以通过某种方式连接到应用系统 通过它的用户界面,它的service API,它的数据库,或者一个TCP/IPHTTP这样的网络连接 那么消息系统可以使用一个Channel Adapter。这允许你连接到一个或多个连接到应用的channel而不必改变应用或者可能也不需要一个同应用运行在同一个机器上的消息客户端。有时‘非消息客户端’真的是一个消息客户端,但是只有连接的是其他消息系统的时候。

 

通讯中枢 随着越来越多的企业应用系统连接到消息系统以便通过消息暴露他们的功能,消息系统变成了企业中一站式功能的集散地。一个应用只需简单的知道用哪个channel来请求功能,以及从哪个监听结果。消息系统本质上变成一个消息总线,一个提供所有企业应用甚至变化中的应用和功能的中枢。你可以更快速的集成。

 

如你所见,使用消息构建应用不仅仅是将他们连接到消息系统并发送消息。消息必须使用Message Channel来发送。Channel必须被设计为某个目的服务,比如基于被共享的数据类型,共享数据的应用类型,和接收数据的应用。

 

posted @ 2005-11-17 22:56 fisher 阅读(1285) | 评论 (1)编辑 收藏

【ESB专题】-面向消息的EAI的关键组件

 

企业集成有很多种模式,随着技术的发展,实时的、面向消息的企业集成越来越成为主流,面向消息的企业集成的稳定性和兼容性要求其基础件,也就是message系统必须提供足够强壮和可扩展的设计,下面几种是作为面向消息的企业集成的基础件所必须提供的几个关键性组件。

 

消息集成使得message系统负责转换两个应用之间的数据格式,从而使得应用可以专注于他们需要共享什么数据而不是如何共享它们。

 

以下这些组件,在著名的ESB系统Mule中都可以见到,有兴趣的同学可以去看看Mule的源代码,虽然Mule对ESB的实现有很多不成熟的地方,以至于让我不敢在生产系统中使用(唉...可恨的Mule),但是毕竟是一个大而全的系统,值得借鉴一下。
 

Channels — Messaging应用通过一个Message Channel传送数据,一个senderreceiver的虚拟管道。一个新安装的消息系统默认不包含任何channel;你必须知道你的应用需要怎样通讯,然后才能建立channel来完成它。

 

Messages — Message是在channel上传输的不可分割的包。因此,为了传输数据,应用必须将数据打包成一个或多个packets,将每个packet包装成一个message,然后将其传输到一个channel。同样的,一个receiver应用在接受到message后必须从message中提取出数据才能使用。Message系统应该能重复的传输message,直到它成功为止。

 

Pipes and Filters 最简单的情况下,message系统将一个消息直接从sender计算机传送到receiver计算机。然而,通常在消息从sender中发出后,receiver接受到之前,有一些动作需要对message执行。举例来说,message也许需要验证或者转换。Pipes and Filters架构使用channel将多个处理步骤连接起来。

 

Routing 在一个大型的、拥有许多不同的应用和channel连接的企业应用中,一个message可能需要穿过多个channel才能到达最终目的地。Message的路由如此复杂以至于最初的发送者无法知道那些channel能将message传送给最终的receiver。因此,最初的发送者将message发送给一个Message Router,一个以Pipes and Filters架构中的filter形式存在的应用组件。Router将决定如何将message发送到最终receiver或者至少是下一个Router

 

Transformation 不同的应用的数据格式可能不同。为了调节senderreceiver之间的数据格式不同的问题,message必须经过一个中介的filter,一个Message Translator,它将message从一个格式转换成另外一个格式,或转换成一个公共的格式。

 

Endpoints 大多数的应用程序没有内建的能力来同一个message系统交互。因此他们必须包含一个中间层,它知道应用系统如何工作,也知道message系统如何工作,并桥接两个系统。这个系统是一组并列的Message Endpoints,它能够使得应用发送和接受message

 

System manager 作为一个大型的消息集成系统,其面向消息的、异步、低耦合的本质使得系统更加难以调试,运行期的状态也难以跟踪,所以,我们必须有强有力的手段进行系统的运行期管理和监控,同时最好能够在运行进行动态更新,以保障系统的强壮性。


企业应用集成是一个巨大而复杂的系统,作为其基础件ESB系统,必须能够提供对其完全的支撑以及足够强壮的系统,这正是ESB系统建设的难度所在。

posted @ 2005-11-16 20:56 fisher 阅读(2326) | 评论 (6)编辑 收藏

在webwork中使用自定义的Result生成动态验证图片

这个动态图片的实现原理是在servlet的response中写入一个ImageOutputStream,并由servlet容器将其转成图片,在非webwork的实现中,可以直接操作response,但是在webwork中,要想直接操作response的output则必须使用不需要对response操作的result类型

实现一个
Result

 

不可以用普通的dispatcherResultresponseoutputStream中写入东西,否则将覆盖所有的dispatcherjsp页面

上次的代码忘记加上response的设置不缓存了,这样即使使用IE的回退也会刷新图片 

    private HttpSession            session;

    
/**
     * 
@see com.opensymphony.webwork.dispatcher.WebWorkResultSupport#doExecute(java.lang.String,
     *      com.opensymphony.xwork.ActionInvocation)
     
*/
    @Override
    
protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception
    {
        HttpServletRequest request 
= (HttpServletRequest) invocation.getInvocationContext().get(
                ServletActionContext.HTTP_REQUEST);
        HttpServletResponse response 
= (HttpServletResponse) invocation.getInvocationContext().get(
                ServletActionContext.HTTP_RESPONSE);
        response.setHeader(
"Pragma""No-cache");
        response.setHeader(
"Cache-Control""no-cache");
        response.setDateHeader(
"Expires"0);
        VerifyImage verify 
= new VerifyImage();
        OutputStream os 
= response.getOutputStream();
        String str 
= verify.GetImage(os);
        session 
= request.getSession(true);
        session.setAttribute(
"rand", str);
    }


 

xwork.xml中配置result-type

        <result-types>

            <result-type name="image"

              class="com.bnt.afp.action.verify.ImageResult"/>

        </result-types>

 

添加一个生成图片的action

        <action name="imageAction"

class="com.bnt.afp.action.verify.ImageAction">

            <result name="success" type="image"/>

        </action>

 

在需要生成验证图片的地方这样调用:

<img border=0 src="imageAction.action">


 ImageAction里只要简单的返回SUCCESS就可以了

    public String execute() throws IOException
    {
        
return SUCCESS;
    }



VerifyImage中生成图片的方法:(来自网上一个JSP生成动态验证图片的实例)

       //获取生成的图片,返回生成的验证码,并将ImageOutputStream写入

       
public String GetImage(OutputStream outputStream){

              

              
int width=60, height=20;

              BufferedImage image 
= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

              Graphics g 
= image.getGraphics();

              Random random 
= new Random();

              g.setColor(getRandColor(
200,250));

              g.fillRect(
00, width, height);

              g.setFont(
new Font("Times New Roman",Font.PLAIN,18));

              

              g.setColor(getRandColor(
160,200));

              
for (int i=0;i<155;i++)

              {

                     
int x = random.nextInt(width);

                     
int y = random.nextInt(height);

                     
int xl = random.nextInt(12);

                     
int yl = random.nextInt(12);

                     g.drawLine(x,y,x
+xl,y+yl);

              }

              String sRand
="";

              
for (int i=0;i<4;i++){

                  String rand
=String.valueOf(random.nextInt(10));

                  sRand
+=rand;

                  g.setColor(
new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));

g.drawString(rand,
13*i+6,16);

              }

              g.dispose();

              
try {

                     ImageIO.write(image, 
"JPEG", outputStream);

                     outputStream.flush();

                     
return sRand;

              } 
catch (IOException e) {

                     e.printStackTrace();

                     
return "fail";

              }

       }

 

       
public Color getRandColor(int fc,int bc){

              Random random 
= new Random();

        
if(fc>255) fc=255;

        
if(bc>255) bc=255;

        
int r=fc+random.nextInt(bc-fc);

        
int g=fc+random.nextInt(bc-fc);

        
int b=fc+random.nextInt(bc-fc);

        
return new Color(r,g,b);

       }


                                                                                                                                 转载请注明作者和来源. 

posted @ 2005-11-15 21:14 fisher 阅读(1658) | 评论 (2)编辑 收藏