Продолжим
серию статей про web
сервисы, здесь я вам расскажу про технологию WS-Policy. WS-Policy
это стандарт который позволяет внедрять в файл описания wsdl новый функционал, т.е. мы вносим в логику web сервиса новые правила поведения. И так по
умолчанию в нашем примере механизм MTOM выключен,
мы посредством политики включим его, он нужен нам для оптимизации передачи
бинарных данных. Подробно, как включать на уровне java кода MTOM, читайтев моей прошлой статье.
Я для примера буду использовать Oracle
Weblogic 12c application server, т. к. в apache CXF я не какими методами не смог включить MTOM посредством внедрения политики WS-Policy в wsdl файл, Weblogic позволяет это сделать. Напишем наш web сервис:
package org.lopanov;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public interface Hello {
@WebMethod
public String sayHello(String name);
@WebMethod
public void getBinary(byte[] b);
}
И класс
который реализует его:
package org.lopanov;
import javax.jws.WebService;
@WebService( endpointInterface =
"org.lopanov.Hello")
public class HelloWorld implements Hello {
public String sayHello(String name){
String result = String.format("Hello, %s!", name);
System.out.println(result);
return result;
}
public void getBinary(byte[] b)
{
try {
System.out.write(b);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Соберите
наш web сервис в .war архив и разверните
его на сервере. Напишем клиента который
будет работать с ним:
package org.lopanov;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
public class Main1 {
private static final QName SERVICE_NAME = new
QName("http://lopanov.org/", "HelloWorldService");
private static final QName PORT_NAME = new
QName("http://lopanov.org/", "HelloWorldPort");
public static void main(String args[]) throws Exception {
Service service = Service.create(new
URL("http://169.254.201.140:7001/hello-ws/HelloWorldService?WSDL"),
SERVICE_NAME);
Hello hw = service.getPort(PORT_NAME, Hello.class);
File file = new File("c:/1.txt");
FileInputStream fis = new FileInputStream(file);
byte[] b = new byte[1024 * 1];
fis.read(b, 0, b.length);
hw.getBinary(b);
//System.out.println(hw.sayHi("World"));
System.exit(0);
}
}
Клиент
посылает байтовый массив, считанный из файла, операции
getBinary() web сервиса, операция распечатывает его в стандартный
вывод, при этом используется такое SOAP сообщение:
C:\jdk1.8.0_31\bin\java -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
org.lopanov.Main1
---[HTTP request -
http://169.254.201.140:7001/hello-ws/HelloWorldService]---
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction:
"http://lopanov.org/Hello/getBinaryRequest"
User-Agent: JAX-WS RI 2.2.11-b150616.1732
svn-revision#a247ba216861f2c0baac9a3657c5690bce0c744d
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope
xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns0:getBinary
xmlns:ns0="http://lopanov.org/">
<arg0>PT09 …
T24tbA==</arg0>
</ns0:getBinary>
</S:Body></S:Envelope>--------------------
Заметьте,
что данные пересылаются в теле SOAP
сообщения
<arg0>PT09 … T24tbA==</arg0>, и у нас не используется технология MTOM. Для включения логирования SOAP сообщений я использовал параметр -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true при вызове клиента, используйте его только в
стеке METRO (Glassfish и Weblogic). Давайте встроим политику в наш wsdl файл которая включит нам механизм MTOM. Как вы заметили мы используем метод разработки “contract-last”, т.е сначало код, потом генерация файла wsdl, еще этот
метод разработки называют “code-first”. И так нам нужно внедрить файл с политикой ws-mtom, это для Weblogic делается посредствам двух аннотаций, основной @Policies()
которая содержит в себе массив аннотаций @Policy(), которые в свою очередь
содержат сылки в параметре uri на файлы ws-policy, которые
будут внедрены в wsdl
файл. Перепишем наш класс используя аннотации:
package
org.lopanov;
import
weblogic.jws.Policies;
import
weblogic.jws.Policy;
import
javax.jws.WebService;
@WebService( endpointInterface =
"org.lopanov.Hello")
@Policies(
{ @Policy(uri = "policy:Mtom.xml",attachToWsdl = true,direction =
Policy.Direction.both) } )
public class HelloWorld implements Hello {
…
public void getBinary(byte[] b) {
try {
System.out.write(b);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Нужно
сказать про одну особенность параметра uri,
он берет все файлы из деректории WEB-INF/policies хотя использует префикс “policy” uri =
"policy:Mtom.xml" ,
смотрите на рисунок.
Создадим
файл Mtom.xml:
<?xml version="1.0"
encoding="utf-8"?>
<wsp:Policy
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"
xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsam="http://www.w3.org/2007/01/addressing/metadata"
wsu:Id="AddNumbersAsynch_policy">
<wsp:ExactlyOne>
<wsp:All>
<wsoma:OptimizedMimeSerialization
wsp:Optional="false" xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization"/>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Расмотрим файл
Mtom.xml, это обычный xml файл, главный
тег <wsp:Policy> в схеме xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" описаны все
возможные теги, их 4 и один атрибут. Они
являются обертками для других тегов из других пространств имен. Логика в них вложена булевская (boolean).
Включение MTOM
производит тег <wsoma:OptimizedMimeSerialization из пространства имен xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization"
Тег <wsp:ExactlyOne>
говорит что должен сработать/включится одно из правил, булевское “ИЛИ”.
Для примера введем еще тег <wsam:Addressing />:
<wsp:ExactlyOne>
<wsp:All>
<wsoma:OptimizedMimeSerialization wsp:Optional="false" />
</wsp:All>
“ИЛИ”
<wsp:All>
<wsam:Addressing />
</wsp:All>
</wsp:ExactlyOne>
Т.е. должно
быть включено/сработать правило или <wsoma:OptimizedMimeSerialization /> или <wsam:Addressing /> или оба сразу. Тег <wsp:All>
включает все правила, работает как булевское “И”:
<wsp:All>
<wsp:ExactlyOne>
<wsoma:OptimizedMimeSerialization wsp:Optional="false"
/>
“И”
вложенное правило
<wsp:All>
<wsp:ExactlyOne>
<wsam:Addressing />
</wsp:ExactlyOne>
</wsp:All>
</wsp:ExactlyOne>
</wsp:All>
Должны
примениться оба правила и <wsoma:OptimizedMimeSerialization /> и <wsam:Addressing />.
Атрибут может быть применен к любому тегу
который включает определенную политику <wsoma:OptimizedMimeSerialization
wsp:Optional="false" /> и он говорит сервису что любое
правило может быть не обязательным, если выставлено в true. Т.е. мы посредством его можем нарушить наши логические “ИЛИ” , “И” тегов <wsp:ExactlyOne>, <wsp:All>, а
точнее это наша страховка от тех реализаций web сервисов которые не поддерживают определенные
политики. Например для Apache
CXF не поддерживается политика ws-mtom
и если провернуть этот пример который вам я
описываю c
Apache CXF, то мы получим такие ошибки:
--------------------------------------
[qtp372469954-16] ERROR
org.apache.cxf.ws.policy.PolicyVerificationInInterceptor - Inbound policy
verification failed: These policy alternatives can not be satisfied:
{http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization}OptimizedMimeSerialization
[qtp372469954-16] WARN
org.apache.cxf.phase.PhaseInterceptorChain - Interceptor for
{http://lopanov.com/}HelloWorldImplService#{http://lopanov.com/}getBinary has
thrown exception, unwinding now
org.apache.cxf.ws.policy.PolicyException:
These policy alternatives can not be satisfied:
{http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization}OptimizedMimeSerialization
Если мы выставим
так <wsoma:OptimizedMimeSerialization
wsp:Optional="true" />, то Apache CXF
не
найдя реализации политики ws-mtom в своих библиотеках, просто проигнорирует обязательное правило и не выдаст ошибки.
Пересоберем проект и заново его развернем, запустим клиента и получим такое SOAP сообщение:
---[HTTP request - http://169.254.201.140:7001/hello-ws/HelloWorldService]---
Accept: text/xml, multipart/related
Content-Type:
multipart/related;start="<rootpart*7d971f60-868e-44ec-98bb-68b0d5cb720e@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:7d971f60-868e-44ec-98bb-68b0d5cb720e";start-info="text/xml"
SOAPAction:
"http://lopanov.org/Hello/getBinaryRequest"
User-Agent: JAX-WS RI 2.2.11-b150616.1732
svn-revision#a247ba216861f2c0baac9a3657c5690bce0c744d
--uuid:7d971f60-868e-44ec-98bb-68b0d5cb720e
Content-Id:
<rootpart*7d971f60-868e-44ec-98bb-68b0d5cb720e@example.jaxws.sun.com>
Content-Type:
application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary
<?xml version='1.0'
encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body>
<ns0:getBinary
xmlns:ns0="http://lopanov.org/">
<arg0>
<xop:Include
href="cid:56c625fb-2cc0-4188-8654-6e39d4274c50@example.jaxws.sun.com"
xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
</arg0>
</ns0:getBinary>
</S:Body></S:Envelope>
--uuid:7d971f60-868e-44ec-98bb-68b0d5cb720e
Content-Id: <56c625fb-2cc0-4188-8654-6e39d4274c50@example.jaxws.sun.com>
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
===========================================================================
......Realtek PCIe GBE Family Controller
......VMware Virtual Ethernet Adapter for
VMnet1
......VMware Virtual Ethernet Adapter for
VMnet8
1...........................Software Loopback Interface 1
14...00 00 00 00 00 00 00 e0 ������ Microsoft ISATAP
15...00 00 00 00 00 00 00 e0 ������ Microsoft ISATAP #2
16...00 00 00 00 00 00 00 e0 ������ Microsoft ISATAP #3
127.255.255.255 255.255.255.255 On-l
--uuid:7d971f60-868e-44ec-98bb-68b0d5cb720e----------------------
Из него
видно что политика сработала для нашего примера и MTOM включен. Давайте расмотрим файл WSDL, как в
него встроилась наша политика:
<definitions
targetNamespace="http://lopanov.org/"
name="HelloWorldService">
<wsp:UsingPolicy
wssutil:Required="true"/>
<wsp1_2:Policy
wssutil:Id="Mtom">
<wsp1_2:ExactlyOne>
<wsp1_2:All>
<ns1:OptimizedMimeSerialization/>
</wsp1_2:All>
</wsp1_2:ExactlyOne>
</wsp1_2:Policy>
<types>
<xsd:schema>
<xsd:import namespace="http://lopanov.org/"
schemaLocation="http://169.254.201.140:7001/hello-ws/HelloWorldService?xsd=1"/>
</xsd:schema>
</types>
<message name="sayHello">
<part name="parameters"
element="tns:sayHello"/>
</message>
<message
name="sayHelloResponse">
<part name="parameters" element="tns:sayHelloResponse"/>
</message>
<message name="getBinary">
<part name="parameters"
element="tns:getBinary"/>
</message>
<message
name="getBinaryResponse">
<part name="parameters"
element="tns:getBinaryResponse"/>
</message>
<portType name="Hello">
<operation name="sayHello">
<input
wsam:Action="http://lopanov.org/Hello/sayHelloRequest"
message="tns:sayHello"/>
<output
wsam:Action="http://lopanov.org/Hello/sayHelloResponse"
message="tns:sayHelloResponse"/>
</operation>
<operation name="getBinary">
<input
wsam:Action="http://lopanov.org/Hello/getBinaryRequest"
message="tns:getBinary"/>
<output
wsam:Action="http://lopanov.org/Hello/getBinaryResponse"
message="tns:getBinaryResponse"/>
</operation>
</portType>
<binding name="HelloWorldPortBinding"
type="tns:Hello">
<wsp:PolicyReference
URI="#Mtom"/>
<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>
<operation name="getBinary">
<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="http://169.254.201.140:7001/hello-ws/HelloWorldService"/>
</port>
</service>
</definitions>
В файле появились строки из нашего файла Mtom.xml
и появился
четвертый тег <wsp:PolicyReference URI="#Mtom"/>
который применяет политику к уровню “Конечная точка”, тегу <binding … болле подробно о теории ws-policy о привязке, можно почитать перейдя по сылке http://www.ibm.com/developerworks/ru/library/j-jws18/
И на
последок привожу свой maven
pom.xml с зависимостями библиотек, определенные зависимости я беру в
домашней деректории куда установлен Weblogic, пометил
желтым цветом:
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.lopanov</groupId>
<artifactId>hello-ws</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>hello-ws Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>weblogic</groupId>
<artifactId>weblogic</artifactId>
<version>12.2.1-0-0</version>
<scope>system</scope>
<systemPath>C:/Oracle_Home/wlserver/server/lib/weblogic.jar</systemPath>
</dependency>
<dependency>
<groupId>wls-api</groupId>
<artifactId>wls-api</artifactId>
<version>12.2.1</version>
<scope>system</scope>
<systemPath>C:/Oracle_Home/wlserver/server/lib/wls-api.jar</systemPath>
</dependency>
</dependencies>
<build>
<finalName>hello-ws</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>