2007年8月7日 星期二

Maven2 Report使用cobertura-maven-plugin

簡介一下Maven2cobertura-maven-plugin進行Cobertura Report的使用。

更詳細的用法請參考:http://mojo.codehaus.org/cobertura-maven-plugin/

簡易使用法:

基本上只要在reporting標籤中使用進行plugin的設定即可。之後在執行maven site時就會產生測試覆蓋率的報表資料。

<reporting>

</plugins>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.0</version>
</plugin>

</plugins>

</reporting>


為何我在這裏特別指定了Plugin的版本。
因為截至目前為止cobertura這個Plugin版本最新為2.1。
但釋出的2.1版中對於產生的報表結果有些問題。
基本上應該經過Maven2中的對Plugin的參數設定才能產生出想要的結果。

但一般使用上並不需要那麼繁覆,而2.0版本只要單純設好Plugin即可產出想要的測試覆蓋率結果。

Read More......

2007年8月6日 星期一

莫非定律

最近我偶爾會跟朋友們或講課時提到「莫非定律」。
在網路上看到幾篇的描述還滿生動的,整理如下:

參考網址:
莫非定律
莫非定律前十名

莫非定律是關於事情如何出錯的幽默規則,簡練地揭露了「人生總難事事順遂」這條顛撲不破的真理。
一切從莫非原始定律發展出來:會出錯的事,一定出錯。(If something can go wrong, it will.)

莫非定律誕生於1949年,以Edward A. Murphy(生於1917年)命名,他是愛德華空軍基地的工程師,專門研究人類對加速度承受的能力。
他發現同仁總會把加速計的固定器裝反,因而脫口而出他的觀察。有受試者在記者會上引述這句名言,於是很快在航太工程研究者之間散播開來,並陸續有人加上新的法則。

1958年,「莫非定律」正式被列入韋氏字典(Webster’s Dictionary)。
但是莫非本人從未發表過莫非定律,這點倒是蠻符合莫非定律的。
莫非定律至今已經發展出各種類別,從莫非通則到電腦、家庭、工作、政府等等,各種領域都有人找出屬於他們自己的莫非定律。

你可曾有過這樣的經驗?不帶傘時,偏偏下雨;帶了傘時,偏不下雨!
在門外,電話鈴猛響;進了門,就不響了!
這樣的事兒總是無可奈何 ,但在我們日常生活中卻是常有!

「莫非定律」講的正是你我的尷尬,點的正是你我共同的弱點,騷的
正是你我共同的癢處!自從我無意間在光華商場翻到它:「莫非定律
」,那一刻起,它便成了我的聖經!我相信讀過它,它也會成為你的!

