2008年12月25日 星期四

jetty 的 JAAS 啟動設定

不能再以 $JETTY_HOME/bin/jetty.sh start 啟動 jetty server
而是在 $JETTY_HOME 下,以 java -jar start.jar etc/jetty.xml etc/jetty-jaas.xml 來啟動 server
首先在 webapp 的 web.xml 下加入有關的security設定,主要是以下3個tag:
security-constraint 、login-config、security-role,
其中login-config下的realm-name會對應到 etc/jetty-jaas.xml下的UserRealm中的setName資料
JAAS又自動從java.security.auth.login.config環境變數指定到的檔案中去找到UserRealm中
LoginModuleName所設定的名字進而找到java.security.auth.login.config裡應該被運作的
LoginModule 。

web.xml(設定realm-name) =>
jetty-jaas.xml (設定realm與LoginModule對應,與指定LoginModule設定檔位置) =>
java.security.auth.login.config(指定LoginModule設定檔位置) =>
LoginModule設定檔(某LoginModuleName使用哪些LoginModule的實作類別及其條件參數)

2008年12月12日 星期五

DNS修改ip對應的小技巧

假設最優先DNS server 為 168.95.1.1
當有client要尋找某網址的ip時,例如要找:www.google.com.tw
168.95.1.1的運作方式是:

會先去問(root) . DNS -> .tw DNS -> .com.tw DNS -> .google.com.tw

但一但問到後168.95.1.1 DNS server會將www.google.com.tw的對應暫時放在memory裡
這樣下一次又有client問www.google.com.tw時就不用再跑一次,

不過如果www.google.com.tw改了ip位址,這樣一來所有和168.95.1.1詢問的client
都會問到錯的ip,這時可以將client的DNS server優先順序改一下,
讓client暫時以別台沒有暫存www.google.com.tw的DNS server去重新由root開始查找ip

如此即可暫時解決,而約1-2天後168.95.1.1的暫存記錄也會因timeout而消失,
這時到168.95.1.1查找的client也可以找到對的ip了。

2008年12月11日 星期四

滑鼠連點3下觸發mouse listener實作(AWT)

source.addMouseListener(new MouseAdapter() {
private int interval = 300; // ms
private int target = 3; // 連點3下
private int addup = 0; // 已連點了addup下
private Calendar calPriorTime = Calendar.getInstance();

@Override
public void mouseClicked(java.awt.event.MouseEvent e) {
Calendar calNow = Calendar.getInstance();
long curInterval = calNow.getTimeInMillis() - calPriorTime.getTimeInMillis();
if (curInterval > interval) {
// 點第一下(和上一次點的時間相差太久)
addup = 1;
} else {
// 連點(和上一次點的時間相差在interval內)
addup++;
}
if (addup >= target) {
addup = 0;
System.out.println("連點三下已被觸發。");
}
calPriorTime = calNow;
}
});

2008年12月5日 星期五

JUnit 4 簡介

JUnit 4是JUnit框架有史以來的最大改進,其主要目標便是利用Java 5的Annotation特性簡化測試用例的編寫。讓我們看看如何使用JUnit 4來進行Unit測試。

