xmlrpc walk through

blues發表於2005-10-19
0.為什麼整理xml rpc,並share
希望互通有無,實際上這些東西並不複雜,但大家的時間都有限。希望能共享。

1.xml rpc是什麼
1.1. xml rpc簡介
xml rpc是使用http協議做為傳輸協議的rpc機制,使用xml文字的方式傳輸命令和資料。
一個rpc系統,必然包括2個部分:1.rpc client,用來向rpc server呼叫方法,並接收方法的返回資料;2.rpc server,用於響應rpc client的請求,執行方法,並回送方法執行結果。
1.2. xml rpc的可用版本
xml rpc client和xml rpc server都有很多版本的實現。一般而言,一個實現版本都會同時實現client/server。但由於都滿足xml rpc規範,從理論上講,任何一個版本的rpc client實現與任何一個版本的rpc server都能配套使用。
更進一步,由於xml rpc以xml文字的方式,使用http協議傳輸,所以與程式語言無關。例如:rpc client的已實現版本包括了:perl,php,python,c/c++,java,等等;rpc server的實現語言包括perl,java,等。
同一種程式語言所實現的版本也不止一個。例如java版的實現有:Marque的xmlrpc實現(http://xmlrpc.sourceforge.net/),apache的xmlrpc 實現(http://ws.apache.org/xmlrpc/)

1.3.xmlrpc的工作原理
完整的需要參考xmlrpc規範(http://www.xmlrpc.com/spec)
簡單描述:
rpcclient的工作原理:rpcclient根據URL找到rpcserver -> 構造命令包,呼叫rpcserver上的某個服務的某個方法 -> 接收到rpcserver的返回,解析響應包,拿出呼叫的返回結果。
rpcserver的工作原理:啟動一個webserver(在使用內建的webserver的情況下) -> 註冊每個能提供的服務,每個服務對應一個Handler類 ->進入服務監聽狀態。
1.4. xmlrpc規範
區區6頁,講的非常清楚,建議細看。http://www.xmlrpc.com/spec

2.在java中使用xml rpc的幾個例子
2.0.環境準備:下載如下包並設定到CLASSPATH中
apache xmlrpc軟體包(http://ws.apache.org/xmlrpc/)
commons-httpclient-3.0-rc4.jar
commons-codec-1.3.jar
2.1.使用apache的java xmlrpc實現版本,實現簡單的加/減服務。參考附錄中test.XmlRPCClient類與test.JavaServer類
2.2.使用apache的java xmlrpc實現版本,測試java的資料型別與xmlrpc資料型別的相互對應關係。參考附錄中test2.XmlRPCClient類與test2.JavaServer類。
在這裡簡單描述一下:
>xmlrpc中的Array型別,對應到java中的Vector型別
例如:在RPC Server中的某個服務方法的返回值的宣告型別是String[],但在Client中接收到的將是Vector物件;
反之,如果Client傳送過去的呼叫引數為String[],但在RPC Server中所接收到的將是Vector物件
當然,如果我們不使用String[],直接宣告為Vector,也是可以的。
>xmlrpc中的struct型別,對應到java中的Hashtable型別
>其它的型別,如:String,int,double,boolean,Date等,都比較好對應。需要注意的是:在rpc Client中,如果使用到int/double/boolean這些基本型別時,需要將他們封裝成一個相應的Object,例如:Integer/Double/Boolean。

2.3.使用apache的java xmlrpc實現版本,實現自定義型別的資料的傳輸
這個sample中,假設所傳輸的object都實現了XmlRPCSerializable介面。這個例子的目的是:模擬unionmon中的command物件。當假設所傳輸的資料是一個Object[]時,可以用這種方式傳輸。結合unionmon中的程式碼生成機制,每個vo的序列化/反序列化方法可以在程式碼生成過程中完成。同樣地,vox的序列化/反序列化方法需要手寫。
參考程式碼:附錄中的test3.XmlRPCSerializable , test3.AccountVO , test3.XmlRPCClient , test3.JavaServer

2.4.不啟動內建的WebServer,讓tomcat支援rpc server。
做法:1.實現一個Servlet,並配置到tomcat中;2.讓rpc client直接找這個servlet,獲得服務。
注意rpc client使用的是http post方法,所以該servlet中只需要實現doPost方法。

過程:在tomcat中的web.xml增加如下配置:
<servlet>
<servlet-name>SampleServiceServlet</servlet-name>
<servlet-class>test4.ServletXmlRPCServer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SampleServiceServlet</servlet-name>
<url-pattern>/SampleServiceServlet</url-pattern>
</servlet-mapping>

參考類:附件中的test4.SampleService,test4.ServletXmlRPCServer,test4.XmlRPCClient

3.todolist
3.1.能否透過introspect方式,使得自定義型別的vo的序列化/反序列化工作自動完成.castor可以完成物件的xml binding,似乎可參考
3.2.soap協議比xmlrpc複雜並強大。soap不熟悉。另,soap一定與web service在一起用?能否不用web service,但使用SOAp做rmi的協議。


4.附錄
4.1.附錄1 xmlrpc所支援的資料型別(略)
4.2.附錄2 xmlrpc資料型別與java語言的資料型別的對映(略)
4.3.參考資料
http://xmlrpc.sourceforge.net/ --Marque的xmlrpc實現
http://ws.apache.org/xmlrpc/ apache上xmlrpc server的實現
http://xmlrpc-c.sourceforge.net/xmlrpc-howto/xmlrpc-howto.html xmlrpc howto
http://www.sentom.net/list.asp?id=80 xml-rpc之例項
http://www.xmlrpc.com/spec xmlrpc規範
4.4.相關程式碼
////////////////////////begin test.XmlRPCClient//////////////////////////////////
package test;
import java.util.*;
import org.apache.xmlrpc.*;
public class XmlRPCClient {
// The location of our server.
private final static String server_url =
"http://localhost:9001";
public static void main(String[] args) throws Exception{
XmlRpc.debug = true;
// Create an object to represent our server.
XmlRpcClient server = new XmlRpcClient(server_url);

// Build our parameter list.
Vector params = new Vector();
params.addElement(new Integer(5));
params.addElement(new Integer(3));

// Call the server, and get our result.
Hashtable result = (Hashtable) server.execute("mysample.sumAndDifference",
params);
int sum = ( (Integer) result.get("sum")).intValue();
int difference = ( (Integer) result.get("difference")).intValue();
System.out.println("Sum: " + Integer.toString(sum) +
", Difference: " +
Integer.toString(difference));
}
}
////////////////////////end test.XmlRPCClient//////////////////////////////////

////////////////////////begin test.JavaServer//////////////////////////////////
package test;

import java.util.*;
import org.apache.xmlrpc.WebServer;

public class JavaServer {

public JavaServer() {
}

public Hashtable sumAndDifference(int x, int y) {
Hashtable result = new Hashtable();
result.put("sum", new Integer(x + y));
result.put("difference", new Integer(x - y));
return result;
}

public static void main(String[] args) {
try {
// Invoke me as <http://localhost:9001/RPC2>.
WebServer webserver = new WebServer(9001);
webserver.addHandler("mysample", new JavaServer());
webserver.start();
}
catch (Exception exception) {
System.err.println("JavaServer: " + exception.toString());
}
}
}
////////////////////////end test.JavaServer//////////////////////////////////

////////////////////////begin test2.XmlRPCClient//////////////////////////////////
package test2;

import java.util.*;
import org.apache.xmlrpc.*;
public class XmlRPCClient {

// The location of our server.
private final static String server_url =
"http://localhost:9001";

public static void main(String[] args) {
try {
XmlRpc.debug = true;
XmlRpcClient server = new XmlRpcClient(server_url);
// Build our parameter list.
Vector params = new Vector();
Vector arg0 = new Vector();
arg0.add("army");
arg0.add("robin");
params.addElement(arg0);
Hashtable arg1 = new Hashtable();
arg1.put("a","a");
arg1.put("b","b");
params.addElement(arg1);
Integer arg2 = new Integer(3);
params.addElement(arg2);
Double arg3 = new Double(11.33);
params.addElement(arg3);
Boolean arg4 = new Boolean(false);
params.addElement(arg4);
Date arg5 = Calendar.getInstance().getTime();
params.addElement(arg5);
// Call the server, and get our result.
Object ret = server.execute("sample.getAllUser",params);
Vector result = (Vector)ret;
if(result!=null){
System.out.println("result:" + result.size() + "records");
for(int i=0;i<result.size();i++){
System.out.println("result " + i + "is:" + result.get(i));
}
}
}
catch (XmlRpcException exception) {
System.err.println("XmlRPCClient: XML-RPC Fault #" +
Integer.toString(exception.code) + ": " +
exception.toString());
}
catch (Exception exception) {
exception.printStackTrace(System.err);
}
}
}
////////////////////////end test2.XmlRPCClient//////////////////////////////////

////////////////////////begin test2.JavaServer//////////////////////////////////
package test2;
import java.util.*;
import org.apache.xmlrpc.WebServer;
public class JavaServer {

public JavaServer () {
// Our handler is a regular Java object. It can have a
// constructor and member variables in the ordinary fashion.
// Public methods will be exposed to XML-RPC clients.
}

public Vector getAllUser (Vector arg0,Hashtable arg1,int arg2,double arg3,boolean arg4,Date arg5) {
if(arg0!=null){
System.out.println(arg0.size());
}
if(arg1!=null){
System.out.println(arg1.size());
}
System.out.println(arg2);
System.out.println(arg3);
System.out.println(arg4);
System.out.println(arg5);
Vector result = new Vector();
result.add("bruce");
result.add("測試中文");
result.add("orbison");
return result;
}

public static void main (String [] args) {
try {

// Invoke me as <http://localhost:9001/RPC2>.
WebServer webserver = new WebServer(9001);

webserver.addHandler("sample", new JavaServer());
webserver.start();
} catch (Exception exception) {
System.err.println("JavaServer: " + exception.toString());
}
}
}
////////////////////////end test2.JavaServer//////////////////////////////////

////////////////////////begin test3.XmlRPCSerializable//////////////////////////////////
package test3;
import java.util.Vector;
public interface XmlRPCSerializable {
/*將本物件序列化為Vector物件*/
public Vector serialize();
/*從v中反序列化本物件*/
public void deSerialize(Vector v);
}
////////////////////////end test3.XmlRPCSerializable//////////////////////////////////

////////////////////////begin test3.AccountVO//////////////////////////////////
package test3;
import java.util.*;

public class AccountVO implements XmlRPCSerializable{
private String acctId;
private double balance;
public AccountVO() {
}

public String toString(){
return "acctId:" + acctId + ",balance:" + balance;
}
public Vector serialize(){
Vector v = new Vector();
v.add(acctId);
v.add(new Double(balance));
return v;
}

public void deSerialize(Vector v){
acctId = (String)v.get(0);
balance = ((Double)v.get(1)).doubleValue();
}

public String getAcctId() {
return acctId;
}
public void setAcctId(String acctId) {
this.acctId = acctId;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}

}
////////////////////////end test3.AccountVO//////////////////////////////////

////////////////////////begin test3.XmlRPCClient//////////////////////////////////
package test3;

import java.util.*;
import org.apache.xmlrpc.*;

public class XmlRPCClient {

// The location of our server.
private final static String server_url =
"http://localhost:9001";

public static void main(String[] args) {
try {
XmlRpc.debug = false;
// Create an object to represent our server.
XmlRpcClient server = new XmlRpcClient(server_url);

// Build our parameter list.
Vector params = new Vector();

// Call the server, and get our result.
Vector result = (Vector) server.execute("mysample.getAllAccountVO",
params);
if (result != null) {
for (int i = 0; i < result.size(); i++) {
Vector v = (Vector) result.get(i);
AccountVO vo = new AccountVO();
vo.deSerialize(v);
System.out.println(vo);
}
}

}
catch (XmlRpcException exception) {
System.err.println("XmlRPCClient: XML-RPC Fault #" +
Integer.toString(exception.code) + ": " +
exception.toString());
}
catch (Exception exception) {
exception.printStackTrace();
}
}
}
////////////////////////end test3.XmlRPCClient//////////////////////////////////

////////////////////////begin test3.JavaServer//////////////////////////////////
package test3;
import java.util.*;
import org.apache.xmlrpc.WebServer;
public class JavaServer {

public JavaServer () {
}

public Vector getAllAccountVO () {
Vector result = new Vector();
AccountVO vo = new AccountVO();
vo.setAcctId("robin");
vo.setBalance(300000.00);
result.add(vo.serialize());
vo = new AccountVO();
vo.setAcctId("amy");
vo.setBalance(100000.10);
result.add(vo.serialize());
return result;
}

public static void main (String [] args) {
try {

// Invoke me as <http://localhost:9001/RPC2>.
WebServer webserver = new WebServer(9001);
webserver.setParanoid (true);
// deny all clients
webserver.acceptClient ("192.168.0.*"); // allow local access
webserver.denyClient ("192.168.0.3"); // except for this one
webserver.setParanoid (false); // disable client filter

webserver.addHandler("sample", new JavaServer());
webserver.addHandler("mysample",new JavaServer());
webserver.start();
} catch (Exception exception) {
System.err.println("JavaServer: " + exception.toString());
}
}
}

////////////////////////end test3.JavaServer//////////////////////////////////

////////////////////////begin test4.SampleService//////////////////////////////////
package test4;
import java.util.*;
public class SampleService {
public SampleService() {
}

public Date currentTime(){
return Calendar.getInstance().getTime();
}

}
////////////////////////end test4.SampleService//////////////////////////////////

////////////////////////begin test4.ServletXmlRPCServer//////////////////////////////////
package test4;

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.xmlrpc.*;

public class ServletXmlRPCServer
extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
XmlRpcServer xmlrpc = new XmlRpcServer();
xmlrpc.addHandler("sampleService", new SampleService());
byte[] result = xmlrpc.execute(request.getInputStream());
response.setContentType("text/xml");
response.setContentLength(result.length);
OutputStream out = response.getOutputStream();
out.write(result);
out.flush();
}

}
////////////////////////end test4.ServletXmlRPCServer//////////////////////////////////

////////////////////////begin test4.XmlRPCClient//////////////////////////////////
package test4;


import java.util.*;
import org.apache.xmlrpc.*;

public class XmlRPCClient {

// The location of our server.
private final static String server_url =
"http://localhost:8080/axis/SampleServiceServlet";

public static void main (String [] args) {
try {
XmlRpc.debug = false;
// Create an object to represent our server.
XmlRpcClient server = new XmlRpcClient(server_url);
// Build our parameter list.
Vector params = new Vector();
// Call the server, and get our result.
Date result = (Date) server.execute("sampleService.currentTime", params);
System.out.println(result.getTime());

} catch (XmlRpcException exception) {
System.err.println("XmlRPCClient: XML-RPC Fault #" +
Integer.toString(exception.code) + ": " +
exception.toString());
} catch (Exception exception) {
System.err.println("XmlRPCClient: " + exception.toString());
}
}
}
////////////////////////end test4.XmlRPCClient//////////////////////////////////

相關文章