Trabajo Sobre Servicios Web

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 16

PRUEBA DE EVALUACIÓN

GRADO
CONTINUA APLICACIONES
DISTRIBUIDAS
WS | ENUNCIADO Y ORIENTACIONES PARA SU DESARROLLO

|Dr. Rafael Pastor Vargas y Dr. Andrés Duque Fernández


GRADO EN INGENIERÍA EN TECNOLOGÍAS DE LA
INFORMACIÓN

2019-2020

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA


APLICACIONES DISTRIBUIDAS

1.- OBJETIVOS

Esta práctica consiste en realizar un sistema distribuido basado en tecnología de servicios Web que permita
ejecutar un generador de señales y obtener los valores de tiempo y calculados por dicho generador.

Para ello se va a implementar la funcionalidad del servicio usando dos tecnologías específicas diferentes
basadas en la arquitectura SOA, y que están asociadas a las tecnologías de servicios Web:

- Servicios SOAP. Fue el primer estándar para publicar y consumir servicios Web. Es un estándar
basado en XML, y todos los mensajes involucrados en el proceso de
uso/búsqueda/consumo/gestión de procesos están basados en el estándar SOAP
(http://www.w3.org/TR/soap/). En el caso de Java, existe un API específico denominado JAX-WS
(http://jax-ws.java.net/) que permite procesar la información SOAP de los mensajes sin necesidad de
un directorio de servicios. Este API fue diseñado originalmente por Sun (ahora Oracle) e
implementada en su pila de servicios Web llamada Metro (http://metro.java.net/)
Para el proceso de desarrollo, se puede partir de varias premisas a la hora de desarrollar un servicio
pero la más habitual es partir de una clase/interface que implemente/defina las operaciones que
publicará el servicio Web (a esta clase/interface se le denomina POJO, Plain Old Java Object).
Posteriormente, se deben añadir “anotaciones” a la clase para indicar el comportamiento del servicio
Web. Las “anotaciones” permiten añadir información al código Java sin interferir en el propio código.
Esta información puede ser usada por otros elementos en el proceso de desarrollo de código java (el
propio compilador) para añadir “elementos ejecutables” (código adicional, ficheros XML, etc.) a la
aplicación. En el caso de JAX-WS, las anotaciones permiten definir, entre otras cosas, que interface/
clase define al servicio web (@WebService) o qué métodos conforman el conjunto de operaciones
del servicio (@WebMethod). Por tanto, una vez desarrollada la clase que implementan las
operaciones del servicio, se procederá a “anotar” la clase para indicar las propiedades del servicio
SOAP. Para una revisión completa de las anotaciones disponibles en JAX-WS, se debe consultar el
siguiente enlace:
https://www.ibm.com/support/knowledgecenter/SSAW57_9.0.5/
com.ibm.websphere.nd.multiplatform.doc/ae/rwbs_jaxwsannotations.html

El procedimiento de desarrollo es bastante directo, pero puede ocurrir que los parámetros de las
operaciones puedan ser elementos complejos, como clases definidas por el usuario. En este caso es
necesario definir un “mapeo” de las clases de usuario a un formato XML que se pueda usar desde
SOAP (recuerde que SOAP es básicamente XML). Para esto se emplea JAXB, que es un API de
procesamiento XML que permite hacer este trabajo automáticamente, mediante anotaciones. Para
más detalles, se debe leer el siguiente enlace:

http://ingmmurillo.blogspot.com.es/2010/08/utilizacion-de-jaxb-para-mapear-clases.html

Para la parte práctica, se va a definir una interface que define las operaciones del servicio JAX-WS
(como un objeto POJO):

package es.uned.scc.grados.appdist.trabajos.ws;

import javax.jws.WebParam;
import javax.jws.WebService;

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 2


|Dr. Rafael Pastor Vargas
import
es.uned.scc.grados.appdist.trabajos.signal.model.data.OperationInfo;
import es.uned.scc.grados.appdist.trabajos.signal.model.data.SignalData;
import
es.uned.scc.grados.appdist.trabajos.signal.model.data.SignalParameters;

@WebService
public interface SignalGeneratorWS {
public OperationInfo start();
public OperationInfo stop();
public OperationInfo isRunning();
public SignalData getSignalValue();
public SignalParameters getSignalParameters();
public void setSignalParameters(
@WebParam(name="signal_parameters")SignalParameters signal_parameters);

Se puede observar que la interface define el servicio Web y dispone de una anotación especial para
nombrar el argumento de la operación setSignalParameters().
Las clases OperationInfo, SignalData y SignalParameters se proporcionan en el espacio
virtual del curso, y están implementadas en el fichero SignalModel.jar. Así mismo, en el propio curso
virtual se muestra el código asociado a dichas clases para comprender su funcionamiento en el
posterior uso de las mismas durante el trabajo. Importante: El código de estas clases ha de
utilizarse importando el archivo JAR directamente, nunca el código fuente. Asímismo, no se
han de añadir dichas clases al código presentado por el estudiante.

- Servicio REST. Al contrario que SOAP, REST (REpresentational State Transfer) no es un protocolo,
sino una forma más simple que SOAP para crear servicios Web (más bien, se puede decir que es
una arquitectura de desarrollo). Fue ideada por el Dr. Roy Fielding en su tesis doctoral, y
básicamente consiste en emplear el modelo de comunicación web tradicional (el protocolo HTTP)
para identificar/consumir servicios Web. Un servicio web creado sobre los principios de REST se
denomina servicio web RESTful. Igual que antes, para el caso de Java, existe un API de referencia
para la implementación de dichos servicios: JAX-RS (http://jcp.org/en/jsr/detail?id=311). Existen
varias implementaciones de este API, por ejemplo el contenedor Jersey (http://jersey.java.net/) entre
otros. Se recomienda leer los siguientes enlaces para comprender los fundamentos de REST:

http://www.infoq.com/articles/rest-introduction
http://eamodeorubio.wordpress.com/2010/07/26/servicios-web-2-%C2%BFque-es-rest/
http://www.fing.edu.uy/inco/grupos/lins/seminario/2010/Introduccion_WS-REST.pdf

Básicamente REST (http://www.dosideas.com/noticias/java/314-introduccion-a-los-servicios-web-


restful.html) sigue cuatro principios de diseño fundamentales:
- Se emplean los métodos HTTP de manera explícita para realizar las operaciones del servicio,
que manejan recursos:
o POST para crear un recurso en el servicio
o GET para obtener un recurso
o PUT para cambiar el estado de un recurso o actualizarlo
o DELETE para borrar un recurso
- No mantiene el estado de las peticiones
- Expone las operaciones del servicio como URI’s (modelo general de identificación de recursos,
el cual la especificación de URL es la más conocida y usada).

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 3


APLICACIONES DISTRIBUIDAS

- Permite la transferencia de cualquier tipo de información codificada en varios formatos: texto,


XML, JavaScript Object Notation (JSON), etc.

Al igual que JAX-WS, JAX-RS dispone de sus propias anotaciones para definir el contrato del
servicio y las operaciones/recursos que ofrece. Para más detalles, consultar el enlace de la
implementación de referencia Jersey: http://jersey.java.net/nonav/documentation/latest/jax-rs.html,
donde se explican todas las anotaciones del estándar con ejemplos de su uso.

Las anotaciones más importantes son:


o @Path, define el URI relativo de acceso al servicio/operación
o @Method, define el método HTTP de acceso a la operación
o @Produces, define el formato de información que el servicio/operación enviará en la llamada
al método HTTP correspondiente (texto, JSON, XML, etc.)
o @Consumes, define el formato de información que el servicio/operación espera en los
parámetros de la invocación al método HTTP correspondiente (texto, JSON, XML, etc.).

Para esta parte de la práctica, se va a definir una interface que define las operaciones del servicio
JAX-RS (como un objeto POJO), a cuya implementación se le deberán añadir las anotaciones JAX-
RS correspondientes:

package es.uned.scc.grados.appdist.trabajos.ws;

import es.uned.scc.grados.appdist.trabajos.signal.model.data.SignalData;
import
es.uned.scc.grados.appdist.trabajos.signal.model.data.SignalParameters;
import
es.uned.scc.grados.appdist.trabajos.signal.model.data.OperationInfo;

public interface RESTSignalGenerator {


public OperationInfo start();
public OperationInfo stop();
public OperationInfo isRunning();
public SignalData getSignalValue();
public SignalParameters getSignalParameters();
public void setSignalParameters(SignalParameters
signal_parameters);
}

Como se ha comentado antes, las clases OperationInfo, SignalData y SignalParameters


se proporcionan en el espacio virtual del curso, y están implementadas en el fichero SignalModel.jar.
Así mismo, en el propio curso virtual se muestra el código asociado a dichas clases para comprender
su funcionamiento en el posterior uso de las mismas durante el trabajo.

Se deben desarrollar los siguientes elementos:


1) Implementación de la interface del servicio SOAP (JAX-WS) definida anteriormente (se debe
mantener tanto el nombre, como el paquete donde está definida dicha interface). La clase que
implementa dicha interface se debe denominar SignalGeneratorWSImpl y debe estar incluida en
el paquete es.uned.scc.grados.appdist.trabajos.ws. La clase que implementa el servicio
SOAP debe emplear la clase SignalGeneratorThread (definida en el paquete
es.uned.scc.grados.appdist.trabajos.signal.model) para la gestión de la ejecución

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 4


|Dr. Rafael Pastor Vargas
parada del generador aleatorio. Véase el apartado de consideraciones de desarrollo para conocer
cómo se debe realizar la implementación del objeto de servicio SOAP.
2) Desarrollo de un servidor que actúe como contenedor del servicio SOAP y exponga dicho servicio
para ser consumido por clientes. La clase que implementa dicho servidor se debe llamar WSServer
y debe estar ubicada en el paquete es.uned.scc.grados.appdist.trabajos.ws.server.
Véase el apartado de consideraciones de desarrollo para conocer cómo se debe realizar la
implementación del servidor SOAP.
3) Desarrollo de un cliente que consuma los servicios definidos por la clase que implementa el servicio
y que estará disponible a través del servidor del punto 2. La clase se deberá denominar WSClient y
deberá estar definida en el paquete es.uned.scc.grados.appdist.trabajos.ws.soap.
Véase el apartado de consideraciones de desarrollo para obtener detalles sobre la generación del
código que representa al servicio Web, y su utilización en la clase cliente.
4) Implementación de la interface del servicio REST definida anteriormente (se debe mantener tanto el
nombre, como el paquete donde está definida dicha interface). La clase que implementa dicha
interface se debe denominar RESTSignalGeneratorWSImpl y debe estar incluida en el paquete
es.uned.scc.grados.appdist.trabajos.ws. La clase que implementa el servicio REST
debe emplear la clase SignalGeneratorThread (definida en el paquete
es.uned.scc.grados.appdist.trabajos.signal.model) para la gestión de la ejecución
parada del generador aleatorio. Véase el apartado de consideraciones de desarrollo para conocer
cómo se debe realizar la implementación del objeto de servicio REST.
5) Desarrollo de un servidor que actúe como contenedor del servicio REST y exponga dicho servicio
para ser consumido por clientes. La clase que implementa dicho servidor se debe llamar y
RESTWSServer debe estar ubicada en el paquete
es.uned.scc.grados.appdist.trabajos.ws.server. Véase el apartado de
consideraciones de desarrollo para conocer cómo se debe realizar la implementación del servidor
REST.
6) Desarrollo de un cliente que consuma los servicios definidos por la clase que implementa el servicio
REST y que estará disponible a través del servidor del punto 5. La clase se deberá denominar
RESTClient y deberá estar definida en el paquete
es.uned.scc.appdist.trabajos.rest.client. Véase el apartado de consideraciones de
desarrollo para obtener detalles sobre el uso del protocolo HTTP para el consumo de los
recursos/operaciones del servicio REST.

