星期一, 7月 17, 2006

JBoss EJB3(HelloWorld)備忘記

EJB (Enterprise JavaBeans) 是 J2EE 的核心組件,
主要目的是提供開發員一個企業基建架構, 使其更容易開發實用的應用程式.
由於這個目的在 EJB2 時徹底失敗. 更加重開發員的工作.
故 EJB3 的主要目標是修正及改良 EJB2 的問題. 期望能夠真正簡化開發員的工作.


這裡並不打算介紹 EJB2 的不足及 EJB3 增強的特性. 亦不打算對 EJB 作簡介.
因為這些在網路上很容易找到相關的教學. 亦不是這編文章的目的.
這編備忘記主要是實作 Stateless Session Beans HelloWorld.


JBoss 是一個開源的 J2EE 服務器, JBoss 4 版本之後支持 EJB3 ,
當其他 J2EE 應用系統需要重啟動才能檢測發佈時, JBoss 2.0 版本後便提供自動發佈檢測,
這是第一個 J2EE 應用系統提供自動發佈及重發佈檢測. JBoss 3.0 後更增強此功能,
加入自動追蹤與發佈相依的服務. 這特性尤其適合要求高的電信系統.


只要簡單設定 JBoss URL, 就能夠從任何的遠端網絡啟動服務,
這可使得單獨的服務器更容易集中管理分佈式的 JBoss 系統.


JBoss 提供以下遠端呼叫協定:
Fast Socket
Fast Socket over HTTP (HTTP tunneling)
IIOP
JMS
SOAP


備忘記開始:
[1]
安裝 jdk 5
[2] 安裝 JBoss EJB3
[3] 第一次啟動 JBoss
[4] 安裝 Eclipse WTP
[5] 安裝 JBoss IDE
[6] 使用 Eclipse 建立第一個 EJB3 Project [ 即 HelloWorld ]
[7] 建立 HelloWorld Stateless Session Bean 及 Local, Remote interfaces
[8] 建立客戶端測試程式
[9] 使用 ANT 建立 EJB-JAR 並執行 Client 程式


這..這.. 簡稱它為 JBoss EJB3 HelloWorld 9 步曲.


[1] 安裝 jdk 5:
下載 jdk-1_5_0_07-nb-5_0-win-ml.exe
http://java.sun.com/j2se/1.5.0/download-netbeans.html
安裝至 D:\jdk1.5.0_07
新增環境變數 JAVA_HOME=D:\jdk1.5.0_07
D:\jdk1.5.0_07\bin 加入至 PATH 中
D:\jdk1.5.0_07\lib\dt.jar 及 D:\jdk1.5.0_07\lib\tools.jar 加入至 CLASSPATH 中
執行 D:\>java -version
輸出 java version "1.5.0_07" 表示安裝成功.


[2] 安裝 JBoss EJB3:
這裡為了簡化備忘過程, 故使用網上直接執行安裝,
[ 亦可選擇下載 JBoss AS 包 及 EJB3 包安裝 ]
http://jboss.sourceforge.net/jnlp/jboss-4.0.4.GA-installer.jnlp
http://labs.jboss.com/portal/jbossas/download
安裝至 D:\jboss
安裝時必需選擇 ejb3-clustered [ 這很重要 ], 如下圖所示


安裝完後, 新增環境變數 JBOSS_HOME=D:\jboss
D:\jboss\bin 加入至 PATH 中

JBOSS 目錄結構如下所示:
D:\jboss
-- bin
-- client
'-- docs
+-- dtd
-- lib
`-- server
+-- all
+-- mininal
`-- default
+-- conf
+-- data
+-- deploy
-- lib
-- log
+-- tmp
+-- work


bin : JBoss 開關 Scripts.
client : 與JBoss通訊使用的客戶端 libraries ( JARs )
docs : 設定文檔樣本. ( 如資訊庫設定文檔樣本等 )
docs/dtd : JBoss 不同XML 的 Document Type Definitions (DTDs) 檔.
lib : JBoss 啟動時, 會讀取放在這裡被不同配置共享的 libraries.
server : 存放 JBoss 不同配置檔案.
server/default : JBoss 預設的配置檔案.
server/default/conf : JBoss 配置檔案.
server/default/data : JBoss 資料庫檔案.
server/default/deploy : JBoss 自動發佈檢測目錄. ( EBJ-JARs, WARs 及 EARs 放下去, JBoss 會自動檢測 )
server/default/lib : JBoss 啟動此配置目錄時, 會讀取這裡的 libraries.
server/default/log : 存放 JBoss 記錄(日誌)檔案.
server/default/tmp : 存放 JBoss 暫存檔案.
server/default/work : 存放 JBoss 編譯後的java byte code.


[3] 第一次啟動 JBoss:
run.bat -c config-name
[ 這裡使用 ejb3-clustered 安裝, 只能選其中一種, 預設是 default ]
[ config-name 為 mininal , 啟動最小配置模式 ]
[ config-name 為 default , 啟動預設配置模式, 不加任何參數亦是此預設模式 ]
[ config-name 為 all , 啟動全部配置模式 ]


使用預設配置模式, 執行
D:\jboss\bin>run.bat
網頁輸入 http://localhost:8080/ ,出現如下畫面即安裝成功:


如果分開安裝 JBoss AS 及 EJB3 就可以打開下面連結. 網上安裝則沒有此功能.
點擊上圖的 JBoss Web Console 進入JBoss Web控制介面. 如下圖所示:


[4] 安裝 Eclipse WTP:

下載 wtp-all-in-one-sdk-R-1.5.0-200606281455-win32.zip
http://www.eclipse.org/webtools/
http://www.eclipse.org/downloads/download.php?file=/webtools/downloads/drops/R-1.5.0-200606281455/wtp-all-in-one-sdk-R-1.5.0-200606281455-win32.zip
解壓至 D:\eclipse_wtp


[5] 安裝 JBoss IDE:
Eclipse:Help -> Software Updates -> Find and Install -> Search for new features to install
按 New Remote Site
Name: JBOSS IDE
URL: http://download.jboss.org/jbosside/updates/stable
選擇最新的版本然後安裝.


[6] 使用 Eclipse 建立第一個 EJB3 Project [ 即 HelloWorld ]:
Eclipse: File -> New -> Other -> EJB 3.0 -> EJB 3.0 Project
Project Name: HelloWorldEJB3 -> Next
選擇 Create a JBoss configuration
打開後右鍵點選 JBoss 4.0.x -> new
Name : jboss_configuration
JBoss 4.0.x Home Directory : D:\jboss
Server Configuration:default
這裡 JDK 面版裡的 Runtime JRE 要設定 jdk 5 的.
然後按 Apply 及 Close, [ 這裡如果按 Debug 就會在 Eclipse 裡啟動 JBoss ]
設定如下圖所示:

然後按 Finish. HelloWorldEJB3 project 就會成功建立.


[7] 建立 HelloWorld Stateless Session Bean 及 Local, Remote interfaces:
/*----------------------- HelloWorld.java ---------------------*/
package ejb3.joeyta.sessions;
public interface HelloWorld {
public String echo(String msg);
}

/*----------------------- HelloWorld.java ---------------------*/


/*----------------------- HelloWorldLocal.java ----------------*/
package ejb3.joeyta.sessions;
import javax.ejb.Local;
@Local
public interface HelloWorldLocal extends HelloWorld {
}

/*----------------------- HelloWorldLocal.java ----------------*/


/*----------------------- HelloWorldRemote.java ---------------*/
package ejb3.joeyta.sessions;
import javax.ejb.Remote;
@Remote
public interface HelloWorldRemote extends HelloWorld {
}

/*----------------------- HelloWorldRemote.java ---------------*/


/*----------------------- HelloWorldBean.java -----------------*/
package ejb3.joeyta.sessions;
import javax.ejb.Stateless;
@Stateless
public class HelloWorldBean implements HelloWorldRemote, HelloWorldLocal {
public String echo(String msg) {
System.out.println("Joeyta try Hello World.");
return msg;
}
}

/*----------------------- HelloWorldBean.java -----------------*/


[8] 建立客戶端測試程式:
/*----------------------- HelloWorldClient.java ---------------*/
package ejb3.joeyta.clients;
import javax.naming.InitialContext;
import ejb3.joeyta.sessions.HelloWorld;
public class HelloWorldClient
{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
HelloWorld helloWorld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");
System.out.println(helloWorld.echo("Hello World, Joeyta"));
}
}

/*----------------------- HelloWorldClient.java ---------------*/

目結構如下所示:


