Introducción a los servicios web - marce.commarce.com/systems/servicios_web.pdf · import...

19
Introducción a los servicios web © 2012 Marcelino Rodríguez Suárez | http://www.marce.com Un servicio web publica su descripción en un documento XML en lenguaje WSDL. De esta forma es conocido y utilizado por sus clientes. Un cliente de un servicio web crea un proxy para llamar a los métodos que el servicio proporciona. Durante la comunicación las API’s JAX-WS (Java API for XML Web Services) y JAXB (Java Architecture for XML Binding), se encargan de las tareas de bajo nivel (generación y análisis de mensajes SOAP). El programador se ocupa exclusivamente de escribir la clase del servicio web y la clase cliente. En el desarrollo del servicio web, no se usará un IDE en particular. Sólo debe tener instalado el JDK6 o posterior y un servidor de aplicaciones como WebSphere Application Server. Creación del servicio web El servicio web que se ha implementado es bastante sencillo. En el apéndice, podrá observar el archivo fuente completo de la interfaz Simple, de la clase SimpleService que la implementa y de la clase de apoyo UserInfo. Las clases son almacenadas en: servicios_web/simple/ WEB-INF/ classes/com/marce/ws. Observe que, excepto la anotación @WebService, es una clase normal del paquete com.marce.ws. Las anotaciones son procesadas por la herramienta apt (annotation processing tool) del JDK. La estructura de directorios para almacenar los componentes del servicio y del cliente, de acuerdo con la utilizada para las aplicaciones web, es la que sigue:

Transcript of Introducción a los servicios web - marce.commarce.com/systems/servicios_web.pdf · import...

Introducción a los servicios web © 2012 Marcelino Rodríguez Suárez | http://www.marce.com

Un servicio web publica su descripción en un documento XML en lenguaje WSDL. De esta forma es conocido y utilizado por sus clientes.

Un cliente de un servicio web crea un proxy para llamar a los métodos que el servicio proporciona. Durante la comunicación

las API’s JAX-WS (Java API for XML Web Services) y JAXB (Java Architecture for XML Binding), se encargan de las tareas de

bajo nivel (generación y análisis de mensajes SOAP). El

programador se ocupa exclusivamente de escribir la clase del

servicio web y la clase cliente.

En el desarrollo del servicio web, no se usará un IDE en particular. Sólo debe tener instalado el JDK6 o posterior y un servidor de aplicaciones como WebSphere Application Server.

Creación del servicio web

El servicio web que se ha implementado es bastante

sencillo. En el apéndice, podrá observar el archivo fuente

completo de la interfaz Simple, de la clase SimpleService que la implementa y de la clase de apoyo UserInfo. Las clases son

almacenadas en:

servicios_web/simple/ WEB-INF/ classes/com/marce/ws. Observe que, excepto la anotación @WebService, es una clase

normal del paquete com.marce.ws. Las anotaciones son procesadas

por la herramienta apt (annotation processing tool) del JDK. La estructura de directorios para almacenar los componentes

del servicio y del cliente, de acuerdo con la utilizada para las

aplicaciones web, es la que sigue:

Compilación del servicio web

Para compilar el servicio, se abre la consola (en System i:

qsh o qp2term) y se va a la carpeta clases del servicio

(servicios_web/simple/WEB-INF/classes). Allí se ejecuta:

