2009年11月17日 星期二

Felix 使用到 rt.jar 裡特殊的 package 設定

在OSGi的環境裡每個bundle都有自己的classloader,因此要使用別的bundle的package
必須透過Import、Export來使用。

Felix是一個java的OSGi實作,jre本身有提供許多官方的package可供使用,因此,
當Felix啟動時,必須啟動一個稱為System Bundle的 bundle,而這個System Bundle即
Export出許多 jre 所提供的 package,然而並非是"整個" jre 的 package 都Export 出來,
如 rt.jar 的一些 com.sun.* 的 package 即有缺少,可以在 Felix 的config.properties 檔裡
加上:
org.osgi.framework.system.packages.extra= \
com.sun.package.a,\
com.sun.package.b,\
....

來將需要的 package export 出來。

2009年11月12日 星期四

java MessageDigest 產生編碼資料

以 java.security.MessageDigest 產生 md5 編碼:
String password = "123";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password.getBytes());
String digest = new String(md5.digest());

除了md5也有rsa等各種編碼詳見MessageDigest javadoc

virtual box 官方版本安裝

http://www.virtualbox.org/wiki/Linux_Downloads
轉載自官方wiki說明如下:

Debian-based Linux distributionsAdd
one of the following lines according to your distribution to your /etc/apt/sources.list:
deb http://download.virtualbox.org/virtualbox/debian karmic non-free
deb http://download.virtualbox.org/virtualbox/debian jaunty non-free
deb http://download.virtualbox.org/virtualbox/debian intrepid non-free
deb http://download.virtualbox.org/virtualbox/debian hardy non-free
deb http://download.virtualbox.org/virtualbox/debian gutsy non-free
deb http://download.virtualbox.org/virtualbox/debian dapper non-free
deb http://download.virtualbox.org/virtualbox/debian lenny non-free
deb http://download.virtualbox.org/virtualbox/debian etch non-free
deb http://download.virtualbox.org/virtualbox/debian sarge non-free
deb http://download.virtualbox.org/virtualbox/debian xandros4.0-xn non-free

The Sun public key for apt-secure can be downloaded here.
You can add this key with

sudo apt-key add sun_vbox.asc

or combine downloading and registering:

wget -q http://download.virtualbox.org/virtualbox/debian/sun_vbox.asc -O- | sudo apt-key add -

The key fingerprint is
AF45 1228 01DA D613 29EF 9570 DCF9 F87B 6DFB CBAE Sun Microsystems, Inc.
(xVM VirtualBox archive signing key)
To install VirtualBox, do

apt-get install virtualbox-3.0

2009年11月10日 星期二

Unit Test 使用 System.in 輸入的物件

有時我們會有程式是需要從 System.in 輸入資料來進行運算的,我們會這樣寫:
BufferedReader inputBr = new BufferedReader(new InputStreamReader(System.in));
String input = inputBr.readLine();
但在寫UnitTest時,不可能測試到一半還要去輸入一些資訊到 console,有違自動化的架構。
且在 ant 結合 junit 時,遇到這種狀況會直接測試失敗,這時我們可以透過 mock System.in 的方式,
完成這一個測試,首先待測物件不可以直接使用 System.in 而是在建構子上加上一個,
傳入 InputStream的建構子,而預設建構子則以 System.in 當作該 InputStream,如:

public LcanorusMain() {
this(System.in);
}
public LcanorusMain(InputStream in) {
this.systemIn = in;
}

真正執行時是使用預設建構子,而測試時就是使用有 InputStream 參數的建構子,
並且傳入假造的 mock InputStream 即可:

@Before
public void before() {
lcMain = new LcanorusMain(new SystemInMockInputStream());
}

假造的 mock InputStream 實作重點就是將所要回傳的資料轉成 byte 再一一由read()方法傳回。
且完成所有 byte 後要傳回 -1 表示結束。

private class SystemInMockInputStream extends InputStream {
private byte[] cmdBytes = "fexit\n".getBytes();
private int readIndex = 0;

@Override
public int read() throws IOException {
if (readIndex < cmdBytes.length) {
int ret = cmdBytes[readIndex];
readIndex++;
return ret;
} else {
return -1;
}
}
}

2009年11月5日 星期四

OSGi 的 Bundle-Classpath header

