2007/7/23

Chain of Responsibility Implementation using Spring IoC

GoF中提到,Chain of Responsibility的實作方式有兩種,一種是製作successor串列(利用Composite的既有父節點指標,或是自己再另外寫一個,這個實作可以寫在Handler裡面或是定義在這些Event Handlers的外面),一種是直接連接successor。

Spring IoC提供使用者以XML定義的方式,初始化物件,假設我們先定義了一個Event Handler interface,接著先依照自己的需要實作多個物件,implements這個Handeler介面,而以Spring XML設定的方式,初始化多個物件實體。

再來就是靠Spring在ApplicationContext中提供的getBeansOfType這個method,一次將所有定義在xml裡面,實作了EventHandler介面的所有beans,然後依序將Event傳送給所有Event Handler處理。當然這種實作方式,沒有辦法彈性地設定這些EventHandler接收Event的前後順序,只能保證Event確實會傳送給每一個在XML中已經定義的EventHandlers。

如果要讓EventHandler自己決定下一個EventHandler是誰,開發人員可以調整XML定義bean的順序,讓getBeansOfType取到bean的順序,就是xml中定義的順序,但這不是一種彈性的作法。另一種作法,得在EventHandler中增加一個method,傳回下一個EventHandler的bean id,但這樣寫似乎也不是一種好方法。

Anyway我們的issue並不在意處理Event的順序,所以...就先這樣吧。

「我的科普寫作經驗講座」 by 曾志朗院士

7月21日下午免費在科博館聽了一場曾志朗校長的演講,他在第一個小時,只用了那一張演講主題的投影片,而一開始他瀏覽投影片時,我發現他總共準備了80張,這似乎是一個專業演講者的通病,順手拈來就能長篇大論,準備的總遠比講出來的多,我不知道他準備的那些投影片中,後面的到底有沒有用過,但這不是我們能挑戰的地方,因為我們多數都希望,他能多講一點多講一點。

曾校長提到他的第一篇科普文章"Who murdered the dinosaur?"『誰謀殺了恐龍?』,他提到他以謀殺案的方式,兩條平行線索,討論究竟是什麼原因造成恐龍在短時間內滅絕。後來他就講到,在寫這篇文章的一開始,他先講了一個"The Lost World"的故事,他在美國授課時,曾經看過第一版的"The Lost World"。

這本小說,在講亞馬遜河的一塊高原,上頭可能有遠古的恐龍還在那裡生活。後來他在霍金斯研究室竟然看到在那本小說中,手繪高原圖片的真實照片,也提到他跟霍金斯在一起的一些故事,還提到阿里來他們實驗室參訪,決定是否要贊助他們的研究。

科普就是在說明科學的本質,定義問題,尋找共通的標準,測量或實驗,得到結論,被推翻或成為定論。這一連串的過程,就是要透過這些科普文章,潛移默化地傳遞給所有人。不管是什麼科學,能以最貼近大眾生活的方式類比,就能讓這篇科普文章,獲得最大的效益。

但曾校長也提到,既然是科學,讀者就必須要花心力去讀,要不然像很多人買了「時間簡史」,就把書供在書架上,其實是一點用處都沒有的,要有優良的科普作家與作品,也要對應有認真的讀者。一個好作家就得讓大家願意去了解與接受,一個科學知識的新概念,這樣就成功了。

有特殊貢獻的人才,多有「超強的記憶力」,這似乎是不可或缺的一項技能,而這種記憶力,並不單只是記住事情而已,而是能夠舉一反三,從某些事情的特徵,快速地在記憶庫中撈出相關的記憶經驗,當然也要生活經驗夠豐富,才能在瞬間類比出多件事物。

2007/7/6

Spring提供的資源搜尋器 PathMatchingResourcePatternResolver

過去在尋找設定檔的時候,總是得先用context.getRealPath("/")找到webapp實體的硬碟位置後,才能逐步以File的方式,尋找每一個設定檔,但是這種方法,在weblogic裡面卻行不通了,因為weblogic以context.getRealPath("/")回傳的結果跟tomcat不同。

這個時候突然想到先前在weblogic上設定spring-hibernate的方法(ex: classpath*:/**/mappings/mysql/**/*.hbm.xml),於是就先去把spring source code抓回來,然後trace這個部份是怎麼寫的。很幸運的是,這一切都是靠一個類別org.springframework.core.io.support.PathMatchingResourcePatternResolver就做完了,因此我就有了一個能在webapp上尋找設定檔的方式,連同在stand-alone的junit test也能運作。

至於這個PathMatchingResourcePatternResolver到底是怎麼做的,把spring framework log4j的 log level設定為info(log4j.logger.org.springframework=info),就能發現PathMatchingResourcePatternResolver把整個classpath裡所有的資源包含jar檔都能掃描一次,如果設定的參數為硬碟路徑(mappingDirectoryLocations),spring就能把該路徑下所有的子目錄都查過一次。至於classpath,包含jar檔的部分,spring則是以class loader提供的getXXXResource methods做出來的,詳細的實作方式我也不清楚,反正直接把PathMatchingResourcePatternResolver拿來就很好用了。

但因為class loader本身的限制,先前這種pattern的寫法**/config/**/mappings/mysql/**/*.hbm.xml,得把一開始的prefix路徑寫上去,改成classpath*:config/**/mappings/mysql/**/*.hbm.xml。

最後,先把大多數可能的package prefix都列出來
String[] prefix={"config", "tw", "com" ... };
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
for (int i = 0; i < prefix.length; i++) {
if (prefix[i] != null & !prefix[i].equals("")) {
Resource[] resources = resolver.getResources("classpath*:" + prefix[i] + "/**/configsomething/config-*.xml");
}
}

這樣就能找到在classpath裡面包含jar檔裡面,所有符合/**/configsomething/config-*.xml這個pattern的資源,回傳的資源類別為org.springframework.core.io.Resource,只要用getInputStream()這個method就能取得該資源檔案的InputStream。

ps. 這種方式只適合在app server打開時,init webapp時使用,換句話說,Spring的ApplicationContext在一個webapp裡面只需要建立一次,大家共用就可以了。