EJB 是 Sun 的服務器端組件模型,最大的用處是部署分布式應用程序。憑借 Java 跨平台的優勢,用 EJB 技術部署的分布式系統可以不限於特定的平台。EJB 3.0 規范使 EJB 的開發變得更加容易,也獲得了越來越多企業級用戶的青睐。在 WebSphere 應用服務器 7.0 中提供了更多對 EJB 3.0 和 EJB 2.1 的支持 , 用戶可以很容易的通過 WPS 7 新特性 EJB export binding 將自己的 SCA 服務發布為一個 EJB service 而再不用由程序員自己進行一系列繁瑣的 EJB 開發。本文結合 WebSphere 裡的開發工具 WID 7 通過一個具體的實例一步步的教導讀者如何進行 EJB export binding service 的開發,同時介紹了在 Websphere Process Server 7 中 EJB binding 相關新特性。相信本文對於准備采用 EJB 發布自己 SCA 服務的編程相關人員有一定幫助。
引言
EJB 是 Sun 的服務器端組件模型,最大的用處是部署分布式應用程序。憑借 Java 跨平台的優勢,用 EJB 技術部署的分布式系統可以不限於特定的平台。EJB 3.0 規范使 EJB 的開發變得更加容易,也獲得了越來越多企業級用戶的青睐。
WebSphere 應用服務器 7.0 提供了更多對 EJB 3.0 和 EJB 2.1 的支持 , 用戶可以很容易的通過 WPS7 版本的新特性 EJB export binding 將自己的 SCA 服務發布為一個 EJB service 而再不用由程序員自己進行一系列繁瑣的 EJB 開發。WPS7 版本支持 Remote 和 Local 兩種 EJB 接口,遵循 EJB3.0 及 EJB2.1 兩種規范,用戶可以根據自身業務的需求采用對應的 EJB 服務。本文結合國內企業級應用中的典型業務需求,通過實現一個簡單的由動態 Web 客戶端調用的 EJB 回顯 SCA 服務來一步步的教導讀者如何利用 WID7 進行 EJB export binding service 的開發,在文末還介紹了如何在運行時配置和查看所部署的 EJB 服務相關屬性,最後總結了在 Websphere Process Server 7 中 EJB export binding 的相關新特性。
EJB Service 方案描述
本文中使用的方案相當典型。它由一個服務組件體系結構(Service Component Architecture,SCA)模塊構成,該模塊包含一個 Java 組件,而該 Java 組件將通過 EJB3.0 export binding 被發布為一個 EJB3.0 service. 在本文案例中,我們將搭建一個 Echo( 回顯 ) 系統,用戶在終端界面輸入顧客 ID 和顧客地址等相關信息,進入 EJB service 後,系統將其輸入信息打印至終端界面並返回相應顧客對象。系統架構如下圖示:
圖 1. EJB service 系統架構圖
開發和測試步驟包括:
創建業務相關對象及接口。
創建由 Java 組件實現的 SCA 回顯服務。
根據案例需求為該 SCA 回顯服務生成相應 EJB 輸出綁定。
構建動態 Web 客戶端按照步驟 3 生成的 EJB 輸出綁定所對應的 JNDI 名來調用步驟 2 所創建的 SCA 回顯服務。
從 WID7 中導出相應應用,安裝並部署到 WPS7 服務器,啟動該 EJB 應用。
鍵入相應 URL 地址以觸發該 EJB 應用,從而訪問對應 SCA 回顯服務。
下圖為在 WID7 中所構建的本文案例模塊概況:
圖 2. 案例模塊概況
下面,筆者將一步步引導讀者打造一個屬於自己的 EJB service
業務數據及接口建模
打開 WebSphere Integration Developer 7.0,確保進入“業務集成”(Business Integration)透視圖。在該透視圖中創建一個模塊(Module),取名為 MyEJBService,下面將在這個模塊中創建該服務所需的數據模型和業務邏輯等。
創建業務對象(Business Object)
首先,為服務創建業務對象,這裡根據場景的需求,將創建一個名為 customer 的業務對象,包括 customer id, home address, email 等一系列顧客信息,如下圖:
圖 3. Customer 業務對象
定義接口
本例中我們定義了一個名為 EJB3RemoteTwoWay 的 Interface, 它的輸入輸出均為業務對象 Customer。
圖 4. 接口定義
創建顧客回顯 SCA service
在 Module “MyEJBService”的業務集成視圖中,創建一個 Java POJO, 命名為 “CustomerEchoService”,並選用接口“EJB3RemoteTwoWay”作為其 Interface.
在該 Java POJO 中,寫入如下代碼完成在系統輸出中打印對應 customer 信息的工作:
清單 1. Customer Service 的代碼片斷
try {
String cus_id = input.getString("cust_id");
xmlSerializer.writeDataObject(
input, input.getType().getURI(), input.getType().getName(), System.out);
System.out.println("Received Customer ID is : " + input.getString(0));
System.out.println("Received Customer Addr is :
" + input.getDataObject(1).get(0));
System.out.println("Received Customer Email is : " + input.getString(2));
}
catch (IOException e) {
e.printStackTrace();
}
return input;
這段代碼首先獲取 customer 的 ID,然後再打印出對應的顧客 ID 以及地址和 Email 信息,最後返回客戶信息。這是一個典型的 Echo ( 回顯 ) 服務。
生成對應 EJB Export Binding
在 Module “MyEJBService”的業務集成視圖中,選中 Java POJO “CustomerEchoService”,點擊右鍵,選擇“Generate Export” -> “Enterprise JavaBeans Binding”(如下圖):
圖 5. 生成 EJB Export Binding
在隨後彈出的 EJB export binding 對話框中,選中”Create an EJB client JAR module”, 在”Name”一欄中點擊”New …”選鍵,並輸入你所想要創建的 EJB Client 的名字,再此,我們將它命名為”EJB3RemoteClient”。在選項”EJB interface type”中,可根據用戶自身的需要選擇使用”Local”或”Remote”, WID 會根據用戶的選擇對應的生成 Local 或者是 Remote 的 EJB service. 在本文案例中,我們選擇采用”Remote”的 EJB service. 在選項“EJB session bean version”中,用戶可以根據自身需要選擇采用 EJB 3.0 或者 EJB 2.1 規范,產品也將根據用戶的選擇,對應的生成 EJB 3.0 或者 EJB 2.1 的 service. 在本文案例中,我們采用 EJB 3.0 version。
圖 6. EJB export binding 對話框
都配置好之後,點擊”Finish”鍵,這時,WID 將根據用戶的選擇生成相應的 EJB export binding。 打開業務集成板塊,我們發現,界面上已經多了一個 EJB export binding 了。
那麼,我們該如何調用這個 EJB service 呢?
在業務集成界面,選中生成的 EJB export, 再單擊 Properties -> Binding, 我們可以看到有三個屬性,分別為”JNDI name”, ”Data Handler Type”, ”Function Selector”
圖 7. EJB export binding 屬性欄
在我們將此應用部署到 WPS7 server 上後,用戶可以采用任何調用 EJB 服務的方式根據該 JNDI 名來訪問此 EJB export service。
構建動態 Web Project 客戶端調用 EJB Service
在本文案例中,我們將構建一個動態 Web Project 來調用我們從 Java 組件中生成的 EJB3.0 Remote Export Binding Service。
首先,選中 File -> New -> Other, 在彈出的對話框中選中”Dynamic Web Project”, 點擊”Next”。(見下圖)
圖 8. 生成 Dynamic Web Project
按照下圖所示配置該動態 Web Project:
圖 9. 配置 Dynamic Web Project
在生成的 Java Resources/src 文件夾下,新建一個 Java 類 “EJBExportInvoker”, 並寫入如下代碼以調用前面所創建的 EJB3.0 Remote Export Binding:
清單 2. EJB Export Invoker Class 的代碼片斷
try{
String jndiName = "
li1627uc14075ejb3remotewsdltwowayexport.ejb3remotetwoway.binding.EJB3RemoteTwoWayRemote
";
Context initialContext = newInitialContext();
java.lang.Object ejbBusIntf = initialContext.lookup(jndiName);
System.out.println(ejbBusIntf);
System.out.println(ejbBusIntf.getClass());
System.out.println(ejbBusIntf.getClass().getName());
EJB3RemoteTwoWay busI = (EJB3RemoteTwoWay) javax.rmi.PortableRemoteObject
.narrow(ejbBusIntf, EJB3RemoteTwoWay.class);
System.out.println(busI);
System.out.println(busI.getClass());
System.out.println(busI.getClass().getName());
Customer customer = newCustomer();
customer.setCustId("custId-" + input);
customer.setEmail("email-" + input);
Address address = newAddress();
address.setAddressId("addressId-" + input);
address.setAddressType(newInteger(100));
customer.setHomeAddress(address);
Customer response = busI.e3Remotetwoway(customer);
if(response != null) {
if(customer.getCustId().equals(response.getCustId())
&& customer.getEmail().equals(response.getEmail())
&& (response.getHomeAddress() != null&& (customer
.getHomeAddress().getAddressId().equals(
response.getHomeAddress().getAddressId()) && customer
.getHomeAddress().getAddressType().equals(
response.getHomeAddress().getAddressType())))) {
System.out.println("@@@@@@@@@@@Response success!");
} else{
System.out.println(response.getCustId());
System.out.println(response.getEmail());
System.out.println(response.getHomeAddress().getAddressId());
System.out.println(response.getHomeAddress().getAddressType());
}
} else{
System.out.println("@@@@@@@@@@@@@@response is null!!!");
}
System.out.println("===================>> end of client");
} catch(NamingException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
這段代碼首先會根據前面所創建的 EJB 服務的 JNDI 名用代碼 initialContext.lookup(jndiName)來查找其所對應該 Service 的對象,隨後再用代碼 (EJB3RemoteTwoWay) javax.rmi.PortableRemoteObject.narrow(ejbBusIntf,EJB3RemoteTwoWay.class)
來獲得該 EJB Service 所對應的業務接口(在本文案例中為 EJB3RemoteTwoWay), 也就是前面定義 EJB3.0 Remote Export Binding 時所采用的接口。然後,再用代碼 busI.e3Remotetwoway(customer)來調用該 EJB3.0 Export Binding 服務。
在 WebContent 目錄下,新建 JSP 文件 EJBTest.jsp 作為用戶輸入終端界面,並寫入如下代碼:
清單 3. EJB Test JSP 的代碼片斷
<%@ page language="java"contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type"content="text/html; charset=ISO-8859-1">
<title>Test invoke EJB export</title>
</head>
<body>
<form action="TestInput.jsp"method="get">
<fieldset><legend>Enter Customer Info: </legend>
<br>Customer Info <input type="text"name="cusInfo">
</fieldset>
<input type="submit"value="submit"><br>
</form>
<%
/**
* Set request character encoding and response caracter encoding to UTF-8
* It must be put ahead the jsp file.
* Since if any characters have been printed on page,
* the encoding set action will be no use.
*/
try{
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
}catch(java.lang.Exception e){
e.printStackTrace();
}
%>
<%
try{
String tcInput=request.getParameter("cusInfo");
if(tcInput != null) {
EJBExportInvoker.invokeEJB3RemoteWsdlTwoWayExport(tcInput);
}
} catch(Exception e){
out.println("UnExpectedException: " + e.getMessage());
e.printStackTrace(System.out);
}
%>
</body>
</html>
該 JSP 界面如下示:
圖 10. Test JSP 界面
用戶在”CustomerInfo”欄中鍵入顧客信息如 email 地址等,並點擊“Submit”, 那麼 JSP 就會通過 EJBExportInvoker 來訪問 JNDI 名為 “li1627uc14075ejb3remotewsdltwowayexport.ejb3remotetwoway.binding.EJB3RemoteTwoWayRemote” 的 EJB Service, 也就是我們前面所生成的 EJB3.0 Remote Export Binding 所連接的 SCA service。
運行時部署及配置
首先,從 WID V7 中導出 ear 文件”MyEJBServiceApp.ear”, 並將它安裝在 WPS V7 runtime server 上,啟動該應用後就可以進行 EJB export binding 測試了。打開網址 http://localhost:9080/EJBWebClient/EJBTest.jsp , 將會看到如下界面:
圖 11. 運行時測試界面
輸入 [email protected]作為用戶信息,並提交。在系統輸出中,我們將看到如下信息:
清單 4. Runtime 測試系統輸出
[1/7/10 11:38:47:406 CST] 0000003b SystemOut
O ===========================>>[email protected]
[1/7/10 11:38:47:687 CST] 0000003b SystemOut
O <?xml version="1.0" encoding="UTF-8"?>
<p:Customer xsi:type="p:Customer"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://LI1627UC14075EJB3RemoteWSDLExport">
<cust_id>[email protected]</cust_id>
<home_address>
<address_id>[email protected]</address_id>
<address_type>100</address_type>
</home_address>
<email>[email protected]</email>
</p:Customer>
[1/7/10 11:38:47:687 CST] 0000003b SystemOut
O Received Customer ID is : [email protected]
[1/7/10 11:38:47:687 CST] 0000003b SystemOut
O Received Customer Addr is : [email protected]
[1/7/10 11:38:47:687 CST] 0000003b SystemOut
O Received Customer Email is : [email protected]
[1/7/10 11:38:47:703 CST] 0000003b SystemOut
O @@@@@@@@@@@Response success!
[1/7/10 11:38:47:703 CST] 0000003b SystemOut
O ===================>> end of client
這表明我們已經通過 EJBTest.jsp 客戶端成功調用了由 EJB3.0 Remote Export Binding 所發布的 SCA 客戶回顯服務。
如果用戶想要在運行時查詢由 EJB export binding 所發布服務的信息如 JNDI 等,可以登陸 WPS 服務器控制台,導航至 “Application Types -> SCA modules -> MyEJBService -> Module components -> Exports -> EJB Export -> Binding -> EJB” (如下圖):
圖 12. EJB Export Runtime 配置界面
點擊 ”EJB” 鏈接,就可以看到所有與此 EJB 綁定相關的信息了:
圖 13. EJB Export Runtime 信息
結束語
本文向您介紹了 WPS7.0 中的新功能 EJB Export Binding (EJB 輸出綁定 ),您可以根據自己業務的需要將任意 SCA 服務在 WID7 中生成相應 EJB 輸出綁定並發布至 WPS7 服務器,從而輕松搞定屬於您自己的 EJB 服務。WPS7 支持 Remote 和 Local 兩種 EJB 接口,遵循 EJB3.0 及 EJB2.1 規范,您可以通過 EJB 輸出綁定對話框來隨意搭配和選擇您所需要的 EJB 服務。
在本文中筆者通過一個具體的實例客戶回顯服務展示了如何開發及配置 EJB 綁定,從而使讀者在實現本例的過程中了解了 EJB 輸出綁定,動態 Web 客戶端等用法。希望這些知識對您今後的實踐有所幫助。