OSGi bundle 可以透過 Import-Package 及 Export-Package 去使用互相的 Class,
但前提是彼此都是 OSGi bundle 格式的 jar 並完成部署在 OSGi 平台上,如Felix、Equinox…,
如果只是單純要使用到非OSGi bundle的第三方 jar,必須要將 jar 整個放到 OSGi bundle 的 bundle space 裡。
所謂的 bundle space 就是 bundle jar 本身,及 bundle 裡的 META-INF/MANIFEST.MF所指定的位置。
MANIFEST.MF 有一個 Bundle-Classpath 的 Header 可以用來指定引用到的第三方 jar。
需注意,指定時要將 "." 目錄也加上去,這裡的 "." 目錄就是指 bundle jar 的根目錄,再
以 "," 分隔,一一加入所需要的第三方 jar,而jar的位置也是以bundle根目錄開始算起。
範例(加入sqlite-jdbc.jar):
Manifest-Version: 1.0
Spring-Context: META-INF/spring/db-context.xml,META-INF/spring/db-osgi-context.xml
Bundle-Name: [feeler] db service
Bundle-Description: provide db service
Bundle-Vendor: muchu@www.bennu.tw
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework
Export-Package: tw.bennu.feeler.db.service
Bundle-ClassPath: .,
META-INF/lib/sqlite-jdbc-3.6.17.jar

因此這一個 bundle jar的裡面還有一個sqlite-jdbc-3.6.17.jar並放在META-INF/lib/ 下。
另外 Bundle-ClassPath 也可以指定含有 *.class 的資料夾做為 classpath。
用法和 java 的 -cp 完全一樣,只是改以"," 分隔。
而且不需再對Bundle-ClassPath的jar做Import-Package的宣告,Import-Package 是偵對
其他 bundle Export 出來的 Package 使用。有宣告反而會因找不到Export-Package而無法啟動 bundle。

2009年11月2日 星期一

easymock 官方範例

mock 是指當用來被 unit 測試對象的物件,需要相依某些其他物件才能正常運作時,
以一個"假冒"的 mock 物件實作被相依的物件之界面,設定給 unit 測試對象物件,
目的是隔離unit 測試對象物件與部署環境,並於測試後直接檢查mock物件的變化,
達到不需要部署測試對象物件到環境,也可以了解測試對象物件對環境的影響是否符合要求。

easymock api 方便我們建立 mock 物件,官方範例如下:
http://www.easymock.org/EasyMock2_5_2_Documentation.html
以一個被測試的 ClassUnderTest 物件,使用到一個 Collaborator 介面為例,
將要為 Collaborator 建立 mock ,並給 ClassUnderTest 做測試。
public class ClassUnderTest {
// ...
public void addListener(Collaborator listener){
// ...
}
public void addDocument(String title, byte[] document) {
// ...
}
public boolean removeDocument(String title) {
// ...
}
public boolean removeDocuments(String[] titles) {
// ...
}
}

public interface Collaborator {
void documentAdded(String title);
void documentChanged(String title);
void documentRemoved(String title);
byte voteForRemoval(String title);
byte[] voteForRemovals(String[] title);
}

測試的 TestCase 實作如下:

import static org.easymock.EasyMock.*;
import junit.framework.TestCase;
public class ExampleTest extends TestCase {
private ClassUnderTest classUnderTest;
private Collaborator mock;

protected void setUp() {
mock = createMock(Collaborator.class); // 1 建立 mock
classUnderTest = new ClassUnderTest();
classUnderTest.addListener(mock);
}

public void testAddDocument() {
mock.documentAdded("New Document"); // 2 設定 mock 物件將replay後該有的行為
replay(mock); // 3 切換 mock 為 replay 準備狀態
classUnderTest.addDocument("New Document", new byte[0]);
}
}

重點在 replay() 之前 mock 物件運作的行為不是 Collaborator 真正的行為,而是,
"預先告知" replay() 之後, mock 應該要有什麼 method 被呼叫,傳進來的參數是什麼…等。
而 replay() 之後, classUnderTest.addDocument("New Document", new byte[0]);
如果沒有觸發 mock 物件"預先告知"的行為,就會產生錯誤使得測試失敗。

ivy 官方範例

ivy 採用和 maven 相同的 lib 管理機置,也使用相同的 repository,
ivy 的 dependency 設定檔叫做 ivy.xml,範例:

<ivy-module version="2.0">
<info organisation="apache" module="hello-ivy"/>
<dependencies>
<dependency org="commons-lang" name="commons-lang" rev="2.0"/>
<dependency org="commons-cli" name="commons-cli" rev="1.0"/>
</dependencies>
</ivy-module>

