程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用CMP2和XML處理動態數值對象

使用CMP2和XML處理動態數值對象

編輯:關於JAVA

在EJB 2.0局部引用和容器管理關系出現之前,通常把實體EJB用於模型粗粒度域對象。這主要是由於與遠程通信有關系統開銷並阻止了細粒度訪問企業層的客戶層對象。粗粒度設計的性能通過實現數值對象而促進改善,壓縮所有的數據也就是說在客戶層和企業層之間傳遞數據。使用有大量域對象的復雜系統,即使這麼樣能提供一個第一流的和高度執行設計,這個設計導致在系統內出現過多的數值對象。這同樣也創建在企業層和客戶層之間的緊密連接。同樣,在EJB出現之間,bean提供者不得不明確地提供用於維護域對象之間聯接的程序。在一個有在域對象之間的復雜關系的情況中,數值對象的設計變得很復雜。在使用EJB開發企業應用程序的過程中,容器管理關系和局部引用的出現開啟了令人興奮的新途徑。在本文中,我將帶你使用EJB 2.0的強大方法連同bean組件和JAXP創建動態的基於數據結構的XML,可以在你的企業層和表現層之間傳遞信息。

從企業層到客戶層傳遞數據的過程中使用XML,可以幫助你實現在的應用程序中的多種寬松連接;然而,當你把新的域對象添加到實體型中時,你可能需要添加用於創建新DOM構架的類來添加該實體。在文中,我們將開發一個框架來動態地遍歷容器管理和給定的局部EJB有關的域,並且創建一個可以在應用程序的多個層之間傳遞的XML件。這個方法將有以下優點∶

在企業層和客戶層之間促進寬松連接。

便於管理域對象之間關系。

從系統中除去復雜數值對象因為XML是由動態地遍歷CMP和CMR域產生的,當它們添加新對象到域模型中時,bean提供者不必創建新的用來創建新的DOM構架的對象類。

EJB 2.0局部引用促進訪問bean組件;bean組件與局部引用結合可以含於與其他的被容器管理的bean的關系。舉例來說,在一個幫助系統中,UserEJB可以有與ServiceRequestEJB的一到多雙向關系和與ProductEJB的一到一的單向聯系以及與ServiceRequestHistoryEJB的一到的雙向關系。UserEJB同時可以有與PhoneEJB一到多的雙向關系。這樣,使用EJB 2.0局部引用和容器管理關系,你可以設計一套復雜的有關體。容器管理持久性和關系域是在bean類中使用抽象存取程序方法定的。用於關系域的存取程序方法要麼返回一個集合要麼返回定義這個系的bean的本機接口,這還取決於這個關系集的容量。這些存取程序法可以通過bean組件的本機接口展示。EJB 2.0的深入研究超出了本文范圍,請參閱EJB 2.0的規范。

一個效率高的設計模式應該通過外觀組件展示你的應用程序的使用案例並且不准從客戶層中直接訪問實體組件。回到我們的幫助系統的例子中來,其中的一個使用案例是取得給定用戶的詳細資料。外部組件可以查找需要的用戶實體組件,並且通過容器管理持久性與關系域取得所需數據並把它返回表現層。

用於數據傳送對象的一個顯而易見的選擇就是簡單的Java bean。UserBean可能有表示持久性與關系域的屬性。這種關系域要麼是java.util.Collection要麼是其他的取決於這種關系的bean組件。UserBean可能有ServiceRequestBean和PhoneBean集。ServiceRequestBean可能有一個ProductBean和許多ServiceRequestHistory bean組件。此外,這些bean組件還可能還有簡單的String或者表現容器管理持久性域的基本屬性。這個選擇的主要的不利之處就是使你的實體模型更加復雜,使你的數據傳送對象bean層次更加復雜,還將在你的服務(企業)層和消費(表現)層之間創建緊密連接。研究一下這個關系的復雜的層次,一個更好的選擇是使用XML DOM對象作為數據傳送對象。你的組件將產生oeg.w3c.dom.Document對象類型並且你的表現組件使用XML的JSP自定義標記和XSLT文件來“消費”它們。

