Creación de SOA con servicios web usando WebSphere Studio, parte 3: Publicación con WSDL y UDDI mediante WebSphere

La tercera parte de esta serie de tutoriales se centra en las interfaces e implementaciones de servicios web de dos empresas de alquiler de DVD. También muestra cómo crear los descriptores del servicio WSDL y conectar el servicio con un servicio agregador. Además, usted podrá examinar la arquitectura orientada a servicios (SOA) y aprender a escalar el modelo para futuras versiones. (Ver todas las partes de esta serie de tutoriales).

Warner Onstine, Senior Mentor, ArcMind

Warner Onstine, Senior Mentor de ArcMind, Inc., es un desarrollador con más de 8 años de experiencia en la industria, la mayor parte de los cuales dedicó al desarrollo de aplicaciones Web. Warner es coautor del libro Professional Java Tools for Extreme Programming, que contiene capítulos sobre Maven, pruebas unitarias en Swing y cobertura de código con jcoverage.



Rick Hightower, Chief Mentor, ArcMind

Rick Hightower, Chief Mentor de ArcMind, Inc., es un desarrollador que ha cosechado múltiples logros, premios de la industria y certificaciones. Es coautor de los libros Professional Jakarta Struts y Java Tools to Extreme Programming, y escribió 1/5 del libro Mastering Tomcat. Rick es autor de numerosos tutoriales bien recibidos sobre EJB 2.0 CMP CMR, XDoclet, Apache Axis, ETTK, WSDK, Struts Tiles, etc. para IBM developerWorks.



05-08-2011

Acerca de este tutorial

Objetivo del tutorial

En este tutorial, usted investigará las interfaces e implementaciones de servicios web de dos empresas de alquiler de DVD. Creará los descriptores del servicio del lenguaje de descripción de servicios web (WSDL) y conectará este servicio con un servicio agregador. Además, examinará la arquitectura orientada a servicios (SOA) y aprenderá a escalar el modelo para futuras versiones.

En primer lugar analizaremos las interfaces de los servicios de alquiler de DVD y examinaremos la interfaz del agregador con mayor profundidad que en tutorial anterior. Luego veremos qué se necesita para publicar el servicio en un registro de Universal Description Discovery and Integration (UDDI) usando Universal Description Discovery and Integration for Java(TM) (UDDI4J).

Conocimientos necesarios para el tutorial

Este tutorial presupone que ya se han completado los dos primeros tutoriales de la serie: Introducción a los servicios web y a WebSphere® Studio Application Developer Integration Edition Versión 5.1 y Creación de un servicio web a partir de una clase Java con WebSphere Studio Application Developer Integration Edition Versión 5.1. Se recomienda tener un conocimiento equivalente de servicios web y de WebSphere Studio Application Developer Integration Edition (en la sección Recursos encontrará un vínculo a una versión de prueba). También es conveniente contar con un conocimiento práctico de servicios web y de ciertas operaciones básicas de IBM(R) WebSphere Studio Application Developer Integration Edition, como iniciar y detener el servidor e implementar un servicio web. Este tutorial presupone un conocimiento práctico del lenguaje de programación Java™y de XML. Si bien no es obligatorio, sí es conveniente contar con un conocimiento de Java 2 Platform, Enterprise Edition (J2EE).

Todas las aplicaciones de ejemplo se implementan en la solución IBM WebSphere Application Server (Application Server, en Recursos encontrará un vínculo a una versión de prueba) que está incluida en WebSphere Studio Application Developer Integration Edition. En la sección Recursos encontrará referencias a documentos introductorios sobre la tecnología Java, XML, IBM WebSphere y J2EE.

Contenido del tutorial

Este tutorial trata de WSDL y de las herramientas de WebSphere Studio Application Developer Integration Edition para desarrollar sistemas basados en servicios web a través de Web Services Description Language (WSDL). También muestra cómo publicar un servicio en UDDI usando UDDI4J. Examina los siguientes temas, herramientas y técnicas:

Temas

  • Revisión de WSDL
  • Introducción a WSDL
  • Elementos de WSDL
    • <types>
    • <message>
    • <portType>
    • <binding>
  • Generalidades del esquema XML
  • Estilos de mensajería y codificación

Herramientas

  • Asistente para servicios web de WebSphere Studio Application Developer Integration Edition
  • Exploración de servicios web de WebSphere Studio Application Developer Integration Edition

Técnicas

  • Creación de una implementación de servicios web a partir de un archivo WSDL
  • Creación de un cliente de servicios web a partir de un archivo WSDL

Herramientas necesarias

Este tutorial requiere el uso de WebSphere Application Developer Integration Edition. En el área de WebSphere Application Developer del sitio Web de IBM, podrá encontrar la descarga de WebSphere Application Developer (Application Developer) e información relacionada. También puede solicitar CD gratuitos, que incluyen Application Developer así como otros productos de IBM preparados para servicios web, como WebSphere Studio del programa de servicios web developerWorks Speed-Start.

Acerca de los laboratorios de esta serie

Todos los tutoriales están centrados en un motor de búsqueda de alquileres de DVD que agrega los resultados de búsqueda de uno o más videoclubes cuyos catálogos están disponibles online. En el correspondiente caso de uso, Recomendaciones, el usuario elige qué categoría de película le gustaría alquilar y, sobre la base de su historial de alquileres, se usan servicios web para sugerir otras películas. En el primer tutorial ("Generación de SOA con servicios web mediante WebSphere Studio, parte 1: Introducción a SOA y servicios web", en Recursos encontrará un vínculo a todas las partes de esta serie), se creó y se ejecutó un servicio web simple. En el segundo tutorial, usted expandió la exploración del trabajo con servicios web a través de los siguientes laboratorios:

  • Laboratorio 1: Generación e implementación de un servicio web: En este laboratorio, usted creó e implementó un servicio web simple que el agregador expuso ante el cliente.
  • Laboratorio 2: Intercambio de objetos SOAP complejos: En este laboratorio, usted mejoró el servicio web permitiendo que devuelva objetos SOAP más complejos para su uso por parte del cliente.
  • Laboratorio 3: Cliente de servicio web dinámico: En este laboratorio, usted creó de manera dinámica un cliente de servicio web que consumió los objetos SOAP complejos.

Herramientas necesarias para el tutorial

Como mínimo, es necesario contar con Java SDK 1.3.1 o superior para ejecutar Application Developer. En el sitio de IBM developerWorks, encontrará una descarga de prueba de WebSphere Application Developer Integration Edition y más información al respecto.


Introducción a WSDL y UDDI

Introducción

La introducción de los servicios web ha generado gran entusiasmo en muchos círculos técnicos. Este entusiasmo tiene numerosas causas, dos de las cuales son las promesas de interoperabilidad y de un rápido acceso al mercado. La interoperabilidad se puede lograr parcialmente con el uso de protocolos comunes y abiertos como HTTP y el protocolo simple de acceso a objetos (SOAP). Sin embargo, esto no alcanza para que la implementación de un proceso de servidor sea completamente transparente para el cliente.

El cliente debe conocer, además, los siguientes elementos:

  • Tipos de datos
  • Parámetros
  • Tipos de devolución
  • Ubicación
  • Detalles de transmisión de los servicios web

Hace falta un metaprotocolo que describa estos elementos fundamentales de una manera independiente del proveedor y de la implementación para que el cliente y el servidor puedan estar completamente desacoplados.

WSDL es un formato de archivo basado en XML que describe, además de estos detalles de la interfaz del servicio web, la manera en que la interfaz abstracta está asociada a un determinado protocolo de transporte (HTTP, SMTP, etc.) y codificación (SOAP, etc.). Sin embargo, las ventajas de WSDL son más que las que se derivan de la interoperabilidad. Como el formato está enlazado a una especificación, los proveedores crean herramientas que usan WSDL para generar no solamente un código de tiempo de ejecución del cliente que interactúe con un servicio web, sino además herramientas que usen WSDL para generar código de plantilla del servidor.

Por eso, WSDL no solo contribuye a la interoperabilidad de procesos distintos, sino que ayuda a reducir el tiempo de desarrollo requerido para que cliente y servidor estén habilitados para servicios web. El asistente para servicios web, incluido en WebSphere Studio Application Developer Integration Edition Versión 5.1, usa WSDL para poner el proyecto en funcionamiento generando el código de tiempo de ejecución del cliente y el código de plantilla del servidor para un servicio web.

Arquitectura WSDL

WSDL proporciona una gramática para describir servicios como un conjunto de extremos que intercambian mensajes. Un documento WSDL actúa como una descripción independiente del lenguaje y de la plataforma (XML) de uno o más servicios. Describe los servicios, la manera de acceder a ellos y qué tipo de respuesta (si hubiera) se debe esperar. WSDL describe:

  • Tipos
  • Mensajes
  • Operaciones
  • portTypes
  • Ubicaciones
  • Enlaces de protocolo del servicio

WSDL se usa para describir servicios web como un conjunto de extremos que operan en los mensajes. WSDL puede describir información orientada a documentos o a procedimientos. Antes de analizar los elementos específicos de WSDL, veamos algunos de los conceptos que WSDL pretende describir.

portTypes: Un portType describe las operaciones proporcionadas por un servicio web. Es como una interfaz Java en cuanto a que describe un conjunto de operaciones. Combina elementos de mensaje para formar una operación.

Mensajes y tipos: Un mensaje es un elemento de datos. Es usado por las operaciones para transportar sus datos. Los mensajes describen la comunicación entre cliente y servidor enumerando los tipos de datos intercambiados. En el elemento tipos se puede encontrar una descripción de ellos, que se suele hacer con el esquema XML. Los tipos son como clases Java y tipos primitivos.

Operaciones, mensajes y errores: Una operación es como un método Java. Consta de mensajes entrantes, salientes y de error. Piense en el mensaje entrante de una operación como si fueran los parámetros de un método en Java. Piense en el mensaje saliente de una operación como si fuera un el tipo de devolución de un método en el lenguaje de programación Java. Piense en el mensaje de error como si fuera una excepción Java.

Enlaces: Un enlace sirve justamente para enlazar un portType con un protocolo específico (por ejemplo, SOAP 1.1, HTTP GET/POST o MIME).

Servicios: Un servicio define la información de conexión de un determinado servicio. Los servicios pueden tener uno o más puertos, cada uno de los cuales define un método de conexión diferente (por ejemplo, HTTP/SMTP, etc.).

En suma, una instancia del protocolo WSDL describe cinco elementos:

  1. Tipos de datos de la interfaz del servicio web (parámetros y tipos de devolución).
  2. Mensajes que agrupan variables de tipos de datos en transmisiones de red.
  3. portTypes que agrupan mensajes en operaciones lógicas.
  4. Enlaces que describen cómo se asigna un portType a un protocolo de transporte o de mensajería.
  5. Servicios que enumeran la información de conexión de un enlace específico.

Estos elementos se describirán en mayor detalle en los siguientes ejemplos.

Elemento <types>

El elemento WSDL <types> permite especificar los tipos de datos, sin importar su simplicidad o complejidad, requeridos por la interfaz del servicio web descripta por un archivo WSDL. La nota WSDL no impone requisitos en cuanto al protocolo que se debe usar para definir los tipos, si bien soporta el esquema XML para su protocolo de tipo canónico. El esquema XML es tanto común como abierto, por lo que su uso dentro de WSDL mantiene la definición de servicio web libre de los detalles específicos del tipo de los lenguajes de programación y de los tipos específicos del proveedor.

El elemento <types> del siguiente ejemplo usa el esquema XML para definir siete tipos de datos. Como se puede observar, el esquema XML es muy flexible y permite definir tipos propios del dominio en cuestión de una manera abierta y común. Es posible hacer referencia a estos tipos dentro de WSDL para describir aún más la interfaz de servicio web.

<wsdl:definitions 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://dvd.com" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:tns="http://dvd.com"> 

