Ha pasado mucho tiempo desde el último post que escribí, pero realmente han sido unos meses duros. Ha habido cambio de ciudad y cambios profesionales, y no he tenido el tiempo suficiente como para sentarme a volver a escribir en el blog. Ya os adelanto que los cambios profesionales desembocarán en nuevos y (espero) interesantes tutoriales. En el proyecto en el que me encuentro, estamos utilizando seam, lucene, EJB3, JSF… en fin, mucho sobre lo que escribir. Pero de momento me centraré en cerrar el círculo que había quedado pendiente.

En este tutorial veremos como crear un web service a partir de un wsdl, y en el próximo (y último antes de cambiar de tema) veremos como crear un cliente a partir de un web service dado.

Como reza la entrada del post, utilizaremos JAXWS para crear nuestro WS de ejemplo. Vamos a ello, viendo los pasos que tendremos que realizar:

  • Descargamos e instalamos JAXWS.
  • Creamos en eclipse un “Dinamic web project”.
  • Crearemos el wsdl que define nuestro WS.
  • Utilizaremos la herramienta wsimport para crear las clases de nuestro WS a partir del wsdl.
  • Implementaremos la lógica de los métodos que tendrá nuestro WS.
  • Añadiremos las anotaciones necesarias.
  • Cambiaremos el fichero web.xml para que se despliegue el WS.
  • Crearemos el fichero de configuración sun-jaxws.xml.
  • Empaquetamos en un war.
  • Instalamos en nuestro servidor de aplicaciones, y listo!

Utilizaremos Eclipse y la versión 2.1.2 de JAXWS para el desarrollo.

Descarga e instalación de JAXWS

Podéis ver los pasos en esta otra entrada.

Creación del proyecto en eclipse

Crearemos un “dinamic web project” en eclipse. Pinchando en “File / New… / Dinamic web project” y dejando las opciones por defecto en el wizard nos será suficiente.

Una vez creado incluiremos las librerías de JAXWS a nuestro proyecto. En el directorio donde hayamos instalado JAXWS encontraréis una carpeta lib. Copiar los jar de esa carpeta dentro de “WEB-INF/lib” de nuestro proyecto recién creado.

nuevo_proyecto

Creación del wsdl

Para nuestra aplicación de ejemplo, tendremos un WS que permite consultar los datos de un grupo musical a partir del nombre de una canción. Como no queremos liarlo demasiado, tendremos un único método que a partir del nombre de una canción, devolverá una lista con los nombres de los grupos a los que puede pertenecer (existen canciones con el mismo nombre que pertenecen a grupos diferentes), y el estilo de música que tocan cada uno.

En este tutorial tendremos que tener el wsdl del que partimos. No vamos a entrar a explicar como definir el wsdl a partir de un xml schema, porque sería un tema que daría para varios tutoriales. Pondremos el wsdl del ejemplo sin más:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:tns="http://example/music/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="music" targetNamespace="http://example/music/">
	<wsdl:types>
		<xsd:schema targetNamespace="http://example/music/">

			<xsd:complexType name="search">
				<xsd:sequence maxOccurs="1" minOccurs="1">
					<xsd:element name="songName" type="xsd:string"/>
				</xsd:sequence>
			</xsd:complexType>

			<xsd:complexType name="result">
				<xsd:sequence maxOccurs="1" minOccurs="1">
					<xsd:element name="groupName" type="xsd:string"/>
					<xsd:element name="musicType" type="xsd:string"/>
				</xsd:sequence>
			</xsd:complexType>

			<xsd:element name="searchSongRequest" type="tns:search"/>

			<xsd:element name="searchSongResponse">
				<xsd:complexType>
					<xsd:sequence minOccurs="0" maxOccurs="unbounded">
						<xsd:element name="result" type="tns:result"/>
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>

		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="SearchSongRequest">
		<wsdl:part name="parameters" element="tns:searchSongRequest">
		</wsdl:part>
	</wsdl:message>
	<wsdl:message name="SearchSongResponse">
		<wsdl:part name="parameters" element="tns:searchSongResponse">
		</wsdl:part>
	</wsdl:message>
	<wsdl:portType name="music">
		<wsdl:operation name="SearchSong">
			<wsdl:input message="tns:SearchSongRequest"/>
			<wsdl:output message="tns:SearchSongResponse"/>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="musicSOAP" type="tns:music">
		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
		<wsdl:operation name="SearchSong">
			<soap:operation soapAction="SearchSong" style="document"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="music">
		<wsdl:port name="musicSOAP" binding="tns:musicSOAP">
			<soap:address location="http://localhost:8080/musicapp/music"/>
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

Incluimos el wsdl en el proyecto. En nuestro caso lo hemos puesto en “WEB-INF/wsdl/music.wsdl”.

Creación de las clases del WS con la herramienta wsimport

Si no habéis incluido en el PATH de vuestro equipo el directorio bin de la instalación de JAXWS, hacerlo antes de seguir con el siguiente paso, ya que llamaremos al wsimport desde el directorio de nuestro proyecto, porque si no las rutas que hay que poner al lanzar el comando son muy largas.

Abriremos una consola, y nos situaremos en el directorio donde tenemos el wsdl. Desde ahí, ejecutaremos el siguiente comando:

wsimport -s [directorio_src] -verbose [ruta_wsdl]

wsimport

Si ahora volvemos al proyecto, y lo actualizamos, veremos que en src se han creado las clases que soportarán nuestro WS.

codigo_generado

Implementación de los métodos del WS

