domingo, 23 de febrero de 2014

Introducción a JAX-WS con Maven.

Hace poco estaba leyendo un pdf de WSO2 sobre sus recomendaciones para los desarrolladores que usan esta plataforma en su día a día y mencionaban con mucho hincapié a JAX-WS y JAX-RS como las APIs preferidas por los desarrolladores para los temas de servicios web y REST.

Además de soportar los servicios axis2 y los servicios de acceso a datos, WSO2 permite el despliegue de servicios JAX-WS con la implementación de CXF y JAX-RS. Entre las ventajas que brinda la plataforma se pueden mencionar:

  • Facilidad de acceso a los almacenes de usuarios a través de las APIs de WSO2.
  • Facilidad de acceso a la API del registro de WSO2 para la persistencia de información.
  • Autorización de grano fino usando el Identity Server de WSO2.
  • Una interfaz gráfica amigable para la gestión de las aplicaciones que contienen los servicios desplegados.
  • Despliegue y actualización en caliente de los servicios web.

Para comenzar a adentrarnos en JAX-WS lo haremos primero con Metro, luego pasaremos a CXF y veremos como desplegar estas aplicaciones en el AS con las facilidades antes mencionadas.

En esta entrada veremos cómo implementar un servicio web en JAX-WS con la ayuda de Maven.
Se implementa el escenario en el cual tenemos un WSDL ya diseñado y queremos implementar el servicio a partir de dicho WSDL. El cual mostramos a continuación:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
        name="helloPersonService"
        targetNamespace="http://example.nl/hellopersonservice/1.0"
        xmlns:tns="http://example.nl/hellopersonservice/1.0"
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        >
    <wsdl:types>
        <xsd:schema targetNamespace="http://example.nl/hellopersonservice/1.0">
            <xsd:import schemaLocation="../xsd/helloPersonService.xsd"
                        namespace="http://example.nl/hellopersonservice/1.0"/>
        </xsd:schema>
    </wsdl:types>
    <wsdl:message name="HelloPersonServiceRequest">
        <wsdl:part name="HelloPersonServiceRequest" element="tns:HelloPersonServiceRequest"/>
    </wsdl:message>
    <wsdl:message name="HelloPersonServiceResponse">
        <wsdl:part name="HelloPersonServiceResponse" element="tns:HelloPersonServiceResponse"/>
    </wsdl:message>
    <wsdl:portType name="HelloPersonServicePortType">
        <wsdl:operation name="greetPerson">
            <wsdl:input name="HelloPersonServiceRequest" message="tns:HelloPersonServiceRequest"/>
            <wsdl:output name="HelloPersonServiceResponse" message="tns:HelloPersonServiceResponse"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="HelloPersonServiceBinding" type="tns:HelloPersonServicePortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="greetPerson">
            <soap:operation style="document" soapAction="http://example.nl/HelloPersonService/greetPerson"/>
            <wsdl:input name="HelloPersonServiceRequest">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="HelloPersonServiceResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="HelloPersonService">
        <wsdl:port name="HelloPersonServicePort" binding="tns:HelloPersonServiceBinding">
            <soap:address location="/service/helloPersonService" />
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

Y como este wsdl referencia a un XSD también les mostramos el XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            xmlns="http://example.nl/hellopersonservice/1.0"
            targetNamespace="http://example.nl/hellopersonservice/1.0">
    <xsd:element name="HelloPersonServiceRequest" type="HelloPersonServiceRequestType"/>
    <xsd:element name="HelloPersonServiceResponse" type="HelloPersonServiceResponseType"/>

    <xsd:complexType name="HelloPersonServiceRequestType">
        <xsd:element name="Person" type="PersonType"/>
    </xsd:complexType>

    <xsd:complexType name="HelloPersonServiceResponseType">
        <xsd:element name="Greetings" type="xsd:string"/>
    </xsd:complexType>

    <xsd:complexType name="PersonType">
        <xsd:sequence>
            <xsd:element name="FirstName" type="xsd:string"/>
            <xsd:element name="LastName" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>


Comencemos a implementar nuestro servicio web usando JAX-WS.

Paso 1: Crear una aplicación web en Maven. Para aquellos que no saben les recomiendo este enlace.