[9] 使用 ANT 建立 EJB-JAR 並執行 Client 程式:
在 HelloWorldEJB3 project 下建立 build.xml [ ANT build File ]
內容如下:
<!------------------------- build.xml ------------------------------->
<?xml version="1.0"?>
<project name="JBoss" default="run.HelloWorldClient" basedir=".">
<property environment="env" />
<property name="jboss.home" value="${env.JBOSS_HOME}" />
<property name="classes.dir" value="bin" />


<path id="classpath">
<fileset dir="${jboss.home}/client">
<include name="**/*.jar" />
</fileset>
<pathelement location="${classes.dir}" />
</path>

<target name="clean">
<delete file="${basedir}/HelloWorld.jar" />
<delete file="${jboss.home}/server/default/deploy/HelloWorld.jar" />
</target>

<target name="ejbjar" depends="clean">
<jar jarfile="HelloWorld.jar">
<fileset dir="${classes.dir}">
<include name="ejb3/joeyta/sessions/*.class" />
</fileset>
</jar>
<copy file="HelloWorld.jar " todir="${jboss.home}/server/default/deploy" />
</target>


<target name="run.HelloWorldClient" depends="ejbjar">
<java classname="ejb3.joeyta.clients.HelloWorldClient" fork="yes" dir=".">
<classpath refid="classpath" />
</java>
</target>
</project>
<!------------------------- build.xml ------------------------------->


點選 build -> Run As -> 2. Ant Build
Eclipse Console 輸出為
Hello World, Joeyta
如下圖所示:


JBoss Console 輸出為
Joeyta try Hello World.
如下圖所示:


這次 JBoss EJB3 HelloWorld 教學己到了終點.
正籌備 EJB3 Statefull Session Bean, Entity Bean , Transaction, Message Driven Bean 教學.
不過我相信有了上面這個起點, 學下去也相當容易.

JBoss EJB3(Stateful Session Beans)備忘記
http://blog.matrix.org.cn/page/joeyta?entry=jboss_ejb3_stateful_session_beans

JBoss EJB3(Entity Beans)備忘記
http://blog.matrix.org.cn/page/joeyta?entry=jboss_ejb3_entity_beans_%E5%82%99%E5%BF%98%E8%A8%98

如果想更了解 EJB3 , 這裡有免費的 Mastering EJB 3.0. 下載.
http://www.theserverside.com/tt/books/wiley/masteringEJB3/index.tss



星期四, 7月 13, 2006

Apache Maven(Project Management)備忘記

Maven 為 Apache 一項開源的軟件項目管理工具計劃,
它建基於項目物件模型(Project Object Model, POM)上,
就能一併對項目進行編譯, 測試, 發佈, 並能產生文檔及報告.


Maven 主要的目的是縮短開發員在開發過程對項目管理所需的時間.
使用 Maven, 只需要使用 Ant 的一半功夫,
就能自動建立更彈性的 project.

以下是 Maven 的目標:
(1) 使項目開發過程更輕鬆.
(2) 提供統一開發系統.
(3) 提供項目品質資訊.
(4) 提供更容易開發的指南.
(5) 允許輕鬆更新功能.



開始進行備忘:
[1] 安裝 Maven
[2] 建立第一個 Maven 管理的 porject
[3] 使用 Maven 對 Project 進行編譯
[4] 使用 Maven 對 Project 進行單元測試
[5] 使用 Maven 產生 Project Jar file
[6] 使用 Maven 將 project 發佈至服務容器


[1] 安裝 Maven
下載 maven-2.0.4-bin.zip
http://www.apache.org/dyn/closer.cgi/maven/binaries/maven-2.0.4-bin.zip
http://apache.mirrors.versehost.com/maven/binaries/maven-2.0.4-bin.zip


解壓至 D:\maven 下
將 D:\maven\bin 加入環境變數 PATH 裡, 方面日後隨處運行.
執行 D:\>mvn --version
出現 Maven version: 2.0.4 即表示安裝正常.


使用 unix like 系統的同志可參考官方安裝文檔:
http://maven.apache.org/download.html#Installation


[2] 建立第一個 Maven 管理的 porject

執行下面指令建立 project 基礎架構(由於需要下載plugin Jars, 必須連結Internet):
D:\>mvn archetype:create -DgroupId=test.joeyta.app -DartifactId=my-app
就會產生 D:\my-app 目錄.
test.joeyta.app 為 project 的 unique identifier.
my-app 為將來 project 產生檔案的基名.
輸出訊息如下所示:
[INFO] ------------------------------------------------
[INFO] Using following parameters for creating Archetype: maven-archetype-quickstart:RELEASE
[INFO] ------------------------------------------------
[INFO] Parameter: groupId, Value: test.joeyta.app
[INFO] Parameter: packageName, Value: test.joeyta.app
[INFO] Parameter: basedir, Value: D:[INFO] Parameter: package, Value: test.joeyta.app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: artifactId, Value: my-app
[INFO] ******* End of debug info from resources from generated POM ********
[INFO] Archetype created in dir: D:\my-app
[INFO] ------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------
[INFO] Total time: 1 minute 39 seconds
[INFO] Finished at: Thu Jul 13 11:21:31 GMT+08:00 2006
[INFO] Final Memory: 4M/8M
[INFO] ------------------------------------------------



產生的 Maven project 目錄結構如下:
D:\my-app
-- pom.xml
`-- src
-- main
`-- java
`-- com
`-- mycompany
`-- app
`-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java


Maven 會產生兩個 sample files ( App.java 及 AppTest.java ),
用作 Maven 作 demo 測試.
------------------ App.java ------------------
package test.joeyta.app;
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}

------------------ App.java ------------------

------------------ AppTest.java ------------------
package test.joeyta.app;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class AppTest extends TestCase
{
public AppTest( String testName )
{
super( testName );
}
public static Test suite()
{
return new TestSuite( AppTest.class );
}
public void testApp()
{
assertTrue( true );
}
}
------------------ AppTest.java ------------------

檢視 pom.xml POM設定檔:

pom.xml (Project Object Model) 描述 Maven 工作基本單元,
這個檔案包含 Maven 需要建立 project 時的資訊及詳細設定.
內容為:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test.joeyta.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>


project -- Maven pom.xml files 的 root element.
modelVersion -- POM 的版本號.
groupId -- project 的 unique identifier.
artifactId -- project 的基名, 用來產生檔案所需的基名. 如 myapp-1.0.jar.
packaging -- 產生的 package 類型, (e.g. JAR, WAR, EAR, etc.)
version -- project 的版本號.
name -- project 的顯示名稱.
url -- project 的網址.



[3] 使用 Maven 對 Project 進行編譯


進入目錄 D:\my-app ( 必須在 pom.xml 的根目錄編譯 )
執行指令
D:\my-app>mvn compile
就會對 project 進行編譯,
在第一次執行編譯指令時需要從網上下載一些plugin Jars, 之後執行則不用下載.


輸出訊息如下所示:
[INFO] [compiler:compile]
Compiling 1 source file to D:\my-app\target\classes
[INFO] -----------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] -----------------------------------------------------
[INFO] Total time: 20 seconds
[INFO] Finished at: Thu Jul 13 12:25:49 GMT+08:00 2006
[INFO] Final Memory: 3M/7M
[INFO] -----------------------------------------------------


就會產生 D:\my-app\target 這個目錄.
目錄結構如下所示:
D:\my-app
-- pom.xml
-- src
`-- target
-- classes
`-- test
`-- joeyta
`-- app
`-- App.class


如果使用 Ant 作同樣的事情, 需要編寫 build file 如下所示:
<project default="compile">
<property name="classesdir=" value="..." />
<property name="libdir" value="..." />
<target name="compile">
<mkdir dir="${classesdir}" />
<javac destdir="${classesdir}">
<src>
<pathelement location="src/main/java" />
</src>
<classpath>
<fileset dir="${libdir}">
<include name="*.jar" />
</fileset>
</classpath>
</javac>
</target>
</project>


由上面 Maven POM file 及 Ant Build file的比較,
就能明顯看出 Maven 的 POM file 管理 project 是如此的輕鬆.



[4] 使用 Maven 對 Project 進行單元測試


執行指令
D:\my-app>mvn test
就會對 project 進行單元測試,


輸出訊息如下所示:
[INFO] Surefire report directory: D:\my-app\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running test.joeyta.app.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.11 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] -----------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] -----------------------------------------------------
[INFO] Total time: 28 seconds
[INFO] Finished at: Thu Jul 13 12:41:57 GMT+08:00 2006
[INFO] Final Memory: 3M/6M
[INFO] -----------------------------------------------------


就會產生兩個目錄,
D:\my-app\target\surefire-reports
D:\my-app\target\test-classes
目錄結構如下所示:
D:\my-app
-- pom.xml
-- src
`-- target
-- classes
-- surefire-reports
`-- test.joeyta.app.AppTest.txt
`-- TEST-test.joeyta.app.AppTest.xml
-- test-classes
`-- test
`-- joeyta
`-- app
`-- AppTest.class