... 
    <wsdl:types> 
        <xsd:schema> 
            <xsd:simpleType name="EmailAddressType"> 
                <xsd:restriction base="xsd:string"> 
                    <xsd:pattern value=".+@.+"/> 
                </xsd:restriction> 
            </xsd:simpleType> 
            <xsd:simpleType name="PriceType"> 
                <xsd:restriction base="xsd:decimal"> 
                    <xsd:totalDigits value="6"/> 
                <xsd:fractionDigits value="2"/> 
                </xsd:restriction> 
            </xsd:simpleType> 
            <xsd:simpleType name="SerialNumberType"> 
                <xsd:restriction base="xsd:string"> 
                    <xsd:pattern value="[0-9a-zA-Z]{3}-[0-9a-zA-Z]
                    {4}-[0-9a-zA-Z]{3}" /> 
                </xsd:restriction> 
            </xsd:simpleType> 
            <xsd:complexType name="DVDAbstractType"> 
                <xsd:sequence> <xsd:element name="title"
                 type="xsd:string"/> 
                    <xsd:element name="artist" type="xsd:string"/> 
                    <xsd:element name="releaseDate" type="xsd:date"/> 
                </xsd:sequence> 
            </xsd:complexType> 
            <xsd:complexType name="DVDPurchaseType"> 
                <xsd:complexContent> 
                    <xsd:extension base=
                    "tns:DVDAbstractType"> 
                        <xsd:sequence> 
                            <xsd:element name="cost" type="tns:PriceType"/> 
                        </xsd:sequence> 
                    </xsd:extension> 
                </xsd:complexContent> 
            </xsd:complexType> 
            <xsd:complexType name="DVDRentalType"> 
                <xsd:complexContent> 
                    <xsd:extension base=
                    "tns:DVDAbstractType"> 
                        <xsd:sequence> 
                            <xsd:element name=
                            "rentalCost" type="tns:PriceType"/> 
                            <xsd:element name=
                            "returnDate" type=
                            "xsd:date" /> 
                        </xsd:sequence> 
                    </xsd:extension> 
                </xsd:complexContent> 
            </xsd:complexType> 
            <xsd:complexType name=
            "ResponseConfirmationType"> 
                <xsd:sequence> 
                    <xsd:element name=
                    "confirmationNumber" type="tns:SerialNumberType" /> 
                    <xsd:element name="message" type="xsd:string" /> 
                </xsd:sequence> 
            </xsd:complexType> 
        </xsd:schema> 
    </wsdl:types> 

... 
</wsdl:definitions>

A continuación se describirá a grandes rasgos el sistema de tipos del esquema XML.

Esquema XML

Los servicios web son solo una cuestión de comunicación entre procesos, es decir, comunicación entre computadoras diferentes. El uso de WebSphere Application Developer Integration Edition junto con WSDL facilita la integración de servicios web en la infraestructura de TI, ya que es posible generar el código de tiempo de ejecución del cliente (si fuera necesario) y el código del servidor con el asistente para servicios web de Application Developer.

La cuestión de los tipos aparece cuando entra en juego el carácter interoperable de los servicios web. Por ejemplo, si un servidor escrito con un lenguaje o una tecnología determinados desea enviar un numérico a un cliente de un lenguaje o una tecnología diferente, ¿cómo le transmite al cliente el significado del tipo enviado? Los dos procesos podrían tener diferentes definiciones de lo que es un 'numérico'. Además, ¿cómo puede saber el cliente si la cadena de bytes que lee no se debería interpretar como una cadena o un objeto serializado en vez de como un numérico? El problema se hace más patente en el caso de un tipo complejo (por ejemplo, DVD, dirección, etc.), en el que es necesario definir no solo los tipos simples envueltos, sino también los tipos envolventes.

El esquema XML le proporciona a los servicios web un conjunto de medios aceptados por la industria para definir tipos de datos complejos, así como tipos predefinidos para datos simples (por ejemplo, cadena, fecha, numérico, etc.). La descripción de un protocolo XML definido por el usuario que sigue las reglas del esquema XML suele estar ubicada en un archivo WSDL.

Veamos algunos ejemplos simples del esquema XML.

<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'> 
    <!-- Other stuff --> 
    <xsd:element name='name' type='xsd:string'/> 
    <xsd:element name='age' type='xsd:positiveInteger'/> 
</xsd:schema>

En el ejemplo anterior, el tipo 'string' está asociado con el espacio de nombres 'http://www.w3.org/2001/XMLSchema' a través del prefijo 'xsd'. Así es como el analizador sabe que el tipo 'string' se encuentra dentro de la especificación del esquema XML. Los tipos son fáciles de entender y se enumeran más adelante.

Los tipos complejos son agregados de propiedades de tipos simples o de otros tipos complejos. Por ejemplo, el tipo DVD tiene las siguientes propiedades:

  • Título
  • Artista
  • Fecha de lanzamiento
  • Precio de lista
  • Precio

Una representación XML de una instancia de DVD sería similar a la siguiente:

<DVD ID="1232232"> 
    <title>Greatest Hits of the 80s</title> 
    <artist>To Be AnnouncedVarious</artist> 
    <releaseDate>1980-01-01</releaseDate> 
    <listPrice>12.00</listPrice> 
    <price>3.00</price> 

</DVD>

El esquema XML nos proporciona una manera de describir el protocolo o esquema que sigue este documento XML. A diferencia de las descripciones basadas en DTD, el esquema XML está basado en XML y casi completamente extensible. El siguiente es un posible documento de esquema XML de la instancia anterior:

<xsd:schema 
    xmlns:xsd='http://www.w3.org/2001/XMLSchema'> 
    <xsd:element name="DVD"> 
        <xsd:complexType> 
            <xsd:sequence> 
                <xsd:element name="title" type="xsd:string" minOccurs="1" 
                maxOccurs="1" /> 
                <xsd:element name="artist" type="xsd:string" minOccurs="1" 
                maxOccurs="1" /> 
                <xsd:element name="releaseDate" xsd:type="date" minOccurs="1" 
                maxOccurs="1" /> 
                <xsd:element name="listPrice" type="xsd:string" minOccurs="1" 
                maxOccurs="1" /> 
                <xsd:element name="price" type="xsd:string" minOccurs="1" 
                maxOccurs="1" /> 
            </xsd:sequence> 
            <xsd:attribute name="ID" type="xsd:string"/> 
        </xsd:complexType> 
    </xsd:element> 

</xsd:schema>
  • El elemento schema es el elemento raíz de un documento de esquema XML. Dentro de él se encuentran todas las definiciones de tipo de elemento y de atributo de un protocolo XML.
  • El elemento element nos permite definir un tipo para un elemento.
  • El elemento complexType define un tipo complejo. El tipo de un elemento se considera complejo si puede tener atributos y/o elementos secundarios. El tipo DVD tiene tanto un atributo como subelementos. Existen tres modelos que pueden seguir los elementos secundarios de un elemento: any, choice y sequence.
    1. El tipo any[cualquiera] significa que cualquiera de los anidados puede aparecer como elemento secundario del nodo principal en cualquier orden.
    2. El choice significa que solo se puede usar uno de un conjunto de elementos secundarios posibles.
    3. Por último, sequence significa que los elementos secundarios tienen que aparecer dentro del elemento principal en el mismo orden en que aparecen en el elemento de la secuencia.
  • En el caso anterior, como se usa una secuencia, el elemento secundario de DVD debe aparecer en el siguiente orden:
    • Title
    • Artist
    • releaseDate
    • listPrice
    • Price
    El elemento attribute indica que en este protocolo, el elemento DVD tiene un atributo ID.

Si bien los tipos complejos se usan para validar y documentar el contenido de un flujo SOAP, el flujo SOAP de por sí no tiene ningún dato del esquema XML de definición de tipos complejos. Por eso, necesitará saber cómo definir tipos complejos en el esquema XML si desea leer o crear sus propios tipos en un archivo WSDL.

En realidad, no es necesario tener un conocimiento profundo del tema de tipos y definición de tipos en servicios web para escribir sistemas de servicios web. La API de stub/invocación y el nivel de código de esqueleto/ayudante que se utilizan se ocupan de los detalles de nivel bajo de serialización y deserialización de datos entre el cliente y el servidor. Esto hace que todo el proceso de conversión de tipos sea transparente. Sin embargo, si desea leer y entender archivos WSDL, o escribirlos de cero, será necesario tener un conocimiento del esquema XML.

La recomendación del esquema XML define una serie de tipos de datos simples (ver tabla). 'Simples' hace referencia a pares nombre-valor o escalares. Por ejemplo, 12334, "hola", 123.322, 12:12:2005, etc. Todos ellos tienes una cosa en común: se los puede describir fácilmente como cadenas, es decir, ninguno tiene una estructura compleja. Sin embargo, algunos de ellos sí tienen una cierta estructura. Las fechas tienen separadores para día, mes y año. Los tipos simples tienen una sintaxis de extensión-restricción, que le permitirá crear o definir sus propios tipos simples tomando como base los tipos simples del esquema XML. Si desea obtener más información, consulte la especificación del esquema XML.

stringCualquier secuencia arbitraria de caracteres.
normalizedStringCualquier secuencia de caracteres en que los únicos espacios en blanco permitidos son los espacios.
tokenCualquier secuencia de caracteres en que los únicos espacios en blanco permitidos son los espacios simples (es decir, no es válido tener dos o más espacios juntos).
NameIgual que el nombre XML.
QNameUn nombre XML con una parte de prefijo de espacio de nombres, un punto y coma y una parte local.
NMTOKENIgual que XML NMTOKEN.
NMTOKENSIgual que XML NMTOKEN.
byteUn número entero entre -128 y 127 inclusive.
unsignedByteUn número entero entre 0 y 255 inclusive.
base64BinaryUn flujo de datos codificados en Base64 de longitud arbitraria.
hexBinaryUn flujo de datos con codificación hexadecimal de longitud arbitraria.
intUn número entero entre -2147483648 y 2147483647 inclusive.
unsignedIntUn número entero entre 0 y 4294967295 inclusive.
integerCualquier número entero.
positiveIntegerUn número entero entre 1 e infinito positivo inclusive.
negativeIntegerUn número entero entre infinito negativo y 1 inclusive.
nonNegativeIntegerUn número entero entre 0 e infinito positivo inclusive.
nonPositiveIntegerUn número entero entre infinito negativo y 0 inclusive.
longUn número entero entre -9223372036854775808 y 9223372036854775807 inclusive.
unsignedLongUn número entero entre 0 y 18446744073709551615 inclusive.
shortUn número entero entre -32768 y 32767 inclusive.
unsignedShortUn número entero entre 0 y 65535 inclusive.
decimalCualquier número decimal.
floatCualquier valor del tipo de punto flotante de 32 bits de precisión sencilla de IEEE [IEEE 754-1985].
doubleCualquier valor del tipo de punto flotante de 64 bits de precisión sencilla de IEEE [IEEE 754-1985].
booleanUno de los valores verdadero o falso.
timeUn momento del día con formato hh:mm:ss.sss.
dateTimeMomento con formato SSAA-MM-DDThh:mm:ss.
durationPeríodo de tiempo con formato PnYnMnDTnHnMnS donde 'T' es el separador entre fecha y hora. El signo '-' es opcional para indicar una duración negativa.
dateUn momento con formato SSAA-MM-DD.
anyURICualquier cadena que cumpla las reglas URI.

Elemento <message>