>javac com/marce/ws/*.java

Empaquetado del servicio web

El servicio se empaqueta en el archivo simple.war, para su

posterior despliegue.

Con este objetivo se va a la carpeta del servicio

(servicios_web/simple) y se ejecuta el comando jar así:

>jar cvf simple.war *

Despliegue del servicio web en el servidor de aplicaciones

Con el servidor de aplicaciones arrancado, se despliega el

servicio web empaquetado, simple.war. Esto genera, entre otros,

el archivo de despliegue web.xml.

Prueba del servicio web

El servicio web ya está preparado para ser accedido por un

cliente que lo descubra. Para probar su funcionamiento se puede

solicitar desde un navegador que sea mostrada su descripción:

http://systemi.marce.com:8080/simple/Simple?wsdl

Creación del cliente del servicio web

Después de finalizada la construcción del servicio web, se

continúa con la creación del cliente que accede a su

funcionalidad.

Se consideran los casos en que el cliente del servicio web

sea una aplicación de consola, windows o web. Sus archivos

fuente son respectivamente, SimpleClientConsole.java,

SimpleClientWindow.java e index.jsp. En el apéndice, podrá

observar su contenido. Las clases se almacenan en:

servicios_web/simple-cliente/ WEB-INF/ classes/com/marce/ws. Compilación y empaquetado del cliente del servicio web

Para compilar el cliente, se va a la carpeta de clases del

cliente (servicios_web/simple-cliente/WEB-INF/classes) y se

ejecuta la orden:

>javac com/marce/ws/*.java

Luego se va a la carpeta del cliente (servicios_web/simple-

cliente) y se empaqueta así:

>jar cvf simple-cliente.war *

Ejecución del cliente

Para probar cómo funcionan los diferentes tipos de clientes

se va a la carpeta de clases del cliente (servicios_web/simple-

cliente/WEB-INF/classes) y se ejecutan las siguientes órdenes

para probar las aplicaciones de consola y window:

>java com.marce.ws.SimpleClientConsole

>java com.marce.ws.SimpleClientWindow

Por último, para ejecutar el cliente web del servicio,

despliegue el archivo WAR en el servidor de aplicaciones.

Apéndice

Simple.java

package com.marce.ws;

import javax.jws.WebService;

/** * La interfaz de la clase SimpleService. * WebSphere Application Server sobre System i. * * @author Marcelino Rodriguez Suarez | http://www.marce.com * @version 1.0 - 2012 */@WebService(serviceName = "Simple", portName = "SimplePort", name = "SimplePortType", targetNamespace = "http://ws.marce.com/")public interface Simple {

/** * Devuelve un mensaje del System i. * * @param sistema * Nombre del System i. * @param usuario * Usuario del System i. * @param password * Password del usuario del System i. * @return Mensaje devuelto por el System i. */public String getMensaje(String sistema, String usuario, String password);

}

Página 1

SimpleService.java

package com.marce.ws;

import javax.jws.WebService;import com.ibm.as400.access.AS400;

/** * Servicio web simple. * * Su objetivo es demostrar como se puede llamar a un programa del System i * pasandole parametros de entrada y recibiendo parametros de salida. * * WebSphere Application Server sobre System i. * * @author Marcelino Rodriguez Suarez | http://www.marce.com * @version 1.0 - 2012 */@WebService(serviceName = "Simple", portName = "SimplePort", name = "SimplePortType", targetNamespace = "http://ws.marce.com/")public class SimpleService implements Simple {

/** * Devuelve un mensaje del System i. * * @param sistema * Nombre del System i. * @param usuario * Usuario del System i. * @param password * Password del usuario del System i. * @return Mensaje devuelto por el System i. */@Overridepublic String getMensaje(String sistema, String usuario, String password) {

String info = "";try {

// Crear un objeto AS400 para el sistema al que se envian los// mandatosAS400 as400System = new AS400(sistema, usuario, password);// AS400 sin interfaz grafica de usuarioas400System.setGuiAvailable(false);// Conexion al servicio de comandos y llamadas a programasas400System.connectService(AS400.COMMAND);// Conexion realizada con exitoif (as400System.isConnected()) {

// Mensaje de bienvenida con informacion sobre la version del// System iString infoSystem = "Bienvenido al System i " + "V"

+ as400System.getVersion() + "R"+ as400System.getRelease() + "M"+ as400System.getModification();

// Composicion de mensaje con informacion del sistema y de la// devuelta por la llamada al programa que da informacion// sobre el usuarioinfo = infoSystem + ". " + UserInfo.getInfo(as400System);

} else {info = "Imposible conectar. Causa: Desconocida";

Página 1

SimpleService.java

}} catch (Exception e) {

info = "Imposible conectar. Causa: " + e.getLocalizedMessage();}return info;

}}

Página 2

UserInfo.java

package com.marce.ws;

import com.ibm.as400.access.AS400;import com.ibm.as400.access.AS400Message;import com.ibm.as400.data.ProgramCallDocument;

