<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>搜斧在wordpress</title>
	<atom:link href="http://searchfull.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://searchfull.wordpress.com</link>
	<description>Java技术，Scrum敏捷开发</description>
	<lastBuildDate>Tue, 07 Apr 2009 08:29:37 +0000</lastBuildDate>
	<language>zh-cn</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='searchfull.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>搜斧在wordpress</title>
		<link>http://searchfull.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://searchfull.wordpress.com/osd.xml" title="搜斧在wordpress" />
	<atom:link rel='hub' href='http://searchfull.wordpress.com/?pushpress=hub'/>
		<item>
		<title>用Scratch教孩子学习编程</title>
		<link>http://searchfull.wordpress.com/2009/04/07/%e7%94%a8scratch%e6%95%99%e5%ad%a9%e5%ad%90%e5%ad%a6%e4%b9%a0%e7%bc%96%e7%a8%8b/</link>
		<comments>http://searchfull.wordpress.com/2009/04/07/%e7%94%a8scratch%e6%95%99%e5%ad%a9%e5%ad%90%e5%ad%a6%e4%b9%a0%e7%bc%96%e7%a8%8b/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 08:29:37 +0000</pubDate>
		<dc:creator>searchfull</dc:creator>
				<category><![CDATA[Java技术]]></category>

		<guid isPermaLink="false">http://searchfull.wordpress.com/2009/04/07/%e7%94%a8scratch%e6%95%99%e5%ad%a9%e5%ad%90%e5%ad%a6%e4%b9%a0%e7%bc%96%e7%a8%8b/</guid>
		<description><![CDATA[很多情况下，家长并不知道怎么编写程序，也就没有办法引导孩子，这是一个遗憾。不过，让孩子搞定事情，首先就要自己搞定。这里推荐一下麻省理工学院专为儿童学习计算机提供的开源项目，Scratch。这是一个跨平台基于Java的可视化编程器。熟悉编程的家长可以直接到http://scratch.mit.edu/上下载编程器就可以了。对不熟悉编程的家长，我这里啰唆几句。 编程是一个相对简单的过程，首先要建立一个控制的概念，例如你要控制一个计算机上的图形，或者角色。建立这个角色后，你就开始控制它，例如，用一个按键动作，来控制移动，之后可以增加更多的控制和角色，相关的案例，可以直接到http://scratch.mit.edu/users/lijuexian 这里直接下载源代码，都是图形的，非常容易理解。 孩子学习这种编程，一般来说，花上几个小时就可以入门了。之后，孩子的兴趣会越来越浓厚。而自己也可以把自己的成果发布到互联网上，也可以通过这个网络结交更多的朋友，这是一个积极健康的过程。 一般来说，孩子学习四个月就基本充分掌握这个编程工具了，在这个过程中，最重要的是，孩子理解了计算机工程的基本概念，例如，面向对象，参数，消息，控制，交互等。而这些概念将让孩子可以接触更加深入的真正的编程。 觉先小同学就在学习两个月之后，开始进行苹果&#62;iPhone的真正编程，而这个过程对很多成年人也是不小的挑战。但孩子编写程序，就像玩游戏一样，只是一个挑战而已。在这个过程中，他会自己加深学习英语，学习更加深入的技术。关键不在于学习了某种特殊的机能，而是在这个过程中，培养孩子独立学习，独立解决问题的能力，而这个创造过程是最让人快乐的。觉先的Scratch编程作品集：http://scratch.mit.edu/users/lijuexian<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=20&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>很多情况下，家长并不知道怎么编写程序，也就没有办法引导孩子，这是一个遗憾。不过，让孩子搞定事情，首先就要自己搞定。这里推荐一下麻省理工学院专为儿童学习计算机提供的开源项目，Scratch。这是一个跨平台基于Java的可视化编程器。熟悉编程的家长可以直接到http://scratch.mit.edu/上下载编程器就可以了。对不熟悉编程的家长，我这里啰唆几句。</p>
<p>编程是一个相对简单的过程，首先要建立一个控制的概念，例如你要控制一个计算机上的图形，或者角色。建立这个角色后，你就开始控制它，例如，用一个按键动作，来控制移动，之后可以增加更多的控制和角色，相关的案例，可以直接到http://scratch.mit.edu/users/lijuexian 这里直接下载源代码，都是图形的，非常容易理解。</p>
<p>孩子学习这种编程，一般来说，花上几个小时就可以入门了。之后，孩子的兴趣会越来越浓厚。而自己也可以把自己的成果发布到互联网上，也可以通过这个网络结交更多的朋友，这是一个积极健康的过程。</p>
<p>一般来说，孩子学习四个月就基本充分掌握这个编程工具了，在这个过程中，最重要的是，孩子理解了计算机工程的基本概念，例如，面向对象，参数，消息，控制，交互等。而这些概念将让孩子可以接触更加深入的真正的编程。</p>
<p>觉先小同学就在学习两个月之后，开始进行苹果&gt;iPhone的真正编程，而这个过程对很多成年人也是不小的挑战。但孩子编写程序，就像玩游戏一样，只是一个挑战而已。在这个过程中，他会自己加深学习英语，学习更加深入的技术。关键不在于学习了某种特殊的机能，而是在这个过程中，培养孩子独立学习，独立解决问题的能力，而这个创造过程是最让人快乐的。觉先的Scratch编程作品集：http://scratch.mit.edu/users/lijuexian</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/searchfull.wordpress.com/20/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/searchfull.wordpress.com/20/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/searchfull.wordpress.com/20/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/searchfull.wordpress.com/20/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/searchfull.wordpress.com/20/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/searchfull.wordpress.com/20/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/searchfull.wordpress.com/20/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/searchfull.wordpress.com/20/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=20&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://searchfull.wordpress.com/2009/04/07/%e7%94%a8scratch%e6%95%99%e5%ad%a9%e5%ad%90%e5%ad%a6%e4%b9%a0%e7%bc%96%e7%a8%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/116763d8b0b42c514a9d41b1c92b6532?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">searchfull</media:title>
		</media:content>
	</item>
		<item>
		<title>设置XP自带的PPPOE拨号连接宽带Internet</title>
		<link>http://searchfull.wordpress.com/2009/04/07/%e8%ae%be%e7%bd%aexp%e8%87%aa%e5%b8%a6%e7%9a%84pppoe%e6%8b%a8%e5%8f%b7%e8%bf%9e%e6%8e%a5%e5%ae%bd%e5%b8%a6internet/</link>
		<comments>http://searchfull.wordpress.com/2009/04/07/%e8%ae%be%e7%bd%aexp%e8%87%aa%e5%b8%a6%e7%9a%84pppoe%e6%8b%a8%e5%8f%b7%e8%bf%9e%e6%8e%a5%e5%ae%bd%e5%b8%a6internet/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 02:45:53 +0000</pubDate>
		<dc:creator>searchfull</dc:creator>
				<category><![CDATA[Java技术]]></category>

		<guid isPermaLink="false">http://searchfull.wordpress.com/?p=18</guid>
		<description><![CDATA[由于Windows XP操作系统自带PPPOE拨号程序，故不需要安装任何额外的软件，设置的步骤有以下几点。 如果你具备了上网的基本条件包括： 电脑已有网卡并且驱动安装正常 运营商的网线已正确接于网卡并提供信号 有 运营商 提供用于PPPOE拨号的帐号密码 具备以上三 由于Windows XP操作系统自带PPPOE拨号程序，故不需要安装任何额外的软件，设置的步骤有以下几点。 如果你具备了上网的基本条件包括： ·电脑已有网卡并且驱动安装正常 ·运营商的网线已正确接于网卡并提供信号 ·有运营商提供用于PPPOE拨号的帐号密码 具备以上三个条件后现在就差万里长征的最后一步也就是配置系统了，设置的步骤如下： 1、点“开始”，选择“控制面板”，点击“网络和Internet连接”，再点击“网络连接”，这时你应该看到一个打开的窗口并发现“本地连接”（如果未发现本地连接则代表电脑无网卡或网卡驱动程序没装好），如下图所示： 2、现在，在上图的“网络任务”下方的选项中，点击“创建一个新的连接”；接着点击“下一步”。 3、按照向导的提示，选择“连接到Internet”，然后点击“下一步”； 4、接着选择“手动设置我的连接”，再点击“下一步”； 5、接下来选择“用要求用户名和密码的宽带连接来连接”，然后“下一步”。 6、现在提示你输入ISP名称，你可以输入你所用的宽带运营商的名字，或者干脆就随便填几个字母数字，如“123”什么的，然后点击“下一步”。 7、在下图的界面中各框里相应的输入运营商提供给你的帐号、密码，底下几个（两个或三个）可选项默认是选中，可根据需要选择，然后再点“下一步”。 8、OK，马上就要大功告成了，在点击“完成”按纽之前，请选中“在我的桌面上添加一个到此连接的快捷方式”，这样你在桌面上可以看到一个刚才建立的连接（以你刚才输入的ISP名称为名）的快捷方式，本例中是“123”。 9、最后，在上网前双击打开桌面上刚才建立的连接，按“连接”按纽连接上网络后，你就尽情享受宽带冲浪的快感吧！ 提醒应注意的两点： 一、如果在桌面上找不到快捷方式（可能被误删除等等），那么根据步骤1的办法你打开“网络连接”，里面将会看到“本地连接”下多了一个你建立的连接的图标。 二、连接时下方提示你保存密码的选项要选上，这样就不必每次连接都重新输入密码了。<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=18&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="intro">由于Windows XP操作系统自带PPPOE拨号程序，故不需要安装任何额外的软件，设置的步骤有以下几点。 如果你具备了上网的基本条件包括： 电脑已有网卡并且驱动安装正常 运营商的网线已正确接于网卡并提供信号 有 运营商 提供用于PPPOE拨号的帐号密码 具备以上三</div>
<div class="content">
<p>由于Windows XP操作系统自带PPPOE拨号程序，故不需要安装任何额外的软件，设置的步骤有以下几点。</p>
<p><strong>如果你具备了上网的基本条件包括：</strong></p>
<p>·电脑已有网卡并且驱动安装正常</p>
<p>·运营商的网线已正确接于网卡并提供信号</p>
<p>·有<span style="color:#3366cc;">运营商</span>提供用于PPPOE拨号的帐号密码</p>
<p><strong>具备以上三个条件后现在就差万里长征的最后一步也就是配置系统了，设置的步骤如下：</strong></p>
<p>1、点“开始”，选择“控制面板”，点击“<span style="color:#3366cc;">网络</span>和Internet连接”，再点击“网络连接”，这时你应该看到一个打开的窗口并发现“本地连接”（如果未发现本地连接则代表电脑无网卡或网卡驱动程序没装好），如下图所示：</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S4125B7-0.gif" border="0" alt=" " /></p>
<p align="center">
<p>2、现在，在上图的“网络任务”下方的选项中，点击“创建一个新的连接”；接着点击“下一步”。</p>
<p>3、按照向导的提示，选择“连接到Internet”，然后点击“下一步”；</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S4122956-1.gif" border="0" alt=" " /></p>
<p align="center">
<p>4、接着选择“手动设置我的连接”，再点击“下一步”；</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S4123449-2.gif" border="0" alt=" " /></p>
<p align="center">
<p>5、接下来选择“用要求用户名和密码的宽带连接来连接”，然后“下一步”。</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S412GL-3.gif" border="0" alt=" " /></p>
<p align="center">
<p>6、现在提示你输入ISP名称，你可以输入你所用的<span style="color:#3366cc;">宽带</span>运营商的名字，或者干脆就随便填几个字母数字，如“123”什么的，然后点击“下一步”。</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S4126232-4.gif" border="0" alt=" " /></p>
<p align="center">
<p>7、在下图的界面中各框里相应的输入运营商提供给你的帐号、密码，底下几个（两个或三个）可选项默认是选中，可根据需要选择，然后再点“下一步”。</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S412D58-5.gif" border="0" alt=" " /></p>
<p align="center">
<p>8、OK，马上就要大功告成了，在点击“完成”按纽之前，请选中“在我的桌面上添加一个到此连接的快捷方式”，这样你在桌面上可以看到一个刚才建立的连接（以你刚才输入的ISP名称为名）的快捷方式，本例中是“123”。</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S412A01-6.gif" border="0" alt=" " /></p>
<p align="center">
<p>9、最后，在上网前双击打开桌面上刚才建立的连接，按“连接”按纽连接上网络后，你就尽情享受宽带冲浪的快感吧！</p>
<p align="center"><img title=" " src="http://www.qchannel.cn/uploads/allimg/090328/0S412AE-7.gif" border="0" alt=" " /></p>
<p align="center">
<p><strong>提醒应注意的两点：</strong></p>
<p>一、如果在桌面上找不到快捷方式（可能被误删除等等），那么根据步骤1的办法你打开“网络连接”，里面将会看到“本地连接”下多了一个你建立的连接的图标。</p>
<p>二、连接时下方提示你保存密码的选项要选上，这样就不必每次连接都重新输入密码了。</p></div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/searchfull.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/searchfull.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/searchfull.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/searchfull.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/searchfull.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/searchfull.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/searchfull.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/searchfull.wordpress.com/18/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=18&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://searchfull.wordpress.com/2009/04/07/%e8%ae%be%e7%bd%aexp%e8%87%aa%e5%b8%a6%e7%9a%84pppoe%e6%8b%a8%e5%8f%b7%e8%bf%9e%e6%8e%a5%e5%ae%bd%e5%b8%a6internet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/116763d8b0b42c514a9d41b1c92b6532?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">searchfull</media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S4125B7-0.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S4122956-1.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S4123449-2.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S412GL-3.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S4126232-4.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S412D58-5.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S412A01-6.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>

		<media:content url="http://www.qchannel.cn/uploads/allimg/090328/0S412AE-7.gif" medium="image">
			<media:title type="html"> </media:title>
		</media:content>
	</item>
		<item>
		<title>使用 Drools 规则引擎实现业务逻辑</title>
		<link>http://searchfull.wordpress.com/2009/04/07/%e4%bd%bf%e7%94%a8-drools-%e8%a7%84%e5%88%99%e5%bc%95%e6%93%8e%e5%ae%9e%e7%8e%b0%e4%b8%9a%e5%8a%a1%e9%80%bb%e8%be%91/</link>
		<comments>http://searchfull.wordpress.com/2009/04/07/%e4%bd%bf%e7%94%a8-drools-%e8%a7%84%e5%88%99%e5%bc%95%e6%93%8e%e5%ae%9e%e7%8e%b0%e4%b8%9a%e5%8a%a1%e9%80%bb%e8%be%91/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 02:40:28 +0000</pubDate>
		<dc:creator>searchfull</dc:creator>
				<category><![CDATA[Java技术]]></category>

		<guid isPermaLink="false">http://searchfull.wordpress.com/?p=15</guid>
		<description><![CDATA[使用规则引擎可以通过降低实现复杂业务逻辑的组件的复杂性，降低应用程序的维护和可扩展性成本。这篇更新的文章展示如何使用开源的 Drools 规则引擎让 Java™ 应用程序更适应变化。Drools 项目引入了一个新的本地规则表达式语言和一个 Eclipse 插件，使 Drools 比以前更容易使用。 要求施加在当今 软件产品上的大多数复杂性是行为和功能方面的，从而导致组件实现具有复杂的业务逻辑。实现 J2EE 或 J2SE 应用程序中业务逻辑最常见的方法是编写 Java 代码来实现需求文档的规则和逻辑。在大多数情况下，该代码的错综复杂性使得维护和更新应用程序的业务逻辑成为一项令人畏惧的任务，甚至对于经验丰富的开发 人员来说也是如此。任何更改，不管多么简单，仍然会产生重编译和重部署成本。 规则引擎试图解决（或者至少降 低）应用程序业务逻辑的开发和维护中固有的问题和困难。可以将规则引擎看作实现复杂业务逻辑的框架。大多数规则引擎允许您使用声明性编程来表达对于某些给 定信息或知识有效的结果。您可以专注于已知为真的事实及其结果，也就是应用程序的业务逻辑。 有多个规则引擎可 供使用，其中包括商业和开放源码选择。商业规则引擎通常允许使用专用的类似英语的语言来表达规则。其他规则引擎允许使用脚本语言（比如 Groovy 或 Python）编写规则。这篇更新的文章为您介绍 Drools 引擎，并使用示例程序帮助您理解如何使用 Drools 作为 Java 应用程序中业务逻辑层的一部分。 更多事情在变化…… 俗话说得好，“惟一不变的是变化。”软件应用程序的业务逻辑正是如此。出于以下原因，实现应用程序业务逻辑的组件可能必须更改： 在开发期间或部署后修复代码缺陷 应付特殊状况，即客户一开始没有提到要将业务逻辑考虑在内 处理客户已更改的业务目标 符合组织对敏捷或迭代开发过程的使用 如果存在这些可能性，则迫切需要一个无需太多复杂性就能处理业务逻辑更改的应用程序，尤其是当更改复杂 if-else 逻辑的开发人员并不是以前编写代码的开发人员时。 Drools 是用 Java 语言编写的开放源码规则引擎，使用 Rete 算法（参阅 参考资料）对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则，从而便于学习和理解。并且，还可以将 Java 代码直接嵌入到规则文件中，这令 Drools [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=15&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<blockquote><p>使用规则引擎可以通过降低实现复杂业务逻辑的组件的复杂性，降低应用程序的维护和可扩展性成本。这篇更新的文章展示如何使用开源的 Drools       规则引擎让 Java™ 应用程序更适应变化。Drools 项目引入了一个新的本地规则表达式语言和一个 Eclipse 插件，使       Drools 比以前更容易使用。</p></blockquote>
<p><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->要求施加在当今 软件产品上的大多数复杂性是行为和功能方面的，从而导致组件实现具有复杂的业务逻辑。实现 J2EE 或 J2SE 应用程序中业务逻辑最常见的方法是编写 Java 代码来实现需求文档的规则和逻辑。在大多数情况下，该代码的错综复杂性使得维护和更新应用程序的业务逻辑成为一项令人畏惧的任务，甚至对于经验丰富的开发 人员来说也是如此。任何更改，不管多么简单，仍然会产生重编译和重部署成本。</p>
<p>规则引擎试图解决（或者至少降 低）应用程序业务逻辑的开发和维护中固有的问题和困难。可以将规则引擎看作实现复杂业务逻辑的框架。大多数规则引擎允许您使用声明性编程来表达对于某些给 定信息或知识有效的结果。您可以专注于已知为真的事实及其结果，也就是应用程序的业务逻辑。</p>
<p>有多个规则引擎可 供使用，其中包括商业和开放源码选择。商业规则引擎通常允许使用专用的类似英语的语言来表达规则。其他规则引擎允许使用脚本语言（比如 Groovy 或 Python）编写规则。这篇更新的文章为您介绍 Drools 引擎，并使用示例程序帮助您理解如何使用 Drools 作为 Java 应用程序中业务逻辑层的一部分。</p>
<table border="0" cellspacing="0" cellpadding="0" width="40%" align="right">
<tbody>
<tr>
<td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" width="10" height="1" /></td>
<td>
<table border="1" cellspacing="0" cellpadding="5" width="100%">
<tbody>
<tr>
<td bgcolor="#eeeeee"><a name="N1006B"><strong>更多事情在变化……</strong></a><br />
俗话说得好，“惟一不变的是变化。”软件应用程序的业务逻辑正是如此。出于以下原因，实现应用程序业务逻辑的组件可能必须更改：</p>
<ul>
<li>在开发期间或部署后修复代码缺陷</li>
<li>应付特殊状况，即客户一开始没有提到要将业务逻辑考虑在内</li>
<li>处理客户已更改的业务目标</li>
<li>符合组织对敏捷或迭代开发过程的使用</li>
</ul>
<p>如果存在这些可能性，则迫切需要一个无需太多复杂性就能处理业务逻辑更改的应用程序，尤其是当更改复杂 if-else 逻辑的开发人员并不是以前编写代码的开发人员时。</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>Drools 是用 Java 语言编写的开放源码规则引擎，使用 Rete 算法（参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#resources">参考资料</a>）对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则，从而便于学习和理解。并且，还可以将 Java 代码直接嵌入到规则文件中，这令 Drools 的学习更加吸引人。Drools 还具有其他优点：</p>
<ul>
<li>非常活跃的社区支持</li>
<li>易用</li>
<li>快速的执行速度</li>
<li>在 Java 开发人员中流行</li>
<li>与 Java Rule Engine API（JSR 94）兼容（参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#resources">参考资料</a>）</li>
<li>免费</li>
</ul>
<p><a name="N100A7"><span class="smalltitle">当前 Drools 版本</span></a></p>
<p>在编写本文之际，Drools 规则引擎的最新版本是 4.0.4。这是一个重要更新。虽然现在还存在一些向后兼容性问题，但这个版本的特性让 Drools 比以前更有吸引力。例如，用于表达规则的新的本地语言比旧版本使用的 XML 格式更简单，更优雅。这种新语言所需的代码更少，并且格式易于阅读。</p>
<p>另一个值得注意的进步是，新版本提供了用于 Eclipse IDE（Versions 3.2 和 3.3）的一个 Drools 插件。我强烈建议您通过这个插件来使用 Drools。它可以简化使用 Drools 的项目开发，并且可以提高生产率。例如，该插件会检查规则文件是否有语法错误，并提供代码完成功能。它还使您可以调试规则文件，将调试时间从数小时减少到 几分钟。您可以在规则文件中添加断点，以便在规则执行期间的特定时刻检查对象的状态。这使您可以获得关于规则引擎在特定时刻所处理的<em>知识（knowledge）</em>（在本文的后面您将熟悉这个术语）的信息。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="problem-desc"><span class="atitle">要解决的问题</span></a></p>
<p>本文展示如何使用 Drools 作为示例 Java 应用程序中业务逻辑层的一部分。为了理解本文，您应该熟悉使用 Eclipse IDE 开发和调试 Java 代码。并且，您还应该熟悉 JUnit 测试框架，并知道如何在 Eclipse 中使用它。</p>
<p>下列假设为应用程序解决的虚构问题设置了场景：</p>
<ul>
<li>名为 XYZ 的公司构建两种类型的计算机机器：Type1 和 Type2。机器类型按其架构定义。</li>
<li>XYZ 计算机可以提供多种功能。当前定义了四种功能：DDNS Server、DNS Server、Gateway 和 Router。</li>
<li>在发运每台机器之前，XYZ 在其上执行多个测试。</li>
<li>在每台机器上执行的测试取决于每台机器的类型和功能。目前，定义了五种测试：Test1、Test2、Test3、Test4 和 Test5。</li>
<li>当将测试分配给一台计算机时，也将<em>测试到期日期</em> 分配给该机器。分配给计算机的测试不能晚于该到期日期执行。到期日期值取决于分配给机器的测试。</li>
<li>XYZ 使用可以确定机器类型和功能的内部开发的软件应用程序，自动化了执行测试时的大部分过程。然后，基于这些属性，应用程序确定要执行的测试及其到期日期。</li>
<li>目前，为计算机分配测试和测试到期日期的逻辑是该应用程序的已编译代码的一部分。包含该逻辑的组件用 Java 语言编写。</li>
<li>分配测试和到期日期的逻辑一个月更改多次。当开发人员需要使用 Java 代码实现该逻辑时，必须经历一个冗长乏味的过程。</li>
</ul>
<table border="0" cellspacing="0" cellpadding="0" width="40%" align="right">
<tbody>
<tr>
<td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" width="10" height="1" /></td>
<td>
<table border="1" cellspacing="0" cellpadding="5" width="100%">
<tbody>
<tr>
<td bgcolor="#eeeeee"><a name="when"><strong>何时使用规则引擎？</strong></a><br />
并 非所有应用程序都应使用规则引擎。如果业务逻辑代码包括很多 if-else 语句，则应考虑使用一个规则引擎。维护复杂的 Boolean 逻辑可能是非常困难的任务，而规则引擎可以帮助您组织该逻辑。当您可以使用声明方法而非命令编程语言表达逻辑时，变化引入错误的可能性会大大降低。</p>
<p>如果代码变化可能导致大量的财政损失，则也应考虑规则引擎。许多组织在将已编译代码部署到托管环境中时具有严格的规则。例如，如果需要修改 Java 类中的逻辑，在更改进入生产环境之前，将会经历一个冗长乏味的过程：</p>
<ol>
<li>必须重新编译应用程序代码。</li>
<li>在测试中转环境中删除代码。</li>
<li>由数据质量审核员检查代码。</li>
<li>由托管环境架构师批准更改。</li>
<li>计划代码部署。</li>
</ol>
<p>即使对一行代码的简单更改也可能花费组织的几千美元。如果需要遵循这些严格规则并且发现您频繁更改业务逻辑代码，则非常有必要考虑使用规则引擎。</p>
<p>对 客户的了解也是该决策的一个因素。尽管您使用的是一个简单的需求集合，只需 Java 代码中的简单实现，但是您可能从上一个项目得知，您的客户具有在开发周期期间甚至部署之后添加和更改业务逻辑需求的倾向（以及财政和政治资源）。如果从一 开始就选择使用规则引擎，您可能会过得舒服一些。</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>因 为在对为计算机分配测试和到期日期的逻辑进行更改时，公司会发生高额成本，所以 XYZ 主管已经要求软件工程师寻找一种灵活的方法，用最少的代价将对业务规则的更改 “推” 至生产环境。于是 Drools 走上舞台了。工程师决定，如果它们使用规则引擎来表达确定哪些测试应该执行的规则，则可以节省更多时间和精力。他们将只需要更改规则文件的内容，然后在生 产环境中替换该文件。对于他们来说，这比更改已编译代码并在将已编译代码部署到生产环境中时进行由组织强制的冗长过程要简单省时得多（参阅侧栏 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#when">何时使用规则引擎？</a>）。</p>
<p>目前，在为机器分配测试和到期日期时必须遵循以下业务规则：</p>
<ul>
<li>如果计算机是 Type1，则只能在其上执行 Test1、Test2 和 Test5。</li>
<li>如果计算机是 Type2 且其中一个功能为 DNS Server，则应执行 Test4 和 Test5。</li>
<li>如果计算机是 Type2 且其中一个功能为 DDNS Server，则应执行 Test2 和 Test3。</li>
<li>如果计算机是 Type2 且其中一个功能为 Gateway，则应执行 Test3 和 Test4。</li>
<li>如果计算机是 Type2 且其中一个功能为 Router，则应执行 Test1 和 Test3。</li>
<li>如果 Test1 是要在计算机上执行的测试之一，则测试到期日期距离机器的创建日期 3 天。该规则优先于测试到期日期的所有下列规则。</li>
<li>如果 Test2 是要在计算机上执行的测试之一，则测试到期日期距离机器的创建日期 7 天。该规则优先于测试到期日期的所有下列规则。</li>
<li>如果 Test3 是要在计算机上执行的测试之一，则测试到期日期距离机器的创建日期 10 天。该规则优先于测试到期日期的所有下列规则。</li>
<li>如果 Test4 是要在计算机上执行的测试之一，则测试到期日期距离机器的创建日期 12 天。该规则优先于测试到期日期的所有下列规则。</li>
<li>如果 Test5 是要在计算机上执行的测试之一，则测试到期日期距离机器的创建日期 14 天。</li>
</ul>
<p>捕获为机器分配测试和测试到期日期的上述业务规则的当前 Java 代码如清单 1 所示：<br />
<a name="N1017E"><strong>清单 1. 使用 if-else 语句实现业务规则逻辑</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
Machine machine = ...
// Assign tests
Collections.sort(machine.getFunctions());
int index;

if (machine.getType().equals("Type1")) {
   Test test1 = ...
   Test test2 = ...
   Test test5 = ...
   machine.getTests().add(test1);
   machine.getTests().add(test2);
   machine.getTests().add(test5);
} else if (machine.getType().equals("Type2")) {
   index = Collections.binarySearch(machine.getFunctions(), "Router");
   if (index &gt;= 0) {
      Test test1 = ...
      Test test3 = ...
      machine.getTests().add(test1);
      machine.getTests().add(test3);
   }
   index = Collections.binarySearch(machine.getFunctions(), "Gateway");
   if (index &gt;= 0) {
      Test test4 = ...
      Test test3 = ...
      machine.getTests().add(test4);
      machine.getTests().add(test3);
   }
...
}

// Assign tests due date
Collections.sort(machine.getTests(), new TestComparator());
...
Test test1 = ...
index = Collections.binarySearch(machine.getTests(), test1);
if (index &gt;= 0) {
   // Set due date to 3 days after Machine was created
   Timestamp creationTs = machine.getCreationTs();
   machine.setTestsDueTime(...);
   return;
}

index = Collections.binarySearch(machine.getTests(), test2);
if (index &gt;= 0) {
   // Set due date to 7 days after Machine was created
   Timestamp creationTs = machine.getCreationTs();
   machine.setTestsDueTime(...);
   return;
}
...</pre>
</td>
</tr>
</tbody>
</table>
<p>清单 1 中的代码不是太复杂，但也并不简单。如果要对其进行更改，需要十分小心。一堆互相缠绕的 if-else 语句正试图捕获已经为应用程序标识的业务逻辑。如果您对业务规则不甚了解，就无法一眼看出代码的意图。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="N10187"><span class="atitle">导入示例程序</span></a></p>
<p>使 用 Drools 规则的示例程序附带在本文的 ZIP 存档中。程序使用 Drools 规则文件以声明方法表示上一节定义的业务规则。它包含一个 Eclipse 3.2 Java 项目，该项目是使用 Drools 插件和 4.0.4 版的 Drools 规则引擎开发的。请遵循以下步骤设置示例程序：</p>
<ol>
<li>下载 ZIP 存档（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#download">下载</a>）。</li>
<li>下载并安装 Drools Eclipse 插件（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#resources">参考资料</a>）。</li>
<li>在 Eclipse 中，选择该选项以导入 <strong>Existing Projects into           Workspace</strong>，如图 1 所示：
<p><a name="N101A7"><strong>图 1. 将示例程序导入到 Eclipse 工作区</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/java/j-drools/img1.jpg" alt="将示例程序导入到 Eclipse 工作区" width="360" height="410" /></li>
<li>然后选择下载的存档文件并将其导入工作区中。您将在工作区中发现一个名为 <code>DroolsDemo</code> 的新 Java 项目，如图 2 所示：
<p><a name="N101BD"><strong>图 2. 导入到工作区中的示例程序</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/java/j-drools/img2.jpg" alt="导入到工作区中的示例程序" width="277" height="455" /></li>
</ol>
<p>如果启用了 <strong>Build automatically</strong> 选项，则代码应该已编译并可供使用。如果未启用该选项，则现在构建 <code>DroolsDemo</code> 项目。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="N101D6"><span class="atitle">检查代码</span></a></p>
<p>现在来看一下示例程序中的代码。该程序的 Java 类的核心集合位于 <code>demo</code> 包中。在该包中可以找到 <code>Machine</code> 和 <code>Test</code> 域对象类。<code>Machine</code> 类的实例表示要分配测试和测试到期日期的计算机机器。下面来看 <code>Machine</code> 类，如清单 2 所示：<br />
<a name="N101F7"><strong>清单 2. <code>Machine</code> 类的实例变量</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public class Machine {

   private String type;
   private List functions = new ArrayList();
   private String serialNumber;
   private Collection tests = new HashSet();
   private Timestamp creationTs;
   private Timestamp testsDueTime;

   public Machine() {
     super();
     this.creationTs = new Timestamp(System.currentTimeMillis());
   }
   ...</pre>
</td>
</tr>
</tbody>
</table>
<p>在清单 2 中可以看到 <code>Machine</code> 类的属性有：</p>
<ul>
<li> <code>type</code>（表示为 <code>string</code> 属性）—— 保存机器的类型值。</li>
<li> <code>functions</code> （表示为 <code>list</code>）—— 保存机器的功能。</li>
<li> <code>testsDueTime</code> （表示为 <code>timestamp</code> 变量）—— 保存分配的测试到期日期值。</li>
<li> <code>tests</code> （<code>Collection</code> 对象）—— 保存分配的测试集合。</li>
</ul>
<p>注意，可以为机器分配多个测试，而且一个机器可以具有一个或多个功能。</p>
<p>出于简洁目的，机器的创建日期值设置为创建 <code>Machine</code> 类的实例时的当前时间。如果这是真实的应用程序，创建时间将设置为机器最终构建完成并准备测试的实际时间。</p>
<p><code>Test</code> 类的实例表示可以分配给机器的测试。<code>Test</code>实例由其 <code>id</code> 和 <code>name</code> 惟一描述，如清单 3 所示：<br />
<a name="N10258"><strong>清单 3. <code>Test</code> 类的实例变量</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public class Test {

   public static Integer TEST1 = new Integer(1);
   public static Integer TEST2 = new Integer(2);
   public static Integer TEST3 = new Integer(3);
   public static Integer TEST4 = new Integer(4);
   public static Integer TEST5 = new Integer(5);

   private Integer id;
   private String name;
   private String description;
   public Test() {
      super();
   }
   ...</pre>
</td>
</tr>
</tbody>
</table>
<p>示例程序使用 Drools 规则引擎对 <code>Machine</code> 类的实例求值。基于 <code>Machine</code> 实例的 <code>type</code> 和 <code>functions</code> 属性的值，规则引擎确定应分配给 <code>tests</code> 和 <code>testsDueTime</code> 属性的值。</p>
<p>在 <code>demo</code> 包中，还会发现 <code>Test</code> 对象的数据访问对象 (<code>TestDAOImpl</code>) 的实现，它允许您按照 ID 查找 <code>Test</code> 实例。该数据访问对象极其简单；它不连接任何外部资源（比如关系数据库）以获得 <code>Test</code> 实例。相反，在其定义中硬编码了预定义的 <code>Test</code> 实例集合。在现实世界中，您可能会具有连接外部资源以检索 <code>Test</code> 对象的数据访问对象。</p>
<p><a name="N1029C"><span class="smalltitle"> <code>RulesEngine</code> 类</span></a></p>
<p><code>demo</code> 中比较重要（如果不是最重要的）的一个类是 <code>RulesEngine</code> 类。该类的实例用作封装逻辑以访问 Drools 类的包装器对象。可以在您自己的 Java 项目中容易地重用该类，因为它所包含的逻辑不是特定于示例程序的。清单 4 展示了该类的属性和构造函数：<br />
<a name="N102B5"><strong>清单 4. <code>RulesEngine</code> 类的实例变量和构造函数</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public class RulesEngine {

   private RuleBase rules;
   private boolean debug = false;

   public RulesEngine(String rulesFile) throws RulesEngineException {
      super();
      try {
         // Read in the rules source file
         Reader source = new InputStreamReader(RulesEngine.class
            .getResourceAsStream("/" + rulesFile));
         // Use package builder to build up a rule package
         PackageBuilder builder = new PackageBuilder();
         // This parses and compiles in one step
         builder.addPackageFromDrl(source);
         // Get the compiled package
         Package pkg = builder.getPackage();
         // Add the package to a rulebase (deploy the rule package).
         rules = RuleBaseFactory.newRuleBase();
         rules.addPackage(pkg);
      } catch (Exception e) {
         throw new RulesEngineException(
            "Could not load/compile rules file: " + rulesFile, e);
      }
   }
   ...</pre>
</td>
</tr>
</tbody>
</table>
<p>在清单 4 中可以看到，<code>RulesEngine</code> 类的构造函数接受字符串值形式的参数，该值表示包含业务规则集合的文件的名称。该构造函数使用 <code>PackageBuilder</code> 类的实例解析和编译源文件中包含的规则。（<strong>注意：</strong> 该代码假设规则文件位于程序类路径中名为 rules 的文件夹中。）然后，使用 <code>PackageBuilder</code> 实例将所有编译好的规则合并为一个二进制 <code>Package</code> 实例。然后，使用这个实例配置 Drools         <code>RuleBase</code> 类的一个实例，后者被分配给         <code>RulesEngine</code> 类的 <code>rules</code> 属性。可以将这个类的实例看作规则文件中所包含规则的内存中表示。</p>
<p>清单 5 展示了 <code>RulesEngine</code> 类的         <code>executeRules()</code> 方法：<br />
<a name="N102F0"><strong>清单 5. <code>RulesEngine</code> 类的 <code>executeRules()</code> 方法</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public void executeRules(WorkingEnvironmentCallback callback) {
   WorkingMemory workingMemory = rules.newStatefulSession();
   if (debug) {
      workingMemory
         .addEventListener(new DebugWorkingMemoryEventListener());
   }
   callback.initEnvironment(workingMemory);
   workingMemory.fireAllRules();
}</pre>
</td>
</tr>
</tbody>
</table>
<p><code>executeRules()</code> 方法几乎包含了 Java 代码中的所有魔力。调用该方法执行先前加载到类构造函数中的规则。Drools <code>WorkingMemory</code> 类的实例用于断言或声明<em>知识</em>，规则引擎应使用它来确定应执行的结果。（如果满足规则的所有条件，则执行该规则的结果。）将知识当作规则引擎用于确定是否应启动规则的数据或信息。例如，规则引擎的知识可以包含一个或多个对象及其属性的当前状态。</p>
<p>规则结果在调用 <code>WorkingMemory</code> 对象的 <code>fireAllRules()</code> 方法时执行。您可能奇怪（我希望您如此）知识是如何插入到 <code>WorkingMemory</code> 实例中的。如果仔细看一下该方法的签名，将会注意到所传递的参数是 <code>WorkingEnvironmentCallback</code> 接口的实例。<code>executeRules()</code> 方法的调用者需要创建实现该接口的对象。该接口只需要开发人员实现一个方法（参见清单 6 ）：<br />
<a name="N10327"><strong>清单 6. <code>WorkingEnvironmentCallback</code> 接口</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public interface WorkingEnvironmentCallback {
   void initEnvironment(WorkingMemory workingMemory) throws FactException;
}</pre>
</td>
</tr>
</tbody>
</table>
<p>所以，应该是 <code>executeRules()</code> 方法的调用者将知识插入到 <code>WorkingMemory</code> 实例中的。稍后将展示这是如何实现的。</p>
<p><a name="N1033C"><span class="smalltitle"> <code>TestsRulesEngine</code> 类</span></a></p>
<p>清单 7 展示了 <code>TestsRulesEngine</code> 类，它也位于 <code>demo</code> 包中：<br />
<a name="listing7"><strong>清单 7. <code>TestsRulesEngine</code> 类</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public class TestsRulesEngine {

   private RulesEngine rulesEngine;
   private TestDAO testDAO;

   public TestsRulesEngine(TestDAO testDAO) throws RulesEngineException {
      super();
      rulesEngine = new RulesEngine("testRules1.drl");
      this.testDAO = testDAO;
   }

   public void assignTests(final Machine machine) {
      rulesEngine.executeRules(new WorkingEnvironmentCallback() {
         public void initEnvironment(WorkingMemory workingMemory) {
            // Set globals first before asserting/inserting any knowledge!
            workingMemory.setGlobal("testDAO", testDAO);
            workingMemory.insert(machine);
         };
      });
   }
}</pre>
</td>
</tr>
</tbody>
</table>
<p><code>TestsRulesEngine</code> 类只有两个实例变量。<code>rulesEngine</code> 属性是 <code>RulesEngine</code> 类的实例。         <code>testDAO</code> 属性保存对 <code>TestDAO</code> 接口的具体实现的引用。         <code>rulesEngine</code> 对象是使用         <code>"testRules1.drl"</code> 字符串作为其构造函数的参数实例化的。testRules1.drl 文件以声明方式捕获         <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#problem-desc">要解决的问题</a> 中的业务规则。         <code>TestsRulesEngine</code> 类的         <code>assignTests()</code> 方法调用         <code>RulesEngine</code> 类的         <code>executeRules()</code> 方法。在这个方法中，创建了 <code>WorkingEnvironmentCallback</code> 接口的一个匿名实例，然后将该实例作为参数传递给         <code>executeRules()</code> 方法。</p>
<p>如果查看         <code>assignTests()</code> 方法的实现，可以看到知识是如何插入到 <code>WorkingMemory</code> 实例中的。         <code>WorkingMemory</code> 类的         <code>insert()</code> 方法被调用以声明在对规则求值时规则引擎应使用的知识。在这种情况下，知识由 <code>Machine</code> 类的一个实例组成。被插入的对象用于对规则的条件求值。</p>
<p>如果在对条件求值时，需要让规则引擎引用<em>未</em> 用作知识的对象，则应使用 <code>WorkingMemory</code> 类的 <code>setGlobal()</code> 方法。在示例程序中，<code>setGlobal()</code> 方法将对 <code>TestDAO</code> 实例的引用传递给规则引擎。然后规则引擎使用 <code>TestDAO</code> 实例查找它可能需要的任何 <code>Test</code> 实例。</p>
<p><code>TestsRulesEngine</code> 类是示例程序中惟一的 Java 代码，它包含专门致力于为机器分配测试和测试到期日期的实现的逻辑。该类中的逻辑永远不需要更改，即使业务规则需要更新时也是如此。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="N103D6"><span class="atitle">Drools 规则文件</span></a></p>
<p>如前所述，testRules.xml 文件包含规则引擎为机器分配测试和测试到期日期所遵循的规则。它使用 Drools 本地语言表达所包含的规则。</p>
<p>Drools 规则文件有一个或多个 <code>rule</code> 声明。每个 <code>rule</code> 声明由一个或多个 <em>conditional</em> 元素以及要执行的一个或多个 <em>consequences</em> 或           <em>actions</em> 组成。一个规则文件还可以有多个（即 0 个或多个）<code>import</code> 声明、多个         <code>global</code> 声明以及多个         <code>function</code> 声明。</p>
<p>理解 Drools 规则文件组成最好的方法是查看一个真正的规则文件。下面来看 testRules1.drl 文件的第一部分，如清单 8 所示：<br />
<a name="N10406"><strong>清单 8. testRules1.drl 文件的第一部分</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
package demo;

import demo.Machine;
import demo.Test;
import demo.TestDAO;
import java.util.Calendar;
import java.sql.Timestamp;
global TestDAO testDAO;</pre>
</td>
</tr>
</tbody>
</table>
<p>在清单 8 中，可以看到 <code>import</code> 声明如何让规则执行引擎知道在哪里查找将在规则中使用的对象的类定义。<code>global</code> 声明让规则引擎知道，某个对象应该可以从规则中访问，但该对象不应是用于对规则条件求值的知识的一部分。可以将 <code>global</code> 声明看作规则中的全局变量。对于         <code>global</code> 声明，需要指定它的类型（即类名）和想要用于引用它的标识符（即变量名）。<code>global</code> 声明中的这个标识符名称应该与调用 <code>WorkingMemory</code> 类的         <code>setGlobal()</code> 方法时使用的标识符值匹配，在此即为         <code>testDAO</code> （参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing7">清单 7</a>）。</p>
<p><code>function</code> 关键词用于定义一个 Java 函数（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing9">清单 9</a>）。 如果看到 consequence（稍后将讨论）中重复的代码，则应该提取该代码并将其编写为一个 Java 函数。但是，这样做时要小心，避免在 Drools 规则文件中编写复杂的 Java 代码。规则文件中定义的 Java 函数应该简短易懂。这不是 Drools 的技术限制。如果想要在规则文件中编写复杂的 Java 代码，也可以。但这样做可能会让您的代码更加难以测试、调试和维护。复杂的 Java 代码应该是 Java 类的一部分。如果需要 Drools 规则执行引擎调用复杂的 Java 代码，则可以将对包含复杂代码的 Java 类的引用作为全局数据传递给规则引擎。<br />
<a name="listing9"><strong>清单 9. testRules1.drl 文件中定义的 Java 函数</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
function void setTestsDueTime(Machine machine, int numberOfDays) {
   setDueTime(machine, Calendar.DATE, numberOfDays);
}

function void setDueTime(Machine machine, int field, int amount) {
   Calendar calendar = Calendar.getInstance();
   calendar.setTime(machine.getCreationTs());
   calendar.add(field, amount);
   machine.setTestsDueTime(new Timestamp(calendar.getTimeInMillis()));
}
 ...</pre>
</td>
</tr>
</tbody>
</table>
<p>清单 10 展示了 testRules1.drl 文件中定义的第一个规则：<br />
<a name="listing10"><strong>清单 10. testRules1.drl 中定义的第一个规则</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
rule "Tests for type1 machine"
salience 100
when
   machine : Machine( type == "Type1" )
then
   Test test1 = testDAO.findByKey(Test.TEST1);
   Test test2 = testDAO.findByKey(Test.TEST2);
   Test test5 = testDAO.findByKey(Test.TEST5);
   machine.getTests().add(test1);
   machine.getTests().add(test2);
   machine.getTests().add(test5);
   insert( test1 );
   insert( test2 );
   insert( test5 );
end</pre>
</td>
</tr>
</tbody>
</table>
<p>如清单 10 所示，<code>rule</code> 声明有一个惟一标识它的 <code>name</code>。还可以看到，<code>when</code> 关键词定义规则中的条件块，<code>then</code> 关键词定义结果块。清单 10 中显示的规则有一个引用 <code>Machine</code> 对象的条件元素。如果回到         <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing7">清单 7</a> 可以看到，         <code>Machine</code> 对象被插入到         <code>WorkingMemory</code> 对象中。这正是这个规则中使用的对象。条件元素对         <code>Machine</code> 实例（知识的一部分）求值，以确定是否应执行规则的结果。如果条件元素等于 <code>true</code>，则启动或执行结果。从清单 10 中还可以看出，结果只不过是一个 Java 语言语句。通过快速浏览该规则，可以很容易地识别出这是下列业务规则的实现：</p>
<ul>
<li>如果计算机是 Type1，则只能在该机器上执行 Test1、Test2 和 Test5。</li>
</ul>
<p>因此，该规则的条件元素检查（         <code>Machine</code> 对象的）         <code>type</code> 属性是否为 <code>Type1</code>。         （在条件元素中，只要对象遵从 Java bean 模式，就可以直接访问对象的属性，而不必调用 getter 方法。）如果该属性的值为 <code>true</code>，那么将 <code>Machine</code> 实例的一个引用分配给         <code>machine</code> 标识符。然后，在规则的结果块使用该引用，将测试分配给         <code>Machine</code> 对象。</p>
<p>在该规则中，惟一看上去有些奇怪的语句是最后三条结果语句。回忆         “<a href="http://www.ibm.com/developerworks/cn/java/j-drools/#problem-desc">要解决的问题</a>” 小节中的业务规则，应该分配为测试到期日期的值取决于分配给机器的测试。因此，分配给机器的测试需要成为规则执行引擎在对规则求值时所使用的知识的一部分。这正是这三条语句的作用。这些语句使用一个名为 <code>insert</code> 的方法更新规则引擎中的知识。</p>
<p><a name="N104B0"><span class="smalltitle">确定规则执行顺序</span></a></p>
<p>规则的另一个重要的方面是可选的         <code>salience</code> 属性。使用它可以让规则执行引擎知道应该启动规则的结果语句的顺序。具有最高显著值的规则的结果语句首先执行；具有第二高显著值的规则的结果语句第二执行，依此类推。当您需要让规则按预定义顺序启动时，这一点非常重要，很快您将会看到。</p>
<p>testRules1.drl 文件中接下来的四个规则实现与机器测试分配有关的其他业务规则（参见清单 11）。这些规则与刚讨论的第一个规则非常相似。注意，<code>salience</code> 属性值对于前五个规则是相同的；不管这五个规则的启动顺序如何，其执行结果将相同。如果结果受规则的启动顺序影响，则需要为规则指定不同的显著值。<br />
<a name="listing11"><strong>清单 11. testRules1.drl 文件中与测试分配有关的其他规则</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
rule "Tests for type2, DNS server machine"
salience 100
when
   machine : Machine( type == "Type2", functions contains "DNS Server")
then
   Test test5 = testDAO.findByKey(Test.TEST5);
   Test test4 = testDAO.findByKey(Test.TEST4);
   machine.getTests().add(test5);
   machine.getTests().add(test4);
   insert( test4 );
   insert( test5 );
end

rule "Tests for type2, DDNS server machine"
salience 100
when
   machine : Machine( type == "Type2", functions contains "DDNS Server")
then
   Test test2 = testDAO.findByKey(Test.TEST2);
   Test test3 = testDAO.findByKey(Test.TEST3);
   machine.getTests().add(test2);
   machine.getTests().add(test3);
   insert( test2 );
   insert( test3 );
end

rule "Tests for type2, Gateway machine"
salience 100
when
   machine : Machine( type == "Type2", functions contains "Gateway")
then
   Test test3 = testDAO.findByKey(Test.TEST3);
   Test test4 = testDAO.findByKey(Test.TEST4);
   machine.getTests().add(test3);
   machine.getTests().add(test4);
   insert( test3 );
   insert( test4 );
end

rule "Tests for type2, Router machine"
salience 100
when
   machine : Machine( type == "Type2", functions contains "Router")
then
   Test test3 = testDAO.findByKey(Test.TEST3);
   Test test1 = testDAO.findByKey(Test.TEST1);
   machine.getTests().add(test3);
   machine.getTests().add(test1);
   insert( test1 );
   insert( test3 );
end
...</pre>
</td>
</tr>
</tbody>
</table>
<p>清单 12 展示了 Drools 规则文件中的其他规则。您可能已经猜到，这些规则与测试到期日期的分配有关：<br />
<a name="listing12"><strong>清单 12. testRules1.drl 文件中与测试到期日期分配有关的规则</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
rule "Due date for Test 5"
salience 50
when
   machine : Machine()
   Test( id == Test.TEST5 )
then
   setTestsDueTime(machine, 14);
end

rule "Due date for Test 4"
salience 40
when
   machine : Machine()
   Test( id == Test.TEST4 )
then
   setTestsDueTime(machine, 12);
end

rule "Due date for Test 3"
salience 30
when
   machine : Machine()
   Test( id == Test.TEST3 )
then
   setTestsDueTime(machine, 10);
end

rule "Due date for Test 2"
salience 20
when
   machine : Machine()
   Test( id == Test.TEST2 )
then
   setTestsDueTime(machine, 7);
end

rule "Due date for Test 1"
salience 10
when
   machine : Machine()
   Test( id == Test.TEST1 )
then
   setTestsDueTime(machine, 3);
end</pre>
</td>
</tr>
</tbody>
</table>
<p>这些规则的实现比用于分配测试的规则的实现要略微简单一些，但我发现它们更有趣一些，原因有四。</p>
<p>第一，注意这些规则的执行顺序很重要。结果（即，分配给 <code>Machine</code> 实例的 <code>testsDueTime</code> 属性的值）受这些规则的启动顺序所影响。如果查看 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#problem-desc">要解决的问题</a> 中详细的业务规则，您将注意到用于分配测试到期日期的规则具有优先顺序。例如，如果已经将 Test3、Test4 和 Test5 分配给机器，则测试到期日期应距离机器的创建日期 10 天。原因在于 Test3 的到期日期规则优先于 Test4 和 Test5 的测试到期日期规则。如何在 Drools 规则文件中表达这一点呢？答案是 <code>salience</code> 属性。为 <code>testsDueTime</code> 属性设置值的规则的 <code>salience</code> 属性值不同。Test1 的测试到期日期规则优先于所有其他测试到期日期规则，所以这应是要启动的最后一个规则。换句话说，如果 Test1 是分配给机器的测试之一，则由该规则分配的值应该是优先使用的值。所以，该规则的 <code>salience</code> 属性值最低：10。</p>
<p>第二，每个规则有两个条件元素。第一个元素只检查工作内存中是否存在一个 <code>Machine</code> 实例。（注意，这里不会对         <code>Machine</code> 对象的属性进行比较。）当这个元素等于 <code>true</code> 时，它将一个引用分配给         <code>Machine</code> 对象，而后者将在规则的结果块被用到。如果不分配这个引用，那么就无法将测试到期日期分配给 <code>Machine</code> 对象。第二个条件元素检查 <code>Test</code> 对象的 <code>id</code> 属性。当且仅当这两个条件元素都等于 <code>true</code> 时，才执行规则的结果元素。</p>
<p>第三，在 <code>Test</code> 类的一个实例成为知识的一部分（即，包含在工作内存中）之前，Drools 规则执行引擎不会（也不能）对这些规则的条件块求值。这很符合逻辑，因为如果工作内存中还没有         <code>Test</code> 类的一个实例，那么规则执行引擎就无法执行这些规则的条件中所包含的比较。如果您想知道 <code>Test</code> 实例何时成为知识的一部分，那么可以回忆，在与分配测试相关规则的结果的执行期间，一个或多个         <code>Test</code> 实例被插入到工作内存中。（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing10">清单 10</a> 和         <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing11">清单 11</a>）。</p>
<p>第四，注意这些规则的结果块相当简短。原因在于在所有结果块中调用了规则文件中之前使用 <code>function</code> 关键词定义的         <code>setTestsDueTime()</code> Java 方法。该方法为         <code>testsDueTime</code> 属性实际分配值。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="N1054A"><span class="atitle">测试代码</span></a></p>
<p>既然已经仔细检查了实现业务规则逻辑的代码，现在应该检查它是否能工作。要执行示例程序，运行 <code>demo.test</code> 中的         <code>TestsRulesEngineTest</code> JUnit 测试。</p>
<p>在该测试中，创建了 5 个 <code>Machine</code> 对象，每个对象具有不同的属性集合（序号、类型和功能）。为这五个 <code>Machine</code> 对象的每一个都调用 <code>TestsRulesEngine</code> 类的 <code>assignTests()</code> 方法。一旦 <code>assignTests()</code> 方法完成其执行，就执行断言以验证 testRules1.drl 中指定的业务规则逻辑是否正确（参见清单 13）。可以修改 <code>TestsRulesEngineTest</code> JUnit 类以多添加几个具有不同属性的 <code>Machine</code> 实例，然后使用断言验证结果是否跟预期一样。<br />
<a name="N1057E"><strong>清单 13. <code>testTestsRulesEngine()</code> 方法中用于验证业务逻辑实现是否正确的断言</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
public void testTestsRulesEngine() throws Exception {
   while (machineResultSet.next()) {
      Machine machine = machineResultSet.getMachine();
      testsRulesEngine.assignTests(machine);
      Timestamp creationTs = machine.getCreationTs();
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(creationTs);
      Timestamp testsDueTime = machine.getTestsDueTime();

      if (machine.getSerialNumber().equals("1234A")) {
         assertEquals(3, machine.getTests().size());
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST1)));
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST2)));
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST5)));
         calendar.add(Calendar.DATE, 3);
         assertEquals(calendar.getTime(), testsDueTime);

      } else if (machine.getSerialNumber().equals("1234B")) {
         assertEquals(4, machine.getTests().size());
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST5)));
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST4)));
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST3)));
         assertTrue(machine.getTests().contains(testDAO.findByKey(Test.TEST2)));
         calendar.add(Calendar.DATE, 7);
         assertEquals(calendar.getTime(), testsDueTime);