我們先看一個簡單的Math類:
package com.javaeedev.junit4;
public class Math {

public int abs(int value) {
return value>=0 ? value : (-value);
}

public int div(int a, int b) {
return a / b;
}

/**
* BUG: if b less than 0!
*/
public float exp(int a, int b) {
float r = 1;
for(int i=0; i
r = r * a;
return r;
}
}

注意exp()方法是有Bug的,如果傳入參數2, -1,則期待的返回值應為0.5F,但實際返回值為1.0F。

傳統的JUnit的TestCase:
public class MathTest extends TestCase {

public void setUp() { super.setUp(); }
public void tearDown() { super.tearDown(); }

public void testAbs() { assertTrue(true); }
public void testDiv() {...}
public void testExp() {...}

}

JUnit依賴反射來執行每個以test開頭的方法。然而,在最新的JUnit 4中,由於有了Annotation的支持,我們的測試方法不需要再以testXxx標識了,而是寫上一個@Test標註即可。例如:
@Test public void doAbs() {...}

甚 至MathTest類也不必繼承自TestCase。你也許會想到,不繼承自TestCase就無法調用assertXxx方法了,正因為如此,所有的 assertXxx方法全部以靜態方法被放入了Assert類,使用Assert.assertXxx()調用。如果使用
import static org.junit.Assert.*;

則原有的代碼不必改動。

setUp()和tearDown()方法也依賴@Before和@After標記,這樣做的最大的好處是在繼承體系內不必擔心忘記了在setUp ()方法中調用父類的super.setUp()方法,JUnit框架會自動處理父類的@Before和@After標記的方法。

並且,JUnit框架對@Before和@After的調用順序類似於類的構造方法和析構方法,即@Before按照父類到子類的順序調用,@After則相反,這樣保證了資源的正確獲取和釋放。

當然,不再強迫必須使用setUp和tearDown作為方法名,可以使用更有意義的方法名,例如:initDatabase()和closeDatabase(),只要它們被標註了@Before和@After即可。

來看看使用Annotation的MathTest:
package com.javaeedev.junit4;

import static org.junit.Assert.*;

import org.junit.*;

public class MathTest {

public MathTest() {
System.out.println("new MathTest instance.");
}

@Before
public void setUp() throws Exception {
System.out.println("call @Before before a test method");
}

@After
public void tearDown() throws Exception {
System.out.println("call @After after a test method");
}

@Test
public void doAbs() {
Math math = new Math();
assertEquals(200, math.abs(200));
assertEquals(100, math.abs(-100));
assertEquals(0, math.abs(0));
}

@Test
public void doDiv() {
Math math = new Math();
assertEquals(5, math.div(100, 20));
assertEquals(4, math.div(100, 21));
}

@Test(expected=ArithmeticException.class)
public void doDiv0() {
new Math().div(127, 0);
}

@Test(timeout=1)
public void doLongTimeTask() {
double d = 0;
for(int i=1; i<10000000; i )
d =i;
}

@Test
public void testExp() {
Math math = new Math();
assertEquals(32f, math.exp(2, 5), 0.001f);
assertEquals(1f, math.exp(2, 0), 0.001f);
assertEquals(0.5f, math.exp(2, (-1)), 0.001f);
}

}

對測試異常,JUnit 4可以用expected=Exception.class來期待一個預期的異常,而不必編寫
try {
...
fail("No exception");
}
catch(Exception e) {
// OK!
}

來看看doDiv0測試,我們期待一個除數為0的ArithmeticException,因此編寫如下測試方法:
@Test(expected=ArithmeticException.class)
public void doDiv0() {
new Math().div(127, 0);
}

對於非常耗時的測試,@Test還有一個timeout來標識該方法最長執行時間,超過此時間即表示該測試方法失敗:
@Test(timeout=1)
public void doLongTimeTask() {
double d = 0;
for(int i=1; i<10000000; i )
d =i;
}

以上方法若執行時間超過1ms則測試失敗,由於依賴CPU的執行速度,在不同的機器上測試結果也不同。

JUnit 4另一個較大的變化是引入了@BeforeClass和@AfterClass,它們在一個Test類的所有測試方法執行前後各執行一次。這是為了能在 @BeforeClass中初始化一些昂貴的資源,例如數據庫連接,然後執行所有的測試方法,最後在@AfterClass中釋放資源。

正如你能想到的,由於@BeforeClass和@AfterClass僅執行一次,因此它們只能標記靜態方法,在所有測試方法中共享的資源也必須是靜態引用:
private static Object dbConnection;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("call @BeforeClass and init database connection");
dbConnection = new Object();
}

@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("call @AfterClass to release database connection");
dbConnection = null;
}

最後執行測試用例,可以看到結果:

各個方法執行順序如下:

call @BeforeClass and init database connection