/** * Recuperar informacion del usuario del System i. * * @author Marcelino Rodriguez Suarez | http://www.marce.com * @version 1.0 - 2012 */public class UserInfo {

/** * Devuelve informacion sobre el usuario que se conecta al System i. * * @param as400System * Conexion del System i. * @return Informacion devuelta sobre el usuario que se conecta al System i. */public static String getInfo(AS400 as400System) {

String info = "";try {

// Construir ProgramCallDocument.// El primer parametro es el sistema al que se va a conectar.// El segundo parametro es el nombre del recurso PCML.// El archivo PCML serializado "UserInfo.pcml.ser" o el archivo// fuente PCML "UserInfo.pcml" deben estar en la ruta de acceso// a las clases.ProgramCallDocument pcml = new ProgramCallDocument(as400System,

"com.marce.ws.UserInfo");// Establecer parametros de entrada.// Varios parametros tienen valores predeterminados especificados// en el fuente PCML y, por lo tanto, no es necesario establecerlos// mediante codigo.pcml.setValue("UserInfo.receiverLength",

new Integer((pcml.getOutputsize("UserInfo.receiver"))));// Codigo de retorno de callProgram()boolean rc = false;// Peticion de llamada al programa.rc = pcml.callProgram("UserInfo");// Si el codigo de retorno es false, se han recibido mensajes del// servidor.if (rc == false) {

// Recuperar la lista de mensajes del servidor.AS400Message[] msgs = pcml.getMessageList("UserInfo");// Iterar a traves de los mensajes y escribirlos.StringBuilder msgAllText = new StringBuilder();for (int m = 0; m < msgs.length; m++) {

// Mensajes devueltos desde el servidorString msgText = msgs[m].getText();msgAllText.append(msgText + " ");

}info = msgAllText.toString();

} else {

Página 1

UserInfo.java

// Si el codigo de retorno ha sido true, la llamada ha sido// satisfactoria.String prvSignonDate = pcml

.getStringValue("UserInfo.receiver.previousSignonDate");String prvSignonTime = pcml

.getStringValue("UserInfo.receiver.previousSignonTime");// Anno, mes y dia del inicio de sesion anteriorString anno = prvSignonDate.substring(1, 3);String mes = prvSignonDate.substring(3, 5);String dia = prvSignonDate.substring(5, 7);// Hora, minutos y segundos del inicio de sesion anteriorString hora = prvSignonTime.substring(0, 2);String minutos = prvSignonTime.substring(2, 4);String segundos = prvSignonTime.substring(4, 6);info = "Inicio de sesion anterior: " + dia + "-" + mes + "-"

+ anno + " " + hora + ":" + minutos + ":" + segundos;}

} catch (Exception e) {info = e.getLocalizedMessage();

}return info;

}}

Página 2

UserInfo.pcml

<pcml version="1.0">

<!-- Fuente PCML que llama al programa QSYRUSRI "API-Recuperar informacion

de usuario" -->

<!-- Format USRI0100-Informacion sobre inicio de sesion y password -->

<struct name="usri0100">

<data name="bytesReturned" type="int" length="4" usage="output" />

<data name="bytesAvailable" type="int" length="4" usage="output" />

<data name="userProfile" type="char" length="10" usage="output" />

<data name="previousSignonDate" type="char" length="7" usage="output" />

<data name="previousSignonTime" type="char" length="6" usage="output" />

<data name="reserved1" type="byte" length="1" usage="output" />

<data name="badSignonAttempts" type="int" length="4" usage="output" />

<data name="status" type="char" length="10" usage="output" />

<data name="passwordChangeDate" type="byte" length="8" usage="output" />

<data name="noPassword" type="char" length="1" usage="output" />

<data name="reserved2" type="byte" length="1" usage="output" />

<data name="passwordExpirationInterval" type="int" length="4"

usage="output" />

<data name="datePasswordExpires" type="byte" length="8" usage="output" />

<data name="daysUntilPasswordExpires" type="int" length="4"

usage="output" />

<data name="setPasswordToExpire" type="char" length="1" usage="output" />

<data name="displaySignonInfo" type="char" length="10" usage="output" />

<data name="localPasswordManagement" type="char" length="1"

usage="output" />

<data name="blockPasswordChange" type="char" length="10" usage="output" />

</struct>