現在,下一個問題是∶怎麼從CMP局部bean引用中創建XML文件?我們可以使用一個基於用於創建不同的類型的DOM組件的方法的工廠;然而,這將創建過多的“工場”組件,並且你可能需要添加新的"工場"組件作為你的實體模型擴展。我們需要的是一個可以使用實體局部對象,引導容器管理關系和創建動態DOM構架的公用程序。這個公用程序將負責在雙向關系中循環引用,以避免無限的循環和深入導航關系元素。

接下來我們將演示一個可以提供這個功能的公用程序類。

package ws.business.service.util;
導入JAXP類。
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
導入DOM類
import org.w3c.dom.Document;
import org.w3c.dom.Element;
導入EJB類
import javax.ejb.EJBLocalObject;
導入Collection類。
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
導入bean內省類。<0}
import java.beans.Introspector;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.beans.IntrospectionException;
導入reflection類
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class DOMGenerator {
生成的文件
private Document doc;
用戶定義的深度∶
private int drillDownDepth;
存儲循環引用的私有實例變量∶
private ArrayList _circularRef = new ArrayList();
存儲當前深度的私有實例變量∶
private int _currentDepth;
方法getEJBLocalHome,getLocalHandle,getClass和getPrimaryKey不必
被處理。
private static String RESERVED =
"EJBLocalHome^localHandle^class^primaryKey";
   public DOMGenerator(String docElementName, int drillDownDepth) {
   try {
使用標准JAXP調用來創建一個DOM並把它存儲為一個實例變量。
DocumentBuilderFactory fact =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = fact.newDocumentBuilder();
doc = builder.newDocument();
}catch(ParserConfigurationException ex) {
throw new RuntimeChainedException(ex);
}
存儲drilldown深度。
this.drillDownDepth = drillDownDepth;
以用戶定義的名稱創建文件元素。
doc.appendChild(doc.createElement(docElementName));
   }
創建傳遞DOM的局部引用的方法。
   public Document getDOM(EJBLocalObject local) {
   try {
調用把容器管理持久性與關系域填充到元素中以便傳遞局部引用的方
法。
populateElement(doc.getDocumentElement(), local);
返回DOM。
return doc;
}catch(IntrospectionException ex) {
throw new RuntimeException(ex.getMessage());
   }catch(IllegalAccessException ex) {
throw new RuntimeException(ex.getMessage());
}catch(InvocationTargetException ex) {
throw new RuntimeException(ex.getMessage());
}
   }
   private void populateElement(Element parent, EJBLocalObject local)
throws
IntrospectionException, IllegalAccessException,
InvocationTargetException
{
   把當前的局部引用添加到連接引用列表中。
_circularRef.add(local);
增加當前的drilldown深度。
_currentDepth++;
取得當前的局部引用的bean組件信息。
BeanInfo info = Introspector.getBeanInfo(local.getClass());
取得屬性描述信息列表並重復數組。
PropertyDescriptor properties[] = info.getPropertyDescriptors();
   for(int i = 0;i < properties.length;i++) {
取得屬性讀取方法。
Method propReadMethod = properties[i].getReadMethod();
取得屬性名稱。
String propName = properties[i].getName();
使用映射取得屬性值。
Object prop = propReadMethod.invoke(local, null);
跳過保留屬性。
if(RESERVED.indexOf(propName) >= 0)
continue;
   try {
嘗試把屬性強制轉化為EJB局部引用。請注意你不能使用instanceof,因
為從容器到容器使用instanceof,實現可能有差異。
EJBLocalObject locProp = (EJBLocalObject)prop;
如果局部引用已經在連接引用的列表中可用或者當前的drilldown深度
已經大於設置的drilldown深度那麼就跳出處理過程。
if(isCircularRef(locProp) || _currentDepth >=
drillDownDepth)
continue;
由屬性創建一個元素。
Element child = doc.createElement(propName);
populateElement(child, locProp);
把新創建的子元素添加到父元素中。
parent.appendChild(child);
   }catch(ClassCastException ex1) {
   如果拋出一個ClassCastException,就要試著把屬性強制轉換成Collection
局部引用類型。請注意你不能使用instanceof,因為從容器到容器使用
instanceof,實現可能有差異。
try {
   Collection colProp = (Collection)prop;
   如果當前的drilldown深度大於設置的drilldown深度,跳出處理。
if(_currentDepth >= drillDownDepth) continue;
創建一個壓縮collection的子元素。
Element child = doc.createElement(propName);
Iterator it = colProp.iterator();
   while(it.hasNext()) {
   得到collection中的每個局部引用。
EJBLocalObject locProp =
(EJBLocalObject)it.next();
如果局部引用已經在連接引用的列表中可用或者當前的drilldown深度
已經大於設置的drilldown深度那麼就跳出處理過程。
if(isCircularRef(locProp)) continue;
創建一個能包含用於這個collection中當前的局部引用持久性與關系信
息的元素,然後把它添加到表現這個collection的元素中。
Element grandChild =
doc.createElement(propName +
"-child");
   child.appendChild(grandChild);
   populateElement(grandChild, locProp);
   }
parent.appendChild(child);
   }catch(ClassCastException ex2) {
   如果拋出一個ClassCastException的話,屬性是一個持久性域並且要把它
的值添加為當前節點的值。
parent.setAttribute(propName, prop.toString());
}
   }
   }
從列表中移走當前的局部引用。
_circularRef.remove(local);
遞減當前的drilldown深度。
_currentDepth--;
   }
這是一個公用程序方法,用來檢查一個引用是否已經在連接引用列表
中。
private boolean isCircularRef(EJBLocalObject local) {
   Iterator it = _circularRef.iterator();
while(it.hasNext())
if(local.isIdentical((EJBLocalObject)it.next())) return true;
return false;
   }
   }

