Desarrollo de servicios WSIF
Un servicio WSIF (Web Services Invocation Framework) es un servicio web que utiliza WSIF.
Acerca de esta tarea
Para desarrollar un servicio WSIF, primero desarrolle el servicio web (o utilice un servicio web existente) y, a continuación, desarrolle el cliente WSIF basándose en el documento WSDL (Web Services Description Language) para ese servicio web.
Existen además dos ejemplos de WSIF precompilados disponibles que se pueden descargar de la página de ejemplos de WebSphere Application Server en el sitio web developerWorks:
- El ejemplo AddressBook.
- El ejemplo StockQuote.
Para obtener más información sobre cómo utilizar los ejemplos predefinidos, consulte la documentación que se incluye en el paquete de descarga de developerWorks. Tenga en cuenta que estos ejemplos se crearon para que funcionaran con WebSphere Application Server Versión 5.
Para desarrollar un servicio WSIF, complete los siguientes pasos:
Procedimiento
Ejemplo: uso de WSIF para invocar el servicio Web de ejemplo AddressBook dinámicamente
El siguiente código de ejemplo sirve para invocar dinámicamente el servicio web de ejemplo Addressbook mediante WSIF:
try {
String wsdlLocation="clients/addressbook/AddressBookSample.wsdl";
// El punto de inicio de cualquier invocación dinámica mediante wsif es una
// WSIFServiceFactory. Cree uno a través del método
// newInstance.
WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
// Una vez que tenga una fábrica, puede utilizarla para crear un objeto WSIFService
// que se corresponda con el servicio AddressBookService en el archivo wsdl.
// Nota: debido a que sólo tiene un servicio definido en el archivo wsdl,
// no necesita utilizar el espacio de nombres y el nombre del servicio y puede pasar
// null, si es necesario. Esto también se aplica al tipo de puerto, aunque los valores
// se han usado en el ejemplo siguiente a efectos ilustrativos.
WSIFService service = factory.getService(
wsdlLocation, // ubicación del archivo wsdl
null, // espacio de nombres del servicio
null, // nombre del servicio
"http://www.ibm.com/namespace/wsif/samples/ab", // espacio de nombres del tipo de puerto
"AddressBookPT" // nombre del tipo de puerto
);
// El archivo AddressBook.wsdl contiene las definiciones para dos elementos complexType
// dentro del elemento schema. Correlacione estos tipos complexTypes
// con las clases Java. El proveedor de Apache SOAP utiliza estas correlaciones
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"));
// Ahora tiene un objeto WSIFService. El paso siguiente consiste en crear un objeto WSIFPort
// para el puerto que desea utilizar. El método getPort(String portName)
// permite generar un objeto WSIFPort a partir del nombre de puerto.
WSIFPort port = null;
if (portName != null) {
port = service.getPort(portName);
}
if (port == null) {
// Si no se ha especificado el nombre de puerto, pruebe a crear un elemento WSIFPort a partir
// de los puertos disponibles para el tipo de puerto especificado en el servicio.
port = getPortFromAvailablePortNames(service);
}
// Una vez que tenga un WSIFPort, puede crear una operación. Ejecute
// la operación addEntry e intente crear una WSIFOperation
// que se corresponda con dicha operación. La operación addEntry se sobrecarga en el wsdl.
// Hay dos versiones de dicha operación, cada una de las cuales
adopta parámetros distintos (partes).
// Esta sobrecarga requiere que se especifique los nombres de mensaje de entrada y salida para la operación
// del método createOperation, de forma que la operación correcta
// se pueda resolver.
// Debido a que la operación addEntry no tiene un mensaje de salida, debe utilizar null como nombre.
WSIFOperation operation =
port.createOperation("addEntry", "AddEntryWholeNameRequest", null);
// Cree mensajes para utilizarlos durante la ejecución de la operación. Esto debe
// hacerse invocando los métodos createXXXXXMessage en la WSIFOperation.
WSIFMessage inputMessage = operation.createInputMessage();
WSIFMessage outputMessage = operation.createOutputMessage();
WSIFMessage faultMessage = operation.createFaultMessage();
// Cree un nombre y dirección para añadirlos a la libreta de direcciones
String nameToAdd="Chris P. Bacon";
WSIFAddress addressToAdd =
new WSIFAddress (1,
"The Waterfront",
"Some City",
"NY",
47907,
new WSIFPhone (765, "494", "4900"));
// Añada el nombre y la dirección al mensaje de entrada
inputMessage.setObjectPart("name", nameToAdd);
inputMessage.setObjectPart("address", addressToAdd);
// Ejecute la operación, obteniendo un distintivo que indique que se ha realizado correctamente
boolean operationSucceeded =
operation.executeRequestResponseOperation(
inputMessage,
outputMessage,
faultMessage);
if (operationSucceeded) {
System.out.println("Successfully added name and address to addressbook\n");
} else {
System.out.println("Failed to add name and address to addressbook");
}
// Empiece de nuevo
operation = null;
inputMessage = null;
outputMessage = null;
faultMessage = null;
// Esta vez buscaremos una dirección de la libreta de direcciones.
// la operación getAddressFromName no está sobrecargada en el
// archivo wsdl y, por lo tanto, se puede especificar el nombre
// de operación sin nombres de mensaje de entrada o salida.
operation = port.createOperation("getAddressFromName");
// Cree los mensajes
inputMessage = operation.createInputMessage();
outputMessage = operation.createOutputMessage();
faultMessage = operation.createFaultMessage();
// Establezca el nombre que va a buscar en la libreta de direcciones
String nameToLookup="Chris P. Bacon";
inputMessage.setObjectPart("name", nameToLookup);
// Ejecute la operación
operationSucceeded =
operation.executeRequestResponseOperation(
inputMessage,
outputMessage,
faultMessage);
if (operationSucceeded) {
System.out.println("Successful lookup of name '"+nameToLookup+"' in addressbook");
// Para obtener la dirección encontrada, se puede consultar el mensaje de salida
WSIFAddress addressFound = (WSIFAddress) outputMessage.getObjectPart("address");
System.out.println("The address found was:");
System.out.println(addressFound);
} else {
System.out.println("Failed to lookup name in addressbook");
}
} catch(Exception e) {
System.out.println("An exception occurred when running the sample:");
e.printStackTrace();
}
}
El código anterior se refiere al método de ejemplo siguiente:
WSIFPort getPortFromAvailablePortNames(WSIFService service)
throws WSIFException {
String portChosen = null;
// Obtenga una lista de los nombres de puerto disponibles para el servicio
Iterator it = service.getAvailablePortNames();
{
System.out.println("Available ports for the service are: ");
while (it.hasNext()) {
String nextPort = (String) it.next();
if (portChosen == null)
portChosen = nextPort;
System.out.println(" - " + nextPort);
}
}
if (portChosen == null) {
throw new WSIFException("No ports found for the service!");
}
System.out.println("Using port " + portChosen + "\n");
// Una forma alternativa de especificar el puerto que se va a utilizar en el servicio
// es utilizar el método setPreferredPort. Una vez que un puerto preferido
// se haya establecido en el servicio, se puede obtener un WSIFPort mediante getPort
// (sin argumentos). Si no se ha establecido un puerto preferido y más de
// un puerto está disponible para el tipo de puerto especificado en el WSIFService,
// se generará una excepción.
service.setPreferredPort(portChosen);
WSIFPort port = service.getPort();
return port;
}
El servicio web utiliza las clases siguientes:
WSIFAddress:
public class WSIFAddress implements Serializable {
//variables de instancia
private int streetNum;
private java.lang.String streetName;
private java.lang.String city;
private java.lang.String state;
private int zip;
private WSIFPhone phoneNumber;
//constructores
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 de instancia
private int areaCode;
private java.lang.String exchange;
private java.lang.String number;
//constructores
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("The name argument must not be " +
"null.");
}
return (WSIFAddress)name2AddressTable.get(name);
}
}
El código siguiente es el archivo WSDL correspondiente del servicio 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>