摘要: 學(xué)習(xí)JBoss Rules有幾天了,因?yàn)檫@方面的中文資料較少,所以這幾天都在看官網(wǎng)上的manual。這是一份不錯的教程,我把我看的一些重要的東西翻譯整理了一下,希望可以對想學(xué)習(xí)JBoss Rules的同學(xué)們提供一點(diǎn)幫助。
在開始這份教程之前,我先簡要介紹一下JBoss Rules:
JBoss Rules 的前身是Codehaus的一個開源項(xiàng)目叫Drools。最近被納入JBoss門下,更名為JBoss Rules,成為了JBoss應(yīng)用服務(wù)器的規(guī)則引擎。
Drools是為Java量身定制的基于Charles Forgy的RETE算法的規(guī)則引擎的實(shí)現(xiàn)。具有了OO接口的RETE,使得商業(yè)規(guī)則有了更自然的表達(dá)。
既然JBoss Rules是一個商業(yè)規(guī)則引擎,那我們就要先知道到底什么是Rules,即規(guī)則。在JBoss Rules中,規(guī)則是如何被表示的
閱讀全文
?? (Jarkata 的 Commons Logging 包現(xiàn)在已經(jīng)被用在幾乎所有的開源項(xiàng)目之中,它可以使你開發(fā)的系統(tǒng)工作在不同的日志框架下,包括Sun的logging框架和Apache Log4j。現(xiàn)在Commons Logging + Apache Log4j 的身影是隨處可見,Commons Logging 的易用與Log4j的強(qiáng)大功能形成了絕配。)
問題:
??? ? 你正在寫一個可重用的代碼庫,而你不知道你的代碼在哪里并且是如何工作的。你需要一個抽象的日志接口來寫入日志信息,因?yàn)槟悴荒艽_定Log4j或者是JDK 1.4 logging的存在性。
解決:
??????? 通過Jakarta Commons Logging 的Log 接口來記錄信息,然后依靠Commons Logging自身來決定在運(yùn)行時(shí)使用哪種具體的日志框架。下面的代碼使用了Log接口來記錄trace,debug,info,warning,error和fatal信息:
?1?import?org.apache.commons.logging.LogFactory;
?2?import?org.apache.commons.logging.Log
?3?
?4?Log?log?=?LogFactory.getLog(?"com.discursive.jccook.SomeApp"?);?
?5?
?6?if(?log.isTraceEnabled(?)?)?{
?7?????log.trace(?"This?is?a?trace?message"?);
?8?}
?9?
10?if(?log.isDebugEnabled(?)?)?{
11?????log.debug(?"This?is?a?debug?message"?);
12?}
13?
14?log.info(?"This?is?an?informational?message"?);
15?
16?log.warn(?"This?is?a?warning"?);
17?
18?log.error(?"This?is?an?error"?);
19?
20?log.fatal(?"This?is?fatal"?);
????? LogFactory.getInstance() 返回一個Log接口的具體實(shí)現(xiàn),這個實(shí)現(xiàn)與底層具體的日志框架相對應(yīng)。例如,如果你的系統(tǒng)是使用Apache Log4j ,一個Log4JLogger將被返回,對應(yīng)于Log4J category
com.discursive.jccook.SomeApp 。
討論:
??????? 一個可重用代碼庫的開發(fā)者不能預(yù)知其代碼庫將在何時(shí)何地被用到,而現(xiàn)在有很多的日志框架可以使用,所以當(dāng)開發(fā)可重用代碼庫的時(shí)候,使用Commons Logging 是非常明智的,例如Jakarta Commons 組件。當(dāng)調(diào)用LogFactory.getInstance()方法的時(shí)候,Commons Logging 將通過系統(tǒng)屬性和classpath中的類庫來決定和管理適當(dāng)?shù)娜罩究蚣堋τ谝粋€小型可重用組件的開發(fā)者來說,進(jìn)行日志記錄只需要調(diào)用Log接口。而配置底層日志框架的負(fù)擔(dān),就轉(zhuǎn)移到使用其組件庫的開發(fā)者身上。
參考:
??????? 7.11節(jié)詳細(xì)的說明了Commons Logging在運(yùn)行時(shí)確定適當(dāng)日志框架的算法。
????
問題:
??????? 你需要使用HTTP POST 方法來向一個servlet傳遞參數(shù)。
討論:
??????? 創(chuàng)建一個 PostMethod 對象,然后調(diào)用 setParameter() 或 addParameter() 方法設(shè)置參數(shù)。 PostMethod 對象將會傳送一個 Content-Type 頭為 application/x-www-form-urlencoded 的請求,并且參數(shù)將在請求body中被傳送。在下列的例子中演示了用 PostMethod 對象傳遞參數(shù)的用法:
import?org.apache.commons.httpclient.HttpClient;
import?org.apache.commons.httpclient.HttpException;
import?org.apache.commons.httpclient.NameValuePair;
import?org.apache.commons.httpclient.methods.PostMethod;
HttpClient?client?=?new?HttpClient(?);
//?Create?POST?method
String?url?=?"http://www.discursive.com/cgi-bin/jccook/param_list.cgi";
PostMethod?method?=?new?PostMethod(?url?);
//?Set?parameters?on?POST????
method.setParameter(?"test1",?"Hello?World"?);
method.addParameter(?"test2",?"This?is?a?Form?Submission"?);
method.addParameter(?"Blah",?"Whoop"?);
method.addParameter(?new?NameValuePair(?"Blah",?"Whoop2"?)?);
//?Execute?and?print?response
client.executeMethod(?method?);
String?response?=?method.getResponseBodyAsString(?);
System.out.println(?response?);
method.releaseConnection(?);
??????
param_list.cgi CGI腳本會對所以接收到的參數(shù)進(jìn)行回顯,從下面的輸出中,你可以看到傳遞給CGI腳本的三個參數(shù):
These?are?the?parameters?I?received:
test1:
??Hello?World
test2:
??This?is?a?Form?Submission
Blah:
??Whoop
??Whoop2
?????? 有幾種方法來在一個PostMethod對象中設(shè)置參數(shù)。最直接的方法就是調(diào)用setParameter()方法,并傳遞兩個字符串給它:參數(shù)的名稱和參數(shù)值。setParameter()方法將會替代任何已經(jīng)存在的同名參數(shù)。但是,如果一個同名的參數(shù)已經(jīng)存在一個PostMethod對象中,addParameter()將會加入另一個同名參數(shù)值;addParameter()方法同樣接受兩個String:參數(shù)名和參數(shù)值。另一種方法,這兩個方法同樣接受一個包裝了參數(shù)名和參數(shù)值的NameValuePair對象。在前面的例子中,通過addParameter()方法,用參數(shù)名Blah傳遞了兩個值,第一次用兩個String作為參數(shù),第二次用一個NameValuePair對象作為參數(shù)。
問題:
??????? 你需要在一個URL中傳送查詢參數(shù)。
解答:
??????? 使用一個HttpMethod實(shí)例的setQueryString()方法來設(shè)置查詢字符串。使用URIUtil類對包含在URL中的文本進(jìn)行編碼。下面的例子在查詢字符串中放入了兩個參數(shù):
?1?import?org.apache.commons.httpclient.HttpClient;
?2?import?org.apache.commons.httpclient.HttpException;
?3?import?org.apache.commons.httpclient.HttpMethod;
?4?import?org.apache.commons.httpclient.NameValuePair;
?5?import?org.apache.commons.httpclient.methods.GetMethod;
?6?import?org.apache.commons.httpclient.util.URIUtil;
?7?
?8?HttpClient?client?=?new?HttpClient(?);
?9?
10?String?url?=?"http://www.discursive.com/cgi-bin/jccook/param_list.cgi";
11?
12?HttpMethod?method?=?new?GetMethod(?url?);
13?
14?// 用setQueryString()來設(shè)置查詢字符串
15?method.setQueryString(URIUtil.encodeQuery("test1=O?Reilly&blah=Whoop"));
16?System.out.println(?"With?Query?String:?"?+?method.getURI(?)?);
17?
18?client.executeMethod(?method?);
19?
20?System.out.println(?"Response:\n?"?+?method.getResponseBodyAsString(?)?);
21?method.releaseConnection(?);
??????
param_list.cgi? CGI腳本只是簡單的回顯接收到的所以參數(shù),在下面的輸出中,你可以看到URIUtil如何對第一個參數(shù)進(jìn)行編碼:
?????? With?Query?String:?http://www.discursive.com/cgi-bin/jccook/param_list.cgi?test1=O%20Reilly&blah=Whoop
Response:
?These?are?the?parameters?I?received:
test1:
??O?Reilly
blah:
??Whoop
????? 提示:你不必在setQueryString()方法中加入?號,當(dāng)HttpClient實(shí)例執(zhí)行executeMethod()方法時(shí),它會被自動加入。
討論:
????? ?? 在前面的例子中,HttpMethod的setQueryString()方法是一次性將整個查詢字符串加進(jìn)去,但是還有另外一種選擇:通過一個NameValuePair對象的數(shù)組來設(shè)置查詢字符串。當(dāng)一個NameValuePair[]傳入setQueryString()方法中時(shí),HttpMethod實(shí)例會從數(shù)組中取出每一個NameValuePair對象,然后創(chuàng)建一系列用&號分割的參數(shù)。這種方法使程序代碼更加干凈,因?yàn)槟悴槐剡B接字符串來傳遞多個參數(shù)。下面的例子用NameValuePair對象,與前一個例子設(shè)置了同樣的參數(shù):
?1?// 用NameValuePair對象設(shè)置查詢參數(shù)
?2?HttpMethod?method?=?new?GetMethod(?url?);
?3?NameValuePair?pair?=?new?NameValuePair(?"test1",?URIUtil.encodeQuery(?"O?Reilly"?)?);
?4NameValuePair?pair2?=?new?NameValuePair(?"blah",?URIUtil.encodeQuery(?"Whoop"?)?);
?5NameValuePair[]?pairs?=?new?NameValuePair[]?{?pair,?pair2?};
?6method.setQueryString(?pairs?);
?7System.out.println(?"With?NameValuePairs:?"?+?method.getURI(?)?);
?8client.executeMethod(?method?);
?9 System.out.println(?"Response:\n?"?+?method.getResponseBodyAsString(?)?);
?10method.releaseConnection(?);
??????? 根據(jù)RFC1738,URL只能夠包含字母和數(shù)字字符:[0-9,a-z,A-Z]和一些特殊字符。如果你需要在參數(shù)中傳送一些URL所不允許的字符,你就需要對你的字符串進(jìn)行編碼,以符合RFC1738的規(guī)定。URIUtil類有一個方法encodeQuery()能夠?qū)η懊胬又械?O Reilly"進(jìn)行編碼。下面的代碼展示了用URIUtil類來對包含在URL中的字符串進(jìn)行編碼:
1?String?encoded1?=?URIUtil.encodeQuery(?"<test>=O'Connell"?);
2?String?encoded2?=?URIUtil.encodeQuery(?"one:two=thr?ee#"?);
3?
4?String?decoded?=?URIUtil.decode(?"Hello%20World%3F"?);
5?
6?System.out.println(?"Encoded:?"?+?encoded1?);
7?System.out.println(?"Encoded:?"?+?encoded2?);
8?System.out.println(?"Decoded:?"?+?decoded?);
??????? 這個簡單的例子用URIUtil類對兩個字符串進(jìn)行了編碼,并對一個經(jīng)過編碼的字符串進(jìn)行解碼。下面的輸出展示了每個轉(zhuǎn)換的結(jié)果:
Encoded:?%3ctest%e3=O'Connell
Encoded:?one%3atwo=thr%20ee#23
Decoded:?Hello?World?
????????
參考:
??????? 在這個例子中,URLUtil對傳入的查詢字符串的內(nèi)容進(jìn)行了編碼。最近,HttpClient小組將一些URL編碼和解碼的邏輯代碼移入了Jakarta Commons Codec項(xiàng)目中,對應(yīng)的類名為URLCodec。需要URLCodec更多的信息,請參考
Jakarta Commons Codec項(xiàng)目主頁(http://jakarta.apache.org/codec)。
???????? RFC1738討論了URL中的合法字符,并規(guī)定了對其他字符進(jìn)行編碼的過程。RFC1738能夠在http:// www.zvon.org/tmRFC/RFC2616/Output/index.html中找到。
問題:
??????? 你需要通過HTTP GET方法來獲取信息。
解答:
??????? 創(chuàng)建一個HttpClient實(shí)例,并調(diào)用以GetMethod對象為參數(shù)的executeMethod方法。然后,響應(yīng)的內(nèi)容就可以通過一個InputStream,byte[],或者是String來獲得。下面的例子將獲得
http://www.discursive.com /jccook/的內(nèi)容,并且以一個String來獲得響應(yīng)。
??????? ?1?import?org.apache.commons.httpclient.HttpClient;
?2?import?org.apache.commons.httpclient.HttpException;
?3?import?org.apache.commons.httpclient.HttpMethod;
?4?import?org.apache.commons.httpclient.methods.GetMethod;
?5?
?6?HttpClient?client?=?new?HttpClient(?);
?7?String?url?=?"http://www.discursive.com/jccook/";
?8?HttpMethod?method?=?new?GetMethod(?url?);
?9?
10?try?{
11?????client.executeMethod(?method?);
12?
13?????if(?method.getStatusCode(?)?==?HttpStatus.SC_OK?)?{
14?????????String?response?=?method.getResponseBodyAsString(?);
15?????????System.out.println(?response?);
16?????}
17?}?catch(?HttpException?he?)?{
18?????System.out.println(?"HTTP?Problem:?"?+?he.getMessage(?)?);
19?}?catch(?IOException?ioe?)?{
20?????System.out.println(?"IO?Exeception:?"?+?ioe.getMessage(?)?);
21?}?finally?{
22?????method.releaseConnection(?);
23?????method.recycle(?);
24?}
???? 這段代碼用HTTP GET方法獲得了
http://www.discursive.com/jccook/的內(nèi)容。如果響應(yīng)的狀態(tài)碼是HttpStatus.SC_OK(即200),下列響應(yīng)將被輸出到控制臺:
<html>
?<head>
??<title>JCCook?Example</title>
?</head>
?<body>
??<h1>Hello?World!</h1>
?</body>
</html>
討論:
??????? 注意這段代碼中對異常的處理。執(zhí)行一個簡單的HTTP GET需要捕捉兩個異常:HttpException和IOException。如果是發(fā)生HTTP協(xié)議錯誤時(shí),將拋出HttpException異常;如果是發(fā)生有關(guān)網(wǎng)絡(luò)的錯誤時(shí),將拋出IOException異常。這一章后面的例子將會忽略對異常的處理。你應(yīng)該要知道每一次調(diào)用executeMethod()都要用適當(dāng)?shù)膖ry/catch塊包裹。
??????? GetMethod類是HttpMethod接口的一種實(shí)現(xiàn)。HttpMethod會被HttpClient所調(diào)用。HttpMethod實(shí)現(xiàn)類的生命周期是很簡單的:一個HttpMethod實(shí)例被創(chuàng)建,然后被HttpClient調(diào)用;一旦響應(yīng)被檢測到以后,HttpMethod釋放連接并被回收使用。當(dāng)HttpMethod調(diào)用了recycle()方法,相當(dāng)于發(fā)送了一個信號給系統(tǒng)表示這個HttpMethod實(shí)例可以再被使用。releaseConnection()方法指示HttpClient釋放掉與這個HttpMethod相關(guān)聯(lián)的連接。無論在使用HttpMethod實(shí)例的過程中發(fā)生了什么,都要調(diào)用releaseConnection()來釋放網(wǎng)絡(luò)資源。
??????? 一旦HttpClient的executeMethod方法被調(diào)用,你可以通過HttpMethod的getStatusCode()方法來獲得響應(yīng)的狀態(tài)碼。這個方法返回一個int,對應(yīng)于HttpStatus類的public static final 變量。HttpStatus類還包括下面一些常量:SC_OK(200),SC_NOT_FOUND(404),SC_INTERNAL_SERVER_ERROR(500),SC_MOVED_TEMPORARILY (302),SC_UNAUTHORIZED(401)等等。請參照HttpStatus的Javadoc來獲得所有的HTTP狀態(tài)列表。當(dāng)服務(wù)器返回一個錯誤的HTTP狀態(tài)是,通常還會返回一小段信息。這一小段信息可以通過HttpMethod類的getStatusText()方法獲得。
?
參考:
?????? 可以從RFC2616(http://www.zvon.org/tmRFC/RFC2616/Output/index.html)獲得HTTP GET方法的官方定義;
?????? 要獲得HTTP 狀態(tài)碼的完整列表,請參見 HttpStatus Javadoc? (http://jakarta.apache.org/commons/ httpclient/apidocs/index.html)。