Développement d'un service WSIF
Un service WSIF (Web Services Invocation Framework) est un service Web qui utilise WSIF.
Pourquoi et quand exécuter cette tâche
Pour développer un service WSIF, développez le service Web correspondant (ou partez d'un service Web existant), puis développez le client WSIF d'après le document WSDL qui définit ce service Web.
Deux exemples WSIF prégénérés sont également disponibles en téléchargement à partir de la page d'exemples WebSphere Application Server du site Web developerWorks :
- l'exemple Address Book (carnet d'adresses),
- l'exemple Stock Quote (cotation boursière).
Pour plus d'informations sur l'utilisation de ces exemples préconfigurés, consultez la documentation incluse dans le module à télécharger developerWorks. Notez que ces exemples ont été conçus pour fonctionner avec WebSphere Application Server version 5.
Pour développer un service WSIF, effectuez les étapes ci-dessous.
Procédure
Exemple : Utilisation de WSIF pour un appel dynamique du modèle de service Web AddressBook
Voici un exemple de code client permettant d'appeler de manière dynamique l'exemple de service AddressBook via l'API WSIF :
try {
String wsdlLocation="clients/addressbook/AddressBookSample.wsdl";
// Le point de départ de tout appel dynamique à l'aide de WSIF est
// un objet WSIFServiceFactory. Nous en créons un avec la méthode
// newInstance.
WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
// Une fois en possession d'une fabrique, utilisez-la pour créer un objet
// WSIFService correspondant au service AddressBookService dans le fichier WSDL.
// Remarque : Comme un seul service est défini dans le fichier WSDL, il
// est inutile d'indiquer l'espace de noms (namespace) et le nom du service
// et "null" peut être passé pour ces paramètres. Cette remarque s'applique aussi
// au type de port, même si des valeurs ont été utilisées plus bas à des fins
// d'illustration.
WSIFService service = factory.getService(
wsdlLocation, // emplacement du fichier WSDL
null, // espace de noms des services
null, // nom du service
"http://www.ibm.com/namespace/wsif/samples/ab", // port type namespace
"AddressBookPT" // port type name
);
// Le fichier AddressBook.wsdl contient les définitions de deux éléments complexType
// à l'intérieur de l'élément schema. Mappez ces types
// complexes vers des classes Java. Ces mappages sont utilisés par le fournisseur Apache SOAP.
service.mapType(
new javax.xml.namespace.QName(
"http://www.ibm.com/namespace/wsif/samples/ab/types",
"address"),
Class.forName("com.ibm.www.namespace.wsif.samples.ab.types.WSIFAddress"));
service.mapType(
new javax.xml.namespace.QName(
"http://www.ibm.com/namespace/wsif/samples/ab/types",
"phone"),
Class.forName("com.ibm.www.namespace.wsif.samples.ab.types.WSIFPhone"));
// Vous disposez maintenant d'un objet WSIFService. L'étape suivante vise à créer
// un objet WSIFPort pour le port à utiliser. La méthode
// getPort(String portName) nous permet de générer un WSIFPort à partir du
// nom de port.
WSIFPort port = null;
if (portName != null) {
port = service.getPort(portName);
}
if (port == null) {
// Si aucun nom de port n'a été spécifié, tentons de créer un WSIFPort à partir
// des ports disponibles pour le type de port spécifié dans le service.
port = getPortFromAvailablePortNames(service);
}
// Une fois en possession d'un WSIFPort, vous pouvez créer une opération. Exécutez
// l'opération addEntry puis créez un objet WSIFOperation correspondant à cette
// opération. L'opération addEntry est surchargée dans le fichier wsdl, à savoir qu'il en
// existe deux versions, chacune recevant en entrée des paramètres
(parties) différents.
// Cette surcharge vous oblige à spécifier les noms des messages d'entrée et de sortie
// de l'opération dans la méthode createOperation afin que
l'opération correcte
// puisse être résolue.
// L'opération addEntry n'ayant pas de message de sortie, utilisez "null" comme nom.
WSIFOperation operation =
port.createOperation("addEntry", "AddEntryWholeNameRequest", null);
// Créons les messages à utiliser dans l'exécution de l'opération. Pour cela, nous
// appelons les méthodes createXXXXXMessage sur l'objet WSIFOperation.
WSIFMessage inputMessage = operation.createInputMessage();
WSIFMessage outputMessage = operation.createOutputMessage();
WSIFMessage faultMessage = operation.createFaultMessage();
// Créons un nom et une adresse à ajouter au carnet d'adresses
String nameToAdd="Chris P. Bacon";
WSIFAddress addressToAdd =
new WSIFAddress (1,
"The Waterfront",
"Some City",
"NY",
47907,
new WSIFPhone (765, "494", "4900"));
// Ajoutons le nom et l'adresse au message d'entrée
inputMessage.setObjectPart("nom", nameToAdd);
inputMessage.setObjectPart("adresse", addressToAdd);
// Exécutons l'opération et récupérons en retour un fanion indiquant si
// elle a réussi ou échoué.
boolean operationSucceeded =
operation.executeRequestResponseOperation(
inputMessage,
outputMessage,
faultMessage);
if (operationSucceeded) {
System.out.println("Le nom et l'adresse ont été ajoutés au carnet d'adresses\n");
} else {
System.out.println("Impossible d'ajouter le nom et l'adresse au carnet d'adresses");
}
// Remettons tout à zéro
operation = null;
inputMessage = null;
outputMessage = null;
faultMessage = null;
// Cette fois, vous rechercherez une adresse dans le carnet d'adresses.
// L'opération getAddressFromName n'est pas surchargée dans le fichier WSDL et,
// par conséquent, nous pouvez spécifier son nom, sans
// indiquer les noms des messages d'entrée et de sortie.
operation = port.createOperation("getAddressFromName");
// Créons les messages
inputMessage = operation.createInputMessage();
outputMessage = operation.createOutputMessage();
faultMessage = operation.createFaultMessage();
// Spécifions le nom à rechercher dans le carnet d'adresses
String nameToLookup="Chris P. Bacon";
inputMessage.setObjectPart("name", nameToLookup);
// Exécutons l'opération
operationSucceeded =
operation.executeRequestResponseOperation(
inputMessage,
outputMessage,
faultMessage);
if (operationSucceeded) {
System.out.println("Recherche du nom '"+nameToLookup+"' effectuée dans le carnet d'adresses");
// Vous pouvez obtenir l'adresse trouvée en interrogeant le message de sortie
WSIFAddress addressFound = (WSIFAddress) outputMessage.getObjectPart("adresse");
System.out.println("L'adresse trouvée était :");
System.out.println(addressFound);
} else {
System.out.println("Echec de la recherche du nom dans le carnet d'adresses");
}
} catch (Exception e) {
System.out.println("Une exception s'est produite lors de l'exécution de l'exemple :");
e.printStackTrace();
}
}
Le code ci-dessus fait appel à l'exemple de méthode suivant :
WSIFPort getPortFromAvailablePortNames(WSIFService service)
throws WSIFException {
String portChosen = null;
// Obtenir la liste des noms de ports disponibles pour le service
Iterator it = service.getAvailablePortNames();
{
System.out.println("Les ports disponibles pour le service sont : ");
while (it.hasNext()) {
String nextPort = (String) it.next();
if (portChosen == null)
portChosen = nextPort;
System.out.println(" - " + nextPort);
}
}
if (portChosen == null) {
throw new WSIFException("Aucun port trouvé pour le service !");
}
System.out.println("Utilisation du port " + portChosen + "\n");
// Un autre moyen de spécifier le port à utiliser sur le service est de recourir
// à la méthode setPreferredPort. Dès lors qu'un port préféré a été défini sur
// le service, un objet WSIFPort peut être obtenu par un appel à getPort
// (sans argument). Si aucun port préféré n'a été défini et que plusieurs ports
// sont disponibles pour le type de port spécifié dans le WSIFService, une
// exception est lancée.
service.setPreferredPort(portChosen);
WSIFPort port = service.getPort();
return port;
}
Le service Web utilise les classes suivantes :
WSIFAddress :
public class WSIFAddress implements Serializable {
//variables d'instance
private int streetNum;
private java.lang.String streetName;
private java.lang.String city;
private java.lang.String state;
private int zip;
private WSIFPhone phoneNumber;
//constructeurs
public WSIFAddress () { }
public WSIFAddress (int streetNum,
java.lang.String streetName,
java.lang.String city,
java.lang.String state,
int zip,
WSIFPhone phoneNumber) {
this.streetNum = streetNum;
this.streetName = streetName;
this.city = city;
this.state = state;
this.zip = zip;
this.phoneNumber = phoneNumber;
}
public int getStreetNum() {
return streetNum;
}
public void setStreetNum(int streetNum) {
this.streetNum = streetNum;
}
public java.lang.String getStreetName() {
return streetName;
}
public void setStreetName(java.lang.String streetName) {
this.streetName = streetName;
}
public java.lang.String getCity() {
return city;
}
public void setCity(java.lang.String city) {
this.city = city;
}
public java.lang.String getState() {
return state;
}
public void setState(java.lang.String state) {
this.state = state;
}
public int getZip() {
return zip;
}
public void setZip(int zip) {
this.zip = zip;
}
public WSIFPhone getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(WSIFPhone phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
WSIFPhone :
public class WSIFPhone implements Serializable {
//variables d'instance
private int areaCode;
private java.lang.String exchange;
private java.lang.String number;
//constructeurs
public WSIFPhone () { }
public WSIFPhone (int areaCode,
java.lang.String exchange,
java.lang.String number) {
this.areaCode = areaCode;
this.exchange = exchange;
this.number = number;
}
public int getAreaCode() {
return areaCode;
}
public void setAreaCode(int areaCode) {
this.areaCode = areaCode;
}
public java.lang.String getExchange() {
return exchange;
}
public void setExchange(java.lang.String exchange) {
this.exchange = exchange;
}
public java.lang.String getNumber() {
return number;
}
public void setNumber(java.lang.String number) {
this.number = number;
}
}
WSIFAddressBook :
public class WSIFAddressBook {
private Hashtable name2AddressTable = new Hashtable();
public WSIFAddressBook() {
}
public void addEntry(String name, WSIFAddress address)
{
name2AddressTable.put(name, address);
}
public void addEntry(String firstName, String lastName, WSIFAddress address)
{
name2AddressTable.put(firstName+" "+lastName, address);
}
public WSIFAddress getAddressFromName(String name)
throws IllegalArgumentException
{
if (name == null)
{
throw new IllegalArgumentException("L'argument du nom ne doit pas être" +
"null.");
}
return (WSIFAddress)name2AddressTable.get(name);
}
}
Le code suivant constitue le fichier WSDL correspondant pour le service Web :
<?xml version="1.0" ?>
<definitions targetNamespace="http://www.ibm.com/namespace/wsif/samples/ab"
xmlns:tns="http://www.ibm.com/namespace/wsif/samples/ab"
xmlns:typens="http://www.ibm.com/namespace/wsif/samples/ab/types"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/"
xmlns:java="http://schemas.xmlsoap.org/wsdl/java/"
xmlns:ejb="http://schemas.xmlsoap.org/wsdl/ejb/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema
targetNamespace="http://www.ibm.com/namespace/wsif/samples/ab/types"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="phone">
<xsd:element name="areaCode" type="xsd:int"/>
<xsd:element name="exchange" type="xsd:string"/>
<xsd:element name="number" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="address">
<xsd:element name="streetNum" type="xsd:int"/>
<xsd:element name="streetName" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="state" type="xsd:string"/>
<xsd:element name="zip" type="xsd:int"/>
<xsd:element name="phoneNumber" type="typens:phone"/>
</xsd:complexType>
</xsd:schema>
</types>
<message name="AddEntryWholeNameRequestMessage">
<part name="name" type="xsd:string"/>
<part name="address" type="typens:address"/>
</message>
<message name="AddEntryFirstAndLastNamesRequestMessage">
<part name="firstName" type="xsd:string"/>
<part name="lastName" type="xsd:string"/>
<part name="address" type="typens:address"/>
</message>
<message name="GetAddressFromNameRequestMessage">
<part name="name" type="xsd:string"/>
</message>
<message name="GetAddressFromNameResponseMessage">
<part name="address" type="typens:address"/>
</message>
<portType name="AddressBookPT">
<operation name="addEntry">
<input name="AddEntryWholeNameRequest"
message="tns:AddEntryWholeNameRequestMessage"/>
</operation>
<operation name="addEntry">
<input name="AddEntryFirstAndLastNamesRequest"
message="tns:AddEntryFirstAndLastNamesRequestMessage"/>
</operation>
<operation name="getAddressFromName">
<input name="GetAddressFromNameRequest"
message="tns:GetAddressFromNameRequestMessage"/>
<output name="GetAddressFromNameResponse"
message="tns:GetAddressFromNameResponseMessage"/>
</operation>
</portType>
<binding name="SOAPHttpBinding" type="tns:AddressBookPT">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="addEntry">
<soap:operation soapAction=""/>
<input name="AddEntryWholeNameRequest">
<soap:body use="encoded"
namespace="http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
</operation>
<operation name="addEntry">
<soap:operation soapAction=""/>
<input name="AddEntryFirstAndLastNamesRequest">
<soap:body use="encoded"
namespace="http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
</operation>
<operation name="getAddressFromName">
<soap:operation soapAction=""/>
<input name="GetAddressFromNameRequest">
<soap:body use="encoded"
namespace="http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output name="GetAddressFromNameResponse">
<soap:body use="encoded"
namespace="http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<binding name="JavaBinding" type="tns:AddressBookPT">
<java:binding/>
<format:typeMapping encoding="Java" style="Java">
<format:typeMap typeName="typens:address"
formatType="com.ibm.www.namespace.wsif.samples.ab.types.WSIFAddress"/>
<format:typeMap typeName="xsd:string" formatType="java.lang.String"/>
</format:typeMapping>
<operation name="addEntry">
<java:operation
methodName="addEntry"
parameterOrder="name address"
methodType="instance"/>
<input name="AddEntryWholeNameRequest"/>
</operation>
<operation name="addEntry">
<java:operation
methodName="addEntry"
parameterOrder="firstName lastName address"
methodType="instance"/>
<input name="AddEntryFirstAndLastNamesRequest"/>
</operation>
<operation name="getAddressFromName">
<java:operation
methodName="getAddressFromName"
parameterOrder="name"
methodType="instance"
returnPart="address"/>
<input name="GetAddressFromNameRequest"/>
<output name="GetAddressFromNameResponse"/>
</operation>
</binding>
<binding name="EJBBinding" type="tns:AddressBookPT">
<ejb:binding/>
<format:typeMapping encoding="Java" style="Java">
<format:typeMap typeName="typens:address"
formatType="com.ibm.www.namespace.wsif.samples.ab.types.WSIFAddress"/>
<format:typeMap typeName="xsd:string" formatType="java.lang.String"/>
</format:typeMapping>
<operation name="addEntry">
<ejb:operation
methodName="addEntry"
parameterOrder="name address"
interface="remote"/>
<input name="AddEntryWholeNameRequest"/>
</operation>
<operation name="addEntry">
<ejb:operation
methodName="addEntry"
parameterOrder="firstName lastName address"
interface="remote"/>
<input name="AddEntryFirstAndLastNamesRequest"/>
</operation>
<operation name="getAddressFromName">
<ejb:operation
methodName="getAddressFromName"
parameterOrder="name"
interface="remote"
returnPart="address"/>
<input name="GetAddressFromNameRequest"/>
<output name="GetAddressFromNameResponse"/>
</operation>
</binding>
<service name="AddressBookService">
<port name="SOAPPort" binding="tns:SOAPHttpBinding">
<soap:address
location="http://myServer/wsif/samples/addressbook/soap/servlet/rpcrouter"/>
</port>
<port name="JavaPort" binding="tns:JavaBinding">
<java:address className="services.addressbook.WSIFAddressBook"/>
</port>
<port name="EJBPort" binding="tns:EJBBinding">
<ejb:address className="services.addressbook.ejb.AddressBookHome"
jndiName="ejb/samples/wsif/AddressBook"
classLoader="services.addressbook.ejb.AddressBook.ClassLoader"/>
</port>
</service>
</definitions>