如果只想對 單元測試進行編譯而不需要測試, 則下執行以下指念
D:\my-app>mvn test-compile



[5] 使用 Maven 產生 Project Jar file


執行指令
D:\my-app>mvn package
就會對 project 進行封裝,


輸出訊息如下所示:
[INFO] [jar:jar]
[INFO] Building jar: D:\my-app\target\my-app-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------
[INFO] Total time: 12 seconds
[INFO] Finished at: Thu Jul 13 12:53:03 GMT+08:00 2006
[INFO] Final Memory: 3M/7M
[INFO] ------------------------------------------------


就會產生 D:\my-app\target\my-app-1.0-SNAPSHOT.jar


目錄結構如下所示:
D:\my-app
-- pom.xml
-- src
`-- target
-- classes
-- surefire-reports
-- test-classes
-- exported-pom.xml
-- my-app-1.0-SNAPSHOT.jar

由於在 pom.xml 設定了 packaging 為 jar, 故產生的為 *.jar



[6] 使用 Maven 將 project 發佈至服務容器


執行指令
D:\my-app>mvn install
就會對 project 進行編譯, 單元測試, 封裝, 及 發佈至服務容器.


輸出訊息如下所示:
[INFO] [jar:jar]
[INFO] Building jar: D:\my-app\target\my-app-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing D:\my-app\target\my-app-1.0-SNAPSHOT.jar to C:\Documents and Settings\joeyta
\.m2\repository\test\joeyta\app\my-app\1.0-SNAPSHOT\my-app-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------
[INFO] Total time: 6 seconds
[INFO] Finished at: Thu Jul 13 13:07:54 GMT+08:00 2006
[INFO] Final Memory: 4M/8M
[INFO] ------------------------------------------------


這裡由於沒有設定發佈的服務器,
故預設發佈至 用戶目錄下的 ( ~/.m2/repository ),
Windows 下的 C:\Documents and Settings\joeyta\.m2\repository


可以執行指令 D:\my-app>mvn site 建立 Maven web site 於 D:\my-app\target\site 目錄下
可以執行指令 D:\my-app>mvn clean , 就會清除 D:\my-app\target 目錄.


由於這編文章只是入門備忘記, 故還有很多 Maven 的功能沒有提及,
官方有詳盡的教學可參考:
http://maven.apache.org/guides/getting-started/index.html

星期二, 7月 11, 2006

Apache Axis2(java web service)備忘記:

Axis (Apache Extensible Interaction System) 為 Apache web service 開源計劃,
Web Service 功能為提供兩個遠端程式互相溝通,
其溝通使用的協定為 SOAP (Simple Object Access Protocol).


Axis2 增強舊版 Axis 的效能, 加入模組化及使其更面向 XML,
Axis2 設計成更容易嵌入 如 security 及其他可靠模組. 官方網站有更詳細的說明.


Web service 其運作原理如下 (下圖引用官方網站簡介):
+--------------------------------------+
web service registry
(aka service broker)
(UDDI)
+--------------------------------------+
^ ^

(2) (1)
(the client (the web service
WSDL finds the WSDL provider publishes
service the web service)
they want)

v v
+-----------+ +-----------+
service <--SOAP--> service
requestor provider
+-----------+ (3) +-----------+


(1) 發佈 Web Service.
(2) 尋找已發佈的 Web Service.
(3) 通過 SOAP 互相溝通.
(1) 及 (2) 均為 optional.


WSDL -- Web Services description Language. WSDL 描述 web service 的功能.
UDDI -- Universal Description, Discovery and Integration. 發佈 web service 的協定.
SOAP -- Simple Object Access Protocol. SOAP 通過 HTTP 傳送 XML message.

下面將對Axis2 作最簡單的實作 Hello World.

開始備忘記:


安裝Tomcat 5.x. ( 亦可選擇使用 Axis2 提供的 SimpleHTTPServer )
http://apache.seekmeup.com/tomcat/tomcat-5/v5.5.17/bin/apache-tomcat-5.5.17.exe
下載後直接安裝到目錄 D:\tomcat
由於本人電腦安裝了幾個 tomcat , 故把 port設為8083 ( 預設port是8080 )
http://localhost:8083/ 測試是否安裝成功.


下載 axis2-std-1.0-bin.zip 並解壓到 D:\axis2
http://ws.apache.org/axis2/download.cgi
http://www.reverse.net/pub/apache/ws/axis2/1_0/axis2-std-1.0-bin.zip


設定系統環境變數 AXIS2_HOME=D:\axis2


下載 axis2.war :
http://ws.apache.org/axis2/download.cgi
http://mirrors.isc.org/pub/apache/ws/axis2/1_0/axis2.war


將 axis2.war 放進 D:\tomcat\webapps 目錄下.
啟動 tomcat 就會自動產生 D:\tomcat\webapps\axis2


瀏覽 http://localhost:8083/axis2/ , 畫面如下:


Services -- 觀看已 desploy 的 web services.
Validate -- 確定系統是否缺少 必要的library.
Administration -- axis2 管理控制台.


點選 Administration 連結進入控制台登入介面, 輸入
User : admin
Password : axis2

上面用戶及密碼為預設值,
可到 D:\tomcat\webapps\axis2\WEB-INF\conf\axis2.xml 修改 用戶名及密碼.
<parameter name="userName" locked="false">admin</parameter>
<parameter name="password" locked="false">axis2</parameter>


登入後畫面如下:



安裝 Axis2 Service Archive & Code Generator Eclipse plug in(使用上發生問題):
下載 Eclipse WTP:
http://www.eclipse.org/webtools/
http://www.eclipse.org/downloads/download.php?file=/webtools/downloads/drops/R-1.5.0-200606281455/wtp-all-in-one-sdk-R-1.5.0-200606281455-win32.zip
解壓至 D:\eclipse_wtp


下載 Axis2_Service_Archiver.zip 及 Axis2_Code_Generator.zip
http://ws.apache.org/axis2/tools/index.html
http://mirrors.combose.com/apache/ws/axis2/tools/1_0/Axis2_Service_Archiver.zip
http://apache.edgescape.com/ws/axis2/tools/1_0/Axis2_Code_Generator.zip
解壓後 將 plugins 目錄複製至 D:\eclipse_wtp\plugins


測試 Axis2 Web Service:
編寫 Axis2 Web Service 主要需要4個步驟:
[1] 編寫實作類別.
[2] 編寫 services.xml 描述 Web Services 檔案.
[3] 建立 Web Services *.aar archive (Axis Archive)
[4] 最後發佈 Web Services.


使用 Eclipse 建立 Project:
Eclipse: File -> New -> Java Project
Project Name: HelloWorldService -> Finish


[1] 建立 HelloWorldService class:
-------------- HelloWorldService.java -----------------
package test.joeyta;
public class HelloWorldService {
public String echo(String value) { // 這個 service 只是將輸入的文字 return 出去
System.out.println("Service HelloWorldService: " + value);
return value;
}
}

-------------- HelloWorldService.java -----------------


[2] 新增目錄 D:\eclipse_wtp\HelloWorldService\META-INF
建立 service descriptor 檔案 D:\eclipse_wtp\HelloWorldService\META-INF\services.xml:
--------------------- services.xml --------------------------
<service>
<parameter name="ServiceClass"
locked="false">test.joeyta.HelloWorldService</parameter>
<operation name="echo">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
</service>

--------------------- services.xml --------------------------


<parameter name="ServiceClass" locked="false">test.joeyta.HelloWorldService</parameter>
描述 service class. 這裡要包含 package,
<operation name="echo">
描述 此 Service 提供的服務.


Eclipse 裡的 project 如下所示:


[3] 建立 Axis2 service archive:
在 Eclipse 裡 right click "HelloWorldService" project
選 Export -> JAR file
Select the resource to export: 點擇 HelloWorldService 裡的 services.xml 及 test.joeyta package
JAR file: D:\eclipse_wtp\workspace\HelloWorldService.aar
然後按 Finish, 就會產生 D:\eclipse_wtp\workspace\HelloWorldService.aar
設定如下圖所示:


[4] 上載 Axis2 Service:
Axis2 Administration 登陸後 選擇 Upload Service 連結:
http://localhost:8083/axis2/axis2-admin/upload
然後選擇瀏覽 D:\eclipse_wtp\workspace\HelloWorldService.aar
按 upload 後, 點選 Available Services 就會看到如下所示:


在上圖中點選 HelloWorldService 連結就會看到該 service 的 WSDL:
http://localhost:8083/axis2/services/HelloWorldService?wsdl


如果檢視 WSDL 時出現 (internal server error page) :
即檢視 WSDL: http://localhost:8083/axis2/services/HelloWorldService?wsdl
出現 Provider org.apache.xalan.processor.TransformerFactoryImpl not found 等信息.
請到 http://www.apache.org/dist/java-repository/xalan/jars/
下載 xalan-2.7.0.jar
把它放在 D:\tomcat\webapps\axis2\WEB-INF\lib 下就能解決.



建立 Client 測試程式:
Eclise: File -> New -> Java Project
Project name: HelloWorldClient
按 Finish 就產生 HelloWorldClient project
點擊 HelloWorldClient 右鍵選 Properties
然後選擇 Java Build Path,
Source:
Source folders on build path: 新增 src 目錄
Default output folder: HelloWorldClient/bin
如下圖所示:

Library:
按 Add External JARs 新增所有 D:\axis2\lib 裡的 jar libraries.


使用 WSDL2JAVA 產生 stub classes:
由於測試時 Eclipse Axis2 Code Generator plugin 出問題,
故只好在 DOS command prompt 用手工輸入產生.


進入目錄 D:\axis2\bin , 執行:
D:\axis2\bin>wsdl2java.bat -uri http://localhost:8083/axis2/services/HelloWorldService?wsdl -o D:\eclipse_wtp\workspace\HelloWorldClient -p test.joeyta
-uri WSDL 的 uri 位置.
-o 輸出 stub classes 的位置. 預設會增加 src 目錄.
-p 設定輸出 stub classes 使用的 package.


產生 HelloWorldServiceStub.java 及 HelloWorldServiceCallbackHandler.java , 如下圖所示.


建立 Client 程式
------------------- HelloWorldClient.java ----------------------
public class HelloWorldClient {


public static void main(String[] args) throws Exception {


HelloWorldServiceStub stub = new HelloWorldServiceStub();


HelloWorldServiceStub.Echo request = new HelloWorldServiceStub.Echo();
request.setValue("Hello world, Joeyta");


EchoResponse response = stub.echo(request);


System.out.println("Response : " + response.get_return());
}


}
------------------- HelloWorldClient.java ----------------------


執行後輸出結果:
Response : Hello world, Joeyta


如下圖下示:


使用 TCP Monitor 監視 request 及 response SOAP conent:
下載舊版 Axis library axis-bin-1_4.zip:
http://apache.seekmeup.com/ws/axis/1_4/
解壓後把 axis.jar 複製至 D:\axis2\lib 裡,
進入 D:\axis2\lib 目錄
執行 D:\axis2\lib> java -classpath axis.jar org.apache.axis.utils.tcpmon
就會彈出 TCPMonitor
Listen port 設為 9999 ,
Target Hostname : 127.0.0.1
Target Port:8083
然後按 Add, 如下圖所示:
[ 這樣設可以依靠 port 9999 去監聽 port 8083 ]

修改 Client program HelloWorldServiceStub.java
將所有 port 從 8083 改為 9999 後, 再次過行 HelloWorldClient.java
就可以得到如下的 SOAP message:


使用 SOAP Monitor 監視 SOAP data, 下面是官方的教學.
http://ws.apache.org/axis2/1_0/soapmonitor-module.html

官方文檔非常多及齊全, 若想進一步了解, 需要花更長的時間:
http://ws.apache.org/axis2/1_0/index.html


Axis2 的文檔及教學非常充足. 官方文檔如下連結:
http://ws.apache.org/axis2/1_0/index.html


Axis2 官方的安裝教學:
http://ws.apache.org/axis2/1_0/installationguide.html


Axis2 用戶指南:
http://ws.apache.org/axis2/1_0/userguide.html


Axis2 WEB Administration 介面的使用教學:
http://ws.apache.org/axis2/1_0/webadminguide.html


Axis2 的設定文檔:
http://ws.apache.org/axis2/1_0/axis2config.html


AXIOM (Axis Object Model) 教學:
http://ws.apache.org/axis2/1_0/OMTutorial.html


Axis2 Eclipse plugin 教學:
http://ws.apache.org/axis2/tools/1_0/eclipse/wsdl2java-plugin.html

星期日, 7月 09, 2006

Apache Lucene(Search Engine)備忘記

Apache Lucene 是一個以java編寫, 具有高效率, 支持全文檢索的開源搜索引擎.
主要功能是對數據作索引及搜索,
它與其他工具配合能處理 word, html, pdf, excel 的全文搜尋.
Lucene 名字的來源是取其始創人 Doug Cutting 的妻子中間名及她外祖母的首名.
Lucene 已成功地應用在 Eclipse , Jive , Ifinder 等不同的領域.

開始備忘記:
首先安裝Tomcat 5.x.
http://apache.seekmeup.com/tomcat/tomcat-5/v5.5.17/bin/apache-tomcat-5.5.17.exe
下載後直接安裝到目錄 D:\tomcat
由於本人電腦安裝了幾個 tomcat , 故把 port設為8083 ( 預設port是8080 )
http://localhost:8083/ 測試是否安裝成功.


下載 lucene-2.0.0.zip
http://www.apache.org/dyn/closer.cgi/lucene/java/


解壓後把 luceneweb.war 放進 D:\tomcat\webapps 目錄下.
啟動 tomcat 就會自動產生 D:\tomcat\webapps\luceneweb


建立 indexing:
建立儲存index目錄 D:\lucene\index
複製 lucene-2.0.0.zip 裡的 docs 目錄至 D:\tomcat\webapps\luceneweb. ( 用作測試資料 )
將 lucene-core-2.0.0.jar 及 lucene-demos-2.0.0.jar 加入到環境變數 CLASSPATH 裡.
打開 DOS command prompt, 執行指令:
java org.apache.lucene.demo.IndexHTML -create -index "D:\lucene\index" "D:\tomcat\webapps\luceneweb"
D:\lucene\index 為 index 儲存的目錄.
D:\tomcat\webapps\luceneweb 為整個web裡搜尋的根目錄.


輸出:
adding D:/tomcat/webapps/luceneweb/docs/mailinglists.html
adding D:/tomcat/webapps/luceneweb/docs/queryparsersyntax.html
.....
.....
adding D:/tomcat/webapps/luceneweb/docs/resources.html
adding D:/tomcat/webapps/luceneweb/docs/systemproperties.html
adding D:/tomcat/webapps/luceneweb/docs/whoweare.html
Optimizing index...
53389 total milliseconds

表示建立 indexing 成功. 下圖為 indexing 產生的檔案:


修改 c:\tomcat\webapps\luceneweb\configuration.jsp
String indexLocation = "/opt/lucene/index";
改為:
String indexLocation = "D:\\lucene\\index";


瀏覽 http://localhost:8083/luceneweb/ 輸入 Search Criteria 後,
按 Search 後就會出現下面的error:
parse(java.lang.String) in org.apache.lucene.queryParser.QueryParser cannot be applied to ...


這是 luceneweb web project 的 bug
修改 c:\tomcat\webapps\luceneweb\result.jsp 第81行
query = QueryParser.parse(queryString, "contents", analyzer); //parse the
改為:
QueryParser qp = new QueryParser("contents", analyzer);
query = qp.parse(queryString);


並需要修改 c:\tomcat\webapps\luceneweb\result.jsp 第129行
String url = doc.get("url"); //get its url field
改為 String url = doc.get("path"); //get its url field
由於使用 IndexHTML 做 indexing 的時候, 並不會產生 url field, 而相對的產生了 path field.
lucenweb 的問題不少, 如果可以的話最好自己寫.


再次瀏覽 http://localhost:8083/luceneweb/ , 畫面如下:

在 Search Criteria 輸入 "lucene" 後, 按 Search 後就會出現如下畫面:


以下有一些官方的教學, 少得可憐:
http://lucene.apache.org/java/docs/gettingstarted.html


有問題可到下面發問:
http://www.gossamer-threads.com/lists/lucene/java-user/


使用 Luke 瀏覽 Index:
Luke 為 Lucene Index 檢視工具, 是以Java 開發的桌面應用程式.
可點選下面連結直接啟動 Java Web Start version ( 亦可到該網站直接下載binary執行):
http://www.getopt.org/luke/webstart.html


打開後如下畫面:

選擇 File -> Open Lucene Index
Browse 我們剛剛建立的 index 目錄 D:\lucene\index, 按 ok 後就會出現如下畫面:


整個介面使用非常簡單, 可參考 Luke 官方的教學:
http://www.getopt.org/luke/

如果要配合 weblucene, 下面為 weblucene 官方的教學:
http://www.chedong.com/tech/weblucene.html

db4o(Object Database)備忘記

db4o 為一項以java 及 .NET 為主的物件資料庫開源計劃.
應用它能節省開發資金及減少開發時間, 使開發員更專注於business logic,
它尤其適合於沒有DBA的嵌入式設備, 提供這些設備更理想的儲存方案.

db4o 以源生物件儲存, 不像一般的 ORM (object relational mapping)解決方案,
由於它應用物件源始儲存概念 , 故儲存效率比 ORM 更階,
其速度 與 hibernate + mysql 相差幾個級數比.
以下是官方的測試報告:
http://www.db4o.com/about/productinformation/benchmarks/

db4o 目前被不同的 168 個國家下載超過三十萬次,

開始備忘記:
下載 db4o-5.2-java.zip
http://developer.db4o.com/Files/

解壓後 把下面的 library 加入環境變數 CLASSPATH 裡:
bloat-1.0.jar // 這個library 優化執行階段
db4o-5.2-java1.2.jar // 這個library 相容 jdk 1.2.x 至 1.4.x
db4o-5.2-java5.jar // 這個library 相容 jdk 5
db4o-5.2-nqopt.jar // 這個library 優化編譯或執行階段

------------------------------------Account.java------------------------------------------
public class Account { // 這是用來測試的 Account class
private String name;


private String password;


public Account(String name, String password) {
this.name = name;
this.password = password;
}


public String toString() { // 列印 Account class 的 properties
return "name:" + this.name + " password:" + this.password;
}


public boolean equals(Object obj) {
// 這裡為了方便測試, 故名字相同為同一物件, db4o亦提供unique universal id
if (!(obj instanceof Account))
return false;
return name.equals(((Account) obj).name);
}


public int hashCode() {
return 15 * name.hashCode();
}


public Account() {
}


public String getName() {
return name;
}


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


public String getPassword() {
return password;
}


public void setPassword(String password) {
this.password = password;
}


}
------------------------------------Account.java------------------------------------------

------------------------------------Db4oObjectPool --------------------------------------
// 這個 Object Pool 其實是為了實現 類似hibernate open session in view 的概念
// 如果只為測試, 這個 class 實在是多餘的, 這裡是為了作為日後回憶之用, 尤其是開發web project
public class Db4oObjectPool {
private static ObjectContainer db;


private static ThreadLocal tl = new ThreadLocal(); // 這裡使用了 thread specific storage


private Db4oObjectPool() {
if (db == null) {
db = Db4o.openFile("db.yap"); // 建立資料檔案
Db4o.configure().encrypt(true); // 設定資料檔案 db.yap 被加密
Db4o.configure().password("123123"); // 設定資料檔案 db.yap 需要密碼才能訪問
}
}


private static synchronized Object getThreadLocalInstance() {
return tl.get();
}


// 其實db4o是 threadsafe, 下面不需要加 synchronized block, 這裡為了方便日後回憶
// 在 J2EE 開發, 使用ObjectServer#openClient().
//
可呼叫 Db4oServlet.sharedTransaction() , 就可以在每個 sesssion 裡取得transaction

// 在這例中為了簡便, 使用了 Db4o.openFile().
// 在 J2EE 開發中, 可呼叫 Db4oServlet.sharedTransaction() ,
// 在多個 session 裡就只能取得一個transaction

public static Db4oObjectPool getInstance() {
// 這裡使用了singleton, 有lazy initialization作用
if (getThreadLocalInstance() == null) { // 這裡使用了 double-checked locking
synchronized (Db4oObjectPool.class){
// 但在 jdk 1.4 double-checked locking 有問題, jdk 5解決了這問題
if (getThreadLocalInstance() == null) { tl.set(new Db4oObjectPool());
// 這裡實現每條thread共享同一個instance, 對web project 尤其重要
}
}

}
return (Db4oObjectPool) getThreadLocalInstance();
}


public ObjectContainer getDB() {
return db;
}


}
------------------------------------Db4oObjectPool --------------------------------------

------------------------------------Db4oObject ------------------------------------------
public abstract class Db4oObject {
// 這個class 集中處理DAO (data access model) 共通代碼


protected ObjectContainer getDB(){
return Db4oObjectPool.getInstance().getDB();
}

protected boolean backup(){ // 設定 backup 資料檔案
try{
getDB().ext().backup("D:\\db_backup.yap"); // 設定產生 backup 檔案路徑
} catch(Exception e){
return false;
}
return true;
}


protected void saveOrUpdate(Object object) {
getDB().set(object); // 由於前面Account裡改寫了equals, 故name已成為unique id
}

protected Object load(Object object){ // 取出某特定的物件實例
return getDB().get(object).next();
}

protected ObjectSet loadAll() { // 將所有物件實例取出來,
return getDB().query().execute();
}

protected void close() { // 關閉資料庫檔案, 這裡要小心
getDB().close();
}


protected void commit(){ // 提交
getDB().commit();
}

protected void rollback(){ // 撤回
getDB().rollback();
}


}
------------------------------------Db4oObject ------------------------------------------

------------------------------------AccountDAO ------------------------------------------
public class AccountDAO extends Db4oObject {
// 這個 DAO class, 主要的工作為 CRUD ( Create, Restore, Update, Delete)


public void deleteAll() { // 將所有Account instances 刪除
for (ObjectSet os = loadAll(); os.hasNext();) {
Account account = (Account) os.next();
getDB().delete(account);
}
}


public static void main(String[] args) { // 我們直接在 DAO class 裡測試
AccountDAO dao = new AccountDAO();
try {
dao.deleteAll(); // 清空 Account instances
Account account1 = new Account("joeyta", "pass123");
dao.saveOrUpdate(account1); // 將 account1 儲存
dao.saveOrUpdate(new Account("jane", "pass456")); // 儲存另一 account
System.out.println("Before update:");
for (ObjectSet os = dao.loadAll(); os.hasNext();) { // 打印所有資料檔案裡的物件實例
// 這裡測試只有Account, 當有不用的class時出現 Type Cast 的 Exception, 要留意

Account account = (Account) os.next();
System.out.println(account);
}


account1.setPassword("pass000"); // 更改 account1 密碼
dao.saveOrUpdate(account1); // 由於 Account 裡name為identifier, 所以這裡 account1 為更新
System.out.println("After update:");
for (ObjectSet os = dao.loadAll(); os.hasNext();) { // 再次打印所有Account物件
// 這裡測試只有Account, 當有不用的class時出現 Type Cast 的 Exception, 要留意

Account account = (Account) os.next();
System.out.println(account);
}

dao.commit();
dao.backup(); // 這裡執行 backup 資料檔案
} catch (Exception e){
dao.rollback(); // 當有 Excption 發生時 rollback 所有變更
} finally {
dao.close(); // 這裡如果實作open session in view 概令, 需要改寫成filer
}
}
}
------------------------------------AccountDAO ------------------------------------------

運行 AccountDAO 後輸出結果為:
Before update:
name:jane password:pass456
name:joeyta password:pass123
After update:
name:jane password:pass456
name:joeyta password:pass000

使用Object Manager 瀏覽數據:
下載 objectmanager-1.7.1-win_ikvm.zip ( 這個包含 java vm)
http://developer.db4o.com/Files/

解壓後 直接 運行 objectmanager.bat
然後會出現 Object Manager 的介面,
選擇 File -> Open "Encrypted" File // 由於上面 encrypt 設為true, 故這裡使用encrypted
browse 上面例子產生的資料庫檔案 db.yap
輸入 例子裡的 password : 123123 // 我測試時使用密碼打不開, 不輸入密碼卻能開啟檔案, 其怪
如果成功連接了就會出現下面的畫面:


選擇 File -> Query , 選擇要查詢的 Object class
就會出現下面的畫面:


選擇 File -> Export to XML
輸入 db.xml, 按存檔就會產生 db.xml 到目錄裡.
db.xml 的內容為:
<com.db4o.reflect.generic.GenericObject id="1527">
<name>&lt>;jane></name>
<password>&lt>;pass456&gt;</password>
</com.db4o.reflect.generic.GenericObject>
<com.db4o.reflect.generic.GenericObject id="2021">
<name>&lt>;joeyta></name>
<password>&lt>;pass000&gt;</password>
</com.db4o.reflect.generic.GenericObject>


當使用commit() 及rollback(), db4o 自動提供 read committed 的transactions.

db4o的功能不少,有興趣的同仁可參考下面更多官方的教學:
http://www.db4o.com/community/testdrive/formulaonetutorial.aspx
http://www.db4o.com/about/productinformation/resources/db4o-5.0-tutorial-java.pdf

星期五, 7月 07, 2006

ZK(Ajax but no JavaScript)備忘記

ZK 為Ajax Web開源框架, 它帶給我們能以最少編程能力,
提供Rich client介面而不需要編寫Javascript. 是一種以事件驅動組件的開發過程.
開發員就像開發桌面應用程式般輕鬆, 類似設計及編寫HTML標記語言般簡單..

ZK 於2006年3月, 獲得2006年社區精選獎項,
並在2006年5月, 成為SourceForge第一熱門項目.

開始備忘記:
首先安裝Tomcat 5.x.
http://apache.seekmeup.com/tomcat/tomcat-5/v5.5.17/bin/apache-tomcat-5.5.17.exe
下載後直接安裝到目錄 D:\tomcat
由於本人電腦安裝了幾個 tomcat , 故把 port設為8083 ( 預設port是8080 )
http://localhost:8083/ 測試是否安裝成功.

測試 ZK:
下載 zk-demo-2.0.1.zip
http://sourceforge.net/project/showfiles.php?group_id=152762
解壓後把 zkdemo-all.war 或 zkdemo-all.ear 放進 c:\tomcat\webapps 目錄下.
啟動 tomcat
瀏覽 http://localhost:8083/zkdemo-all/userguide/ 進行測試

這裡有很多範例, 可在 Try me 下的 TextArea 裡更改,
然後按 Try me 按鈕就會在上面顯示. 有興趣的同仁可在這裡玩一陣子.

測試:
[1] ZK HelloWorld(第一個例子 -- 問候Joeyta):
由於啟動 tomcat 後, 會把 zkdemo-all.war 自動解壓.
產生 c:\tomcat\webapps\zkdemo-all 的目錄.
建立測試目錄 c:\tomcat\webapps\zkdemo-all\mydemo
建立測試檔案 c:\tomcat\webapps\zkdemo-all\mydemo\HelloWorld.xul
HelloWorld.zul 的內容為:
<window title="My First window" border="normal" width="200px">
Hello, Joeyta!
</window>


如果有web view的開發經驗, 上面代碼看下去不用解釋都知識在幹甚麼.

瀏覽 http://localhost:8083/zkdemo-all/mydemo/HelloWorld.zul 結果為:


以上教學可參考官方更完整的文檔:
http://zk1.sourceforge.net/wp/ZK-quickstart.pdf

集成 Eclipse WTP 可參考:
http://zk1.sourceforge.net/smalltalks/eclipse/ek.html

如果想更了解 XUL(XML User-interface Language) 可參考:
http://xul.sourceforge.net/mozilla.html
http://xulplanet.com/tutorials/xultu/


[2] ZK Interactive(第二個例子 -- 互動):
建立測試檔案 c:\tomcat\webapps\zkdemo-all\mydemo\Interactivity.zul
內容為:
<window title="Hello" border="normal">
<button label="Say Hello" onClick="alert(&quot;Hello Joeyta!")"/>
</window>

瀏覽 http://localhost:8083/zkdemo-all/mydemo/Interactivity.zul


整個測試過程既輕鬆, 又簡單. 有興趣的同仁可跟隨官方的教學文檔, 很充足.

以上只是簡單的示例, 可參考官方的開發文檔:
http://zk1.sourceforge.net/wp/ZK-devguide.pdf

JSUnit備忘記

JSUnit 是網頁View開發過程的品質保證. 用以測試客戶端的代碼.
它能測試javascript的function是否與預期一致..
還能保證代碼後期變得巨大時, 更方便進行 Refactoring 的工作.
使代碼更能Reusable 及減少bad smell.

下載 jsunit2.2alpha11.zip
https://sourceforge.net/project/showfiles.php?group_id=28041

把它解壓至 c:\jsunit 下.
建立測試用的目錄 c:\jsunit\mytest
建立測試檔案 c:\jsunit\mytest\HelloWorld.html
內容為:
<html>
<head>
<title>Test Page for Hello Joeyta</title>
<script language="javascript" src="../app/jsUnitCore.js"></script>
</head>
<body>
<script language="javascript">
var sHello = "";
function setUp(){ // 這個function用來初始化, 每一個test之前都會運行此function
sHello = "Hello Joeyta";
}
function sayHello(sayContent){ // 這是我們要測試的function
return sayContent;
}
function testSayHello(){ // 測試function的前面要加 "test" , 這裡測試上面的function是否如預期一致
assertEquals(sHello, sayHello(sHello));
}
function testFailSayHello(){ // 測試function失敗的情形
assertNotEquals("Hello Joey", sayHello(sHello));
}
function tearDown(){ // 每個test之後會運行此function
sHello = "";
}
</script>
</body>
</html>

以 IE 打開 C:\jsunit\testRunner.html
瀏覽 按鈕 選擇 測試檔案 c:\jsunit\mytest\HelloWorld.html
按 Run
如果測試全部成功 progress bar就會是綠色. 失敗則是紅色.

其實熟識 JUnit 的人仕很容易明白怎樣使用 JSUnit.
上面這個例子只是入門, 是最基本的, 官方有更詳盡的教學:
http://www.jsunit.net/examples/example1.html
http://www.jsunit.net/documentation/index.html

Javascript Debugger(IE & Firefox)備忘記

以下這些工具對網頁開發員來說, 可以說是雪中送碳.
因為網頁開發員的工作一般來說有點枯燥,
尤其是專注於View開發的同仁.

Firefox:

到 https://addons.mozilla.org/firefox/216/ 點選 Install now.
Firefox 重啟後就會自動安裝.
然後選 工具 -> javascript debugger 就可以開始使用了.

這裡有官方FAQ使用教學:
http://www.hacksrus.com/~ginda/venkman/faq/venkman-faq.html

Internet Explorer:
下載 Script Debugger for Windows
http://www.microsoft.com/downloads/details.aspx?FamilyID=2f465be0-94fd-4569-b3c4-dffdf19ccd99&displaylang=en
安裝後 可以到 IE -> 工具 -> 進階 -> 停止指令碼偵錯 [反點選即開啟]
個人建議是平時把它關閉,因為每次網頁有問題都會跳出來嚇你一跳.
其功能如下:
[1] View the source code of the script they are debugging.
[2] Control the pace of script execution with break points and stepping.
[3] View and change variable and property values with the Command Window.
[4] View and control script flow with the Call Stack Window.

下載 Internet Explorer Developer Tollbar
http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d-4511-bb3e-2d5e1db91038&displaylang=en
安裝後在 IE -> 檢視 -> 工具列 -> Developer Toolbar 就會顯示Toolbar
然後按 View DOM 就開始瀏覽之旅了

其功能如下:
[1] Explore and modify the document object model (DOM) of a Web page.
[2] Locate and select specific elements on a Web page through a variety of techniques.
[3] Selectively disable Internet Explorer settings.
[4] View HTML object class names, ID's, and details such as link paths, tab index values, and access keys.
[5] Outline tables, table cells, images, or selected tags.
[6] Validate HTML, CSS, WAI, and RSS Web feed links.
[7] Display image dimensions, file sizes, path information, and alternate (ALT) text.
[8] Immediately resize the browser window to a new resolution.
[9] Selectively clear the browser cache and saved cookies. Choose from all objects or those associated with a given domain.
[10] Choose direct links to W3C specification references, the Internet Explorer team weblog (blog), and other resources.
[11] Display a fully featured design ruler to help accurately align and measure objects on your pages.







使用 Http Watch 監視 TCP:




下載Http Watch試用版:
http://www.simtec.ltd.uk/download/

選擇 IE -> View -> Explor Bar -> HttpWatch , 然後按 Start.
就會出現如下畫面:






星期四, 7月 06, 2006

OPENSYMPHONY Quartz(java cron job)備忘記

在java裡,自己寫一個Scheduler實在是煩人的事,
有些人選擇依靠OS的Scheduler或Crontab job.
在java的世界裡,可以使用Quartz來實作定時執行工作,
就像在unix like系統裡設定crontab job一樣簡單.


首先下載 quartz-1.5.2.zip
http://www.opensymphony.com/quartz/download.action
解壓後把 quartz-all-1.5.2.jar 加入環境變數 CLASSPATH 裡.


由於Quartz logging使用了Apache Commons logging.
故需要同時下載 commons-logging-1.1.zip
http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi
解壓後把 commons-logging-1.1.jar 加入環境變數中及加到 jdk_home/jre/lib/ext 裡.
這問題也煩了我一陣子. 如果沒加到 jdk_home/jre/lib/ext 裡, 會出現下面這個exception.
java.lang.NoClassDefFoundError: org/apache/commons/logging/Log


在quartz-1.5.2.zip裡亦包含以下的examples:
example1 - Your first Quartz Program
example2 - Simple Job Triggers
example3 - Cron Triggers
example4 - Job State and Job Parameters
example5 - Job Misfires
example6 - Handling Job Exceptions
example7 - Interrupting Jobs
example8 - How to use Quartz Calendars
example9 - Using Job Listeners
example10 - Using Quartz Plug-Ins
example11 - Loading Up Quartz with Many Jobs
example12 - Remoting with Quartz using RMI
example13 - Clustering Quartz and JDBC Job Stores


跟隨這些examples作練習會對quartz更進一步的了解.


我要實作的案例很簡單,在一定的間隔裡執行某項工作.


SayHelloJob.java
public class SayHelloJob implements Job { // 我們的job需要implement Job的execute.
public void execute(JobExecutionContext arg0) throws JobExecutionException {
Log log = LogFactory.getLog(SayHelloJob.class);
log.info(new Date()+"#start myjob!"); // 打印開始時間

System.out.println("Joeyta says hello to EveryBody.");
// 這裡我們的job是print message

log.info(new Date()+"#end myjob!"); // 打印結束時間
}
}


MyCronJob.java
public class MyCronJob {


public void doMyCronJob() throws SchedulerException, ParseException {
Log log = LogFactory.getLog(MyCronJob.class);
log.info("-----------job initialize----------");
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler(); // 取得scheduler的reference


JobDetail job = new JobDetail("job1", "group1", SayHelloJob.class);
// 由於quartz support多group到多job. 這裡我們只有一個job. 我們自己我隨意把它命名.
// 但相同group裡如果出現相同的job名,會被overrride.
CronTrigger cTrigger = new CronTrigger("trigg1", "group1", "job1",
"group1", "1/10 * * * * ?");
// 這裡指定trigger執行那個group的job.
// "1/10 * * * * ?" 與 在unix like裡的crontab job的設定類似. 這裡表示每天裡的每10秒執行一次
// Seconds Minutes Hours Day-of-Month Month Day-of-Week Year(optional field)
// 可參考 http://www.opensymphony.com/quartz/wikidocs/TutorialLesson6.html
// 及 http://www.opensymphony.com/quartz/api/org/quartz/CronTrigger.html
Date ft = sched.scheduleJob(job, cTrigger);
log.info("job start at:" + ft); // 記錄何時開始執行工作
sched.start();
}


public static void main(String[] args) throws Exception {
MyCronJob cronJob = new MyCronJob();
cronJob.doMyCronJob();
}


}


以下是一些官方的教學:
http://www.opensymphony.com/quartz/wikidocs/Tutorial.html

Subversion & Subclipse 備忘記

Subversion 項目的目標是取代現在開源社區流行使用的代碼版本控制系統 CVS,
用戶介面類似 CVS, 並修正 CVS 大部份的缺點.
尤其是對目錄, 複製, 更名 的等版本控制不足.

以下是官方的 FAQ, 有更多 Subversion 的簡介:
http://subversion.tigris.org/faq.html

開始備忘記:
這裡為求簡潔, 安裝在 windows 下, 在 linux 下配置亦是類似.


下載 svn-1.3.2-setup.exe
http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91


下載 TortoiseSVN-1.3.5.6804-svn-1.3.2.msi
http://prdownloads.sourceforge.net/tortoisesvn/TortoiseSVN-1.3.5.6804-svn-1.3.2.msi?download


執行 svn-1.3.2-setup.exe
執行 TortoiseSVN-1.3.5.6804-svn-1.3.2.msi 並重啟電腦


建立目錄 D:\svndemo\repository
執行指令 svnadmin create D:\svndemo\repository


修改 D:\svndemo\repository\conf\svnserve.conf
[general]
# password-db = passwd
改為:
[general]
password-db = passwd


修改 D:\svndemo\repository\conf\passwd
[users]
# harry = harryssecret
# sally = sallyssecret
改為:
[users]
harry = harryssecret
sally = sallyssecret


運行服務器
執行指令 svnserve -d -r D:\svndemo\repository


建立目錄 D:\svndemo\initproject
右鍵 D:\svndemo\initproject -> TortoiseSVN -> Import
URL of repository:
svn://localhost/trunk
按 ok 後 輸入:
username: harry
password: harryssecret


右鍵 D:\svndemo\initproject -> SVN Checkout
URL os repository: svn://localhost/trunk
checkout directory: D:\svndemo\initproject
按 ok -> ok


建立檔案 D:\svndemo\initproject\test.txt
右鍵 D:\svndemo\initproject\test.txt -> TortoiseSVN -> add
選擇 test.txt -> ok -> ok
修改 test.txt 然後按右鍵 -> SVN Commit -> ok -> ok


以上教學可參考:
http://www.subversion.org.cn/content/view/18/1/


安裝 jdk 及 Eclipse 後 , 安裝subclipse plug in:
執行 Eclipse -> help -> Software Updates -> Find and Install
->> Search for new features to install -> next
Name: subclipse
URL: http://subclipse.tigris.org/update
按 ok


安裝subclipse後, 打開SVN repository:
按 Add SVN repository
URL: svn://localhost/trunk
username: harry
password: harryssecret
按 ok


然後就可以 右鍵 svn://localhost/trunk -> checkout as
就可以選擇你想要的project.
就可以對project進行version control了.


以下有一些官方的教學:
http://subclipse.tigris.org/screenshots.html


雖然Subversion改進了CVS, 功能亦比他強.
但在SDI的開發過程中,subclipse給了我們一些不好的印像.
http://www2.cpttm.org.mo/cyberlab/SDI/2005-001/index.html.en
尤其是在rename方面,給我們帶來了不小煩惱.
http://www2.cpttm.org.mo/cyberlab/SDI/2005-001/review.html.en


我自己最後的總結是 M$ 的 VSS 比較好用.
可能是公司用了幾年習慣了的關係.
而且 Eclipse 亦有開源的 plug in.
以下是 Eclipse vss plugin 安裝的官方教學:
http://vssplugin.sourceforge.net/







Apache Commons(UploadFile)備忘記

以前一向以 JspSmartUpload 或 Oreilly MultiPartRequest 上載文件到伺服器.
今次使用 Apache Commons FileUpload .


首先下載 commons-fileupload-1.1.1.zip
http://jakarta.apache.org/site/downloads/downloads_commons-fileupload.cgi
下載後將 commons-fileupload-1.1.1.jar 放進 Project_name/WEB-INF/lib 裡.

下載 commons-io-1.2.zip :
http://jakarta.apache.org/site/downloads/downloads_commons-io.cgi
如果沒有下載這個library,會出現下面這個Exception,這個花了我不了的時間找.
java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream


UploadExcel.java
public class UploadExcel{
String tempDirectory = "/web_project_path/excel/temp/"; // 設定暫存目錄
String fileDirectory = "/web_project_path/fileupload/"; // 設定上存檔案目錄
String fileExtention = ".xls";

public UploadExcel() {}


public int uploadFile(HttpServletRequest request) {
try {
DiskFileItemFactory factory = new DiskFileItemFactory(); // 建立factory
factory.setSizeThreshold(4000); // 設定緩存大小
factory.setRepository(new File(tempDirectory));  // 設定暫存Directory
ServletFileUpload upload = new ServletFileUpload(factory); // 建立Servlet File
upload.setSizeMax(1000000); // 設定上存檔案最大容量

List items = upload.parseRequest(request);
Iterator iter = items.iterator();

while (iter.hasNext()) { // 這裡lookup所有上存檔案
FileItem item = (FileItem) iter.next();


//if (item.isFormField()) {
// String name = item.getFieldName(); // 這裡取得parameter的名字
// String value = item.getString(); // 取得parameter的數值
//}
if (!item.isFormField()) {
String fieldName = item.getFieldName();
String fileName = item.getName();
// String contentType = item.getContentType();
// boolean isInMemory = item.isInMemory();
// long sizeInBytes = item.getSize();
if(!fileName.endsWith(fileExtention)) continue; //這裡亦可使用contentType來判斷
File uploadedFile = new File(fileDirectory + fieldName
+ ".xls");
item.write(uploadedFile); //將檔案寫到上存目錄
}
}


} catch (Exception e) {
System.out.println("Exception (UploadExcel): " + e);
return -1;
}
return 1;
}


}



uploadexcel.jsp
<jsp:useBean id="myUpload" scope="page" class="com.excel.UploadExcel" />


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=big5">
<title>Upload Excel</title>
</head>
<body>


<%
int iError = 1;
if (request.getParameter("action") != null
&& request.getParameter("action").equals("upload")) { // 判斷是否上存
iError = myUpload.uploadFile(request);
if(iError > 0){
out.println("<script>alert('Success');</script>");
} else {
out.println("<script>alert('Fail');</script>");
}
}


%>
<script type="text/javascript">
function openPopUp(){
self.location = 'excelDownload.jsp';
window.open(self.location,'openWin','');
}
function uploadsave(){
obj = document.formfile;
document.formfile.action='uploadexcel.jsp?action=upload';
document.formfile.submit();
}
</script>


<form name="formfile" method="post" enctype="multipart/form-data">
Please select file(Chinese)
<input type="file" name="excel_ch">
<br>
<input type="button" name="preview" value="Preview Excel" onclick="openPopUp();">
<input type="button" value="Upload" onclick="uploadsave();">
</form>
</body>
</html>



excelDownload.jsp
<%@ page import="java.io.*" %><%
response.setHeader("Content-disposition","attachment; filename=excel_ch.xls");
FileInputStream fis=new FileInputStream("/web_project_path/fileupload/excel_ch.xls");
OutputStream os=response.getOutputStream();
int byteRead;
while(-1 != (byteRead = fis.read())) {
os.write(byteRead);
}
os.close();
if (fis != null)
fis.close();
%>



以下是一些官方的教學:
http://jakarta.apache.org/commons/fileupload/using.html
http://jakarta.apache.org/commons/fileupload/faq.html








iText(PDF)備忘記

下載 itext-1.4.2.jar:
http://prdownloads.sourceforge.net/itext/itext-1.4.2.jar

這個工具真的很好用,當時使用的時候大概兩年前,現在回頭把它記錄下來.
官方的教學文件很充足.
而且編寫完成後,很容易就能將它從產生pdf的檔轉成html或rtf.
這裡不打算將我當初寫的案例作為簡介,由於太多太大了.
只把官方的其中一個例子作為簡介.拋專引玉.
希望對我日後回憶及有意無意間觀看到的讀者有所幫助.
但我記得中文的輸出還需要下載iTextAsian.jar (這個比較雖要注意)

http://itextdocs.lowagie.com/examples/com/lowagie/examples/objects/tables/MyFirstTable.java
public class MyFirstTable {
public static void main(String[] args)
System.out.println("My First PdfPTable");


// step 1: creation of a document-object
Document document = new Document();


try {
// step 2:
// we create a writer that listens to the document
// and directs a PDF-stream to a file
PdfWriter.getInstance(document, new FileOutputStream("MyFirstTable.pdf"));


// step 3: we open the document
document.open();


PdfPTable table = new PdfPTable(3);
PdfPCell cell = new PdfPCell(new Paragraph("header with colspan 3"));
cell.setColspan(3);
table.addCell(cell);
table.addCell("1.1");
table.addCell("2.1");
table.addCell("3.1");
table.addCell("1.2");
table.addCell("2.2");
table.addCell("3.2");
cell = new PdfPCell(new Paragraph("cell test1"));
cell.setBorderColor(new Color(255, 0, 0));
table.addCell(cell);
cell = new PdfPCell(new Paragraph("cell test2"));
cell.setColspan(2);
cell.setBackgroundColor(new Color(0xC0, 0xC0, 0xC0));
table.addCell(cell);
document.add(table);
} catch (DocumentException de) {
System.err.println(de.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
}


// step 5: we close the document
document.close();
}
}

這裡有更多官方的教學:
http://itextdocs.lowagie.com/tutorial/

JDOM(generate xml)備忘記

續上一編讀取Excel後,
最後還需要將資料轉成為xml,發佈到其他地方或資料庫.

下載jdom-1.0.zip
http://www.jdom.org/dist/binary/

解壓後將jdom.jar加入到classpath中.

Account.java
public class Account{
private String name;
private String password;
private String email;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public String getPassword(){
return this.password;
}
public void setPassword(String password){
this.password= password;
}
public String getEmail(){
return this.email;
}
public void setAge(String email){
this.email= email;
}
public String getClassName() {
return this.getClass().getName().substring(
this.getClass().getPackage().getName().length() + 1);
}

public String toString(){
return getClassName() + "@" this.name + "#" + this.password + "#" + this.email;
}

}

GenerateXML.java
public class GenerateXML(){
private String xmlFilePath = "account.xml";
public void addNode(Element accountElement,String nodeName,String nodeData){
Element tmpElement = new Element(nodeName); // 建立新element
tmpElement.addContent(nodeData); // 將content加入到element裡
accountElement.addContent(tmpElement); // 將有content的element加入到預設的element
}

public void generateXML() throws IOException{
Element rootElement = new Element("ACCOUNTS"); // 建立 Root Element
Document document = new Document(rootElement); // 建立 Xml Document
Element accountElement = null; // 設定Element, 這個Element將會加入到 Root Element裡

accountElement = new Element("ACCOUNT"); // 建立新的Element
addNode(accountElement,"NAME", "joeyta"); // 將name element加入到root element裡
addNode(accountElement,"PASSWORD", "123456");
addNode(accountElement,"EMAIL", " joeyta@matrix.org.cn");
rootElement.add(accountElement);

accountElement = new Element("ACCOUNT");
addNode(accountElement,"NAME", "jane");
addNode(accountElement,"PASSWORD", "123123");
addNode(accountElement,"EMAIL", "jane@matrix.org.cn");
rootElement.add(accountElement);

Format format = Format.getCompactFormat(); // 建立輸出格式物件
format.setEncoding("big5"); // 設定輸出encoding 為big5
format.setOmitEncoding(false); // 設定是否省略輸出的encoding
format.setIndent(" "); // 設定縮排時的格式
format.setLineSeparator(System.getProperty("line.separator")); // 設定隔行的格式


XMLOutputter outputter = new XMLOutputter(); // 建主輸出物件
outputter.setFormat(format); // 加入輸出格式物件

System.out.println(outputter.outputString(document)); // 打印xml出來

FileWriter fw = new FileWriter(xmlFilePath); // 建立writer
BufferedWriter fout = new BufferedWriter(fw);
outputter.output(document,fw); // 產生xml檔案
fout.close();
}

public static void main(String args){
GenerateXML gx = new GenerateXML();
gx.generateXML();

}
}

輸出的account.xml內容:
<?xml version="1.0" encoding="big5"?>
<ACCOUNTS>
<ACCOUNT>
<NAME>joeyta</NAME>
<PASSWORD>123456</PASSWORD>
<EMAIL>joeyta@matrix.org.cn</EMAIL>
</ACCOUNT>
<ACCOUNT>
<NAME>jane</NAME>
<PASSWORD>123123</PASSWORD>
<EMAIL>jane@matrix.org.cn</EMAIL>
</ACCOUNT>
</ACCOUNTS>

以下有更多官方的文檔及教學:
http://www.jdom.org/downloads/docs.html
http://www.cafeconleche.org/books/xmljava/

POI HSSF(Read Excel)備忘記

由於最近工作需要讀取某些Excel,故將測試的過程簡單的記錄下來.

下載poi-bin-3.0-alpha2-20060616.zip
http://apache.mirrors.hoobly.com/jakarta/poi/dev/bin/


解壓縮後把下面三個 library 加入 CLASSPATH 中:
poi-3.0-alpha2-20060616.jar
poi-contrib-3.0-alpha2-20060616.jar
poi-scratchpad-3.0-alpha2-20060616.jar

account.xls 內容:
name password email
joeyta 123456 joeyta@matrix.org.cn
jane 123123 jane@matrix.org.cn

Account.java
public class Account{
private String name;
private String password;
private String email;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public String getPassword(){
return this.password;
}
public void setPassword(String password){
this.password= password;
}
public String getEmail(){
return this.email;
}
public void setAge(String email){
this.email= email;
}
public String getClassName() {
return this.getClass().getName().substring(
this.getClass().getPackage().getName().length() + 1);
}
public String toString(){
return getClassName() + "@" this.name + "#" + this.password + "#" + this.email;
}

}

ReadAccountFromExcel.java
public class ReadAccountFromExcel {
private ArrayList accountList = new ArrayList();
private String filePath = "account.xls";
public void readExcel() throws IOException {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(filePath));
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFSheet sheet = wb.getSheetAt(0); // 取得Excel第一個sheet(從0開始)
for (int i = 1; i < sheet.getLastRowNum(); i++) { // 由於第 0 Row 為 title, 故 i 從 1 開始
HSSFRow row = sheet.getRow(i); // 取得第 i Row
Account account = new Account();
account.setName(row.getCell((short)0).toString()); // 取得第1個cell (為name)
account.setPassword(row.getCell((short)1).toString()); // 取得第2個cell (為password)
account.setEmail(row.getCell((short)2).toString()); // 取得第3個cell (為email)
accountList.add(account); // 將account加入ArrayList裡
}
}

public static void main(String[] args) throws IOException {
ReadAccountFromExcel rafe = new ReadAccountFromExcel();
rafe.readExcel();

for (Iterator iter = rafe.accountList.iterator(); iter.hasNext();) { // 將所有account打印出來
Acount element = (Acount) iter.next();
System.out.println(element);
}
}
}

執行後輸出結果:
Account@joeyta#123456#joeyta@matrix.org.cn
Account@jane#123123#jane@matrix.org.cn

這裡還有更多官方的教學:
http://jakarta.apache.org/poi/hssf/quick-guide.html
http://jakarta.apache.org/poi/hssf/how-to.html