级别: 初级
C. Enrique Ortiz ([email protected]), 移动技术专家和作家, IBM
2004 年 9 月 01 日
用于 Java 2 平台袖珍版 (Java 2 Platform, Micro Edition,J2ME) 的 Web 服务 API (WSA) 是由 Java Community Process为 Java 规范请求 172 (JSR 172) 而定义的,这些 API 是两个相互独立的可选包,用于远程服务调用和 XML 解析。他们是针对基于连接设备配置 (Connected Device Configuration,CDC) 和有限连接设备配置 (Connected Limited Device Configuration,CLDC 1.0 和 CLDC 1.1) 的框架的。为什么用户应该关注这些呢?因为 JSR 172 在设备层为远程服务调用和 XML 解析提供了支持,也就意味着开发人员不用将这项功能嵌入到每一个应用程序中。本文介绍了远程服务调用可选包 API。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
Java 2 平台袖珍版 (J2ME) 平台中的 Web 服务是由 Java 规范请求 172 (JSR 172) 定义的,它与标准 Web 服务遵循同样的规范、结构以及调用模型。我们来回顾一下清单。
JSR 172 Web 服务 API (WSA) 遵循下面这些核心 Web 服务规范:
注意 JSR 172 不支持统一描述、发现和集成 (UDDI) 2.0规范,该规范定义了如何发现远程服务。
由于有相当多的与 Web 服务相关并且涵盖了不同技术的规范出台,而且越来越多,Web 服务互操作组织 (WS-I)定义了 WS-I 基本概要 1.0 (WS-I Basic Profile,Version 1.0) 来定义 Web 服务规范的最小集,和一致性规则一样,所有的基础 Web 服务提供者和消费者都必须遵守该概要。JSR 172 规范也遵守 WS-I 基本概要。
JSR 172 WSA 从客户端访问 Web 服务,从服务-消费者的角度来看,WSA 提供远程服务调用 API (JAX-RPC) 以及运行时环境,从而允许 J2ME 应用程序在 Web 上消费服务,而不是作为服务生产者(端点)来运行。除了这一点差别之外,JSR 172 WSA 体系结构的其它部分与 Web 服务的标准体系结构/组织一致,如下图所示:
该高级体系结构组织如下:
J2ME 应用程序通过 JSR 172 存根和运行时调用远程服务,通常要通过 HTTP 和 SOAP 来进行传输。存根和运行时将与远程服务调用相关的复杂部分都隐藏起来了,包括输入值和返回值如何编码并解码,以及与服务器进行网络通信的管理。方法调用遵循同步请求-应答模型,如下图所示:
*由于调用是按模块进行的,所以您应该把这些调用分派到不同的执行线程中。
![]() ![]() |
![]()
|
要消费 Web 服务,您必须首先创建服务调用存根。让这些存根来执行任务,例如对输入值和返回值进行编码和解码、与 JSR 172 运行时交互来调用远程服务端点。存根通过运行时的服务提供者接口 (SPI) 与运行时进行交互,这样通过概述运行时执行的详细情况,使存根在不同厂商之间的执行更便捷。
存根通常是用工具生成的,该工具读取一个 WSDL XML 文档,文档描述了将要使用到的 Web 服务。同样的,WSDL 文档通常也是通过工具生成的,该工具读取接口定义,例如 Java 接口产生了 WSDL 文档。
从我们移动开发的角度来看,需要消费的 WSDL 文档通常已经存在,您需要做的仅仅是生成 JSR 172 WSA 存根。要生成这些存根,您应该使用例如J2ME Wireless Toolkit 2.1存根生成器这样的工具,如下图所示:
该生成器生成存根 Java 文件,以及相关的支持类。如下一部分所描述的,它还考虑到了 WSDL 到 Java 的数据类型映射。
一旦生成了 JSR 172 JAX-RPC 存根和支持文件,您的应用程序就已经被编译并部署到启用了 JSR 172 的设备上了,消费 Web 服务是很简单的而且几乎是透明的。您很快就会看到,调用远程方法几乎和调用本地方法一样简单。
![]() ![]() |
![]()
|
JSR 172 远程方法调用 API 是以基于 XML 的 RPC 的 J2SE Java API (JAX-RPC 1.1) 的子集为基础的。它同样遵守 WS-I 基本概要。下面来详细研究一下 JSR 172 JAX-RPC 子集 API:
它支持:
xsd:boolean
到 boolean
或 Boolean
。 xsd:byte
到 byte
或 Byte
。 xsd:short
到 short
或 Short
。 xsd:int
到 int
或 Integer
。 xsd:long
到 long
或 Long
。 xsd:float
到 float
,或 Float
。对基于 CLDC 1.0 的平台,该数据类型映射到 String。 xsd:double
到 double
,或 Double
。对基于 CLDC 1.0 的平台,该数据类型映射到 String。 xsd:string
到 String
。 xsd:base64Binary
到 byte[]
。 xsd:hexBinary
到 byte[]
。 xsd:complexType
到基本类型和类类型序列。 xsd:QName
到 javax.xml.namespace.QName
。 它不支持:
设备端没有规定 XML 编码方法。这样做是通过允许执行程序使用更有效的数据编码方法来帮助减少网络传输,例如在设备和无线网关间使用二进制协议(只要这样编码对消费者和生产者是透明的)。
JSR 172 远程调用 API 包括下面这些包:
javax.microedition.xml.rpc
javax.xml.namespace
javax.xml.rpc
java.rmi
(包括确保 JAX-RPC 相关型) 注意这些 API(有一些异常 API,例如 RemoteException)不是直接由应用程序调用,相反,应用程序调用生成的存根。上面的 API 主要是供存根使用的。有关详细信息请参阅 JSR 172 规范和/或 Java 文档。
![]() ![]() |
![]()
|
一旦生成、编译并部署了 JSR 172 JAX-RPC 存根和支持文件,消费远程服务就很容易了。事实上,除了导入 RemoteException,完成最少量的 JAX-RPC 细节初始化工作,您的应用程序不光是看上去,而且运行起来也和非 Web 服务消费者应用程序一样。由于有 JSR 172 存根和运行时,实现这种简单的应用程序是可能的,正如前面提到的,JSR 172 存根和运行时把与远程调用相关的大部分细节都隐藏了。
要调用远程服务,您首先需要实例化存根,完成最少的存根初始化工作,然后就是如何编写调用存根方法。下面的代码片断显示了如何使用 JSR 172 JAX-RPC 调用远程服务。
package j2medeveloper.wsasample // MIDP import javax.microedition.midlet.MIDlet; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Form; ... Form form = new Form("Employee Info"); ... // JAX-RPC import java.rmi.RemoteException; String serviceURL = "www.j2medeveloper.com/webservicesample"; ... /** * Entry point to MIDlet, from start or restart states. * @throws javax.microedition.midlet.MIDletStateChangeException */ public void startApp() throws MIDletStateChangeException { // Instantiate the service stub. EmployeeService_Stub service = new EmployeeService_Stub(); // Initialize the stub/service. service._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, serviceURL); service._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, new Boolean(true)); ... display.setCurrent(mainScreen); } /** * Paused state. Release resources (connection, threads, etc). */ public void pauseApp() { ... } /** * Destroy state. Release resources (connection, threads, etc). * @param uc If true when this method is called, the MIDlet must * cleanup and release all resources. If false the MIDlet may * throw MIDletStateChangeException to indicate it does not want * to be destroyed at this time. * @throws javax.microedition.midlet.MIDletStateChangeException * to indicate it does not want to be destroyed at this time. */ public void destroyApp(boolean uc) throws MIDletStateChangeException { ... } : : /** * Command Listener. * @param c is the LCDUI Command. * @param d is the source Displayable. */ public void commandAction(Command c, Displayable d) { if (c == UiConstants.COMMAND_GET_EMPINFO) { Thread th = new Thread(new GetEmpInfoTask()); th.start(); } else { ... } : : } /** * On its own thread, invoke the remote service getEmployeeInfo */ public class GetEmpInfoTask implements Runnable { public void run() { try { // Invoke the remote service. EmployeeInfo empInfo = service.getEmployeeInfo(empId); : : // Display the employee Information form.append("Name:" + empInfo.firstname+empInfo.lastname); form.append("Status:"+empInfo.status); : : display.setCurrent(form); } catch (RemoteException e) { // Handle RMI exception. } catch (Exception e) { // Handle exception. } } } : : |
注意远程调用是如何在自己的执行线程中执行的。由于 JSR 172 中的远程调用是按模块进行的,而且如果在主事件线程中调用,用户界面会冻结,直到远程调用结束。
您已经学习了 JSR 172 JAX-RPC 存根是如何生成的。以后,有关详细信息请参考适当的存根生成器文档。
![]() ![]() |
![]()
|
本文介绍了用于 J2ME 平台的 JSR 172 WSA,重点介绍了用于 J2ME 远程服务调用 API 的 JAX-RPC。另外,还涵盖了 JSR 172 WSA 中用到的核心 Web 服务标准、典型结构以及调用模型。并用一个简短的代码实例回顾了如何消费 Web 服务,即 JAX-RPC 子集 API。
在本文的第 2 部分,我将讨论 JSR 172 XML 解析 API。
![]() |
||
![]() |
C. Enrique Ortiz 是一位软件工程师,有 14 年多的工作经验,他最近担任 Aligo 公司的移动应用程序主管、AGEA 公司无线副总裁,还是 IBM Pervasive 软件,智能推理系统的一位软件工程师。Enrique 与人合作设计了 Sun Microsystems 的移动 Java 开发人员认证考试。他还与人合著了一本最早的关于 J2ME 的书——用于 J2ME 的移动信息设备框架。Enrique 积极参与无线 Java 社区及各种 J2ME 专家组。您可以通过C. Enrique Ortiz与他联系。 |