El elemento <message> agrupa datos (cuyos tipos se definen en el elemento <types>) en una firma a efectos de una transmisión de red lógica y los enlaza con un nombre. Este nombre se usa para hacer referencia a un elemento <message> en el contexto de una definición de operación. Cada instancia de datos dentro de un elemento <message> se declara en un elemento <part>. Ver el siguiente ejemplo.

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" ...> 
... 
    <wsdl:message name="Subscribe"> 
        <wsdl:part name="email" type="tns:EmailAddressType"/> 
        <wsdl:part name="until" type="xsd:date"/> 
    </wsdl:message> 
    <wsdl:message name="PurchaseResponse"> 
        <wsdl:part name="paymentResponse"
         type="tns:ResponseConfirmationType" /> 
        <wsdl:part name="purchaseDate" type="xsd:date" /> </wsdl:message> 
    <wsdl:message name="PurchaseRequest"> 
        <wsdl:part name="purchaseRequest" type="tns:DVDPurchaseType" /> 
    </wsdl:message> 
    <wsdl:message name="RentalRequest"> 
        <wsdl:part name="rentalRequest" type="tns:DVDRentalType" /> 
    </wsdl:message> 
    <wsdl:message name="PaymentFault"> 
        <wsdl:part name="errorCode" type="tns:SerialNumberType"/> 
    </wsdl:message> 

... 
</wsdl:definitions>

Elemento <portType>

El elemento <portType> es el equivalente WSDL de la interfaz Java. Agrupa referencias a elementos <message> en operaciones lógicas que un proceso puede ejecutar en otro proceso y las enlaza con un nombre. Un elemento <operation> puede contener elementos <input>, <output> y <fault>. Respecto de los tres elementos, el atributo de mensaje hace referencia a un elemento <message> definido en el archivo WSDL. El elemento <input> declara los requisitos de la transmisión de una solicitud de cliente a un servicio web. El elemento <output> declara la respuesta de contenido de un servicio web. El elemento <fault> describe las excepciones a nivel mensaje que se producen cuando se intenta responder a la solicitud del cliente. Ver el siguiente ejemplo.

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" ...>
... 
    <wsdl:portType name="DVDRenting"> 
        <wsdl:operation name="SubscribeToSpecialsAlertList"> 
            <wsdl:input message="tns:Subscribe" /> 
        </wsdl:operation> 
        <wsdl:operation name="RentDVD"> 
            <wsdl:input message="tns:RentalRequest" /> 
            <wsdl:output message="tns:PurchaseResponse" /> 
            <wsdl:fault name="tns:RentFault" message="tns:PaymentFault" /> 
        </wsdl:operation> 
    </wsdl:portType> 
    <wsdl:portType name="DVDPurchasing"> 
        <wsdl:operation name="BuyDVD"> 
            <wsdl:input message="tns:PurchaseRequest" /> 
            <wsdl:output message="tns:PurchaseResponse" /> 
            <wsdl:fault name="tns:PurchaseFault"
             message="tns:PaymentFault" /> 
        </wsdl:operation> 
    </wsdl:portType> 

... 
</wsdl:definitions>

Elemento <binding>

Todos los elementos WSDL enumerados hasta ahora han sido abstractos en lo que respecta a un protocolo de transporte o mensajería específico (es decir, SOAP, SMTP, HTTP, etc.). Una organización que use cualquier protocolo podría implementar la interfaz de servicio web descripta más arriba. El contenido de un elemento <binding> une estos enlaces abstractos con un protocolo Web. El elemento de enlace tiene tanto un atributo de nombre que lo identifica dentro del documento WSDL como un atributo de tipo que hace referencia al portType respecto del que este elemento describe un enlace. También tiene un elemento <operation> para cada elemento <operation> del elemento <portType> del cual es un enlace. A su vez, el elemento <operation> tiene elementos <input>, <output> y <fault> para aquellos definidos en su correspondiente elemento <operation>. Los elementos que describen un enlace están anidados dentro del elemento <binding> descendiente para vincular los detalles del protocolo de mensajería a las generalidades mencionadas en el portType de destino. Sigue un ejemplo:

<wsdl:definitions> ... 
    <wsdl:binding name="SoapDVDRenting" type="tns:DVDRenting"> 
        <wsdl:operation name="tns:SubscribeToSpecialsAlertList"> 
            <wsdl:input> </wsdl:input> 
        </wsdl:operation> 
        <wsdl:operation name="tns:RentDVD"> 
            <wsdl:input> </wsdl:input> 
            <wsdl:output></wsdl:output> 
            <wsdl:fault> </wsdl:fault> 
        </wsdl:operation> 
    </wsdl:binding> 

... 
</wsdl:definitions>

W3C recomienda tres enlaces para servicios web: SOAP sobre HTTP, HTTP GET/POST y SOAP/MIME. Analizaremos SOAP sobre HTTP ya que parece ser el más popular. Al intentar crear un enlace SOAP para el protocolo DVDRenting, podrían surgir ciertas preguntas:

  1. ¿Dónde debería estar ubicado el valor de entrada de RentDVD? ¿En el encabezado SOAP?
  2. ¿Los datos del valor de entrada SubscribeToSpecialsAlertList tienen que cumplir las reglas de codificación SOAP o pueden constituir un archivo XML arbitrario (ver estilos de codificación)?
  3. ¿En qué lugar del mensaje SOAP debería estar ubicado el error RentDVD en caso de que se necesite una comunicación?

Estas preguntas son respondidas por un enlace SOAP:

<wsdl:definitions> 
... 
    <wsdl:binding name="SoapDVDRenting" type="tns:DVDRenting"> 
        <soap:binding style="document"
         transport="http://schemas.xmlsoap.org/soap/http"/> 
        <wsdl:operation name="SubscribeToSpecialsAlertList"> 
            <soap:operation soapAction=""/> 
            <wsdl:input> <soap:body namespace=
            "http://dvd.com" use="literal"/> 
            </wsdl:input> 
        </wsdl:operation> 
        <wsdl:operation name="RentDVD"> 
            <soap:operation soapAction=""/> 
            <wsdl:input> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:input> 
            <wsdl:output> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:output> 
            <wsdl:fault name="tns:RentFault"> 
              <soap:fault namespace="http://dvd.com" use="literal"/> 
            </wsdl:fault> 
        </wsdl:operation> 
    </wsdl:binding> 

... 
</wsdl:definitions>

El elemento <soap:binding> indica el estilo de mensajería (documento) de las comunicaciones SOAP (ver estilos de mensajería) y el protocolo de transporte deseado (HTTP). El atributo soapAction del elemento <soap:operation> se traduce en un encabezado HTTP que declara la intención de la solicitud HTTP que se enviará. Este encabezado fue introducido en SOAP 1.1 para permitir que los firewalls y otros nodos de preprocesamiento pudieran filtrar solicitudes SOAP. En SOAP 1.2, este encabezado cayó en desuso para dar paso a la declaración de la intención de la solicitud dentro de la solicitud como un parámetro llamado 'action'. Por consiguiente, a este encabezado se lo suele dejar en blanco. Los elementos <soap:body> y <soap:fault> denotan en qué lugar del elemento <Envelope> SOAP generado deberían estar los datos del mensaje. En nuestro ejemplo, todos los mensajes quedarán contenidos dentro del elemento <Body> SOAP regular, a excepción de los datos de errores RentDVD, que estarán contenidos dentro de un elemento <Fault> SOAP.

Elemento <service>

Por último, el elemento WSDL <service> sirve para asociar un enlace específico con uno o más procesos de la red que puedan atender solicitudes en función del portType implementado por el enlace. En SOAP sobre HTTP, esto es simplemente una URL que apunta a ese proceso.

<wsdl:service name="DVDRentalServices"> 
    <wsdl:documentation>Here are some endpoints that support the
     DVDRental SOAP HTTPbinding
    </wsdl:documentation> 
    <wsdl:port name="LPCDVDRentalService" binding="tns:SoapDVDRenting"> 
        <soap:address location=
        "http://localhost:6080/soap/servlet/rpcrouter" /> 
    </wsdl:port> 
    <wsdl:port name="ClassicsDVDRentals" binding="tns:SoapDVDRenting"> 
        <soap:address location=
        "http://www.classicsdvdrentals.com/soap/servlet/rpcrouter" /> 
    </wsdl:port> 

</wsdl:service>

Estilos de mensajería

Existen dos tipos de mensajes que puede describir un elemento <Body> SOAP: un documento XML que describe una llamada a procedimiento remoto (RPC) o un documento XML arbitrario (documento).

En el caso de la mensajería al estilo RPC, es común que exista un tipo de comunicación de solicitud-respuesta entre dos procesos. Un proceso de cliente invoca un procedimiento en un proceso de servidor trasmitiéndole los parámetros que requiere el procedimiento, y el proceso de servidor le envía al proceso de cliente los valores devueltos que tiene. El nombre del procedimiento, los parámetros y los tipos devueltos se describen como XML dentro del elemento <Body> SOAP.

La mensajería al estilo documento denota que el contenido del elemento SOAP <Body> es un documento XML arbitrario. Si bien la mensajería al estilo documento se puede usar en un escenario de comunicación de tipo solicitud-respuesta, es ideal para una comunicación asincrónica ya que el documento XML autónomo se puede poner en cola para su procesamiento.

El estilo del mensaje tiene un impacto significativo en la interoperabilidad del servicio web. WS-I, una organización de la industria dedicada a la interoperabilidad de los servicios web, recomienda usar servicios web con estilo documento.

En el siguiente ejemplo, el estilo de mensajería se indica con el uso del atributo style del elemento <soap:binding>.

<wsdl:definitions> 
... 
    <wsdl:binding name="SoapDVDRenting" type="tns:DVDRenting"> 
        <soap:binding style="document" transport=
        "http://schemas.xmlsoap.org/soap/http"/> 
        <wsdl:operation name="tns:SubscribeToSpecialsAlertList"> 
            <soap:operation soapAction=""/> 
            <wsdl:input> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:input> 
        </wsdl:operation> 
        <wsdl:operation name="tns:RentDVD"> 
            <soap:operation soapAction=""/> 
            <wsdl:input> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:input> 
            <wsdl:output> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:output> 
            <wsdl:fault> 
                <soap:fault namespace="http://dvd.com" use="literal"/> 
            </wsdl:fault> 
        </wsdl:operation> 
    </wsdl:binding> 

... 
<wsdl:definitions>

Codificaciones

Un flujo XML que se envía por una red en el cuerpo de un mensaje SOAP puede tener dos codificaciones: codificada o literal. Para comprender la diferencia entre estos dos conceptos, primero es necesario entender las diferentes maneras en que se puede trabajar con un flujo XML en un proceso.

Cualquier documento XML bien formado puede ser deserializado en un árbol de Document Object Model (DOM). Una vez que se crea el árbol, los subprocesos pueden desplazarse por el árbol DOM y leerlo o modificarlo recursivamente. Es posible convertir las referencias a los tipos del árbol DOM o transformar los datos del árbol DOM (por ejemplo, de la cadena "10" al número entero 10) en la medida de lo necesario. Los tipos deseados de los datos de un documento XML arbitrario se pueden definir en un documento de esquema XML o, más vagamente, en una DTD. El estilo de codificación, literal, denota que el valor del elemento SOAP <Body> se puede convertir directamente en un árbol DOM sin preocuparse por los tipos programáticos exactos. Si es necesario conocer los tipos deseados, se los puede descubrir a través de una referencia al esquema del documento XML.

En la recomendación SOAP 1.1 se definió un conjunto de reglas de codificación que describen cómo los datos se deberían serializar en un flujo XML y deserializar en tipos programáticos. El estilo de codificación codificado indica que el contenido de mensaje de una transmisión SOAP debería seguir estas reglas de serialización y deserialización.

La ventaja de la codificación literal es que el documento XML transportado no presenta restricciones. Su codificación depende del esquema y es totalmente extensible. Por este motivo, la codificación literal se está convirtiendo en el modo más común de transmitir contenidos del elemento SOAP <Body>.

En los siguientes ejemplos, todos los mensajes SOAP están literalmente codificados, y no es necesario que sigan las reglas de codificación SOAP. La codificación se declara a través del atributo 'use' de los elementos <soap:body> y <soap:fault>. El otro valor posible del atributo 'use' se encuentra codificado.