...</pre>
</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="more-knowledge"><span class="atitle">关于知识的其他备注</span></a></p>
<p>值 得一提的是，除了将对象插入至工作内存之外，还可以在工作内存中修改对象或从中撤回对象。可以在规则的结果块中进行这些操作。如果在结果语句中修改作为当 前知识一部分的对象，并且所修改的属性被用在 condition 元素中以确定是否应启动规则，则应在结果块中调用 <code>update()</code> 方法。调用 <code>update()</code> 方法时，您让 Drools 规则引擎知道对象已更新且引用该对象的任何规则的任何条件元素（例如，检查一个或多个对象属性的值）应再次求值，以确定条件的结果现在是 <code>true</code> 还是 <code>false</code>。这意味着甚至当前活动规则（在其结果块中修改对象的规则）的条件都可以再次求值，这可能导致规则再次启动，并可能导致无限循环。如果不希望这种情况发生，则应该包括 <code>rule</code> 的可选 <code>no-loop</code> 属性并将其赋值为 <code>true</code>。</p>
<p>清单 14 用两个规则的定义的伪代码演示了这种情况。<code>Rule 1</code> 修改 <code>objectA</code> 的 <code>property1</code>。然后它调用 <code>update()</code> 方法，以允许规则执行引擎知道该更新，从而触发对引用 <code>objectA</code> 的规则的条件元素的重新求值。因此，启动 <code>Rule 1</code> 的条件应再次求值。因为该条件应再次等于 <code>true</code>（<code>property2</code> 的值仍相同，因为它在结果块中未更改），<code>Rule 1</code> 应再次启动，从而导致无限循环的执行。为了避免这种情况，添加 <code>no-loop</code> 属性并将其赋值为 <code>true</code>，从而避免当前活动规则再次执行。<br />
<a name="N105E0"><strong>清单 14. 修改工作内存中的对象并使用规则元素的 <code>no-loop</code> 属性</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
...
rule "Rule 1"
salience 100
no-loop true
when
   objectA : ClassA (property2().equals(...))