2.- CONSIDERACIONES DE DESARROLLO

Para el desarrollo de esta práctica, se va a emplear Apache CXF (http://cxf.apache.org/) ya que proporciona
un entorno de ejecución e implementaciones de las APIs, tanto de JAX-WS como de JAX-RS. En particular,
se recomienda que se lean los ejemplos que están ubicados en la documentación del producto:
1) Escribir/Publicar/Consumir un servicio JAX-WS con CXF (http://cxf.apache.org/docs/a-simple-jax-ws-
service.html)
2) Conceptos básicos de JAX-RS (http://cxf.apache.org/docs/jax-rs-basics.html)

Otros enlaces interesantes que se deben revisar, son los siguientes:

http://www.javamexico.org/blogs/mariogarcia/servicios_web_con_apache_cxf_utilizando_jaxws_y_jaxrs

http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=jaxwscxf (incluye la configuración de CXF


en Eclipse y como crear clientes de servicios web a través de su WDSL).

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 5


APLICACIONES DISTRIBUIDAS

Es importante descargarse la distribución CXF (la versión empleada es la 3.3.3, pero debería funcionar con
cualquiera superior o de la misma rama, 3.x) desde la web de cxf: http://cxf.apache.org/download.html. Para
la compilación/ejecución de los elementos de esta parte, hay que añadir los ficheros jar correspondientes a
esta distribución (o configurar el IDE de manera adecuada).

2.1 Detalles de desarrollo en la implementación del objeto de servicio


SOAP.

Como se ha comentado anteriormente, se debe usar la clase SignalGeneratorThread para desarrollar el


objeto que implementa el servicio SOAP (JAX-WS). Esta clase y la clase SignalGenerator asociada
están incluidas en el fichero SignalModel.jar. Se proporciona en el entorno virtual el código de ambas clases
(SignalGeneratorThread, SignalGenerator).

Esta clase proporciona la gestión de ejecución de la tarea asociada al generador y permite obtener la
referencia al objeto de la clase SignalGenerator, que proporciona los métodos de acceso al valor de la
señal (SignalData) y los parámetros de la misma ( SignalParameters). Para obtener el valor de la señal
se puede usar el siguiente grupo de sentencias ( sgThread es una instancia de la clase
SignalGeneratorThread):

SignalGenerator sg = this.sgThread.getSignalgenerator();
sd = new SignalData(sg.getTime(), sg.getOutput());

Para gestionar la lectura/escritura de los parámetros del generador de señales se pueden usar las siguientes
sentencias:
// Lectura
SignalGenerator sg = this.sgThread.getSignalgenerator();
SignalParameters sp = new SignalParameters(sg.getType(), sg.getAmplitude(), sg.getFrequency());
// Escritura
SignalGenerator sg = this.sgThread.getSignalgenerator();
sg.setSignalType(sp.getType());
sg.setAmplitude(sp.getAmplitude());
sg.setFrequency(sp.getFrequency());

La clase que implementa el servicio se denomina SignalGeneratorWSImpl, y debe tener las anotaciones
necesarias para marcar la clase como un servicio Web. Al implementar la interface correspondiente (que ya
está anotada como @WebService) automáticamente se define como servicio Web, pero es necesario añadir
el código asociado para identificar el punto de publicación del servicio Web (que permite conocer su WDSL,
y el punto de invocación de las operaciones por parte del cliente). De nuevo, es necesario usar las
anotaciones de JAX-WS para indicar esto. Las anotaciones permiten la herencia, así que podemos “redefinir”
la anotación e indicar un conjunto de propiedades de la anotación. En este caso, se necesita indicar que
interface define el conjunto de operaciones del servicio (propiedad endpointInterface) y el nombre a
través del cual se accederá al servicio ( serviceName). Por tanto, se deberá añadir la anotación a la clase
SignalGeneratorWSImpl, quedando la definición de la clase así:

@WebService(endpointInterface =
"es.uned.scc.grados.appdist.trabajos.ws.SignalGeneratorWS",
serviceName = "SignalGenerator")
public class SignalGeneratorWSImpl implements SignalGeneratorWS {

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 6


|Dr. Rafael Pastor Vargas
2.2 Detalles de desarrollo en la implementación del servidor SOAP.

En el caso del servidor SOAP, es muy sencillo usar las funcionalidades de CXF para que ejecute un
contenedor de servicios JAX-WS, y publique en una URL conocida el servicio. El código necesario (que se
puede encontrar en la documentación de CXF) es el siguiente.

SignalGeneratorWSImpl implementor = new SignalGeneratorWSImpl(sampleTime);


String address = "http://localhost:9000/SignalGenerator";
Endpoint.publish(address, implementor);

Se puede ver que solo se necesita indicar la dirección de publicación (address) y la clase que implementa el
servicio SOAP (se le pasa al constructor de la clase el tiempo asociado a la tarea definida en la clase
SignalGeneratorThread, pero el estudiante puede desarrollarlo de otra forma). El parámetro sampleTime
define el tiempo de actualización de la señal generada por la tarea (salida y tiempo), y debe usarse un valor
adecuado (se recomienda un valor de 0.01 segundos). Es importante que el servidor SOAP debe quedar
ejecutándose. Para ello se puede usar un mecanismo de entrada/salida que compruebe si el servidor debe
parar o no. Un ejemplo de mecanismo basado en petición de una cadena de texto, podría implementarse con
la siguiente función:
public void waitForKey(){
boolean waiting = true;
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter 'yes' to exit...");
String c;
while (waiting){
try {
c = in.readLine();
} catch (IOException e) {
e.printStackTrace();
c = "Yes";
}
if (c.equalsIgnoreCase("yes")){
waiting = false;
} else {
System.out.println("Entered '" + c + "' string (wrong!!!)\nPress 'yes' to exit...");
}
}
}

Al ejecutar el servidor SOAP, deberían mostrarse unas líneas parecidas a estas:


Starting Server
28-nov-2012 21:23:55
org.apache.cxf.service.factory.ReflectionServiceFactoryBean
buildServiceFromClass
INFO: Creating Service
{http://ws.trabajos.appdist.grados.scc.uned.es/}SignalGenerator from class
es.uned.scc.grados.appdist.trabajos.ws.SignalGeneratorWS
28-nov-2012 21:23:55 org.apache.cxf.endpoint.ServerImpl initDestination
INFO: Setting the server's publish address to be
http://localhost:9000/SignalGenerator
28-nov-2012 21:23:56 org.eclipse.jetty.server.Server doStart
INFO: jetty-7.5.4.v20111024
28-nov-2012 21:23:56 org.eclipse.jetty.server.AbstractConnector doStart
INFO: Started SelectChannelConnector@localhost:9000 STARTING
28-nov-2012 21:23:56 org.eclipse.jetty.server.handler.ContextHandler
startContext
INFO: started o.e.j.s.h.ContextHandler{,null}
Server ready...
Enter 'yes' to exit...

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 7


APLICACIONES DISTRIBUIDAS

Una vez que el servidor SOAP está ejecutándose, se debería poder visualizar el documento WDSL de
definición del servicio en el siguiente enlace: http://localhost:9000/SignalGenerator?wsdl

En la siguiente figura se puede ver el contenido del fichero WDSL.

2.3 Detalles de desarrollo en la implementación del cliente SOAP.

El primer paso para desarrollar el cliente SOAP es obtener la “representación” del servicio como clases Java.
Para ello, se debe usar el enlace de acceso al fichero WDSL y usar alguno de los siguientes mecanismos:
1) Usar los asistentes del IDE de desarrollo para generar las clases que representan al servicio. Puede
consultar los siguientes enlaces para ver como se hace en Eclipse
(http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.jst.ws.cxf.doc.user%2Ftasks
%2Fcreate_client.html) o Netbeans (http://netbeans.org/kb/docs/websvc/jax-ws.html, sección
Consuming the Web Service, Client 1: Java Class in Java SE Application).
2) Usando la utilidad wdsl2java que viene con la distribución de CXF. Se pueden ver las opciones de
las que dispone la utilidad en el siguiente enlace: http://cxf.apache.org/docs/wsdl-to-java.html. Este
comando generará las clases Java necesarias (que representan al servicio Web) que se deben
incorporar al proyecto en el que se defina el cliente (importándolas o copiándolas directamente en el
directorio donde se ubiquen las fuentes dl proyecto).

Se recomienda el uso de la primera opción, ya que genera las clases dentro del propio proyecto. Además, el
cliente SOAP debería implementarse en un proyecto nuevo, ya que al generar las clases que representan al
servicio es posible que se “sobre-escriban” las originales (se puede modificar el mapeo de los espacios de
nombres, pero es más sencillo aislar la generación de las clases en un proyecto nuevo). Una vez que se han
generado las clases, para poder usar el servicio web se debe usar la clase Proxy generada, que se debería
llamar SignalGeneratorWSProxy. Simplemente se debe instanciar y llamar al método adecuado.

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 8


|Dr. Rafael Pastor Vargas

// Get service reference


SignalGeneratorWS service = new SignalGeneratorWSProxy();
OperationInfo info = service.start();

Para probar el funcionamiento del servidor SOAP, se debe emplear la clase auxiliar ClientGUI
incorporándola en el código del cliente SOAP (mediante las clases que sean necesarias). Para su correcto
funcionamiento será necesario importar las librerías “Jfreechart” y “Jcommon”, cuyos JAR también se
proporcionan en el espacio virtual del curso.

La clase auxiliar ClientGUI proporciona una interface gráfica (GUI) que permite comprobar el
funcionamiento del servidor. Para emplear esta función es necesario que la clase cliente (o una auxiliar)
implemente la interface ClientPlot:
package es.uned.scc.grados.appdist.trabajos.plot;

import es.uned.scc.grados.appdist.trabajos.signal.model.data.SignalData;
import es.uned.scc.grados.appdist.trabajos.signal.model.data.SignalParameters;

public interface ClientPlot {


boolean start();
boolean stop();
SignalData getSignalValue();
public SignalParameters getSignalParameters();
public void setSignalParameters(SignalParameters sp);
}

De esta forma, la instancia de la clase que representa la GUI podrá invocar a las funciones de dicha interface
que, a su vez, estarán implementadas en la clase que emplea el cliente SOAP. La forma más sencilla de
desarrollar este mecanismo es asociar a una clase auxiliar denominada PlottingFrame la implementación
de la interface y usar las llamadas correspondientes dentro del código de cada función de la interface. Esta
sería la definición de dicha clase (sin la implementación de las funciones de interface, que le corresponde
realizar al estudiante).
public class PlottingFrame implements ClientPlot{

SignalGeneratorWS wsClient = null;


ClientGUI frame = null;

public PlottingFrame(SignalGeneratorWS client) {


wsClient = client;
frame = new ClientGUI(this);
}

public void show() {


frame.getFrame().setVisible(true);
}

Para visualizar la interface, simplemente se debe crear una instancia de la clase PlottingFrame y mostrar
la interface, una vez creado el proxy de acceso al servicio SOAP
if (sgClient!=null){
PlottingFrame window = new PlottingFrame(sgClient);
window.show();
}

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 9


APLICACIONES DISTRIBUIDAS

2.4 Detalles de desarrollo en la implementación del objeto de servicio


REST.

Como se ha comentado anteriormente, se debe usar la clase SignalGeneratorThread para desarrollar el


objeto que implementa el servicio REST (JAX-RS). Esta clase y la clase SignalGenerator asociada están
incluidas en el fichero SignalModel.jar. Se proporciona en el entorno virtual el código de ambas clases
(SignalGeneratorThread, SignalGenerator).

La clase que implementa el servicio se denomina RESTSignalGeneratorWSImpl, y debe tener las


anotaciones necesarias para marcar la clase como un servicio REST. En este caso, la implementación
asociada a la clase RESTSignalGeneratorWSImpl, debe definir las funciones de la interface y por tanto
hay que anotar las operaciones como URI’s usando la anotación @Path, definir que método se usará para
invocar la operación (@GET, @POST, @PUT, @DELETE) y que información consumirá/producirá
(@Consumes, @Produces). En la siguiente tabla se muestra cuales son los valores de las anotaciones para
las operaciones.

Opración/Recurso @Path Método @Consumes @Produces


HTTP
OperationInfo start(); @Path("start") @Get No es necesario @Produces({"text/
indicarlo
xml"})
OperationInfo stop(); @Path("stop") @Get No es necesario @Produces({"text/
indicarlo
xml"})
OperationInfo isRunning(); @Path("isrunning @Get No es necesario @Produces({"text/
indicarlo
") xml"})
SignalData @Path("get") @Get No es necesario @Produces({"text/
getSignalValue(); indicarlo
xml"})
SignalParameters @Path("getParams @Get No es necesario @Produces({"text/
getSignalParameters(); indicarlo
") xml"})
void @Path("setParams @Post @Consumes No es necesario indicarlo
setSignalParameters(SignalP
") ({"text/
arameters
signal_parameters); xml"})

Finalmente, es necesario anotar el @Path asociado al propio servicio (todos los @Path definidos en las
operaciones son relativos al @Path del servicio). Para ello se debe añadir al principio de la definición de la
clase, la siguiente anotación:

@Path("SignalGenerator")
public class RESTSignalGeneratorWSImpl implements RESTSignalGenerator{

De esta forma, para invocar la operación start() del servicio REST se deberá usar el siguiente URI relativo:
“SignalGenerator/start”. En la siguiente sección, una vez desarrollado el servidor, se verán ejemplos de URI’s
absolutas para el uso del servicio REST.

2.5 Detalles de desarrollo en la implementación del servidor REST.

La creación del servidor REST con CXF es muy sencilla, y consiste en cuatro pasos sencillos, que se
comentan a continuación:

// Create the JAX-RS Server with CXF

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 10


|Dr. Rafael Pastor Vargas
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
// Set REST implementor class
sf.setResourceClasses(RESTSignalGeneratorWSImpl.class);
// Create absolute Path
sf.setAddress("http://localhost:9002/");
// Start JAX-RS Server
sf.create();

Por tanto, solo es necesario codificar la clase RESTWSServer con un método main() que contenga las
líneas anteriores. Al arrancar el servidor REST deberían mostrarse las líneas de información sobre el
servidor, generadas por CXF (Jetty):

29-nov-2012 16:13:28 org.apache.cxf.endpoint.ServerImpl initDestination


INFO: Setting the server's publish address to be http://localhost:9002/
29-nov-2012 16:13:28 org.eclipse.jetty.server.Server doStart
INFO: jetty-7.5.4.v20111024
29-nov-2012 16:13:28 org.eclipse.jetty.server.AbstractConnector doStart
INFO: Started SelectChannelConnector@localhost:9002 STARTING
29-nov-2012 16:13:28 org.eclipse.jetty.server.handler.ContextHandler
startContext
INFO: started o.e.j.s.h.ContextHandler{,null}

Una vez que se ejecute el servidor REST, se pueden invocar las operaciones del servicio usando cualquier
cliente HTTP (por ejemplo, un navegador web). Una sesión de trabajo típica sería:
1) Arrancar el generador de señales: http://localhost:9002/SignalGenerator/start

2) Obtener el valor de la señal: http://localhost:9002/SignalGenerator/get

3) Comprobar si el generador está ejecutándose: http://localhost:9002/SignalGenerator/isrunning

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 11


APLICACIONES DISTRIBUIDAS

4) Parar el generador de señales: http://localhost:9002/SignalGenerator/stop

5) Comprobar el estado del generador: http://localhost:9002/SignalGenerator/isrunning

2.6 Detalles de desarrollo en la implementación del cliente REST.

Cualquier servicio REST se puede consumir usando un cliente Web, esto es, un cliente que permite realizar
operaciones HTTP. CXF dispone de una clase denominada WebClient, que permite al desarrollador no
tener que ocuparse de los detalles de implementación del protocolo HTTP y le facilita el desarrollo de
clientes REST. La clase WebClient está definida en el paquete org.apache.cxf.jaxrs.client. y se
pueden ver un ejemplo de uso en el siguiente enlace: http://cxf.apache.org/docs/jax-rs-client-api.html
(sección CXF WebClient API).

Para obtener los valores de los resultados complejos (se entienden por complejos, las clases Java definidas
por el desarrollador distintas a los tipos primitivos de java) de las invocaciones a los métodos REST, es
necesario usar la clase Response (ubicada en el paquete javax.ws.rs.core.Response). Esta clase es
la responsable de “representar” el resultado obtenido de una invocación REST como una entidad XML (que
es lo que envía el método de servicio, al ser anotado para producir XML). Una vez que se dispone de esa
entidad XML, se puede convertir a un objeto de la clase correspondiente haciendo una conversión directa
(cast). Para usar ambas clases ( WebClient y Response) es necesario primero crear el objeto de la clase
WebClient:

WebClient client = WebClient.create(REST_SERVICE);

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 12


|Dr. Rafael Pastor Vargas

donde REST_SERVICE representa el punto de publicación del servicio


(http://localhost:9002/SignalGenerator).

Una vez hecho esto (en el constructor de la clase cliente o en la propia definición de los atributos de dicha
clase), se deben implementar los diferentes métodos que se invocarán desde la interface GUI
proprocionada. A modo de ejemplo, se muestra el código asociado a una de esas funciones y como se
realiza la invocación REST y la obtención del dato de la invocación con el objeto OperationInfo
(proporcionado en el curso virtual).

public boolean startGenerator(){


// Set relative path to REST method
// REST_PATH_START = "start";
client.replacePath(REST_PATH_START);
// Set type of data received
client.type("application/xml");
// Call the REST method
Response r = client.get();
// Get the XML entity in response and cast to class
OperationInfo i = r.readEntity(OperationInfo.class);
System.out.println("Response: " + i.getMessage());
return i.isOk();
}

Como se puede apreciar en el código anterior, la clase Response se emplea para obtener la respuesta del
servicio REST y posteriormente, obtener un objeto Java que representa a la llamada ( OperationInfo en
este caso).

La estructura del código para el resto de métodos del cliente son similares, y se debe modificar lo necesario
adaptándolo a la estructura del método REST del servidor (la clase esperada y el @PATH del método,
básicamente).

Para probar el funcionamiento del servidor REST, de nuevo, se debe emplear la clase auxiliar ClientGUI
incorporándola en el código del cliente REST (mediante las clases que sean necesarias). Recuérdese que,
para emplear esta función, es necesario que la clase cliente (o una auxiliar) implemente la interface
ClientPlot. El procedimiento es similar al desarrollado en apartados anteriores.

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 13


APLICACIONES DISTRIBUIDAS

3.- PRUEBAS

Una vez desarrolladas las clases necesarias, se debe probar la ejecución de los servidores SOAP y REST,
usando los desarrollos de los clientes SOAP y REST. A continuación se muestra el ejemplo desarrollado por
el equipo docente, que se encuentra disponible en el entorno virtual.

En primer lugar se debe ejecutar el servidor, tal y como se muestra en la siguiente figura.

Ejecución de los servidores SOAP y REST

Si todo es correcto, debería mostrar un mensaje indicando que está disponible para gestionar conexiones de
clientes (tal y como aparece en la figura anterior). En este punto, se debe comprobar que los servidores
están ofreciendo los respectivos servicios, tomando sendos pantallazos de los
1) SOAP Server. Pantallazo mostrado el fichero WSDL del servicio SOAP generado automáticamente
(http://localhost:9000/SignalGenerator?wsdl)
2) REST Server. Pantallazos de una sesión de trabajo (descritos al final del apartado 2.5).

A continuación se deben ejecutar los clientes, tal y como se muestra en la siguiente figura.

Figura 3. Ejecución de los clientes SOAP y REST.

Si todo es correcto, debería mostrar el interface gráfico (GUI) desarrollado por el equipo docente (en ambos
caos) y que permite probar la funcionalidad pedida. Se puede ver el aspecto inicial en la figura 4.

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 14


|Dr. Rafael Pastor Vargas

Figura 4. Aspecto inicial del GUI de prueba.

Para arrancar el generador de señales (es decir, llamar al método start() del objeto remoto) se debe pulsar el
botón correspondiente. En la figura 5 se muestra una ejecución de una señal sinusoidal de frecuencia 0.05
Hz y amplitud 10.

Figura 5. Ejemplo de ejecución del cliente.


Pruebas a desarrollar (con ambos clientes):
- Arrancar el cliente, usando el botón Start.
- Observar la representación de la señal. Si hay algo que no parece correcto, indicarlo y si es posible,
dar una explicación.
- Tomar un pantallazo de la GUI cuando el tiempo llegue al minuto (se deberá incluir en la
documentación)
- Cambiar la frecuencia de la señal a 0.1 (usando el botón Apply)
- Observar la representación de la señal. Si hay algo que no parece correcto, indicarlo y si es posible,
dar una explicación.
- Tomar un pantallazo de la GUI cuando el tiempo llegue a los dos minutos (se deberá incluir en la
documentación)
- Cambiar la amplitud de la señal a 5 (usando el botón Apply)
- Tomar un pantallazo de la GUI cuando el tiempo llegue a los dos minutos y medio (se deberá incluir
en la documentación)
- Cambiar el tipo de señal a triangular (usando el botón Apply)
- Tomar un pantallazo de la GUI cuando el tiempo llegue a los tres minutos (se deberá incluir en la
documentación)
- Cambiar el tipo de señal a cuadrada (usando el botón Apply)
- Tomar un pantallazo de la GUI cuando el tiempo llegue a los tres minutos y medio (se deberá incluir
en la documentación)
- Parar el generador, usando el botón Stop.
- Cambiar el tipo de señal a sinusoidal, con una amplitud de 1 y una frecuencia de 10;

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 15


APLICACIONES DISTRIBUIDAS

- Arrancar el generador, usando el botón Start.


- Comprobar el efecto del slider inferior del GUI modificando los valores y utilizando los valores
máximo (1 segundo), mínimo (0.1 segundos) y medio (aproximadamente 0.5 segundos). Intentar
explicar cuál es el efecto que produce en la representación de la onda y porque ocurre.
- Parar el generador, usando el botón Stop.

4.- INFORME

Cómo informe del trabajo se debe entregar un fichero zip en la pestaña de Evaluación del curso virtual en
aLF. El fichero debe llamarse “Nombre_Alumno”.zip, donde Nombre_Alumno debe contener el nombre
completo del estudiante, sin usar acentos y usando guiones bajos (_) en vez de espacios en blanco entre
nombre y apellidos.

En este fichero deben aparecer los siguientes ficheros/subdirectorios:

- Las clases compiladas y empaquetadas en tres ficheros jar:


o WS_Services.jar. Debe contener las clases correspondientes a los servidores SOAP y
REST.
o WS_SOAP_Client.jar. Debe contener las clases correspondientes al cliente SOAP.
o WS_REST_Client.jar. Debe contener las clases correspondientes al cliente REST.

Deben estar situados en el directorio lib del fichero zip. Se deben incluir en dicho directorio, todos
los ficheros jar que se empleen en la ejecución de los servidores/clientes SOAP y REST. En el caso
de las librerías CXF, no es necesario incluirlas (debido al gran tamaño que tienen), pero en los
scripts de ejecución se deberán referenciar en el classpath con el path .\lib\apache-cxf-3.3.3\lib. De
esta forma, para que el equipo docente pueda probar la solución del alumno, solo deberá copiar
esas librerías a esa localización.

- Los ficheros fuentes de las clases generadas situados en el directorio sources, manteniendo la
estructura de paquetes (esto es, los subdirectorios asociados), pero sin incluir ficheros relativos al
IDE utilizado para el desarrollo, es decir, sólo se han de incluir las clases implementadas por el
estudiante.

- Documento en formato texto (puede ser word, txt o pdf) con la arquitectura desarrollada y
comentarios sobre los problemas encontrados durante el desarrollo y prueba de los
servidores/clientes SOAP/REST. Además se deben incluir los pantallazos/comentarios pedidos en la
parte de pruebas. Este documento debe estar situado en el directorio doc del fichero zip.

- Guiones de trabajo (scripts) para poder ejecutar las aplicaciones cliente y servidor, tanto de SOAP
como REST (usando los ficheros jar del directorio lib). Estos scripts deben estar situados en la raíz
del fichero comprimido y deben considerar los paths relativos al subdirectorio lib al ejecutar dichos
scripts (tenga en cuenta además, el path relativo a las librerías CXF y adicionales).

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA 16

También podría gustarte