<wsdl:definitions> 
... 
    <wsdl:binding name="SoapDVDRenting" type="tns:DVDRenting"> 
        <soap:binding style="document" transport=
        "http://schemas.xmlsoap.org/soap/http"/> 
        <wsdl:operation name="tns:SubscribeToSpecialsAlertList"> 
            <soap:operation soapAction=""/> 
            <wsdl:input> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:input> 
        </wsdl:operation> 
        <wsdl:operation name="tns:RentDVD"> 
            <soap:operation soapAction=""/> 
            <wsdl:input> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:input> 
            <wsdl:output> 
                <soap:body namespace="http://dvd.com" use="literal"/> 
            </wsdl:output> 
            <wsdl:fault> 
                <soap:fault namespace="http://dvd.com" use="literal"/> 
            </wsdl:fault> 
        </wsdl:operation> 
    </wsdl:binding> 

... 
<wsdl:definitions>

Estilo ajustado documento/literal

El asistente para servicios web trabaja de manera predeterminada con un estilo o uso de enlace WSDL comúnmente llamado estilo ajustado documento/literal.

El estilo ajustado documento/literal está definido por las siguientes características:

  1. El mensaje de entrada tiene una única parte.
  2. Esta parte es un elemento.
  3. Este elemento tiene el mismo nombre que la operación.
  4. El tipo complejo del elemento no tiene atributos.

Nota: El estilo ajustado tiene su origen en Microsoft(R). No existe ninguna especificación que defina este estilo. Por eso, si bien este es un buen estilo, desgraciadamente, la única opción para interoperar con Microsoft y otras implementaciones consiste en hacer una conjetura bien fundada acerca de su funcionamiento sobre la base de los resultados del generador WSDL de Microsoft.

Introducción a UDDI

UDDI es una especificación que sirve para crear registros Web de servicios web. Un registro UDDI almacena información sobre empresas, servicios ofrecidos por esas empresas e información técnica sobre esos servicios. La API de programación y modelo de datos usada por UDDI está basada en XML y SOAP y ofrece una manera de publicar y localizar toda clase de servicios. No es necesario que los servicios sean servicios web. De hecho, ni siquiera es necesario que sean informáticos.

Comparemos un registro UDDI y un motor de búsqueda de Internet. El motor de búsqueda contiene información clasificada y categorizada sobre las páginas disponibles en la World Wide Web. Sin embargo, mientras que el motor de búsquedas de Internet solo devuelve una URL de una página Web, el registro UDDI debe devolver no solamente la ubicación de los servicios sino además información sobre el servicio, cómo funciona, qué parámetros usa, cuáles son sus valores devueltos, etc.

Específicamente, se dice que UDDI es compatible con tres tipos de datos de registro: Páginas Blancas (que organizan las empresas por nombre), Páginas Amarillas (que organizan las empresas por categoría) y Páginas Verdes (que organizan las empresas por servicio). Estos tres tipos de especificación, que son parte de la especificación UDDI, ofrecen una visión general de los diferentes tipos de datos que se pueden almacenar en el registro.

Páginas Blancas, Amarillas y Verdes

Páginas Blancas
Las Páginas Blancas contienen información sobre la empresa propiamente dicha, incluido su nombre, detalles de contacto y ubicación. Además, se pueden agregar Id. impositivos o números D-U-N-S (que se explicarán en breve) para identificar la empresa de forma unívoca. Una vez que esta información se anota en el registro, el cliente podrá buscar en el registro basándose en la información de la empresa.

La información de las Páginas Blancas es facilitada a través del elemento <businessEntity>. (Más adelante se analizará el uso del elemento <businessEntity>).

Páginas Amarillas

Las Páginas Amarillas contienen información categorizada sobre los servicios prestados por una empresa. La categorización se lleva a cabo asignando una o más taxonomías a la empresa. Por ejemplo, un servicio podría ser categorizado como un servicio de 'tienda online' y al mismo tiempo como un servicio de 'tienda de música'.

La información de las Páginas Amarillas también está asociada con el elemento <businessEntity>. (Más adelante se analizará el uso del elemento <businessEntity>).

Páginas Verdes

Las Páginas Verdes contienen información técnica sobre los servicios ofrecidos por una empresa. Esta información incluye toda la información técnica que se necesita para usar el servicio. En las Páginas Verdes podrá encontrar información tal como la ubicación del servicio, la categoría a la que pertenece y la especificación de los servicios.

La información de las Páginas Verdes está facilitada por los elementos <businessService> y <bindingTemplate>. (Más adelante se analizará el uso de los elementos <businessService> y <bindingTemplate>).

En un futuro cercano, una aplicación podrá buscar en el registro UDDI de manera dinámica los servicios que requiere. Sin embargo, en la actualidad es mucho más probable que los analistas de negocios busquen en el registro manualmente el servicio que necesitan. Si bien la mayoría de los registros tienen interfaces fáciles de usar, los analistas no suelen acceder al registro de manera directa. La interacción con los registros UDDI tiene lugar en uno de los portales de UDDI disponibles en la actualidad.

API para programadores

La interfaz de un registro UDDI se define como un conjunto de mensajes SOAP que son aceptados por un registro UDDI a fin de publicar y localizar un determinado servicio. Esto es lógico, ya que la especificación fue creada para servir de registro de servicios web.

Aquellos desarrolladores que deseen acceder a un registro UDDI pueden hacerlo de diversas formas, por ejemplo, usando una API SOAP basada en Java o una API de cliente UDDI basada en Java personalizada, como se explica en este tutorial.

Este tutorial usa IBM UDDI4J como su API programática. UDDI4J es una implementación de código abierto basada en Java del protocolo UDDI que contiene un conjunto completo de clases para publicar, buscar y enlazar un servicio web. La versión más reciente de UDDI4J (Versión 2) tiene compatibilidad total con la especificación UDDI Versión 2, viene con una capacidad de registro completa e incluye capacidades de configuración mejoradas en comparación con las versiones anteriores. Todos los ejemplos que se dan en este tutorial están escritos con UDDI4J Versión 2.


Laboratorio 1: Generación e implementación de un servicio de alquiler de DVD con WSDL

Objetivo y generalidades del laboratorio

Este laboratorio tiene por objeto crear el primero de los dos servicios de alquiler de DVD. Como estos dos servicios son muy similares, en este tutorial solo crearemos el primer servicio. La implementación del segundo queda como ejercicio para realizar en otro momento. Este ejercicio es muy similar al uno de los laboratorios de la parte 2 de esta serie de tutoriales ("Intercambio de objetos SOAP complejos"). En consideración a este tutorial, devolveremos el mismo objeto DVD para ambos servicios, pero es muy probable que en la práctica sea un objeto totalmente distinto. Este objeto DVD (aunque tiene un paquete diferente al del segundo tutorial) es idéntico y solamente está incluido en la descarga de código fuente.

Definición del servicio

En esta sección, usted creará un servicio web que devuelva tipos complejos. Siga estos pasos:

  1. Cree un nuevo proyecto Web llamado DavesDVD (no se pueden usar apóstrofos en los nombres de proyectos).
  2. Cree un nuevo paquete llamado davesdvd.server.
  3. Cree un segundo paquete llamado davesdvd.service.
  4. En este segundo paquete, inserte el objeto DVD creado en el segundo tutorial.
  5. A continuación, cree una clase Java llamada DVDDelivery.
  6. Agregue el siguiente código al archivo de origen:
    package davesdvd.server;
    
    import java.util.List;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    import davesdvd.service.DVD;
    
    public class DVDDelivery {
    
        private List dvds;
        
        public DVDDelivery() {
            super();
            dvds = new ArrayList();
            DVD dvd = new DVD("Fight Club", 10, "Weird but good");
            dvds.add(dvd);
        }
        
        public DVD findDVD(String title) {
            // we first must determine if we have this title
            Iterator iter = dvds.iterator();
            while(iter.hasNext()) {
                DVD dvd = (DVD) iter.next();
                if (dvd.getTitle().equals(title)) {
                   return dvd;
                }
            }
            return null;
        
        }//end findDVD(title)
    }//end DVDDelivery

    Este código es levemente diferente del código original, que devolvía un solo DVD, "Fight Club". Si bien este código solamente devuelve un DVD, la interfaz está generada con un método findDVD(), que permite buscar por título. Alternativamente, también sería posible agregar otros métodos como findDVDByDirector(),findDVDByCastMember()ofindDVDByPrice(). Estas son solo algunas de las opciones.

  7. Haga clic con el botón derecho en DVDDelivery.javay seleccione "Deploy as Web Service" ("Implementar como servicio web") del menú Web Services (servicios web). Luego haga clic en Next (Siguiente).
  8. Seleccione el Java bean a exponer y haga clic en Next (Siguiente).
  9. Seleccione el style and use (estilo y uso) del servicio web y haga clic en Finish (Finalizar). Este paso puede tardar un poco.

Prueba del servicio web

  1. Haga clic con el botón derecho enDVDDelivery.javay seleccione "Launch the Universal Test Client" ("Iniciar cliente de prueba universal") del menú Web Services (servicios web). Esto lo llevará directamente al explorador Web que muestra los servicios.
  2. Explore hasta llegar a su servicio haciendo clic en la referencia de objeto de DVDDelivery.
  3. Haga clic en el método findDVD y luego invoque el servicio haciendo clic en el botón "Invoke" ("Invocar").
  4. Debería aparecer un cuadro para escribir el título del DVD que desea buscar. Escriba "Fight Club" en el cuadro.
  5. Ya tiene una instancia del objeto DVD.
  6. Para recuperar información sobre el objeto DVD devuelto, es necesario hacer clic en su instancia, que le dará acceso a todos sus métodos. Haga clic en "Work with Object" ("Trabajar con objeto") y luego navegue hasta llegar a su instancia en el panel izquierdo.
  7. Para recuperar el título, haga clic en el métodogetTitle()y luego en "Invoke" ("Invocar").
  8. Si aparece el mensaje de respuesta de "Fight Club", es porque el servicio ha sido probado y está activo y en funcionamiento. ¡Felicitaciones!

Laboratorio 2: Conexión entre el agregador y los servicios

Generalidades del laboratorio

Este laboratorio tiene por objeto conectar el agregador de búsquedas de DVD a uno de los dos servicios de alquiler de DVD. A tal efecto, se usarán los archivos WSDL generados anteriormente para crear stubs que se conecten al servicio.

Ahora que ya sabe que el primer servicio funciona, es necesario conectarlo con un cliente. Una vez que el cliente esté conectado, se podrá conectar el servicio agregador. Use esta misma técnica para conectar el agregador con múltiples servicios.

Creación del código de cliente del servicio para DVDDelivery

  1. En primer lugar, se creará un nuevo proyecto para contener el agregador y el cliente que se está por generar.
  2. Elija File (Archivo) > New (Nuevo) del menú superior y luego "Dynamic Web Project" ("Proyecto Web dinámico").
  3. Especifique DVDFinder como el nombre del proyecto y active Configure Advanced Options (Configurar opciones avanzadas).
  4. La única opción que se cambiará es el archivo EARque se implementa. Es el primer cuadro de la siguiente pantalla. Escriba DVDFinderEAR, que es donde se implementará. Puede hacer clic en "Finish" ("Finalizar") desde aquí para finalizar la creación del proyecto.
  5. Haga clic con el botón derecho en "DVDDelivery.wsdl" y seleccione Generate Client (Generar cliente) del menú Web Services (servicios web).
  6. Asegúrese de seleccionar Java proxy (proxy Java) en el menú desplegable Client proxy type (Tipo de proxy de cliente). Luego haga clic en "Finish (Finalizar)".
  7. Cree un paquete llamadodvdfinder.client
  8. Dentro del paquete,dvdfinder.client directory, cree un archivo de origen Java llamado DVDFinderClient.java. Agregue el siguiente código al archivo de origen:
    package dvdfinder.client; 
    import davesdvd.server.*; 
    import davesdvd.service.*; 
    
    public class DVDFinderClient { 
        public DVD findDVD(String title) throws Exception {
            DVDDeliveryService loc = new DVDDeliveryServiceLocator(); 
            DVDDelivery port = (DVDDelivery)loc.getDVDDelivery(); 
            DVD dvd = port.findDVD(title); 
            return dvd;
        } //end findDVD()
    } //end DVDFinderClient