then
   Object value = ...
   objectA.setProperty1(value);
   update( objectA );
end

rule "Rule 2"
salience 100
when
   objectB : ClassB()
   objectA : ClassA ( property1().equals(objectB) )
   ...
then
   ...
end
...</pre>
</td>
</tr>
</tbody>
</table>
<p>如果对象不再是知识的一部分，则应将该对象从工作内存中撤回（参见清单 15）。通过在结果块中调用 <code>retract()</code> 方法实现这一点。当从工作内存中移除对象之后，引用该对象的（属于任何规则的）任何条件元素将不被求值。因为对象不再作为知识的一部分存在，所以规则没有启动的机会。<br />
<a name="listing15"><strong>清单 15. 从工作内存中撤回对象</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
...
rule "Rule 1"
salience 100
when
   objectB : ...
   objectA : ...
then
   Object value = ...
   objectA.setProperty1(value);
   retract(objectB);
end

rule "Rule 2"
salience 90
when
   objectB : ClassB ( property().equals(...) )
then
  ...
end
...</pre>
</td>
</tr>
</tbody>
</table>
<p>清单 15 包含两个规则的定义的伪代码。假设启动两个规则的条件等于 <code>true</code>。则应该首先启动 <code>Rule 1</code>，因为 <code>Rule 1</code> 的显著值比 <code>Rule 2</code> 的高。现在，注意在 <code>Rule 1</code> 的结果块中，<code>objectB</code> 从工作内存中撤回（也就是说，<code>objectB</code> 不再是知识的一部分）。该动作更改了规则引擎的 “执行日程”，因为现在将不启动 <code>Rule 2</code>。原因在于曾经为真值的用于启动 <code>Rule 2</code> 的条件不再为真，因为它引用了一个不再是知识的一部分的对象（<code>objectB</code>）。如果清单 15 中还有其他规则引用了 <code>objectB</code>，且这些规则尚未启动，则它们将不会再启动了。</p>
<p>作为关于如何修改工作内存中当前知识的具体例子，我将重新编写前面讨论的规则源文件。业务规则仍然与 “<a href="http://www.ibm.com/developerworks/cn/java/j-drools/#problem-desc">要解决的问题</a>” 小节中列出的一样。但是，我将使用这些规则的不同实现取得相同的结果。按照这种方法，任何时候工作内存中惟一可用的知识是 <code>Machine</code> 实例。换句话说，规则的条件元素将只针对 <code>Machine</code> 对象的属性执行比较。这与之前的方法有所不同，之前的方法还要对         <code>Test</code> 对象的属性进行比较（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing12">清单 12</a>）。         这些规则的新实现被捕获在示例应用程序的          testRules2.drl 文件中。清单 16 展示了 testRules2.drl  中与分配测试相关的规则：<br />
<a name="listing16"><strong>清单 16. testRules2.drl 中与分配测试相关的规则</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
rule "Tests for type1 machine"
lock-on-active true
salience 100

