星期五, 8月 04, 2006

JBoss EJB3(Stateful Session Beans)備忘記

上一編介紹如何安裝 JBoss 及建立第一個 Stateless Session Beans HelloWorld:
http://blog.matrix.org.cn/page/joeyta?entry=jboss_ejb3_helloworld_%E5%82%99%E5%BF%98%E8%A8%98


很多書對 Entity Beans , Stateful 及 Stateless Session Beans 有非常詳細的說明,
小弟愚昧, 當初看 Mastering EJB 時, 看完了還是一頭問號, 現在亦了解不深.
由於這編只是以簡潔實作為主的備忘記, 故以最簡單的表示方法作簡介.


Session Beans 的主要作用是訪問 Entity Beans, Sesseion Beans 可看作 domain story,
它描述幾個 Beans 之間的工作流程, 所以 Session Beans 主要包含 business logic 的流程.
Entity Beans 主要是作為 OR Mapping 的 business model 對像, 與資料庫儲存對應的 model.
有了 Entity Beans 的 ORM(Object Relational Mapping), 開發員就不用關心關聯式資料庫的資料關係,
交由 EntityManager service 幫忙管理, 開發員把重心放在 objects model (Entity Beans) 間關係,
簡單的說, 開發員在操作 Entity Beans 時可看作操作虛擬的 Objects Database.


Session Beans 分為 Stateless 及 Stateful Session Beans, 即 無狀態 及 有狀態 Session Beans.
無狀態 Session Beans 主要是執行基於單個 request 的動作, 如產生報告 及 驗證 credit cards等.
有狀態 Session Beans 可記錄 client 多個 request 間動作, 典型的例子是記錄 client 已點選的購物車商品.


開始備忘記:
這次備忘記主題是 Stateful Session Beans, 當然是以 Shopping Cart 作為例子.
[1] Eclipse 啟動 JBoss Server
[2] Eclipse 建立第一個 Stateful Session Beans Project
[3] 建立 Shopping cart Stateful Beans
[4] 建立客戶端測試程式
[5] 使用 ANT 建立 EJB-JAR 並執行 ShoppingCartClient 程式


[1] Eclipse 啟動 JBoss Server:
Eclipse: Windows -> Show View -> Other
-->> JBoss-IDE -> Server Configuration
就會顯示 JBoss Server Configuration console
然後 right client 它按 start , JBoss 就會啟動, 如下圖所示:



[2] Eclipse 建立第一個 Stateful Session Beans Project:
Eclipse: File -> New -> Other -> EJB 3.0 -> EJB 3.0 Project
Project Name: StatefullEJB3 -> Next
選擇上一編已建立的 JBoss 4.0.x: jboss_configuration [default](not running)
打開後右鍵點選 JBoss 4.0.x -> new
然後按 Finish. StatefullEJB3 project 就建立了


[3] 建立 Shopping cart Stateful Beans:
/*----------------------- ShoppingCart.java ---------------------*/
package ejb3.joeyta.sessions;
import java.util.HashMap;
import javax.ejb.Remove;
public interface ShoppingCart // 建立 interface
{
void buy(String product, int quantity); // 建立 Shopping Cart buy method
HashMap<String, Integer> getCartContents(); // 取回 Shopping Cart HashMap
@Remove void checkout(); // 結帳, 這裡加入 @Remove 的意思是當呼叫它, 就會清除這個 Instance
}
/*----------------------- ShoppingCart.java ---------------------*/


/*----------------------- ShoppingCartBean.java -----------------*/
package ejb3.joeyta.sessions;
import java.io.Serializable;
import java.util.HashMap;
import javax.ejb.Remote;
import javax.ejb.Remove;
import javax.ejb.Stateful;


