|
2005年8月6日
blog也搬迁了:http://blog.sina.com.cn/liuwendao
来武汉快三年了,留在北京的最后一件物件-电吉它,也被我拿到武汉来了
我们这么混,能成功吗?
立帖为证
军事演习区,一位妇女驾车在大桥前被一名军官拦住:“对不起,公民,您现在不能过去。”“为什么?”“这座桥在一小时前被炸毁了。”“您能告诉我这究竟是怎么回事吗?”“很抱歉,不行。我本人已于2小时前阵亡。” 伊万看电视,是勃在演讲。伊万觉得无聊,换了一个,还是勃在演讲,又换一个,还是他。伊万一连拨了几十个台,最后累了,准备关电视。这时候电视画面变成一个KGB,怒气冲冲地叫:“你再敢换?再敢换?再换判你10年大牢!” 某日苏联举行国庆**,沿着大街开来了炮兵、机械化步兵、坦克、自行火炮、战术导弹、战略核导弹,破坏力一个比一个大;队列末尾却是两个带公文包的矮子。在看台上勃列日涅夫惊讶地说:“这两个人破坏力比核导弹还大!他们是什么人?” KGB头子说:“不是我的人。” 国防部长说:“没见过他们。” 苏联总理说:“他们是国家计委的...” 戈尔巴乔夫视察农场,看到猪儿乖乖,一时兴起站在猪中间照了张像。 待到报纸准备发表时,编辑为照片的标题犯了难?? “戈尔巴乔夫同志和猪在一起”不好。 “猪和戈尔巴乔夫同志在一起”也不好。 报纸出版后,照片下的说明文字是?? “左起第三位是戈尔巴乔夫同志” 勃列日涅夫和美国总统卡特在瑞士开会,休息时间两个人很无聊,就开始比谁的保膘更忠诚。卡特先来,他把自己的报膘叫进来,推开窗(外面是20层楼)说:“约翰,从这里跳下去!” 约翰哭着说:“你着么能这样呢,总统先生,我还有老婆孩子呐。” 卡特被感动了,流着泪说是自己不对,叫约翰走了,然后抡到勃列日涅夫,他也大声叫自己的保膘伊万。 “伊万,从这里跳下去!” 伊万二话不说就要往下跳,卡特一把抱住他说:“你疯了?跳下去会死的!” 伊万一边挣扎着要跳下去一边说:“放开我,混蛋,我还有老婆孩子呐。” 早年莫斯科修地铁,工程师将方案上报斯大林审批。不久,方案发下来,上面有斯大林的签字。 细心的工程师发现图纸上多了一个圆型的茶杯印,于是莫斯科地铁就多了一条环形线。 斯大林肃反时期的苏联。一位内务人民委员部审判员结束一天的审判工作,回到办公室,突然一个人大笑起来。对面办公桌的同事奇怪的问道:“有什么好笑的事吗?”“是啊,”审判员用手帕擦着笑出来的眼泪:“一个很好笑的笑话……”“哦?说来听听?”“你疯了吗?!我刚判了说这笑话的家伙五年苦役!” 苏联30年代肃反扩大化时期。内务人民委员部的一间牢房里关了三个人,彼此间谈起坐牢的原因。 第一个人说,我因为反对了党书记彼得罗夫; 第二个人说,我因为支持了彼得罗夫; 第三个人说,我就是彼得罗夫。 戈尔巴乔夫和他的司机开着车在路上,戈尔巴乔夫突发异想,说:让开!我来开。一个老警察和一个新警察在路上值勤,见一辆车歪歪扭扭的开得疯快,老警察就对新警察说:去!好好收拾一下。新警察将车拦住之后,又没趣没趣地回来了。老警察问:怎么?里面是谁?新警察回答说:我也不知道里面是谁,反正给他开车的是戈尔巴乔夫。 美国外交代表团到苏联访问,苏联接待官员陪他们参观“建设的伟大成就”,并且得意的说:“到了下一个五年计划,每个苏联家庭都可以拥有一架私人飞机!”美国人惊讶的问:“ 他们要飞机干什么呢?”苏联官员说:“当然有用啊……譬如你在莫斯科听说列宁格勒开始供应面包了,你可以马上开着飞机赶去排上队。” 一位公民打电话到基辅电台问主持人:“共产主义到底是艺术还是科学?” 主持人说:“我也不清楚,但我肯定不是科学” “为什么?” “如果是科学的话,他们应该拿狗做试验。” 斯大林在大会上引经据典地说:“马克思和列宁说1+1=2,而托洛茨基和布哈林说1+1不等于3。是托洛茨基和布哈林说的对呢?还是马克思和列宁说得对呢?”下面听众一脸疑惑,“毫无疑问,是马克思和列宁说的对!”底下热烈鼓掌,“托洛茨基和布哈林是帝国主义派来的间谍,说1+1不等于3的人罪不容赦……” 列宁快去世了,叫赶快把继承人斯大林召进克里姆林宫来,临终有几句话要嘱托。“不瞒你说,我还有一个隐忧啊,斯大林。”“说吧,亲爱的伊里奇。”斯大林专心地听着。“那就是,人们会跟你走吗?不知你想过了没有?”“他们一定会跟我走的。”斯大林强调说,“一定会!” “但愿如此。”列宁说,“我只是担心,万一他们不跟你走,你怎么办?”“没问题!”斯大林答道:“那他们就得跟你走!” 集体农庄庄员伊万在河里捉到一条大鱼,高兴的回到家里和老婆说:“看,我们有炸鱼吃了!” “没有油啊。” “那就煮!” “没锅。” “烤鱼!” “没柴。” 伊万气死了,走到河边把鱼扔了回去。那鱼在水里划了一个半圆,上身出水,举起右鳍激动地高呼:“斯大林万岁!” “瑞典能否建立共产主义”? “不能。” “为何?” “列宁同志说了:共产主义不在山那边。” 一个苏联KGB特工和一个美国CIA特工互相吹嘘各自的机构是如何的杰出。 那个KGB特工首先发言说,“我们拥有你们美国过去15年里所有导弹发射的详细数据。” CIA特工说:“这不算什么。我们CIA掌握着你们苏联未来15年里所有当选的中央委员名单。” 一艘航行在大海上的轮船快要沉了,船长叫乘客赶紧跳海,但他喊了半天没有一个人跳,一个社会学家说我来喊,他去喊过之后所有的人都跳下海去了。船长觉得奇怪,问他是怎么喊的,社会学家回答说:我对法国人说这样跳下去很浪漫,我对西班牙人说这样跳下去很潇洒,我对英国人说这样跳下去是一种体育运动,我对美国人说这样跳下去有利可图,我对苏联人说这样跳下去是革命行动。 在苏联的一趟公交车,一个男的非常谦恭地问站在他身旁的另一个男的:“同志,请问您是克格勃吗?” 那人答道:“不是。” 又问:“那您有没有亲戚或朋友是克格勃呢?” 答:“没有。” 还问:“那您是否跟克格勃有些交往或联系?” 答:“没有,你要干嘛啊!” 该男生气地说:“干嘛,他妈的,你踩着我的脚了!” 赫鲁晓夫作报告,批判斯大林。忽然,有人从台下递了个纸条,写道:当他做坏事的时候,你在哪里?赫鲁晓夫一看这个条子,大声怒喝道:“是谁写的,给我站出来。”台下雅雀无声,没有人站出来。赫鲁晓夫接着说道:“同志们,我当时就和你们现在一样,你们知道我当时为什么不敢站出来了吧” 勃列日涅夫:同志们,美国人登上了月球,我们不能再等了,党决定让你们上太阳。 宇航员:总书记同志,我们会被烧死的。 勃列日涅夫:没关系,同志们,党都替你们想好了,你们晚上去。 电影《这里的黎明静悄悄》试映时,由于其中有部分裸体镜头,因此主管电影审核的官员曾试图把这部电影禁演,幸亏勃列日涅夫内部观看时感动得热泪盈眶,这部优秀的电影才有幸与观众见面,成为世界电影史上不朽的篇章。而另一部电影由于其中有主人公走到教堂时跪地痛哭的镜头,被电影审核官员认为是宣扬宗教而准备勒令裁掉这部分内容,恰恰勃列日涅夫看到这里时动了感情,因此这个镜头得以幸存下来。 当年的捷克斯洛伐克政府中,设立了一个“海军部”,结果,苏联老大哥就对捷克人说:你们是内陆国家,设什么海军部? 捷克人回答说:那你们不是也设了文化部吗?
最近看到越来越多的人使用mina,甚至在线下也碰到合作公司的库中使用MINA,出于好奇,尝试一下用自己的blog做一下调查,访问本blog的兄弟,如果您使用MINA作为自己的通讯基础件,请留言介绍一下自己
软件开发的世界里充满了不理解, 客户不理解软件是怎样开发的、经理不理解开发人员、开发人员不理解指挥者。问题在于软件开发惊人的困难,造成很少有开发人员能够说出软件自始至终是怎样开发的,并能够对这个过程中会遇到的不同选择所隐含的结果表现出适度的理解。 在软件开发人员还很年轻的时候(十几岁或二十出头),他们通常集中精力学习和使用技术,称自己为perl程序员、Linux专家、EJB开发人员、.NET开发人员等。对他们来说技术是最重要的事情。因为技术在不断的变化,年轻的程序员倾向于大致学习一个技术,在一到两个项目中使用,然后重新开始学习新技术或者是学习以前使用过的技术的最新发展。这里的问题是,他们一遍又一遍的重复的学习的不过是同样的低层次基本技能的不同风味。 幸运的是,很多开发人员在经过了几轮技术学习之后逐渐意识到:一旦用COBOL、Java、C#等语言为事务控制编写过代码,就会开始认识到基本的、本质的东西是不变的。不同环境下的数据库访问、用户界面设计等领域也是同样的情况。不久以后,开发人员逐渐认识到无论具体的技术怎样,很多基础性的东西是保持不变的,这些基础性的东西有的在学校里讲过,有的没有。 这种认识经常发生在开发人员接近三十岁或刚过三十岁的时候,通常是人们开始稳定下来,结婚、买房的时候。这是比较幸运的情况,因为上面提到的这些新的个人需求意味着他们不可能再投入大量的时间去学习新的技术,他们需要用这些时间和家庭成员在一起。突然的,高层次的角色如项目负责人、项目经理、(非敏捷的)建模人员等对他们变得非常有吸引力,因为这些角色不需要持续花费大量的时间和精力去学习新技术。于是,等到开发人员开始真正学到技艺的时候,他们已经处于离开开发人员角色的转变过程中了。所幸的是,新的“小年轻”不断的跟上来,这个过程在不断的循环重复。最终的结果是:大部分最活跃的正在开发软件的人通常不是最称职的做这件事的人,而他们自己甚至还不知道。
来自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______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
/*-------------------------------------------
程序员的进化——从学生到首席执行官
翻译 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 --------------------------------------------------------------------------------
下午写完设计,趴在武汉办公室的窗户上看风景,天气好的时候,左面长江右边东湖都可以看到,其实想想在武汉出差也挺不错的,呵呵
彼得·德鲁克在他的《 卓有成效的管理者 》当中,阐述了知识工作者管理的秘诀,那就是知识工作者的工作效率来自于对其工作的有效性以及他的工作是否有所成就。这本1966年出版的管理学书籍经过近50年的时间,反而越发显得适应潮流。 而卓有成效的知识工作管理者现在显得比过去任何时候都要短缺,也比现时任何人才都要短缺。在现时这个信息爆炸,案例丰富的年代,战略眼光与部署格局对于一个企业人才不再如此重要,对于企业战略,任何有管理常识、了解企业实情的人大都可以分析得很到位,关键是要找到合适的人去实施。知道什么样的人合适,以及找到这个合适的人,成为企业家最需要做的事情。而成为那个合适的人,则成为草根阶层走入舞台中央的必备能力。 附一篇来自经济观察报刘军的《 笨蛋,最重要的是人!》 --------------------------------- 2005年10月8日管理大师彼得·德鲁克曾经讲过一个他和《时代》《财富》等杂志的出版人亨利·鲁斯交往的故事。鲁斯有个很好的新杂志方案——试图创办“从美国人思考角度出发”的高格调文化杂志,他去向德鲁克求教。德鲁克分析了一番说,“这份企划案很棒,不过晚了50年。”接着,他对鲁斯说出了最重要的话:“此外,《时代》的人也无法胜任。我猜,你想鼓励一些外面的作家来为这本杂志执笔,并以一般大众为读者群。但是你的专长却是叫自己手下人搞定,因此大有不同。” 鲁斯回答说,“我来向你请教,正因为我猜想你会这么说。”他因而放弃了这个计划,因为他深知人的重要性。经过十多年的西方管理教育和知识传播,中国企业管理者已经熟知战略的理性分析,与重视人比起来更重视事,另外先建立制度、而不是依靠人的观念也被广泛接受。不过,我却逐渐感觉到,在这些问题上我们可能有点矫枉过正,对于知识型工作、对于管理,或许人更重要,是应该优先考虑的。 9月底,索尼新任CEO、美国人霍华德·斯特林格(Howard Stringer)宣布索尼的战略调整计划:全球裁员一万人,缩减工厂数目,出售1200亿日元的不动产与股票等非核心资产,对消费电子业务进行架构调整、将权力集中到这一业务的最高主管手中。在过去五年中,索尼逐渐失去消费电子霸主地位,业绩很不理想,这背后的根本原因正是这些战略调整所触及的问题。对于这一点,大概稍微有点管理常识的人都知道,我想索尼前CEO出井伸之自然了然于心,他之下的索尼高管也清楚。不过,大概只有霍华德·斯特林格、索尼历史上第一个外国人CEO、这个日本文化的局外人才能推行上述改革。 战略,有管理常识、了解企业实情的人大都可以分析得很到位,但真正去做,就需要“合适的人”。我一直相信,选择霍华德·斯特林格作为继任者,是出井伸之的最重要的决策,体现这个亚洲最优秀的商业领袖的领导才能。卡洛斯·戈恩已经因成功在日产汽车(Nissan)实现大逆转而成为全球最知名的管理者之一,他当初所做的关闭工厂与裁员、破除日本式企业联盟等措施,都是众所周知的弊端,但惟有他这个合适的人才能推动变革。斯特林格和戈恩都是在这种情境下最合适的人,只是恰巧他们都是外国人。 Google、微软和李开复之间的纷争一直没有停息的迹象。在这个过程中李开复把自己再次塑造成了最优秀的技术专家形象,但如果相信这一点,我们就错误理解了Google的智慧。如果要一流的中文搜索研发人才,Google的最佳人选绝对不是李开复,而可能是李彦宏。如果它的战略诉求点是这个,它可以百度买下,从而得到李彦宏。但是,Google在中国,需要的哪里是什么技术专家、研发中心?现在Google中国战略要的合适的人是据称是“技术专家”的李开复,但他在公众心目中的号召力和政府公关能力才是Google所看重的。 我们也可以循同样的视角来看待雅虎和阿里巴巴之间的联姻。这一次是把雅虎中国的业务交道马云手中去让他照料,因为对于谁了解中国市场和能够帮助雅虎发现中国市场潜力这个问题,马云是最佳答案。雅虎在中国的最近两次战略行动目标都首先是为了“人”。上一次是雅虎在中国收购3721,反而让其老板周鸿一担任中国区总裁,从而让雅虎中国从跨国公司在华分支机构这样的角色变成勇猛的中国本土企业。但在经历一段发展时期之后,雅虎中国就需要更合适的人。我们可以认为,这是雅虎、阿里巴巴联姻的主要原因之一。 先建立制度、体系,而不是“因人设事”这样的观点被广泛接受,可是,我们忘记了这个观念背后的工业化背景:所有人的都被当成了可替换的零件,所以制度体系最重要。但是,对于知识型工作来说,特别是非重复的创造性工作,每个人的工作方式、结果都截然不同。 我们所设计的制度体系,在当前的人员安排下也似乎运转正常。但是,由于这些人是无法替换的,人走了,看似精妙的体系也就出现出现问题了。这个时候,是去做不可能完成的任务:寻找适合制度体系的一摸一样的人?还是更改体系?或者看得更远点,在现在的情境下,我们根本就不该把制度体系的重要性神话到这种程度?针对知识型工作的讨论,和上文对最高管理者的讨论并非没有联系,因为在我看来,管理工作是最重要的、最具创造性的知识工作。 吉姆·柯林斯在《从优秀到卓越》说卓越公司是“先人后事”:这些公司的主管不是先确定目的地(先有方向、愿景、战略),然后才把人们引向那里;他们首先让合适的人上车(不合适的人自然请下车),然后才决定去向何处。他所说的虽是方向、远景,但大体上和制度是同一类型的事物。我们都应该了解,合适的人更重要,那些看似严密的战略分析和完善的制度体系有时候会变成令人难以忍受的障碍,因为它们和“合适的人”可能是完全矛盾的,这些人通常都难以放到一个既定的模子中去。
今天将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" >
于是就出现了上面的问题 多谢飞云小侠的帮助^_^
自工作以来,我就养成了睡前读书的习惯,这一年在武汉,实在买不到一些好书,每次回北京总要带很多书过来,最近再次面临回京购书的局面,在回京之前总不能闲着,于是从去年看过的书中乱翻,以第一感觉来决定自己最想重读那本书,结果选中了温博格的《成为技术领导者-解决问题的有机方法》 两年前,当一位同窗好友集齐全套的温博格系列的时候,我曾很不屑的说他:一个人写那么多书,质量显然没保证,买他作甚?现在看来,当时确是井底之蛙了,温博格的书中少有瑕疵,尤其是后期作品,读来总是让人意犹未尽。 过去的几年里,我看过很多书,无论是早期GOF的设计模式,Martin Fowler的企业架构系列,还是Rod的J2EE开发厚厚的两卷本,甚至我最喜欢的POSA系列,虽然都会给人技术方面成长的感觉,但最好情况下也只是让我感觉到技艺的变化。 而管理方面的书籍,则大多走入两个极端,要么是学院式的分析解构,要么是江湖术士式的技巧集合。就像过去我曾很喜欢DEBORAH G. ANCONA的那本组织行为学和曾士强的中国式管理,但现在看来,DEBORAH关注组织多过于关注团队,而曾士强则过于强调中国人的心理情结,实用归实用,但可能不太适合技术人员的口味,读他的书让人感觉有些厚黑,让我常常想到一句俗语:人老精,鬼老灵。
而温博格的写作方式,如同Ken在英文版序中所说,会引起大量的思考,对温博格的文字的思考,思考对温博格文字的思考,以及对自身思考的思考....通过温博格的书,让我体会到的事是,读书,有时候是为了实用,而的有时候,则纯粹是为了过瘾。 本书中温博格的MOI模型,实际上不是一个行为指导手册,而是带来了更加宏观和可思考的空间,让你对自己在团队中的行为更加有目的性,也更加有效。我仍然记得两年前,上述同窗好友在某技术论坛发表的一篇名为《任务分解和任务分配》的帖子,现在看来,在该贴中提出的Effective Communication仍然太过于关注技术视角了,而现在,我则更加注重人文关怀,包括对技术架构。这一点,在本书第十章得到了精彩的阐述。
下面的内容,来自于本书第三章摘录
各种各样的想法是解决问题的核心,没有想法就不可能找到解决方案,但想法太多又会杂乱无章,领导者需要对想法的交流进行有效的管理。以下是领导者常用的12种典型的管理想法交流的方法以及点评。 > 为团队提供一个聪明的想法。尽管这是最显而易见的领导者行为,而且有时新的想法的确会起到关键性作用,但事实上真正全新的想法是非常罕见的。比发掘一个新的聪明想法更重要的是创建一个合适的环境,是能够解决问题的想法一旦提出就能被大家意识到。 > 鼓励和借鉴有用的旧想法。尽管有些领导者不愿意承认,但他们实际上是根深蒂固的模仿者。最优秀的领导者不仅承认这一点,而且将其视为一门艺术而精心培育。 > 认真完善团队成员提出的想法。大部分解决问题型领导者在完善一个想法上花费的时间比提出这个想法多上百倍的精力。 > 放弃自己的想法并支持团队采纳的想法,但只有当每个成员都充分了解你的想法时才予以放弃。放弃或保留你的想法是相当简单的,难的是要做到理智和公正。 > 尽管时间压力很大,仍然不要吝啬花时间听其他人解释他们的想法。迫于时间压力,大部分想法没有经过充分理解就被否决了,事实上,其中一些想法可以为我们节省的时间是花在了解错误想法上时间的上百倍。 > 检验别人提出的想法。在任何给定的环境中,绝大部分的想法都是没用的,但到底哪些才是有用的呢?领导者要做的就是分析和检验这些想法。 > 为了保持想法的交流,不要轻易否定团队成员的想法。尽管检验这些想法是非常重要的,但几乎没有什么想法会危险到使我们来不及重新考虑一下我们的第一反应,就必须立刻否定。 > 如果你不得不否定一个想法,那么一定要明确,你所否定的只是这个想法,而不是提出这个想法的人。解决问题型领导者一直清楚地知道,并不是所有的想法对每个问题都有帮助,但他们更知道,团队中的每一个成员都是有用的。 > 在给出你的想法之前要先对它进行检验。没有人可以聪明到提出所有建设性的想法,而一个喋喋不休地发表自己未经仔细考虑的想法的人却能有效地阻止其他人给出自己的想法。 > 当时间和人力吃紧时,不要再考虑新的想法而应该专注于现有的想法。 > 鼓励团队成员放弃以前曾经成功过,但并不适用于现在情况的想法。 > 如果一个已被否定的想法对问题的其他部分有价值,就应该重新采纳它。其实没有绝对不好的想法,之所以“不好”只是因为它们出现在不适当的地点或时间。
去年年底,osgi R4发布,eclipse建立equinox项目,标志着以osgi为核心的组件管理模型正式进入使用阶段,鉴于今年年初jsr291的推出,osgi正式走向java世界的前端,遂建立osgi观察者group,希望能同所有关心和喜爱osgi的国内技术人员共同进步。 加入osgi观察者:
最近的忙碌加上精神压力,让我患上了胃病,每天吃完饭都会难受好一阵子,给自己学医的儿时好友打电话,被劝之:“人生苦短,要学会善待自己每一天”。遂发此文为戒。
附一篇BJUG中Tin发的文章《白天纽约黑夜巴黎》 ------------------------------- 白天纽约黑夜巴黎 ------------------------------- 【王文华/文】
我在赶些什么?我耗尽青春用尽全力,拼命追求身外之物,结果我真的比别人有钱、有名吗?更重要的,我真的因此而快乐吗?远方有广阔的地平线,为何我还在原地摇过时的呼拉圈?
纽约和巴黎,代表了我人生的两个面向。纽约是白天,巴黎是黑夜。纽约是前半生,巴黎是下半场。
三十五岁之前,我认定纽约是世上最棒的城市。我在加州念研究所,毕业后迫不及待地去纽约工作。一做五年,快乐似神仙。我爱纽约的原因跟很多人一样:她是二十世纪以来世界文化的中心。丰富、方便。靠着地铁和出租车,你可以穿越时间,前后各跑数百年。人类最新和最旧、最好和最坏的东西,纽约都看得见。
所以在纽约时,我把握每分每秒去体会。白天,我在金融机构做事,一天十小时。晚上下了班,去NYU学电影,一坐四小时。在那二十多岁的年纪,忙碌是唯一有意义的生活方式。活着,就是要把自己榨干,把自己居住的城市,内外翻转过来。
这种想法并不是到纽约才有的。其实从小开始,台湾人就过着纽约生活。纽约生活,充满新教徒的打拚精神和资本主义的求胜意志。相信人要借着不断努力,克服万难、打败竞争。活着的目的,是更大、更多、更富裕、更有名。权力与财富,是纽约人的两个上帝。而能帮你走进天堂的鞋,就是事业、事业、事业。
在这种弱肉强食的生活方式,为了保持领先,每个人都在赶时间、抢资源。进了电梯,明明已经按了楼层的钮,那灯也亮了,偏偏还要再按几下,彷佛这样就可以快一点。出了公司,明明已经下班了,却还要不停讲手机,摇控每一个环节。在纽约,为达目的,可以不择手段,甚至赶尽杀绝。在纽约,没有坏人,只有失败者。
台湾,是不是也变成这样?
每一件事,都变成工作。上班当然是工作,下班后的应酬也是工作。有人谈恋爱是在工作,甚至到酒店喝酒、KTV狂欢,脸上都杀气腾腾,准备拚个你死我活。
我曾热烈拥抱这种生活,并着迷于这种因为烧烤成功而冒出的焦虑。这种焦虑让我坐在椅子边缘,以便迅速地跳起来闪躲明枪暗箭。这种警觉性让我练就了酒量和胆量、抗压性和厚脸皮。但也养成了偏执和倔强、优越感和势利眼。在纽约时我深信:能在这里活下来的,都是可敬的对手。黯然离开的,统统是输家。人生任何事,绝对要坚持到底。半途而废的,必定有隐疾。在这不睡的城市,每天我醒来,带着人定胜天的活力,跟着法兰克辛纳屈唱〈纽约?纽约〉:「如果你能在纽约成功,你可以在任何地方成功!」是的,在纽约,现代的罗马竞技场,我要和别人,以及自己,比出高低。
这套想法,在我三十五岁以后,慢慢改变。
第一件动摇我想法的,是父亲的过世。我父亲一生奉公守法、与人为善。毫无不良嗜好,身体健康地像城堡。七十二岁时,他得了癌症、引发中风,经历了所有的痛苦和羞辱。他一生辛勤工作、努力存钱、坚信现在的苦可以换得更好的明天。我们也相信一分耕耘、一分收获,用在纽约拚事业的精神照顾他。但两年的治疗兵败如山倒,最后他还是走了。父亲逝世的那天,我的价值系统崩溃了。我一路走来引以为傲的「纽约精神」,没想到这么脆弱。
不止在病床,也在职场。当我在企业越爬越高,才发现「资本主义」在职场中也未必灵验。上过班的都知道,很少公司真的是「开放市场」、「公平竞争」。大部分的同事都觉得你不是朋友、就是敌人。职场上伟大的,未必会成功。成功的,有时很渺小。很多人一辈子为公司鞠躬尽瘁,最后得到一支纪念笔。那些卷款潜逃的,反而变成传奇。
慢慢的,我体会到:世上有一种比「善有善报、恶有恶报」更高、更复杂的公平。人生有另一种比「功成名就」更幽微、更持久的乐趣。那是冲冲冲的美式资本主义,所无法解释的。
我能在哪里找到那种公平和乐趣呢?我想过西藏、不丹、非洲、纽西兰。然后,我注意到法国。
住纽约时,法国是嘲讽的对象。身为经济、科技、和军事强权的美国,谈起法国总是忍不住调侃一番。法国是没落的贵族,值得崇拜的人都已作古。法国人傲慢,高税率让每个人都很慵懒。动不动就罢工,连酒庄主人都要走上街头。
搬回台湾后,普罗旺斯、托斯卡尼突然流行。我看了弗朗西斯?梅思的《美丽的托斯卡尼》,其中一句话打动了我:「在加州,时间像呼拉圈。我扭个不停,却停在原地。在托斯卡尼,我可以在地中海的阳光下,提着一篮李子,逍遥地走一整天。」
是啊!我在赶些什么?我耗尽青春用尽全力,拚命追求身外之物,结果我真的比别人有钱、有名吗?更重要的,我真的因此而快乐吗?远方有广阔的地平线,为何我还在原地摇过时的呼拉圈?
当我重新学习法国,我发现法国和美国代表两种截然不同的生活方式。美国人追求人定胜天,凡事要逆流而上。法国人讲究和平共存,凡事顺势而为。纽约有很多一百层的摩天大楼,巴黎的房子都是三百年的古迹。纽约不断创新,巴黎永远有怀旧的气息。巴黎人在咖啡厅聊天,纽约人在咖啡厅用计算机。纽约有人潮,巴黎有味道。纽约有钞票,巴黎有蛋糕。
不论是政府或个人,法国人都把精神投注在食、衣、住、行等「身内之物」。就让美国去做老大哥吧。要征服太空、要打伊拉克、要调高利率、要发明新科技,都随他去。法国人甘愿偏安大西洋,抽烟、喝酒、看足球、搞时尚。当美国人忙出了胃溃疡,法国人又吃了一罐鹅肝酱。
讲到吃,法国有三百种起司、光是波尔多就有五十七个酒的产区。晚上六点朝咖啡厅门口一坐,一杯红酒就可以聊三个小时。九点再去吃晚餐,一直吃到隔天凌晨。他们在吃上所花的时间,跟我们上班时数一样。但讽刺的是:他们没有「All You Can Eat」。
吃很重要,但也要会挑时间,朋友介绍我去试一家法国餐厅,提醒我他们礼拜二、四晚上休息。「为什么?」我问。他说:「因为主厨要回家看足球。」
聪明的主厨懂法律。法国法律规定一周工作最多三十五小时,大部分的人一年有五周的假期。而美国人把加班当作自己有价值的表示,度假时还拿着手机回E-mail。法国人比美国人会玩。每年六月的巴黎音乐节,从午后到深夜,几百场露天音乐会在各处同时举行,人多到地铁都暂停收费。每年十月的「白夜」,平日入夜就打烊的店面,彻夜营业到清晨七点。每年夏天,巴黎市政府在塞纳-马恩省河右岸布置了三段、总长一.八公里的人工海滩。细砂、吊床、躺椅、棕榈树,自然海滩有的景致这里都有,让没有钱去海边度假的民众,也可以享受到海滩风光。
当然,法国这么深厚的文化,不可能只从吃喝玩乐而来。美国人读书,为了考证照。法国人读书,为了搞情调。每年十月的读书节,大城市的火车站内,民众轮流上台朗诵诗句。书店营业到天明,整晚有现场演奏的乐曲。「美食书展」选在铜臭味最重的证券交易所举办。小镇书展的书直接「长」在树上,读者必须爬到树上,把书摘下来品尝。
一直跟着美国走的台湾人,会心动吗?
我心动了。十一月我到巴黎,一位法国朋友来接待我。临走前我问他:「明天你要干嘛?」
「我要去银行。」
「然后呢?」我问。
「我不懂你的意思......」
对我来说,「去银行」是吃完午饭后跑去办的小事。对法国人来说,这是他一天全部的行程。法国人总是专心而缓慢的,每天把一件小事做好。
这样的生活,对美国或台湾人来说,实在是太颓废了。的确也是。法国失业率接近10%,高税率让雇主宁愿打烊休息,免得帮员工缴税。巴黎闹区纸醉金迷,但郊区的少数民族却没有工作机会。这些都是黑暗面,但对于每日被强光烤焦的台湾人,阴暗也许提供了喘息空间。生命的终点都一样,有钱人的丧礼只是比较多人上香。不断的追赶只是提前冲向谢幕,为什么不把时间花在慢慢为生命暖场?你不需要一辈子鞠躬尽瘁、死而后已。你可以偶尔伸伸懒腰、安步当车。
我从巴黎回来,台北并没有改变。关了两周的手机再度响起,一通电话找不到我的人会连续狂call十通。和朋友见面,他很关心地问我:「好了,你现在工作也辞了、欧洲也去了,接下来有什么projects?」
「Projects」?多么纽约的字眼。
我真想说:「好好生活,不就是人生最大的project?」但我知道在熙来攘往的台北街头,在不到四十岁的年纪,这样说太矫情了。况且,我今天之所以有钱有闲享受法式生活,不也正因为我曾在美式生活中得到很多利益?我仍热爱工作、热爱纽约,但已不用像二十岁时一样亦步亦趋、寸步不离。
所以我说:「我还是会早起,白天努力写作。但到了晚上,我想关掉手机。」
世界少了我,其实无所谓。但我少了我,还剩什么?
他笑一笑:「你这是用纽约来过白天,用巴黎来过黑夜。」
唉,他讲得真好!这应该是一个完美的妥协吧。也许有一天,我能创造自己的「白夜」,让白天和黑夜融合在一起。但我还没到那个境界。
「明天星期一,你要干嘛?」他问。
「我要去银行。」
「然后呢?」
我张大眼睛,停顿了一下。
「然后呢?」他追问。
「然后我会摩拳擦掌,认真地写一篇文章。」
我们是不是也应该学一学法国人呢?提高些生活质量,注意身体。
很久没更新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
摘要: Eclipse3.1刚刚release的时候,它的RCP发布功能就很吸引我,当时正好有个小东西要做,就用了这个功能发布了一个小程序,似乎很多人推荐用NSIS,但是我觉得Eclipse的这个功能似乎更方便,几乎不用担心任何部署的问题。
阅读全文
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年让我感觉到人的精力毕竟有限,以及,一个纯技术人员能发挥的能量实在太小了,虽然不情愿,但这可能促使我更早的脱离纯技术岗位,真是凌乱的一年......
开发一个基于消息的解决方案是不容易的事情,在生产中操作这样一个产品同样也是一个挑战:一个基于消息的集成解决方案一天可以产生、路由和转换成千上万的消息。我们不得不处理异常、效率瓶颈或改变合作系统。而为了使事情变得更加有挑战性,组件经常被分布在不同的平台和机器上,甚至位于不同的地理位置。
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将这个症状称为“架构师的梦想,开发者的梦魇”。低耦合的架构原则以及间接的依赖于外部系统提供了灵活性。然而,测试一个消息生产者不了解消息消费者的系统可能会是一个挑战。另外异步的和时间相关的消息使得事情变的更加复杂。举例来说,消息方案可能被设计没有被成消息生产者者必须从接受者那里得到一个回应。同样的消息基础设施通常保证传输消息,但不能保证传输时间。这是的开发基于消息传送结果的测试用例变得困难。
当监控一个消息解决方案,我们可以在两个抽象层面上跟踪消息流。一个典型的系统管理方案监控多少消息被发送或者它多长时间得到一个被处理的消息。这些监控方案不检查消息数据,除了可能会检查消息头中的几个字段(比如消息标识或者消息历史)。与之相对的,BAM(business activity monitoring)方案聚焦于包含在消息中的有效数据,举例来说,发生在过去一小时的所有订单的金额。System Management中的很多模式都足够通用并可以用在以上两个目的中(监控消息头或者消息内容)。然而,由于BAM本身就是一个新领域,并且需要从数据仓库中获得很多数据(有些我们根本就没有涉及到),我们决定在系统管理的内容中讨论这些模式。
系统管理模式被设计用于为保持一个基于消息的复杂系统的运转所提出的需求并提供工具。System Management的模式涉及三个种类:监控和控制,观察和分析消息流量,测试和调试。
监控和控制
一个Control Bus提供一个单独的控制点来对一个分布式方案进行监控和管理。它将多个组件连接到一个中心管理控制台,这里可以显示每个组件的状态并且监控通过每个组件的消息流量。控制台同时也可以用于发送控制命令给组件,比如,转变消息流。
我们可能想要在路由消息时添加附加的步骤,比如验证或者日志。由于这些步骤可能使效率降低,所以我们可以通过Control Bus来控制他们开关。一个Detour为我们提供这种能力。
观察和分析消息流量
有时我们想要在不影响主要消息流的情况下观察消息的内容。一个Wire Tap允许我们接入到消息流中。
当我们调试一个基于消息的系统,知道一个特定的消息在哪使很有帮助的。Message History保留一个消息访问过的所有组件的日志,而不需要增加组件间的依赖。
然而Message History依赖于单独的消息,一个中心的Message Store可以提供一个穿越系统的每个消息的完整记录。结合Message History,Message Store可以分析所有消息穿过系统的可能路径。
Wire Tap, Message History, 和Message Store帮助我们分析异步的消息流。为了跟踪发送到请求-应答service的消息,我们需要在消息流中插入一个Smart Proxy。
测试和调试
在部署前测试一个消息系统是一个非常好的注意。但是测试不应该停止在部署前。你应该有能力验证正在运行的消息系统运行持续的运行正常。你可以周期性的发送一个Test Message到系统中并验证结果。
当一个组件失败或者运行不正常,它可以简单的终止,并放弃一个channel中的剩余消息。在测试期间这是很有用的。一个Channel Purger可以为我们做这些。
最近身体不太好,转贴一则文章,提醒自己多多休息和锻炼。 ------------------------
只要踏入在我们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/
上面下划线的是我有的问题,你都有哪些?
经过这半年的使用,WTP在我们组内已经从只用于开发Web Service的工具变成web开发的首选插件 虽然只是0.7版,但WTP的设计确实很好,目前WTP1.0已经release到了M9,还有20几天就到达release date了,热烈期待中....
在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的消息对于监听着这个channel的Message Endpoint都是可用的。然而有些消费者并不打算处理channel上的任何消息,而是希望只处理其中几种。这样一个识别的消费者可以使用一个Selective Consumer来描述它将接收什么类型的消息。然后消息系统将只将匹配的消息对该接受者描述为可用。
当断开连接的时候订阅消息 - Publish-Subscribe Channels带来的问题是,如果一个消费者感兴趣一个channel,但是现在网络是断开的怎么办?是不是一个未连接的应用将错过发布的消息,即使它已经订阅过该消息?默认的,是的,订阅只对连接的订阅者有效,为了使应用不会因为连接而错过订阅的消息,要使用Durable Subscriber。
等幂 - 有时一个消息可能被传输不只一次,可能因为消息系统不确定该消息是否已经被成功的传递过,或者可能因为Message Channel的QoS被设置较低来提高效率。另一面的,消息接受者认为每个消息只会被传输一次,并且当它们重复处理相同的消息,它们会出错。一个Idempotent Receiver可以优雅的处理重复的消息,并且阻止它们引起接收者应用的发生错误。
同步或异步服务 - 另外一个选择是一个应用应该暴露它的service为同步(RPI)还是异步的(Messaging)。不同的客户端可能喜欢不同的方式;不同的环境可能需要不同的方式。既然很难选择,就一起使用。一个Service Activator连接一个Message Channel到一个应用的同步服务以便当一个消息被接收,service就被调用。同步客户端可以简单的直接调用service;异步客户端可以通过发送消息调用service。
Message Endpoint的相关主题
Message Endpoint的另外一个重要主题是很难同其他模式共同应用Transactional Client。Event-Driven Consumer通常不能适当的在外部控制事务,Message Dispatcher也必须小心的设计这个问题,Competing Consumers的事务也是个重大问题。最安全的使用Transactional Client是使用一个单独的Polling Consumer,但是这不会是一个令人满意的解决方案。
这里特别要提到应该会保证成功的JMS风格的MDB,EJB的一种。一个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模式用于解释这些选择是什么以及如何最好的使用它们。
通常,通过消息系统集成的应用很少有同样的消息格式。比如说,一个帐务系统同一个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 Channels和Message Routers可以通过消除应用必须知道另外一个应用的位置的需求从而解除应用间的基本依赖。
一个应用可以发送一个消息到Message Channel而不必担心谁来取出消息。然而消息格式增加了另外一种依赖。如果一个应用不得不将消息格式化成另外一个应用的数据格式,通过Message Channel解耦的说法就像一个幻想。接收系统的任何改变或切换到另外一个接收系统都需要对发送应用进行改变。Message Translators可以帮助除去这种依赖。
元数据管理
将消息从一个消息格式转换到另一个格式需要操作元数据 - 描述数据格式的数据。
元数据在两个并行系统之间的集成中扮演着非常重要的角色。一个处理实际的消息数据,另外一个处理元数据。许多用于处理消息数据的模式也同样可以管理元数据。比如说,Channel Adapter不仅可以从一个系统中移进和移出消息,还可以从一个外部应用中获取元数据,并将其加载到一个元数据仓库中。使用这个仓库,集成开发者可以定义应用元数据与Canonical Data Model.之间的转换。
元数据集成
举例来说,上面的图描述了两个需要交换客户信息的应用的集成。每个系统的客户数据的定义稍有不同。从A到B的消息需要转换一下才能被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》。
在前面的关键组件中我们提到了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接受到一个超出该时间点的消息,也要取消该消息。
总之,只选择使用消息是不够的。使一个消息工作的其他决定性因素来自于消息所要完成的任务。
在前面一个专题中,我们列出了一个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,并在请求消息中指定该channel为Return 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 Delivery将channel持久化以便将它们的消息存储到硬盘上。这会影响效率,但会使消息更加可靠,即使消息系统是不可靠的。
非消息客户端 - 如果一个应用不能连接到一个消息系统但是仍然想要参与消息怎么办?通常它只能自认倒霉了,但是如果消息系统可以通过某种方式连接到应用系统 - 通过它的用户界面,它的service API,它的数据库,或者一个TCP/IP或HTTP这样的网络连接 - 那么消息系统可以使用一个Channel Adapter。这允许你连接到一个或多个连接到应用的channel而不必改变应用或者可能也不需要一个同应用运行在同一个机器上的消息客户端。有时‘非消息客户端’真的是一个消息客户端,但是只有连接的是其他消息系统的时候。
通讯中枢 - 随着越来越多的企业应用系统连接到消息系统以便通过消息暴露他们的功能,消息系统变成了企业中一站式功能的集散地。一个应用只需简单的知道用哪个channel来请求功能,以及从哪个监听结果。消息系统本质上变成一个消息总线,一个提供所有企业应用甚至变化中的应用和功能的中枢。你可以更快速的集成。
如你所见,使用消息构建应用不仅仅是将他们连接到消息系统并发送消息。消息必须使用Message Channel来发送。Channel必须被设计为某个目的服务,比如基于被共享的数据类型,共享数据的应用类型,和接收数据的应用。
企业集成有很多种模式,随着技术的发展,实时的、面向消息的企业集成越来越成为主流,面向消息的企业集成的稳定性和兼容性要求其基础件,也就是message系统必须提供足够强壮和可扩展的设计,下面几种是作为面向消息的企业集成的基础件所必须提供的几个关键性组件。
消息集成使得message系统负责转换两个应用之间的数据格式,从而使得应用可以专注于他们需要共享什么数据而不是如何共享它们。
以下这些组件,在著名的ESB系统Mule中都可以见到,有兴趣的同学可以去看看Mule的源代码,虽然Mule对ESB的实现有很多不成熟的地方,以至于让我不敢在生产系统中使用(唉...可恨的Mule),但是毕竟是一个大而全的系统,值得借鉴一下。
Channels — Messaging应用通过一个Message Channel传送数据,一个sender到receiver的虚拟管道。一个新安装的消息系统默认不包含任何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 — 不同的应用的数据格式可能不同。为了调节sender和receiver之间的数据格式不同的问题,message必须经过一个中介的filter,一个Message Translator,它将message从一个格式转换成另外一个格式,或转换成一个公共的格式。
Endpoints — 大多数的应用程序没有内建的能力来同一个message系统交互。因此他们必须包含一个中间层,它知道应用系统如何工作,也知道message系统如何工作,并桥接两个系统。这个系统是一组并列的Message Endpoints,它能够使得应用发送和接受message。
System manager - 作为一个大型的消息集成系统,其面向消息的、异步、低耦合的本质使得系统更加难以调试,运行期的状态也难以跟踪,所以,我们必须有强有力的手段进行系统的运行期管理和监控,同时最好能够在运行进行动态更新,以保障系统的强壮性。
企业应用集成是一个巨大而复杂的系统,作为其基础件ESB系统,必须能够提供对其完全的支撑以及足够强壮的系统,这正是ESB系统建设的难度所在。
这个动态图片的实现原理是在servlet的response中写入一个ImageOutputStream,并由servlet容器将其转成图片,在非webwork的实现中,可以直接操作response,但是在webwork中,要想直接操作response的output则必须使用不需要对response操作的result类型
实现一个Result:
不可以用普通的dispatcherResult在response的outputStream中写入东西,否则将覆盖所有的dispatcher的jsp页面
上次的代码忘记加上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(0, 0, 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);
}
转载请注明作者和来源.
最近登陆google,看到了google的主页上的新软件:Picasa2
最新! Google 的照片管理软件:查找、编辑和分享您计算机上的照片
下载试用了一下,感觉很不错,设计的很人性化,越来越觉得google在关注用户体验方面不输于MS
《秘密》 主演:小林熏 广末凉子 -虽然每个女人都想再回到18岁,可是以这种方式回到18岁,我想她宁愿不回去。
影片简介:
◎译 名 秘密 ◎片 名 Himitsu ◎年 代 1999 ◎国 家 日本 ◎类 别 剧情/幻想 ◎语 言 日语 ◎字 幕 韩文/英文 ◎IMDB评分 6.6/10 (97 votes) ◎IMDB链接 http://www.imdb.com/title/tt0211413 ◎文件格式 XviD + AC3 ◎视频尺寸 720 x 384 (1.88 : 1) ◎文件大小 15MB x 100 ◎片 长 01:59:53 (119 Min ◎导 演 Yojiro Takita ◎主 演 Ryoko Hirosue .... Monami Sugita/Naoko Sugita Yuriko Ishida .... Taeko Hashimoto Hideaki Ito .... Haruki Soma Ken Kaneko .... Fumio Kajikawa Kayoko Kishimoto .... Naoko Sugita 小林薰 Kaoru Kobayashi .... Heisuke Sugita 大杉涟 Ren Osugi .... Hiroyuki Kajikawa Rie Shibata .... Kazuko Yoshimoto Tomoe Shinohara .... Kuniko Kimura Hatsuo Yamatani .... Naoko Sugita
◎简 介
一对母女搭巴士准备回老家祭祖。巴士的司机(约40~50岁的中年人)因为要供儿子上学所以兼职加班,因此睡眠不足,结果在路上出了车祸。由小林熏所饰演的男主角(剧中约40~45岁)经由新闻得知太太跟女儿出了车祸,赶到医院时,太太撑不了多久就死了,结果当女儿清醒时,他才发现太太的灵魂进入了女儿的身体。总之,就是太太的身体死了,灵魂跑到女儿的身体里,而女儿的灵魂则消失了。
当男主角经历了这样的事故之后,他不知该如何悲伤,原因是太太死的是身体,但还是藉由女儿的身体生活着,而女儿的灵魂消失了,但却还是看的到人。那失去的到底是什么呢?
当女主角(广末凉子饰演)出院后便与男主角过着奇异的生活。女主角用着女儿的身体,立志帮女儿生活下去。于是便帮女儿完成了高中的学业并且考上了医学院。在这个时间里女主角在家中依然扮演着妈妈的角色,但在外面则得假装是自己的女儿。
男主角跟女主角的生活开始有了摩擦。男主角无法跟女主角过着夫妻的生活,因为他爱他的太太,他也很爱他的女儿,所以他无法跟他太太过之前的生活。而女主角上了大学之后,开始参加社团的活动,而且认识了不同的人,于是先生开始约束太太的生活,并且私下偷听太太的电话与偷窥太太的私人物品。
女主角无法接受无隐私的生活,而她依然深爱着她的丈夫,然而男主角却坚持生活上需保持父女的关系,只有在精神上维持夫妻的关系。在这样的情形下,深深的伤害了两个人的生活,在一次的争吵之后,女主角假装女儿的灵魂回到了身体。于是先生快乐了起来,因为女儿跟妈妈又与他一同生活,只是后来妈妈出现的次数越来越少,最后妈妈终于消失了,只剩下女儿活着。
几年后,女儿终于要结婚了,结婚的对象是当初肇事司机的儿子。在结婚典礼完毕后父亲与女儿正在话别,此时女主角不小心做了一个只有妈妈才知道的小动作。这时男主角才发现女主角依然是妈妈而不是女儿,而他的太太却嫁给了别人。这时两个人都非常的难过,然而这却是无法改变的事实。
Duncan's心情:
这部片子的过程中是蛮幽默的,而且剧情也很特殊。不过整片的风格让人有种浓郁的忧伤。到了结局,更让人感到深深的无奈。
一开始所思考的第一个问题,即是女儿离开的事实。但是到底应如何哀伤呢?失去的是感受的灵魂而不是身体,然而人们都是用眼睛来思考,那么哀伤是如何的感觉呢?光是这个问题就让我思考了很久,我觉得这是一个很有想象力的假设。
第二个问题,原本认为两人仍能快乐的生活下去。但是这却突显了时间与环境对于人们的改变。大多数的人们都恐惧改变,由于女主角变换了身体,所以生活有了不同的变化,她再度回到学生的日子,不在是家中的主妇生活,一下子生活的视野宽阔了起来。然而男主角依然是拉面研究公司的老师,他已经是中年人,过着一成不变的生活,他并没有改变,然而女主角的改变却连带的影响了男主角的生活。所以世事都是无常的,有许多是我们无法去承诺的。
第三个问题是爱的极限。男主角因为爱他的太太与女儿,所以事情发生后他选择了痛苦的生活,不论是生活上或是精神上。太太也爱先生,也深爱女儿。所以最后她决定以女儿的身分生活,帮她女儿过完他无法继续的人生。原本他选择跟她先生一起度过,然而她先生却再也无法快乐的生活,于是她只好真的扮演她自己的女儿,再也无法过她原本的生活,包括私人的时候。
因为爱的太深,所以突显了生活是如此无奈。一辈子的誓约,女主角经历了两次,那是多么的幸福却又多么的残酷。
所以爱能有多深呢???
爱到浓时,真的是幸福吗???
推荐大家看看这部片子,尤其是感情已经到老夫老妻境界的人,也许会有更强烈的感想吧!
这部片子的主题曲是「天使的叹息」,真是贴切,所有的感想到后来便成了深深的叹息!
摘要: 很久没更新了,拿以前写的日记充充数 阅读全文
六度分割是这样的理论:所谓六度分割理论是指six degrees of separation,是在20世纪60年代由哈佛大学心理学家 stanley milgram提出的,six degrees of separation,六度分割。简单来说,六度分割就是在这个社会里,任何两个人之间建立一种联系,最多需要六个人(包括这两个人在内),无论这两个人是否认识,生活在地球的任何一个地方,他们之间只有六度分割。 1、残缺的六度 (1)关系的强弱——权值问题 (2)到达和建立联系的区别——目的和结果问题 (3)传递的成本和激励——阻尼问题... 这两年,社会性网络的探讨在国内很热,很多搞网络多年但是还没发家的都在抄这个概念。 随着社会性网络的探讨逐渐走向成熟和实用化,很多网络大潮的前沿人士已经开始实践六度分割理论,国内的 linkist就是在社会人脉方面的一个实践 可以使用下面的链接加入我的交际圈: ,Just for fun!^_^ 下面这个试验很有意思,有兴趣的朋友可以实践实践 用六度分割理论买火车票不过六度分割理论虽然很可能是正确的,但是对于现实来说,确没有太大意义,如果不能建立高度信任的关系,仅仅认识是不够的,要想调动人脉资源还是主要靠一度或二度联系,要想让一个朋友的朋友的朋友的朋友帮你搞点事情....除非有利益驱动。 最后推荐一篇很好的关于六度理论和SNS实践的文章 残缺的六度理论和SNS的实践者们
23号,Webwork团队的领导者写了篇Blog宣布如下信息: adopted Spring as the official IoC container. WebWork's own IoC container is deprecated as of version 2.2 beta 2. WebWork的Ioc容器停摆了 http://blogs.opensymphony.com/webwork/2005/09/spring_and_webwork_together.html新的集成方法使得Spring的applicationContext.xml中的Action的配置更加简单 http://wiki.opensymphony.com/display/WW/Spring在Spring的网站首页上也报道了该事件 http://www.springframework.org
写了几个月的通讯中间件,再次带领一个J2EE项目,使用WebWork、Spring、Hibernate,感觉写J2EE项目就像在休假,要考虑的事情少之又少,无论是效率、异常处理、线程调度、架构模式,一切都不再那么重要,无需考虑那么多,只要语义清晰,沟通流畅就好了。 想起一周前跟Jerry聊天,说起因为Unixware下JDK1.3的notify语义的不稳定问题而一天内重新编写了三次通讯框架,最后采用了完全非框架的过程化写法,Jerry说应该先写出一个实现,然后在之上重构,就像爬山一样,不可能一下子攀登到顶峰,当时虽然心里感觉不是这样,但竟一时语塞,不知从何说起,再次回到J2EE开发,才恍然明白那天的感觉,框架开发和业务开发的不同就在于,很难重构,尤其是通讯框架,架构通常决定了它的几个重要指标。
架构模式不同于设计模式,设计模式的问题可以通过重构解决,而架构模式几乎只能重新做(当然也有例外),架构一旦确定,很多东西就无法再加入,所以为什么很多开源的J2EE框架在大版本升级后不得不抛弃向后兼容。这也是为什么国产通讯框架Cindy的作者想在其中加入FilterChain,而最终放弃的原因,因为这对基础库的改动实在太大。
而MINA的架构就足够灵活,它屏蔽了不同通讯方式和通讯底层事件机制的差异,就像在如同Cindy和Netty2这种基于NIO的reactor模式之上的框架,要想重构到BIO,就几乎要全部重写,不过Netty2要好一些,毕竟有Netty1作为铺垫,所以在NIO的reactor的路上走的不是很远(NIO的reactor实现真是的不咋个),而MINA则只需要在SocketIoProcessor中使用Helf Sync/Helf Async模式替换掉reactor之上的事件处理即可,当然,最好还要提供线程池以便进行overload shield,在向Apache LDAP团队提交了MINA的JDK1.3核心库时也曾想提起该问题,可惜后太忙,忘记了。不过我想以Trustin的聪明,一定会想到这个问题。
又一名IT精英人士英年早逝,北京和北京IT圈成为培养精英及早逝精英的温床
北京几秒钟产生一个百万负翁职业IT人在IT“榨汁机”里的逝水年华
Trustin Lee,MINA、Netty2通讯框架的作者 韩国人,80年出生,8岁起在MSX迷你计算机上编写BASIC程序,爱好游戏编程以及使用汇编、C和C++解决编程问题,1998年获得韩国信息奥林匹克竞赛铜牌。 就读于韩国Yonsei大学计算机系期间,曾为多家公司编写高性能网络应用以及少量的web程序,毕业后,就职于Arreo通讯公司,该公司为韩国最大的移动短信提供商之一。 目前为Apache SEDA framework的主要开发者以及LDAP的网络框架MINA的作者。
四、预览结果
使用BIRT提供的预览窗口来预览所制作的报表,这是BIRT必须知道该如何找到在Script中引用的类,而BIRT的预览窗口是使用一个内嵌的web服务器来预览的,所以,我们需要将用于数据库资源访问的类和在script中使用的类打包成jar放入到这个web-app的classpath下。
这个web-app是作为一个Eclipse的plugin存在的,它位置在:
<ECLIPSE_HOME>\plugins\org.eclipse.birt.report.viewer_1.0.0
将打包好的jar文件放入到该plugin下的如下目录:
<ECLIPSE_HOME>\plugins\org.eclipse.birt.report.viewer_1.0.0\birt\WEB-INFO\lib
然后将你的数据库访问组件所依赖的jar文件都一并拷贝到这个lib目录下,并将数据库访问组件需要的配置文件放入到WEB-INFO下,以便其可以在这个web应用的classpath中找到自己的配置文件
另外,如果使用配置文件的话,需要象在Tomcat中使用配置文件一样,将配置文件拷贝到以下目录,以便dom4j能够找到
<ECLIPSE_HOME>\plugins\org.eclipse.birt.report.viewer_1.0.0\birt\WEB-INFO\classes
最后,也是最重要的一点!也是困扰了我几个小时的问题
教程中没有提到,拷贝完自己的这些数据库访问组件后,需要重启Eclipse才能使用!!?
这个viewer的web程序会在每次Eclipse启动时启动,并读入这些配置信息,运行期则不会在重新装载配置信息
―――――――――――
另外,还有另一种方法来发布数据库访问组件,就是将编译好的class文件放入到这个WEB-INFO目录的classes目录下,但要注意要建立目录以匹配自己的包结构,就如同普通的Tomcat程序那样
―――――――――――
预览结果:(图)
五、 发布环境中运行
发布时的操作要比预览时简单的多,你可以将这个报表文件当作你的web程序中的一个JSP文件来通过URL来访问,并可以在URL中传递参数给报表文件,以便指定查询条件,这些问题在BIRT的教程中讲的很清楚了,这里就不再说明
开始说正题
二、建立使用ScriptDataSource和ScripteDataSet的BIRT报表
在你的Web项目中建立一个report目录,并在其中建立一个报表文件,如下:
首先,根据BIRT的Help文档中的教程,建立一个ScriptDataSource:
然后建立ScriptDataSet:
然后鼠标右击建立的DataSet,选择编辑,在左边选择‘输出列’,为其添加三个输出列,类型为‘任何’,建立后DataSet如下:
三、编写ScriptDataSet方法
ScriptDataSet的主要方法有三个:open、fetch、close
打开rptdesign文件,用鼠标点击srcDataSet,并在报表文件窗口下方选择‘代码’,就可以看到这些方法,这些是一些类javaScript的代码,并提供了一些BIRT自己的函数,下面说明这三个方法:
l Open方法:
Open方法用于引入java包,并创建数据库访问资源
写入如下代码:
(其中in_sys_user是数据库中的表)
l fetch方法:
fetch方法用于取得数据并为报表复制
代码如下:
l close方法:
close方法用于关闭资源
代码如下:
摘要: 配置文件dbconfig.xml如下:
1<config>2 <dbinfo>3 <url>jdbc:oracle:thin:@133.1.72.44:1521:test</url>4  ... 阅读全文
摘要: 在前面说明过使用Script数据源来获得web service数据源的做法,在实际操作中,发现虽然有BIRT的帮助文件,但同事对BIRT的Script数据源的使用还是不太理解,于是写出下文以便帮助使用BIRT的高级特性
熟悉了BIRT的Script数据源之后,你会感叹BIRT功能之强大,BIRT团队承诺在2.0中加入对数据库连接池的支持,但目前为止,我们还只能通过Script数据... 阅读全文
今天跟好友在网上聊天,被问到如何使用web serivce作为数据源来制作BIRT报表,BIRT的例子里都是基于数据库表来构建报表的,所以产生了这个疑问,本想写一篇step by step的文章来详细介绍一下,可是最近实在太忙了,只好在这里介绍一下思路。 这个问题,可以使用ScriptDataSource和ScripteDataSet来解决,ScripteDataSource后台基于java bean,可以在bean里连接自己的数据源,无论是用web service还是用socket取数据源都应该没什么问题,另外还可以为BIRT报表提供数据库连接池,因为本来的报表设计文件是自己去连数据库的,所以难免会比较慢 另外一个问题是基于属性拖拽的问题,这个问题我没有具体试验过ScriptDataSet中的属性拖拽是否可用,但我想既然基于表的可以,基于Bean的对于BIRT的开发组来说也没什么难度,毕竟属性都已经绑定到DataSet里了,拖拽一下又有何妨
BIRT作为Eclipse的BI和Report工具,由业界领先的公司Actuate公司开发,总体印象来说,在java报表方面已经很强了,当然比起一些商业工具还是有差距的,最近在一个BOSS系统上看到的报表so强,据说那工具70W一套,比起Actuate公司的商用BIRT贵了不知道多少倍,不过感觉还是满不错的。 java在报表方面要想达到PB那样简单易用还是比较难,对于BIRT来说,首先是高级查询报表的实现,必须依靠ScriptedDataSource和ScriptedDataSet,而BIRT在这个事情上则只起到了一个界面生成的工具的作用,为了生成Excel的报表,则必须自己制作一个report engine嵌入到BIRT的framework中去,另外让我不解的一个问题是BIRT竟然将插入到报表中的图片以二进制源文件的形式存储在XML格式的.rptdesign文件中,而web报表的参数传递全部采用http的get方式,why not post?? 总之在BIRT中制作初级报表以及固定查询条件组合的报表还是比较方便的,几乎都是自动生成了,还算比较合用,虽然有时候会有点Bug,而且速度也不快。但是在高级条件组合查询方面还稍显不足,只有自己写数据库访问类来解决这个问题,不过有这样的开源工具用,也算是很幸福了^_^
l 使用DataSet的‘open’方法来执行初始化任务:右击DataSet选择‘编辑代码’,然后在其中选择‘open’方法,这里初始化一个java对象来完成数据访问功能
l Open方法
a) 在script中引用的包含java对象的class文件的jar文件,必须包含在<ECLIPSE_INSTALL>\plugins\org.eclipse.birt.report.viewer\birt\WEB-INF\lib.目录下
b) 引入一个package:importPackage(Packages.com.yourCompany.yourApplication); 引入通常在open方法的第一行。
c) 创建一个java对象的实例:var myList = MyListFactory.getList();
d) 从java对象中获取数据的典型方式是从该对象中获得一个包含数据的Iterator: var iterator = myList.getIterator();
l Fatch方法(fatch方法从Open中创建的java实例中获得数据,并赋值给行)
a) Fatch方法的第一步是判断Iterator中是否有数据: if(iterator.hasNext() == false ){ return null; }
b) 然后是从iterator中得到一个行对象node以便得到该行中每列的数据: var node = iterator.next( ); row[1] = node.getFirstCol( ); row[2] = node.getSecondCol( ); row[3] = node.getThirdCol( );
c) 最后,是返回true:return true;
l Close方法:
a) 最后,在Close方法中清理所有创建的对象: myList = null; iterator = null; node = null;
l 每个应用只需创建一个ReportEngine的实例
l ReportEngine的构造函数要传入一个EngineConfig作为参数,如果参数为null,则一个默认值的ReportEngine被创建。
l 退出时,应用应该调用destroy()来卸载外挂以及删除临时文件
l 使用report engine有以下几个主要步骤:
a) 创建一个EngineConfig来设置report engine的选项
b) 创建一个ReportEngine类的实例
c) 你可以用这个对象去进行多种任务
d) 使用ReportEngine的一个openReport( )方法来打开一个report design文件
e) 使用IgetParameterDefinitionTask来获得report参数的信息
f) 使用IrunAndRenderReportTask运行并转换一个report到一个输出格式
g) 调用你的report engine的destroy( )方法
l EngineConfig:The EngineConfig class wraps configuration settings for a report engine. It allows a developer to specify where to look for engine plug-ins and data drivers, and to add an application-wide scriptable object.
l IReportRunnable:为了使用report engine,你必须首先调用openDesign( )方法来打开report设计文件,这些方法返回一个IreportRunnable实例来代表report设计文件的engine’s view。使用IreportRunnable做以下任务:
a) Get parameter data
b) Get report title
c) Get report author.
d) Get images embedded within the report design
e) Run the report
l IEngineTask:该类提供一个管理脚本上下文以及report locales的框架,它从ReportEngine的工厂方法中创建,需要参数:IreportRunnable对象、a scripting context, and a locale。
l 应用开发者只需要了解公用的API,这些API包含在以下的几个包内:
a) org.eclipse.birt.report.model.api:这个包内包含了93个class,两个接口和一个exception,这个包是为那些想要定制report designer的开发者使用的
b) org.eclipse.birt.report.engine.api:这个包包含了一个类,17个接口和四个exception,是给那些想要定制一个report generator的开发者使用的
c) org.eclipse.birt.chart hierarchy:这个包是给想定制一个chart generator的开发者使用的
l BIRT report engine在几个环境提供了报表生成和翻译服务,包含以下组件:
a) Stand-alone engine:这个engine可以让开发者使用一个命令行程序来从一个report design文件(.rptdesign)中得到Html或PDF格式的report
b) BIRT report viewer:BIRT Report Designer使用它来预览report。这个程序是一个web程序,它运行在一个Eclipse内嵌的Tomcat中,这个Tomcat中有一个内嵌的report engine
c) Custom report designer with an embedded engine:一个定制的桌面报表应用集成BIRT report engine来预览报表
d) Web application that embeds the engine:一个类似于BIRT report viewer的Web程序,可以产生基于web的报表。
l Report engine的核心engine运行并实施报表,而将其他的环境相关的任务留给运行该引擎的应用程序,比如:URL construction, image storage, and design file caching
l BIRT report engine的API可以做以下几件事情:
a) 发现一组为报表定义的参数
b) 获得参数的默认值
c) 运行报表产生HTML或PDF格式的输出
d) 为报表产生图片或chart
l 你可以使用以下几种技术来过滤数据集:
a) 在查询时指定过滤,以便在数据库或其他数据源中过滤数据,要尽量使用这种方式来过滤数据,可以通过两种方式来指定SQL SELECT声明:
1. 在设计期间的SQL Select中以WHERE的方式指定,并在数据库中执行。
2. 创建report参数来让用户指定,在SQL SELECT的WHERE处使用参数来指定条件,使用这种方式,WHERE的参数在运行期指定,并在数据库中执行。
b) 在BIRT Report Designer中过滤数据,使用javascript或者数据不是在一个数据库中从而不能执行SQL语句的情况下,可以用以下两种方式来执行这种过滤:
1. 编辑数据集来指定filter,使用这种技术,查询获得你的SELECT活动的全部数据,然后BIRT Report Designer过滤数据以便获得符合你指定的条件的数据,由于数据集只能有一个,所以这种技术只能使用一种table或者所有的report都显示相同的行
2. 编辑report element filter properties来指定要显示的行,使用这种技术,BIRT Report Designer处理这个过程,如果有多个table、list或chart使用同一个数据集,而且要显示不同的行,则就需要使用这种技术
这家旧金山南部的软件厂商Actuate是商业智能厂商中的佼佼者,于去年7月加入Eclipse为其制作了商业智能及报表工具(BIRT),使用BIRT的朋友应该认识一下他。同时认识一下构架于BIRT上的商业组件,这就是Eclipse生态系统的威力。 公司网站: http://www.actuate.com/home/index.asp
Google的翻译服务,非常有意思,虽然有时候翻译不是很准确,但却可以整个页面的翻译,有点象金山快译,还提供打印版本。 下面是本页的翻译: English
WTP对于J2EE开发者来说是新的福音 尤其是在开发Web Serivce的时候,简直太方便了 还有对于XML、XSD、WSDD文件的编辑 WTP项目组放出的教程也很全面,如下: http://www.eclipse.org/webtools/community/community.html#tutorials只不过这套教程的版本有点老,是基于M4的,所以有些界面有点变化 另外,根据WTP的数据库浏览子项目RDB开展的DTP项目也已启动 计划明年三月Eclipse年会之前Release,据称可以支持Oracle的PL/SQL开发 大家期待吧!
|