Conexión entre el cliente y el servicio agregador

Ahora que ya creó el código del cliente para acceder a DavesDVD, es necesario conectarlo con su servicio agregador. Esto es muy similar a lo que se realizó anteriormente cuando se creó crear DavesDVD, pero lo repasaremos brevemente.

  1. Lo primero que se debe hacer es crear un nuevo servidor para implementar el segundo servicio. A tal efecto, seleccione la pestaña Server (Server), ubicada en la parte inferior del proyecto, y haga clic con el botón derecho en cualquier parte de esa sección. Aparecerá lo siguiente:
  2. Desde aquí, seleccione New (Nuevo) > Server (Servidor) y Server Configuration (Configuración del servidor).
  3. "Integration Test Environment" ("Entorno de prueba de integración").
  4. En lugar de aceptar los valores predeterminados (con los que se ejecuta DavesDVD), seleccione la segunda opción y escriba 6080 para crear una instancia de servidor aparte que se ejecute en diferentes puertos.
  5. En el proyecto DVDFinder, haga clic con el botón derecho en la carpeta JavaSources y seleccione "New > Package" ("Nuevo > Paquete").
  6. El primer paquete que se creará esdvdfinder.server.
  7. Repita estos pasos para crear otro paquete llamadodvdfinder.service.
  8. Para crear el servidor, haga clic con el botón derecho en el nuevo paquete dvdfinder.server y elija "New > Class" ("Nuevo > Clase").
  9. Cree aquí la nueva clase, llamada DVDAggregateSearch. Una vez creada la clase, agréguele el siguiente código:
    package dvdfinder.server;
    
    import davesdvd.service.DVD;
    import dvdfinder.client.DVDFinderClient;
    
    public class DVDAggregateSearch {
        public DVD findDVD(String title) {
            DVDFinderClient davesDVD = new DVDFinderClient();
            try {
                DVD dvd = davesDVD.findDVD(title);
                return dvd;
            } catch (Exception e) {
                //do something with this
                return null;
            }
        
        }
    }
  10. Lo que está haciendo es usar el cliente recién creado para interactuar con el servicio a fin de buscar un DVD en función del título.
  11. Después de guardar la clase, haga clic con el botón derecho en la clase DVDAggregateSearch y seleccione "Web Services > Deploy as Web Service" ("servicios web > Implementar como servicio web").
  12. En la primera pantalla, asegúrese de seleccionar el servidor y el archivo EAR.
  13. Para seleccionar el servidor recién creado, haga clic en el botón edit (editar), seleccione DVDFinder y haga clic en "OK" ("OK").
  14. Haga clic en "Next (Siguiente)" y aparecerá la siguiente pantalla:



    Puede hacer clic en "Next (Siguiente)" hasta el final.

  15. En esta pantalla, haga clic en "Finish (Finalizar)". ¡Ya terminó de crear el servicio!

Prueba del servicio web

  1. Haga clic con el botón derecho en "DVDAggregateSearch.java" y seleccione "Launch the Universal Test Client" ("Iniciar cliente de prueba universal") del menú Web Services (servicios web). Esto lo llevará directamente al explorador Web que muestra los servicios.
  2. Explore hasta llegar a su servicio haciendo clic en la referencia de objeto de DVDAggregateSearch.
  3. Haga clic en "findDVD" y luego invoque el servicio haciendo clic en el botón "Invoke" ("Invocar").
  4. Aparecerá un cuadro para escribir el título del DVD que desea buscar. Escriba "Fight Club" en el cuadro.
  5. Ya tiene una instancia del objeto DVD.
  6. Para recuperar información sobre el objeto DVD devuelto, es necesario hacer clic en su instancia, que le dará acceso a todos sus métodos. Haga clic en "Work with Object" ("Trabajar con objeto") y luego navegue hasta llegar a su instancia en el panel izquierdo.
  7. Para recuperar el título, haga clic en el métodogetTitle()y luego en "Invoke" ("Invocar").
  8. Si aparece el mensaje de respuesta de "Fight Club", es porque el servicio ha sido probado y está activo y en funcionamiento. ¡Felicitaciones!

Solución de problemas de servicios

Hay muchos factores que pueden causar problemas cuando se prueban los servicios, pero es posible estar alerta para prevenir algunos de estos factores. En primer lugar, observe la consola para ver si hay algún mensaje de error. Estos mensajes pueden ser indicios de algún problema. Asimismo, compruebe si todos los servidores funcionan y no presentan ningún problema (por ejemplo, "Server needs to be republished" ("El servidor se debe volver a publicar")). Por lo general, si aparece algún mensaje de error, Application Developer lo guiará en la dirección correcta en cuanto a lo que es necesario corregir.

También es posible rastrear el error en un servicio por vez. Asegúrese de que el problema no se encuentra en un servicio externo o fuera de la cadena. Usando el cliente de prueba universal en cada sección de la cadena, es posible rastrear con exactitud dónde está el problema. Tampoco viene mal realizar pruebas unitarias. A veces, agregar pruebas unitarias para cada uno de los servicios puede indicar exactamente dónde hay errores y dónde se debería devolver el tipo de objeto incorrecto. Otra opción sería comprobar si el servicio externo no ha cambiado su descriptor WSDL, lo cual significaría que es necesario actualizar el cliente.

Todas estas son cuestiones con las que usted podría tener que lidiar; afortunadamente, Application Developer le facilita la tarea.


Introducción a la publicación con UDDI4J

Generalidades de UDDI4J

Como se mencionó más arriba, la interfaz programática de un registro usa un conjunto de mensajes SOAP definidos en la especificación UDDI. Para crear programas que interactúen con un registro UDDI, es necesario crear mensajes SOAP que el registro UDDI pueda comprender.

Existen muchas formas de escribir un programa para crear estos mensajes SOAP. La manera más fácil y más habitual es usar una API de nivel alto superpuesta arriba de SOAP. IBM UDDI4J es justamente la API que necesitamos. Es una implementación Java del protocolo UDDI.

En este mismo tutorial, usted ya examinó las estructuras de datos de un registro UDDI e interactuó con un registro de diferentes maneras. Ahora es momento de aprender a interactuar con un registro usando UDDI4J.

