Web Services

Transkrypt

Web Services
Web Services
1. Podstawy usług sieciowych.
●
SOAP,
●
WSDL.
2. Usługi sieciowe w JAX-RPC.
●
interfejs punktu końcowego,
●
korzystanie z usługi z poziomu komponentu EJB,
●
programy klienckie,
●
narzędzia i deskryptory XML.
3. Usługi sieciowe w JAX-WS.
●
adnotacje,
●
korzystanie z usługi.
1
SOAP
Przykładowy interfejs:
public interface TravelAgent {
public void makeReservation(int cruiseID, int cabinID,
int customerId, double price);
}
Wywołanie metody poprzez SOAP:
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:titan="http://www.titan.com/TravelAgent"/>
<env:Body>
<titan:makeReservation>
<cruiseId>23</cruiseId>
<cabinId>144</cabinId>
<customerId>9393</customerId>
<price>5677.88</price>
</titan:makeReservation>
</env:Body>
</env:Envelope>
2
WSDL
Aby udostępnić usługę poprzez sieć jako tzw. WebService należy
przygotować jej opis w języku WSDL (WebService Description
Language). Na jego podstawie klienci korzystający z usługi wiedzą
w jaki sposób przesyłać i interpretować odebrane dane. Umożliwia to
automatyzację procesu przesyłu danych i pozwala programiście
skoncentrować się na logice aplikacji.
3
WSDL – opis usługi
WSDL służy do informowania klienta o dostępnych usługach
sieciowych:
<?xml version="1.0"?>
<definitions name="TravelAgent"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:titan="http://www.titan.com/TravelAgent"
targetNamespace="http://www.titan.com/TravelAgent">
<!-- message: opis parametrów wywołania i wyników -->
<message name="RequestMessage">
<part name="cruiseId" type="xsd:int" />
<part name="cabinId" type="xsd:int" />
<part name="customerId" type="xsd:int" />
<part name="price" type="xsd:double" />
</message>
<message name="ResponseMessage">
<part name="reservationId" type="xsd:string" />
</message>
4
WSDL – opis usługi
<!-- portType opisuje interfejs usługi sieciowej -->
<portType name="TravelAgent">
<operation name="makeReservation">
<input message="titan:RequestMessage"/>
<output message="titan:ResponseMessage"/>
</operation>
</portType>
Element <portType> opisuje dostępne operacje (metody Javy).
Operacja posiada wejście <input> i wyjście <output> oraz informacje
o błędach (dowolną liczbę) <fault>.
EJB 3.0 wspiera dwa typy usług sieciowych:
●
request-response – pojedynczy element <input> i <output> oraz
ew. <fault>,
●
one-way - wyłącznie <input>.
5
WSDL – opis usługi
<!-- binding informuje o protokole i kodowaniu -->
<binding name="TravelAgentBinding" type="titan:TravelAgent">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="makeReservation">
<soap:operation soapAction="" />
<input>
<soap:body use="literal"
namespace="http://www.titan.com/TravelAgent"/>
</input>
<output>
<soap:body use="literal"
namespace="http://www.titan.com/TravelAgent"/>
</output>
</operation>
</binding>
Usługa będzie dostępna poprzez protokół SOAP.
6
WSDL – opis usługi
<!-- service: adres usługi -->
<service name="TravelAgentService">
<port name="TravelAgentPort"
binding="titan:TravelAgentBinding">
<soap:address
location="http://www.titan.com/webservices/TravelAgent"/>
</port>
</service>
</definitions>
Na zakończenie określamy adres pod którym usługa będzie widoczna
w sieci internet.
7
Dostęp do WebServices
poprzez JAX-RPC
JAX-RPC umożliwia dostęp do usług sieciowych opartych na dowolnych
platformach sprzętowych i programowych.
1
program
kliencki
2
pośrednik
4
Web Service
3
Pośrednik (proxy) może być generowany dynamicznie na podstawie
pobranej z serwera specyfikacji usługi zapisanej w języku WSDL. Do
utworzenia tzw. interfejsu punktu końcowego (endpoint interface)
wykorzystuje się dane zawarte w elemencie portType.
8
Interfejs punktu końcowego
<message name="chargeRequest">
<part name="name" type="xsd:string"/>
<part name="number" type="xsd:string"/>
<part name="exp-date" type="xsd:dateTime"/>
<part name="card-type" type="xsd:string"/>
<part name="amount" type="xsd:float"/>
</message>
<message name="chargeResponse">
<part name="return" type="xsd:int"/>
</message>
<portType name="Processor">
<operation name="charge">
<input message="tns:chargeRequest"/>
<output message="tns:chargeResponse"/>
</operation>
</portType>
package com.charge_it;
public interface Processor extends java.rmi.Remote{
public int charge(String name, String number,
java.util.Calendar expDate, String cardType,
float amount) throws java.rmi.RemoteException;
}
9
Adres usługi
<service name="ProcessorService">
<port name="ProcessorPort" binding="tns:ProcessorSoapBinding">
<soap:address
location="http://www.charge-it.com/ProcessorService"/>
</port>
</service>
Adres usługi jest podany w elemencie service. Element bingings
zawiera specyfikacje odnośnie wykorzystywanego protokołu.
<binding name="ProcessorSoapBinding" type="tns:Processor">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="charge">
<soap:operation soapAction="" style="rpc"/>
<input><soap:body use="literal"
namespace="http://charge-it.com/Processor"/>
</input>
<output><soap:body use="literal"
namespace="http://charge-it.com/Processor"/>
</output>
</operation>
</binding>
10
Adres usługi
Oprócz interfejsu końcowego, w oparciu o element service tworzony
jest interfejs usługi:
package com.charge_it;
public interface ProcessorService extends javax.xml.rpc.Service{
public Processor getProcessorPort()
throws javax.xml.rpc.ServiceException;
public Processor getProcessorPort(URL portAddress)
throws javax.xml.rpc.ServiceException;
public String getProcessorPortAddress( );
}
Interfejs usługi pozwala na utworzenie pośrednika (Processor),
poprzez którego otrzymamy dostęp do usługi sieciowej.
11
Korzystanie z usługi
sieciowej w obrębie EJB
...
@Stateful
public class AnyBean implements AnyRemote {
private ProcessorService service;
...
public void aMethod(...) throws EJBException{
...
try{
Processor processor = service.getProcessorPort();
processor.charge(customerName, card.number, expDate,
card.type, price);
...
}catch(Exception e) { throw new EJBException(e); }
}
}
UWAGA: wystąpienie błędu (zwrócenie wyjątku) spowoduje
anulowanie operacji wykonanych przez komponent w ramach
transakcji, jednak nie spowoduje odwołania zmian wykonanych przez
usługę sieciową.
12
Korzystanie z usługi
sieciowej w obrębie EJB
Parametry wstrzyknięcia określamy w deskryptorze wdrożenia ejbjar.xml:
...
<ejb-name>AnyBean</ejb-name>
<service-ref>
<service-ref-name>service/ProcessorService</service-ref-name>
<service-interface>com.charge_it.ProcessorService
</service-interface>
<wsdl-file>META-INF/wsdl/ChargeItProcessor.wsdl</wsdl-file>
<jaxrpc-mapping-file>META-INF/mapping.xml</jaxrpc-mapping-file>
<service-qname>chargeIt:ProcessorService</service-qname>
<mapped-name>webservices/ProcessorService</mapped-name>
<injection-target>
<injection-target-class>AnyBean</injection-target-class>
<injection-target-name>service</injection-target-name>
</injection-target>
</service-ref>
...
13
Korzystanie z usługi
sieciowej w obrębie EJB
Specyfikacja JAX-RPC wymaga dostarczenia odwzorowania, które
wiąże WSDL i Javę. Zwykle jest ono umieszczone w pliku jaxrpcmapping.xml. Ponadto, w zależności od tego czy jesteśmy dostawcą
czy odbiorcą usługi mogą specyfikacja wymaga dodatkowych plików
opisujących usługę. Zwykle jednak producenci kontenerów EJB
dostarczają narzędzi, które automatycznie generują wszystkie
potrzebne pliki na podstawie interfejsu w Javie i kilku dodatkowych
parametrów.
14
Korzystanie z usługi
w programie klienckim
...
public class Client {
public static void main(String [] args) {
...
try{
Context jndiContext = new javax.naming.InitialContext();
ProcessorService service = (ProcessorService)jndiContext.
lookup("java:comp/env/service/ProcessorService");
Processor processor = service.getTravelAgentPort();
processor.charge(customerName, card.number, expDate,
card.type, price);
}catch (javax.naming.NamingException ne){
ne.printStackTrace();
}catch (java.rmi.RemoteException re){
re.printStackTrace();
}catch (javax.xml.rpc.ServiceException se){
se.printStackTrace();
}
...
}
...
}
15
Narzędzia
Producenci kontenerów EJB dostarczają narzędzi pozwalających
automatycznie generować potrzebne pliki. Przykład zadania Ant'a (JBoss):
<target name="wstool">
<taskdef name="wstools" classname="org.jboss.ws.tools.ant.wstools">
<classpath refid="build.classpath" />
</taskdef>
<wstools dest="dd/ws" config="wstools-config.xml"/>
</target>
oraz plik konfiguracyjny:
<configuration xmlns="http://www.jboss.org/jbossws-tools">
<java-wsdl>
<service name="ProcessorService" style="rpc"
endpoint="com.charge_it.ProcessorService"/>
<namespaces target-namespace="http://charge-it.com/Processor"
type-namespace="http://charge-it.com/Processor"/>
<mapping file="jaxrpc-mapping.xml"/>
<webservices ejb-link="ProcessorBean"/>
</java-wsdl>
</configuration>
16
Narzędzia
Przedstawiony kod generuje następujące pliki:
●
ProcessorService.wsdl: definicja usługi w formacie WDSL.
Niektóre dane mogą być uzupełnione po uruchomieniu usługi (np.
adres SOAP).
●
jaxrpc-mapping.xml: odwzorowanie pomiędzy typami WSDL i Javy.
Może być wykorzystywany przez usługę i klienta.
●
webservices.xml: deklaracja usługi. Ustaniawia połączenie
pomiędzy adresem usługi a komponentem EJB, który ją realizuje.
17
JAX-RPC podsumowanie
Usługa:
●
interfejs punktu końcowego rozszerzający java.rmi.Remote,
●
bezstanowy komponent sesyjny implementujący interfejs punktu
końcowego,
●
deskryptory: opis usługi w WSDL'u, jaxrpc-mapping.xml,
webservices.xml.
Klient:
●
interfejs usługi i interfejs punktu końcowego,
●
odwzorowanie danych: jaxrpc-mapping.xml.
18
JAX-WS
Aby zdefiniować usługę sieciową w oparciu o bezstanowy komponent
sesyjny zgodnie ze specyfikacją JAX-RPC należy wykonać sporo
dodatkowej pracy związanej z przygotowaniem wymaganych plików
opisujących usługę. Aby zredukować tą dodatkową pracę do minimum
powstała alternatywna specyfikacja JAX-WS zgodna z EJB 3.0.
19
JAX-WS
Aby zdefiniować usługę sieciową w oparciu o bezstanowy komponent
sesyjny zgodnie ze specyfikacją JAX-RPC należy wykonać sporo
dodatkowej pracy związanej z przygotowaniem wymaganych plików
opisujących usługę. Aby zredukować tą dodatkową pracę do minimum
powstała alternatywna specyfikacja JAX-WS zgodna z EJB 3.0:
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.WebMethod;
@Stateless
@WebService
public class TravelAgentBean{
@WebMethod
public String makeReservation(int cruiseId, int cabinId,
int customerId, double price) {
...
}
}
20
Adnotacja @WebService
package javax.jws;
@Target({TYPE}) @Retention(value=RetentionPolicy.RUNTIME)
public @interface WebService {
String name( ) default ""; // nazwa usługi: wsdl:portType,
// domyślnie nazwa klasy lub
// interfejsu
String targetNamespace( ) default ""; // domyślnie nazwa
// pakietu
String serviceName( ) default "";
// odwzorowane na
// wsdl:service
String wsdlLocation( ) default ""; // używane gdy istnieje już
// plik WSDL
String portName( ) default "";
}
// odwzorowane na wsdl:port
String endpointInterface( ) default ""; // deklaracja może być
// oddzielona od
// implementacji
21
Adnotacja @WebMethod
Jeżeli bezstanowy komponent sesyjny oznacony jako @WebService
nie posiada żadnej metody oznaczonej przez @WebMethod wtedy
wszystrkie jego metody są udostępnione jako elementy usługi
siecowej. W przeciwnym razie widoczne są tylko te oznaczone
adnotacją.
@Target({ElementType.METHOD}) @Retention(value =
RetentionPolicy.RUNTIME)
public @interface WebMethod{
String operationName( ) default ""; // wsdl:operation,
// domyślnie nazwa metody
String action( ) default ""; // nazwa akcji SOAP
}
22
Adnotacja @WebParam
Adnotacja @WebParam umożliwia dalszą kontrolę WSDL'a
generowanego dla metody oznaczonej przez @WebMethod.
@Target({PARAMETER})@Retention(value=RetentionPolicy.RUNTIME)
public @interface WebParam {
public enum Mode {IN, OUT, INOUT};
String name() default ""; // odwzorowywane na wsdl:part
String targetNamespace() default "";
Mode mode() default Mode.IN;
}
boolean header() default false; // parametr w nagłówku SOAP
// zamiast w treści (body)
23
Adnotacja @WebParam
@WebMethod(operationName = "CheckStatus")
public int checkStatus(
@WebParam(name = "ReservationID") String reservationId,
@WebParam(name = "CustomerID", mode = WebParam.Mode.OUT)
javax.xml.ws.Holder<Integer> customerId){
...
}
<message name="CheckStatus">
<part name="ReservationID" type="xsd:string"/>
</message>
<message name="CheckStatusResponse">
<part name="return" type="xsd:int"/>
<part name="CustomerID" type="xsd:int"/>
</message>
<portType name="TravelAgent">
<operation name="CheckStatus"
parameterOrder="ReservationID CustomerID">
<input message="tns:CheckStatus"/>
<output message="tns:CheckStatusResponse"/>
</operation>
</portType>
24
Adnotacja @WebResult
@WebMethod(operationName = "Reserve")
@WebResult(name = "ReservationID") // oprócz name może zawierać
// także targetNamespace()
public String makeReservation(...) {...}
<xs:element name="ReserveResponse" type="ReserveResponse"/>
<xs:complexType name="ReserveResponse">
<xs:sequence>
<xs:element name="ReservationID" type="xs:string"
nillable="true"/>
</xs:sequence>
</xs:complexType>
...
<message name="ReserveResponse">
<part name="parameters" element="tns:ReserveResponse"/>
</message>
...
<portType name="TravelAgent">
<operation name="Reserve">
<input message="tns:Reserve"/>
<output message="tns:ReserveResponse"/>
</operation>
</portType>
25
Inne adnotacje
@SoapBinding pozwala dookreślić postać wywołań SOPAP:
@Target(value = {ElementType.TYPE}) @Retention(value =
RetentionPolicy.RUNTIME)
public @interface SOAPBinding {
public enum Style {DOCUMENT,
RPC}; // parametry mapowane na wsdl:part
public enum Use {LITERAL,ENCODED};
public enum ParameterStyle {BARE, // jeden parametr w elemencie
// root określający całą
// wiadomość
WRAPPED}; // wiele parametrów
// w elemencie root
Style style() default Style.DOCUMENT;
Use use() default Use.LITERAL; //LITERTAL wymagane przez JAX-WS
ParameterStyle parameterStyle() default ParameterStyle.WRAPPED;
}
@OneWay – w odpowiedzi przesyłana jest pusta wiadomość: brak
elementu output w WSDL'u,
26
Rozdzielenie interfejsu
i implementacji
package com.titan.webservice;
import javax.jws.WebService;
@WebService
public interface TravelAgentEndpoint{
public String makeReservation(int cruiseId, int cabinId,
int customerId, double price);
}
package com.titan.webservice;
import javax.jws.WebService;
@WebService(endpointInterface =
"com.titan.webservice.TravelAgentEndpoint")
public class TravelAgentBean implements TravelAgentEndpoint {
...
}
27
Punkt końcowy usługi
Podobnie jak w JAX-RPC dostęp do usługi sieciowej realizowanej np.
przez komponent EJB może być zrealizowany poprzez interfejs
końcowy usługi i klasę usługi:
package com.charge_it;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface Processor{
public int charge(String name, String number,
java.util.Calendar expDate, String cardType,
float amount);
}
28
Klasa usługi
package com.charge_it;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebEndpoint;
@WebServiceClient(name="ProcessorService",
targetNamespace="http://charge-it.com/Processor"
wsdlLocation="http://charge-it.com/Processor?wsdl")
public class ProcessorService extends javax.xml.ws.Service {
public ProcessorService( ) {
super(new URL("http://charge-it.com/Processor?wsdl"),
new QName("http://charge-it.com/Processor","ProcessorService"));
}
public ProcessorService(String wsdlLoc, QName sName){
super(wsdlLoc, sName);
}
@WebEndpoint(name = "ProcessorPort")
public Processor getProcessorPort( ) {
return (Processor) super.getPort(new QName("http://chargeit.com/Processor","ProcessorPort"),Processor.class);
}
}
29
Dostęp do usługi
@Stateful
public class AnyBean implements AnyRemote {
@WebServiceRef(ProcessorService.class) Processor processor;
...
public void aMethod(...) throws EJBException {
...
try {
processor.charge(customerName, card.number, expDate,
card.type, price);
...
} catch(Exception e) {
throw new EJBException(e);
}
}
...
}
30
Podsumowanie
Usługi sieciowe, ze względu na swoją elastyczność i uniwersalność
zyskały bardzo mocną pozycję w środowisku aplikacji biznesowych.
Większość rozwiązań integrujących różne systemy opiera się właśnie
na usługach sieciowych. Specyfikacja JavaEE umożliwia tworzenie
komponentów realizujących tekie usługi jak również korzystanie
z nich. Jest to możliwe za pośrednictwem dwóch mechanizmów: JAXRPC i JAX-WS.
31