分享
 
 
 

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

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

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

英文原文

内容:

引言

创建供应链 Web 服务

创建供应链 EMF 模型

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

测试供应链 Web 服务

结束语

获取产品

参考资料

关于作者

对本文的评价

级别: 中级

Jeffrey Liujeffliu@ca.ibm.com

软件开发人员, IBM

2004 年 8 月

本文演示了如何使用 Eclipse Modeling Framework (EMF) 来加强 JAX-RPC 类型映射模型的功能。本文还提供了示例代码指导您从 Web 服务描述语言 (Web Services Description Language,WSDL) 文档创建 Web 服务的整个过程,Web 服务描述语言文档使用的是不支持 XML 数据类型的 JAX-RPC。

引言

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

向导完成之后,您会在 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

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 构建路径中。右键单击 SupplyChainWeb project 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 类,也可以反过来转换。清单 345 以及 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 模式示例

清单 8.全局元素实例

Some String

清单 9.局部元素实例

Some String

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

来自 复杂类型的 元素

来自 复杂类型的 元素

来自 复杂类型的 元素 要在 这个局部元素和 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);

接下来,将为两个 局部元素建立自定义映射。和 元素不同的是,不能在 initializePackageContents() 方法中添加静态映射条目,这是因为 EMF 模型对每个局部元素名称只允许一个映射。要克服这个缺点,可以象使用映射那样动态注册并移除必要的映射。清单 11 显示了 4 个方法,这 4 个方法允许您从 复杂类型中注册和移除 元素映射,以及从 复杂类型中注册和移除 元素映射。在 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.参数值

参数

customerReference

John Doe

paymentMethod

tns:creditCard

creditCardType

VISA

creditCardNumber

12345-67890

expiration

2004-06-17

id

Plasma TV

description

42-inch

quantity

1

price

3000

recipient

John Doe

address

123 Fake street

height

40

width

25

length

10

weight

60

fragile

true

单击 Go 调用 submitPurchaseOrder 操作。图 3 显示了调用结果。

图 3.调用 submitPurchaseOrder 操作的结果

结束语

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 来开发、测试、评估和演示您的应用程序。如果您不是一个订阅者,您可以现在订阅

参考资料

查看下列规范:

JAX-RPC (JSR-101)

Java APIs for XML Messaging: SOAP with Attachments API for Java (JSR-67)

Service Data Objects (JSR-235)

阅读 XML Schema Part 0: Primer 关于 XML 模式工具的描述 (W3C,2001 年 5 月 2 日)。

通过阅读 XML Schema Part 1: Structures(W3C,2001 年 5 月 2 日)更好的理解 XML 模式定义语言的结构。

阅读 XML Schema Part 2: Datatypes,讨论 XML 模式(W3C,2001 年 5 月 2 日)中的数据类型。

下载 60 天试用版的 IBM WebSphere Studio Application and Site Developer V5.1.2

Eclipse.org 上下载 Eclipse 项目、关于 Eclipse 工具的文章、新闻组及更多相关内容。

Developer Bookstore 购买关于各种的技术主题的打折图书。

下载源代码

关于作者

Jeffrey Liu 是 IBM 多伦多实验室 Rational Studio Web 服务工具小组的一位软件开发人员,您可以通过 jeffliu@ca.ibm.com 与 Jeffrey 联系。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有