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

2009年8月21日 星期五

spring 的 annotation @Value 介紹

通常在 bean.xml 裡我們常以 value 注入單純的資料,如 int,string、
也會注入 properties 檔裡的變數資料,如:
x-setting.properties -
com.transtep.xdna.doc.projplan.docDirLocation=tpma_doc

x-bean.xml -
<property name="docDirLocation">
<value>${com.transtep.xdna.doc.projplan.docDirLocation}</value>
</property>

但spring 3.0 使用 annotation 的時候,x-bean.xml 有些 bean 就不需要再宣告了,如 @Controller
而是自動讓 spring 去 scan 某 package 找到的,如此一來就無法注入 value
在 spring 3.0.M3 時加入了 @Value 這一個方便的 annotation 讓我們可以重拾 value 注入。
用法:

@Value("${com.transtep.xdna.doc.projplan.docDirLocation}")
private String docDirLocation = "";

2009年8月9日 星期日

svn merge 合併 用法理解

svn merge 是用來合併 "其他" repos目錄的某段版本之間的 diff 到你指定的目錄(一般為 . )
假設 有 trunk/stable 和 branches/maintain 兩個目錄都是同一個專案的程式碼,

直接以範例來解釋:
一開始,在trunk下已經有一個穩定版本,但是在 ver 27 時發現一個 bug,
於是將 stable 以 svn copy 到 branches/maintain 並 commit 準備進行修正,此時,
ver 28 時 trunk/stable 和 branches/maintain 均為同一版本的程式碼。

maintain 開始修正 bug ...
在 bug 修正的過程中,一共 commit 了10個版本,並將 bug修正完成。
同時 stable 也有做一些新功能開發,但和 maintain 正在修正的 bug 無太大關聯。

此時 ver為 38,但 maintain 的程式碼和 stable 的程式碼,
已經有 28->38 之間 10個版本的落差,

為了將 maintain 做的修正 "補回" 到 trunk 中,我們要做 merge,首先 cd 到 stable 目錄下
執行 svn merge -r 28:38 ../../branches/maintain/ .
結果即是將 maintain 在版本 28->38 之間做的變更(diff) ,合併到目前的 stable 目錄下。

此階段也許會產生衝突,因為trunk也有可能和 maintain 在同一段程式碼有做修改。
解決衝突後,stable的版本就會是 maintain bug 修正 加 stable 新功能開發版本,
但是 "尚未 commit"。
再進行 stable 的 commit 後,stable 即是最新的版本。

2009年7月31日 星期五

java ee servlet response

HttpServletResponse 物件是用來傳回結果到 browser,有些方法常用的方法:

設定 mime type:以下為 open office 的 odt 文件的 mime type
res.setContentType("application/vnd.oasis.opendocument.text");
設定編碼:
res.setCharacterEncoding("utf-8");
設定元件檔名:
res.addHeader("Content-Disposition", "attachment; filename=project-plan-book.odt");

2009年7月22日 星期三

hql 結合 distinct 過瀘重復的查詢結果

有些情況下,會有查詢到重復物件的問題,
舉一個例子直接說明:
A -> B :1 -> 多
from A as a left join fetch a.b as b
由於A與B是一對多的關係,即許多個B可能以外鍵指向同一個A
以上的hql查詢結果會返回許多重覆的A物件,
假設某A有3個B指向他,則會返回3個某A物件。
這時可以透過distinct將重復的A物件去除,如下:
select distinct a from A as a left join fetch a.b as b

2009年7月6日 星期一

debian 簡易檔案加密解密 ccrypt

安裝:
sudo aptitude install ccrypt

加密:
ccencrypt target-file
Enter encryption key:
Enter encryption key: (repeat)
target-file -> 變成 target-file.cpt 檔案

解密:
ccdecrypt target-file.cpt
Enter decryption key:
target-file.cpt -> 變成 target-file 檔案

顯示加密檔的內容但不解密:
ccat target-file.cpt
Enter decryption key:
.....秘密的資料內容....#@$
target-file.cpt 維持不變。

2009年7月2日 星期四

使用JFreeChart畫甘特圖(gantt)範例

JFreeChart主要分為 JFreeChart 物件表示圖表 及 Dataset 物件表示資料
不同的圖表物由 ChartFactory 不同的 static 方法建立,而不同的圖表物件也需要不同的 Dataset
來儲存資料,如甘特圖的 Dataset 為 IntervalCategoryDataset :

/**
*主程式進入點
*/
public static void main(String[] args){

final IntervalCategoryDataset dataset = createFakeDataset();
final JFreeChart chart = createChart(dataset);
// 輸出圖表成png檔(如果是web servlet可以輸出到response.getOutputStream())
ChartUtilities.writeChartAsPNG(target.getOutputStream(), outputChart, 2000, 600);
}