(Nota: Xe describe la conexión con un registro UDDI local.

Fundamentos de UDDI4J

UDDI4J está estructurado en una serie de paquetes bajo org.uddi4j, que incluyen:

  • org.uddi4j.client: contiene la importante clase de cliente UDDIProxy
  • org.uddi4j.datatype: representa objetos de datos UDDI
  • org.uddi4j.request: contiene mensajes enviados al servidor
  • org.uddi4j.response: representa mensajes de respuesta de un servidor UDDI
  • org.uddi4j.transport: compatible con transportes acoplables
  • org.uddi4j.util: clases de utilidad para varias tareas

Una de las principales clases que usará es la claseorg.uddi4j.client.UDDIProxy. Es un proxy para el servidor UDDI al que se accede a partir del código del cliente. Sus métodos se asignan a los mensajes en la especificación de API del programador UDDI.

El enfoque de esta sección consiste en seguir paso a paso un ejemplo que detalla los pasos importantes del uso de UDDI4J. Si bien nos saltearemos algunos detalles, como las importaciones de paquetes y las declaraciones de variables, los podrá encontrar en el listado de código completo al final de la sección.

Si desea obtener mucha más información, visite el sitio Web de UDDI4J. Vale la pena descargar la versión binaria desde el sitio y buscar la biblioteca en los Javadocs.

Configuración del entorno

Hay algunas propiedades que se deben configurar, como se puede ver en el siguiente código. Muchas de ellas se relacionan con HTTPS. Como ya se analizó anteriormente, es necesario usar HTTPS para publicar en un registro UDDI. No profundizaremos el tema de HTTPS, ya que excede el alcance de este tutorial. Si desea obtener más información al respecto, consulte el tutorial de seguridad de esta serie.

Establecer una conexión HTTPS de manera programática es un poco complicado porque la clase java.net.URL del JDK no es compatible con el protocolo HTTPS. Para usar HTTPS se necesita una implementación de este protocolo, y Application Developer trae una. Para habilitar la compatibilidad con HTTPS, es necesario especificar esta implementación de HTTPS en tiempo de ejecución como se indica a continuación:

Listado de código 1: Configuración del entorno

System.setProperty("java.protocol.handler.pkgs",
   "com.ibm.net.ssl.internal.www.protocol");

// imports 
... 
public class Publisher { 
    // ... 
    // Trust file supplied with the WSAD. 
    
    private static final String trustStoreFilename =
     "DummyClientTrustFile.jks"; 
    // Password for WSAD trust store. 
    private static final String trustStorePassword = "WebAS"; 
    // ... 
    
    private void setEnvironment() { 
        //Set appserver username and password 
        System.setProperty("http.basicAuthUserName", "admin"); 
        System.setProperty("http.basicAuthPassword", "adminpwd"); 
        String WAS_HOME = System.getProperty("wsdk.app.server.home"); 
        
        if ( WAS_HOME == null || WAS_HOME.equals("") ){ 
            // Can't find WAS - print error message and exit ... 
        } 
        
        trustStoreDirPath = 
        WAS_HOME + java.io.File.separatorChar + "etc" +
           java.io.File.separatorChar; 
        
        //Set the trust store file and password 
        System.setProperty("javax.net.ssl.trustStore", trustStoreDirPath + 
        trustStoreFilename); 
        System.setProperty("javax.net.ssl.trustStorePassword",
         trustStorePassword); 
        
        //Add SSL as a supported protocol. 
        System.setProperty("java.protocol.handler.pkgs",
         "com.ibm.net.ssl.internal.www.protocol"); 
    }

Acceso al registro

La clase más importante del paquete UDDI4J es la clase org.uddi4j.client.UDDIProxy. Constituye el principal objeto cuando se accede a un registro UDDI. Contiene todos los métodos necesarios para conectarse con un registro, consultar el registro y procesar el resultado. Tiene un constructor que lleva la URL de publicación de información a un registro UDDI.

La URL que sirve para publicar información en un registro de Application Developer instalado en la máquina local es: https://localhost:9443/uddisoap/publishapi.

(Nota: Se describe la conexión con un registro UDDI local.

Listado de código 2: Creación de UDDIProxy

private static String publishURLsecure =
     "https://localhost:9443/uddisoap/publishapi";
    // ... 
    private void setupProxy(){ 
    //set up proxy proxy = new UDDIProxy(); 
        try { 
            proxy.setPublishURL(publishURLsecure); 
        } catch (MalformedURLException e) { 
            // Can't create proxy - exit ... 
        } 
    }

Obtención del token de autorización

Para poder publicar un servicio, se requiere un token de autorización. Este token se obtiene enviando un nombre de usuario y una contraseña válidos al registro a través de una conexión segura. El objeto devuelto es un objeto org.uddi4j.response.AuthToken. Este objeto es necesario para todas las llamadas a la API del publicador.

Listado de código 3: Obtención del token

//Get authorization token 
    private String getAuthorization(String usr, String pwd){ 
        String authInfo = null; 
        try { 
            AuthToken authToken = proxy.get_authToken(usr,pwd); 
            authInfo = authToken.getAuthInfoString(); 
        }catch (Exception e){
         
        } 
        return authInfo; 
    }

Creación de un objeto BusinessEntity

Una vez obtenido el token de autorización, es necesario crear un objeto org.uddi4j.datatype.BusinessEntity. El objeto BusinessEntity contiene todos los parámetros que conforman un elemento BusinessEntity tal como se lo describe en el modelo de datos. Como esta empresa tiene dos nombres (inglés y español), se usará el constructor predeterminado para crear el objeto BusinessEntity y los nombres se establecerán más adelante.

Este objeto BusinessEntity debe tener una clave de negocios. Como se publicará un nuevo BusinessEntity, se proporcionará una cadena vacía como la clave de negocios. Esto le indicará al registro que tiene que generar una clave única para la entrada cuando esta es insertada en el registro.

Se crea un objeto java.util.Vector, que puede contener un número cualquiera de objetos org.uddi4j.datatype.name. Cada nombre de objeto contiene el nombre de la empresa en el idioma correspondiente. El parámetro del método setLang() es un objeto de cadena que contiene un identificador de idioma. (Los valores posibles de los identificadores de idioma están especificados en ISO3166).

Una vez que todos los nombres están definidos (inglés y español), se agrega el vector de objetos de nombre al objeto BusinessEntity invocando el método setNameVector().

Nota: La empresa y el servicio, que se publican de manera programática, son idénticos a los que se publican usando la consola. Al finalizar, es posible comparar estos dos servicios para asegurarse de que el programa funciona correctamente. Por supuesto que el UUID de los servicios será diferente.

Listado de código 4: Creación del objeto BusinessEntity

void publishBusinessEntity() { 
        try { 
        //Create the DVDOnline businessEntity Object 
        BusinessEntity businessEntity = new BusinessEntity(); 
        businessEntity.setBusinessKey(""); 
        Vector businessNames = new Vector(); 
        Name businessName_EN = new Name(); 
        businessName_EN.setLang("en"); 
        businessName_EN.setText("DVDOnline"); 
        businessNames.add(businessName_EN); 
        Name businessName_ES = new Name(); 
        businessName_ES.setLang("es"); 
        businessName_ES.setText("DVDOnline-es"); 
        businessNames.add(businessName_ES); 
        businessEntity.setNameVector(businessNames); 
    // ...

Agregación de una descripción a BusinessEntity

La descripción se agrega al servicio invocando el método setDescriptionVector() en el objeto BusinessEntity.

Como las descripciones se pueden agregar en múltiples idiomas, el método setDescriptionVector() toma un objeto java.util.Vector como su único argumento. El vector contiene una serie de objetos org.uddi4j.datatype.Description. Los objetos Description contienen una descripción correspondiente a un idioma específico.

El parámetro del método setLang() es un objeto String que contiene un identificador de idioma. Los valores posibles de los identificadores de idioma están especificados en la norma ISO3166.

Tanto el identificador de idioma como el texto de la descripción pueden ser introducidos como parámetros del constructor.

Listado de código 5: Agregación de descripciones

        // ... 
        //The description for this businessEntity 
        Description description = new Description(); 
        description.setLang("en"); 
        description.setText("Online DVD store"); 
        Vector descriptionVector = new Vector(); 
        descriptionVector.add(description); 
        businessEntity.setDescriptionVector(descriptionVector);

Agregación de información de localizador a BusinessEntity

Cuando se agrega información de localizador a BusinessEntity, es posible usar la API de consulta para localizar la categoría o tModel adecuados. Como la API de consulta se analizará en un futuro tutorial, por ahora ingresemos la información del localizador manualmente.

Un objeto org.uddi4j.util.KeyedReference sirve para representar una referencia a una categoría específica. La clase KeyedReference contiene una variedad de constructores que permiten crear un objeto KeyedReference en una sola línea de código. El ejemplo usa los diversos métodos set para agregar los datos adecuados en lugar de un constructor.

Los valores de cada uno de los campos se pueden encontrar en los portales, que están disponibles para cada uno de estos espacios de nombres.

Como se explicó anteriormente, las categorías están contenidas dentro de un elemento CategoryBag. En UDDI4J, este elemento está representado por un objeto org.uddi4j.util.CategoryBag. Los tres objetos KeyedReference se agregan al objeto CategoryBag. Luego CategoryBag se agrega a BusinessEntity invocando el método setCategoryBag().

Listado de código 6: Agregación de información de localizador

        // ... 
        KeyedReference reference_US = new KeyedReference(); 
        reference_US.setKeyName("United States"); 
        reference_US.setKeyValue("US"); 
        reference_US.setTModelKey
          ("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88"); 
        KeyedReference reference_MX = 
          new KeyedReference(); reference_MX.setKeyName("Mexico"); 
        reference_MX.setKeyValue("MX"); 
        reference_MX.setTModelKey
          ("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88"); 
        KeyedReference reference_naics = new KeyedReference(); 
        reference_naics.setKeyName
          ("Electronic Shopping and Mail-Order Houses"); 
        reference_naics.setKeyValue("4541");
         reference_naics.setTModelKey
         ("UUID:C0B9FE13-179F-413D-8A5B-5004DB8E5BB2"); 
        CategoryBag categoryBag = new CategoryBag(); 
        categoryBag.add(reference_US); 
        categoryBag.add(reference_MX); categoryBag.add(reference_naics); 
        businessEntity.setCategoryBag(categoryBag);

Agregación de información de contacto a BusinessEntity

Un objeto org.uddi4j.datatype.business.Contactcontiene toda la información de una persona que se puede contactar para obtener información sobre la empresa.

El rol de esa persona se puede establecer a través del método setUseType()del objeto de contacto.

Como se pueden definir múltiples contactos para una empresa, los objetos Contact se agregan a un objeto org.uddi4j.datatype.business.Contacts. Esto se realiza antes de que sean agregados al objeto BusinessEntity invocando el método setContacts().

Listado de código 7: Agregación de información de contacto

                    // ...
                    //Add contact information for this businessEntity
                    Contact contact = new Contact(); contact.setPersonName("Jack Smith");
                    contact.setUseType("Director"); Contacts contacts = new Contacts();
                    contacts.add(contact); businessEntity.setContacts(contacts);

El objeto de contacto contiene varios métodos para agregar información sobre el contacto. Además de los métodos para establecer el nombre y el rol de este contacto, contiene métodos para agregar información relativa a la dirección, el correo electrónico, etc. La mayoría de la información adicional que se puede agregar al contacto se agrega usando objetos java.util.Vector. El uso de un vector proporciona flexibilidad al número de elementos que se pueden agregar respecto de un tipo de información específico. Cada dato del vector está representado por un objeto correspondiente a la información en cuestión. Por ejemplo, para agregar una dirección de correo electrónico de un contacto, se agrega al contacto un vector que contenga uno o más objetos org.uddi4j.datatype.business.Email.

Al especificar múltiples direcciones de correo electrónico, es necesario establecer el UseType de cada una de ellas (por ejemplo, 'Comercial', 'Privada', etc.).

Nota: Como no se especificó ningún correo electrónico al publicar el BusinessEntity DVDOnline con la consola, la incorporación de esta porción de código se puede omitir a fin de obtener exactamente el mismo resultado que antes. Se incluye a efectos ilustrativos.

Listado de código 8: Agregación de información a un contacto

// ...
Vector emailaddresses = new Vector();
Email email_1 = new Email();
email_1.setText("J.Smith@DVDOnline.lpc");
email_1.setUseType("Business");
emailaddresses.add(email_1);
Email email_2 = new Email();
email_2.setText("J.Smith@quicknet.lpc");
email_2.setUseType("Private");
emailaddresses.add(email_2);
contact.setEmailVector(emailaddresses);

Publicación de BusinessEntity

El métod o save_business() del objeto UDDIProxy se usa para publicar uno o más objetos BusinessEntity en el registro. Antes de su publicación, BusinessEntity debe ser agregado a un objeto java.util.Vector. De esta manera, es posible publicar múltiples objetos BusinessEntity en una llamada al método.

El primer parámetro del método save_business() es el token de autorización obtenido anteriormente. El token de autorización expira después de un cierto plazo, y resulta imposible publicar o actualizar un servicio usando este token. Cuando la autorización expira, se puede solicitar un nuevo token invocando el método get_AuthToken() en el objeto UDDIProxy.

El método save_business() devuelve un objeto org.uddi4j.response.BusinessDetail que contiene información sobre las empresas recién publicadas (incluidos los UUID de estas empresas).

Después de publicar BusinessEntity, el token de autorización se puede descartar si no es necesario llevar a cabo otras acciones de publicación.

Listado de código 9: Publicación de BusinessEntity

                    // ...
                    Vector businessEntities = new Vector();
                    businessEntities.add(businessEntity); BusinessDetail businessDetail =
                    proxy.save_business(authInfo, businessEntities);
                    proxy.discard_authToken(authInfo); }
                    // end publishBusinessEntity

Vista de los resultados

Al iniciar la aplicación, se agrega un segundo BusinessEntity DVDOnline al registro.

  • Abra el navegador de servicios web
  • Realice una búsqueda de los BusinessEntities actualmente registrados

La página mostrará las dos empresas publicadas, que deberían ser idénticas, con excepción de los UUID de cada servicio.

Estructura XML de BusinessEntity

Para ver la representación XML de BusinessEntity, haga clic en la URL de descubrimiento. A continuación se muestra el XML del servicio.

<?xml version="1.0" encoding="UTF-8"?> 
<businessDetail generic="2.0" xmlns="urn:uddi-org:api_v2" operator=
"http://www.mycompany.com/uddi" truncated="false"> 
    <businessEntity businessKey="3FA5353C-2856-4C88-BBA3-23881A9E09EF" 
        operator="www.mycompany.com/uddi" authorizedName="admin"> 
        <discoveryURLs> 
            <discoveryURL useType="businessEntity"> 
                http://localhost:6080/uddisoap/get?businessKey=
                3FA5353C2856-4C88-BBA3-23881A9E09EF 
            </discoveryURL> 
        </discoveryURLs> 
        <name xml:lang="en">DVDOnline</name> 
        <name xml:lang="es">DVDOnline-es</name> 
        <description xml:lang="en">Online DVD store</description> 
        <contacts> 
            <contact useType="Director"> 
                <personName>Jack Smith</personName> 
            </contact> 
        </contacts> 
        <categoryBag> 
            <keyedReference tModelKey=
            "UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88" 
                keyName="United States" keyValue="US"/> 
            <keyedReference tModelKey
            ="UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88" 
                keyName="Mexico" keyValue="MX"/> 
            <keyedReference tModelKey=
            "UUID:C0B9FE13-179F-413D-8A5B-5004DB8E5BB2" 
                keyName="Electronic Shopping and Mail-Order Houses"
                 keyValue="4541"/> 
        </categoryBag> 
    </businessEntity>
</businessDetail>

Creación del servicio y agregación a BusinessEntity

Para publicar un BusinessService, se crea un objeto org.uddi4j.datatype.service.BusinessService. El objetoBusinessService contiene todos los parámetros que conforman un elemento BusinessService, tal como se describe en el modelo de datos.

Para agregar este BusinessService a un BusinessEntity, es necesario establecer un valor BusinessKey en el objeto BusinessService. La clave de negocios es el UUID del objetoBusinessEntity al que se agrega este servicio.

Cuando este valor es conocido, puede ser establecido en el objeto BusinessService invocando el método setBusinessKey().

En este ejemplo, el servicio será registrado en el BusinessEntity publicado anteriormente. El UUID de este BusinessEntity se puede obtener del objeto BusinessDetail devuelto por el método save_business(). Como se ha publicado un solo BusinessEntity, el vector contiene un solo objeto BusinessEntity.

Listado de código 10: Agregación de BusinessService

public void publishBusinessService(){
    BusinessService businessService = new BusinessService();

    //obtain businessKey
    Vector businessVector = businessDetail.getBusinessEntityVector();
    String businessKey=null;
    if(businessVector.size()>0){
        businessKey=        
        ((BusinessEntity)businessVector.get(0)).getBusinessKey();
    }else{ // ... Fail }
businessService.setBusinessKey(businessKey);

Determinación de propiedades de BusinessService

Determinación del nombre
El nombre del servicio se establece de la misma manera que con el nombre del BusinessEntity. Se pueden agregar diferentes nombres para diferentes idiomas a un objeto java.util.Vector.

Como a este servicio se le agrega un solo nombre, esta tarea se realiza en tres líneas de código. Vector, que contiene los objetos Name, se agrega al objeto BusinessService invocando el método setNameVector().

Listado de código 11: Determinación del nombre de BusinessService

                    // ...
                    Vector serviceNames = new Vector(); serviceNames.add(new
                    Name("OrderDVD")); businessService.setNameVector(serviceNames);

Determinación de la clave de servicio
El servicio debe contar con una clave de servicio. Al crearse un servicio nuevo, se pasa una cadena vacía al método setServiceKey(), que le indica al registro que genere una clave única para la entrada cuando esta es insertada en el registro.

Listado de código 12: Determinación de una clave de servicio

businessService.setServiceKey("");

Agregación de una descripción
Luego se agrega una descripción corta del servicio. También en este caso se pueden agregar al servicio múltiples descripciones para múltiples idiomas. Esto se logra agregando múltiples objetos de descripción al objeto java.util.Vector.

Solo una descripción se agrega al servicio. El vector que contiene un objeto de descripción se agrega al servicio invocando el método setDescriptionVector().

Listado de código 13: Agregación de una descripción

                    Vector descriptions = new Vector(); descriptions.add(new
                    Description("Online service for ordering DVDs"));
                    businessService.setDescriptionVector(descriptions);

Definición del punto de acceso del servicio

Es necesario agregar el punto de acceso (ubicación) de este servicio al objeto BindingTemplate. Se crea un objeto org.uddi4j.datatype.binding.AccessPoint. El URLType de este punto de acceso se establece en HTTP. Hay una gran variedad de URLTypes disponibles cuando se define el punto de acceso de un servicio. Por ejemplo, un URLType debe ser establecido en HTTPS cuando se requiere una conexión segura para el servicio.

Se usa el método setText() para establecer el punto de acceso de este servicio, que en este caso es la URL del servicio. No hace falta decir que cuando se establece un URLType diferente, el valor del punto de acceso cambiará de manera de reflejar un punto de acceso adecuado para el URLType especificado.

Una vez que se establece el URLType y la ubicación real, debe agregarse el AccessPoint al BindingTemplate, que representa un elemento. ElAccessPointse agrega al BindingTemplate invocando el método setAccessPoint().

El objeto BindingTemplate contiene referencias a los modelos técnicos y puntos de acceso del servicio. BindingKey se convierte en una entrada independiente en el registro y en un valor UUID. Como se crea una nueva entrada en el registro, es necesario proporcionar una cadena vacía como valor inicial para indicarle al registro que genere un nuevo UUID cuando se inserte la entrada.

Listado de código 14: Agregación de un punto de acceso

// ...
BindingTemplate bindingTemplate = new BindingTemplate();
bindingTemplate.setBindingKey("");
AccessPoint accessPoint = new AccessPoint();
accessPoint.setURLType("http");
accessPoint.setText
  ("http://localhost:6080/DVDOnline/services/OrderDVD ");
bindingTemplate.setAccessPoint(accessPoint);

Agregación de referencia a tModel

Para indicar que el servicio cumple una determinada especificación técnica, se debe agregar una referencia al modelo técnico que se cumple. Un enfoque sería ubicar el modelo pertinente usando la API de consulta UDDI4J. Sin embargo, como esta API recién se explicará en el tutorial de consulta, la información necesaria sobre el modelo técnico se obtiene usando la consola UDDI. En el próximo tutorial, Descubrimiento de servicios web: UDDI, se explicará cómo hacerlo con la API UDDI4J.

Usted acaba de publicar un modelo técnico. Al ingresar al registro, el modelo recibió un UUID. Ahora es necesario usar la consola para ubicar el UUID del modelo técnico publicado. Esta tarea se puede realizar usando la opción Quick find (Búsqueda rápida) de la consola o bien la opción show owned entities (mostrar entidades propias). Aparecerá una lista que incluye el modelo técnico deseado y los vínculos. Debería poder ver el UUID. Por supuesto que con la API de consulta UDDI, tendrá mejores opciones para hacerlo.

Un objeto TModelInstanceInfo contiene la referencia al modelo técnico. Como se pueden asignar múltiples modelos técnicos a un servicio, se agregan uno o más objetos TModelInstancea l objeto TModelInstanceDetails. A su vez, el objeto TModelInstanceDetails se agrega a bindingTemplate.

Listado de código 15: Agregación de tModel

// ...
//Adding tModel instance data
// NOTE - You need to use the actual UUID from your technical model
TModelInstanceInfo tModelInstanceInfo =
new TModelInstanceInfo("UUID:1B830749-20BB-4F97-BADF-24353B5424E8");
Vector tModelInstanceInfoList=new Vector();
tModelInstanceInfoList.addElement(tModelInstanceInfo);
TModelInstanceDetails tModelInstanceDetails =
new TModelInstanceDetails();
tModelInstanceDetails.setTModelInstanceInfoVector
  (tModelInstanceInfoList);
bindingTemplate.setTModelInstanceDetails(tModelInstanceDetails);

Agregación de plantillas de enlace al servicio

Una vez agregada toda la información necesaria, el objeto BindingTemplate se puede agregar al BusinessService.

Como se pueden definir múltiples enlaces para un único servicio, se crea un objeto org.uddi4j.datatype.binding.BindingTemplates. Un objeto BindingTemplates contiene cero o más objetos BindingTemplate.

El objeto BindingTemplates se agrega al BusinessService invocando el método setBindingTemplates().

Listado de código 16: Agregación de la plantilla de enlace al servicio

// ... BindingTemplates bindingTemplates = new
                    BindingTemplates(); bindingTemplates.add(bindingTemplate);
                    businessService.setBindingTemplates(bindingTemplates);

Agregación de información de localizador al servicio

La información de categoría se agrega a un BusinessService de la misma manera en que se agrega información de categoría a un BusinessEntity.

Se usa un objeto org.uddi4j.util.KeyedReference para representar una referencia a una categoría específica.

En el caso de este servicio, se crea una sola categoría. Esta categoría especifica la ubicación geográfica del servicio, en este caso, Estados Unidos.

Los valores de cada uno de los campos del objeto KeyedReference también se podrían determinar usando la API de consulta para ubicar la categoría adecuada. Como la API de consulta se analizará en un futuro tutorial, la información debe ser ingresada manualmente.

Listado de código 17: Agregación de información de localizador al servicio

    // ... 
    //Add category information for this businessEntity 
    KeyedReference reference_US = new KeyedReference();
    reference_US.setKeyName("United States"); reference_US.setKeyValue("US"); 
    reference_US.setTModelKey("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88"); 
    CategoryBag categoryBag = new CategoryBag(); 
    categoryBag.add(reference_US); 
    businessService.setCategoryBag(categoryBag);

Publicación del servicio

El método save_service() del objeto UDDIProxy se usa para publicar uno o más objetos businessService en el registro. Antes de publicar el businessService, debe ser agregado al objeto java.util.Vector. De esta manera, es posible publicar múltiples objetos BusinessService en una llamada al método.

El primer parámetro del método save_service() es el token de autorización que fue obtenido anteriormente. Como el token de autorización puede estar expirado o puede haber sido descartado después de publicar BusinessEntity, quizás se requiera un nuevo token de autorización antes de la publicación del servicio. Se puede solicitar un nuevo token invocando el método get_AuthToken() en el objeto UDDIProxy.

El método save_service() devuelve un objeto org.uddi4j.response.ServiceDetail que contiene información acerca de los servicios recién publicados (incluidos los UUID de estos servicios empresariales).

Listado de código 18: Publicación del servicio

    // ... 
    Vector businessServices = new Vector(); 
    businessServices.add(businessService); 
    try{ 
        ServiceDetail serviceDetails =
         proxy.save_service(authInfo,businessServices); 
    }catch(Exception e){ 
        // Failed ... 
    }

Misión cumplida

Si llegó hasta aquí, ¡felicitaciones! El uso de API Java para interactuar con el registro no es para los débiles. Son complejas y requieren una atención minuciosa. Sin embargo, se puede lograrlo.

Puede examinar el listado de código completo que se encuentra al final de esta sección y ejecutarlo en su propio sistema. Pruebe modificar el código para publicar diferentes cosas, y luego examine el registro con la GUI para ver los resultados.

Listado de código completo

El código que se muestra en esta sección explica los diferentes pasos que se necesitan para publicar un BusinessEntity y un BusinessService en el registro UDDI. Antes de profundizar en el código, revisemos las diferentes partes de la aplicación.

Como la publicación de una entrada requiere una conexión segura con el registro, se tiene que configurar el entorno local de manera de permitir la creación de una conexión HTTPS con el servidor. El controlador de protocolo de la conexión HTTPS, así como los certificados intercambiados mediante esta conexión, deben ser registrados.

Una vez configurado el entorno para usar HTTPS, será necesario crear la conexión real con el registro. Esto se realiza creando un objeto UDDIProxy y proporcionándole a este objeto la URL de publicación del registro. Cuando Application Developer se ejecuta en una máquina local, la URL debería ser https://localhost:9443/uddisoap/publishapi.

La clase UDDIProxy contiene diversos métodos para comunicarse con el registro. La publicación de la empresa o servicio se efectúa invocando métodos en la clase UDDIProxy. Además, la clase UDDIProxy también contiene métodos para borrar entradas del registro y para obtener y descartar tokens de autorización.

Los tokens de autorización son necesarios para publicar o actualizar entradas en el registro UDDI. Todos los métodos de la clase UDDIProxy que se usan para manipular el registro de alguna forma requieren un token de autorización. Este token se obtiene de la clase UDDIProxy proporcionando el nombre y la contraseña del usuario que administra la entrada UDDI en cuestión. Los tokens de autorización se otorgan por un plazo determinado. Si este plazo se cumple, ya no será posible actualizar o publicar entradas UDDI con el mismo token.

Una vez establecida la conexión con el registro y obtenido el token de autorización, se puede empezar a publicar información de la empresa, información del servicio o modelos técnicos en el registro.

Como un determinado servicio es proporcionado por una o más empresas, comience publicando un BusinessEntity. El BusinessEntity está representado en UDDI4J por un objeto BusinessEntity. Una vez creado este objeto, es necesario agregar información sobre la empresa. Para empezar, se debe establecer el nombre de la empresa. Además, se puede agregar información descriptiva, como categorías e información de contacto, al BusinessEntity.

Una vez publicada la empresa, los servicios proporcionados por esta empresa se anotan en el registro. Una entrada BusinessService está representada en UDDI4J por un objeto BusinessService. Como en el caso de BusinessEntity, se debe establecer el nombre del servicio, pero además es necesario agregar el BusinessKey (UUID) de la empresa que presta este servicio (la empresa publicada anteriormente) al objeto BusinessService. De esta manera se establece la relación entre BusinessService y el objeto BusinessEntity en el registro.

También se agrega al servicio información descriptiva sobre este. Esto les da a los analistas de negocios que buscan un servicio en particular una visión general de la funcionalidad del servicio.

Una vez agregada la información descriptiva, es necesario agregar información técnica sobre el servicio para permitir a las aplicaciones de los futuros clientes buscar el servicio especificado y conectarse con él.

Todas las referencias a las ubicaciones de los servicios, así como los modelos técnicos que sigue este servicio, están especificados dentro de un objeto BindingTemplate. El objeto BindingTemplate contiene la URL del accessPoint del servicio, así como el tipo de punto de acceso. Un servicio web ubicado dentro del registro no tiene por qué ser un componente de negocios; podría ser una dirección de correo electrónico, en cuyo caso el tipo de punto de acceso se definiría como SMTP.

Además del punto de acceso, BindingTemplate también contiene una referencia al modelo técnico según el cual se creó el servicio. En el caso de un componente de negocios que actúa como un servicio web, el modelo técnico define la interfaz que se usará para este servicio, así como sus parámetros y valores devueltos.

Una vez establecidos todos los valores en el objeto BindingTemplate, la plantilla también se agrega al objeto BusinessService.

Por último, se agrega información de categoría al BusinessService. La información de categoría se puede usar para localizar servicios. Por ejemplo, sería posible buscar solamente servicios ubicados en los Estados Unidos. Una vez agregada toda la información acerca de BusinessService, se publican en el registro.

Al finalizar la siguiente sección, usted ya podrá publicar un BusinessEntity y BusinessService de manera programática. El resultado se puede examinar usando la consola UDDI, tal como se describió anteriormente.

En el próximo tutorial, Descubrimiento de Web Services: UDDI, aprenderá a ubicar y recuperar entradas de registro UDDI. El ejemplo de programación del final del próximo tutorial usa la API de publicación UDDI4J para publicar un par de empresa y servicios y recupera la información publicada usando la API de consulta UDDI4J. En vez de usar UUID codificados de forma rígida, encuentra todo lo que necesita en el registro. Es un ejemplo completo que incluye scripts para compilar y ejecutar el código de publicación.

Note: En el próximo tutorial, "Descubrimiento de servicios web: UDDI", encontrará un ejemplo completo que incluye una publicación más realista.

package com.ibm.wsdk.tutorial6.ex1; 
import java.util.*; 
import java.net.MalformedURLException; 
import org.uddi4j.response.*; 
import org.uddi4j.client.UDDIProxy; 
import org.uddi4j.util.*; 
import org.uddi4j.datatype.*; 
import org.uddi4j.datatype.business.*; 
import org.uddi4j.datatype.binding.*; 
import org.uddi4j.datatype.service.BusinessService;
                
public class Publisher { //UDDI proxy object representing
  the UDDI registry.
    protected static UDDIProxy proxy;
    private static String authInfo=null;
    //Paths to inquiry and publish api.
    private static String inquiryURL =
     "http://localhost:6080/uddisoap/inquiryapi";
    private static String publishURLnonsecure =
     "http://localhost:6080/uddisoap/publishapi";
    private static String publishURLsecure =
     "https://localhost:9443/uddisoap/publishapi";
     
    //UDDI User ID and password. private 
      static String uddiUserID = "admin"; 
    private static String uddiPassword = "adminpwd"; 
    
    // trustStoreDirPath depends on the location of the 
    application server // which is obtained by reading the 
     System property "wsdk.app.server.home". 
    private String trustStoreDirPath = null; 
    private static final String trustStoreFilename =
     "DummyClientTrustFile.jks"; 
    private static final String trustStorePassword = "WebAS"; 
    private BusinessDetail businessDetail = null;
    
    private void setEnvironment(){ 
        //Set appserver username and password 
        System.setProperty("http.basicAuthUserName", "admin"); 
        System.setProperty("http.basicAuthPassword", "adminpwd"); 
        String WAS_HOME = System.getProperty("wsdk.app.server.home"); 
        
        if ( WAS_HOME == null || WAS_HOME.equals("") ){ 
            System.out.println("Unable to determine location of
             application server."); 
            System.exit(1); 
        }
        
        trustStoreDirPath = 
        WAS_HOME + java.io.File.separatorChar + 
        "etc" + java.io.File.separatorChar; 
        
        //Set the trust store file and password 
        (see comments near top of this sample.) 
        System.setProperty("javax.net.ssl.trustStore",
         trustStoreDirPath + trustStoreFilename); 
        System.setProperty
        ("javax.net.ssl.trustStorePassword", 
         trustStorePassword);
        
        //Add SSL as a supported protocol. 
        System.setProperty("java.protocol.handler.pkgs",
         "com.ibm.net.ssl.internal.www.protocol"); 
    }
    
    private void setupProxy(){ 
        //set up proxy proxy = new UDDIProxy(); 
        try{ 
            proxy.setInquiryURL(inquiryURL); 
            proxy.setPublishURL(publishURLsecure); 
        } catch (MalformedURLException e) { 
            System.out.println( "MalformedURLException 
            was thrown when attempting to set the UDDI proxy's URLs"); 
            System.out.println(e.getMessage()); System.exit(1); 
        } 
    } 
        
    protected String getAuthorization(String usr,String pwd){ 
        //Get authorization token 
        String authInfo=null; 
        try{ 
            AuthToken authToken = proxy.get_authToken(usr,pwd); 
            authInfo = authToken.getAuthInfoString(); 
        }catch (Exception e){ 
            System.out.println( "An exception was thrown 
            when getting the authorization token:\n"+e); 
            System.exit(1); 
        } 
        
        if(authInfo!=null){ 
            System.out.println("Successfully obtained 
            authorization token and its info string."); 
        } 
        return authInfo; 
    }
    
    void publishBusinessEntity() { 
        System.out.println("Publishing the 
        businessEntity to the UDDI"); 
        try { 
            //The DVDOnline businessEntity Object 
            BusinessEntity businessEntity = new BusinessEntity(); 
            businessEntity.setBusinessKey(""); 
            Vector businessNames = new Vector(); 
            Name businessName_EN = new Name(); 
            businessName_EN.setLang("en"); 
            businessName_EN.setText("DVDOnline"); 
            businessNames.add(businessName_EN); 
            Name businessName_ES = new Name(); 
            businessName_ES.setLang("es"); 
            businessName_ES.setText("DVDOnline-es"); 
            businessNames.add(businessName_ES); 
            businessEntity.setNameVector(businessNames); 
            
            //The description for this businessEntity 
            Description description = new Description(); 
            description.setLang("en"); 
            description.setText("Online DVD store"); 
            Vector descriptionVector = new Vector(); 
            descriptionVector.add(description); 
            businessEntity.setDescriptionVector(descriptionVector);
            
            //Add category information for this businessEntity 
            KeyedReference reference_US = new KeyedReference(); 
            reference_US.setKeyName("United States"); 
            reference_US.setKeyValue("US"); 
            reference_US.setTModelKey
            ("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88"); 
            KeyedReference reference_MX = new KeyedReference(); 
            reference_MX.setKeyName("Mexico");
             reference_MX.setKeyValue("MX"); 
            reference_MX.setTModelKey
            ("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88"); 
            KeyedReference reference_naics = new KeyedReference(); 
            reference_naics.setKeyName
            ("Electronic Shopping and Mail-Order Houses"); 
            reference_naics.setKeyValue("4541"); 
            reference_naics.setTModelKey
            ("UUID:C0B9FE13-179F-413D-8A5B-5004DB8E5BB2"); 
            CategoryBag categoryBag = new CategoryBag(); 
            categoryBag.add(reference_US); 
            categoryBag.add(reference_MX); 
            categoryBag.add(reference_naics); 
            businessEntity.setCategoryBag(categoryBag);
            
            //Add contact information for this businessEntity 
            Contact contact = new Contact(); 
            contact.setPersonName("Jack Smith"); 
            contact.setUseType("Director"); 
            Vector emailaddresses = new Vector(); 
            Email email_1 = new Email();
            email_1.setText("J.Smith@DVDOnline.lpc");
            email_1.setUseType("Business"); 
            emailaddresses.add(email_1); 
            Email email_2 = new Email();
            email_2.setText("J.Smith@quicknet.lpc");
            email_2.setUseType("Private"); 
            emailaddresses.add(email_1); 
            contact.setEmailVector(emailaddresses); 
            Contacts contacts = new Contacts(); 
            contacts.add(contact); businessEntity.setContacts(contacts); 
            Vector businessEntities = new Vector(); 
            businessEntities.add(businessEntity); 
            businessDetail = proxy.save_business
            (authInfo, businessEntities); 
        }catch (Exception e){ 
            System.out.println("Attempting to publish 
            the service provider to the UDDI:\n"+e); 
            e.printStackTrace(); 
            System.exit(1); 
        } 
    } 
    
    public void publishBusinessService(){ 
        BusinessService businessService = new BusinessService(); 
        //obtain businessKey Vector businessVector =
         businessDetail.getBusinessEntityVector(); 
        String businessKey=null; 
        if(businessVector.size()>0){ 
            businessKey=
            ((BusinessEntity)businessVector.get(0)).getBusinessKey(); 
        }else{ 
            System.exit(1); 
        } 
        
        businessService.setBusinessKey(businessKey); 
        Vector serviceNames = new Vector(); 
        serviceNames.add(new Name("OrderDVD")); 
        businessService.setNameVector(serviceNames); 
        businessService.setServiceKey(""); 
        Vector descriptions = new Vector(); 
        descriptions.add(new Description("Online service 
        for ordering DVDs")); 
        businessService.setDescriptionVector(descriptions); 
        BindingTemplate bindingTemplate = new BindingTemplate(); 
        bindingTemplate.setBindingKey(""); 
        AccessPoint accessPoint = new AccessPoint(); 
        accessPoint.setURLType("http"); 
        accessPoint.setText
        ("http://localhost:6080/DVDOnline/services/OrderDVD ");
        bindingTemplate.setAccessPoint(accessPoint); 
        
        //Adding tModel instance data 
        TModelInstanceInfo tModelInstanceInfo = new TModelInstanceInfo
        ("UUID:1B830749-20BB-4F97-BADF-24353B5424E8"); 
        Vector tModelInstanceInfoList=new Vector(); 
        tModelInstanceInfoList.addElement(tModelInstanceInfo); 
        TModelInstanceDetails tModelInstanceDetails = 
        new TModelInstanceDetails(); 
        tModelInstanceDetails.setTModelInstanceInfoVector
        (tModelInstanceInfoList);
        bindingTemplate.setTModelInstanceDetails
        (tModelInstanceDetails); 
        BindingTemplates bindingTemplates = new BindingTemplates(); 
        bindingTemplates.add(bindingTemplate); 
        businessService.setBindingTemplates(bindingTemplates); 
        
        //Add category information for this businessEntity 
        KeyedReference reference_US = new KeyedReference(); 
        reference_US.setKeyName("United States"); 
        reference_US.setKeyValue("US"); 
        reference_US.setTModelKey
        ("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88"); 
        CategoryBag categoryBag = new CategoryBag(); 
        categoryBag.add(reference_US); 
        businessService.setCategoryBag(categoryBag); 
        Vector businessServices = new Vector(); 
        businessServices.add(businessService); 
        
        try{ 
            ServiceDetail serviceDetails =
             proxy.save_service(authInfo,businessServices); 
        }catch(Exception e){ 
            e.printStackTrace(); 
        }
    } 
    
    public static void main(String[] args) { 
        Publisher p = new Publisher(); p.setEnvironment(); 
        p.setupProxy(); 
        authInfo = p.getAuthorization(uddiUserID,uddiPassword); 
        p.publishBusinessEntity(); p.publishBusinessService(); 
    } 
}

Conclusión

Revisión del tutorial

En este tutorial, usted:

  • Revisó WSDL y su importancia.
  • Aprendió la estructura y los elementos de WSDL.
  • Revisó el esquema XML y aprendió a usarlo con WSDL.
  • Usó los complementos de IBM Application Developer para Eclipse para crear sistemas basados en servicios web a partir de archivos WSDL.
  • Creó, implementó y usó un pequeño sistema de servicios web a partir de un archivo WSDL.

A primera vista, WSDL podría parecer un poco esotérico. También se lo podría considerar una parte poco importante de la arquitectura de servicios web. Si bien es verdad que se pueden realizar muchas tareas de desarrollo de servicios web sin usar WSDL directamente si se dispone de las herramientas de nivel alto adecuadas, es importante comprender su estructura y para qué se usa. Es un elemento fundamental en la interoperabilidad de los servicios web. Además, es muy importante si se usa un registro UDDI.

En este tutorial, se dio una idea de qué es WSDL y cómo se puede usar con WebSphere Studio Application Developer Integration Edition Versión 5.1. También se analizó brevemente la tecnología UDDI, y se la seguirá analizando en el próximo tutorial. Esto le resultará muy útil si su trabajo con servicios web sigue creciendo.


Descargar

DescripciónNombretamaño
Source code for this tutorialws-soa-3code.zip21MB

Recursos

Aprender

Obtener los productos y tecnologías

Comentar

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=SOA y servicios web
ArticleID=681887
ArticleTitle=Creación de SOA con servicios web usando WebSphere Studio, parte 3: Publicación con WSDL y UDDI mediante WebSphere
publish-date=08052011