when
   machine : Machine( type == "Type1" )
then
   Test test1 = testDAO.findByKey(Test.TEST1);
   Test test2 = testDAO.findByKey(Test.TEST2);
   Test test5 = testDAO.findByKey(Test.TEST5);
   machine.getTests().add(test1);
   machine.getTests().add(test2);
   machine.getTests().add(test5);
   update( machine );
end

rule "Tests for type2, DNS server machine"
lock-on-active true
salience 100

when
   machine : Machine( type == "Type2", functions contains "DNS Server")
then
   Test test5 = testDAO.findByKey(Test.TEST5);
   Test test4 = testDAO.findByKey(Test.TEST4);
   machine.getTests().add(test5);
   machine.getTests().add(test4);
   update( machine );
end

rule "Tests for type2, DDNS server machine"
lock-on-active true
salience 100

when
   machine : Machine( type == "Type2", functions contains "DDNS Server")
then
   Test test2 = testDAO.findByKey(Test.TEST2);
   Test test3 = testDAO.findByKey(Test.TEST3);
   machine.getTests().add(test2);
   machine.getTests().add(test3);
   update( machine );
end

rule "Tests for type2, Gateway machine"
lock-on-active true
salience 100

when
   machine : Machine( type == "Type2", functions contains "Gateway")