@SuppressWarnings("serial")
@Stateful // @Stateful 表示這是 Statefull Session Beans
@Remote(ShoppingCart.class)
public class ShoppingCartBean implements ShoppingCart, Serializable {
private HashMap<String, Integer> cart = new HashMap<String, Integer>();
// 建主 HashMap cart 儲存購買的 product
public void buy(String product, int quantity) {
if (cart.containsKey(product)) { // 判斷是否曾經選購此 product
int currq = cart.get(product);
currq += quantity;
cart.put(product, currq); // 將慾選購的 product 加入 HashMap cart 裡
} else {
cart.put(product, quantity);
}
}

public HashMap<String, Integer> getCartContents() {
return cart;
}

@Remove
public void checkout() {
System.out.println("Print cart list on server:"); // 結帳時在Server打印選購清單
HashMap<String, Integer> fullCart = getCartContents();
for(String product : fullCart.keySet()){
System.out.println(fullCart.get(product) + " " + product);
}
System.out.println("Checked Out");
}
}
/*----------------------- ShoppingCartBean.java -----------------*/



[4] 建立客戶端測試程式:
/*----------------------- ShoppingCartClient.java ---------------*/
package ejb3.joeyta.clients;
import java.util.HashMap;
import javax.naming.InitialContext;
import ejb3.joeyta.sessions.ShoppingCart;
public class ShoppingCartClient
{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
ShoppingCart cart = (ShoppingCart) ctx.lookup("ShoppingCartBean/remote");


System.out.println("Buying 1st Cake");
cart.buy("Cake", 1); // 買第一個 Cake


System.out.println("Buying 2nd Cake");
cart.buy("Cake", 1); // 買第二個 Cake

System.out.println("Buying 1st Bread");
cart.buy("Bread", 1); // 買第一個 Bread


System.out.println("Print cart list on client:"); // 打印選購清單
HashMap<String, Integer> fullCart = cart.getCartContents();
for (String product : fullCart.keySet())
{
System.out.println(fullCart.get(product) + " " + product);
}


System.out.println("Checkout");
cart.checkout(); // 結帳, 還記得嗎, 呼叫此 method 會清除此 instance


System.out.println("Should throw an object not found exception by invoking on cart after @Remove method");
try
{
cart.getCartContents(); // 由於己清除此instance, 這裡再測試是否己清除
}
catch (javax.ejb.EJBNoSuchObjectException e)
{
System.out.println("Successfully caught no such object exception.");
}
}
}
/*----------------------- ShoppingCartClient.java ---------------*/


項目結構如下所示:


[5] 使用 ANT 建立 EJB-JAR 並執行 ShoppingCartClient 程式:
在 HelloWorldEJB3 project 下建立 build.xml [ ANT build File ]
內容如下:
<!------------------------- build.xml ------------------------------->
<?xml version="1.0"?>
<project name="JBoss" default="run.ShoppingCartClient" 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}/ShoppingCart.jar" />
<delete file="${jboss.home}/server/default/deploy/ShoppingCart.jar" />
</target>

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


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


build.xml 項目:
classpath 描述所需的 libraries 及 classes 的位置.
clean 清除項目所產生的 ShoppingCart.jar 及 JBoss deploy 裡的 ShoppingCart.jar
ejbjar 產生 ShoppingCart.jar
run.ShoppingCartClient 執行 Client 測試程式 ShoppingCartClient


點選 build -> Run As -> 2. Ant Build
Eclipse Console 輸出為
[java] Buying 1st Cake
[java] Buying 2nd Cake
[java] Buying 1st Bread
[java] Print cart list on client:
[java] 1 Bread
[java] 2 Cake
[java] Checkout
[java] Should throw an object not found exception by invoking on cart after @Remove method
[java] Successfully caught no such object exception.

如下圖所示:


JBoss Console 輸出為
18:09:03,714 INFO [STDOUT] Print cart list on server:
18:09:03,714 INFO [STDOUT] 1 Bread
18:09:03,714 INFO [STDOUT] 2 Cake
18:09:03,714 INFO [STDOUT] Checked Out

如下圖所示:


這次 JBoss EJB3 Stateful Session Beans 教學己到了終點.
正籌備 Entity Beans , Message Driven 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

沒有留言: