WEB开发网
开发学院软件开发Java 利用 Eclipse Modeling Framework 加强 JAX-RPC 类... 阅读

利用 Eclipse Modeling Framework 加强 JAX-RPC 类型映射的功能

 2009-12-17 00:00:00 来源:WEB开发网   
核心提示:引言JAX-RPC,也称为 JSR-101,利用 Eclipse Modeling Framework 加强 JAX-RPC 类型映射的功能,是完成标准编程模型的一个重要步骤,该标准编程模型简化了 Java™ 平台上可互操作的 Web 服务的构建,那么您将具有一个单用户许可证,可以使用 WebSphere

引言

JAX-RPC,也称为 JSR-101,是完成标准编程模型的一个重要步骤,该标准编程模型简化了 Java™ 平台上可互操作的 Web 服务的构建。由 XML 向 Java 类型映射模型的转换是 JAX-RPC 的关键,该转换是 Web 服务产品提供者的一个实现标准。没有这样的模型,Web 服务产品提供者会陷入定义专用类型映射的陷阱中,从而严重影响 Java 的互操作性问题。

虽然 JAX-RPC 在支持 XML 数据类型方面做了大量的工作,但是还有很多地方需要改进。而且,JAX-RPC 需要将任何不被支持的 XML 数据类型映射到 javax.xml.soap.SOAPElement 接口。javax.xml.soap.SOAPElement 接口没有为用户提供强类型的 Java 模型,也就是说用户必须编写自定义代码,然后通过 SOAPElement 实例来解析。这对初学者来说比较难,特别是当处理大的 XML 片段的时候。本文演示了如何使用 EMF 来支持没有标准 JAX-RPC 类型映射的 XML 数据类型。使用不支持 XML 数据类型的 JAX-RPC 生成 Web 服务并非易事,但是本文把 Web 服务工具和 IBM® WebSphere® Studio Application 以及 Site Developer V5.1.2 (Application and Site Developer) 中的 EMF 工具结合起来使用,提供了一个有效的解决方案。

创建供应链 Web 服务

要实现本文所介绍的方法,必须安装 WebSphere Application 和 Site Developer V5.1.2。如果需要的话,可以下载一个 60 天的试用版。

创建一个 Web 项目。单击菜单File>New>Project...>Web > Dynamic Web Project>Next,打开 New Dynamic Web Project wizard。

输入SupplyChainWeb作为 Web 项目的名称,选中Configure advance options复选框,然后单击Next。

输入SupplyChainEAR作为 EAR 项目的名称,然后单击Finish。

单击本文顶部的Code图标,下载 SupplyChainService.wsdl 和 SupplyChainSchema.xsd 到本地文件系统中。

将 SupplyChainService.wsdl 和 SupplyChainSchema.xsd 导入或复制到 SupplyChainWeb 项目的根目录下。

在 navigator 视图中,右键单击SupplyChainService.wsdl>Web Services>Generate Java bean skeleton打开图 1所示的 WSDL to Java Bean Skeleton wizard。该向导生成一个基于 WSDL 文档中定义的信息的 Java 架构代码实现。接受所有的默认设置,然后单击Finish。
图 1.WSDL to Java Bean Skeleton wizard
利用 Eclipse Modeling Framework 加强 JAX-RPC 类型映射的功能

向导完成之后,您会在 tasks 视图中看见一些 WSDL 验证错误,这是由于 XML 模式文件 (SupplyChainSchema.xsd) 没有被复制到正确的地方。要更正这些错误,将 SupplyChainSchema.xsd 从 SupplyChainWeb 项目的根目录下复制到 /SupplyChainWeb/WebContent/WEB-INF/wsdl/ 和 /SupplyChainWeb/WebContent/wsdl/com/example/supplychain/www/ 这两个目录中。右键单击SupplyChainService.wsdl>Run validation,再次运行验证。

创建供应链 EMF 模型

WSDL to Java Bean Skeleton wizard 生成带一个或多个映射到 SOAPElement (具体的,PurchaseOrderType.java、PurchaseReferenceType.java 以及 ShippingNoticeType.java)属性的 JavaBean。在本部分中,将生成一个供应链 Web 服务的 EMF 模型来支持映射到 SOAPElement 的 XML 数据类型。