then
   Test test3 = testDAO.findByKey(Test.TEST3);
   Test test4 = testDAO.findByKey(Test.TEST4);
   machine.getTests().add(test3);
   machine.getTests().add(test4);
   update( machine );
end

rule "Tests for type2, Router machine"
lock-on-active true
salience 100

when
   machine : Machine( type == "Type2", functions contains "Router")
then
   Test test3 = testDAO.findByKey(Test.TEST3);
   Test test1 = testDAO.findByKey(Test.TEST1);
   machine.getTests().add(test3);
   machine.getTests().add(test1);
   update( machine );
end
...</pre>
</td>
</tr>
</tbody>
</table>
<p>如果将清单 16 中第一个规则的定义与 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing10">清单 10</a> 中的定义相比较，可以看到，新方法没有将分配给 <code>Machine</code> 对象的 <code>Test</code> 实例插入到工作内存中，而是由规则的结果块调用 <code>update()</code> 方法，让规则引擎知道 <code>Machine</code> 对象已被修改。（<code>Test</code> 实例被添加/指定给它。）         如果看看清单 16 中其他的规则，应该可以看到，每当将测试分配给一个 <code>Machine</code> 对象时，都采用这种方法：一个或多个         <code>Test</code> 实例被分配给一个         <code>Machine</code> 实例，然后，修改工作知识，并通知规则引擎。</p>
<p>还应注意清单 16 中使用的 <code>active-lock</code> 属性。该属性的值被设为         <code>true</code>；如果不是这样，在执行这些规则时将陷入无限循环。将它设为 <code>true</code> 可以确保当一个规则更新工作内存中的知识时，最终不会导致对规则重新求值并重新执行规则，也就不会导致无限循环。可以将 <code>active-lock</code> 属性         看作 <code>no-loop</code> 属性的加强版。         <code>no-loop</code> 属性确保当修改知识的规则更新后不会再被调用，而         <code>active-lock</code> 属性则确保在修改知识以后，文件中的任何规则（其 active-lock 属性被设为 <code>true</code>）不会重新执行。</p>
<p>清单 17 展示了其他规则有何更改：<br />
<a name="listing17"><strong>清单 17. testRules2.drl 中与分配测试到期日期有关的规则</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">
rule "Due date for Test 5"
salience 50
when
   machine : Machine(tests contains (testDAO.findByKey(Test.TEST5)))