對應於 maven 的 dependency
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.0</version>
</dependency>

groupId 對應到 org
artifactId 對應到 name
version 對應到 rev

完成 ivy.xml後將他放在和 ant build.xml 同目錄下,並在 build.xml 裡加上 resolve target:
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="hello-ivy" default="run">

...

<!-- =================================
target: resolve
================================= -->
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve />
</target>
</project>

執行 ant resolve 時,ivy 會自動到 maven repository 上找到 ivy.xml 裡定義的 library,
並將之下載到 ~/ivy2/cache 下儲存為本地函式庫,再 copy 到 build.xml 同目錄下的 lib 資料夾裡。

spring-DM webcontainer 啟動

spring-DM 以 extender bundle 去偵測install進來的 bundle中
的META-INF/MANIFEST.MF含有:

Spring-Context: xxxxx/xxxx.xml

這個 header 的 bundle 並以這個 xml 為這個 bundle 建立一個屬於他的
ApplicationContext.....

與 war 整合時,則透過類似相同的概念,不過不是用同一個 extender 偵測,
而是要另外再加上 org.springframework.osgi.web.extender 這個 bundle,
他一樣會偵測 install 進來的 war (war 也可以被當做 bundle install),
並看 war 裡面的 META-INF/MANIFEST.MF 的 Spring-Context
但是不為 war 建立 ApplicationContext 而是將 war 丟給指定的 WebContainer,
預設為 tomcat,tomcat當然也是一個 bundle,再由WebContainer去建立ApplicationContext。

tomcat WebContainer 有自己原本的啟勳方式,但現在被當成一個 bundle,
就必須以OSGi的方式啟動,也就是 Activator ,而tomcat bundle本身沒有這一個Activator,
因此,除了tomcat bundle以外,還要再加裝一個Spring-DM提供的catalina.start.osgi-1.0.0.jar
由這個 start bundle 來啟動 tomcat。這裡的 tomcat bundle 和 tomcat start bundle
都可以在 Spring-DM 的 zip 檔裡的 lib 目錄下找到,目前試過只有 Spring-DM 提供的bundle,運作正常。

除了 tomcat WebContainer ,也可以使用 jetty 做為 WebContainer ,只要以 OSGi 的 fragment 機致,
去修改 org.springframework.osgi.web.extender 的設定即可,Spring-DM 文件中有寫:
http://static.springsource.org/osgi/docs/1.2.0/reference/html-single/#web:configuration:changing-deployer
但由於目前使用的 Felix Osgi Framework 未支援 fragment 機致,因此只能先以 tomcat 做為 WebContainer。

jetty 同樣也需要 start bundle,jetty fragment 、 start bundle 在 Spring-DM zip 檔的 lib 裡都可以找到。

2009年10月29日 星期四

ivy 新增 maven repository 以外的 repository

先在 build.xml 所在目錄下加入 ivysettings.xml 覆寫掉 ivy.jar 裡預設的 ivysettings.xml
僅修改 main-chain 部分內容如下:
<?xml version="1.0" encoding="utf-8"?>
<ivysettings>
<settings defaultResolver="default"/>
<include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
<include url="ivysettings-main-chain.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml"/>
</ivysettings>
${ivy.default.settings.dir}的位置就是 ivy.jar 裡的 org.apache.ivy.core.settings package
修改後改為指到 build.xml 所在目錄下的 ivysettings-main-chain.xml
新增 ivysettings-main-chain.xml 其內容如下:
<?xml version="1.0" encoding="utf-8"?>
<ivysettings>
<resolvers>
<url name="com.springsource.repository.bundles.release">
<ivy pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<url name="com.springsource.repository.bundles.external">
<ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<chain name="main" dual="true">
<resolver ref="shared"/>
<resolver ref="public"/>
<resolver ref="com.springsource.repository.bundles.release"/>
<resolver ref="com.springsource.repository.bundles.external"/>
</chain>
</resolvers>
</ivysettings>

這裡新增的public和shared resolver 是原本ivy.jar就預設定義的,而新增的兩個 url resolver是 spring 的 SpringSource Enterprise Bundle Repository

安裝 ivy - 類似 maven 的 java 函式庫管理工具

下載 ivy 後將 ivy-x.x.x.jar 放到 ant 的 lib 目錄下…如:
/usr/share/ant/lib/ivy-2.1.0.jar
即可在 ant 的 build.xml 裡使用 ivy 的 tag
並且編寫 ivy.xml 定義所用到的函式庫,放在 build.xml 檔案的同目錄下。