下面的代碼片斷演示如何使用這個類:

User local = userHome.findByPrimaryKey("1");
return new DOMGenerator("user", 4).getDOM(local);
下面演示的這段生成的DOM取決於你的實體模型∶
<?xml version="1.0" encoding="UTF-8"?>
<user firstName="Wayne" id="1" lastName="Zheng">
   <requests>
quests-child description="Outlook not working" id="2"
status="P">
<product description="Install Laptop" id="1"
name="SVC01"/>
</requests-child>
<requests-child description="PC not booting" id="1" status="O">
<histories>
<histories-child description="Informtion requested"
id="2"
loggedAt="2002-4-7 12:12:12.0"/>
<histories-child description="Request logged" id="1"
loggedAt="2000-4-7 00:00:00.0"/>
</histories>
<product description="Install Laptop" id="1"
name="SVC01"/>
</requests-child>
</requests>
   <phones>
<phones-child id="2" number="0771 8210586" type="M"/>
<phones-child id="1" number="01908 251575" type="W"/>
</phones>
   </user>

在本文中,我們詳細研究了一個模型用於在一個J2EE應用程序的企層和表現層之間傳遞復雜數據。表現層可以交付XML數據,這些數據在企業層上生成的,被使用XSLT或者XML JSP自定義標記交付到客設備上。

當你添加新的定義到你的域模型中的時候,你唯一需要做的事情就是使用精細局部實體bean定義,然後使用容器管理關系定義關系。DOM生成程序提供一個一般的方法生成動態的XML文件。

然而,就象任何其他的設計方案,這個方法也有它的缺點。一個明顯的方面就是開發人員經常擔心基於XML的數值對象的性能。在一台1GHz CPU, 256MB內存,操作系統為Windows ME的機器中,運行應用軟件服務器(WLS 6.1)和數據庫服務器,上述對一千條紀錄的記錄集的操作以及處理多元聯系用了不到0.5秒鐘。第二個明顯的方面就是類型安全性。因為XML提供了數據抽象化的最高級別,屬性的結點值和文本節點總是被當做字符串。如果你打算在從企業層上檢索回來的數值對象上進行進一步的事務操作的話,最好就使用Java bean組件。然而,XML模式提供了一個功能強大的機制,用於加強XML文件的類型安全性。在兩種情況下都要使用局部實體對象作為域對象。

這個方法最大的缺點就是沒有模型化基於XML數據的明確定義的方法。我還沒有看見過任何模型化使用XML的域對象關系的UML注釋或者通用的規范定義。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved