(二) wsdeploy工具 1 工具介紹
這個工具和wscompile協(xié)同工作來生成一個能在任何servlet容器中發(fā)布的war文件,它授受一個生WAR文件,它包括一個SEI,一個SEI實現(xiàn),一些值類型,一些服務(wù)特定的異常,一個model文件,一個部署描述符(jaxrpc-ri.xml), 和一些可選的其它實現(xiàn)特定的制品.工具處理生的war文件并生成一個實現(xiàn)特定的熟的war文件.這個過程包括生成串行化器,連接(TIEs),運行時描述符以及其它為了成功的發(fā)布WS需要的制品. 這個工具也有兩種使用形式:批處理和Ant構(gòu)建腳本.
批的例子:
wsdeploy -o target.war myapp.war
Ant腳本,在Ant中使用這個任務(wù)前要先定義:
<taskdef name="wsdeploy" classname="com.sun.xml.rpc.tools.ant.Wsdeploy">
<classpath path="${classpath}"/>
</taskdef>
其中的類路徑指向同wscompile相同:
<wsdeploy classpath="xyz.jar" tmpdir="${tmp}" outWarFile="stock.war" inWarFile="stock-raw.war"/>
<wsdeploy keep="true" outWarFile="stock.war" inWarFile="stock-raw.war"><classpath refid="compile.classpath"/></wsdeploy>
<wsdeploy fork="true" source="1.0.3" outWarFile="stock.war" inWarFile="stock-raw.war"></wsdeploy>
2 wscompile的配置文件(部署描述符 jaxrpc-ri.xml)
它被打包在生的WAR文件中,并由wsdeploy工具使用來生成熟的WAR文件.這個描述符提供了wsdeploy工具向web容器中發(fā)布WS的信息.
該文件主要是使用endpoint和endpointMapping兩個元素來定義端點和服務(wù)影射,把SEI及其實現(xiàn)聚集在一起,連同model文件提供給發(fā)布工具.
三 編寫一個Hello例子
IDE環(huán)境:Eclipse,插件sysdeo,發(fā)布環(huán)境:Tomcat559.
使用類庫:Sun公司的參考實現(xiàn).
本例要使用的材料: 1 HelloIF.java,一個SEI接口,它擴展了Remote接口.
2 HelloImpl.java,實現(xiàn)了SEI接口.
3 web.xml ,這個文件可以是你的任何Web應(yīng)用的部署描述符文件,這個例子可以發(fā)布到你的現(xiàn)有Web應(yīng)用,只需要把那個應(yīng)用的部署描述符文件放在開發(fā)環(huán)境的WEB-INF文件夾下.
4 config-interface.xml,描述SEI接口.
5 config-wsdl.xml,使用WSDL描述服務(wù)接口,本例不介紹這個文件的使用方法,通常這個使用場景多是為訪問服務(wù)生成客戶端stub文件.另一個場景就是加入自定義的java類型到SOAP類型的影射等等很多細(xì)微的控制,或者是完全替代SEI接口.
以上文件的位置,可參看下圖:
1 編寫SEI,HelloIF:
package helloservice;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloIF extends Remote {
public String sayHello(String s) throws RemoteException;
}
2 實現(xiàn)SEI:
package helloservice;
public class HelloImpl implements HelloIF {
public String message ="Hello";
public String sayHello(String s) {
return message + s;
}
}
3 配置文件 config-interface.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<service name="MyHelloService" targetNamespace="urn:Foo"
typeNamespace="urn:Foo" packageName="helloservice">
<interface name="helloservice.HelloIF"
servantName="helloservice.HelloImpl" />
</service>
</configuration>
4 構(gòu)建服務(wù),下面是一個Ant構(gòu)建腳本.<?xml version="1.0" encoding="GBK"?>
<project name="webservice" default="build" basedir=".">
<property name="jaxrpc.lib.dir" value="D:\Sun\AppServer\lib">
</property>
<property name="classes.dir" value=".\build\classes">
</property>
<property name="src.dir" value=".\build\src">
</property>
<property name="war.file" value="hello_raw.war">
</property>
<property name="nonclass.dir" value=".\build\nonclass">
</property>
<property name="build" value="${nonclass.dir}">
</property>
<property name="assemble" value=".\assemble">
</property>
<property name="assemble.war" value=".\assemble\war">
</property>
<property name="assemble.ear" value=".\assemble\ear">
</property>
<path id="jaxrpc-classpath">
<fileset dir="${jaxrpc.lib.dir}">
<include name="**/*.jar" />
</fileset>
<fileset dir="D:\jdbc\postgresql">
<include name="*.jar" />
</fileset>
</path>
<path id="compile.classpath">
<fileset dir="${jaxrpc.lib.dir}">
<include name="**/*.jar" />
</fileset>
<fileset dir="D:\jwsdp-1.5\jaxrpc\lib">
<include name="**/*.jar" />
</fileset>
</path>
<taskdef name="wscompile" classpathref="jaxrpc-classpath" classname="com.sun.xml.rpc.tools.ant.Wscompile">
</taskdef>
<taskdef name="wsdeploy" classpathref="jaxrpc-classpath" classname="com.sun.xml.rpc.tools.ant.Wsdeploy">
</taskdef>
<target name="prepare">
<mkdir dir="${src.dir}" />
<mkdir dir="${nonclass.dir}" />
<mkdir dir="${classes.dir}" />
<mkdir dir="${assemble}" />
<mkdir dir="${assemble.war}" />
<mkdir dir="${assemble.ear}" />
</target>
<target name="build" depends="prepare" description="生成java制品,如生成可供wsdeploy使用的web檔案,稱為生war,就象作菜一樣,先順菜,以及model,wsdl文件,這里生成的WSDL文件,wsdeploy并不使用">
<echo message="build the WAR...." />
<wscompile import="false" define="true" gen="false" keep="true" base="${classes.dir}" sourceBase="${src.dir}" classpath=".\classes" nonClassDir="${nonclass.dir}" model="model.xml.gz" xPrintStackTrace="true" config="config-interface.xml" verbose="true">
<classpath refid="compile.classpath" />
</wscompile>
</target>
<target name="deploy" description="生成可供發(fā)布的web檔案,稱為煮熟的war,這個階段也生成了WSDL文件并被直接打包了">
<echo message="deploy the WAR...." />
<wsdeploy keep="false" verbose="true" tmpDir=".\tmp" outWarFile="skysoft.war" inWarFile="hello_raw.war">
<classpath refid="compile.classpath" />
</wsdeploy>
</target>
<target name="create-war" description="打包由wscompile生成的制品,以及所有發(fā)布所用的材料">
<echo message="Creating the WAR...." />
<delete file="${assemble.war}/${war.file}" />
<delete dir="${assemble.war}/WEB-INF" />
<copy todir="${assemble.war}/WEB-INF/classes/">
<!--fileset dir="${build}/" includes="**/*.class" excludes="**/*Client.class, **/*.wsdl, **/*mapping.xml" /-->
<fileset dir="./classes" includes="**/*.class" excludes="**/*Client.class, **/*.wsdl, **/*mapping.xml" />
</copy>
<copy todir="${assemble.war}/WEB-INF/lib/">
<fileset dir="./lib" includes="**/*.jar" excludes="**/*Client.class, **/*.wsdl, **/*mapping.xml" />
</copy>
<copy file="jaxrpc-ri.xml" todir="${assemble.war}/WEB-INF" />
<copy file="model.xml.gz" todir="${assemble.war}/WEB-INF" />
<war destfile="${assemble.war}/${war.file}" webxml="./web.xml" filesonly="true">
<fileset dir="${assemble.war}" includes="WEB-INF/**, build/**" />
</war>
<copy file="${assemble.war}/${war.file}" todir="." />
</target>
<target name="genstaticstub" description="生成靜態(tài)樁,供靜態(tài)的調(diào)用服務(wù)">
<echo message="gen statics tub" />
<wscompile client="true" keep="true" base="." sourceBase="." xPrintStackTrace="true" config="config-wsdl.xml" verbose="true">
<classpath refid="compile.classpath" />
</wscompile>
</target>
<target name="generate-dynamic-interface" description="根據(jù)WSDL文件生成SEI及其它材料,供動態(tài)調(diào)用">
<echo message="generate dynamic interface" />
<wscompile import="true" keep="true" features="norpcstructures" base="./dynmicstub" sourceBase="./dynmicstub" xPrintStackTrace="true" config="config-wsdl.xml" verbose="true">
<classpath refid="compile.classpath" />
</wscompile>
</target>
</project>
其中的各個任務(wù)都有說明.
注意,如果你使用JAX-RPC1.1.2的話,wsdeploy生成web.xml文件有些小錯誤,需要手工更改,這個問題在1.1.3中已經(jīng)修正.
好了,在Eclipse中運行各個任務(wù),把最后得到的skysoft.war,作為一個新的應(yīng)用發(fā)布,也可發(fā)布到你現(xiàn)有的應(yīng)用,需要解壓這個文件,然后拷貝需要的文件以及庫文件到你的應(yīng)用中即可.
(四) 調(diào)用服務(wù)
調(diào)用服務(wù)的方式有三種:靜態(tài)調(diào)用,動態(tài)調(diào)用,動態(tài)調(diào)用接口.
1 靜態(tài)調(diào)用,使用了wscompile生成的靜態(tài)樁文件.
package hello;
import javax.xml.rpc.Stub;
import staticstub.*;
public class HelloClient {
private String endpointAddress;
public static void main(String[] args) {
args=new String[]{"http://localhost:8080/skysoft/hello?WSDL"};
System.out.println("Endpoint address = " + args[0]);
try {
Stub stub = createProxy();
stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
args[0]);
HelloIF hello = (HelloIF) stub;
System.out.println(hello.sayHello("Duke!"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static Stub createProxy() {
// Note: MyHelloService_Impl is implementation-specific.
return (Stub) (new MyHelloService_Impl().getHelloIFPort());
}
}
2 動態(tài)調(diào)用,主要是使用ServiceFactory來執(zhí)行調(diào)用.
package hello;
import java.net.URL;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
//import dynamicproxy.HelloIF;
import staticstub.HelloIF;
public class DynClient {
public static void main(String[] args) {
try {
args = new String[] { "http://localhost:8080/skysoft/hello" };
String UrlString = args[0] + "?WSDL";
String nameSpaceUri = "urn:Foo";
String serviceName = "MyHelloService";
String portName = "HelloIFPort";
System.out.println("UrlString = " + UrlString);
URL helloWsdlUrl = new URL(UrlString);
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service helloService = serviceFactory.createService(helloWsdlUrl,
new QName(nameSpaceUri, serviceName));
HelloIF myProxy = (HelloIF) helloService.getPort(new QName(
nameSpaceUri, portName), HelloIF.class);
System.out.println(myProxy.sayHello("Buzz"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
3 動態(tài)調(diào)用接口(DII),這種方式不需要任何附加代碼,根據(jù)WSDL提供的調(diào)用方法的元描述,動態(tài)確定方法及其參數(shù)返回類型,有些類似于CORBA的接口池提供的服務(wù).package hello;
import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.ParameterMode;
public class DiiClient {
private static String qnameService = "MyHelloService";
private static String qnamePort = "HelloIF";
private static String BODY_NAMESPACE_VALUE = "urn:Foo";
private static String ENCODING_STYLE_PROPERTY = "javax.xml.rpc.encodingstyle.namespace.uri";
private static String NS_XSD = "http://www.w3.org/2001/XMLSchema";
private static String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";
public static void main(String[] args) {
args=new String[]{"http://localhost:8080/skysoft/hello?WSDL"};
System.out.println("Endpoint address dii = " + args[0]);
try {
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(new QName(qnameService));
QName port = new QName(qnamePort);
Call call = service.createCall(port);
call.setTargetEndpointAddress(args[0]);
call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);
QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
call.setReturnType(QNAME_TYPE_STRING);
call.setOperationName(new QName(BODY_NAMESPACE_VALUE, "sayHello"));
call.addParameter("String_1", QNAME_TYPE_STRING, ParameterMode.IN);
String[] params = { "Murph!" };
String result = (String) call.invoke(params);
System.out.println(result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
到此,這個Web Service入門描述就結(jié)束了,它提供了WS的Sun描述,以及在tomcat上發(fā)布服務(wù)的過程和一個構(gòu)建腳本,借助jsp插件,使用Eclipse完成了一個簡單的Web服務(wù)開發(fā),發(fā)布,并用三種方式進(jìn)行了測試.