<!-- Programa llamado y su lista de parametros -->

<program name="UserInfo" path="/QSYS.lib/QSYRUSRI.pgm">

<data name="receiver" type="struct" struct="usri0100" usage="output" />

<data name="receiverLength" type="int" length="4" usage="input" />

<data name="format" type="char" length="8" usage="input" init="USRI0100" />

<data name="profileName" type="char" length="10" usage="input"

init="*CURRENT" />

<data name="errorCode" type="int" length="4" usage="input" init="0" />

</program>

</pcml>

Página 1

SimpleClientConsole.java

package com.marce.ws;

import java.io.PrintStream;import java.util.Scanner;import java.net.URL;

import javax.xml.namespace.QName;import javax.xml.ws.Service;import javax.xml.ws.WebServiceRef;

/** * Llama al servicio web simple con interfaz de consola. * WebSphere Application Server sobre System i. * * @author Marcelino Rodriguez Suarez | http://www.marce.com * @version 1.0 - 2012 */public class SimpleClientConsole {

// Definir la referencia al servicio web@WebServiceRef(wsdlLocation = "http://systemi.marce.com:8080/simple/Simple?wsdl")private static Service service;

/** * Llamada al servicio web simple. * * @param args * Array de objetos String pasados al metodo main. */public static void main(String[] args) {

// Lectura de la entrada estandarScanner input = new Scanner(System.in);// Escritura en la salida estandarPrintStream output = System.out;try {

output.println("Nombre del sistema: ");String sistema = input.nextLine();

output.println("Usuario: ");String usuario = input.nextLine();

output.println("Password: ");String password;// De iniciar desde la linea de comandos se lee el password sin ecoif (System.console() != null) {

char[] passwordChar = System.console().readPassword();password = new String(passwordChar);

} else {password = input.nextLine();

}// URL del servicio webURL url = new URL("http://systemi.marce.com:8080/simple/Simple?wsdl");// Representacion del nombre completo del servicio webQName qname = new QName("http://ws.marce.com/", "Simple");// Creacion del objeto que implementa el servicio

Página 1

SimpleClientConsole.java

service = Service.create(url, qname);// Proxy de soporte a la interfaz de servicio webSimple smpl = service.getPort(Simple.class);// Invocacion del metodo correspondiente del servicio webString mensaje = smpl.getMensaje(sistema, usuario, password);

output.println(mensaje);} catch (Exception e) {

output.println(e.getLocalizedMessage());}

}}

Página 2

SimpleClientWindow.java

package com.marce.ws;

import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.net.URL;import javax.xml.namespace.QName;import javax.xml.ws.Service;import javax.xml.ws.WebServiceRef;

/** * Llama al servicio web simple con interfaz grafica. * WebSphere Application Server sobre System i. * * @author Marcelino Rodriguez Suarez | http://www.marce.com * @version 1.0 - 2012 */public class SimpleClientWindow extends JFrame {

// Variablesprivate static final long serialVersionUID = 1L;private JTextField jtfSistema, jtfUsuario;private JPasswordField jtfPassword;private JButton jbtConectar;// Definir la referencia al servicio web@WebServiceRef(wsdlLocation = "http://systemi.marce.com:8080/simple/Simple?wsdl")private Service service;

/** * Inicio * * @param args * Array de objetos String pasados al metodo main. */public static void main(String args[]) {

new SimpleClientWindow().setVisible(true);}

/** * Creacion del formulario. */public SimpleClientWindow() {

setName("jfrConnect");setTitle("Conexion al System i");setLocationRelativeTo(null);setResizable(false);setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

jtfSistema = new JTextField("", 10);jtfUsuario = new JTextField("", 10);jtfPassword = new JPasswordField("", 10);jbtConectar = new JButton("Realizar la conexion");

JPanel jpnDatos = new JPanel();jpnDatos.setLayout(new GridLayout(3, 2));jpnDatos.add(new JLabel("Nombre de sistema"));

Página 1

SimpleClientWindow.java

jpnDatos.add(jtfSistema);jpnDatos.add(new JLabel("Usuario"));jpnDatos.add(jtfUsuario);jpnDatos.add(new JLabel("Password"));jpnDatos.add(jtfPassword);

Container jpnFrm = getContentPane();jpnFrm.setLayout(new BoxLayout(jpnFrm, BoxLayout.PAGE_AXIS));jpnFrm.add(jpnDatos);jpnFrm.add(jbtConectar);

jbtConectar.setAlignmentX(CENTER_ALIGNMENT);pack();

// Llamada a la operacion del Web ServicejbtConectar.addActionListener(new ActionListener() {

@Overridepublic void actionPerformed(ActionEvent evt) {

jbtConectarActionPerformed(evt);}

});

}