new MathTest instance.
call @Before before a test method
call @After after a test method

new MathTest instance.
call @Before before a test method
call @After after a test method

...

call @AfterClass to release database connection

可以看到,@BeforeClass是在實例化MathTest之前調用的,因此不能在構造方法中初始化共享資源。

最後需要注意的是由於Java 5的自動Box/Unbox特性,在調用assertEquals()時要特別注意,如果你傳入:

assertEquals(100F, 100);

則按照自動Box變為:

assertEquals(new Float(100F), new Integer(100));

測試失敗,因為Float類和Integer類不是同一類型。

因此要特別注意float和double的測試。事實上對float和double應使用

assertEquals(float, float, float delta);
assertEquals(double, double, double delta);

delta指定了兩個作比較的浮點數的相差範圍,在此範圍內的兩個浮點數將認為相等。可以傳入一個很小的數例如0.0001F。

JUnit 4非常適合使用Java 5的開發人員,但是無法在Java 1.4中獲得這些好處,並且,也不與以前的版本兼容。因此,如果你正在使用Java 5,就可以考慮使用JUnit 4來編寫測試。

spring aop 架構概觀

2008年11月26日 星期三

Spring資料庫Unit測試

進行資料庫測試,卻又不把資料寫入資料庫的方法就是使用 Transaction 交易機置,
在進行Unit測試時,開始一個 Transaction 並將之後Unit測試的資料庫操作都在 Transaction 中進行
,等到測試完畢再將 Transaction 給 rollback,如此一來即不會在資料庫中留下測試資料。

Spring提供了一個AbstractTransactionalSpringContextTests測試類別,該類別已經實作了
JUnit 的 TestCase,所以直接繼承他就可以開始寫測試程式,另外必須 override 他的:

//提供 spring bean 設定檔的位置
protected String[] getConfigLocations()

// 取代原本的 SetUp
protected void onSetUpInTransaction() throws Exception

// 取代原本的 TearDown
protected void onTearDownInTransaction() throws Exception

除此之外,由於AbstractTransactionalSpringContextTests會使用宣告式的交易,也就是說,
在 spring bean 設定檔裡必須提供一個bean
id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
並注入 SessionFactory (如:org.springframework.orm.hibernate3.LocalSessionFactoryBean)
property name="sessionFactory"

2008年11月23日 星期日

svn 使用merge 進行undo

假設當前 repository 版本為 50
假設之前 commit 了一個錯誤的資料進 repository ,版本為 48。
而現在才發現錯誤想進行 undo
意思就是 47->48 之間的 diff 是我不想要的部分
如果說47->48的diff是新增xxx反過來說 48->47的diff就是刪除xxx
因此,目前的workcopy就是要去merge 48->47的diff,就可以達到 undo的效果
svn merge -r 48:47 workcopy/
目前只是undo了workcopy還要進行commit
svn ci workcopy/ -m "undo"

2008年11月12日 星期三

vbox guest 與 host 分享資料夾

安裝完guest電腦後,啟動guest電腦。

選擇 "裝置" > "安裝客端額外功能"

vbox 會要求從網路下載 VBoxGuestAdditions_1.6.6.iso 檔案,
並存放在 ~/.VirtualBox 下。

下載完成後將此 iso 檔掛載到 guest 電腦的光碟機上,並 mount 到 /media/cdrom0。
在 cdrom0 中找到 VBoxLinuxAdditions.run 這一個 script

先確定guest電腦有安裝好 gcc 套件,再執行 VBoxLinuxAdditions.run。

安裝完成 VBoxLinuxAdditions.run 後先關閉 guest 電腦。

在 vbox 設定值 > 分享資料夾 右上角加入新的分享資料夾,例:
資料夾路徑:/home/muchu1983/vboxsf
名稱:vboxsf

重新啟動guest 電腦。

在guest電腦建立~/vboxsf 目錄,例:mkdir /home/vbox/vboxsf