创建一个 EMF 项目。单击菜单File>New>Project...>Eclipse Modeling Framework>EMF Project>Next,打开 New EMF Project wizard。

输入SupplyChainEMF作为项目的名称,然后单击Next。

选择Load from an XML schema,然后单击Next。

单击Browse Workspace...打开文件选择对话框。查找并选择SupplyChainSchema.xsd,然后单击OK。单击Next。

选择supplychain包,然后单击Finish。参阅图 2。
图 2.New EMF Project wizard
利用 Eclipse Modeling Framework 加强 JAX-RPC 类型映射的功能

New EMF Project wizard 完成后,系统将打开 EMF Generator Editor。在这个编辑器中,右键单击SupplyChainSchema节点,选择Generate Model Code。您已经成功生成了供应链 EMF 模型。在下一部分中,将学习如何将 EMF 代码集成到供应链 Web 服务中。

集成供应链 Web 服务与 EMF 模型

为 SupplyChainWeb 项目设置所有的依赖关系。将 SupplyChainEMF 项目添加到 SupplyChainEAR 作为一个实用的 JAR 文件,并指定从 SupplyChainWeb 项目到该实用 JAR 文件的 JAR 文件依赖性。

在应用程序部署描述编辑器 (Application Deployment Descriptor Editor) 中打开 /SupplyChainEAR/META-INF/application.xml。单击Module选项卡。

在 Project Utility JARs 栏中,单击Add...,选择SupplyChainEMF,然后单击Finish。保存并关闭应用程序部署描述编辑器。

在 JAR Dependency Editor 中打开 /SupplyChainWeb/WebContent/META-INF/MANIFEST.MF。在 Dependencies 栏中选择SupplyChainEMF.jar。保存并关闭应用程序部署描述编辑器。

将 EMF 库添加到 SupplyChainWeb 项目的 Java 构建路径中。右键单击SupplyChainWebproject >Properties>Java Build Path。单击Libraries选项卡,选择Add Variable...。

选择EMF_COMMON、EMF_ECORE 以及 EMF_ECORE_XMI。单击OK>OK。

清单 1显示了用到的所有导入语句。在 Java 编辑器中打开 /SupplyChainWeb/JavaSource/com/example/supplychain/www/SupplyChainBindingImpl.java 并添加这些导入语句。


清单 1.导入语句
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.util.List; 
import java.util.Random; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.soap.SOAPElement; 
import javax.xml.soap.SOAPException; 
import javax.xml.soap.SOAPFactory; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerConfigurationException; 
import javax.xml.transform.TransformerException; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 
import org.eclipse.emf.common.util.URI; 
import org.eclipse.emf.ecore.EObject; 
import org.eclipse.emf.ecore.resource.Resource; 
import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.xml.sax.SAXException; 
import com.example.supplychain.ItemType; 
import com.example.supplychain.PaymentMethodType; 
import com.example.supplychain.ProcessingType; 
import com.example.supplychain.ShippingItemType; 
import com.example.supplychain.StatusType; 
import com.example.supplychain.SupplychainFactory; 
import com.example.supplychain.SupplychainPackage; 
import com.example.supplychain.impl.SupplychainPackageImpl; 
import com.example.supplychain.util.SupplychainResourceFactoryImpl; 


使用生成的供应链 EMF 模型之前必须先初始化。初始化过程在 XML 模式 (SupplyChainSchema.xsd) 中声明的元素和 EMF 代码生成器创建的 Java 类之间建立了一个映射。该映射用于 XML 片段与相应的基于 EMF 的 Java 类之间的相互转换。要初始化供应链 EMF 模型,将下面的静态代码块添加到 SupplyChainBindingImpl.java 中。


清单 2.初始化 EMF 包
static 
{ 
 SupplychainPackageImpl.init(); 
} 


接下来,在 SupplyChainBindingImpl.java 中添加 4 个方法,这些方法将 SOAPElement 转换为 DOMElement,然后再转换为相应的基于 EMF 的 Java 类,也可以反过来转换。清单3、4、5以及6 显示了这些方法。 soapElement2DOMElement(SOAPElement soapElement) 方法和 domElement2SOAPElement(Element e) 方法利用两个特定于应用程序和站点开发者实现的方法: getAsDOM() 和 setAlternateContent(e) ,来负责 SOAPElement 到 DOMElement 的转换。要从特定于提供商的代码中清除这些方法,可以手动的遍历 SOAPElement 并构造相应的 DOMElement。

在本文中,可以使用现成的方法,也就是说,可以使用应用程序和站点开发者实现提供的方法。事实上,如果 SOAP 附带了 Java V1.2 (SAAJ)- 兼容实现的附加 API 函数,那么就不再需要将 SOAPElement 转换为 DOMElement,这是因为 SAAJ V1.2 需要 SOAPElement 以直接扩展 DOMElement。


清单 3.将 SOAPElement 转换为 DOMElement
public Element soapElement2DOMElement(SOAPElement soapElement) 
throws Exception 
{ 
 return ((com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapElement).getAsDOM(); 
} 



清单 4.将 DOMElement 转换为 EMF 对象
public EObject domElement2EObject(Element e) 
throws TransformerConfigurationException, TransformerException, IOException 
{ 
 DOMSource domSource = new DOMSource(e); 
 Transformer serializer = TransformerFactory.newInstance().newTransformer(); 
 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
 serializer.transform(domSource, new StreamResult(baos)); 
 byte[] b = baos.toByteArray(); 
 System.out.println(new String(b)); 
 URI uri = URI.createURI(SupplychainPackage.eNS_URI); 
 SupplychainResourceFactoryImpl factory = new SupplychainResourceFactoryImpl(); 
 Resource res = factory.createResource(uri); 
 ByteArrayInputStream bais = new ByteArrayInputStream(b); 
 res.load(bais, null); 
 List contents = res.getContents(); 
 return (!contents.isEmpty()) ? (EObject)contents.get(0) : null; 
} 



清单 5.将 EMF 对象转换为 DOMElement
public Element eObject2DOMElement(EObject eObject) 
throws IOException, ParserConfigurationException, SAXException 
{ 
 URI uri = URI.createURI(SupplychainPackage.eNS_URI); 
 SupplychainResourceFactoryImpl factory = new SupplychainResourceFactoryImpl(); 
 Resource res = factory.createResource(uri); 
 res.getContents().add(eObject); 
 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
 res.save(baos, null); 
 byte[] b = baos.toByteArray(); 
 System.out.println(new String(b)); 
 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); 
 DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); 
 Document doc = docBuilder.parse(new ByteArrayInputStream(b)); 
 return doc.getDocumentElement(); 
} 