Entre el código que se ha generado, tenemos una interfaz (en nuestro caso “Music”) que es la que implementará el Web Service. Lo que tenemos que hacer ahora es crear una clase que implemente esta interfaz, y que contenga la lógica de negocio de nuestra aplicación. Para nuestro ejemplo, obviaremos la parte de consulta a base de datos, y pondremos un par de canciones “hardcodeadas” como ejemplo. Por último añadiremos las anotaciones que necesitamos para que JAXWS despliegue nuestro WS. Serán las siguientes:

	@WebService(
		endpointInterface = "[Nombre de la interfaz]",
		name = "[Nombre del WS]",
		portName = "[Nombre del portName que hemos puesto en el wsdl]",
		serviceName = "[Nombre del service que hemos puesto en el wsdl]",
		targetNamespace = "[Nombre del targetNamespace que hemos puesto en el wsdl]",
		wsdlLocation = "[Ubicación del wsdl dentro del proyecto]"
	)

En nuestro ejemplo, la clase quedará así:

package example.music;
import javax.jws.WebService;

	@WebService(
		endpointInterface = "example.music.Music",
		name = "music",
		portName = "musicSOAP",
		serviceName = "music",
		targetNamespace = "http://example/music/",
		wsdlLocation = "WEB-INF/wsdl/music.wsdl"
	)
	public class MusicImpl implements Music {

	public SearchSongResponse searchSong(Search parameters) {
	SearchSongResponse response = new SearchSongResponse();

	// Aquí estarían las consultas a base de datos, para recuperar los datos de los grupos.
	// Para simplificar están hardcodeados dos ejemplos (y perdón por los ejemplos, pero
	// no se me ocurría nada mejor :) 

	if (parameters.getSongName().equalsIgnoreCase("The number of the beast")) {
		Result result = new Result();
		result.setGroupName("Iron Maiden");
		result.setMusicType("Heavy");
		response.getResult().add(result);
	} else if (parameters.getSongName().equalsIgnoreCase("Nothing else matters")) {
		Result result1 = new Result();
		result1.setGroupName("Metallica");
		result1.setMusicType("Heavy");
		response.getResult().add(result1);
		Result result2 = new Result();
		result2.setGroupName("Alicia Keys");
		result2.setMusicType("Pop");
		response.getResult().add(result2);
	}

	return response;
}

}

Modificación del web.xml

Bueno, la mayor parte del trabajo ya está hecho. Nos queda tocar un par de ficheros de configuración, y por fin podremos desplegar nuestro WS. Primero modificaremos el “web.xml” que, como seguramente ya sabréis, se encuentra en la carpeta WEB-INF. Tenemos que indicar en el web.xml la clase que se encargará de atender las peticiones que lleguen al web service. Incluímos las siguientes líneas en el fichero:

	<listener>
		<listener-class>
			com.sun.xml.ws.transport.http.servlet.WSServletContextListener
		</listener-class>
	</listener>
	<servlet>
		<description>Music WS</description>
		<display-name>music</display-name>
		<servlet-name>music</servlet-name>
		<servlet-class>
			com.sun.xml.ws.transport.http.servlet.WSServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>music</servlet-name>
		<url-pattern>/music</url-pattern>
	</servlet-mapping>

Estamos definiendo la clase que implementará el servlet que es “com.sun.xml.ws.transport.http.servlet.WSServlet”. También indicamos el listener del servlet: “com.sun.xml.ws.transport.http.servlet.WSServletContextListener”.

Creación del fichero sun-jaxws.xml

Para que el ws se despliegue tenemos que crear este fichero. Irá en el mismo directorio que el web.xml, es decir en “WEB-INF”. El contenido del fichero de nuestro ejemplo es el siguiente:

	<?xml version="1.0" encoding="UTF-8"?>
	<endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'>
		<endpoint name='music'
			implementation='example.music.MusicImpl'
			url-pattern='/music'
		/>
	</endpoints>

De esta forma le estamos diciendo a JAXWS cual es la clase q implementa los métodos del WS.

Creación del fichero de despliegue (war)

Ya estamos listos para crear nuestro fichero de despliegue. Pinchamos con el botón derecho en nuestro proyecto, y seleccionamos export como “war file”. Seleccionamos la ruta y le damos nombre. Si abris el war con el winrar, veréis que la estructura de ficheros ha quedado así:

  • META-INF
    • MANIFEST.MF
  • WEB-INF
    • wsdl
      • music.wsdl
    • lib
      • activation.jar
      • FastInfoset.jar
      • http.jar
      • jaxb-api.jar
      • jaxb-impl.jar
      • jaxb-xjc.jar
      • jaxws-api.jar
      • jaxws-rt.jar
      • jaxws-tools.jar
      • jsr173_api.jar
      • jsr181-api.jar
      • jsr250-api.jar
      • resolver.jar
      • saaj-api.jar
      • saaj-impl.jar
      • sjsxp.jar
      • stax-ex.jar
      • streambuffer.jar
    • classes
      • example
        • music
          • Music.class
          • MusicImpl.class
          • Music_Service.class
          • ObjectFactory.class
          • package-info.class
          • Result.class
          • Search.class
          • SearchSongResponse.class
    • web.xml
    • sun-jaxws.xml

Instalación en el servidor de aplicaciones

En nuestro caso, como estamos utilizando jboss como servidor de aplicaciones, tenemos que copiar el war en la carpeta “[JBOSS_DIR]/server/default/deploy“. Una vez arrancado el servidor, si vamos a la URL “http://[server]:[port]/music/music” (en nuestro caso http://localhost:8080/music/music”) veremos si el servlet del WS se ha desplegado correctamente:

web_service_desplegado

Y hasta aquí este nuevo tutorial. Intentaremos que no pase tanto tiempo hasta el próximo que publiquemos.

Hasta la vista.