2006年 7月 25日 火曜日 为什么转用document/literal而不是rpc/encoded
遵循document/literal符合WS-I的规定,在制作Web Services时,JAX-WS 2.0和VS.NET
2003在默认的情况下,都是生成document/literal服务.那么和rpc/encoded服务相比,
document/literal有哪些优点呢.
-
document/literal符合XML Schema的形式,可以用XML validator对传递的信息进行校对.
-
rpc/encoded时的信息中,含有数据类型的记述.如果数据增加,所传递的数据量会增加,这样会影响性能.而documeht/literal使用了在服务端和客户端共享的WSDL中的信息,从而可以省略数据类型的传递.
Accessing JAX-WS 2.0 with SSL in Glassfish
作業ディレクトリは、図1になります。
図 1.
1.サーバー側
package endpoint;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.annotation.Resource;
import javax.xml.ws.WebServiceContext;
@WebService(
name="MyHelloWorld",
serviceName="MyHelloWorldService",
targetNamespace="http://javaee5.com/jaxws/helloworld"
)
public class HelloWorld{
//the implementation class must have a default public constructor
public HelloWorld() {};
//
@Resource WebServiceContext wsContext;
@WebMethod(operationName="mySayHello", action="urn:mySayHello")
public String sayHello(String name){
return name + "'s user principal is "
+ wsContext.getUserPrincipal();
}
}
JAX-WS 2.0からJSR 181のannotationを使って、直接にサービスクラスを実装するだけで、開発はとてもシンプルとなってます。 List 1.をコンパイルして、 Glassfishから提供されているユーティリティwsgenを用いて、対応したWSDLファイルを生成できます。
~/ssl> javac -classpath %GLASSFISH_HOME%/lib/javaee.jar -d ./build/classes/service -g endpoint/HelloWorld.java
~/ssl> wsgen.bat -cp ./build/classes/service -keep -d ./build/classes/service -r ./build/generated -wsdl endpoint.HelloWorld
warファイルをパッケージするには、List 2.のweb.xmlを使います。相互認証を行うため、<auth-method>ではCLIENT-CERTと設定します。サービスクラスはWebServiceContext.getUserPrincipal()を読んでるため、その設定はList 3.のsun-web.xmlの<security-role-mapping>で行います。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:j2ee="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<description>WebTier for the HelloWorld Service</description>
<display-name>HelloWorldWAR</display-name> <servlet>
<description>Endpoint for HelloWorld Web Service</description>
<display-name>HelloWorldWebService</display-name>
<servlet-name>MyHelloWorld</servlet-name>
<servlet-class>endpoint.HelloWorld</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>MyHelloWorld</servlet-name>
<url-pattern>/HelloWorldService</url-pattern>
</servlet-mapping> <security-constraint>
<web-resource-collection>
<web-resource-name>Secure Area</web-resource-name>
<url-pattern>/HelloWorldService</url-pattern>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>ENGINEER</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>certificate</realm-name>
</login-config>
<security-role>
<role-name>ENGINEER</role-name>
</security-role>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app
PUBLIC "-//Sun Microsystems,
Inc.//DTD Application Server 9.0 Servlet 2.5//EN"
"http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd">
<sun-web-app>
<context-root>/HelloWorldService</context-root>
<security-role-mapping>
<role-name>ENGINEER</role-name>
<principal-name>
CN=zerra, OU=JPE, O=Sun, L=HaiDian, S=Beijing, C=China
</principal-name>
</security-role-mapping>
</sun-web-app>
asadminコマンドツールを使ってデプロイします。
~/ssl/archive> jar cvf helloworld-webservice.war WEB-INF/
~/ssl/archive> asadmin.bat deploy --user admin --passwordfile s1as_password.txt --host localhost --port 4848 --contextroot helloworld-webservice --upload=true --target server helloworld-webservice.war
2.クライアント側
サーバーで公開されているサービス(WSDL)から、Glassfishのユーティリティwsimportを使い、アクセスするためのクラスを生成します。
~/ssl> wsimport.bat -keep -d ./build/classes/client https://zerra:8181/helloworld-webservice/HelloWorldService?WSDL
生成されたクラスをimportして、クライアントのクラス(List 4.)を作ります。WebServiceRefのwsdlLocationでhttpsの指定にご注目。そしてクラスパスを指定し、クラスをコンパイルします。
package client;
import javax.xml.ws.WebServiceRef;
import com.javaee5.jaxws.helloworld.MyHelloWorldService;
import com.javaee5.jaxws.helloworld.MyHelloWorld;
public class WSClient{
@WebServiceRef(wsdlLocation=
"https://zerra:8181/helloworld-webservice/HelloWorldService?WSDL")
static MyHelloWorldService service;
public static void main(String[] args){
try{
WSClient client = new WSClient();
client.callEndpoint(args[0]);
}catch(Exception e){
e.printStackTrace();
}
}
public void callEndpoint(String name){
try{
MyHelloWorld port = service.getMyHelloWorldPort();
System.out.println(port.mySayHello(name));
}catch(Exception e){
e.printStackTrace();
}
}
}
~/ssl> javac -d ./build/classes/client -classpath %GLASSFISH_HOME%/lib/javaee.jar\;$GLASSFISH_HOME/lib/appserv-ws.jar\;./build/classes/client client/WSClient.java
サーバーと相互認証を行うには、クライアントが自分のキーを生成する必要があり、それをサーバーにあるトラストストーアに導入します。具体的な手順はImport Client's cert into Glassfishに書いてあります。
準備が整ったら、サーバーのトラストストーアとクライアントのキーストーアをVMARGSという環境変数に設定し、実行します。
~/ssl/build/classes/client> set VMARGS=-Djavax.net.ssl.trustStore=%GLASSFISH_HOME%/domains/domain1/config/cacerts.jks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.keyStore=E:\ssl\clientCertificate\xiaojunkeystore.jks -Djavax.net.ssl.keyStorePassword=changeit
~/ssl/build/classes/client> appclient.bat client.WSClient Duke
Duke's user principal is CN=zerra, OU=JPE, O=Sun, L=HaiDian, S=Beijing, C=China
Posted by xiaojun ( 6月 14日 2006年, 04:26:02 午後 JST ) Permalink 投稿されたコメント [0]
Import Client's cert into Glassfish
Glassfishと双方向認証を行うには、クライアントが自分のkeyを生成し、それをGlassfishサーバーサイドにあるトラストストーアに導入する必要があります。 以下その手順を示します。
1.クライアント側のkeyの生成
JDK 5.0で提供されているkeytoolを使い、簡単にkeyを生成できます。
keytool -genkey -validity 10000 -alias clientkey -dname "CN=zerra, OU=JPE, O=Sun, L=HaiDian, S=Beijing, C=China" -keypass changeit -storepass changeit
2.クライアントの証明書の導出
keytool -export -alias clientkey -storepass changeit -file client.cer -keystore clientstore.jks
このコマンドにより、キー情報が中間ファイルclient.cerに保存されます。
3.クライアントの証明書の導入
keytool -import -noprompt -v -trustcacerts -alias clientkey -file client.cer -keystore ${GLASSFISH_HOME}/domains/domain1/config/cacerts.jks -storepass changeit
${GLASSFISH_HOME}が実際のインストールパスをあらわします。これで、クライアントの証明書がサーバーにあるトラストストーアに保存されました。
下のコマンドを発行し、clientkeyをgrepして確認できます。
keytool -list -v -keystore cacerts.jks -storepass changeit
別名: clientkey
作成日: 2006/06/05
エントリのタイプ: trustedCertEntry
所有者: CN=zerra, OU=JPE, O=Sun, L=HaiDian, ST=Beijing, C=China
実行者: CN=zerra, OU=JPE, O=Sun, L=HaiDian, ST=Beijing, C=China
シリアル番号: 4483a90a
有効日: Mon Jun 05 12:46:18 JST 2006 有効期限: Fri Oct 21 12:46:18 JST 2033
証明書のフィンガープリント:
MD5: 2B:A2:0C:5C:0D:D6:4C:00:09:A3:84:B0:A6:60:53:4D
SHA1: A4:CE:41:4E:12:F3:EB:29:5A:8A:A0:76:87:08:C8:0D:C5:1D:A7:E3
また、証明書をトラストストーアから削除するには、下のコマンドで消せます。
keytool -delete -alias clientkey -keystore ${GLASSFISH_HOME}/domains/domain1/config/cacerts.jks -storepass changeit
Posted by xiaojun ( 6月 07日 2006年, 11:01:34 午前 JST ) Permalink 投稿されたコメント [0]
JAX-WS 2.0 Java<===>WSDL1.1 mappings (written in Japanese)
別のスレッドで書いたサンプルをいじって(文章が中国語となってますが、クラスやコマンドが化けないと思うが)、Java<===>WSDL1.1のマッピングをみていきたいと思います。
まず、List1を使って、annotationsのWebServiceとWebMethodの属性のデフォルト値を確認します。Glassfishに提供されているwsgenを使って、WSDLファイル(List2)を生成します。
List 1 (HelloWorld.java)@WebService()
public class HelloWorld{
//the implementation class must have a default public constructor
public HelloWorld() {};
@WebMethod()
public String sayHello(String name){
return "Hello "+ name + "!";
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://endpoint/" name="HelloWorldService" xmlns:tns="http://endpoint/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema>
<xsd:import namespace="http://endpoint/" schemaLocation="HelloWorldService_schema1.xsd"/>
</xsd:schema>
</types>
<message name="sayHello">
<part name="parameters" element="tns:sayHello"/>
</message>
<message name="sayHelloResponse">
<part name="parameters" element="tns:sayHelloResponse"/>
</message>
<portType name="HelloWorld">
<operation name="sayHello">
<input message="tns:sayHello"/>
<output message="tns:sayHelloResponse"/>
</operation>
</portType>
<binding name="HelloWorldPortBinding" type="tns:HelloWorld">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="sayHello">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="HelloWorldService">
<port name="HelloWorldPort" binding="tns:HelloWorldPortBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>
クラスHelloWorldがportTypeのnameに、メソッド名sayHelloがportTypeの子要素operationの名前にそれぞれとマッピングされているのが分かります。
ここで、annotationsのWebService、WebMethodの属性を指定して(List 3)、List 4のWSDLが生成されます。
@WebService(
name="MyHelloWorld",
serviceName="MyHelloWorldService",
targetNamespace="http://javaee5.com/jaxws/helloworld"
)
public class HelloWorld{
//the implementation class must have a default public constructor
public HelloWorld() {};
@WebMethod(operationName="mySayHello", action="urn:mySayHello")
public String sayHello(String name){
return "Hello "+ name + "!";
}
}<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions
targetNamespace="http://javaee5.com/jaxws/helloworld"
name="MyHelloWorldService"
xmlns:tns="http://javaee5.com/jaxws/helloworld"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema>
<xsd:import namespace="http://javaee5.com/jaxws/helloworld" schemaLocation="MyHelloWorldService_schema1.xsd"/>
</xsd:schema>
</types>
<message name="mySayHello">
<part name="parameters" element="tns:mySayHello"/>
</message>
<message name="mySayHelloResponse">
<part name="parameters" element="tns:mySayHelloResponse"/>
</message>
<portType name="MyHelloWorld">
<operation name="mySayHello">
<input message="tns:mySayHello"/>
<output message="tns:mySayHelloResponse"/>
</operation>
</portType>
<binding name="MyHelloWorldPortBinding" type="tns:MyHelloWorld">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document"/>
<operation name="mySayHello">
<soap:operation soapAction="urn:mySayHello"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="MyHelloWorldService">
<port name="MyHelloWorldPort" binding="tns:MyHelloWorldPortBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>
グラフ1にマッピング関係を示しています。
グラフ 1
ここで見た例はstyle/useに関して暗黙でDocument/Literalが使用されますが、
List 5 (SOAPBindingの指定)@WebService
@SOAPBinding(style=SOAPBinding.Style.RPC, use=SOAPBinding.Use.ENCODED)
public class HelloWorld{
//the implementation class must have a default public constructor
public HelloWorld() {};
@WebMethod(operationName="mySayHello",
action="urn:mySayHello")
public String sayHello(String name){
return "Hello "+ name + "!";
}
}
List 5のようにSOAPBinding属性の指定を通して、RPC/Encodedに変えられます。
他にも、Oneway、WebParamなどがありますので、用途に応じてカスタマイズできます。
Posted by xiaojun ( 2月 24日 2006年, 09:18:16 午後 JST ) Permalink 投稿されたコメント [1]
JAX-WS 2.0, an HelloWorld例子 (written in Chinese)
在JAX-RPC 1.1中,开发人员需要写一个接口类Service Endpoint Interface(SEI),在JAX-WS 2.0中,开发人员一上来就可以直接写自己的实现类. 通过使用annotations,自动生成SEI和其他一些文件.这样有助于开发人员专注于自己想开发的部分,而不必要地分散精力去维护其他的一些附属文件.
下面通过一个HelloWorld的例子来看看,JAX-WS 2.0 API的应用过程.程序是客户端传给服务端一个名字,经过服务端处理后,返回到客户端并打印出来.
一. 环境配置.
1.
JDK 5.0 下载: http://java.sun.com/j2se/1.5.0/download.jsp
2.
Java EE 5.0 App Server.
https://glassfish.dev.java.net/public/downloadsindex.html
本例中测试用了Build 37
下载完毕后请设置一下Path.还有例子中使用的命令对应于Cygwin,如果用Dos或Linux的话,请适当更改相应的形式.
例子中执行中的命令行以E:\jaxws20为基准,在其下面创造相对应的文件夹.
二.编写建立服务端
1.
实现类.
package endpoint;
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService()
public class HelloWorld{
//the implementation class must
have a default public constructor
public HelloWorld() {};
@WebMethod(operationName="sayHello", action="urn:SayHello")
public String sayHello(String
name){
return "Hello "+ name + "!";
}
}
请注意实现类必须标注WebService(),还必须包括一个default public constructor.
2.
编译实现类.
编译前,创造相应文件夹build/classes/service来保存class文件.还请注意命令在同一行.
javac -classpath $GLASSFISH_HOME/lib/javaee.jar -d
./build/classes/service endpoint/HelloWorld.java
3.
生成相应文件
在E:\jaxws20下,执行下面的命令,注意事先生成/build/generated.
$GLASSFISH_HOME/bin/wsgen.bat-cp ./build/classes/service -keep -d ./build/classes/service -r ./build/generated -wsdl endpoint.HelloWorld
通过这个命令,会生成相对应的WSDL文件.
4.
打包
4.1 WEB-INF`结构准备
WEB-INF/classes/
WEB-INF/wsdl/
4.2 Web.xml
在WEB-INF/下,编写下面的文件.
<?xml version="1.0"
encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:j2ee="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<description>HelloWorld Service</description>
<display-name>HelloWorldWAR</display-name>
<servlet>
<description>Endpoint for HelloWorld Web
Service</description>
<display-name>HelloWorldWebService</display-name>
<servlet-name>HelloWorldPort</servlet-name>
<servlet-class>endpoint.HelloWorld</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldPort</servlet-name>
<url-pattern>/HelloWorldService</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
4.3 拷贝文件
cp -r build/classes/service/endpoint ./WEB-INF/classes/
cp build/generated/* archive/WEB-INF/wsdl/
4.4打包
jar cvf helloworld-webservice.war WEB-INF/
5.
配置
先启动服务器,
asadmin.bat
start-domain domain1
配置到服务器中,
asadmin.bat deploy
--user admin --password adminadmin --host localhost --port 4848 --contextroot
helloworld-webservice --upload=true --target server
helloworld-webservice.war
三. 客户端
1.
客户端类.
在client/下,
package
client;
import
javax.xml.ws.WebServiceRef;
import
endpoint.HelloWorldService;
import
endpoint.HelloWorld;
public class
WSClient{
@WebServiceRef(wsdlLocation=
"http://localhost:8080/helloworld-webservice/HelloWorldService?WSDL")
static
HelloWorldService service;
public static
void main(String[] args){
try{
WSClient client
= new WSClient();
client.callEndpoint(args[0]);
}catch(Exception e){
e.printStackTrace();
}
}
public void
callEndpoint(String name){
try{
HelloWorld port
= service.getHelloWorldPort();
System.out.println(port.sayHello(name));
}catch(Exception e){
e.printStackTrace();
}
}
}
2.
生成相关文件
在编译客户端类之前, 需要从服务端公开中的WSDL生成相关的文件.
wsimport.bat
-keep -d ./build/classes/client http://localhost:8080/helloworld-webservice/HelloWorldService?WSDL
3.
编译客户端类
javac-d ./build/classes/client -classpath $GLASSFISH_HOME/lib/javaee.jar\;$GLASSFISH_HOME/lib/appserv-ws.jar\;./build/classes/client client/WSClient.java
四. 执行
在build/classes/client/下,
appclient.bat
-mainclass
client.WSClient Duke
你会看到如下反馈
Hello Duke!
追加: 通过下面的命令,可以卸掉装配好的war文件.
asadmin.bat undeploy
--user admin --password adminadmin helloworld-webservice