/**
* 建立甘特圖資料
*
* @return The dataset.
*/
public IntervalCategoryDataset createDataset() {

final TaskSeries s1 = new TaskSeries("計劃");
s1.add(new Task("許功蓋中文測試", new SimpleTimePeriod(date(1, Calendar.APRIL, 2001), date(5, Calendar.APRIL, 2001))));
s1.add(new Task("Obtain Approval", new SimpleTimePeriod(date(9, Calendar.APRIL, 2001), date(9, Calendar.APRIL, 2001))));
s1.add(new Task("Requirements Analysis", new SimpleTimePeriod(date(10, Calendar.APRIL, 2001), date(5, Calendar.MAY, 2001))));
s1.add(new Task("Design Phase", new SimpleTimePeriod(date(6, Calendar.MAY, 2001), date(30, Calendar.MAY, 2001))));
s1.add(new Task("Design Signoff", new SimpleTimePeriod(date(2, Calendar.JUNE, 2001), date(2, Calendar.JUNE, 2001))));
s1.add(new Task("Alpha Implementation", new SimpleTimePeriod(date(3, Calendar.JUNE, 2001), date(31, Calendar.JULY, 2001))));
s1.add(new Task("Design Review", new SimpleTimePeriod(date(1, Calendar.AUGUST, 2001), date(8, Calendar.AUGUST, 2001))));
s1.add(new Task("Revised Design Signoff", new SimpleTimePeriod(date(10, Calendar.AUGUST, 2001), date(10, Calendar.AUGUST, 2001))));
s1.add(new Task("Beta Implementation", new SimpleTimePeriod(date(12, Calendar.AUGUST, 2001), date(12, Calendar.SEPTEMBER, 2001))));
s1.add(new Task("Testing", new SimpleTimePeriod(date(13, Calendar.SEPTEMBER, 2001), date(31, Calendar.OCTOBER, 2001))));
s1.add(new Task("Final Implementation", new SimpleTimePeriod(date(1, Calendar.NOVEMBER, 2001), date(15, Calendar.NOVEMBER, 2001))));
s1.add(new Task("Signoff", new SimpleTimePeriod(date(28, Calendar.NOVEMBER, 2001), date(30, Calendar.NOVEMBER, 2001))));

final TaskSeries s2 = new TaskSeries("實際");
s2.add(new Task("許功蓋中文測試", new SimpleTimePeriod(date(1, Calendar.APRIL, 2001), date(5, Calendar.APRIL, 2001))));
s2.add(new Task("Obtain Approval", new SimpleTimePeriod(date(9, Calendar.APRIL, 2001), date(9, Calendar.APRIL, 2001))));
s2.add(new Task("Requirements Analysis", new SimpleTimePeriod(date(10, Calendar.APRIL, 2001), date(15, Calendar.MAY, 2001))));
s2.add(new Task("Design Phase", new SimpleTimePeriod(date(15, Calendar.MAY, 2001), date(17, Calendar.JUNE, 2001))));
s2.add(new Task("Design Signoff", new SimpleTimePeriod(date(30, Calendar.JUNE, 2001), date(30, Calendar.JUNE, 2001))));
s2.add(new Task("Alpha Implementation", new SimpleTimePeriod(date(1, Calendar.JULY, 2001), date(12, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Design Review", new SimpleTimePeriod(date(12, Calendar.SEPTEMBER, 2001), date(22, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Revised Design Signoff", new SimpleTimePeriod(date(25, Calendar.SEPTEMBER, 2001), date(27, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Beta Implementation", new SimpleTimePeriod(date(27, Calendar.SEPTEMBER, 2001), date(30, Calendar.OCTOBER, 2001))));
s2.add(new Task("Testing", new SimpleTimePeriod(date(31, Calendar.OCTOBER, 2001), date(17, Calendar.NOVEMBER, 2001))));
s2.add(new Task("Final Implementation", new SimpleTimePeriod(date(18, Calendar.NOVEMBER, 2001), date(5, Calendar.DECEMBER, 2001))));
s2.add(new Task("Signoff", new SimpleTimePeriod(date(10, Calendar.DECEMBER, 2001), date(11, Calendar.DECEMBER, 2001))));

final TaskSeriesCollection collection = new TaskSeriesCollection();
collection.add(s1);
collection.add(s2);

return collection;
}

/**
* 方便建立日期
*
* @param day
* the date.
* @param month
* the month.
* @param year
* the year.
*
* @return a date.
*/
public Date date(final int day, final int month, final int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
Date result = calendar.getTime();
return result;
}

/**
* 產生甘特圖物件
*
* @param dataset
* the dataset.
*
* @return The chart.
*/
public JFreeChart createChart(final IntervalCategoryDataset dataset) {
final JFreeChart chart = ChartFactory.createGanttChart("測試甘特圖 Demo", // chart title
"事件", // domain axis label
"日期", // range axis label
dataset, // data
true, // include legend
true, // tooltips
false // urls
);
//設定各處的字型(需設定為支援中文的字型,才不會造成中文亂碼)
Font font = new Font("標楷體", Font.BOLD, 16);
chart.getLegend().setItemFont(font);
chart.getTitle().setFont(font);
chart.getCategoryPlot().getDomainAxis().setLabelFont(font);
chart.getCategoryPlot().getDomainAxis().setTickLabelFont(font);
chart.getCategoryPlot().getRangeAxis().setLabelFont(font);
chart.getCategoryPlot().getRangeAxis().setTickLabelFont(font);
return chart;
}

結果如下(web)

2009年6月26日 星期五

hibernate order by

假設 Account 的主鍵是 username VARCHAR,如果想要列出所有帳號資料,並依主鍵排序的話。
可以使用 id 進行排序即可,不一定要指定 username,如:

from Account as acc order by acc.id

這樣的寫法等同於

from Account as acc order by acc.username

但由於以 id 排序,不需要知道特定表格的主鍵 column 的名稱,
在某些無法得知 column 名稱的場合,可以派得上用場

2009年6月19日 星期五

hibernate 關聯 hbm.xml 設定 範例

many-to-one範例 -
<many-to-one name="targetGroup" column="group_id" class="com.transtep.green.servlet.framework.hibernate.GreenGroup" insert="false" update="false" cascade="save-update" outer-join="true" />

one-to-many範例 -
<set name="relAccExtSet" cascade="all" inverse="true" lazy="true">
<key>
<column name="account_id" />
</key>
<one-to-many class="com.transtep.green.servlet.framework.hibernate.GreenAccountExt" />
</set>

one-to-one範例 -
<one-to-one name="relSauth" class="com.transtep.green.servlet.framework.hibernate.GreenSimpleAuth" cascade="all" property-ref="relAccount" />

<many-to-one name="relAccount" column="account_id" class="com.transtep.green.servlet.framework.hibernate.GreenAccount" insert="false" update="false" cascade="save-update" outer-join="true" unique="true"/>

2009年6月8日 星期一

Spring PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurer 的作用是可以將 spring 的 bean-config.xml 裡的某些資料
抽離出來,放到另外一個 key-value 的 property file 裡,方便統一設定。
先在bean-config.xml裡加入:

<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:green-setting.properties</value>
</property>
</bean>

再建立對應的 green-setting.properties 檔:
com.transtep.green.db.jdbcurl=jdbc:postgresql://db.transtep.com:5432/MARK_GREEN?charSet=utf8
com.transtep.green.db.user=postgres
com.transtep.green.db.password=admin

如此一來就可以在bean-config.xml裡使用${key}變數來設定資料,如:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>org.postgresql.Driver</value>
</property>
<property name="jdbcUrl">
<value>${com.transtep.green.db.jdbcurl}</value>
</property>
<property name="user">
<value>${com.transtep.green.db.user}</value>
</property>
<property name="password">
<value>${com.transtep.green.db.password}</value>
</property>
略....

2009年6月7日 星期日

debian 下的啟動服務設定 script update-rc.d

在 /etc/init.d 中建立一個叫作 zope 的 script , 然後

update-rc.d zope defaults

就會產生以下連結::

Adding system startup for /etc/init.d/zope ...
/etc/rc0.d/K20zope -> ../init.d/zope
/etc/rc1.d/K20zope -> ../init.d/zope
/etc/rc6.d/K20zope -> ../init.d/zope
/etc/rc2.d/S20zope -> ../init.d/zope
/etc/rc3.d/S20zope -> ../init.d/zope
/etc/rc4.d/S20zope -> ../init.d/zope
/etc/rc5.d/S20zope -> ../init.d/zope

2009年6月6日 星期六

hql 的left outter join轉換成sql的結果

hql:
from TpmaAccount as a
left join a.relTpmaStaff as staff with staff.projectId = 1

sql:
select
tpmaaccoun0_.username as username0_0_,
tpmastaff1_.staff_id as staff1_10_1_,
tpmaaccoun0_.password as password0_0_,
tpmaaccoun0_.role as role0_0_,
tpmaaccoun0_.enabled as enabled0_0_,
tpmaaccoun0_.valid_bdate as valid5_0_0_,
tpmaaccoun0_.valid_edate as valid6_0_0_,
tpmaaccoun0_.staff_id as staff7_0_0_,
tpmaaccoun0_.login_date as login8_0_0_,
tpmaaccoun0_.login_cnt as login9_0_0_,
tpmaaccoun0_.login_ip as login10_0_0_,
tpmastaff1_.project_id as project2_10_1_,
tpmastaff1_.first_name as first3_10_1_,
tpmastaff1_.last_name as last4_10_1_,
tpmastaff1_.sex as sex10_1_,
tpmastaff1_.org as org10_1_,
tpmastaff1_.cellphone as cellphone10_1_,
tpmastaff1_.telephone as telephone10_1_,
tpmastaff1_.address as address10_1_,
tpmastaff1_.skype as skype10_1_,
tpmastaff1_.msn as msn10_1_,
tpmastaff1_.email as email10_1_,
tpmastaff1_.remark as remark10_1_
from
public.tpma_account tpmaaccoun0_
left outer join
public.tpma_staff tpmastaff1_
on tpmaaccoun0_.staff_id=tpmastaff1_.staff_id
and (
tpmastaff1_.project_id=1
)

2009年5月15日 星期五

regex網頁版測試工具

regexpal
http://regexpal.com/

在下方貼上要測試的文字
在上方寫RegEx語法

2009年5月7日 星期四

apache commons httpclient 送出 multipart post 寫法

public byte[] uploadMessage(File fileToUpload, UPLOAD_FILE_TYPE type, int[] messageIds) {
byte[] response = null;
try {
// new method
PostMethod postHttpMethod = new PostMethod(webappUrl + uploadFileUrl);
// prepare
// key-value part
Part fileNamePart = new StringPart("fileName", fileToUpload.getName(), "UTF-8");
Part typePart = new StringPart("type", type.toString(), "UTF-8");
StringBuffer strbuf = new StringBuffer();
for (int i = 0; i < messageIds.length; i++) {
strbuf.append(messageIds[i]);
if (i != messageIds.length) {
strbuf.append(",");
}
}
Part messageIdsPart = new StringPart("messageIds", strbuf.toString(), "UTF-8");
// file part
Part filePart = new FilePart("content", fileToUpload);
// multipart
Part[] parts = new Part[] { fileNamePart, typePart, messageIdsPart, filePart };
MultipartRequestEntity multipartEntity = new MultipartRequestEntity(parts, postHttpMethod.getParams());
postHttpMethod.setRequestEntity(multipartEntity);
// execute
try {
httpclient.executeMethod(httpMethod);
response = httpMethod.getResponseBody();
} catch (HttpException e) {
log.error(e.getMessage(), e);
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
httpMethod.releaseConnection();
}
return response;
} catch (FileNotFoundException e) {
log.error(e.getMessage(), e);
}
return response;
}

JFrame的最小化與還原

使用JFrame的setState方法:
public void setState(int state)
state 的值可以是 Frame.NORMAL(還原) 或 Frame.ICONIFIED(最小化)

另外:
JFrame還有 toFront() 及 toBack() 方法可以調整前後,
但必須在 Frame.NORMAL 狀態下才有效。

toFront() 讓 JFrame 到最前面不被其他視窗擋住。

2009年5月4日 星期一

以vim進行檔案編碼轉換

首先必須確定vim有支援multi_byte
開啟vim後輸入
:echo has('multi_byte')
如果結果為1則表示有支援

在vim下要以指定的encoding開啟某一檔案
:e ++enc=

在vim下要以指定的encoding儲存某一檔案
:w ++enc=

例:以vim開啟一個ucs-2le編碼的檔案,並轉存成utf-8編碼。
:e ++enc=ucs-2le /tmp/file_ucs2le.csv
:w ++enc=utf-8 /tmp/file_utf8.csv

ps.ucs-2le為windows下用的unicode編碼

2009年4月22日 星期三

java 的 odt 轉換工具 JODConverter

官方網頁
http://www.artofsolving.com/opensource/jodconverter

首先啟動openoffice的服務模式,最簡單的方式是,到openoffice安裝目錄下的program,如:
C:\Program Files\OpenOffice.org 3\program執行
soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard

可以使用 netstat -a 檢查 8100 port 是否有在 LISTENING
下載 jodconverter-2.2.2.zip 並將裡面的 lib 下的 jar放到classpath下

轉換的程式碼:
public static void main(String[] args) throws Exception {
File inputFile = new File("test.odt");
File outputFile = new File("test.doc");

// connect to an OpenOffice.org instance running on port 8100
OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
connection.connect();

// convert
DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
converter.convert(inputFile, outputFile);

// close the connection
connection.disconnect();
}

jodconverter是透過輸入的副檔名來做為轉換的依據的。

2009年4月16日 星期四

Junit 4.5 的 TestAll寫法

Junit 4.5 的 TestAll寫法

@RunWith(Suite.class)
@SuiteClasses( { TestAllDao.class, TestAllController.class })
public class TestAllXdna {

}

2009年4月11日 星期六

hinet 中華電信 DNS 列表

DNS Server 中華電信的全區 168.95.1.1
中華電信分區如下
北區 DNS 139.175.55.244(主) 139.175.252.16(次) 適用地區範圍:台北, 桃園, 新竹, 宜蘭, 花蓮, 苗栗
中區 DNS 139.175.150.20(主) 139.175.55.244(次) 適用地區範圍:台中, 彰化, 南投, 雲林
南區 DNS 139.175.10.20(主) 139.175.55.244(次) 適用地區範圍:高雄, 台南, 嘉義, 屏東, 台東

2009年4月8日 星期三

spring 3.0.0.M2 整合 Apache Tiles 2 模版

一、
tiles相關的jar加到WEB-INF/lib,以3.0.0.M2的情型,必需下載tiles-2.0.7的版本,
tiles-2.1.x以上的版本,尚有問題,tiles本身也相依commons-beanutils 及 commons-digester,
都可以在Tiles-2.0.7-bin.tar.gz下載得到。固與Tiles相關的jar有:
commons-beanutils-1.7.0.jar
commons-digester-1.8.jar
commons-logging-1.1.1.jar
tiles-api-2.0.7.jar
tiles-core-2.0.7.jar
tiles-jsp-2.0.7.jar

二、
在spring的bean設定檔稍做修改,
a在viewResolver將InternalResourceViewResolver改用UrlBasedViewResolver
b並加入viewClass 設定為 org.springframework.web.servlet.view.tiles2.TilesView
c加入 TilesConfigurer
如下:
<!-- test jsp view -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>

<!-- Tiles 模版 -->
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/defs/templates.xml</value>
</list>
</property>
</bean>

三、
在上面的TilesConfigurer bean中指定了/WEB-INF/defs/templates.xml這個模版定義檔
建立templates.xml內容為:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="/WEB-INF/jsp/test.jsp" template="/WEB-INF/jsp/templates/layout.jsp">
<put-attribute name="title" value="TPMA Tiles tutorial homepage" />
<put-attribute name="header" value="/WEB-INF/jsp/templates/header.jsp" />
<put-attribute name="menu" value="/WEB-INF/jsp/templates/menu.jsp" />
<put-attribute name="body" value="/WEB-INF/jsp/body.jsp" />
<put-attribute name="footer" value="/WEB-INF/jsp/templates/footer.jsp" />
</definition>
</tiles-definitions>

四、
上面的定義了當Controller的return
return new ModelAndView("test", "test", model);
的時後,test會被UrlBasedViewResolver組合成/WEB-INF/jsp/test.jsp,而TilesView則會到,
templates.xml找到/WEB-INF/jsp/test.jsp的定義,並根據layout.jsp頁面組合title、header、
menu、body、footer等頁面,layout.jsp的內容如下:
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><tiles:getAsString name="title" /></title>
</head>
<body>
<table border="0" width="100%" cellspacing="5">
<tr>
<td colspan="2"><tiles:insertAttribute name="header" /></td>
</tr>
<tr>
<td width="140" valign="top"><tiles:insertAttribute name="menu" /></td>
<td valign="top" align="left"><tiles:insertAttribute name="body" /></td>
</tr>
<tr>
<td colspan="2"><tiles:insertAttribute name="footer" /></td>
</tr>
</table>
</body>
</html>

以tiles:getAsString插入templates.xml定義的value為文字
以tiles:insertAttribute插入templates.xml定義的value的網頁

五、
準備templates.xml中定義的其他jsp頁面。

六、
每個網頁一樣可以使用EL取得model的值
${test.name } ${test.passwd }

2009年3月26日 星期四

wine 下好用的 winetricks script

在linux上裝wine可以模擬 windows 環境,並執行 *.exe程式。
然而windows上許多api/dll,官方的wine並不完全包含,必須另外安裝,如:
常用的DirectX、.net等,有一隻script可以幫忙快速安裝這些軟體,叫作winetricks:

winetricks主站:
http://wiki.winehq.org/winetricks

下載:
wget http://www.kegel.com/wine/winetricks

winetricks必須用到cabextract套件來解開*.CAB檔,所以必須安裝cabextract套件:
aptitude install cabextract

執行:
sh winetricks dotnet11 directx9 ie6 firefox3

即安裝 .net-1.1 directx9 ie6 firefox3

使用 apache mina 框架建立網路程式

server:
public class FlavorServer {

private int PORT = 6275;

public void startServer() {
try {
ByteBuffer.setUseDirectBuffers(false);
ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
IoAcceptor acceptor = new SocketAcceptor();
SocketAcceptorConfig cfg = new SocketAcceptorConfig();
cfg.getFilterChain().addLast("logger", new LoggingFilter());
cfg.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

acceptor.bind(new InetSocketAddress(PORT), new FlavorServerHandler(), cfg);
System.out.println("MINA Flavor server started.");
} catch (IOException e) {
e.printStackTrace();
}
}
}

client:
public class FlavorClient {
private int PORT = 6275;

public void startClient() {
ByteBuffer.setUseDirectBuffers(false);
ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
IoConnector connector = new SocketConnector();
SocketConnectorConfig cfg = new SocketConnectorConfig();
cfg.getFilterChain().addLast("logger", new LoggingFilter());
cfg.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
connector.connect(new InetSocketAddress(PORT), new FlavorClientHandler(), cfg);
}
}

無論是 server 或 client 用到的 Handler 都是繼承 IoHandlerAdapter 物件的子類別:
public class FlavorServerHandler extends IoHandlerAdapter
public class FlavorClientHandler extends IoHandlerAdapter
並override IoHandlerAdapter所提供的方法,就可以進行網路的溝通,如:

@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String msgStr = (String) message;
if (msgStr.trim().equalsIgnoreCase("bye")) {
session.close();
return;
}
if (count == 1000) {
session.write("quit");
} else {
session.write(count);
}
count++;
System.out.println(msgStr);

}

@Override
public void sessionCreated(IoSession session) throws Exception {
System.out.println("client session created");
if (session.getTransportType() == TransportType.SOCKET) {
((SocketSessionConfig) session.getConfig()).setReceiveBufferSize(2048);
}

session.setIdleTime(IdleStatus.BOTH_IDLE, 10);
}

apache2 建立新的 Virtual Host site

#aptitude install apache2
安裝好apache2後,預設只有/var/www/做為default site,
可以在 /etc/apache2/site-available/default 進行設定,
如果想增加一個 site 並綁定到不同的 根目錄 位置及 Virtual Host domain,
首先必須先去擁有的domain設定 CNAME 一個要用 domain 如:
storage CNAME www.bennu.tw.
也就是增加一個 storage.bennu.tw 但storage 的ip和 www.bennu.tw 其實是一樣的。

再到/etc/apache2/site-available/ 建立一個storage.bennu.tw檔案
vim storage.bennu.tw 內容為:

<VirtualHost *:80>
ServerName storage.bennu.tw
ServerAdmin muchu1983@storage.bennu.tw
DocumentRoot /storage/
ErrorLog /var/log/apache2/storageError.log
CustomLog /var/log/apache2/storageAccess.log common
</VirtualHost>

再將這個檔案建立一個連結在 /etc/apache2/site-enabled/ 下
ln -s /etc/apache2/site-availiable/storage.bennu.tw /etc/apache2/site-enabled/storage.bennu.tw

再來要記得用a2ensite enable 這個新的 site
a2ensite storage.bennu.tw

最後重新啟動 apache2 服務即可
/etc/init.d/apache2 restart

重新啟動後,用網址連storage.bennu.tw所看到的網站的根目錄,
就是/storage/* 下的資料。

spring app context 的 event 通知

spring 的 ApplicationContext 或 WebApplicationContext 在啟動/關閉時,會發出許多事件,
這些事件都是org.springframework.context.ApplicationEvent的子類別

ContextClosedEvent -
在ApplicationContext關閉時發佈事件。
ContextRefreshedEvent -
在ApplicationContext初始或Refresh時發佈事件。
RequestHandledEvent -
在Web應用程式中,當請求被處理時,ApplicationContext會發佈此事件。

如果需要對這些事件做處理,必須實作org.springframework.context.ApplicationListener介面,
並在bean-config.xml定義實作ApplicationListener的bean,一但有事件發生,ApplicationContext
即會通知bean-config.xml中的所有ApplicationListener做處理。

2009年3月16日 星期一

lxde autostart 自動啟動設定

到/usr/share/applications/下找到需要的啟動檔案,
如pidgin的啟動檔案為pidgin.desktop
將pidgin.desktop copy 到 ~/config/autostart/pidgin.desktop 即可
如果沒有autostart資料夾就自行建立。

2009年3月10日 星期二

spring framework mvc 處理編碼的 filter

只要在web.xml加入下列的filter
就可以統一將get/post的url,textfield的內容都轉換為utf-8編碼。

<!-- encoding -->
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>

2009年3月8日 星期日

善用/etc/hosts及ipconfig 綁定多個ip

如果沒有經過任何設定,當使用 domain name 存取一個對方的主機時,等於是以外部ip傳遞封包
封包一定是經由網域的外部出去internet再到對方的主機,即使對方的主機是和自已主機同網域。
例如:
同一個hub的兩個孔的主機,各指定自己的domain name為ftp.bennu.tw和www.bennu.tw
ftp到www封包路徑 ftp -> hub -> internet -> hub -> www,速度會變得很慢。

這個情況下可以將ftp和www的網卡,假設都是eth0,各綁定第二個內部ip
ftp:
#ifconfig eth0:0 192.168.1.100
www:
#ifconfig eth0:0 192.168.1.101

然後再將各自的/etc/hosts加入:
ftp:
192.168.1.101 www.bennu.tw www
www:
192.168.1.100 ftp.bennu.tw ftp

這樣一來即使使用domain name傳遞封包,路徑就不會再繞到internet,
而是僅僅在內部的網域內傳遞,速度快得多了:
ftp -> hub -> www

2009年3月7日 星期六

python的中文註解

必須在#!/usr/bin/env python下加入:
#-*- coding: utf-8 -*-
否則當python直譯器遇到中文字時會抱怨非ANSI字元,顯示以下訊息:
SyntaxError: Non-ASCII character .....

2009年2月23日 星期一

掃描 XSANE-HP Deskjet

安裝 xsane
sudo aptitude install xsane
並加入 scanner group
sudo usermod -G scanner -a muchu1983
之後在X的功能選單下就可以使用XSane進行掃描。

2009年2月16日 星期一

使用 springframework 3.0.0 建立 RESTful 網路應用程式 Controller

RESTful是一種新的Webapp設計概念,可以減少很多傳統Webapp程式的code,
傳統Webapp以一個 url mapping 到一個 service ,如 java servlet 或 spring controller,
以操作資料庫的 CRUD 四個步驟來說,一張資料表至少就需要4個 service 命令來完成實作。
也就是要分別對四個 url 進行操作。

RESTful 則將資料當成一種資源,利用 http 原本就有的 Get、Post、Delete、Put…
等七個 method ,對同一個 url 進行操作,如下圖。
















spring 在 3.0版之後的 spring MVC 框架就有提供 RESTful 相關的支援,並使用 java 5.0 的
annotation 語法,用起非常簡單方便。

spring 3.0.0 相依的 jar有:
antlr-3.0.1.jar
asm-3.1.jar
asm-common-3.1.jar
commons-logging.jar
log4j-1.2.13.jar

簡單的 RESTful 範例 /rest/{i}/{n} : i、n 均為變數


web.xml 加入 DispatcherServlet 的servlet定義,並mapping到 /rest/*

<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/conf/spring-restful-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

需注意:
DispatcherServlet 因為被 mapping 到 /rest/* 所以在 DispatcherServlet 帶起來的WebApplicationContext 之下 做mapping時, "/"符號就等於 "/rest/"這一層 ,
也就是說 html form action 的 "/rest/1/2/3/4" mapping 要寫成 "/1/2/3/4"。

在 web.xml 指定了 /WEB-INF/conf/spring-restful-config.xml 這個檔為 spring bean config
內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

<!-- test jsp view -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>

<bean id="testController"
class="com.transtep.restful.server.framework.spring.controller.TestController">
</bean>
</beans>

spring-restful-config.xml 檔裡有 2 個 bean 負責 spring 2.5 開始有的 annotation MVC功能,
DefaultAnnotationHandlerMapping -> 處理 class level 的 annotation。
AnnotationMethodHandlerAdapter -> 處理 method level 的 annotation。
底下再定義 Controller 的 bean class,這些 bean 就可以用 annotation 的語法來定義了。
如這裡的 TestController :

@Controller
public class TestController {

@RequestMapping(value = "/1/{ii}/{nn}", method = RequestMethod.GET)
public ModelAndView getTest(@PathVariable(value = "ii") String id, @PathVariable(value = "nn") String number) {
System.out.println("run 1");
Map model = new HashMap();
model.put("message", "id " + id + "\n" + "number " + number);
return new ModelAndView("test", model);
}

@RequestMapping(value = "/1/{ii}/{nn}", method = RequestMethod.POST)
public ModelAndView postTest(@PathVariable(value = "ii") String id, @PathVariable(value = "nn") String number) {
Map model = new HashMap();
model.put("message", "id " + id + "\n" + "number " + number);
return new ModelAndView("test", model);
}
}

首先在 class 宣告上以 @Controller 定義這是一個 Controller (不需要再implements Controller)
再以
@RequestMapping 定義各別的 method 的 URI 、 method mapping,特別是 URI 可以{}
定義成變數的格式,再配合 @PathVariable 將變數的實際值綁到 method的參數上,同時根據
方法的參數型別不同,自動轉換成正確的型別。

上面的例子以 get /rest/1/123/456 則會執行 getTest() 方法,id=123,number=456
而如果以 post /rest/1/456/789 則會執行 postTest() 方法,id=456,number=789

2009年2月10日 星期二

在 xorg.conf 檔調整顯示器的水平垂直更新率

每個場商的每個螢幕的設定範圍都不同,即使設定不正確螢幕也不一定就沒畫面,
有可能是在執行某些需要特殊畫面更新率的軟體,例如640x480解析度的遊戲時,
會因為更新率不支援(其實是沒設定好),而造成畫面一片黑,出現 out of range 等等。

先查詢螢幕的正確水平,垂直更新率。
編輯 /etc/X11/xorg.conf
找到 Section "Monitor" 裡面有 HorizSync VertRefresh 兩項,
各自填入查到的 水平(HorizSync)、垂直(VertRefresh) 更新率,
有時可能填的範圍要比查詢到的還小一點,50.0 - 80.0 可以只填 30.0 - 70.0就好。
更新後 startx 進入X,切換一下解析度,看看能不能正常顯示。

2009年2月8日 星期日

lenny中使用wine設定執行魔獸爭霸3

首先安裝wine就不多說了,我使用的是1.0.1-1

安裝好wine後,先執行winecfg設定一下
1.windows版本的地方選windows 2000
2.函式庫->已有的函式庫頂替 維持空的
3.顯示 -> 模擬一個虛擬桌面 打勾 800x600
4.儲存槽 -> 按一下自動偵測 讓wine對應linux的路徑到磁碟機代號

開始安裝Warcraft3,如果已經有安裝好的則直接copy過來linux下,跳過這一步
mount主程式的光碟,並在光碟的掛載點下執行wine install.exe
mount資料片的光碟,並在光碟的掛載點下執行wine install.exe

更新patch
下載 http://todian.myweb.hinet.net/ 提供的傻瓜包來更新
更新完成後也會變成免光碟版,一樣以 wine 執行更新程式,
wine warcraft_patch_upgrade_122a_v3.exe
選擇Warcraft III的安裝(或copy)資料夾,由於傻包完成後會自動執行遊戲,
但wine的Directx3D還不夠完整,現在執行畫面可能一片黑,先想辦法關掉遊戲
大絕招是ctrl-alt-←關掉整個X再startx

透過安裝步驟 wine的register表也會自動加入Warcraft資料,
但如果是從別的地方copy的,就要手動去新增wine register裡的資料
執行 regedit
找到下列的key,如果沒有就按右鍵新增key(一個key就是一層資料夾)
HKEY_CURRENT_USER\Software\Blizzard Entertainment\Warcraft III
在右側建立名為Gfx OpenGL的DWORD值,Value data設置為1
(這個regedit主要設定War3以opengl執行遊戲)

現在回到 Warcraft III 資料夾下,執行
wine War3.exe -opengl或wine War3.exe -x11
順利的話會在wine虛擬桌面下看到開場動畫,等動畫播完,遊戲畫面會一片黑
滑鼠點一下黑色的遊戲畫面,則遊戲界面就會出來。先離開遊戲

再次執行 winecfg
將 顯示 -> 模擬一個虛擬桌面 打勾取消掉
重新回到Warcraft III 資料夾下,執行
wine War3.exe -opengl或wine War3.exe -x11
就可以以全螢幕進行遊戲了。
(因為開場動畫沒有用虛擬桌面的話就不能播)

2009年2月7日 星期六

debian下apache2安裝mod_python模組

首先安裝好apache2
sudo aptitude install apache2
安裝好後預設的web context根目錄會在/var/www下

安裝mod_python模組
sudo aptitude install libapache2-mod-python

設定網站支援mod_python
vim /etc/apache2/sites-available/default
在Directory /var/www的項目中
把內容改為:
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
存檔

重新啟動apache
/etc/init.d/apache2 restart

這樣就完成mod_python的安裝與設定了
現在可以建立python程式

vi /var/www/test.py
內容為:
#!/usr/bin/env python
def index(req):
return "Test successful";

以browser連到 http://localhost/test.py
就可以看到 Test successful 的輸出結果。

2009年1月23日 星期五

svnadmin dump 參數說明

在命令列下輸入
$svnadmin help dump 會出現以下訊息:

dump: 用法: svnadmin dump REPOS_PATH [-r LOWER[:UPPER]] [--incremental]

將檔案系統的內容, 以一種可攜式 '傾印檔' 格式輸出到標準輸出, 並將訊息
回報輸出到標準錯誤. 將 LOWER 與 UPPER 之間修訂版內容傾印出來. 如果沒
有指定修訂版的話, 傾印所有的修訂版樹. 如果只有指定 LOWER 的話, 只傾印
一個修訂版樹. 如果使用了 --incremental 選項, 那麼第一個傾印的修訂版會
是與前一個修訂版的差異, 而非平常的全文輸出.

有效選項:
-r [--revision] ARG : 指定修訂版編號 ARG (或 X:Y 範圍)
--incremental : 以差異增量進行傾印
--deltas : 於傾印檔輸出中使用檔案差異
-q [--quiet] : 不顯示進度 (僅錯誤) 至標準錯誤輸出


僅備份部分版本需使用 -r 參數,如:
repos檔案庫的最新版本號為100
svnadmin dump repos/ -r 90:100
即是完整備份90到最新的100的資料,但下次使用svnadmin load指令回來時
版本會從1開始算,也就是之前的版本90變成版本1

--incremental是進行差異備份,影響的是第一個版本的內容,如:
svnadmin dump repos/ -r 90:100 --incremental
一樣是備份 90-100 之間的資料,但版本90的資料卻不包含版本89之前的資料
也就是備份出來的資料必須建立在已經有版本89的檔案庫為基礎的檔案庫
如果 svnadmin load 時沒有版本 89的檔案庫為基礎,則會出現錯誤。

2009年1月19日 星期一

非 standalone jetty的啟動關閉方式

非 standalone jetty的啟動關閉方式:
cd %JETTY_HOME%
java -DSTOP.PORT=8079 -DSTOP.KEY=secret -jar start.jar

這將告訴Jetty在8079 Port偵聽Stop命令,並且Stop時要求提供Key:secret。對應的Stop命令:
java -DSTOP.PORT=8079 -DSTOP.KEY=secret -jar start.jar --stop

一個簡單的 shell script進行控制
#!/bin/bash
cd /usr/local/jetty-6.1.12.rc2
if [ "$1" == "start" ]; then
java -DSTOP.PORT=8079 -DSTOP.KEY=green -jar start.jar etc/jetty.xml etc/green-jaas.xml &
elif [ "$1" == "stop" ]; then
java -DSTOP.PORT=8079 -DSTOP.KEY=green -jar start.jar --stop
else
echo "useage: switch.sh [start|stop]."
fi

2009年1月14日 星期三

debian base安裝+icewm+基本套件

安裝好base system

xorg:
aptitude install xorg
x window:
aptitude install icewm
update-alternatives --config x-session-manager
update-alternatives --config x-window-manager
terminal:
aptitude install mlterm mlterm-tools
update-alternatives --config x-terminal-emulator
input:
aptitude install gcin
font:
sudo aptitude install ttf-wqy-zenhei
sudo aptitude install xfonts-wqy

修改startx啟動的X windows manager

update-alternatives --config x-session-manager
update-alternatives --config x-window-manager

2009年1月9日 星期五

Spring支援的log4j設定web.xml

在web.xml裡增加下列設定,即可整合log4j到webapp裡:

2009年1月3日 星期六

Debian好看的中文字型-文泉驛

文泉驛
sudo aptitude install ttf-wqy-zenhei
sudo aptitude install xfonts-wqy
文鼎
sudo aptitude install ttf-arphic-bkai00mp
sudo aptitude install ttf-arphic-uming

Debian安裝過程載入adsl pppoe設定

使用debian安裝光碟開機後,不直接按Enter進入安裝程序.
選擇Help選項,即可查尋及輸入特殊參數,
啟動載入 pppoe 模組的參數:
install modules=ppp-udeb
這樣一來在安裝過程,安裝程式會詢問adsl的帳號密碼
來進行網路設定.

2009年1月2日 星期五

建立USB隨身碟debian安裝碟

安裝套件:
dosfstools,syslinux,mtools,mbr
步驟:

1. 建立FAT16到USB的第一分割區上
#fdisk /dev/sdb (設定bootable,partition system id)
#mkdosfs /dev/sdb1

2. 安裝syslinux到USB
#syslinux /dev/sdb1 (會在sdb1上建立
ldlinux.sys)

3. mount USB 並 copy必需的檔案
#mount /dev/sdb1 /mnt
#cp
vmlinuz /mnt (kernel)
#cp
initrd.gz /mnt (initrd)

4. 建立 syslinux 設定檔
在 /mnt 新建 syslinux.cfg
內容包含下兩行:

DEFAULT vmlinuz auto url=debian.org.tw modules=ppp-udeb
APPEND initrd=initrd.gz

5. copy debian 安裝光碟映象檔
#cp debian-testing-i386-xfce-CD-1.iso /mnt

6. mount USB
#umount /dev/sdb1

7. 安裝mbr到USB的開機區
#install-mbr /dev/sdb

8. 重開機並設定BIOS使用USB開機

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要小心資料共用的問題。

2008年8月20日 星期三

apache ftpserver-1.0-M2

apache ftpserver 可以加入自定的Ftplet來處理Ftp Event。
只要實作Ftplet interface 或 直接繼承DefaultFtplet。
再加入Ftplet到ftpserver,當Ftp command到來後就會自動呼叫對應的方法。

FtpServer ftpserver = new FtpServer();
ftpserver.setFtplets(getFtpletsMap());
ftpserver.start();

想使用DefaultFtplet來處理Ftp命令,可以override DefaultFtplet的onXXXStart方法。
卻找不到onListStart方法,來顯示檔案列表。
看了一下source code 發現DefaultFtplet的實作只是把beforeCommand根據,
request.getCommand()取得的命令來分支到其他方法,如下,

public FtpletResult beforeCommand(FtpSession session, FtpRequest request)
throws FtpException, IOException {
String command = request.getCommand().toUpperCase();

if ("DELE".equals(command)) {
return onDeleteStart(session, request);
} else if ("STOR".equals(command)) {
return onUploadStart(session, request);
} else if ("RETR".equals(command)) {
return onDownloadStart(session, request);
} else if ("RMD".equals(command)) {
return onRmdirStart(session, request);
} else if ("MKD".equals(command)) {
return onMkdirStart(session, request);
} else if ("APPE".equals(command)) {
return onAppendStart(session, request);
} else if ("STOU".equals(command)) {
return onUploadUniqueStart(session, request);
} else if ("RNTO".equals(command)) {
return onRenameStart(session, request);
} else {
// TODO should we call a catch all?
return null;
}
}

於是就可以自己重新override beforeCommand方法再增加LIST分支即可,
@Override
public FtpletResult beforeCommand(FtpSession session, FtpRequest request) throws FtpException, IOException {
String command = request.getCommand().toUpperCase();
if ("LIST".equals(command)) {
return this.onListStart(session, request);
} else {
return super.beforeCommand(session, request);
}
}

2008年8月11日 星期一

Spring 整合 Hibernate

classpath所需要的jar
===== postgresql ==========
pg74.216.jdbc3.jar
======= spring ===========
spring.jar
commons-logging.jar
======= hibernate =========
antlr-2.7.6.jar
asm.jar
c3p0-0.9.1.jar
cglib-2.1.3.jar
commons-collections-2.1.1.jar
dom4j-1.6.1.jar
ehcache-1.2.3.jar
hibernate3.jar
jta.jar
log4j-1.2.13.jar
=======================

範例資料表DDL
CREATE TABLE tbl_user
(
id serial NOT NULL,
name character varying(20),
age integer,
CONSTRAINT tbl_user_pkey PRIMARY KEY (id)
)

使用HibernateTools產生TblUser.java POJO物件 及 TblUser.hbm.xml mapping file

建立IUserDAO介面
package idv.muchu.test.spring;

public interface IUserDAO {
public void insert(TblUser user);
public void update(TblUser user);
public void delete(TblUser user);
public TblUser find(Integer id);
}

實作IUserDAO介面(使用HibernateTemplate簡化實作)

package idv.muchu.test.spring;

import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class UserDAO implements IUserDAO {
private HibernateTemplate hibernateTemplate = null;

public void setSessionFactory(SessionFactory sf) {
this.hibernateTemplate = new HibernateTemplate(sf);
}

public void delete(TblUser user) {
hibernateTemplate.delete(user);
}

public TblUser find(Integer id) {
return (TblUser) hibernateTemplate.get(TblUser.class, id);
}

public void insert(TblUser user) {
hibernateTemplate.save(user);
}

public void update(TblUser user) {
hibernateTemplate.update(user);
}
}

spring bean設定檔透過DataSource設定SessionFactory物件並"注入"到UserDAO物件


Demo程式
package idv.muchu.test.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class SpringHibernateDemo {
/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext("dao-config.xml");
IUserDAO userDAO = (IUserDAO)context.getBean("userDAO");
TblUser user = new TblUser();
user.setAge(15);
user.setName("mars");
userDAO.insert(user); //新增
TblUser mark = userDAO.find(1); //查詢
System.out.println("mark's age:" + mark.getAge());
mark.setAge(30);
userDAO.update(mark); //修改
System.out.println("mark's age:" + mark.getAge());
userDAO.delete(mark); //刪除
}
}

2008年7月26日 星期六

hibernate LazyInitializationException

hibernate 3 預設有啟動LazyInitialization
在Session.
load(Class theClass,Serializable id)時
還不會將資料庫中的資料載入到物件中,一直要到物件屬性被改變時才會載入,
但修改物件時Session必須處於open狀態,否則會丟出LazyInitializationException
如果在Session關閉後才要使用物件則可以使用Hibernate.initialize(rec_obj);
來先行載入資料庫的資料到物件中
如:
Session session = HibernateUtil.getSessionFactory().openSession();
User user = (User) session.load(User.class, new Integer(1));
Hibernate.initialize(user);

session.close();

Hibernate的Session物件有兩個:
org.hibernate.Session 及 org.hibernate.classic.Session
classic版是為了相容於Hibernate 2.x的物件,已半棄用,建議新的開發要使用
org.hibernate.Session

使用Hql進行查詢時可以一次查詢多個資料表的物件,只要把資料TO物件extends/implements同一個class/interface即可,如:
Man implements Human ...
Woman implements Human ...
同時查找Man 及 Woman的資料:
Session.find("from Human ...");

透過ThreadLocal讓多個Thread各自管理自己的Session物件範例:
public class HibernateUtil {
public static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException {
Session s = session.get();
if(s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = session.get();
if(s != null) {
s.close();
}
session.set(null);
}
}

2008年7月22日 星期二

debian下使用zhcon

沒有做任何設定直接執行zhcon會造成畫面錯亂當機的情型
只要在/boot/grub/menu.list檔案的最下面的kernel字串後加上vga=791再重新開機就可以了

title Debian GNU/Linux, kernel 2.6.18-4-k7
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-4-k7 root=/dev/hdd1 ro vga=791
initrd /boot/initrd.img-2.6.18-4-k7
savedefault

vga其他顯示模示代碼如下:
Screen 640x480 800x600 1024x768 1280x1024 1600x1200
Colors --------------------------- -------------------------------------------
256 | 769 771 773 775 796
32,768 | 784 787 790 793 797
65,536 | 785 788 791 794 798
16.8M | 786 789 792 795 799

2008年7月21日 星期一

virtualbox

下載:
http://www.virtualbox.org/wiki/Downloads

安裝:
#dpkg --install virtualbox_1.6.2-31466_Debian_etch_i386.deb

加入群組:
#usermod -G vboxusers -a muchu1983

設定Host key:
檔案 -> 偏好設定 -> 輸入

複製一份.vdi硬體檔:
VBoxManage clonevdi /mnt/hdb1/debian-vbox.vdi /mnt/hdb1/debian-vbox-v2.vdi
複製完成即可再建立一台新的虛擬機來使用新的硬碟檔

虛擬機之間的網路互通:
啟用虛擬機的新網卡eth1並設定為掛附到內部網路及給定相同的network name
再分別設定各別虛擬機的eth1 ip (例:192.168.1.100 & 192.168.1.200)
#ifconfig eth1 192.168.1.100

主端分享資料夾給客端電腦:
需先安裝客端額外功能 -
#sh /media/cdrom0/VboxLinuxAdditions.run
在主端vbox程式的 設定值 -> 分享資料夾 -> 加入新的分享資料夾
啟動客端電腦,mount 分享資料夾
#mount -t vboxsf share /mnt/share

2008年7月12日 星期六

java Thread wait() notify() notifyAll() 運作

.使用wait()、notify()、notifyAll()方法前,執行緒必需先獲得物
件鎖,也就是說,執行緒必需是處理物件的synchronized區段
中,該執行緒是處於Running狀態的。

.當執行緒在物件的synchronized區段中碰到了wait()方法,該執
行緒就必需釋放出該物件的Lock,並進入該物件的wait pool中
等待。

.執行的過程式可能會有多個執行緒因為碰到wait()方法而在wait
pool中等待。

..此時。如果某個使用該物件的執行緒碰到了notify()方法,那麼在
物件的wait pool中第一個碰到了wait()方法的執行緒就會被移到該
物件的lock pool中繼續等待取得物件鎖。

..而如果某個使用該物件的執行緒碰到了notifyAll()方法,那麼在物
件的wait pool中所有的執行緒就會被移到該物件的lock pool中,
而優先權最高的執行緒會先取得物件鎖。

2008年7月8日 星期二

Jaas Login module flag意義

      1) Required     - The LoginModule is required to succeed.
If it succeeds or fails, authentication still continues
to proceed down the LoginModule list.

此LoginModule一定要驗証成功整個Login程序才會通過,無論驗証成敗,均會繼續
進行下一個LoginModule驗証。

2) Requisite - The LoginModule is required to succeed.
If it succeeds, authentication continues down the
LoginModule list. If it fails,
control immediately returns to the application
(authentication does not proceed down the
LoginModule list).

此LoginModule一定要驗証成功整個Login程序才會通過,驗証成功,則繼續進行
下一個LoginModule驗証,若驗証失敗,則不繼續進行下一個LoginModule驗証,
驗証程式完成。
3) Sufficient - The LoginModule is not required to
succeed. If it does succeed, control immediately
returns to the application (authentication does not
proceed down the LoginModule list).
If it fails, authentication continues down the
LoginModule list.
此LoginModule不一定要驗証成功,若驗証成功,則繼續進行則不繼續進行下一個
LoginModule驗証,若驗証失敗,則繼續進行下一個LoginModule驗証,
4) Optional - The LoginModule is not required to
succeed. If it succeeds or fails,
authentication still continues to proceed down the
LoginModule list.
此LoginModule不一定要驗証成功,無論驗証成敗,均會進行下一個LoginModule驗証。

2008年7月6日 星期日

XFce4快捷鍵記錄檔位置

XFce4 的預設快捷鍵位置在
/usr/share/themes/Default/xfwm4/keythemerc

2008年6月30日 星期一

xfce新增圖示主題

先到http://www.xfce-look.org/下載想要的圖示
例如XXX.tar.gz
移到~/icons/並解壓縮開來 (如果沒有icons資料夾就自行mkdir)
~/icons/XXX/
即可在 Xfce設定管理程式 -> 使用者介面 -> 圖示主題 下
看到剛新增的圖示主題

2008年6月20日 星期五

JCR研究:jackrabbit

一。使用 svn checkout出jackrabbit的src code
svn co http://svn.apache.org/repos/asf/jackrabbit/trunk jackrabbit
二。進到checkout出來的根目錄,使用 maven 進行build
mvn install
三。完成建置後 maven 會在家目錄產生jackrabbit的jars:
${home}\.maven\repository\org.apache.jackrabbit\jars\jackrabbit-*-SNAPSHOT.jar

四。在classpath引入必要的jars
jcr的有:
jcr-1.0.jar
jackrabbit的有:
jackrabbit-api-1.5-SNAPSHOT.jar
jackrabbit-core-1.5-SNAPSHOT.jar
jackrabbit-jcr-commons-1.5-SNAPSHOT.jar
jackrabbit-spi-1.5-SNAPSHOT.jar
jackrabbit-spi-commons-1.5-SNAPSHOT.jar
jackrabbit-text-extractors-1.5-SNAPSHOT.jar
slf4j的有:
slf4j-api-1.3.0.jar
slf4j-simple-1.5.2.jar
其他:
commons-collections-3.1.jar
concurrent-1.3.4.jar
derby-10.2.1.6.jar
commons-io-1.4.jar
lucene-core-2.2.0.jar
PDFBox-0.7.3.jar
poi-3.0.2-FINAL-20080204.jar
tm-extractors-0.4.jar
poi-scratchpad-3.0.2-FINAL-20080204.jar
poi-contrib-3.0.2-FINAL-20080204.jar

五。第一個登入程式FirstHop
public static void main(String[] args) throws Exception {
// local repository
// System.setProperty("org.apache.jackrabbit.repository.home", "D:/jackrabbit-repos");
// Repository repository = new TransientRepository();
// http rmi repository
Repository repository = new URLRemoteRepository("http://192.168.1.57:-1/jackrabbit-webapp-1.5-SNAPSHOT/rmi");
// rmi repository
// Repository repository = new RMIRemoteRepository("//localhost/jackrabbit.repository");
Session session = repository.login(new SimpleCredentials("transtep", "".toCharArray()));
try {
String user = session.getUserID();
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
System.out.println("Logged in as " + user + " to a " + name + " repository.");
Workspace workspace = session.getWorkspace();
Node rootNode = session.getRootNode();
// // 儲存資料
workspace.getNamespaceRegistry().registerNamespace("xsignage", "http://www.transtep.com/xsignage/1.0");
Node imageNode = rootNode.addNode("xsignage:image");
imageNode.setProperty("xsignage:type", "圖片");
imageNode.setProperty("xsignage:read", true);
imageNode.setProperty("xsignage:write", true);
Node jpegImage = imageNode.addNode("xsignage:jpeg");
jpegImage.setProperty("xsignage:yuffie", new FileInputStream(new File("./尤菲.jpg")));
session.save();
// 取出資料
Node imageNode2 = rootNode.getNode("xsignage:image");
System.out.println("type: " + imageNode2.getProperty("xsignage:type").getString());
System.out.println("read: " + imageNode2.getProperty("xsignage:read").getString());
System.out.println("write: " + imageNode2.getProperty("xsignage:write").getString());
Node jpegImage2 = imageNode2.getNode("xsignage:jpeg");
InputStream ins = jpegImage2.getProperty("xsignage:yuffie").getStream();
FileOutputStream pos = new FileOutputStream("./yuffie.jpg");
int read = -1;
while ((read = ins.read()) != -1) {
pos.write(read);
}
} finally {
session.logout();
}
}

2008年6月19日 星期四

從servlet上下載檔案的寫法

public void execute(HttpServletRequest req, HttpServletResponse res) {
PrintWriter out = null;
// 取得輸入參數
String did = req.getParameter("did");
String filename = req.getParameter("filename");
if (did == null) {// 無did
out.print("公文文號(did)為空值");
return;
} else if (filename == null) {// 無filename
out.print("檔案名稱(filename)為空值");
return;
}
// Dao
DocAttDao docAttDao = DocAttDao.getInstance();
TblDocattId id = new TblDocattId(Integer.parseInt(did), filename);
TblDocatt tblDocAtt = new TblDocatt(id);
tblDocAtt = (TblDocatt) docAttDao.get(tblDocAtt);
try {
res.setHeader("Pragma", ""); // HTTP 1.0
res.setHeader("Cache-Control", ""); // HTTP 1.1
if (tblDocAtt != null) {
String fileurl = tblDocAtt.getUrl();
String agent = req.getHeader("User-Agent");
if (agent.indexOf("MSIE") > -1) {
// encoding filename for IE
filename = URLEncoder.encode(filename, "utf-8");
} else {
filename = new BCodec().encode(filename);
}
// 下載檔案
res.setContentType("application/octet-stream;charset=utf-8");
res.setHeader("Content-Disposition", "attachment; filename = " + filename);
// 打開指定文件的stream
File file = new File(fileurl);
FileInputStream bis = new FileInputStream(file);
OutputStream bos = res.getOutputStream();
byte[] buff = new byte[1024];
int readCount = 0;
readCount = bis.read(buff);
while (readCount != -1) {
bos.write(buff, 0, readCount);
readCount = bis.read(buff);
}
if (bis != null)
bis.close();
if (bos != null)
bos.close();
} else {
res.getWriter().print("無此檔案");
}
} catch (Exception e) {
e.printStackTrace();
}

}

maven安裝

1.下載maven
2.解壓縮
3.新增M2_HOME環境變數到解壓縮目錄
4.新增M2_HOME\bin 路徑到Path環境變數
5.在console下運行svn --version檢查是否安裝成功

2008年6月18日 星期三

DTO DAO 物件

[轉載]http://www.javaworld.com.tw/jute/post/view?bid=44&id=85388&tpg=1&ppg=1&sty=3&age=0
DTO:Data Transfer Object
DAO:Data Access Object

由名稱來猜,DTO 就是類似用來作資料傳輸的 Java 類別,個人看過的寫法是寫成有 getter/setter 的 JavaBean
透過 DTO 可以很方便地將資料跨 tier 傳遞,且完整封裝

比如:

Servlet 產生 DTO 物件,將 Client 端輸入的資料透過 setter 寫進 DTO,呼叫企業邏輯處理元件時將 DTO 物件當成參數向後端傳遞

而後端的企業邏輯處理元件就可以透過 DTO 的 getter 取出所需要的資料,並進行運算
若後端運算完畢之後必須要將處理結果傳回 Client 端,也是透過 DTO 的 setter 設定新的值,並回傳給 Servlet

這整個過程當中都只需要 DTO 物件一個參數,像坐捷運一樣從前端一路傳到後端
不需要串一堆參數傳來傳去的,若後端須新增參數時也只需要更改 DTO 及用到相關 getter/setter 的程式碼即可,大部分程式都不需要變動


至於 DAO,是跟資料庫存取有關的類別
我看過的做法是將所有操作資料庫的動作都萃取集中起來寫成特定的公用類別
程式中若需要存取資料庫時一律透過 DAO 處理

這樣的好處是,當資料庫更換時,僅需抽換 DAO 即可,其他程式可以繼續使用,可以將應用程式與資料庫的耦合度降低

linux 下使用藍芽傳輸

1.安裝kdebluetooth套件
2.確定相關服務已啟動
sudo /etc/init.d/dbus start
sudo /etc/init.d/bluetooth start
3.啟動kbluetoothd
4.使用kbtobexclient程式傳送資料到手機上

ps.手機 -> pc 尚未試成功

2008年6月13日 星期五

java 的 enum

透過java列舉型別可以很容易的表達一些常數性質的資料
public enum ROLE {
CHANNEL, PLAYLIST, TERMINAL, CONTENT;
};
而使用列舉型別的values()方法可以取出所有的列舉常數陣列
public static void main(String[] args) {
for(ROLE role : ROLE.values()){
System.out.println(role);
}
}
同時列舉型別也可以自定所屬的成員和方法,更可以override toString()方法來自定常數的表示
public enum ROLE {
CHANNEL, PLAYLIST, TERMINAL, CONTENT;
private Integer id;
private String name;

public void setId(Integer id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return name + "(" + id + ")";
}
};

使用列舉型自定的方法:
public static void main(String[] args) {
for(ROLE role : ROLE.values()){
role.setId(4);
role.setName("頻道四號");
System.out.println(role);
}
}

2008年6月2日 星期一

使用URL post XML給server端的servlet

URL urlobj = new URL(servletUrl);
HttpURLConnection urlconn = (HttpURLConnection) urlobj.openConnection();
urlconn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8"); //<--注意編碼設定
urlconn.setDoOutput(true);
urlconn.setDoInput(true);
urlconn.setRequestMethod("POST");
PrintWriter urlpw = new PrintWriter(new OutputStreamWriter(new DataOutputStream(urlconn.getOutputStream()),"UTF-8")); //<--注意編碼設定
JAXBAgent jaxbAgent = new JAXBAgent();
urlpw.print(jaxbAgent.marshal(reqObj));
urlpw.flush();
urlpw.close();
BufferedReader urlbr = new BufferedReader(new InputStreamReader(new DataInputStream(urlconn.getInputStream()),"UTF-8")); //<--注意編碼設定
StringBuffer strbuf = new StringBuffer();
String line = null;
while (null != (line = urlbr.readLine())) {
strbuf.append(line);
}
Object resObj = jaxbAgent.unmarshal(pkgName, strbuf.toString());


//server端的Servlet也要使用
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
//來設定編碼,才不會有中文字亂碼的問題。