/** * Llamada a la operacion del Web Service * * @param evt * Evento de accion (pulsacion del boton) */private void jbtConectarActionPerformed(ActionEvent evt) {

try {String sistema = jtfSistema.getText();String usuario = jtfUsuario.getText();String password = new String(jtfPassword.getPassword());

// URL del servicio webURL url = new URL("http://systemi.marce.com:8080/simple/Simple?wsdl");// Representacion del nombre completo del servicio web QName qname = new QName("http://ws.marce.com/", "Simple");// Creacion del objeto que implementa el servicioservice = Service.create(url, qname);// Proxy de soporte a la interfaz de servicio webSimple smpl = service.getPort(Simple.class);// Invocacion del metodo correspondiente del servicio web String mensaje = smpl.getMensaje(sistema, usuario, password);

JOptionPane.showMessageDialog(this, mensaje, this.getTitle(),JOptionPane.INFORMATION_MESSAGE);

} catch (Exception e) {JOptionPane.showMessageDialog(this, e.getLocalizedMessage(),

this.getTitle(), JOptionPane.ERROR_MESSAGE);}

}

Página 2

SimpleClientWindow.java

}

Página 3

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"import="java.net.URL"import="javax.xml.namespace.QName"import="javax.xml.ws.Service"import="javax.xml.ws.WebServiceRef"import="com.marce.ws.Simple"

%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><%-- Llama al servicio web simple con JavaServer Pages (JSP)WebSphere Application Server sobre System i.(c) Marcelino Rodriguez Suarez | http://www.marce.comversion 1.0 - 2012--%><%!

// Definir la referencia al servicio web// @WebServiceRef(wsdlLocation =

"http://systemi.marce.com:8080/simple/Simple?wsdl")private Service service;

%><%

String sistema = request.getParameter("sistema");String usuario = request.getParameter("usuario");String password = request.getParameter("password");if (sistema == null || usuario == null || password == null) {

sistema = "";usuario = "";password = "";

}request.setAttribute("sistema", sistema);request.setAttribute("usuario", usuario);request.setAttribute("password", password);request.setAttribute("mensaje", "");if (!sistema.isEmpty() || !usuario.isEmpty() || !password.isEmpty()) {

try {// URL del servicio webURL url = new URL(

"http://systemi.marce.com:8080/simple/Simple?wsdl");// Representacion del nombre completo del servicio webQName qname = new QName("http://ws.marce.com/", "Simple");// Creacion del objeto que implementa el servicioservice = Service.create(url, qname);// Proxy de soporte a la interfaz de servicio webSimple smpl = service.getPort(Simple.class);// Invocacion del metodo correspondiente del servicio webString mensaje = smpl

.getMensaje(sistema, usuario, password);

request.setAttribute("mensaje", mensaje);} catch (Exception e) {

request.setAttribute("mensaje", e.getLocalizedMessage());

Página 1

index.jsp

}}

%><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Conexion al System i</title></head><body>

<center><h2>Conexion al System i</h2><hr /><!-- Invocacion al servicio Web --><form style="font-family: arial" action="index.jsp" method="post">

<table border="0"><tr>

<td align="left">Nombre de sistema</td><td><input type="text" name="sistema"

value='${requestScope.sistema}' /></td></tr><tr>

<td align="left">Usuario</td><td><input type="text" name="usuario"

value='${requestScope.usuario}' /></td></tr><tr>

<td align="left">Password</td><td><input type="password" name="password"

value='${requestScope.password}' /></td></tr>

</table><input type="submit" value="Realizar la conexion" name="conectar" />

</form><hr /><p style="font-family: arial; color: blue;">${requestScope.mensaje}</p>

</center></body></html>

Página 2