莫非者,查無其人,是個虛構人物:一九五○年代美國海軍的教育宣
導卡通裡面,有個笨手笨腳的機械士叫做莫非。所謂莫非定律,最
早就是出自這部卡通。後來又衍生出各式各樣的莫非定律,原來的
那一則因而又被稱為莫非第一定律 (Murphy's First Law)。

莫非定律風行一時,世界各地的人都能琅琅上口。不少好事者也動
腦筋想出各式各樣的定律原理,其中不乏許多有趣的想法。

★莫非定律

一、別試圖教豬唱歌,這樣不但不會有結果,還會惹豬不高興!
二、別跟傻瓜吵架,不然旁人會搞不清楚,到底誰是傻瓜!
三、不要以為自已很重要,因為沒有你,太陽明天還是一樣從東方升上來!

●開宗明義
莫非定律;凡事只要有可能出錯,那就一定會出錯。
莫非哲學;笑一笑,明天未必比今天好。
莫非準則;東西越好,越不中用。

●開始
好的開始,未必就有好結果。
壞的開始,結果往往會更糟。

●人
你若幫助了一個急需用錢的朋友,他一定會記得你─( 在他下次急需用錢的時 候。)

●領導人
愚人居高位,正如一個人置身山頂,他會小看每個人。
每個人也會小看他。

●智愚之間
有能力的──讓他做。
沒能力的──教他做。
做不來的──管理他。

●愛情
你愛上的人,總以為你愛上他是因為;他使你想起你的老情人。
你最後硬著頭皮寄出的情書;寄達對方的時間有多長,你反悔的時間就有多長 。

●早到與晚到
你早到了,會議卻取消。
你準時到,卻還要等。
遲到,就是遲了。

●品質保證
一種產品保證60天不會故障,等於保證第61天一定就會壞掉

●東西
東西久久都派不上用場,就可以丟掉。
東西一丟掉,往往就必須要用它。

●尋找失物
你丟掉東西時,最先去找的地方,往往也是可能找到的最後一個地方。
你往往會找到不是你正想找的東西。

●精彩
你出去買爆米花的時候,銀幕上偏偏就出現了精彩鏡頭。

●排隊
另一排總是動的比較快。
你換到另一排,你原來站的那一排,就開始動的比較快了。
你站的越久,越有可能是站錯了排。

●失事報導
失事的地點越遠,傷亡的人數就得越多,否則寫不成一則故事。

●攜伴出遊
你攜伴出遊,越不想讓人看見,越會遇見熟人。

●相對論
一分鐘有多長?
這要看你是蹲在廁所裡面,還是等在廁所外面。

●撥錯電話號碼
撥錯電話號碼時,總不會打不通。

●結局
有個恐怖的結局,總好過恐怖綿綿無絕期。

莫非定律前十名
Top Ten Murphy's Laws


1.Notheing is as easy as it looks.
萬物皆比表象難

2.Everything takes longer than you think.
凡事耗費的時間都比原先料想的長。

3.Anything that can go wrong will go wrong.
可能會出錯的地方定會出錯。

4.If there is a possibility of several things going wrong,
the one that will cause the most damage will be the one to go wrong.
如果有好幾件事都有出錯的可能,定會出錯者就會是可能造成最嚴重損失的那一個。

5.If any things simply cannot go wrong, it will anyway.
鐵定不會出錯的的是一定會砸鍋。

6.If everything seems to be go wrong, you have obviously overlooked something.
如果事事乍看順利,那顯然是由某個地方沒有注意到。

7.Nature always sides with the hidden flaw.
所有的隱藏缺陷都會因為各種自然因素而被暴露出來。

8.It's impossible to make anything foolproof because fools are so ingenious.
要把所有東西都弄得萬無一失是不可能的,因為蠢蛋都太天才了,肯定會搞砸。

9.Where you set out to do something, something else must be done first.
每當你準備要做某件事時,就會有另一件得先處理的事情冒出來。

10.Every solution breeds new problems.
每一個問題的解決都會引發新的問題。

Read More......

2007年8月5日 星期日

(2006.08月號--151期) 如何以Maven協助Hibernate開發

在今日的企業級應用開發環境中,物件導向開發方式已成為主流,但在實際的應用中,物件只存在於程式與記憶體之中,並不能直接進行儲存。如果想要永久保存物件狀態,則必須要進行物件的持久化,也就是把物件狀態儲存進專門的資料庫系統中,而目前最廣泛使用的關聯式資料庫(RDBMS),並不支援儲存物件導向數據資料。


因此傳統的關聯式資料庫程式設計,必須直接在程式中以Hard code的方式撰寫SQL語法進行開發,而以Hard code撰寫SQL語法的方式,相對的也代表了開發的應用程式無法跨資料庫平台。雖然JDBC統一了Java程式與資料庫之間的操作介面,讓開發人員可以不用了解與資料庫相關特定的API操作,然而自行撰寫SQL語法或再次將SQL語法進行封裝仍是不可避免的事,而在物件導向程式設計之中,物件與關聯式資料並無法以簡單的方式進行轉換,導致了資料永續性的開發上受到了先天的限制。


ORM(Object/Relational Mapping)物件-關聯映射技術,在該問題的處理上已經有完善的解決方案,而目前在開放原始碼的技術中,最受人矚目的ORM實作,應該就是Hibernate了。在本期中筆者將介紹如何使用Maven協助Hibernate進行快速開發,而對於Hibernate的基本觀念,筆者在此並不詳述,請參考之前刊載於RunPC中的相關文章。


註:關於Hibernate文章,請參考RunPC128129130132期,資料永續層解決方案Hibernate的相關介紹,作者為Mark Ho


設定hibernatedoclet環境

在開發過程中Hibernate進行物件與關聯式資料的處理過程中,需要有一份映射文件,用以描述物件與關聯式資料的轉換關係,例如:資料型態的對應、資料欄位長度的限制、單向關聯、雙向關聯、一對多、一對一與多對多關聯等等的設定。一般而言映射文件命名通常為*.hbm.xml


然而在實際開發上當物件作了修改或重構後,必須對映射文件進行維護。如此的開發方式相當的不直覺與不方便。並且學習映射文件的撰寫不是一件簡單的事。


因此我們換一個角度思考,如果在物件的設計中,順手將這些轉換關係的資訊寫在物件中,由物件編譯過程中直接幫我們產生相關的映射文件,則我們只要維護一份原始碼即可,當進行修改與重構的過程中,映射檔案的變更也將立即的反應出來。在此我們將使用XDoclet進行Code generate來達到這個目的。


註:有關於XDoclet相關觀念的文章,請參考RunPC130131期,XDoclet入門篇與進階篇,作者為歐宣修。


首先請參考筆者於148期中的Maven文章,使用Maven Genapp Plugin產生專案,並且參考設定 1project.xml進行修改,在該檔中可以看到我們在Maven相依的plugin套件中加入了maven-xdoclet-plugin。接著參考設定 2project.properties加入設定參數。說明請參考表 1中關於hibernatedoclet的參數設定。最後再對maven.xml進行設定,參考設定 3中可知當我們執行java:compile這個goal前會先行運作xdoclet:hibernatedoclet協助我們產生Mapping file


設定 1 project.xml

<?xml version="1.0" encoding="UTF-8"?>

<project>

<pomVersion>3</pomVersion>

<artifactId>hibernate-example</artifactId>

<groupId>hibernate-example</groupId>

<name>Example Hibernate Application</name>

<currentVersion>1.0</currentVersion>

<dependencies>

<dependency>

<groupId>xdoclet</groupId>

<artifactId>maven-xdoclet-plugin</artifactId>

<version>1.2.3</version>

<type>plugin</type>

</dependency>

中間省略…

</dependencies>

中間省略…

</project>


設定 2 project.properties

#####################################

# hibernatedoclet properties

#####################################

maven.xdoclet.hibernatedoclet.fileset.0=true

maven.xdoclet.hibernatedoclet.fileset.0.sourcedir=${maven.src.dir}/java

maven.xdoclet.hibernatedoclet.fileset.0.include=**/*.java

maven.xdoclet.hibernatedoclet.fileset.0.exclude=

maven.xdoclet.hibernatedoclet.hibernate.0=true

maven.xdoclet.hibernatedoclet.hibernate.0.Version=3.0

maven.xdoclet.hibernatedoclet.destDir=${maven.build.dest}


設定 3 maven.xml

<?xml version="1.0" encoding="UTF-8"?>

<project

xmlns:j="jelly:core"

xmlns:ant="jelly:ant">

<preGoal name="java:compile">

<attainGoal name="xdoclet:hibernatedoclet"/>

</preGoal>

</project>


1 maven-xdoclet-plugin設定

參數

說明

maven.xdoclet.hibernatedoclet.fileset.[index]

設定hibernatedoclet引用的檔案集設定,index值為0~910組設定,也就是說最多可以針對10組路徑下的原始檔進行hibernatedocletCode generate,預設index=0為啟用。若指定的maven.xdoclet.hibernatedoclet.fileset.[index]未設定,則以下相對應的檔案集設定即無效。

maven.xdoclet.hibernatedoclet.fileset.[index].sourcedir

指定檔案集原始碼放置路徑,預設為${maven.src.dir}/java

maven.xdoclet.hibernatedoclet.fileset.[index].include

指定檔案集引入檔案規則,預設為**/*.java

maven.xdoclet.hibernatedoclet.fileset.[index].exclude

指定檔案集排除檔案規則,預設不排除任何檔。

maven.xdoclet.hibernatedoclet.hibernate.[index]

設定對maven.xdoclet.hibernatedoclet.fileset.[index]進行hibernatedoclet是否生效,預設為true,若為false則對指定的檔案集不執行hibernatedoclet

maven.xdoclet.hibernatedoclet.hibernate.[index].Version

設定對maven.xdoclet.hibernatedoclet.fileset.[index]進行hibernatedoclet所產生的*.hbm.xml檔案可使用於hibernate那個版本,預設為1.1版,目前可設定的值為目前有1.12.02.13.0

maven.xdoclet.hibernatedoclet.destDir

所有檔案集產生出的*.hbm.xml放置的目的路徑。


建立Domain Object並產生Mapping File

當上一節的設定完成後,我們正式建立Domain Object,並試圖產生Hibernate所需要的Mapping file。這裏我們

是以POJO定義Domain Object,而POJO就是所謂的Plain Ordinary Java Object,字面上來講就是無格式普通Java 物件,簡單的可以理解爲一個不包含邏輯程式碼的值物件。


我們在此建立二個POJO,分別是User(使用者)Role(所屬角色)作為開始。這時Maven專案架構應該如資料結構 1所示,圖 1展示了類別屬性與其setget相關method。接著參考程式 1、程式 2分別在類別中加入<hibernatedoclet>Tag設定,在此我們簡單的了解一下相關屬性用途,若讀者希望了解更詳細的屬性設定,可參考XDoclet官方網站http://xdoclet.sourceforge.net/xdoclet/tags/hibernate-tags.html


  1. @hibernate.class:該Tag用於宣告定義持久化類別,需放置於Class宣告的上方。

    1. table:指定持久化類別對應資料庫Table名稱。

  2. @hibernate.id:定義主鍵欄位相關屬性。

    1. column:指定欄位對應資料庫欄位名稱,若未指定則使用相對應的property名稱。

    2. generator-class:主鍵產生器屬性,目前有uuid.hexuuid.stringincrementassignednativeidentitysequencehiloseqhiloforeign可供設定。

  3. @hibernate.property:定義持久化類別對應資料庫欄位相關屬性。

    1. column:指定欄位對應資料庫欄位名稱,若未指定則使用相對應的property名稱。

    2. length:指定對應資料庫欄位長度。

    3. not-null:是否允許欄位存放null值。

    4. unique:是否允許資料庫欄位值重覆

    5. type:對應資料庫欄位型態

另外,讀者可能發現,在範例中的二個POJO都實現了java.io.Serializable介面,這是Hibernate規範中所提到的,但目前大多數資料並未說明為何必須實現Serializable。事實上Hibernate並不要求持久化類必須實現Serializable介面,但是對於採用分散式架構的Java應用,當Java物件在不同的分散節點之間傳輸時(例如:RMI),這個物件所屬的類別必須實現Serializable介面,此外,在Java Web應用中,如果希望對HttpSession中存放的Java物件進行持久化,那麼這個Java物件所屬的類也必須實現Serializable介面,因此若只拿Hibernate作單純資料庫應用可不遵守該規定外,HibernateJ2EE的應用上都是必須實現Serializable的。


經過maven的設定與撰寫完POJO後,在Console下執行maven java:compile,當指令運作結束後,在[hibernate_example/target/classes/demo/model]路徑下將會出現User.hbm.xmlRole.hbm.xmlHibernate Mapping file

資料結構 1

hibernate-example

|--src

| --main

| --java

| --demo

| --model

| |--Role.java

| --User.java

|--maven.xml

|--project.properties

--project.xml


1 Domain Object類別圖


程式 1 User.java

package demo.model;

import java.io.Serializable;


/**

* @hibernate.class table="app_user"

*/

public class User implements Serializable {

private Long id;

private String username;

private String password;


/**

* @hibernate.id column="id" generator-class="native"

*/

public Long getId() {

return id;

}


/**

* @hibernate.property length="50" not-null="true" unique="true"

*/

public String getUsername() {

return username;

}


/**

* @hibernate.property column="password" not-null="true"

*/

public String getPassword() {

return password;

}

…set method 省略…

}


程式 2 Role.java

package demo.model;

import java.io.Serializable;


/**

* @hibernate.class table="role"

*/

public class Role implements Serializable {

private Long id;

private String name;

private String description;


/**

* @hibernate.id column="id" generator-class="native"

*/

public Long getId() {

return id;

}


/**

* @hibernate.property column="name" length="20"

*/

public String getName() {

return name;

}


/**

* @hibernate.property column="description" length="64"

*/

public String getDescription() {

return description;

}

…set method 省略…

}


使用Hibernate Plugin建立Table Schema

到目前為止我們設定了hibernatedoclet、建立了POJO的類別並自動產生了相關的Mapping file。假設這時資料庫Schema早已建立好的話,就可以開始使用Hibernate進行DAO的開發與測試了。倘若Schema尚未建立呢?需要自行建立嗎?而自行建立則又會引發另一個問題,POJO的設計是基於Schema所建立的。當日後Schema修改時也必須對應相關的POJOMapping file進行維護。一次、二次還可以接受,但在專案開發的過程中需求永遠在變化,很難保證Schema不會一直變更,一旦次數一多,將引發難以重構的災難。


Ant中可以透過net.sf.hibernate.tool.hbm2ddl.SchemaExportTask協助我們將*.hbm.xml再次轉化成相對應資料庫的Schema,而在Maven上可以使用Hibernate Plugin協助進行SchemaExport。基於某些因素Hibernate Plugin最新版本為1.3並且已有一段時間沒有新版本釋出,該版本並未支援Hibernate 3.X,若讀者使用Hibernate 2開發的話,可以直接進行下載。在本次範例中我們將下載經過1.3版本修改的Hibernate Plugin1.4 (請讀者參考相關資源4進行下載)


[%MAVEN_HOME%/plugins]下的1.3版移除,放置下載完成的maven-hibernate-plugin-1.4.jar於該資料夾內即完成了hibernate plugin的安裝。接著參考設定 4project.xml中加入相依套件,此處的設定中我們加入了maven-hibernate-plugin的設定與Hibernate進行SchemaExport時所需的套件,另外為了示範Hibernate跨資料庫平台的特色,在此引入而PostgreSqlHsqldb二個開放原始碼資料庫的JDBC協助進行測試。


在進行SchemaExport功能時可以設定是否正式進行資料庫的更新,或者只是單純的產生資料庫Schema的文字檔供開發人員進行修改或使用。為此必須正確設定Hibernate與資料庫連結的相關參數,參考設定 5與設定 6比較範例中二種資料庫設定的異同處,而關於hibernate.dialect參數的設定,請參考Hibernate官方參考手冊。


最後參考設定 7加入Hibernate plugin所需的參數,讀者對照表 2即可知相關參數的意義為何。當設定完成後於Console下執行maven hibernate:schema-export即可進行SchemaExport,在此我們分別為了PostgreSqlHsqldb作了SchemaExport,請參考圖 2與圖 3的結果。若讀者不希望直接進行資料庫的更新,則可將project.properties檔中參數maven.hibernate.text設為yes再次進行hibernate:schema-export,即可於[target/schema/schema.sql]檔中查看匯出的資料庫SQL語法。


hibernate:schema-export這個goal可以協助我們進行建立資料庫Schema,而當進行POJO的修改並重新產生Mapping file時,可運行maven hibernate:schema-update,該指令將可在不移除資料表的清況下進行資料庫Schema的更新,對於DataBase Schema的重構有很大的幫助。


設定 4 project.xml增添相依套件

<dependency>

<groupId>maven</groupId>

<artifactId>maven-hibernate-plugin</artifactId>

<version>1.4</version>

<type>plugin</type>

</dependency>

<dependency>

<groupId>postgresql</groupId>

<artifactId>postgresql</artifactId>

<version>8.1-407.jdbc3</version>

</dependency>

<dependency>

<groupId>hsqldb</groupId>

<artifactId>hsqldb</artifactId>

<version>1.7.3.3</version>

</dependency>

<dependency>

<groupId>geronimo-spec</groupId>

<artifactId>geronimo-spec-jta</artifactId>

<version>1.0.1B-rc4</version>

</dependency>

<dependency>

<groupId>commons-lang</groupId>

<artifactId>commons-lang</artifactId>

<version>2.1</version>

</dependency>

<dependency>

<groupId>hibernate</groupId>

<artifactId>hibernate</artifactId>

<version>3.0.5</version>

</dependency>


設定 5 database-postgresql.properties

hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

hibernate.connection.url=jdbc:postgresql://localhost/demo

hibernate.connection.driver_class=org.postgresql.Driver

hibernate.connection.show_sql=true

hibernate.connection.username=test

hibernate.connection.password=test


設定 6 database-hsqldb.properties

hibernate.dialect=org.hibernate.dialect.HSQLDialect

hibernate.connection.url=jdbc:hsqldb:hsql://localhost/demo

hibernate.connection.driver_class=org.hsqldb.jdbcDriver

hibernate.connection.show_sql=true

hibernate.connection.username=sa

hibernate.connection.password=


設定 7 project.properties增添相關屬性設定

#####################################

# hibernate properties

#####################################

maven.hibernate.properties=${basedir}/database-postgresql.properties

#maven.hibernate.properties=${basedir}/database-hsqldb.properties

maven.hibernate.quiet=no

maven.hibernate.text=no

maven.hibernate.drop=no

maven.hibernate.delimiter=;

maven.hibernate.output.dir=${maven.build.dir}/schema

maven.hibernate.output.file=${maven.hibernate.output.dir}/schema.sql


2 maven-hibernate-plugin設定

參數

說明

maven.hibernate.properties

hibernate參數設定檔放置路徑,無論直接進行資料庫的更新或單純產出Schema的文字檔,皆必須要進行該項設定主要以hibernate.dialect參數決定使用何種資料庫方言。

maven.hibernate.text

若為yes則執行Schema Export時將直接匯出SQL成文字檔,並不會進行資料庫的更新,若設為no則直接進行資料庫Schema的更新,預設為no

maven.hibernate.quiet

是否顯示詳細的Schema Export資訊,例:當maven.hibernate.text=nomaven.hibernate.quiet=yes時,將直接進行資料庫Schema的更新,Console下不會顯示任何訊息,預設為yes

maven.hibernate.drop

是否只執行drop資料表的動作,若maven.hibernate.text=yes則匯出SQL檔將只包含drop tableSQL語法。

maven.hibernate.delimiter

分隔SQL Commands的定義符號,預設值為空字串,而大多數狀況使用”;”作為分隔符號。

maven.hibernate.output.dir

maven.hibernate.text=yes,匯出檔放置資料夾,預設為${maven.build.dir}/schema

maven.hibernate.output.file

maven.hibernate.text=yes,匯出檔放置路徑,預設為${maven.hibernate.output.dir}/${maven.final.name}-schema.sql


2 PostgreSql SchemaExport結果

3 Hsqldb SchemaExport結果


結論

Hibernate是一個開放原始碼的物件關聯映射技術,針對了JDBC進行了輕量化的將關聯資料轉化為物件封裝,使得開發人員可以隨心所欲的使用物件導向思維來駕馭資料庫。而在本期的介紹中我們了解了使用Maven協助Hibernate建立Domain Object的一種應用,而除了本次範例的方式外,Hibernate也可以使用Middlegen的方式透過現有的資料庫Schema產生出Mapping file,又或著從Mapping file建立出SchemaJava Domain Object。因此可依專案的狀況進行彈性的調整。


Hibernate的應用可以切入在任何使用JDBC的場合,既可以應用於單純的Java Application,也可以在Servlet/JSPWeb應用程式中使用,更可以應用在EJBJ2EE架構中取代CMP,完成資料持久化的重任。倘若更深入Hibernate的架構與觀念中,則將更了解物件關聯映射技術的最佳化實踐。

Read More......