Paso 2: incluir la dependencia de jax-ws en su fichero pom.xml. les muestro el pom.xml completo del proyecto


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>jaxws3</groupId>
  <artifactId>jaxws3</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>jaxws3 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
      <dependency>
          <groupId>javax</groupId>
          <artifactId>javaee-web-api</artifactId>
          <version>6.0</version>
          <scope>provided</scope>
      </dependency>
   <!-- Dependencia de JAX-WS-->
      <dependency>
          <groupId>com.sun.xml.ws</groupId>
          <artifactId>jaxws-rt</artifactId>
          <version>2.2.8</version>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>com.sun.xml.bind</groupId>
          <artifactId>jaxb-xjc</artifactId>
          <version>2.2.6</version>
      </dependency>
      <dependency>
          <groupId>org.codehaus.plexus</groupId>
          <artifactId>plexus-io</artifactId>
          <version>2.0.6</version>
      </dependency>
  </dependencies>
  <build>
    <!-- Nombre que tendra la aplicacion web-->
    <finalName>hello_person</finalName>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>2.0.2</version>
              <configuration>
                  <source>1.7</source>
                  <target>1.7</target>
              </configuration>
          </plugin>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-war-plugin</artifactId>
              <version>2.2</version>
              <configuration>
                  <failOnMissingWebXml>false</failOnMissingWebXml>
              </configuration>
          </plugin>
           
          <plugin>
              <groupId>org.mortbay.jetty</groupId>
              <artifactId>jetty-maven-plugin</artifactId>
              <configuration>
                  <webAppConfig>
                      <contextPath>hello_person</contextPath>
                  </webAppConfig>
                  <connectors>
                      <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
                          <port>8083</port>
                      </connector>
                  </connectors>
              </configuration>
          </plugin>

          <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>build-helper-maven-plugin</artifactId>
              <version>1.8</version>
              <executions>
                  <execution>
                      <id>add-source</id>
                      <phase>generate-sources</phase>
                      <goals>
                          <goal>add-source</goal>
                      </goals>
                      <configuration>
                          <sources>
                              <source>${basedir}/target/generated/src/main/java</source>
                          </sources>
                      </configuration>
                  </execution>
              </executions>
          </plugin>
          <!-- Plugin para generar el codigo a partir del WSDL del servicio web-->
          <plugin>
              <groupId>org.jvnet.jax-ws-commons</groupId>
              <artifactId>jaxws-maven-plugin</artifactId>
              <version>2.1</version>
              <configuration>
                  <sei>cu.uci.cdae.hello_person.service.HelloPersonServiceImpl</sei>
                  <wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
                  <packageName>cu.uci.cdae.hello_person.service.generated</packageName>
                  <keep>true</keep>
                  <sourceDestDir>${basedir}/target/generated/src/main/java</sourceDestDir>
              </configuration>
              <executions>
                  <execution>
                      <goals>
                          <goal>wsimport</goal>
                      </goals>
                  </execution>
              </executions>
              <dependencies>
                  <dependency>
                      <groupId>com.sun.xml.bind</groupId>
                      <artifactId>jaxb-xjc</artifactId>
                      <version>2.1.12</version>
                  </dependency>
                  <dependency>
                      <groupId>com.sun.xml.ws</groupId>
                      <artifactId>jaxws-rt</artifactId>
                      <version>2.1.7</version>
                      <scope>compile</scope>
                  </dependency>
              </dependencies>
          </plugin>
      </plugins>
  </build>
</project>

Paso 3: incluir el plugin para Maven de JAX-WS, el cual pueden ver en el pom.xml. Este plugin nos permite generar el código del servicio web a partir del WSDL. Su configuración es bastante sencilla y debemos especificarle la ubicación del wsdl, el paquete donde se generará el código, si mantenemos el fuente generado pues por defecto se borran los .java y solo quedan los compilados, y por último el destino de donde pondremos el fuente generado.


Paso 4: crear un carpeta en [proyecto]\src\main\resources\ con el nombre wsdl que es donde se pondrá el wsdl diseñado y otra xsd que es donde se pondrá el xsd referenciado por el wsdl.

Paso 5: debemos ir a [proyecto]\ src\main\webapp\WEB-INF\ y crear 2 ficheros sun-jaxws.xml y web.xml cuyo contenido es el siguiente.

fichero sun-jaxws.xml
<?xml version="1.0" encoding="UTF-8"?>
<endpoints
        xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime'
        version='2.0'>
    <endpoint
            name='helloPersonService'
            implementation='cu.uci.cdae.hello_person.service.HelloPersonServiceImpl'
            url-pattern='/helloPersonService' />
</endpoints>

fichero web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>
    <servlet>
        <description>JAX-WS endpoint</description>
        <display-name>The JAX-WS servlet</display-name>
        <servlet-name>jaxws</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>jaxws</servlet-name>
        <url-pattern>/helloPersonService</url-pattern>
    </servlet-mapping>
</web-app>


En sun-jaxws.xml definimos el endpoint que usaremos, el patrón para la URL y la clase que implementa este endpoint.
En web.xml definimos el Servlet y el mapeo que usaremos.

Llegado este punto podemos ir a la raíz del proyecto y ejecutar el siguiente comando Maven:
mvn clean compile

En la carpeta /target/generated/src/main/java y en el paquete cu.uci.cdae.hello_person.service.generated tendremos el código generado automáticamente.

Paso 5: implementar la lógica de negocio del servicio.
Si revisaron el WSDL verán que recibimos un objeto persona que tiene nombre y apellidos y se devuelve un String.

La clase que implementa el  servicio es la siguiente:

package cu.uci.cdae.hello_person.service;

import cu.uci.cdae.hello_person.service.generated.HelloPersonServiceRequestType;
import cu.uci.cdae.hello_person.service.generated.HelloPersonServiceResponseType;

import javax.jws.WebService;

@WebService(endpointInterface = "cu.uci.cdae.hello_person.service.generated.HelloPersonServicePortType")
public class HelloPersonServiceImpl implements cu.uci.cdae.hello_person.service.generated.HelloPersonServicePortType {

    @Override
    public HelloPersonServiceResponseType greetPerson(HelloPersonServiceRequestType helloPersonServiceRequest) {
        HelloPersonServiceResponseType helloPersonServiceResponse = new HelloPersonServiceResponseType();
        helloPersonServiceResponse.setGreetings("Hello " + helloPersonServiceRequest.getPerson().getFirstName() + " " + helloPersonServiceRequest.getPerson().getLastName() + "!");
        return helloPersonServiceResponse;
    }

}

Como pueden ver la implementación es realmente limpia. La clase es anotada para que sea contemplada como uun servicio web y especificamos la interfaz del endpoint. Esta clase debe implementar dicha interfaz y acepta  un objeto que contiene la estructura de la persona definida en el XSD que vimos al inicio.

Lo que nos queda ahora es empaquetar nuestro servicio usando el siguiente comando de maven:
mvn clean package

Y el war generado desplegarlo en un Tomcat o en el AS de WSO2

Espero les sea de utilidad

0 comentarios:

Publicar un comentario