then
   setTestsDueTime(machine, 14);
end

rule "Due date for Test 4"
salience 40
when
   machine : Machine(tests contains (testDAO.findByKey(Test.TEST4)))
then
   setTestsDueTime(machine, 12);
end

rule "Due date for Test 3"
salience 30
when
   machine : Machine(tests contains (testDAO.findByKey(Test.TEST3)))
then
   setTestsDueTime(machine, 10);
end

rule "Due date for Test 2"
salience 20
when
   machine : Machine(tests contains (testDAO.findByKey(Test.TEST2)))
then
   setTestsDueTime(machine, 7);
end

rule "Due date for Test 1"
salience 10
when
   machine : Machine(tests contains (testDAO.findByKey(Test.TEST1)))
then
   setTestsDueTime(machine, 3);
end</pre>
</td>
</tr>
</tbody>
</table>
<p>这些规则的条件元素现在检查一个         <code>Machine</code> 对象的 <code>tests</code> 集合，以确定它是否包含特定的 <code>Test</code> 实例。因此，如前所述，按照这种方法，规则引擎只处理工作内存中的一个对象（一个         <code>Machine</code> 实例），而不是多个对象（<code>Machine</code> 和 <code>Test</code> 实例）。</p>
<p>要测试 testRules2.drl 文件，只需编辑示例应用程序提供的 <code>TestsRulesEngine</code> 类（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-drools/#listing7">清单 7</a>）：将         <code>"testRules1.drl"</code> 字符串改为         <code>"testRules2.drl"</code>，然后运行          <code>TestsRulesEngineTest</code> JUnit 测试。所有测试都应该成功，就像将 testRules1.drl 作为规则源一样。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="N106D4"><span class="atitle">关于断点的注意事项</span></a></p>
<p>如前所述，用于 Eclipse 的 Drools 插件允许在规则文件中设置断点。要清楚，只有在调试作为 “Drools Application” 的程序时，才会启用这些断点。否则，调试器会忽略它们。</p>
<p>例如，假设您想调试作为 “Drools         Application” 的         <code>TestsRulesEngineTest</code> JUnit 测试类。在 Eclipse 中打开常见的 Debug 对话框。在这个对话框中，应该可以看到一个 “Drools Application” 类别。在这个类别下，创建一个新的启动配置。在这个新配置的 Main 选项卡中，应该可以看到一个         Project 字段和一个 Main class 字段。对于 Project 字段，选择           <strong>Drools4Demo</strong> 项目。对于 Main class 字段，输入         <code>junit.textui.TestRunner</code>（参见图 3）。<br />
<a name="N106ED"><strong>图 3. <code>TestsRulesEngineTest</code> 类的 Drools application 启动配置（Main 选项卡）</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/java/j-drools/img3.jpg" alt="TestsRulesEngineTest 类的 Drools application 启动配置（Main 选项卡）" width="572" height="312" /></p>
<p>现在选择 <strong>Arguments</strong> 选项卡并输入          <code>-t demo.test.TestsRulesEngineTest</code> 作为程序参数（参见图 4）。输入该参数后，单击对话框右下角的 <strong>Apply</strong> 按钮，保存新的启动配置。然后，可以单击 <strong>Debug</strong> 按钮，开始以 “Drools         Application” 的形式调试          <code>TestsRulesEngineTest</code> JUnit 类。如果之前在 testRules1.drl 或 testRules2.drl 中添加了断点，那么当使用这个启动配置时，调试器应该会在遇到这些断点时停下来。<br />
<a name="N10714"><strong>图 4. <code>TestsRulesEngineTest</code> 类的 Drools Application 启动配置（Arguments 选项卡）</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/java/j-drools/img4.jpg" alt="TestsRulesEngineTest 类的 Drools Application 启动配置（Arguments 选项卡）" width="572" height="375" /></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.ibm.com/i/c.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table class="no-print" border="0" cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" alt="" width="16" height="16" /></td>
<td align="right" valign="top"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-drools/#main"><strong>回页首</strong></a></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="N10725"><span class="atitle">结束语</span></a></p>
<p>使用规则引擎可以显著降低实现 Java 应用程序中业务规则逻辑的组件的复杂性。使用规则引擎以声明方法表达规则的应用程序比其他应用程序更容易维护和扩展。正如您所看到的，Drools 是一种功能强大的灵活的规则引擎实现。使用 Drools 的特性和能力，您应该能够以声明方式实现应用程序的复杂业务逻辑。Drools 使得学习和使用声明式编程对于 Java 开发人员来说相当容易。</p>
<p>本文展示的 Drools 类是特定于 Drools 的。如果要在示例程序中使用另一种规则引擎实现，代码需要作少许更改。因为 Drools 是 JSR 94 兼容的，所以可以使用 Java Rule Engine API（如 JSR 94 中所指定）设计特定于 Drools 的类的接口。（Java Rule Engine API 用于 JDBC 在数据库中的规则引擎。）如果使用该 API，则可以无需更改 Java 代码而将规则引擎实现更改为另一个不同的实现，只要这个不同的实现也是 JSR 94 兼容的。JSR 94 不解析包含业务规则的规则文件（在本文示例应用程序中为 testRules1.drl）的结构。文件的结构将仍取决于您选择的规则引擎实现。作为练习，可以修改示例程序以使它使用 Java Rule Engine API，而不是使用 Java 代码引用特定于 Drools 的类。</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/searchfull.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/searchfull.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/searchfull.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/searchfull.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/searchfull.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/searchfull.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/searchfull.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/searchfull.wordpress.com/15/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=15&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://searchfull.wordpress.com/2009/04/07/%e4%bd%bf%e7%94%a8-drools-%e8%a7%84%e5%88%99%e5%bc%95%e6%93%8e%e5%ae%9e%e7%8e%b0%e4%b8%9a%e5%8a%a1%e9%80%bb%e8%be%91/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/116763d8b0b42c514a9d41b1c92b6532?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">searchfull</media:title>
		</media:content>

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/developerworks/cn/java/j-drools/img1.jpg" medium="image">
			<media:title type="html">将示例程序导入到 Eclipse 工作区</media:title>
		</media:content>

		<media:content url="http://www.ibm.com/developerworks/cn/java/j-drools/img2.jpg" medium="image">
			<media:title type="html">导入到工作区中的示例程序</media:title>
		</media:content>

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />

		<media:content url="http://www.ibm.com/developerworks/cn/java/j-drools/img3.jpg" medium="image">
			<media:title type="html">TestsRulesEngineTest 类的 Drools application 启动配置（Main 选项卡）</media:title>
		</media:content>

		<media:content url="http://www.ibm.com/developerworks/cn/java/j-drools/img4.jpg" medium="image">
			<media:title type="html">TestsRulesEngineTest 类的 Drools Application 启动配置（Arguments 选项卡）</media:title>
		</media:content>

		<media:content url="http://www.ibm.com/i/v14/rules/blue_rule.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/c.gif" medium="image" />

		<media:content url="http://www.ibm.com/i/v14/icons/u_bold.gif" medium="image" />
	</item>
		<item>
		<title>Nekohtml设置连接属性User-Agent等</title>
		<link>http://searchfull.wordpress.com/2009/04/07/nekohtml%e8%ae%be%e7%bd%ae%e8%bf%9e%e6%8e%a5%e5%b1%9e%e6%80%a7user-agent%e7%ad%89/</link>
		<comments>http://searchfull.wordpress.com/2009/04/07/nekohtml%e8%ae%be%e7%bd%ae%e8%bf%9e%e6%8e%a5%e5%b1%9e%e6%80%a7user-agent%e7%ad%89/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 02:21:23 +0000</pubDate>
		<dc:creator>searchfull</dc:creator>
				<category><![CDATA[Java技术]]></category>

		<guid isPermaLink="false">http://searchfull.wordpress.com/2009/04/07/nekohtml%e8%ae%be%e7%bd%ae%e8%bf%9e%e6%8e%a5%e5%b1%9e%e6%80%a7user-agent%e7%ad%89/</guid>
		<description><![CDATA[import org.apache.xerces.parsers.DOMParser; import org.apache.xerces.xni.parser.XMLDocumentFilter; import org.cyberneko.html.HTMLConfiguration; import org.cyberneko.html.filters.*; URL url = new URL(urlStr); HttpURLConnection hcon = (HttpURLConnection)url.openConnection(); hcon.setConnectTimeout(cto); hcon.setReadTimeout(rto); hcon.setUseCaches(false); hcon.setRequestProperty(”User-Agent”,userAgent); hcon.setRequestProperty(”Accept-Charset”,”utf-8″); hcon.setRequestProperty(”Keep-Alive”,”300″); InputStream instr = hcon.getInputStream(); HTMLConfiguration config = new HTMLConfiguration(); XMLDocumentFilter[] filters = { new Purifier() }; config.setProperty(”http://cyberneko.org/html/properties/filters”,filters); DOMParser dp = new DOMParser(config); dp.setFeature(”http://apache.org/xml/features/dom/include-ignorable-whitespace”,false); dp.parse(new org.xml.sax.InputSource(instr)); return dp.getDocument();<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=14&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>import org.apache.xerces.parsers.DOMParser;<br />
import org.apache.xerces.xni.parser.XMLDocumentFilter;<br />
import org.cyberneko.html.HTMLConfiguration;<br />
import org.cyberneko.html.filters.*;</p>
<p>URL url = new URL(urlStr);<br />
HttpURLConnection hcon = (HttpURLConnection)url.openConnection();<br />
hcon.setConnectTimeout(cto);<br />
hcon.setReadTimeout(rto);<br />
hcon.setUseCaches(false);<br />
hcon.setRequestProperty(”User-Agent”,userAgent);<br />
hcon.setRequestProperty(”Accept-Charset”,”utf-8″);<br />
hcon.setRequestProperty(”Keep-Alive”,”300″);<br />
InputStream instr = hcon.getInputStream();<br />
HTMLConfiguration config = new HTMLConfiguration();<br />
XMLDocumentFilter[] filters = { new Purifier() };<br />
config.setProperty(”http://cyberneko.org/html/properties/filters”,filters);<br />
DOMParser dp = new DOMParser(config);<br />
dp.setFeature(”http://apache.org/xml/features/dom/include-ignorable-whitespace”,false);<br />
dp.parse(new org.xml.sax.InputSource(instr));<br />
return dp.getDocument();</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/searchfull.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/searchfull.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/searchfull.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/searchfull.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/searchfull.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/searchfull.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/searchfull.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/searchfull.wordpress.com/14/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=14&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://searchfull.wordpress.com/2009/04/07/nekohtml%e8%ae%be%e7%bd%ae%e8%bf%9e%e6%8e%a5%e5%b1%9e%e6%80%a7user-agent%e7%ad%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/116763d8b0b42c514a9d41b1c92b6532?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">searchfull</media:title>
		</media:content>
	</item>
		<item>
		<title>Hello world!</title>
		<link>http://searchfull.wordpress.com/2005/11/25/hello-world/</link>
		<comments>http://searchfull.wordpress.com/2005/11/25/hello-world/#comments</comments>
		<pubDate>Fri, 25 Nov 2005 05:31:15 +0000</pubDate>
		<dc:creator>searchfull</dc:creator>
				<category><![CDATA[Java技术]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=1&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Welcome to <a href="http://wordpress.com/">WordPress.com</a>. This is your first post. Edit or delete it and start blogging!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/searchfull.wordpress.com/1/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/searchfull.wordpress.com/1/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/searchfull.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/searchfull.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/searchfull.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/searchfull.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/searchfull.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/searchfull.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/searchfull.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/searchfull.wordpress.com/1/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=searchfull.wordpress.com&amp;blog=29242&amp;post=1&amp;subd=searchfull&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://searchfull.wordpress.com/2005/11/25/hello-world/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/116763d8b0b42c514a9d41b1c92b6532?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">searchfull</media:title>
		</media:content>
	</item>
	</channel>
</rss>