編輯guest電腦的/etc/fstab,加上一行:
vboxsf /home/vbox/vboxsf vboxsf uid=vbox,rw,auto 0 0

重新開機或執行mount -a,如此,guest和host電腦就可以
透過各自的~/vboxsf 共享資料夾分享資料。

2008年11月11日 星期二

bash下輸出命令到serial/parallel port

serial port
echo -e "\x9e123" > /etc/ttyS0
parallel port
echo -e "\x9e123" > /etc/lp0

-e 是 enable backslash escape 也就是 "\"
而字串中的 "\x" 是指16進位。
java 對 serial/parallel 支援的 api 為

RXTX:
RXTXcomm.jar 及一些 native lib
http://www.rxtx.org/

JCA:
http://java.sun.com/products/javacomm/index.jsp

2008年11月6日 星期四

2008年11月5日 星期三

Debian backports

參考:http://wiki.debian.org/Backports
Debian下分為 stable testing unstable 三個主要版本,stable 最穩定但套件也最老舊。
backports 是一個Debian套件更新站,上面放著只有testing和unstable的套件,
但經由stable的環境重新compile而成。所以可以在stable環境中正常執行,
透過使用 backports 可以讓 stable 版本的 Debian 用到 testing 和 unstable 下才有的套件。

必須先安裝:debian-backports-keyring 套件,用來通過 backports 上的驗証。
在 /etc/apt/sources.list 加上
deb http://www.backports.org/debian/ etch-backports main contrib non-free
開啟aptitude並update即可安裝backports上的套件
aptitude -t etch-backports install "package"

Linux 下的 VirtualBox bridge 模式

安裝 VirtualBox:
先設定好backports
安裝 virtualbox-ose、virtualbox-ose-source 兩個套件
編譯並載入vboxdrv模組:
# cd /usr/src
# tar xvjf virtualbox-ose.tar.bz2
# cd modules/virtualbox-ose
# make
# make install
# modprobe vboxdrv
# lsmod | grep vbox
vboxdrv 55344 0
VirtualBox 有兩種模式 NAT 以及 Bridge 。
Bridge 設定方式如下。
停止eth0
#ifconfig eth0 down
修改/etc/network/interfaces檔案,註解掉eth0相關設定。
並加上br0設定。
# allow-hotplug eth0
# iface eth0 inet dhcp
auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_fd 2.5
要先安裝 bridge-utils uml-utilities 兩個套件
sudo apt-get install bridge-utils uml-utilities
設定方式
tunctl -t tap0 -u
brctl addbr br0
ifconfig eth0 0.0.0.0 promisc
brctl addif br0 eth0
dhclient br0
brctl addif br0 tap0
ifconfig tap0 up
chmod 666 /dev/net/tun
上面可以寫成shell script 存檔,記得用 root 身份執行這些指令,
完成後 ifconfig 會多 br0 , tap0 。
而在 VirtualBox 網路設定為 “Host Interface” 而 Interface Name 為 tap0。
而 guest os 就可以互連 host os 。
若要關掉 bridge 模式
brctl delif br0 eth0
brctl delif br0 tap0
brctl delbr br0
ifconfig tap0 down
ifconfig br0 down
ifconfig eth0 down
ifconfig eth0 up
不過 bridge 模式適合用在有線網卡,無線網卡部份還無法適用。

2008年10月23日 星期四

Live USB Debian 20g隨身碟筆電

製作自己的LiveUSB:
將Debian裝在隨身碟上,並將BIOS設定為USB開機
即可進入作業系統進行一般電腦操作。

下載live-helper套件並安裝:
http://packages.debian.org/sid/live-helper/all/download
dpkg -i live_helper_1.0~a31-1_all.deb
同時也必須安裝 live-helper 相依的 debootstrap

安裝完成後建立一工作目錄
mkdir liveusb
cd liveusb

使用lh_config設定參數,並以 lh_build 產生 image 檔 - binary.img
lh_config
-b usb-hdd
-d etch
-p xfce-desktop
--bootappend-live "local=zh_TW.UIF-8 keyb=us"
-m "http://ftp.tw.debian.org/debian"
&&
lh_build
(需要很長時間)