清单 6.将 DOMElement 转换为 SOAPElement
public SOAPElement domElement2SOAPElement(Element e) 
throws SOAPException 
{ 
 SOAPFactory soapFactory = SOAPFactory.newInstance(); 
 com.ibm.ws.webservices.engine.xmlsoap.SOAPElement soapElement = 
  (com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapFactory.createElement( 
  "temp"); 
 soapElement.setAlternateContent(e); 
 return soapElement; 
} 


全局元素和局部元素

正如前面所提到的,供应链 EMF 模型依靠映射到 Java 的元素将 XML 片段转换为相应的基于 EMF 的 Java 类。但是,默认的情况是,EMF 代码生成器只为全局元素生成映射条目,而不为局部元素生成。全局元素是 XML 模式文档中作为模式元素的子元素来声明的元素,而局部元素却不是。默认的映射清单不包括局部元素,因此,供应链 EMF 模型不能转换描述局部元素实例的 XML 片段。研究一下清单 7中的示例 XML 模式。相应的 EMF 模型识别清单 8中的全局元素实例。相反,清单 9中的局部元素实例却导致异常。要支持局部元素的转换,必须在 Java 映射中添加自定义元素。


清单 7.XML 模式示例
<schema> 
 <element name="GlobalElement"> 
  <complexType> 
   <sequence> 
    <element name="LocalElement" type="xsd:string"/> 
   </sequence> 
  </complexType> 
 </element> 
</schema> 



清单 8.全局元素实例
<GlobalElement> 
 <LocalElement>Some String</LocalElement> 
</GlobalElement> 



清单 9.局部元素实例
<LocalElement>Some String</LocalElement> 

考虑 SupplyChainSchema.xsd 文档和 WSDL to Java Bean Skeleton wizard 生成的 JavaBean 时,您将看见有三个局部元素被映射到 SOAPElement:

来自 <PurchaseOrderType> 复杂类型的 <paymentMethod> 元素

来自 <PurchaseOrderType> 复杂类型的 <item> 元素

来自 <ShippingNoticeType> 复杂类型的 <item> 元素

要在 <paymentMethod> 这个局部元素和 com.example.supplychain.PaymentMethodType 这个 Java 类之间建立自定义映射,请在 SupplyChainEMF 项目中打开 /SupplyChainEMF/src/com/example/supplychain/impl /SupplychainPackageImpl.java。将清单 10 中的代码片段添加到 initializePackageContents() 方法的尾部。该方法将作为初始化的一部分被调用。


清单 10.添加一个局部元素映射
initEClass(paymentMethodTypeEClass, PaymentMethodType.class, 
 "paymentMethod", !IS_ABSTRACT, !IS_INTERFACE); 


接下来,将为两个 <item> 局部元素建立自定义映射。和 <paymentMethod> 元素不同的是,不能在 initializePackageContents() 方法中添加静态映射条目,这是因为 EMF 模型对每个局部元素名称只允许一个映射。要克服这个缺点,可以象使用映射那样动态注册并移除必要的映射。清单 11 显示了 4 个方法,这 4 个方法允许您从 <PurchaseOrderType> 复杂类型中注册和移除 <item> 元素映射,以及从 <ShippingNoticeType> 复杂类型中注册和移除 <item> 元素映射。在 SupplyChainEMF 项目中,打开 SupplychainPackageImpl.java 并添加清单 11所示的代码片段。


清单 11.添加一个局部元素映射
private EClass purchaseItem; 
public void initPurchaseItem() 
{ 
 purchaseItem = initEClass(createEClass(ITEM_TYPE), 
  ItemType.class, "item", !IS_ABSTRACT, !IS_INTERFACE); 
} 
public void removePurchaseItem() 
{ 
 if (purchaseItem != null) 
  this.eClassifiers.remove(purchaseItem); 
} 
private EClass shippingItem; 
public void initShippingItem() 
{ 
 shippingItem = initEClass(createEClass(SHIPPING_ITEM_TYPE), 
  
  ShippingItemType.class, "item", !IS_ABSTRACT, !IS_INTERFACE); 
} 
public void removeShippingItem() 
{ 
 if (shippingItem != null) 
  this.eClassifiers.remove(shippingItem); 
} 


最后,如清单 12 所示,执行 SupplyChainBindingImpl.java 中的 submitPurchaseOrder(com.example.supplychain.www.PurchaseOrderType purchaseOrder) 方法。该清单演示了如何使用前面创建的方法。


清单 12.执行 submitPurchaseOrder 方法示例
public com.example.supplychain.www.PurchaseReferenceType 
submitPurchaseOrder(com.example.supplychain.www.PurchaseOrderType purchaseOrder) 
throws java.rmi.RemoteException 
{ 
 try 
 { 
  String customerReference = purchaseOrder.getCustomerReference(); 
  /* 
   * Converting SOAPElement to PaymentMethodType. The local element 
   * mapping for paymentMethod is statically registered in the 
   * initializePackageContents() method of SupplychainPackageImpl.java 
   */ 
  PaymentMethodType paymentMethod = 
   (PaymentMethodType)domElement2EObject(soapElement2DOMElement(( 
   SOAPElement)purchaseOrder.getPaymentMethod())); 
  /* 
   * Converting SOAPElement to ItemType. The local element mapping 
   * for item is dynamically registered and removed using the 
   * initPurchaseItem() and removePurchaseItem() methods. 
   */ 
  ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initPurchaseItem(); 
  ItemType item = (ItemType)domElement2EObject(soapElement2DOMElement(( 
  SOAPElement)purchaseOrder.getItem())); 
  ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removePurchaseItem(); 
  ShippingNoticeType shippingNotice = purchaseOrder.getShippingNotice(); 
  String recipient = shippingNotice.getRecipient(); 
  String address = shippingNotice.getAddress(); 
  /* 
   * Converting SOAPElement to ShippingItemType. 
   */ 
  ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initShippingItem(); 
  ShippingItemType shippingItem = 
   (ShippingItemType)domElement2EObject(soapElement2DOMElement(( 
   SOAPElement)shippingNotice.getItem())); 
  ((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removeShippingItem(); 
  float height = shippingItem.getHeight(); 
  float length = shippingItem.getLength(); 
  float width = shippingItem.getWidth(); 
  float weight = shippingItem.getWeight(); 
  boolean fragile = shippingItem.isFragile(); 
  float total = 0; 
  total += item.getQuantity() * item.getPrice(); 
  total += weight; 
  if (fragile) 
   total += 100; 
  ProcessingType processingType = 
  SupplychainFactory.eINSTANCE.createProcessingType(); 
  StatusType status = SupplychainFactory.eINSTANCE.createStatusType(); 
  status.setProcessing(processingType); 
  PurchaseReferenceType purchaseReference = new PurchaseReferenceType(); 
  purchaseReference.setReferenceNumber(String.valueOf(Math.abs(( 
  new Random()).nextInt()))); 
  /* 
   * Converting StatusType to SOAPElement. 
   */ 
  purchaseReference.setStatus(domElement2SOAPElement(eObject2DOMElement(status))); 
  purchaseReference.setTotal(total); 
  return purchaseReference; 
 } 
 catch (Throwable t) 
 { 
  t.printStackTrace(); 
 } 
 return null; 
} 

测试供应链 Web 服务

您已经完成了供应链 Web 服务。现在使用 Web Services Explorer 对其进行测试。

启动部署了供应链 Web 服务的服务器。打开 server 视图。单击菜单Window > Show View>Other...。展开Server文件夹,然后单击Servers>OK。

在 Servers 视图中,右键单击WebSphere v5.1 Test Environment>Start。

右键单击/SupplyChainWeb/WebContent/wsdl/com/example/supplychain/www/SupplyChainService.wsdl > Web Services>Test with Web Services Explorer启动 Web Services Explorer。

在操作栏中,单击submitPurchaseOrder链接。

输入如表 1 所示的参数值。

表 1.参数值
参数
customerReferenceJohn Doe
paymentMethodtns:creditCard
creditCardTypeVISA
creditCardNumber12345-67890
expiration2004-06-17
idPlasma TV
description42-inch
quantity1
price3000
recipientJohn Doe
address123 Fake street
height40
width25
length10
weight60
fragiletrue

单击Go调用 submitPurchaseOrder 操作。图 3 显示了调用结果。
图 3.调用 submitPurchaseOrder 操作的结果
利用 Eclipse Modeling Framework 加强 JAX-RPC 类型映射的功能

查看原图(大图)

结束语

JAX-RPC 定义了一个 XML 到 Java 类型映射的标准模型,但是,该模型还需要为所有的 XML 数据类型提供标准映射。本文演示了如何联合 EMF 和 JAX-RPC 的功能来支持没有标准映射的 XML 数据类型。虽然 EMF 提供了一个解决方案,但是该方法需要用户同时使用两种不同的编程模型。以后,新兴技术服务数据对象 (Service Data Objects) 将会针对该问题提供更好的解决方案。

获取本文中所使用的产品和工具

如果您是一个 developerWorks 订阅者,那么您将具有一个单用户许可证,可以使用 WebSphere Studio Application and Site Developer 和其他的 DB2®、Lotus®、Rational®、Tivoli®,以及 WebSphere® 产品 —— 其中包括基于 Eclipse 的 WebSphere Studio IDE 来开发、测试、评估和演示您的应用程序。

本文示例源代码或素材下载

Tags:利用 Eclipse Modeling

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接