2009年10月27日 星期二

META-INF/MANIFEST.MF 的最後一行注意事項

要多加一行空白行(多按一次Enter),否則最後一行的參數將無法被 jar 讀到。
如:
========= MANIFEST.MF 開始 ==========
Manifest-Version: 1.0
Bundle-Name: Service listener example
Bundle-Description: A bundle that displays messages at startup and when service events occur
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Bundle-Activator: tw.bennu.tutorial.example.Activator
Import-Package: org.osgi.framework (<===最後一行參數)

========= MANIFEST.MF 結束 ==========

2009年10月23日 星期五

以 mutt 結合 msmtp 透過遠端 MTA 幫忙發信

mutt 是 linux 下常見預設安裝好的文字模式 mail client
但是,本身預設不但不包含 pop3、smtp 功能,甚至連郵件編輯器也是委拖其他軟體
同樣的我們可以安裝 msmtp ,並讓 mutt 委拖 smtp 功能給 msmtp 就可以寄信了。
安裝 msmtp
sudo aptitude install msmtp

在家目錄下建立 ~/.msmtprc 內容:
# Example for a user configuration file
# Set default values for all following accounts.
defaults
tls on #Gmail TLS有打開
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log

# A freemail service
account gmail
host smtp.gmail.com
from yourid@gmail.com
auth on #Gmail SMTP要認證
user yourid #gmail 帳號
password secret #gmail 密碼,明碼,記得chmod 600本檔案
account default : gmail

在家目錄下建立 ~/.muttrc 內容
set sendmail="/usr/bin/msmtp"
set from=yourid@yourdomain.com #gmail SMTP會覆寫

2009年10月22日 星期四

ssh disable 掉 password 登入

注意!進行此動作前需先確定可以透過 ssh-key 登入,
否則…主機最好別放太遠.....

編輯 /etc/ssh/ssh_config 檔
sudo vim /etc/ssh/ssh_config
設定以下三行為 no
ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no
重新 reload ssh 服務
sudo /etc/init.d/ssh reload

測試,先將私錀改名
mv ~/.ssh/id_rsa ~/.ssh/id_rsa.backup
以 ssh 登入如果出現以下訊息表示ok (不再要求輸入密碼):
“Permission denied (publickey).”
成功後再把私錀改回來
mv ~/.ssh/id_rsa.backup ~/.ssh/id_rsa

以 ssh-key 代替密碼登入遠端機器

muchu@glory:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/muchu/.ssh/id_rsa): /home/muchu/id_rsa
Enter passphrase (empty for no passphrase): #直接按 enter
Enter same passphrase again: #直接按 enter
Your identification has been saved in /home/muchu/id_rsa.
Your public key has been saved in /home/muchu/id_rsa.pub.
The key fingerprint is:
21:02:7e:b1:7d:11:85:26:e7:4b:16:ae:39:d5:79:ed muchu@glory
The key's randomart image is:
+--[ RSA 2048]----+
| . . o+. |
| . . +. =. |
| . + o*oo . . |
| . . o*.o . . |
| *S. . . |
| + . E |
| . |
| |
| |
+-----------------+
muchu@glory:~$ ls /home/muchu | grep id_rsa
id_rsa id_rsa.pub

id_rsa 是私錀,id_rsa.pub 是公錀。
將 "公錀的內容" 附加在 "對方" 主機的 ~/.ssh/authorized_keys 下。
並將私錀以 id_rsa 的名稱放在 ~/.ssh/ 下。就可以不用密碼 ssh 登入 "對方" 主機。

在 debian 系統,放公錀到對方主機的動作可以透過以下命令完成,先將公錀放在 ~/.ssh/ 下
ssh-copy-id muchu@www

2009年10月19日 星期一

trac 重新同步 svn

如果在 trac 已經指定了某個 svn repository 的環境下,
重新建立 svn repository 導致 repositoy 版本變動,如:
將 rev 101 僅 dump 出第 101 版本,並放棄第 1~100 版。
重新建立 reposiotry load 101 版為新 repository 的第 1 版。
這時連到原本指定 repository 的 trac 時會看到以下的錯誤訊息:

Can't synchronize with the repository

執行以下命令重新進行 trac 與 svn 的同步即可解決:

trac-admin </path/to/projenv> resync

2009年10月12日 星期一

trac 備份及還原

備份
trac-admin /usr/local/trac/wiki hotcopy ~/backup/wiki
還原
cp 回去即可

apache2 + svn + trac 設置

一、apache2 + svn
#安裝 svn apache2 及 apache2-svn 模組
apt-get install apache2 subversion libapache2-svn
#建立 svn 目錄
mkdir -p /usr/local/svn
#建立 repos svn倉庫
svnadmin /usr/local/svn/repos
#改變 repos 存取權限
chown -R www-data /usr/local/svn/repos
#設定 apache dav_svn 模組
vim /etc/apache2/mods-available/dav_svn.conf
#修改為
<Location /svn>
DAV svn
SVNPath /usr/local/svn/repos
AuthType Basic
AuthName "Subversion repos"
AuthUserFile /etc/apache2/dav_svn.passwd
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
#<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
#</LimitExcept>
</Location>
#建立 dav_svn.authz 設定帳號讀寫權限
vim /etc/apache2/dav_svn.authz
#修改為 :設定 "/" = /repos 下的資料除了 muchu 帳號可以讀寫,其他帳號均不可讀寫。
[/]
* =
muchu = rw
#建立 dav_svn.passwd 設定帳號密碼 (如果檔案已存在就不需要 -c)
/usr/bin/htpasswd -c /etc/apache2/dav_svn.passwd muchu
#重新啟動 apache2
/etc/init.d/apache2 restart
#以 http co svn
svn co http://www.bennu.tw/svn

二、trac
#安裝 trac 及 mod_python 模組
apt-get install trac libapache2-mod-python
#建立 trac 根目錄
mkdir -p /usr/local/trac
#初始化 trac
trac-admin /usr/local/trac/wiki initenv
#Project Name 指定為
wiki
#Path to Repository 指定為
/usr/local/svn/repos
#設定 trac.ini
vim /usr/local/trac/wiki/conf/trac.ini
#修改 default_charset 編碼
default_charset = utf-8
#修改存取權限
chown www-data.www-data -R /usr/local/trac/wiki
# standalone 執行測試
sudo -u www-data tracd --port 8000 /usr/local/trac/wiki
存取 http://127.0.0.1:8000/ 檢查是否正常運作
#建立 apache2 Virtual Host
vim /etc/apache2/sites-available/trac
#修改為:
<VirtualHost *:80>
ServerName trac.bennu.tw
ServerAdmin muchu@trac.bennu.tw

DocumentRoot /usr/local/trac

ErrorLog /var/log/apache2/trac-error.log
CustomLog /var/log/apache2/trac-access.log combined

SetHandler mod_python
PythonHandler trac.web.modpython_frontend
PythonOption TracEnv "/usr/local/trac/wiki"
PythonOption TracUriRoot "/trac/wiki"
<LocationMatch "/trac/[^/]+/login">
AuthType Basic
AuthName "trac"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</LocationMatch>
</VirtualHost>
#啟動 trac Virtual Site
sudo a2ensite trac
#重啟 apache2
/etc/init.d/apache2 restart
#新增 trac.bennu.tw domain
trac CNAME www.bennu.tw.
#存取 http://trac.bennu.tw/trac/wiki
並可以 svn 使用的 muchu 帳號登入

2009年10月2日 星期五

python 的第三方模組安裝 (windows)

直接將第三方的模組:如 eazygui.py 放到 C:\Python26\Lib\site-packages 下即可。

2009年10月1日 星期四

python 學習資料小集

Python 教學文件
http://www.python.tw/ebook/Guido%20van%20Rossum/tut.html
Python 學習手冊
http://www.oreilly.com.tw/product2_c.php?id=a240
易記學
http://ez2learn.com/index.php/python-tutorials
pydoing
http://pydoing.blogspot.com/
官方 module index
http://docs.python.org/modindex.html

2009年8月28日 星期五

java JVM 增大記憶體配置參數 -X 與 -XX

java OOM 分為兩種:

java.lang.OutOfMemoryError: PermGen space
表示 stack 空間不夠,可能是 static 變數太多,或 class 太多。

java.lang.OutOfMemoryError: Java heap space
表示 heap 空間不夠,可能是建立的物件太多,或是處理資料檔案太大。

-Xms<size> : 初始的記憶體大小 (heap)
-Xmx<size> : 最大的記憶體大小 (heap)
-XX:MaxNewSize=<size> : 初始的記憶體大小 (stack)
-XX:MaxPermSize=<size> :最大的記憶體大小 (stack)
-Xincgc = 讓gc在背景持續執行

例:
java -Xms512M -Xmx1024M -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Xincgc -version