將usb隨身碟 umount
umount /dev/sda1

以 dd 將 binary.img 輸出到隨身碟上
dd if=binary.img of=/dev/sda bs=1M
注意要輸出到整個隨身碟(sda)而不是單一磁區(sda1)

2008年10月22日 星期三

Spring i18n 設定

Spring使用MessageSource介面做為i18n資訊的存取介面,
而且ApplicationContext即實作了MessageSource介面,
只需要在bean-config.xml裡加上MessageSource的bean即可。
ApplicationContext在啟動時會自動尋找bean-config.xml裡id為messageSource的bean
並將ApplicationContext所收到的MessageSource介面的呼叫都轉到這個bean來實作,

MessageSource bean的 id 一定要稱為 messageSource

一般使用 ResourceBundleMessageSource 做為 MessageSource bean
並指定 property basename 假設 basename 為 message
ResourceBundleMessageSource 會尋找 classpath 下的
message_zh_TW.properties , message_en_US.properties, message_xx_XX.properties ...
做為 i18n的資料來源。

如果是webapp的環境下,想將 i18n的資料放在 WEB-INF 下 (非classpath)
則應該改用 ReloadableResourceBundleMessageSource 做為 MessageSource bean
並指定 basename 為 WEB-INF/i18n/message

如果有中文亂碼的情型,
使用 utf-8 儲存資料來源檔 (message_xx_XX.properties)
且 messageSource bean 加上 property defaultEncoding value當然是 UTF-8 即可。

2008年10月6日 星期一

svn dump 備份

備份:
svnadmin dump REPOS_PATH > back_file.dmp
回存:
svnadmin create NEW_REPOS
svnadmin load NEW_REPOS_PATH < back_file.dmp

2008年10月3日 星期五

Spring Multipart

MutipartResolver要設定UTF-8為預設編碼,不然會造成中文亂碼的問題。


2008年9月22日 星期一

JavaEE HttpSession 用法

先建立一個儲存使用者資訊用的POJO物件,如:

使用WebApp的Servlet或Spring Controller,建立Login及Logout的動作,

Login:


Logout:

2008年9月19日 星期五

Hibernate 自定 generator

Hibernate的generator tag 是用來定義如何Hibernate物件的主鍵
如:


使用increment可以使主鍵每次自動加一。
然而class也可以是自己設計的 java CustGenerator class
要設計一個generator class 必須 implement兩個interface:
public class GreenBookGroupGenerator implements IdentifierGenerator, Configurable

IdentifierGenerator interface 提供 的方法
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException
會在每次需要主鍵時被呼叫,obj即是要被指定id的Hibernate entity POJO
要return Serializable id回去。

Configurable interface 提供 的方法
public void configure(Type type, Properties props, Dialect dialect) throws MappingException
只會在SessionFactory建立時呼叫一次,如果generator有提供param會以 key-value pair把參數
放在Properties裡傳進來:

自從Hibernate 3.3 後複合主鍵才可以使用generator tag

2008年9月4日 星期四

hibernate 關連

在hbm.xml使用many-to-one進行多對一關連
當被關連的對象是複合主鍵時,不可在many-to-one tag使用column attribute
只要在many-to-one tag下建立多個子column tag並一一指定name=主鍵欄位名稱即可
如圖:

2008年8月21日 星期四

Eclipse UML2 工具

在預設的Site Ganymede下的Models and Model Development下的UML2*
選擇 UML2 Tools 、 UML2 Tools SDK 、UML2 End-User Features 、UML2 Extender SDK四項,
安裝即可。

使用時New -> Others -> UML 2.1 Diagrams 就可以建立UseCase 等UML圖,
建立時會產生一個.uml的model xml檔案,及另一個.umlxxx的圖形render定義檔,
使用model可以產生各種的render圖,但如果多個圖共用同一個model要小心資料共用的問題。