XML-RPC的Apache实现
XML-RPC 规范及 Java 实现
在新技术、新概念甚⾄新思维层见叠出的 IT ⾏业,XML-RPC 绝对不是最新的热门技术,但它⾃诞⽣之⽇起,⼀直在IT ⾏业占有⼀席之地。XML-RPC 具有简单且易于实现,可以⾼效跨越不同的软硬件平台上应⽤系统等优点。相对于庞⼤、复杂的分布式计算机制,它⼀直是中⼩型应⽤的最佳选择之⼀。⽐如,流⾏于软件研发团队的任务计划管理系统 JIRA、开源的测试⽤例管理⼯具 TestLink 等都提供了开放的 XML-RPC 接⼝,供⽤户定制开发时进⾏调⽤。
XML-RPC(XML-based Remote Procedure Call,基于 XML 的远程过程调⽤)是⼀种⼯作在互联⽹上的远程过程调⽤协议。⼀个 XML-RPC 请求消息就是⼀个 HTTP-POST 请求消息,其请求消息主体基于 XML 格式。客户端发送XML-RPC 请求消息到服务端,调⽤服务端的远程⽅法并在服务端上运⾏远程⽅法。远程⽅法执⾏完毕后,返回响应消息给客户端,其响应消息主体同样基于 XML 格式。远程⽅法的参数⽀持数字,字符串、⽇期等;也⽀持列表数组和其他复杂结构类型。
主流的开发语⾔都提供了 XML-RPC 协议的客户端程序和服务端程序的实现,这些语⾔包括 Java、Ruby、Python、C/C++ 、Perl 和 PHP 等。本⽂选择以 XML-RPC 的 Java 实现 Apache XML-RPC 为例,来研究 XML-RPC 协议规范。Apache XML-RPC 完全兼容 XML-RPC 协议规范,同时也提供了⼀些
扩展特性,使其还具有下述能⼒:
⽀持 Java 的全部基本数据类型,如 long、byte、short,以及 double
⽀持 Calendar 对象
⽀持⽀持 DOM 节点、JAXB 对象实例能通过 XML-RPC 进⾏传输。事实上,任何实现 java.io.Serializable 接⼝的对客户端和服务端都可以通过配置在流模式(stream mode)下进⾏操作,这样⽐基于⼤字节数组的默认模式节省资源象都可以被传输
下⾯就以实例来学习 XML-RPC 的请求和响应消息的格式。本⽂以当前⼯作使⽤的 Window 机器为客户端,IP 为192.168.1.105。服务端为 Ubuntu 机器,IP 为 192.168.1.126。
步骤 1. 下载本⽂附带的源代码⽂件,内含三个 Eclipse Java 项⽬,请把他们导⼊到 Eclipse ⼯作区间:
XML-RPC-Client XML-RPC 客户端实现的例⼦
XML-RPC-EmbeddedWebServer 嵌⼊式服务端端实现的例⼦,可以直接运⾏
XML-RPC-Server Servlet 服务端端实现的例⼦ , 需要部署在 Servlet 容器,⽐如 Tomcat、Jetty 等
步骤 3,下载安装 SmartSniff(下载地址见参考资源部分)。SmartSniff ⽤于捕获客户端与服务端的 XML-RPC 消息交互数据包。运⾏该软件,在菜单 Options-Capture Filter 与 Display Filter ⾥设置捕获过滤、展⽰过滤:include:remote:tcpudp: 192.168.1.126:8080,这样只显⽰我们感兴趣的协议数据。点击 Start Capture 按钮,启动捕获监听。注意:SmartSniff 只能运⾏在 Window 机器上,并且只能捕获不同的机器之间的 TCP/IP ⽹络数据交互。如果 XML-RPC 客户端与服务端运⾏在相同的机器上,⽆法使⽤该⼯具捕获协议交互数据。
步骤 4,运⾏客户端的单元测试类,研究 XML-RPC 消息格式。在 Eclipse 项⽬ XML-RPC-Client 中,打开单元测试类 junit.TestClientServletWebServer.java。选择testXMLRPC()⽅法,以 JUnit Test ⽅式运⾏。可以发现 JUnit 单元测试可以运⾏成功,SmartSniff 捕获的协议见图 1。使⽤相同的⽅法,可以运⾏更多的测试类,研究更多的 XML-RPC 消息的格式。
图 1. 捕获 XML-RPC 协议消息
图 1:捕获 XML-RPC 协议消息
XML-RPC 请求消息格式
清单 1 是捕获的请求消息,可以看出和普通的 HTTP 请求⼀样,包含如下消息头:POST、Content-T
ype、User-Agent、Authorization、Host 与 Content-Length 等。XML 格式的消息体包含⼀个 methodCall 元素来指定远程⽅法的信息。MethodName 指定远程⽅法名称,params/param/value 等标签元素指定远程⽅法需要的参数列表。xmlns:ex 名称空间是 Apache XML-RPC 对 XML-RPC 协议的扩展,后续会详细介绍。
清单 1. 请求消息例⼦
POST /xmlrpc/xmlrpc HTTP/1.1
Content-Type: text/xml
User-Agent: Apache XML RPC 3.1.3 (Jakarta Commons httpclient Transport)
Authorization: Basic Zm9vOmJhcg==
Host: 192.168.1.126:8080
Content-Length: 260
<?xml version="1.0" encoding="UTF-8"?>
<methodCall xmlns:ex="/xmlrpc/namespaces/extensions">
<methodName>Calculator.add</methodName>
<params>
<param>
<value>
<i4>2</i4>
</value>
</param>
<param>
<value>
<i4>3</i4>
</value>
</param>
</params>
</methodCall>
XML-RPC 响应消息格式
清单 2 是捕获的响应消息。消息体同样是 XML 格式的,它包含⼀个 methodResponse 元素来指定远程⽅法的响应内容。methodResponse 元素下⾯可以包含⼀个 params 元素,⽤于包装返回的数据内容。也可以包含 <fault> 元素,⽤于返回遇到的异常消息。XML-RPC 响应消息必须有返回值,因此 <fault> 和 <params> 必须出现⼀个且只能出现⼀个。
清单 2. 响应消息例⼦
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml
Content-Length: 189
Date: Thu, 18 Oct 2012 02:23:04 GMT
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse
xmlns:ex="/xmlrpc/namespaces/extensions">
<params>
<param>
<value>
<i4>5</i4>
</value>
</param>
</params>
</methodResponse>
在本节,我们研究了 XML-RPC 协议规范及其消息内容格式。下⾯继续介绍的是,如何使⽤ Apache XML-RPC 开发客户端和服务端 Java 代码。
如何开发客户端代码
在 Eclipse 项⽬ XML-RPC-Client 中,打开单元测试类 junit.TestClientServletWebServer.java。我们研究⼀下客户端的代码实现,见清单 3:
清单 3. 客户端代码实现
import lrpc.client.XmlRpcClient;
import lrpc.client.XmlRpcClientConfigImpl;
……
// 创建客户端实例
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("192.168.1.126:8080/xmlrpc/xmlrpc"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
// 设置传输⼯⼚类
client.setTransportFactory(new XmlRpcSunHttpTransportFactory(client));
// 创建远程⽅法的参数数组,通过指定远程⽅法名称进⾏调⽤
Object[] params = new Object[]{new Integer(33), new Integer(9)};
Integer result = (Integer) ute("Calculator.add", params);
上⾯的代码⾸先实例化⼀个客户端配置对象 XmlRpcClientConfigImpl config ,为该实例指定服务端 U
RL 属性。接着创建 XmlRpcClient 对象,为其指定配置对象,然后为其设置⼀个 Sun HTTP 传输⼯⼚对象,这个属于默认的传输⼯⼚对象,可以忽略该⾏语句。最后创建参数数组,并调⽤服务端的⽅法 Calculator.add (后⽂会介绍如何查询服务端可以提供的⽅法列表)。
我们可以选择不同的传输⼯⼚对象,⽐如可以不使⽤默认的 Sun HTTP 传输⼯⼚对象,⽽是使⽤基于 Jakarta
Commons HttpClient 的传输⼯⼚。使⽤不同的传输⼯⼚, XML-RPC 请求消息头 User-Agent 部分可以看出差异。使⽤ SmartSniff 捕获到的请求消息头,如下图所⽰。图 2. 使⽤不同传输⼯⼚的 XML-RPC 请求消息
图 2:使⽤不同传输⼯⼚的 XML-RPC 请求消息
XmlRpcClient 是⼀个⽆状态的线程安全的对象,实例化 client 对象时,需要设置下⾯的对象:
表 1. 配置 XmlRpcClient
名称
描述ClientConfig
该对象是 XmlRpcClientConfig 的实例,包括如下原⼦属性,⽐如服务端 URL ,认证信息,编码字符集等TransportFactory
该⼯⼚类⽤于创建负责使⽤客户端配置与服务端通讯的对象。下⽂会介绍常⽤的传输⼯⼚类。XmlWriterFactory XmlWriter ⽤于创建 XML
传输⼯⼚类 TransportFactory 决定客户端与服务端通讯的⽅式,Apache XML-RPC ⽀持如下⼏种⼯程类:
表 2. 传输⼯⼚类
⼯⼚类名
描述XmlRpcSunHttpTransportFactory
默认的⼯程类 , 使⽤ java.HttpURLConnection 与服务端连接XmlRpcCommonsTransportFactory 该⼯⼚类使⽤ Jakarta Commons HttpClient 与 HTTP 服务端通讯 . 该⼯⼚允许直接访
问结果⽂档,可以降低内存资源的使⽤。
XmlRpcLiteHttpTransportFactory 该⼯⼚类基于内置的 HTTP 客户端,速度很快,但不⽀持
HTTP/1.1, 不能使⽤ keepalive 连接。
XmlRpcLocalTransportFactory 该⼯⼚类拥有内置的 XML-RPC 服务器,可以直接使⽤ Java 调⽤,主要⽤于调试与开
发环境。
根据传输⼯⼚的不同,客户端配置分为如下两种类型:
lrpc.client.XmlRpcHttpClientConfig
⽤于 HTTP 传输⼯⼚,即上⽂提到的 XmlRpcSunHttpTransportFactory 、XmlRpcCommonsTransportFactory 和XmlRpcLiteHttpTransportFactory 。HTTP 传输⼯⼚对应的客户端配置实例⽀持以下属性设置 basicUserName 、basicPassword 、basicEncoding 、contentLengthOptional 、enabledForExceptions 、enabledForExtensions 、Encoding 、gzipCompressing 和 gzipRequesting 。关于这些属性的详细描述,请参考 Apache XMl-RPC 官⽅站点。lrpc.client.XmlRpcLocalClientConfig ⽤于本地传输⼯⼚,即上⽂提到的 XmlRpcLocalTransportFactory 。本地传输⼯⼚对应的客户端配置实例⽀持配置属性 xmlRpcServer 。作为内置的 XML-RPC 客户端,模拟来⾃客户端的请求,⽤于调试与开发。
lrpc.client.XmlRpcClientConfigImpl 实现了上述两个接⼝,为⽅便计,不管使⽤什么传输⼯⼚类,客如何开发服务端代码
户端配置都可以使⽤实现类 XmlRpcClientConfigImpl。
相对于 XmlRpcClient,服务端的 XmlRpcServer 对象⽤于接收并执⾏来⾃客户端的 XML-RPC 调⽤,该对象可以嵌⼊ Servlet 容器(Tomcat,Jetty 等),或其他的 HTTP 服务器。在使⽤本地传输⼯⼚类的情况下,XML-RPC 被集成到客户端应⽤内。和 XmlRpcClient 类似,XmlRpcServer 也需要制定⼀个服务端配置对象XmlRpcServerConfigImpl。该配置对象⽀持的属性如下:
表 3. 服务端配置属性
属性名称描述
enabledForExceptions在启⽤该属性时,如果服务端捕获异常,服务端会把异常转换成字节数组,
并返回客户端。
enabledForExtensions指定是否启⽤ Apache 对 XML-RPC 的扩展。
下⾯,我们就来研究⼀下如果使⽤ XML-RPC Servlet 来开发服务端的代码。
⾸先,创建⼀个业务逻辑类,供客户端调⽤。见清单 4。需要注意:能被客户端调⽤的⽅法必须是 public 的,返回值不是 void 的、实例⽅法。像构造⽅法、存取⽅法的 setter ⽅法和静态⽅法都不能被远程调⽤。任何抽象类、接⼝类,不能被实例化,它们的⽅法也不能被远程调⽤。
清单 4. Calculator 业务逻辑类
package lrpc.demo;
public class Calculator {
public int add(int i1, int i2) {
return i1 + i2;
}
public int subtract(int i1, int i2) {
return i1 - i2;
}
}
接着,在源⽂件⽬录 org/apache/xmlrpc/webserver/ 下创建属性⽂件 XmlRpcServlet.properties。XmlRpcServlet 默认在上述包路径下寻属性⽂件。在⽂件中添加如下条⽬(清单 5)。左侧为⼀标识符,右侧为业务逻辑类的全限定类名。
清单 5. 句柄属性⽂件
Calculator=lrpc.demo.Calculator
然后,在 Web 应⽤的部署描述⽂件 l 添加如下内容(清单 6):
清单 6. 部署描述符配置 XmlRpcServlet
<servlet>
<servlet-name>XmlRpcServlet</servlet-name>
<servlet-class>lrpc.webserver.XmlRpcServlet</servlet-class>
<init-param>
<param-name>enabledForExtensions</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>XmlRpcServlet</servlet-name>
<url-pattern>/xmlrpc</url-pattern>
</servlet-mapping>
现在已经完成了服务端的代码开发,可以把它打成 war 包,部署在 servlet 容器内。启动服务端后,就可以运⾏客户端代码对服务端上提供的远程⽅法进⾏调⽤。关于如何运⾏,请详细参考本⽂附带的源代码项⽬。
另外,为了给服务端上提供的 XML-RPC 接⼝提供安全保障,可以为服务端启⽤认证机制。Apache X
ML-RPC 使⽤XmlRpcHandler 处理认证,它以 XmlRpcRequest 作为参数。XmlRpcRequest 的 getConfig() ⽅法可以返回XmlRpcRequestConfig 对象。使⽤ XmlRpcRequestConfig 的⽅法 getBasicUserName() 和 getBasicPassword() 可以获得客户端的认证信息。获取客户端的认证信息后,就可以采取适当的逻辑去验证。
⾸先,实现 AuthenticationHandler 接⼝,编写处理认证信息的逻辑代码,见清单 7。
清单 7. 认证处理器程序
public class myAuthenticationHandler implements AuthenticationHandler {
@Override
public boolean isAuthorized(XmlRpcRequest req) throws XmlRpcException {
XmlRpcHttpRequestConfig config = (XmlRpcHttpRequestConfig) Config();
return BasicUserName(),
}
private boolean isAuthenticated(String pUserName, String pPassword) {
return "foo".equals(pUserName) && "bar".equals(pPassword);
}
}
在⾃⼰定义的 XmlRpcServlet 类中使⽤ AuthenticationHandler,见清单 8。并在应⽤的部署描述⽂件中,修改servlet-class,使⽤定制的 Servlet 类 MyServlet。
清单 8. ⾃定义的 XmlRpcServlet
public class MyServlet extends XmlRpcServlet {
private static final long serialVersionUID = 4499604583805027974L;
protected XmlRpcHandlerMapping newXmlRpcHandlerMapping()
throws XmlRpcException {
PropertyHandlerMapping mapping = (PropertyHandlerMapping) super
.newXmlRpcHandlerMapping();
AuthenticationHandler handler = new myAuthenticationHandler();
mapping.setAuthenticationHandler(handler);
//XmlRpcSystemImpl.addSystemHandler(mapping);
return mapping;
}
python处理xml文件
重启 Servlet 容器,刚才的单元测试类必须添加如下⽤户认证信息(清单 9)才能执⾏成功。
清单 9. XML-RPC 客户端提供认证信息
config.setBasicUserName("foo");
config.setBasicPassword("bar");
⾄此,我们完成了使⽤ Apache XML-RPC 开发客户端和服务端代码,部署到了 Servlet 容器 Tomcat 上,并掌握了如何运⾏客户端代码调⽤服务端的远程⽅法。下⾯对 Apache XML-RPC 的⾼级特性进⾏介绍。除了部署在 Servlet 容器⾥,Apache XML-RPC 还提供了嵌⼊式 WebServer。XML-RPC 动态代理技术带来了良好的编程体验。通过启⽤扩展,Apache XML-RPC ⽀持了更多的 Java 数据类型。还对内省机制进⾏了简单介绍。
嵌⼊式 WebServer 实现
嵌⼊式 WebServer,更加便携,适⽤于为⾮ Web 应⽤提供远程⽅法。WebServer 实现代码见如下清单 10。
清单 10. 嵌⼊式 WebServer 代码

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。