332
UNIVERSIDAD DE SEVILLA ESCUELA SUPERIOR DE INGENIEROS INGENIERÍA DE TELECOMUNICACIÓN Transmisión de imágenes de vídeo mediante Servicios Web XML sobre J2ME Francisco Prieto Donate Tutor: Antonio Jesús Sierra Collado Departamento de Ingeniería de Sistemas y Automática Área de Ingeniería Telemática

Transmisión de imágenes de vídeo mediante Servicios Web XML …bibing.us.es/proyectos/abreproy/11372/fichero/Memoria... · transmisión de una señal de vídeo así como de imágenes

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

UNIVERSIDAD DE SEVILLA ESCUELA SUPERIOR DE INGENIEROS

INGENIERÍA DE TELECOMUNICACIÓN

Transmisión de imágenes de vídeo mediante Servicios Web XML sobre J2ME

Francisco Prieto Donate Tutor: Antonio Jesús Sierra Collado

Departamento de Ingeniería de Sistemas y Automática

Área de Ingeniería Telemática

Francisco Prieto Donate III

Sevilla, Febrero de 2007

IV Francisco Prieto Donate

Francisco Prieto Donate V

AGRADECIMIENTOS

A mis padres y mi hermana, que tanto han confiado en mí, me han apoyado y han compartido conmigo las alegrías y tristezas en estos años de carrera.

A mis amigos de la facultad, con los que he compartido cada uno de mis días universitarios.

A mis amigos de la residencia, que tantos buenos momentos me han hecho pasar.

Al “Carry Team”, por ser el mejor grupo de amigos que haya existido jamás.

A todos ellos, muchísimas gracias.

VI Francisco Prieto Donate

Francisco Prieto Donate VII

OBJETIVOS

El objetivo de este proyecto consiste en transmitir imágenes de vídeo desde un servidor de vídeo hasta un teléfono móvil utilizando Servicios Web XML.

Partimos de un servidor de vídeo ya implementado, que permite la captura y transmisión de una señal de vídeo así como de imágenes estáticas, con el cual debemos interactuar para realizar una petición y recibir una respuesta.

En primer lugar es necesario estudiar cómo adaptar el servidor de vídeo para que se comporte como un servidor de aplicaciones, atendiendo peticiones mediante el protocolo estándar SOAP. Buscamos además que esta adaptación provoque el menor número de cambios posible en el servidor de vídeo.

Asimismo tendremos que implementar un cliente que se comunique con dicho servidor. Se utilizará el lenguaje de programación orientado a objetos Java, en su versión para dispositivos de recursos limitados (J2ME). Para realizar esta implementación se hace necesario conocer las tecnologías existentes para utilizar Servicios Web XML en dispositivos inalámbricos.

Para poder ejecutarse, la aplicación será instalada en el teléfono por descarga OTA, es decir, a través de Internet siguiendo el procedimiento normal de descarga de aplicaciones para móviles. El teléfono móvil debe disponer de conexión a Internet a través de GPRS.

La interfaz gráfica de usuario de la aplicación será realizada para que resulte lo más fácil e intuitiva posible, de forma que su manejo sea lo suficientemente sencillo como para que la aplicación pueda ser utilizada por cualquier persona con unos mínimos conocimientos sobre teléfonos móviles.

Por último debemos comparar entre distintos formatos de imagen, codificaciones y tecnologías de Servicios Web para conseguir la mejor relación entre calidad de imagen y tiempo de espera.

VIII Francisco Prieto Donate

Francisco Prieto Donate IX

ÍNDICE

1 INTRODUCCIÓN........................................................... 1

1.1 Java en dispositivos inalámbricos..................................................................... 1

1.2 SOAP y XML en dispositivos inalámbricos .................................................... 2

1.3 Organización de la memoria............................................................................. 3

1.3.1 Introducción teórica.......................................................................... 3

1.3.2 Aplicación desarrollada .................................................................... 4

1.3.3 Temporización y presupuesto........................................................... 5

1.3.4 Guía de instalación y planos de código ............................................ 5

2 J2ME .......................................................................... 7

2.1 Introducción...................................................................................................... 7

2.2 Java 2 Platform Micro Edition (J2METM) ........................................................ 7

2.3 Arquitectura J2ME ........................................................................................... 9

2.3.1 Máquina Virtual.............................................................................. 11

2.3.2 Configuraciones.............................................................................. 12

2.3.3 Perfiles ............................................................................................ 13

2.3.4 Capas altas ...................................................................................... 14

2.4 Seguridad ........................................................................................................ 14

2.5 Objetivos, requisitos y alcance de J2ME........................................................ 16

2.5.1 Objetivos......................................................................................... 17

2.5.2 Requisitos ....................................................................................... 18

2.5.3 Alcance ........................................................................................... 19

2.6 CLDC (Connected Limited Device Configuration) ....................................... 20

2.6.1 CLDC Expert Group....................................................................... 21

2.6.2 Modelo de Aplicación de CLDC.................................................... 21

2.6.3 Compatibilidad con JavaTM Virtual Machine Specification ........... 22

2.6.4 Verificación de ficheros de clase.................................................... 24

2.6.5 Librerías de CLDC ......................................................................... 25

2.6.6 CLDC 1.1 ....................................................................................... 30

2.7 MIDP (Mobile Information Device Profile)................................................... 31

X Francisco Prieto Donate

2.7.1 MIDP Expert Group ....................................................................... 32

2.7.2 Modelo de Aplicación de MIDP..................................................... 33

2.7.3 MIDlet Suites.................................................................................. 37

2.7.4 Librerías de MIDP.......................................................................... 38

2.7.5 MIDP 2.0 ........................................................................................ 55

2.8 Descarga OTA ................................................................................................ 60

2.8.1 Usos de la tecnología OTA............................................................. 61

2.9 Consideraciones finales .................................................................................. 61

3 GPRS ........................................................................ 63

3.1 Introducción.................................................................................................... 63

3.2 Introducción histórica a GPRS ....................................................................... 63

3.3 Protocolo GPRS.............................................................................................. 67

3.3.1 Identificador del protocolo GPRS .................................................. 68

3.3.2 Identificador del protocolo de los PDU.......................................... 68

3.3.3 Mensaje GPRS................................................................................ 68

3.4 Arquitectura de la red GPRS .......................................................................... 69

3.4.1 Elementos de una red GPRS........................................................... 69

3.4.2 Interfaces de una red GPRS............................................................ 74

3.5 Tipología de servicios..................................................................................... 76

3.6 Terminales GPRS ........................................................................................... 77

3.7 Tercera generación de móviles: UMTS.......................................................... 79

3.8 Consideraciones finales .................................................................................. 80

4 SERVICIOS WEB XML.............................................. 83

4.1 Introducción.................................................................................................... 83

4.1.1 Evolución de los Servicios Web..................................................... 83

4.1.2 Conceptos básicos .......................................................................... 84

4.2 XML ............................................................................................................... 85

4.2.1 Introducción.................................................................................... 85

4.2.2 Reglas sintácticas............................................................................ 86

4.2.3 DTD (Definición de Tipos de Documentos) .................................. 87

4.2.4 XML Schema.................................................................................. 89

Francisco Prieto Donate XI

4.2.5 Espacios de nombres XML ............................................................ 91

4.2.6 Analizadores XML ......................................................................... 93

4.3 SOAP.............................................................................................................. 94

4.3.1 Concepto de SOAP......................................................................... 95

4.3.2 Objetivos de SOAP......................................................................... 95

4.3.3 Un ejemplo sencillo de mensajes SOAP ........................................ 96

4.3.4 Partes de un mensaje SOAP ........................................................... 97

4.3.5 Enlaces SOAP (bindings) ............................................................. 101

4.3.6 SOAP 1.2...................................................................................... 101

4.4 WSDL........................................................................................................... 102

4.4.1 Elementos de un documento WSDL ............................................ 103

4.4.2 Estilo y uso de un documento WSDL .......................................... 106

4.4.3 Generación del documento WSDL............................................... 112

4.4.4 Interpretación del documento WSDL........................................... 112

4.5 UDDI ............................................................................................................ 113

4.5.1 Concepto de UDDI ....................................................................... 113

4.5.2 Datos almacenados en el registro ................................................. 114

4.5.3 Publicación en UDDI ................................................................... 115

4.5.4 Búsqueda en UDDI....................................................................... 115

4.6 Servicios Web XML para dispositivos móviles ........................................... 116

4.6.1 kSOAP.......................................................................................... 116

4.6.2 JSR-172 ........................................................................................ 127

4.7 Consideraciones finales ................................................................................ 132

5 PROTOCOLO HTTP................................................ 135

5.1 Características y funcionamiento.................................................................. 135

5.2 Comandos de HTTP ..................................................................................... 139

5.3 Codificación de la información .................................................................... 143

5.4 Consideraciones finales ................................................................................ 145

6 TRANSMISIÓN DE VÍDEO EN INTERNET .................. 147

6.1 Introducción.................................................................................................. 147

6.2 Descarga y visualización del contenido ....................................................... 147

XII Francisco Prieto Donate

6.2.1 Formatos de imagen ..................................................................... 148

6.2.2 Formatos de codificación de vídeo............................................... 159

6.3 Tecnología de streaming............................................................................... 167

6.3.1 Funcionamiento ............................................................................ 168

6.3.2 Reproductores de streaming ......................................................... 169

6.3.3 Servidores de streaming................................................................ 170

6.3.4 Protocolos de streaming ............................................................... 170

6.4 Consideraciones finales ................................................................................ 171

7 APLICACIÓN DESARROLLADA ................................ 173

7.1 Introducción.................................................................................................. 173

7.2 Desarrollo del servidor ................................................................................. 173

7.2.1 Transformación del servidor de vídeo en servidor web XML...... 174

7.2.2 Comunicación entre servidor de vídeo y servidor web ................ 174

7.2.3 Protocolo de comunicación entre servidores ................................ 175

7.3 Desarrollo del cliente.................................................................................... 176

7.3.1 Servicios web en dispositivos móviles ......................................... 176

7.3.2 Formato de imagen solicitada....................................................... 177

7.4 Comunicación cliente-servidor..................................................................... 177

7.5 Consideraciones finales ................................................................................ 179

8 ESCENARIO DE PRUEBAS ........................................ 181

8.1 Introducción.................................................................................................. 181

8.2 Escenario de pruebas .................................................................................... 181

8.3 Escenario kSOAP ......................................................................................... 182

8.3.1 Desarrollo del servicio web .......................................................... 182

8.3.2 Despliegue del servicio web......................................................... 185

8.3.3 Desarrollo del cliente.................................................................... 188

8.3.4 Simulación del cliente .................................................................. 197

8.4 Escenario JSR-172........................................................................................ 201

8.4.1 Desarrollo del servicio web .......................................................... 201

8.4.2 Despliegue del servicio web......................................................... 204

8.4.3 Desarrollo del cliente.................................................................... 208

Francisco Prieto Donate XIII

8.4.4 Simulación del cliente .................................................................. 217

8.5 Consideraciones finales ................................................................................ 222

9 PRUEBAS Y RESULTADOS........................................ 223

9.1 Introducción a las pruebas ............................................................................ 223

9.2 Escenario kSOAP ......................................................................................... 224

9.2.1 Codificación Base64..................................................................... 224

9.2.2 Codificación Array de enteros...................................................... 226

9.3 Escenario JSR-172........................................................................................ 228

9.3.1 Codificación Base64..................................................................... 228

9.3.2 Codificación Array de enteros...................................................... 230

9.4 Análisis de los resultados ............................................................................. 233

9.4.1 Consumo de memoria................................................................... 233

9.4.2 Tiempo entre imágenes................................................................. 234

9.4.3 Información enviada por el servidor............................................. 235

9.5 Consideraciones finales ................................................................................ 236

10 CONCLUSIONES .................................................... 237

10.1 Conclusiones................................................................................................. 237

10.2 Líneas de desarrollo futuras.......................................................................... 239

11 TEMPORIZACIÓN.................................................. 241

12 PRESUPUESTO ...................................................... 243

12.1 Coste de recursos humanos .......................................................................... 243

12.2 Coste de hardware ........................................................................................ 243

12.3 Coste de software ......................................................................................... 243

12.4 Coste de consumibles ................................................................................... 243

12.5 Resumen de costes........................................................................................ 244

13 GUÍA DE INSTALACIÓN......................................... 245

13.1 Servidor de vídeo.......................................................................................... 245

XIV Francisco Prieto Donate

13.1.1 Instalación..................................................................................... 246

13.1.2 Funcionamiento ............................................................................ 247

13.1.3 Formato de la petición al servidor ................................................ 249

13.2 Servidor web Apache Tomcat 4.1 ................................................................ 251

13.2.1 Instalación..................................................................................... 251

13.2.2 Funcionamiento ............................................................................ 252

13.3 Apache Axis 1.4 ........................................................................................... 254

13.3.1 Instalación..................................................................................... 254

13.3.2 Despliegue de servicios ................................................................ 257

13.4 J2ME Wireless Toolkit 2.2........................................................................... 263

13.5 NetBeans IDE 5.5 ......................................................................................... 265

14 PLANOS DE CÓDIGO ............................................. 269

14.1 Escenario kSOAP ......................................................................................... 269

14.1.1 Servidor Web................................................................................ 269

14.1.2 Cliente J2ME................................................................................ 272

14.2 Escenario JSR-172........................................................................................ 295

14.2.1 Servidor web................................................................................. 295

14.2.2 Cliente J2ME................................................................................ 298

14.2.3 Stub del cliente J2ME................................................................... 308

15 REFERENCIAS BIBLIOGRÁFICAS .......................... 315

15.1 Libros de consulta......................................................................................... 315

15.2 Proyectos fin de carrera ................................................................................ 315

15.3 Páginas web .................................................................................................. 316

15.4 Apuntes de asignaturas ................................................................................. 318

15.5 Artículos ....................................................................................................... 318

1. Introducción

Francisco Prieto Donate 1

1 INTRODUCCIÓN

1.1 Java en dispositivos inalámbricos

El lenguaje de programación Java fue concebido inicialmente para el desarrollo de aplicaciones en dispositivos comerciales controlados digitalmente. El objetivo de los creadores de Java fue el diseño de un nuevo lenguaje de alto nivel que permitiese controlar dispositivos hardware de prestaciones más o menos reducidas. Se buscaba un lenguaje totalmente portable e independiente de la plataforma de ejecución.

Con el tiempo se vio la verdadera potencia que podía proporcionar, y su inclusión en el navegador Netscape marcó el inicio de su extensión a los ordenadores. Al disponer de mayor capacidad de procesamiento que en los dispositivos para los que inicialmente estaba pensado, las sucesivas versiones de Java requieren más recursos y añaden nuevas características útiles.

En la actualidad, debido al creciente mercado de dispositivos móviles, Java ha tenido que volver a sus inicios y desarrollar una versión más limitada para que pueda ser usada en dichos dispositivos. Esta versión es la Java 2 Micro Edition, o J2ME.

Son muchas las características que hacen de Java el lenguaje ideal para este tipo de dispositivos inalámbricos. De entre todas ellas cabe destacar:

• Es independiente de la red, por tanto permite descargar cualquier tipo de aplicaciones y servicios en cualquier tipo de conexión.

• Tareas como la verificación de ficheros de clase proporcionan una alta seguridad de que las aplicaciones que se desarrollen con este lenguaje funcionen adecuadamente.

• La portabilidad, debida a la independencia de Java respecto de la plataforma subyacente, hace que sea este lenguaje ideal para aplicaciones que irán dirigidas a dispositivos diseñados por diferentes fabricantes.

• J2ME ha sido diseñado de forma que se pueda presentar de forma sencilla al usuario un conjunto de prestaciones gráficas que hacen muy atractivas las aplicaciones desarrolladas con este lenguaje.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

2 Francisco Prieto Donate

• Para las aplicaciones diseñadas con J2ME no es necesario la conexión a permanente a la red, ya que estas aplicaciones residen en el dispositivo inalámbrico y no tienen por qué ser descargadas cada vez que vayan a ser ejecutadas.

• Se puede decir que la comunidad de desarrolladores de aplicaciones Java en la red es la mayor de todas las existentes, con un número de participantes que supera los cuatro millones y medio.

1.2 SOAP y XML en dispositivos inalámbricos

Debido a las características del lenguaje Java es posible la ampliación de la funcionalidad de una aplicación sin más que añadir nuevas librerías.

Esto hace que las aplicaciones software desarrolladas con Java, y en particular con J2ME, tengan un potencial muy grande, ya que pueden adaptarse de forma sencilla a las distintas tecnologías que vayan apareciendo, de modo que nunca se quedarán obsoletas.

La tendencia actual en cuanto a la representación de datos es el uso de la tecnología XML, la cual permite de forma sencilla contener cualquier tipo de dato dentro de mensajes de texto plano. Esto hace que la sencillez en la transferencia de datos mediante XML sea tal que prácticamente todas las aplicaciones Web que corren sobre Internet usen este lenguaje de marcas.

Comprobada la versatilidad de XML, continuamente se están llevando a cabo proyectos con el fin de desarrollar las prestaciones que ofrece este lenguaje. De esta forma son múltiples los campos de la tecnología que hacen uso de XML, no solamente en la red, sino ya en tareas de configuración de dispositivos físicos.

De entre todos estos proyectos nació uno que recibió el nombre de SOAP, cuyo objetivo es el utilizar XML en tareas de transferencia de datos en la red. Así, SOAP encapsula en documentos XML los mensajes intercambiados entre un servidor de aplicaciones y un cliente.

Puesto que los dispositivos inalámbricos se están introduciendo cada día más en Internet, es evidente que antes o después sería necesario para éstos el uso de XML y por tanto de SOAP. Este hecho ha traído consigo que algunos de los componentes de la comunidad de desarrollo con la que cuenta Java se hayan dedicado a desarrollar las

1. Introducción

Francisco Prieto Donate 3

librerías necesarias para el uso de SOAP o XML en aplicaciones sobre J2ME. En la actualidad existen las librerías ksoap para SOAP inalámbrico y kxml2, nanoXml, TAM, X-parse y tinyXml para analizar documentos XML en dispositivos inalámbricos.

1.3 Organización de la memoria

La memoria de este proyecto se estructura en cuatro bloques principales. El primer bloque contiene una introducción teórica de las tecnologías utilizadas. El segundo muestra una descripción de la aplicación desarrollada junto con las pruebas realizadas, resultados obtenidos y conclusiones. En tercer lugar presentamos la temporización y el presupuesto. Por último se incluye la guía de instalación y el código fuente utilizado en el desarrollo de la aplicación.

1.3.1 Introducción teórica

Los primeros capítulos de la memoria están dedicados a presentar cada una de las tecnologías implicadas en la realización de este proyecto. Este bloque está formado por los siguientes capítulos:

• Capítulo 2: J2ME. En este capítulo presentamos y analizamos Java 2 Micro Edition, también conocida como “Java para móviles”. Esta tecnología nos permite ejecutar programas Java en dispositivos móviles con reducidas prestaciones de capacidad y memoria.

• Capítulo 3: GPRS. Estudiamos la tecnología que usará nuestro dispositivo móvil para conectarse a Internet con el fin de comunicarse con un servidor.

• Capítulo 4: Servicios Web XML. Este capítulo se dedica a explicar el marco que utilizarán cliente y servidor para intercambiarse información. Analizaremos las distintas tecnologías y protocolos asociados a los servicios web, prestando especial atención al estudio de XML. Por último presentaremos dos escenarios diferentes de comunicación entre cliente y servidor.

• Capítulo 5: Protocolo HTTP. Estudiaremos las características y el fundamento del protocolo de transferencia de datos más utilizado en la red para la descarga de páginas web e intercambio de información de los Servicios Web.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

4 Francisco Prieto Donate

• Capítulo 6: Transmisión de vídeo en Internet. En este capítulo haremos un repaso de las principales alternativas utilizadas en la actualidad para la transmisión de vídeo a través de Internet. Analizaremos distintos formatos de imágenes y vídeo y comentaremos las tecnologías existentes para transmisión en tiempo real.

1.3.2 Aplicación desarrollada

Tras la introducción teórica realizamos una aplicación con la que se pretende recibir imágenes de vídeo en un cliente móvil compatible con J2ME mediante Servicios Web XML utilizando todas las tecnologías anteriormente explicadas. Este segundo bloque está formado por los siguientes capítulos:

• Capítulo 7: Aplicación desarrollada. Capítulo dedicado a presentar una panorámica de la aplicación que se va a desarrollar. En este punto se introducen los servidores que se van a utilizar y las distintas tecnologías, formatos y codificaciones de los que haremos uso para realizar la implementación.

• Capítulo 8: Escenario de pruebas. En este capítulo se detalla la aplicación desarrollada. Se presentan dos escenarios, donde cada uno utiliza una tecnología de servicios web diferente. Para cada escenario se explica cómo se ha realizado y desplegado el servicio web, y cual es el funcionamiento del cliente móvil. Se adjuntan fragmentos de planos de código fuente con comentarios para mejorar la comprensión de las implementaciones.

• Capítulo 9: Pruebas y resultados. Una vez preparado el escenario, establecemos una batería de pruebas destinada a medir factores como tiempos de respuesta y consumo de memoria en tiempo de ejecución. Al final del capítulo se ponen en común y se justifican todos los resultados obtenidos.

• Capítulo 10: Conclusiones. El último capítulo del bloque está dedicado a estudiar y comentar los resultados obtenidos en las pruebas para conseguir una aplicación con altos niveles de rendimiento. Asimismo se hace un repaso de cada una de las tecnologías implicadas y cómo ha afectado cada una de ellas en la aplicación desarrollada.

1. Introducción

Francisco Prieto Donate 5

1.3.3 Temporización y presupuesto

Este bloque está dedicado a mostrar el tiempo utilizado en la realización del proyecto y redacción de la memoria y el presupuesto necesario para su puesta en práctica. Dos son los capítulos que conforman este bloque:

• Capítulo 11: Temporización. En este capítulo exponemos la división que se ha realizado del proyecto en fases, estableciendo el tiempo dedicado a la realización de cada una de ellas.

• Capítulo 12: Presupuesto. Presentamos el coste total necesario para poner en práctica la aplicación desarrollada en este proyecto.

1.3.4 Guía de instalación y planos de código

El último bloque de la memoria presenta la guía de instalación y los planos de código fuente utilizados.

• Capítulo 13: Guía de instalación. El primer capítulo de este bloque expone todos los pasos necesarios para poner en práctica el escenario de pruebas que se ha utilizado en este proyecto. Se presenta todo el software utilizado y se explica detalladamente el proceso de instalación y configuración de cada uno de los programas.

• Capítulo 14: Planos de código. Por último mostramos el código fuente utilizado para crear un servicio web, desplegarlo y acceder a él a través del cliente móvil.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

6 Francisco Prieto Donate

2. J2ME

Francisco Prieto Donate 7

2 J2ME

2.1 Introducción

El cliente desarrollado en este proyecto está basado en la tecnología J2ME, una plataforma que permite la ejecución de programas Java en dispositivos móviles. Esta tecnología puede encontrarse en teléfonos móviles, PDAs o Palms, o incluso cualquier otro tipo de dispositivo móvil que pudiese ser diseñado en un futuro próximo.

La aplicación cliente se ejecutará en un teléfono móvil con soporte J2ME y se conectará, mediante el protocolo de comunicación SOAP, con un servicio Web el cual le facilitará una serie datos de utilidad para el usuario.

2.2 Java 2 Platform Micro Edition (J2METM)

Actualmente Sun Microsystems ha agrupado la tecnología Java en tres tecnologías claramente diferenciadas, cada una de ellas adaptada a un área específica de la industria:

• Java 2 Platform, Enterprise Edition (J2EETM), pensada para cubrir las necesidades que puedan tener las empresas que quieran ofrecer servicios a sus clientes, proveedores y empleados.

• Java 2 Platform, Standard Edition (J2SETM), pensada para satisfacer las necesidades de usuarios y programadores en sus equipos personales y estaciones de trabajo.

• Java 2 Micro Edition (J2METM), enfocada tanto para productores de dispositivos portátiles de consumo como para quienes proporcionan servicios de información aplicables a estos dispositivos.

Cada una de estas plataformas define en su interior un conjunto de tecnologías que pueden ser utilizadas con un producto en particular:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

8 Francisco Prieto Donate

• Java Virtual Machine que encuadra en su interior un amplio rango de equipos de computación.

• Librerías y APIs especializadas para cada tipo de dispositivo.

• Herramientas para desarrollo y configuración de equipos.

J2ME abarca un espacio de consumo en rápido crecimiento, que cubre un amplio rango de dispositivos, desde pequeños dispositivos de mano hasta incluso televisores. Todo esto manteniendo siempre las cualidades por las cuales la tecnología Java ha sido mundialmente reconocida: consistencia entre los distintos productos Java y portabilidad de código entre equipos, así como gratuidad y escalabilidad.

La idea principal de J2ME es proporcionar aplicaciones sencillas, que permitan al programador desarrollar aplicaciones de usuario para el consumidor de dispositivos móviles y portátiles. De esta forma se abre un amplio mercado para todas aquellas empresas que deseen cubrir las necesidades que los usuarios demandan en sus dispositivos móviles, tales como teléfonos móviles o agendas personales.

J2ME está orientada a dos categorías muy concretas de productos, como son:

• Dispositivos de información compartida conectados de forma permanente. Esta categoría se conoce con la denominación CDC (Connected Device Configuration). Ejemplos típicos de éstos son televisores, teléfonos conectados a Internet y sistemas de navegación y entretenimiento para el automóvil. Estos dispositivos se caracterizan por tener un gran número de interfaces de usuario, conexión permanente a Internet de banda ancha de tipo TCP/IP y unos rangos de capacidad de memoria entre 2 y 16 MB.

• Dispositivos de información personales móviles. Categoría conocida como CLDC (Connected, Limited Device Configuration). De entre todos éstos los más representativos son los teléfonos móviles y las agendas personales (PDAs). Se caracterizan por disponer de interfaces simples, conexión no permanente a Internet, menor ancho de banda y rangos de capacidad de memoria muy reducidos, entre 128 y 512 KB.

2. J2ME

Francisco Prieto Donate 9

Figura 2.1: Dispositivos Java y sus ediciones

Con el paso de los años la línea fronteriza que separa ambos grupos es cada vez más fina, hecho que va potenciándose aún más a medida que la tecnología avanza y van apareciendo nuevos tipos de dispositivos y evolucionando los ya existentes. De esta forma hoy ya se “confunden” los ordenadores y los dispositivos de comunicaciones y cada vez más se va haciendo más uso de conexiones sin cables, lo cual nos lleva a realizar en la práctica una agrupación de equipos basándonos únicamente en sus capacidades de memoria, sus consumos de batería y el tamaño de la pantalla.

2.3 Arquitectura J2ME

Aunque los dispositivos mencionados tales como teléfonos móviles, PDAs o televisores tienen muchos aspectos en común, también son muy diferentes en cuanto a forma y función. Éstos contarán con diferentes configuraciones hardware, diferentes modos de uso (uso de teclado, voz, etc.), diferentes aplicaciones y características software, así como todo un amplio rango de futuras necesidades a cubrir. Para considerar esta diversidad la arquitectura J2ME está diseñada de forma modular y extensible de tal forma que se dé cabida a esta extensa variedad de dispositivos así como a aquellos que sean desarrollados en el futuro.

La arquitectura J2ME tiene en cuenta todas aquellas consideraciones relativas a los dispositivos sobre los que tendrá que trabajar. De esta forma, son tres los conceptos básicos en los que se fundamenta:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

10 Francisco Prieto Donate

• Máquina Virtual: Ya que el mercado de venta de los dispositivos a los que se refiere J2ME es tan variado y heterogéneo, existiendo un gran número de fabricantes con distintos equipos hardware y distintas filosofías de trabajo, J2ME proporciona una máquina virtual Java completamente optimizada que permitirá trabajar con diferentes tipos de procesadores y memorias comúnmente utilizados.

• Configuración y Perfil: Como los dispositivos sobre los que trabaja J2ME son tan reducidos en lo que se refiere a potencia de cálculo y capacidad de memoria, J2ME proporciona una máquina virtual Java muy reducida que permite solo aquellas funciones esenciales y necesarias para el funcionamiento del equipo. Además, como los fabricantes diseñan distintas características en sus equipos y desarrollan continuos cambios y mejoras en sus aplicaciones estas configuraciones tan reducidas deben poder ser ampliadas con librerías adicionales. Por ello se han considerado dos conceptos extremadamente importantes, que son las Configuraciones y los Perfiles. El objetivo de realizar esta distinción entre Perfiles y Configuraciones es el de preservar una de las principales características de Java, la portabilidad.

Figura 2.2: Capas en un dispositivo con soporte J2ME

2. J2ME

Francisco Prieto Donate 11

2.3.1 Máquina Virtual

En la actualidad existen dos implementaciones de máquina virtual para ejecución de programas Java en dispositivos móviles:

• K Virtual Machine

La tecnología KVM define una máquina virtual Java específicamente pensada para su funcionamiento en dispositivos de pequeño tamaño y de características muy reducidas y limitadas. El objetivo de esta tecnología fue el de crear la mínima máquina virtual posible pero que mantuviese los aspectos fundamentales del lenguaje Java, todo ello funcionando en un dispositivo con una capacidad de memoria de tan solo unos cuantos centenares de KB (de ahí el nombre de la máquina virtual).

KVM puede trabajar con microprocesadores de 16/32 bits tales como teléfonos móviles, PDAs, equipos de audio/vídeo portátiles, etc.

La mínima cantidad ideal de memoria necesaria para la KVM es de 128 KB en los cuales se incluyen la propia máquina virtual, un mínimo número de librerías y espacio libre para las aplicaciones. A pesar de esto, una implementación típica real necesita de unos 256 KB de los que aproximadamente se utilizan la mitad para las aplicaciones, de 60 a 80 KB para la máquina virtual y el resto para las librerías.

• CLDC HotSpot ImplementationTM

Es una máquina virtual optimizada que presenta una diferencia de rendimiento muy alta frente a la KVM. Está pensada para funcionar en dispositivos de nueva generación con mayores capacidades de memoria. Incluye características que soportan una ejecución más rápida de aplicaciones y una gestión de recursos más eficientes, manteniendo los requisitos en cuanto a plataforma de ejecución.

El CLDC HotSpot ImplementationTM está diseñado para trabajar en microprocesadores o microcontroladores RISC/CISC de 32 bits. La cantidad mínima de memoria necesaria es de 512 KB en los cuales se incluyen la propia máquina virtual, un conjunto de librerías y espacio libre para las aplicaciones.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

12 Francisco Prieto Donate

2.3.2 Configuraciones

Una Configuración J2ME define una plataforma mínima para una categoría horizontal de dispositivos con similares características de memoria y procesamiento. A su vez, proporciona una definición completa de máquina virtual y el conjunto mínimo de clases Java que todo dispositivo o aplicación debería tener. Más concretamente, una configuración especifica:

• Las características del lenguaje Java soportadas por el dispositivo.

• Las características soportadas por la máquina virtual Java.

• Las librerías y APIs Java soportadas.

En un entorno J2ME una aplicación es desarrollada para un Perfil en particular, el cual se basa en una Configuración específica. De esta forma una Configuración define una plataforma común tanto para la fabricación de dispositivos como para el posterior desarrollo de aplicaciones sobre éstos.

Por tanto, todos los dispositivos que se encuadren dentro de una Configuración concreta deben cumplir todas las características de ésta, y todas las aplicaciones que corran sobre estos dispositivos deben cumplir las restricciones del Perfil que se monta sobre dicha Configuración.

El objetivo de esta diferenciación entre Configuraciones y Perfiles es evitar la fragmentación y limitar en lo posible el número de Configuraciones desarrolladas por los fabricantes. Concretamente, solo existen dos Configuraciones estándar permitidas, que son:

• CLDC (Connected Limited Device Configuration), que abarca el conjunto de los dispositivos móviles personales, tales como teléfonos móviles, PDAs, etc. Implementa una serie de librerías y APIs que no se encuentran en J2SE y que son específicas para este tipo de dispositivos.

• CDC (Connected Device Configuration), que comprende fundamentalmente el conjunto de dispositivos de información compartida, fijos y de conexión permanente, tales como televisores, terminales de comunicación, etc. Incluye un conjunto de librerías mucho mayor que el anterior, siendo CLDC un subconjunto de ésta.

2. J2ME

Francisco Prieto Donate 13

Figura 2.3: Relación J2SE-J2ME

La mayoría de las funcionalidades de CLDC y CDC son heredadas de J2SE, de forma que toda clase perteneciente a CDC y CLDC debe ser exactamente igual a su correspondiente en J2SE o bien un subconjunto de ésta. Pero además ambas configuraciones pueden añadir características que no se encuentren en J2SE y que sean específicas del dispositivo en sí.

2.3.3 Perfiles

Un Perfil de dispositivo es una capa definida sobre una Configuración concreta, de forma que el Perfil extienda las posibilidades de dicha Configuración. Un Perfil está pensado para garantizar la interoperabilidad de una familia vertical de dispositivos, y se compone de una serie de librerías de clases más específicas del dispositivo que las de la Configuración.

Para un dispositivo será posible soportar varios tipos de Perfiles. Algunos de éstos serán específicos del propio dispositivo y otros serán específicos de alguna aplicación que corra sobre el dispositivo. Las aplicaciones son diseñadas para un Perfil concreto y solo podrán funcionar en él y no en otro Perfil, ya que harán uso de las funcionalidades propias de éste. Según esto podemos considerar que un Perfil no es más que un conjunto de librerías de clases que proporciona funcionalidades adicionales a las de las Configuración que reside debajo de él.

Actualmente el único Perfil que existe y está en funcionamiento para la configuración CLDC es MIDP, el cual está pensado para teléfonos móviles.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

14 Francisco Prieto Donate

2.3.4 Capas altas

Sobre las capas anteriores se implementan las distintas aplicaciones que corren sobre el dispositivo. Pueden ser de tres tipos:

• Una aplicación MIDP, también llamada MIDlet, es una aplicación que solamente hace uso de librerías Java definidas por las especificaciones CLDC y MIDP.

• Una aplicación OEM-specific es aquella que no solo utiliza clases propias de MIDP, sino que también hace uso de clases de la especificación OEM (Original Equipment Manufacturer, o fabricante original del equipo). Estas clases normalmente no son portables de un equipo a otro, ya que son propias de cada fabricante.

• Una aplicación Nativa es aquella que no está escrita en lenguaje Java sino que va montada sobre el software nativo del propio equipo.

Figura 2.4: Arquitectura de alto nivel de un dispositivo móvil

2.4 Seguridad

Tanto empresas como usuarios individuales dependen cada vez más de información crítica almacenada en computadoras y redes, por lo que el uso de sistemas y aplicaciones de seguridad se ha convertido en algo extremadamente importante. En el

2. J2ME

Francisco Prieto Donate 15

ámbito de los dispositivos móviles y redes inalámbricas la utilización de sistemas de seguridad resulta esencial.

La plataforma de desarrollo de Java es muy útil en estos aspectos debido a su inherente arquitectura de seguridad. En la plataforma J2SE el modelo de seguridad proporciona a los desarrolladores de aplicaciones funcionalidades con las que crear distintas políticas de acceso y articular permisos independientes para cada usuario.

Desafortunadamente la cantidad de código con el que se consigue este modelo y que se encuentra en la plataforma J2SE excede en mucho las capacidades de memoria de los dispositivos sobre los que trabaja J2ME, por lo que se hacen necesarias una serie de simplificaciones que reduzcan este código pero que mantengan cierta seguridad. El modelo de seguridad definido en CLDC en conjunto con MIDP se basa en tres niveles:

1. Seguridad de bajo nivel: También conocida como seguridad de la máquina virtual. Asegura que un fichero de clase, o un fragmento de código malintencionado no afecte a la integridad de la información almacenada en el dispositivo móvil. Esto se consigue mediante el verificador de ficheros de clase, el cual asegura que los bytecodes almacenados en el fichero de clase no contengan instrucciones ilegales, que ciertas instrucciones no se ejecuten en un orden no permitido y que no contengan referencias a partes de la memoria no válidas o que se encuentren fuera del rango de direccionamiento real. Debido a esto el estándar CLDC exige que bajo él se encuentre una máquina virtual que realice estas operaciones de seguridad.

2. Seguridad de nivel de aplicación: Este nivel de seguridad asegura que las aplicaciones que corren sobre el dispositivo sólo puedan acceder a aquellas librerías, recursos del sistema y otros dispositivos que tanto el equipo como el entorno de aplicación permitan. El verificador de ficheros de clase sólo puede garantizar que la aplicación dada es un programa Java válido. Por lo tanto existen una serie de aspectos que se escapan del control del verificador de clases, como por ejemplo el acceso a recursos externos: ficheros de sistema, impresoras, dispositivos infrarrojos o la red. La seguridad en este nivel se apoya en tres conceptos básicos:

� Modelo Sandbox: En el modelo CLDC y MIDP el nivel de seguridad de aplicación se obtiene mediante un sandbox, un contenedor virtual que asegura un entorno cerrado. En este entorno una aplicación solo puede acceder a aquellas librerías que han sido definidas por la Configuración, el Perfil y las clases específicas OEM del dispositivo. El sandbox asegura que la aplicación no se escape de él y acceda a recursos o funcionalidades no permitidas. Más concretamente el uso de un sandbox asegura que:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

16 Francisco Prieto Donate

� Los ficheros de clases han sido preverificados y las aplicaciones Java son válidas.

� La Configuración, el Perfil y las clases OEM han determinado un conjunto de APIs válidas para la aplicación.

� La descarga y gestión de aplicaciones Java dentro del dispositivo se encuentran en su lugar correcto de almacenamiento, no permitiéndose el uso de clases y aplicaciones de descarga diseñadas por el usuario que podrían dañar a las del sistema.

� El programador de aplicaciones no puede descargar al dispositivo librerías que contengan nuevas funcionalidades nativas o que accedan a funcionalidades nativas no permitidas.

� Protección de clases de sistema: Una de las características del CLDC es la habilidad de soportar la descarga dinámica de aplicaciones a la máquina virtual del dispositivo. Podría existir por tanto una falta de seguridad, ya que una aplicación podría ignorar o sobreescribir ciertas clases del sistema. No obstante, CLDC y MIDP se encargan de que esto no ocurra.

� Restricciones adicionales en la carga dinámica de clases: Existe una restricción de seguridad muy importante en la carga dinámica de clases que consiste en que por defecto una aplicación Java solo puede cargar clases pertenecientes a su Java Archive file (JAR). Esta restricción asegura que las distintas aplicaciones que corran sobre un dispositivo no puedan interferir entre sí.

3. Seguridad punto a punto: Garantiza que una transacción iniciada en un dispositivo móvil se encuentre protegida a lo largo de todo el camino recorrido entre el dispositivo y la entidad proveedora del servicio. Este tipo de seguridad no está recogida en el CLDC ni en el MIDP, por lo que será siempre una solución propietaria del fabricante y del proveedor de servicios.

2.5 Objetivos, requisitos y alcance de J2ME

Desde el principio todo el diseño de la tecnología J2ME ha pretendido lograr una serie de objetivos muy concretos para facilitar un funcionamiento adecuado a los dispositivos sobre los que se va a montar. Con el fin de conseguir una cierta

2. J2ME

Francisco Prieto Donate 17

portabilidad ha sido necesario además establecer una serie de requerimientos mínimos que deben cumplir los dispositivos con soporte J2ME.

2.5.1 Objetivos

Todos los objetivos que la tecnología J2ME ha conseguido hacen que despierte un gran interés, por ello resulta interesante conocer algunas de sus características:

• Reparto dinámico de contenidos y aplicaciones Java: Uno de los grandes beneficios que aporta la tecnología Java a estos dispositivos de reducidas prestaciones es el reparto dinámico y con total seguridad de servicios interactivos y aplicaciones sobre diferentes redes lo cual se consigue gracias al CLDC y al MIDP. Desde que aparecieron los primeros teléfonos móviles y hasta el día de hoy en el que el uso de Internet está mundialmente extendido, los fabricantes han intentado diseñar dispositivos con mayores posibilidades de comunicación y con mayores facilidades en lo que concierne al desarrollo de aplicaciones, motivo que impulsó el despliegue de esta tecnología.

• Desarrollo de aplicaciones Third-party: El enfoque de J2ME en cuanto al reparto dinámico de aplicaciones que CLDC y MIDP aportan no favorece únicamente a los diseñadores y a los fabricantes de equipos y sus programadores de aplicaciones, sino también a los diseñadores de aplicaciones independientes o third-party. Se prevé que una vez que los dispositivos portátiles sean de uso de común e imprescindible para el usuario serán los desarrolladores third-party los que abarcarán todo el mercado de diseño de aplicaciones J2ME, por eso en CLDC y MIDP se han incorporado una serie de librerías que favorezcan a estos desarrolladores en sus diseños.

• Independencia de las tecnologías estándar de comunicación: Existe un amplio rango de tecnologías de comunicación inalámbrica actualmente en uso por todo el mundo, las cuales varían entre sí respecto de niveles de sofisticación, compatibilidad e interoperabilidad. En la Segunda Generación (2G) destacan, entre otras, tecnologías tales como GSM, TDMA o CDMA. La tecnología 2,5G, a caballo entre 2G y 3G, cuenta con GPRS, EDGE, CDPD, etc. En la actual Tercera Generación (3G) tenemos W-CDMA, CDMA2000 y TD-SCDMA. Y en la recién llegada 3,5G podemos hablar de HSDPA. Debido al gran número de tecnologías existentes, cada una con sus características propias e incompatibles con las demás, J2ME se ha esforzado en definir una serie de soluciones que se adapten a todas ellas de forma estándar. Esto se ha conseguido huyendo de aquellas APIs que solo puedan ser encuadradas en un tipo de tecnología, así como realizando soluciones que se adapten tanto a las características de ancho de banda de comunicación actual como a las futuras características de comunicación de banda ancha.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

18 Francisco Prieto Donate

• Compatibilidad con otros estándares inalámbricos: Una característica muy interesante de J2ME es que no es una nueva tecnología inalámbrica que viene a desbancar a las demás ya existentes, sino que puede ser utilizada para favorecer y mejorar a estas otras tecnologías. Así teléfonos móviles provistos de las tecnologías WAP o i-Mode pueden mejorar sus posibilidades gracias a J2ME, ya que se puede utilizar código Java para ampliar, por ejemplo, la funcionalidad de los navegadores Web.

2.5.2 Requisitos

Los estándares CLDC y MIDP exigen una serie de requisitos tanto hardware como software a cumplir por los dispositivos sobre los que se montan aplicaciones J2ME.

• Requisitos CLDC

CLDC tiene en cuenta la gran cantidad de dispositivos existentes en el mercado así como de las grandes diferencias existentes entre éstos, por ello solo se imponen restricciones respecto de la capacidad de memoria. Considerando que la KVM, las librerías de Configuración y de Perfil y las aplicaciones corriendo sobre el dispositivo sólo deben ocupar entre 160 y 512 KB, se exigen al menos 128 KB de memoria no volátil para la KVM y las librerías, y al menos 32 KB de memoria volátil para la KVM en funcionamiento.

En lo concerniente al software ocurre algo parecido: debido a la gran diversidad de software nativos que pueden correr en el dispositivo, el CLDC sólo exige la existencia de un software muy sencillo, tal que cuente con una entidad de control de programas para que pueda correr la KVM. No es necesario que dé soporte para espacios de direccionamiento separados para cada proceso ni tampoco que ofrezca garantías de un buen funcionamiento en tiempo real.

• Requisitos MIDP

Los requisitos exigidos por el MIDP son algo más estrictos, ya que debe tratar aspectos complejos tales como la presentación en pantalla. De esta forma se exigen 128 KB de memoria no volátil para componentes MIDP, 8 KB de memoria no volátil para almacenamiento de datos de aplicación de forma persistente y 32 KB de memoria volátil para la KVM en ejecución. Los requisitos en el display del equipo son un tamaño de 96 x 54 mm2, una profundidad de 1 bit y una relación de aspecto en el display de 1:1. La interfaz de entrada debe tener al menos uno de los siguientes mecanismos: pantalla táctil o teclado a una o dos manos. En lo relativo a la red se

2. J2ME

Francisco Prieto Donate 19

pide una conexión bidireccional inalámbrica con un ancho de banda limitado que puede ser intermitente.

En lo referente al software, MIDP exige varias características: la existencia de un kernel mínimo que controle el hardware y proporcione la entidad de control de programas anteriormente mencionada, un mecanismo de lectura/escritura de memoria no volátil para dar soporte a las APIs de almacenamiento de datos persistentemente, un mecanismo de lectura/escritura para dar soporte a las APIs de red, un mecanismo que proporcione soporte de temporización, una capacidad mínima para escribir en la pantalla del dispositivo y un mecanismo para capturar la entrada de datos por parte del usuario.

2.5.3 Alcance

Basado en la especificación JSR-30 (CDLC 1.0), tanto CLDC como MIDP tienen definidos una serie de alcances o aspectos que pueden abarcar.

• Alcance CLDC

La especificación del CLDC indica que los campos que este estándar cubre son los siguientes:

1. Lenguaje Java y características de la KVM

2. Librerías básicas: java.lang.*, java.io.*, java.util.*.

3. Entrada/salida

4. Red

5. Seguridad

• Alcance MIDP

De todas las posibles funcionalidades que se pueden encontrar en un dispositivo, el MIDP Expert Group decidió abarcar en MIDP solo aquellas que realmente aseguren la portabilidad:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

20 Francisco Prieto Donate

1. Modelo de Aplicación: estructura que debe seguir una aplicación

2. Interfaz de usuario, tanto pantalla como entrada de datos.

3. Almacenamiento persistente de datos

4. Red

5. Temporización

2.6 CLDC (Connected Limited Device Configuration)

El objetivo del CLDC es definir una plataforma Java para dispositivos pequeños y de reducidas prestaciones:

• De 160 a 512 KB de memoria

• Procesador de 16-32 bits

• Bajo consumo de la batería de alimentación

• Conexión a redes inalámbricas, de forma intermitente y de ancho de banda reducido (normalmente 9600 bps o menos)

En este grupo de dispositivos podemos incluir a los teléfonos móviles, PDAs y terminales punto de venta.

En la actualidad existen dos versiones de CLDC, la 1.0 y la 1.1. En adelante, cuando hablemos de CLDC nos estaremos refiriendo a la versión 1.0. Una vez explicadas las características de CLDC 1.0, pasaremos a ver las novedades que aporta la versión 1.1.

2. J2ME

Francisco Prieto Donate 21

2.6.1 CLDC Expert Group

La especificación del CLDC ha sido desarrollada por el Sun’s Java Community Process (JCP) y el resultado se encuentra en la norma JSR-30. Este grupo de fabricantes y desarrolladores de software está formado por las siguientes empresas:

• America Online • Bull • Ericsson • Fujitsu • Matsushita • Mitsubishi • Motorola • Nokia • NTT DoCoMo

• Oracle • Palm Computing • Research In Motion • Samsung • Sharp • Siemens • Sony • Sun Microsystems • Symbian

2.6.2 Modelo de Aplicación de CLDC

2.6.2.1 Arquitectura

Tal y como se comentó anteriormente, la arquitectura que se sigue en J2ME se divide en tres capas. La primera es la llamada Host Operating System, que se encarga de proporcionar la capacidad de controlar el hardware subyacente. Sobre ésta se encuentra el CLDC, el cual tiene en su interior la máquina virtual y una serie de librerías con los que damos al móvil la posibilidad de trabajar con lenguaje Java corriendo sobre una máquina virtual Java. Como última capa tenemos el Perfil MIDP, el cual aporta un conjunto de librerías que completan a las del CLDC.

Para el CLDC el concepto de aplicación Java se refiere a una colección de ficheros de clases Java que contienen un único método public static void main (String[] args) e identifica el punto de lanzamiento de la aplicación. De esta forma la máquina virtual iniciará la ejecución de la aplicación llamando a este método.

Figura 2.5: Modelo de capas de J2ME

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

22 Francisco Prieto Donate

2.6.2.2 Gestor de aplicaciones

Con el fin de poder mantener almacenadas las aplicaciones dentro del dispositivo para posteriormente ser ejecutadas desde memoria existe el denominado gestor de aplicaciones. Este gestor suele estar programado en lenguaje C o bien en cualquier lenguaje de bajo nivel que controle al hardware y que sea dependiente de él, pero nunca en lenguaje Java, ya que la realización de estas operaciones es tarea del propio dispositivo, y por tanto está fuera del alcance de J2ME. El gestor de aplicaciones es el encargado de realizar las siguientes operaciones:

• Descargar e instalar aplicaciones Java

• Inspeccionar la existencia de aplicaciones Java almacenadas en el dispositivo

• Seleccionar y lanzar aplicaciones Java

• Borrar de memoria aplicaciones Java almacenadas en el equipo

2.6.3 Compatibilidad con JavaTM Virtual Machine Specification

Debido a las fuertes restricciones de memoria que se dan en los dispositivos con los que trabaja J2ME, existen ciertas diferencias entre la maquina virtual definida en J2SE y la máquina virtual que proporciona CLDC. En esta última se observan una serie de limitaciones a la hora de desarrollar aplicaciones.

• Inexistencia de punto flotante: Debido a que la mayoría de dispositivos hardware subyacentes no soportan por sí mismos numeración en punto flotante, tendría que conseguirse ésta mediante el software, pero debido a las fuertes restricciones de capacidad de memoria el CLDC Expert Group decidió no implementarlo en el estándar. De esta forma, toda clase y método de usuario debe cumplir las siguientes reglas:

1. Ningún campo puede tener los tipos float, double, array, o array de arrays de estos tipos.

2. Ningún método puede tener como argumento o como tipo devuelto float, double, array, o array de arrays de estos tipos.

2. J2ME

Francisco Prieto Donate 23

3. Ninguna constante puede ser de tipo float o double.

• Inexistencia de Java Native Interface (JNI): La forma en que la máquina virtual del CLDC invoca una funcionalidad nativa es dependiente del dispositivo. El motivo por el que se ha eliminado esta funcionalidad es la falta de capacidad de memoria y que el CLDC asume que el conjunto de funciones nativas es cerrado por motivos de seguridad.

• Inexistencia clases y programas diseñados por el usuario de carga de aplicaciones: La propia máquina virtual diseñada por el CLDC tiene ya cargador de clases que por motivos de seguridad no se puede sobrescribir o sustituir por una solución de usuario.

• Inexistencia de reflexión: No existen en la máquina virtual del CLDC funcionalidades de reflexión que permitirían a las aplicaciones Java inspeccionar el número y contenido de clases, objetos, métodos, campos, hilos y demás características de ejecución en el interior de la máquina virtual. De esta forma no será posible implementar Remote method invocation (RMI), serialización de objetos, JVMDI (Debbugging Interface), JVMPI (Profiler Interface), etc.

• Inexistencia de Grupos de hilos e hilos demonio: No se permite el uso de hilos demonio ni de grupos de hilos. Los hilos solo podrán ser lanzados y parados uno a uno.

• Inexistencia de finalización: En las librerías del CLDC no aparece el método java.lang.Object.finalize(), por lo que no hay soporte para finalización de instancias de clases.

• Limitaciones en la captura de errores: La máquina virtual del CLDC soporta el lanzamiento y captura de excepciones. No obstante, existe una gran limitación en el conjunto de clases de errores permitidas respecto de las que se dan en J2SE. Esto es debido a dos aspectos: por un lado que los propios dispositivos reaccionan de forma distinta a los errores (algunos sencillamente resetean mientras que otros intentan recuperarse), por otro lado la implementación de la gran riqueza de lanzamientos y capturas de errores que se da en J2SE es extremadamente costoso en términos de memoria, lo que supondría la necesidad de una gran cantidad de espacio.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

24 Francisco Prieto Donate

2.6.4 Verificación de ficheros de clase

Al igual que la máquina virtual de J2SE, la máquina que implementa el CLDC debe ser capaz de detectar ficheros de clases no válidas. No obstante, como las necesidades de memoria serían excesivas si implementásemos la solución que aporta J2SE, se ha desarrollado una solución alternativa.

El espacio en memoria que se necesitaría si usásemos la solución aportada por J2SE sería de un mínimo de 50 KB sólo para el verificador de clases y al menos de 20 a 100 KB de memoria RAM para ejecución. La potencia de cálculo de la CPU debería ser además bastante alta. En cambio, la solución aportada por CLDC solamente toma 12 KB para la verificación y al menos 100 Bytes de memoria RAM para ejecución.

El nuevo verificador pensado para CLDC solamente realiza un escaneo lineal de bytecodes y se fundamenta en dos fases:

• Una primera fase en la que los ficheros de clases se hacen pasar por una herramienta de preverificación con el fin de completar dichos ficheros con información adicional que permita realizar la verificación a mayor velocidad y con menor carga de trabajo. Este proceso se realiza en la estación de trabajo en la que se esté diseñando la aplicación mediante emuladores de dispositivo.

• La segunda fase se da en ejecución, momento en el que el verificador en tiempo de ejecución de la máquina virtual utiliza la información adicional que el preverificador añadió para verificar por completo los ficheros de clase.

Figura 2.6: Verificación de clases

2. J2ME

Francisco Prieto Donate 25

La interpretación de los bytecodes del fichero de clases podrá comenzar únicamente cuando el fichero de clases haya pasado correctamente la verificación.

Puesto que el preverificador añade a los ficheros de clases una serie de atributos adicionales podría pensarse que dichos ficheros, tras sufrir el proceso de preverificación, dejarían de ser compatibles con el verificador del estándar J2SE. Esto no es lo que ocurre en realidad, ya que el verificador J2SE ignora automáticamente dichos atributos añadidos, manteniéndose por tanto la compatibilidad con el estándar.

2.6.5 Librerías de CLDC

Tanto J2SE como J2EE cuentan con unas librerías de funciones muy ricas con funcionalidades que sacan todo el provecho de las estaciones de trabajo sobre las que se montan. Desafortunadamente en J2ME no ocurre lo mismo debido al escaso espacio de almacenamiento con el que cuentan los dispositivos.

Las librerías que se han desarrollado para J2ME cuentan con un número mínimo de funciones, pero debido al gran número de dispositivos existentes en el mercado es totalmente imposible contar con librerías que cubran todas las necesidades de todos los dispositivos en tan reducido espacio de almacenamiento. Aún así se han conseguido una serie de funcionalidades bastante útiles para todos ellos.

Con el fin de asegurar compatibilidad entre las librerías de J2ME y de sus homólogos J2SE y J2EE, la mayoría de las librerías del CLDC son un subconjunto de las que se dan en J2SE y J2EE. Las librerías definidas en el CLDC se pueden dividir en dos categorías:

• Clases derivadas del J2SE

Estas clases son un subconjunto de las existentes en las librerías del J2SE, todas tienen el mismo nombre que se les daba en J2SE y pertenecen a paquetes del mismo nombre que en el J2SE. Los paquetes en los que se encuentran son java.lang, java.util, java.io:

1. Clases de sistema

java.lang.Object java.lang.Class java.lang.Runtime java.lang.System java.lang.Thread

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

26 Francisco Prieto Donate

java.lang.Runnable java.lang.String java.lang.StringBuffer java.lang.Throwable

2. Clases de tipos de datos

java.lang.Boolean java.lang.Byte java.lang.Short java.lang.Integer java.lang.Long java.lang.Character

3. Clases de Colecciones de objetos

java.util.Vector java.util.Stack java.util.Hashtable java.util.Enumeration

4. Clases de Entrada/Salida

java.io.InputStream java.io.OutputStream java.io.ByteArrayInputStream java.io.ByteArrayOutputStream java.io.DataInput java.io.DataOutput java.io.DataInputStream java.io.DataOutputStream java.io.Reader java.io.Writer java.ioInputStreamReader java.ioOutputStreamReader java.ioPrintStream

5. Clases de Temporización y Calendario

java.util.Calendar java.util.Date java.util.TimeZone

6. Clases de Adicionales

2. J2ME

Francisco Prieto Donate 27

java.util.Random java.util.Math

7. Clases de Errores

java.lang.Error java.lang.VirtualMachineError java.lang.OutOfMemoryError

8. Clases de Excepciones

java.lang.Exception java.lang.ClassNotFoundException java.lang.IlegalAccesException java.lang.InstantiationException java.lang.InterruptedException java.lang.RuntimeException java.lang.ArithmeticException java.lang.ArrayStoreException java.lang.ClassCastException java.lang.IlegalArgumentException java.lang.IlegalThreadStateException java.lang.NumberFOrmatException java.lang.IlegalMonitorStateException java.lang.IndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException java.lang.StringIndexOutOfBoundsException java.lang.NegativeArraySizeException java.lang.NullPointerException java.lang.SecurityException java.util.EmptyStackException java.util.NoSuchElementException java.io.EOFException java.io.IOException java.io.InterruptedIOException java.io.UnsupportedEncodingException java.io.UTFDataFormatException

• Clases específicas del CLDC

Las clases específicas del CLDC tienen como objetivo permitir una serie de funcionalidades que el dispositivo puede realizar y que las clases anteriores no implementan. Estas clases se encuentran en el paquete javax.microedition.

El conjunto de librerías que existen en J2SE y J2EE enfocadas a dar funcionalidades de entrada y salida de datos desde y hacia redes es extremadamente rico: tan solo el paquete java.io de J2SE cuenta con 60 clases e interfaces y más de 15

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

28 Francisco Prieto Donate

excepciones, y el paquete java.net cuenta con unas 20 clases y unas 10 excepciones. Para almacenar todas estas clases se necesitan aproximadamente 200 KB, cantidad de memoria imposible de alcanzar en un dispositivo móvil. Debido a ello no es posible reaprovechar dichas librerías y por tanto hay que diseñar todo un conjunto de librerías propias del J2ME que aporten estas características. Teniendo en cuenta que no todas las funcionalidades de red son aplicables a los dispositivos móviles y que los fabricantes no hacen uso del amplio rango de posibles comunicaciones en red existentes (en la mayoría de los casos estos dispositivos no cuentan con soporte TCP/IP o incluso se restringen a ciertos protocolos como IrDA o Bluetooth), el problema se simplifica enormemente.

De esta forma, en el CLDC de J2ME se rediseñaron las clases para entrada/salida y para el soporte a conexiones de red de J2SE, definiendo lo que se denomina CLDC Generic Connection Framework. El CLDC Generic Connection Framework define una serie de interfaces para dar soporte a la variedad de tipos de conexiones que nos podemos encontrar en dispositivos móviles, pero no implementa ninguna de ellas, sino que es en los perfiles donde se debe realizar esta implementación.

� Objeto javax.microedition.io.Connector

En este objeto reside una interfaz en la que J2ME encapsula las conexiones a red. Dependiendo del dispositivo y de la red a la que se conecta será necesario un protocolo u otro. En este objeto el Generic Connection Framework puede encapsular cualquiera de las posibles conexiones que se puedan dar. Indistintamente del tipo que sea, el Generic Connection Framework se encarga de asegurar compatibilidad.

El Generic Connection Framework es implementado según una jerarquía de interfaces de conexión encapsuladas en el objeto Connection, que suman en total seis tipos: una entrada serie, una salida serie, una conexión orientada a datagrama, una conexión orientada a circuito, un mecanismo de notificación de conexiones y una conexión a un servidor Web:

Figura 2.7: Jerarquía de la interfaz de conexión

2. J2ME

Francisco Prieto Donate 29

� Métodos

Sobre el objeto Connector existen una serie de métodos con los cuales es posible hacer uso de las distintas funcionalidades de comunicación que permite J2ME.

Con el método public void open(“<protocol> : <address> ; <parameters>”) es posible abrir y establecer una comunicación. Cuenta con la ventaja de permitir varios protocolos de comunicación, no solo los protocolos que ya se están utilizando, sino que está preparado para adaptarse a los nuevos posibles protocolos que puedan llegar en el futuro. Así algunos ejemplos son:

HTTP Connector.open(“http://www.sun.com”); Sockets Connector.open(“socket://129.144.111.222:2800”); Comunicación por puertos Connector.open(“comm:0;baudrate=9600”); Datagramas Connector.open(“datagram://129.144.111.222:2800”); Ficheros Connector.open(“file:/foo.dat”);

Las principales interfaces, con sus métodos correspondientes, son:

Interfaz Connection public void close() throws IOException Interfaz InputConnection public InputStream openInputStream() throws IOException public DataInputStream openDataInputStream() throws IOException Interfaz OutputConnection public OutputStream openOutputStream() throws IOException public DataOutputStream openDataOutputStream() throws IOException Interfaz Connection public String getType() public String getEncoding() public long getLength() Interfaz StreamConnectionNotifier public StreamConnection acceptAndOpen() throws IOException Interfaz DatagramConnection public int getMaximumLength() throws IOException public int getNominalLength() throws IOException public void send(Datagram datagram) throws IOException public void receive(Datagram datagram) throws IOException public Datagram newDatagram(int size) throws IOException

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

30 Francisco Prieto Donate

public Datagram newDatagram(int size, String addr) throws IOException public Datagram newDatagram(byte[] buf, int size) throws IOException public Datagram newDatagram(byte[] buf, int size, String addr) throws IOException

2.6.6 CLDC 1.1

CLDC 1.1 es una revisión de la especificación CLDC 1.0 e incluye nuevas características como son punto flotante o soporte a referencias débiles, junto con otras mejoras. CLDC 1.1, especificado en la norma JSR-139, es compatible con versiones anteriores y sigue soportando dispositivos pequeños o con recursos limitados.

A continuación se detallan las mejoras que introduce CLDC 1.1:

• Se añade soporte para operaciones en punto flotante, permitiendo el uso de todos los bytecodes asociados al mismo.

• Se añaden las clases Float y Double.

• Se añaden métodos a otras librerías para la gestión de operaciones en punto flotante.

• Se añade soporte para referencias débiles.

• Se han rediseñado las clases Calendar, Date y TimeZone para adecuarse mejor a J2SE.

• La gestión de errores se ha mejorado y se ha añadido una nueva clase de error, NoClassDefFoundError.

• Los objetos Thread tienen nombre con los subprocesos en J2SE. Se ha introducido el método Thread.getName() y la clase Threadclass incorpora nuevos constructores heredados de J2SE.

• Se han cambiado bibliotecas y se han corregido algunos defectos, entre los que se incluyen los siguientes métodos y campos:

2. J2ME

Francisco Prieto Donate 31

� Boolean.TRUE y Boolean.FALSE

� Date.toString()

� Random.nextInt(int n)

� String.intern()

� String.equalsIgnoreCase()

� Thread.interrupt()

• Se ha elevado el mínimo de memoria necesaria de 160 a 192 KB, debido principalmente a la adición de funcionalidad de punto flotante.

• Se ha mejorado y actualizado la especificación.

• Se ha detallado la especificación del verificador de bytecode para CLDC (CLDC Byte Code Typechecker Specification).

2.7 MIDP (Mobile Information Device Profile)

El estándar MIDP es una arquitectura y un conjunto de librerías que aportan un entorno de desarrollo de aplicaciones abiertas Third-Party para dispositivos móviles de información (MIDs). Ejemplos típicos de dispositivos MIDP son teléfonos móviles, PDAs con conexión inalámbrica, etc.

Actualmente existen dos versiones de este Perfil: la especificación MIDP 1.0 y la versión revisada MIDP 2.0. En adelante cuando hablemos de MIDP nos estaremos refiriendo a la primera versión. Posteriormente veremos las mejoras que aporta la especificación MIDP 2.0.

El conjunto mínimo de requisitos que debe cumplir cualquier dispositivo sobre el que se quiera implementar MIDP es el siguiente:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

32 Francisco Prieto Donate

• Memoria: 128 KB de memoria no volátil para los componentes MIDP, 8 KB de memoria no volátil para datos de aplicaciones almacenados de forma persistente y 32 KB de memoria volátil para la ejecución de la máquina virtual.

• Pantalla: Tamaño de pantalla: 96 x 54 píxeles, profundidad de display de 1 bit y relación de aspecto 1:1.

• Interfaz de entrada: Al menos uno de los siguientes mecanismos: teclado a una mano, teclado a dos manos, pantalla táctil.

• Red: Conexión bidireccional, inalámbrica, posiblemente intermitente y con ancho de banda limitado.

2.7.1 MIDP Expert Group

La MIDP Specification fue producida por el MIDPEG (Mobile Information Device Profile Expert Group) como parte del Java Community Process (JCP) en la norma de estandarización JSR-37. Este grupo está formado por un conjunto de empresas:

• America Online • DDI • Ericsson • Espiral Group • Fujitsu • Hitachi • J-Phone • Matsushita • Mitsubishi • Motorola • NEC

• Nokia • NTT DoCoMo • Palm Computing • Research In Motion • Samsung • Sharp • Siemens • Sony • Sun Microsystems • Symbian • Telecordia Technologies

El MIDP ha sido diseñado para extender las funcionalidades del CLDC. De esta forma la especificación MIDP define una serie de APIs que añaden un conjunto mínimo de funciones comunes a los distintos tipos de dispositivos MIDP:

• Soporte de interfaz de usuario: LCDUI (Limited Connected Device User Interface)

2. J2ME

Francisco Prieto Donate 33

• Soporte de red, basado en el protocolo HTTP y en el Generic Connection Framework introducido por el CLDC

• Soporte de almacenamiento persistente de datos: RMS (Record Management System)

• Una serie de clases adicionales de interesante utilidad como temporizadores y excepciones.

2.7.2 Modelo de Aplicación de MIDP

Debido a las fuertes restricciones de memoria con las que se enfrenta y a los requisitos exigidos por el estándar, MIDP no soporta el modelo de Applet introducido en el J2SE, sino que utiliza un nuevo modelo de aplicación gráfica que permite compartir e intercambiar datos entre aplicaciones, así como un funcionamiento concurrente sobre la KVM.

En el MIDP la unidad mínima de ejecución es el MIDlet, el cual no es más que una clase que extiende a la clase javax.microedition.MIDlet.

A continuación se muestra la implementación del MIDlet más sencillo posible, el clásico “Hola Mundo”:

import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class HolaMundo extends MIDlet implements CommandListener{ private TextBox tb; private Command Salir; public HolaMundo(){ tb = new TextBox("Hola MIDlet", "Hola Mundo!", 15, 0); Salir = new Command ("Salir", Command.EXIT, 1); tb.addCommand(Salir); tb.setCommandListener(this); } protected void startApp(){ Display.getDisplay(this).setCurrent(tb); } protected void pauseApp(){} protected void destroyApp(boolean u){} public void commandAction(Command c, Displayable s){ if(c == Salir){

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

34 Francisco Prieto Donate

destroyApp(false); notifyDestroyed(); } }

}

La salida de este sencillo código ejemplo se muestra en la figura:

Figura 2.8: Salida del MIDlet Hola Mundo

El estado en el cual se encuentra el MIDlet en esta figura es tal que el método startApp acaba de terminar su ejecución. Si en este momento pulsásemos el botón superior izquierdo del teclado del móvil se invocaría al método commandAction y éste, al detectar el comando ejecutado, llamaría al método destroyApp y al método notifyDestroyed.

En este ejemplo se encuentran un conjunto de elementos típicos de todos los MIDlets:

• En primer lugar la clase HolaMundo extiende a la clase javax.microedition.midlet.MIDlet.

• En segundo lugar, la clase HolaMundo cuenta con un constructor que en el modelo de aplicación del MIDP se ejecuta una sola vez, exactamente al instanciar el MIDlet. Por lo tanto, todas aquellas operaciones que queramos que se realicen al lanzar el MIDlet por primera vez se deben encontrar en este constructor.

2. J2ME

Francisco Prieto Donate 35

• La clase javax.microedition.midlet.MIDlet define tres métodos abstractos que deben ser sobrescritos en todos los MIDlets, estos métodos son: startApp, pauseApp y destroyApp.

El método startApp es ejecutado al arrancar y rearrancar el MIDlet. Su función es la de adquirir (al arrancar por primera vez) o readquirir (al reanudar tras una pausa) una serie recursos necesarios para la ejecución. Este método puede ser llamado más de una vez, bien sea al arrancar el MIDlet por primera vez o cada vez que se quiera reanudar al MIDlet tras una pausa.

El método pauseApp es llamado por el sistema con el fin de parar momentáneamente al MIDlet, liberando así durante la pausa una serie de recursos que puedan ser usados en ese tiempo por otros MIDlets.

Por último, el método destroyApp es llamado por el sistema cuando el MIDlet está a punto de ser destruido. También puede ser llamado indirectamente por el propio MIDlet mediante el método notifyDestoyed. Este método juega un papel muy importante, ya que es el encargado de liberar definitivamente todos aquellos recursos que el MIDlet ha tomado y ya no necesitará después de ser destruido.

Debido a la existencia de estos tres métodos, un MIDlet puede pasar por una serie de estados diferentes a lo largo de su ejecución, dándose en cada estado una serie de procesos sobre dicho MIDlet y pasando de un estado a otro mediante cada uno de estos métodos. Gráficamente es sencillo entender estas transiciones:

Figura 2.9: Estados y transiciones de un MIDlet

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

36 Francisco Prieto Donate

Como podemos ver en la figura, un MIDlet puede encontrarse en tres posibles estados:

• Parado: Un MIDlet se encuentra en estado parado cuando está a punto de ser arrancado pero aún no ha sido ejecutado el método startApp, o también como resultado de pauseApp o notifyPaused. En este estado el MIDlet debería ya haber acaparado tantos recursos como le sean necesarios. Además en este estado pueden también recibirse notificaciones asíncronas.

• Activo: Un MIDlet entra en estado activo mediante el método startApp o bien desde el estado parado mediante la ejecución del método resumeRequest. En este estado el MIDlet puede acaparar y emplear todos aquellos recursos que necesite para realizar una ejecución óptima.

• Destruido: El MIDlet se encuentra en estado destruido cuando vuelve de los métodos destroyApp o notifyDestroyed. Tras llegar a este punto, el MIDlet no puede pasar a ningún otro estado.

Para pasar de un estado a otro existen una serie de métodos que hacen posibles las distintas transiciones del MIDlet. Ya hemos comentado los métodos startApp, pauseApp y destroyApp, que son llamados por el sistema de forma automática. Existen también una serie de métodos que realizan estas transiciones y que en su caso son utilizados por el programador de la aplicación con la intención de forzar dichas transiciones cuando sea conveniente. Estos métodos son:

• resumeRequest: Este método puede ser llamado por un MIDlet parado para indicar su intención de volver a estar activo. Un ejemplo típico es el caso del cumplimiento de un temporizador el cual necesite reanudar la aplicación para continuar con la ejecución del MIDlet.

• notifyPaused: Éste permite al MIDlet indicarle al sistema que voluntariamente se ha pasado a estado parado. Un ejemplo de uso sería el del inicio de cuenta de un temporizador cuando resulte conveniente liberar una serie de recursos para que otras aplicaciones los usen. Cuando dicho temporizador cumple se pasa de nuevo a ejecución.

• notifyDestroyed: Con este método la aplicación puede indicarle al sistema que ya ha liberado todos los recursos y ha almacenado todos los datos convenientemente y por tanto se va a pasar a estado parado.

2. J2ME

Francisco Prieto Donate 37

2.7.3 MIDlet Suites

Uno de los principales objetivos del Modelo de Aplicación del MIDP es dar soporte para compartir datos y recursos entre varios MIDlets que incluso podrían estar funcionando simultáneamente. Para conseguir esto todos aquellos MIDlets que quieran compartir datos y recursos deben encapsularse en un mismo fichero JAR. Este fichero es lo que se llama un MIDlet Suite. Todos los MIDlets que se encuentren dentro de este MIDlet Suite comparten un espacio común de nombres para almacenamiento persistente de datos y un mismo conjunto de clases y campos estáticos. Con el fin de mantener la seguridad, el MIDlet Suite es tratado como un “todo”, de forma que ningún elemento de éste puede ser instalado, actualizado o eliminado individualmente.

El contenido del fichero JAR que contiene al MIDlet Suite es el siguiente:

• Los ficheros de clases que implementan los distintos MIDlets.

• Los distintos recursos utilizados por estos MIDlets, tales como iconos o ficheros de imagen, por ejemplo.

• Un manifiesto que describa el contenido del JAR.

El manifiesto proporciona un mecanismo de información acerca del contenido del fichero JAR por medio de una serie de atributos de los cuales unos están reservados para el MIDP Expert Group (son los que sus nombres empiezan por MIDlet-) y otros son atributos propios de los desarrolladores de MIDlet Suites.

Dentro del manifiesto deben ir obligatoriamente los siguientes atributos:

� MIDlet-Name

� MIDlet-Version

� MIDlet-Vendor

� MIDlet-<nombre>, uno por cada MIDlet

� MicroEdition-Profile

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

38 Francisco Prieto Donate

� MicroEdition-Configuration

Además del fichero JAR existe el application descriptor, de carácter opcional, que se encarga de verificar que su MIDlet Suite asociado se ajusta convenientemente al dispositivo sobre el que será descargado desde la estación de trabajo donde se está desarrollando la aplicación. Este fichero tiene la extensión .jad y sigue una sintaxis muy concreta. Debe contener los siguientes atributos:

� MIDlet-Name

� MIDlet-Versión

� MIDlet-Vendor

� MIDlet-Jar-URL

� MIDlet-Jar-Size

2.7.4 Librerías de MIDP

Teniendo en cuenta el gran número de restricciones con las que cuentan los dispositivos sobre los que se monta J2ME es conveniente tener en mente una serie de requisitos a la hora de diseñar el conjunto de librerías con las que contará:

• Los equipos y aplicaciones tienen que ser de fácil manejo para los usuarios, que no necesariamente serán expertos en el uso de computadores.

• Estos equipos y aplicaciones deben ser de fácil utilización en situaciones comprometidas en las que el usuario no pueda poner total atención, situaciones como estar conduciendo, cocinando, etc.

• La forma e interfaz de usuario varía considerablemente de un equipo a otro.

• Las aplicaciones Java para móviles deben tener interfaces de usuario compatibles con las de las aplicaciones nativas de forma que los usuarios las encuentren fáciles de usar.

2. J2ME

Francisco Prieto Donate 39

Dados estos requisitos el MIDP Expert Group decidió que el API AWT (Abstract Windowing Toolkit) proporcionado por J2SE no fuese utilizado para los dispositivos con los que trata J2ME. Los motivos fueron varios:

• AWT fue diseñado expresamente para ordenadores de sobremesa, por lo que existen una serie de características no compatibles con los dispositivos con los que tratamos.

• AWT necesita de un complejo mecanismo de recolección de basura para eliminar todos aquellos elementos que no se estén utilizando. Esta recolección de basura no se ha implementado en J2ME.

• Por último, AWT desarrolla su diseño pensando en que el usuario hará uso de las posibilidades gráficas que se le presentan mediante un puntero como el del ratón, pero en los dispositivos del J2ME muy pocos cuentan con este puntero, sino que trabajan directamente con las flechas de dirección de un teclado reducido.

2.7.4.1 Librerías de la Interfaz Gráfica de Usuario

La principal abstracción en la interfaz de usuario es el objeto Displayable (visible) perteneciente al paquete javax.microedition.lcdui el cual encapsula los distintos gráficos que se presentan por pantalla.

La visualización de un MIDlet es controlada por un objeto de tipo Displayable, de modo que para ser visible por pantalla un MIDlet debe crear un objeto que derive de la clase Displayable. Esta clase será entonces la responsable de dibujar la pantalla correspondiente. Para que un objeto Displayable sea visible, se debe invocar al método void setCurrent(Displayable next).

Todo MIDlet debe poseer al menos una instancia del objeto Display para gestionar lo que muestra la pantalla del dispositivo. Para obtenerla empleamos el siguiente código: Display display = Display.getDisplay(this). La clase Display incluye una serie de métodos útiles para gestionar lo que se va a presentar en la pantalla del dispositivo, así como la interacción con el usuario.

Gráficamente podemos ver la jerarquía de clases derivadas de Display:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

40 Francisco Prieto Donate

Figura 2.10: Jerarquía de clases de la interfaz de usuario de MIDP

Existen dos tipos de objetos Displayable:

• Canvas: Objeto de bajo nivel que permite al programador tener un control total de lo que aparecerá por pantalla.

• Screen: Objeto de alto nivel que encapsula una interfaz de usuario completa.

En cualquier aplicación estos dos tipos de objetos pueden combinarse sin ningún tipo de problemas.

2.7.4.1.1 Interfaz de usuario de Bajo Nivel

El API de la interfaz de usuario de bajo nivel está especialmente diseñado para aplicaciones que necesitan un control preciso de los elementos gráficos en la pantalla. Ejemplos típicos de esto serían aplicaciones de dibujo de gráficos por parte del usuario, juegos, etc.

Con este API podemos controlar varios aspectos, tales como:

• Control de lo que se está dibujando en la pantalla.

• Captura de eventos primitivos tales como pulsación de teclas concretas del teclado.

2. J2ME

Francisco Prieto Donate 41

• Acceso a otras vías de entrada de datos.

A la hora de realizar cualquier gráfico sobre la pantalla mediante el API de bajo nivel necesitamos de un sistema de coordenadas, el cual sitúa el origen de coordenadas (0,0) en la esquina superior-izquierda de la pantalla. De este modo la coordenada x crece hacia la derecha de la pantalla y la coordenada y crece hacia abajo. Los valores de las coordenadas siempre son enteros positivos.

La clase Graphics contiene la mayoría de funcionalidades para dibujar a bajo nivel, proporcionando la capacidad de dibujar gráficas primitivas (líneas, rectángulos...), texto e imágenes tanto en la pantalla como en un buffer de memoria. El método paint() será el encargado de dibujar en la pantalla del dispositivo MID.

La clase Graphics tiene una serie de atributos que determinan cómo se llevan a cabo las diferentes operaciones. El más importante de ellos es el atributo color, que determina el color usado del dibujo que se esté realizando. Este atributo se puede modificar con el método setColor, que recibe tres parámetros enteros que especifican el color en función de los tres colores primarios, o bien el método setGrayScale() que toma como parámetro un único valor entero que establece el grado de gris en un rango que va desde 0 hasta 255.

Los objetos de tipo Graphics contienen también un atributo denominado font que determina el tamaño y la apariencia del texto. Este atributo se modifica a través del método setFont().

Las gráficas primitivas que podemos dibujar son líneas, rectángulos y arcos. La clase Graphics proporciona métodos para trazar las líneas y rellenar las áreas.

El método que permite dibujar una línea es void drawLine (int x1, int y1, int x2, int y2), los parámetros x1 e y1 indican el punto de comienzo de la línea y x2 e y2 indican el punto final. Para cambiar el estilo de la línea tenemos el método setStrokeStyle(), que acepta un valor de los siguientes:

• Graphics.SOLID: Línea sólida

• Graphics.DOTTED: Línea de puntos

El método para dibujar rectángulos es void drawRect (int x, int y, int width, int height), donde los parámetros x e y especifican la localización de la esquina superior-izquierda del rectángulo y los parámetros width y height especifican el ancho y el alto

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

42 Francisco Prieto Donate

del rectángulo respectivamente. Para dibujar rectángulos con las esquinas redondeadas tenemos void drawRoundRect (int x, int y, int width, int height, int arcWidth, int arcHeight), método que contiene los parámetros arcWidth y arcHeigth para configurar el arco de las esquinas del rectángulo. La clase Graphics también tiene métodos para dibujar rectángulos rellenos de un color determinado según el atributo color. Los métodos para hacer esto son fillRect() y fillRoundRect().

Figura 2.11: Ejemplo de pantalla Canvas

Tenemos además los arcos, que no son más que una sección de un óvalo. El método que dibuja un arco es void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle). Los primeros cuatro parámetros definen la posición y dimensiones del rectángulo que rodea al óvalo del que el arco forma parte y los últimos dos parámetros definen el arco como una sección del óvalo. Tanto el ángulo inicial como el ángulo total se expresan en grados. El método para dibujar un arco relleno de color es fillArc().

El texto que se escribe usando la clase Graphics está configurado por el atributo font, el cual se cambia con el método void setFont (Font font). El objeto Font indica el tipo de fuente, el estilo y el tamaño del texto. Para crear un objeto de tipo Font usamos el método static Font getFont(int face, int sytle, int size). Una vez que tenemos la fuente usamos el método setFont() para utilizar la misma en operaciones sucesivas.

El método para dibujar el texto es void drawstring (String str, int x, int y, int anchor), donde el primer parámetro es el texto a escribir y los dos siguientes (x e y) especifican la localización del texto. Aparte de este método tenemos algunos otros para dibujar texto como son drawChar() y drawChars(), usados para dibujar caracteres de texto individuales. También podemos usar el método drawSubstring(), que permite escribir una parte de una cadena.

Por último están las imágenes que son objetos gráficos rectangulares compuestos de píxeles grises o de color. Antes de dibujar una imagen es necesario cargarla. Las imágenes son cargadas y creadas usando un método de la clase Image denominado Public static Image createImage (String name), donde el parámetro indica el nombre

2. J2ME

Francisco Prieto Donate 43

del fichero que contiene la imagen. Este método retorna un objeto de tipo Image que puede ser usado dentro del MIDP. La clase Image representa una imagen gráfica como puede ser un fichero PNG. También incluye un método para recuperar un objeto Graphics que permite dibujar directamente sobre la imagen: boolean drawImage (Image img, int x, int y, int anchor).

2.7.4.1.2 Interfaz de usuario de Alto Nivel

El API del interfaz de usuario de alto nivel está pensado para aplicaciones profesionales dirigidas a usuarios trabajando en dispositivos móviles de información. Por tanto la portabilidad de código de un equipo a otro es muy importante, lo cual se consigue empleando un nivel de abstracción alto que da lugar a una pérdida de control sobre el dispositivo. Por tanto las aplicaciones no definen la apariencia de las pantallas, la navegación, el scroll y demás operaciones de interacción con el usuario, sino que lo hace el sistema. Las aplicaciones tampoco pueden acceder a mecanismos de entrada de datos concretos, como por ejemplo una tecla individual del teclado.

La clase abstracta Screen proporciona la funcionalidad básica para una pantalla, que principalmente consiste en un título que aparecerá en la parte superior de ésta. Se puede modificar este título con los métodos getTitle() y setTitle (String s). Además del atributo de título, las pantallas también pueden tener una línea de texto en movimiento que aparecerá sobre la pantalla. Este texto se configura a través de la clase Ticker, elemento que se puede manejar con los métodos Ticker getTicker() y void setTicker (Ticker ticker).

Las funcionalidades de esta API se dan a través de cuatro clases las cuales heredan de Screen, que son:

1. List: Esta clase proporciona una pantalla que contiene una lista de elementos que el usuario puede seleccionar. Existen tres tipos básicos de listas:

� EXCLUSIVE: Permite seleccionar un único elemento a la vez.

� IMPLICIT: Una lista EXCLUSIVE en la que la selección de un elemento provoca un evento.

� MULTIPLE: Permite seleccionar uno o más elementos a la vez.

� Los constructores de la clase List son List(String title, int listType) y List(String title, int listType, String[] stringElements, Image[] imageElements).

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

44 Francisco Prieto Donate

� Una vez creada la lista se puede interactuar con ella. Para recuperar el elemento seleccionado en una lista EXCLUSIVE o IMPLICIT se usa el método getSelectedIndex(), que devuelve el índice del elemento seleccionado dentro de la lista. Para listas de tipo MULTIPLE se usa el método getSelectedFlags(), que devuelve una matriz cuyos valores son de tipo boolean e indican si el elemento correspondiente está seleccionado o no.

Figura 2.12: Ejemplo de lista

2. TextBox: La clase TextBox implementa un componente de edición de texto que ocupa toda la pantalla. El constructor de la clase es TextBox(String title, String text, int maxSize, int constraints) donde el parámetro title es un texto que aparecerá en la parte superior de la pantalla, mientras que el parámetro text es usado para inicializar el texto que contendrá el TextBox, si es necesario. El parámetro maxSize especifica el número máximo de caracteres de texto que pueden ser introducidos.

Figura 2.13: Ejemplo de TextBox

� Por último, el parámetro constraints describe las limitaciones a aplicar sobre el texto. Estas limitaciones son especificadas según unas constantes:

� ANY: No hay limitaciones en el texto.

2. J2ME

Francisco Prieto Donate 45

� EMAILADDR: Solo se puede introducir una dirección de correo electrónico.

� NUMERIC: Solo se pueden introducir valores numéricos.

� PASSWORD: El texto es protegido para que no sea visible.

� PHONENUMBER: Solo se puede introducir un número de teléfono.

� URL: Solo se puede introducir una URL

3. Alert: La clase Alert implementa una pantalla que muestra un texto informativo al usuario. Esta información se muestra durante un determinado espacio de tiempo o hasta que el usuario seleccione un comando, según se configure. El constructor de la clase Alert es: Alert(String title, String alertText, Image alertImage, AlertType alertType) donde el título es un texto que aparece en la parte superior de la pantalla, mientras que el texto de la alerta actúa como el cuerpo del mensaje de alerta, con el tercer parámetro se puede indicar una imagen para que se muestre en la alerta y el último parámetro indica el tipo de alerta. Los tipos de alertas pueden ser:

� ALARM

� CONFIRMATION

� ERROR

� INFO

� WARNING

Figura 2.14: Ejemplo de Alert

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

46 Francisco Prieto Donate

Mediante el método AlertType.ERROR.playSound(display) se puede emitir un sonido de error. Por defecto, las alertas se mostrarán durante unos segundos y desaparecerán automáticamente. Este periodo de visualización de la alerta se puede configurar con el método void setTimeout(int time).

4. Form: Sirve como contenedor para construir interfaces de usuario con otros componentes o Items. Para añadir elementos de tipo Item al Form y componer una interfaz de usuario personalizada se utiliza el método int append (Item item). Cada Item añadido posee un índice dentro del Form, y este índice es el número que retorna el método append.

Para eliminar un Item de un Form se usa el método void delete(int index). Se puede insertar un Item en un punto concreto del Form con el método void insert(int index, Item item). Para modificar un Item debemos usar el método void set(int index, Item item). Para recuperar un determinado Item disponemos del método Item get(int index). Finalmente, para saber el número total de Items en un Form tenemos el método int size().

La clase Form está pensada para aquellos casos en los que una pantalla con una única funcionalidad no es suficiente, sino que es necesario que contenga un pequeño número de elementos de interfaz de usuario, o Items. Si el número de Items fuese tal que no entrasen en una sola pantalla, el propio sistema se encarga de implementar un scroll que permita subir o bajar a lo largo de la pantalla para visualizar a los distintos Items.

En cualquier orden y número, un Form puede contener los siguientes Items:

� StringItem: Esta clase representa un elemento que contiene una cadena de texto. Se usa para mostrar texto en un Form y está compuesta de dos partes, una etiqueta y un texto. El constructor de esta clase es StringItem(String label, String text).

� ImageItem: La clase ImageItem es similar a StringItem pero está diseñada para mostrar imágenes en lugar de texto. El constructor de esta clase es ImageItem(String label, Image img, int layout, String altText). El primer parámetro es un texto a mostrar en pantalla, la imagen es el segundo parámetro y el parámetro layout determina cómo se posiciona la imagen en el Form respecto a otros elementos. El último� parámetro especifica un texto alternativo para mostrar en pantalla si la imagen no se pudiera representar.

2. J2ME

Francisco Prieto Donate 47

� TextField: Esta clase proporciona un editor de texto diseñado para ser usado dentro de los Forms (ésta es la principal diferencia con respecto a la clase TextBox). El constructor de la clase es TextField(String label, String text, int maxSize, int constraints), donde el primer parámetro establece la etiqueta que se muestra junto al componente, el segundo es el texto utilizado para inicializar el elemento, el parámetro maxSize indica el máximo número de caracteres que pueden ser introducidos y el último parámetro, de forma similar a lo indicado en la clase TextBox, indica las restricciones del texto a introducir.

Figura 2.15:Ejemplo de TextField

� DateField: Presenta al usuario una interfaz intuitiva para introducir fechas y horas. El constructor de esta clase es DateField (String label, int mode). En el primer parámetro tenemos la etiqueta a mostrar con el elemento, el parámetro mode indica el modo de funcionar del componente. Estos modos de funcionamiento son:

� DATE: Se introduce solo una fecha (día, mes y año). � TIME: Se introduce solo una hora (horas y minutos). � DATE_TIME: Se introduce el día y la hora.

� Gauge: La clase Gauge implementa una barra gráfica que puede ser usada para visualizar un valor dentro de un rango. Un objeto de tipo Gauge tiene un valor máximo que define el rango del objeto (de 0 al máximo) y un valor actual que determina el estado actual de la barra. La clase Gauge puede funcionar interactivamente y no interactivamente. Si funciona de forma no interactiva, simplemente se muestra la barra, mientras que si trabaja de forma interactiva, se usará la barra como método para introducir un valor por parte del usuario.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

48 Francisco Prieto Donate

Figura 2.16: Ejemplo de Gauge

Para crear un objeto de tipo Gauge tenemos el constructor Gauge(String label, boolean interactive, int maxValue, int initialValue). El primer parámetro es la etiqueta asociada al componente, el segundo parámetro indica si es interactivo o no interactivo. Se puede acceder al valor actual y cambiar dicho valor con int getValue() y void setValue(int value). También es posible manipular el valor máximo con los métodos int getMaxValue() y void setMaxValue(int value).

� ChoiceGroup: Presenta una lista de elementos que el usuario puede seleccionar. Esta clase es similar a la clase List, pero a diferencia de ésta, ChoiceGroup está pensada para ser usada dentro de un Form. Los constructores son ChoiceGroup(String label, int choiceType) y ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements).

2.7.4.1.3 Comandos de Pantalla

Puesto que el MIDP implementa una interfaz de usuario de alto nivel, no se facilita una técnica concreta de interacción con el usuario. En su lugar se utiliza un mecanismo de gestión de comandos abstracto de forma que se pueda ajustar a los distintos dispositivos físicos sobre los que trabaja J2ME.

En una aplicación MIDP se definen una serie de comandos, así como la forma de gestionarlos por parte del usuario mediante botones, menús o cualquier otro mecanismo que pueda existir en un dispositivo.

El objeto Command ofrece un constructor con tres parámetros concretos:

Command(String label, int commandType, int priority)

2. J2ME

Francisco Prieto Donate 49

� label: Texto que se muestra al usuario en la pantalla para identificar el comando.

� commandType: Tipo del comando que queremos crear. Existen varias funcionalidades:

� OK: Verifica que se puede comenzar una acción � CANCEL: Cancela la acción � STOP: Detiene la acción � EXIT: Sale del MIDlet � BACK: Envía al usuario a la pantalla anterior � HELP: Solicita la ayuda � ITEM: Comando especifico de la aplicación que es relativo a un

determinado item de la pantalla actual � SCREEN: Comando especifico de la aplicación que es relativo a

la pantalla actual

� priority: Permite al sistema emplazar al comando en función de su prioridad, de forma que si hubiese demasiados comandos y no cupieran en una sola pantalla se presentarían los de mayor prioridad, pasando los otros a un submenú adicional.

Existe un comando especial que es el List.SELECT_COMMAND, el cual está pensado para albergar la selección realizada de entre las posibles existentes en un objeto List.

Por último, para poder capturar la selección de un comando en cada objeto Displayable existe un “listener” que se encarga de estar a la escucha de comandos, de forma que cuando un comando sea seleccionado, este listener lo detecta y pasa a ejecutar el código relacionado con dicho comando. Para registrar este listener contamos con el método Displayable.setCommandListener y para gestionar la ejecución de código relativo a un comando se debe implementar la interfaz CommandListener y su método commandAction.

2.7.4.2 Librerías de Red

Los equipos con los que trabaja MIDP operan en una amplia variedad de redes inalámbricas de comunicación, cada una de ellas con un protocolo de comunicación distinto e incompatible con todos los demás.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

50 Francisco Prieto Donate

Un objetivo del MIDP Specification es de adaptar su modelo de conexión a la red no solo a todos los protocolos existentes hoy en día, sino también a todos aquellos que puedan llegar en un futuro.

Además de lo ya visto anteriormente al respecto de las comunicaciones de red, el API de MIDP añade la interfaz HttpConnection, que proporciona un componente nuevo en el GFC (Generic Connection Framework) para conexiones HTTP. Estas conexiones permiten a los MIDlets conectarse con servidores Web. La especificación MIDP indica que las conexiones HTTP son el único tipo de conexiones obligatorio en las implementaciones de MIDP.

Después de un largo estudio acerca de la situación actual de los protocolos de red, el MIDP expert group decidió tomar el protocolo HTTP como protocolo base para las comunicaciones de red. HTTP es un protocolo muy rico y ampliamente utilizado que puede implementarse sobre redes inalámbricas de forma sencilla, aprovechando además la extensa infraestructura de servidores ya existente que corren con este protocolo.

Dar soporte al protocolo HTTP no implica necesariamente que el equipo implemente el protocolo TCP/IP. Un equipo podría utilizar otros protocolos como WAP o i-Mode conectándose en la red con un Gateway que sirva de puente de unión con los servidores de Internet.

Figura 2.17: Conexiones de red HTTP

Toda la funcionalidad HTTP se encuentra en la interfaz javax.microedition.io.HttpConnection, la cual añade una serie de facilidades que permiten el uso del protocolo HTTP.

2. J2ME

Francisco Prieto Donate 51

El protocolo HTTP es un protocolo de petición-respuesta en el cual los parámetros de la petición deben establecerse antes de que la petición sea lanzada. En una conexión exiten tres posibles estados:

• Setup: Antes de que se haya establecido la conexión con el servidor nos encontramos en el estado setup. En este estado se prepara toda la información necesaria para conectar con el servidor, como pueden ser los parámetros de la petición y las cabeceras, lo cual se hace con los métodos setRequestMethod o setRequestProperty.

• Connected: En este estado nos encontramos cuando se haya establecido la conexión con el servidor. Dependiendo del método utilizado se enviará en esta etapa la información establecida en el estado setup.

• Closed: Nos encontraremos en este estado cuando la conexión se haya cerrado y no pueda ser usada más.

Para abrir una conexión HttpConnection es necesario indicar la URL completa con la dirección destino a la que nos queremos conectar, incluyendo el protocolo, el host, el puerto y otros parámetros. Esto se consigue con la siguiente línea de código: HttpConnection c = (HttpConnection) Connector.open(String URL).

El protocolo HTTP proporciona un conjunto amplio de cabeceras en la fase de petición para que el MIDlet pueda negociar la forma, el formato, el lenguaje, la sesión y otros atributos más de la petición que se realiza al servidor. Para esto tenemos los métodos setRequestMethod y setRequestProperty. De entre todas estas cabeceras hay unas muy interesantes que son User-Agent, que permite al cliente identificarse en el servidor, y Accept-Language, que permite al cliente indicarle al servidor el idioma en el que quiere que le devuelva la respuesta.

Una vez establecidos los parámetros y cabeceras de la conexión HTTP podemos usarla en tres modos distintos de conexión, los modos GET, POST o HEAD. Esto se indica con el método setRequestMethod(HttpConnection.POST). Los métodos GET y POST son similares, solo que en aquellos casos en los que sea necesario pasarle al servidor una serie de datos y parámetros adicionales es mejor usar el segundo método. En cambio, el método HEAD devuelve solamente la cabecera de la petición.

Para lanzar al servidor una serie de datos en la petición podemos, por ejemplo, hacer:

OutputStream os = c.openOutputStream(); os.write(“Cadena de prueba”.getBytes());

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

52 Francisco Prieto Donate

os.flush();

Y para recibir los datos que el servidor devuelva:

InputStream is = c.openInputStream(); // Lectura carácter a carácter.

Por último, el servidor HTTP responde al cliente enviando la respuesta a la petición junto con una serie de cabeceras de respuesta donde se describe el contenido, la codificación, la longitud, etc.

2.7.4.3 Librerías de almacenamiento persistente

La MIDP Specification proporciona un mecanismo simple de base de datos para que los MIDlets almacenen datos de forma persistente llamado RMS (Record Management System).

RMS trabaja con records y record stores de forma que un record store es una colección de registros (records) cuyos datos almacenados se mantienen de lo largo de múltiples invocaciones al MIDlet. Cada registro es un array de bytes cuya longitud no tiene por qué ser la misma que la del resto de registros que pertenezcan a ese mismo record store y cuyos datos no tienen por qué ser del mismo tipo dentro de dicho array. Por ejemplo, el registro Record_ID 1 puede contener un String seguido de un int, mientras que el registro Record_ID 5 puede contener un array de números de tipo short.

Cada registro dentro de un record store tiene un recordId único que lo identifica. Registros adyacentes no tienen por qué tener recordIds consecutivos, e incluso no tienen por qué estar almacenados en memoria de forma consecutiva.

El sistema software del equipo se encarga de mantener la integridad de los RMS record stores en el uso normal de la aplicación y también en caso de caídas del sistema a causa de errores o falta de batería.

Tal y como se mencionó anteriormente, por motivos de seguridad solo aquellos MIDlets que pertenezcan al mismo MIDlet suite podrán acceder a los mismos RMS record stores, no pudiendo acceder a los de otros MIDlet suites.

2. J2ME

Francisco Prieto Donate 53

Toda la funcionalidad de almacenamiento de datos de forma persistente se encuentra en el paquete javax.microedition.rms, cuyas clases e interfaces proporcionan un marco de trabajo para los registros, los almacenes y otras características. Por tanto, tenemos capacidad para añadir y borrar registros de un almacén, además de la posibilidad de compartir almacenes por parte de todos los MIDlets de un MIDlet suite.

Para representar el record store tenemos la clase RecordStore que nos permite abrir, cerrar y borrar almacenes de registros. También podemos añadir, recuperar y borrar registros, así como enumerar los registros de un almacén. Los métodos son:

• openRecordStore: Abre el almacén de registros.

• closeRecordStore: Cierra el almacén de registros.

• deleteRecordStore: Borra el almacén de registros.

• getName: Recupera el nombre del almacén de registros.

• getNumRecords: Recupera el número de registros del almacén.

• addRecord: Añade un registro al almacén de registros.

• getRecord: Recupera un registro del almacén de registros.

• deleteRecord: Borra un registro del almacén de registros.

• enumerateRecord: Obtiene un enumeration del almacén de registros.

Aparte de la clase RecordStore tenemos las siguientes interfaces:

• RecordEnumeration: Describe una enumeración del almacén de registros.

• RecordComparator: Describe la comparación de registros.

• RecordFilters: Describe cómo usar filtros sobre los registros.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

54 Francisco Prieto Donate

• RecordListener: Describe un listener que recibe notificaciones cuando un registro es añadido, modificado o borrado del almacén de registros.

El primer paso para trabajar con RMS es abrir el almacén de registros usando el método estático openRecordStore de la clase RecordStore. Con este método también podemos crear un almacén nuevo y abrirlo:

RecordStore rs = RecordStore.openRecordStore(“data”, true);

El primer parámetro indica el nombre del almacén y el segundo indicará si el almacén debe ser creado o si ya existe.

Para añadir un nuevo registro a un almacén debemos tener antes la información en el formato correcto, es decir, como una matriz de bytes. El siguiente código muestra cómo añadir un registro:

int id = 0; try{ id = recordStore.addRecord(bytes, 0, bytes.length); }catch (RecordStoreException e){ e.printStackTrace(); }

El primer parámetro de addRecord es la matriz de bytes, el segundo es el desplazamiento dentro de la matriz y el tercero es el número de bytes a añadir. Este método devuelve el identificador del registro añadido, que lo identifica unívocamente en el almacén.

Para recuperar un registro de un almacén utilizamos el método getRecord que recupera el registro del almacén a través de su identificador. La información devuelta por este método es una matriz de bytes. Un ejemplo de uso sería:

byte[] recordData = null; try{ recordData = recordStore.getRecord(id); }catch (RecordStoreException ex){ ex.printStackTrace(); }

Se pueden borrar registros de forma similar a como se recuperan. El método para borrar un registro es deleteRecord. Un ejemplo de uso sería:

2. J2ME

Francisco Prieto Donate 55

try{ recordStore.deleteRecord(id); }catch (RecordStoreException ex){ ex.printStackTrace(); }

Es importante cerrar el almacén una vez que hemos acabado de trabajar con él. La clase RecordStore proporciona el método closeRecordStore con este fin. Este método tiene la siguiente forma: recordStore.closeRecordStore().

2.7.5 MIDP 2.0

MIDP 2.0, especificado en la norma JSR-118, es la versión revisada y mejorada de la especificación MIDP 1.0. Para poder ejecutar aplicaciones MIDP 2.0, los dispositivos deberían tener las siguientes características mínimas:

• Tamaño de pantalla de 96x54 píxeles con una profundidad de color de 1 bit.

• Entrada por teclado o pantalla táctil.

• Memoria de 256KB no volátil para la aplicación MIDP, 8KB no volátil para datos persistentes y 128KB volátil para el entorno de ejecución Java.

• Conexión a redes bidireccional con acceso inalámbrico posiblemente intermitente con ancho de banda limitado.

• Capacidad para reproducir sonidos.

El MIDP 2.0 mejora y amplía algunas características definidas en MIDP 1.0, entre las que podemos destacar las siguientes:

• Permisos y firma de código de aplicaciones.

• Mejoras en la seguridad de operaciones en red.

• Incorporación de capacidades multimedia.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

56 Francisco Prieto Donate

• Interfaces de usuario mejoradas.

• Cadenas de conexión estandarizadas para acceso por puerto serie.

• Cadenas de conexión estandarizadas para datagramas, sockets y sockets de servidor.

• Registro de solicitudes (push registry) que permite que se ejecuten MIDlets en respuesta a conexiones de red entrantes.

• OTA como práctica recomendada (en MIDP 1.0 era un anexo, no formaba parte de la especificación).

• Los repositorios de registros se pueden compartir entre MIDlets.

2.7.5.1 Permisos y firma de código de aplicaciones

La especificación MIDP 2.0 reconoce los conceptos de código de confianza y código no confiable y de permisos. El código no confiable no puede establecer conexiones por su cuenta, sino que ha de recibir permiso del usuario. El código se puede definir como de confianza si el desarrollador lo firma digitalmente y el usuario del dispositivo puede verificar esta firma.

MIDP 2.0 mejora de manera considerable el modelo de seguridad del MIDP 1.0 a través del paquete javax.microedition.pki. Este paquete permite manejar certificados que se utilizan para la autenticación de la información en conexiones seguras.

2.7.5.2 Mejoras en la seguridad de operaciones en red

MIDP 2.0 requiere HTTPS, HTTP sobre Secure Sockets Layer (SSL). SSL es un protocolo de socket que cifra los datos que se envían por la red y proporciona autenticación de los sockets extremos de la comunicación.

2.7.5.3 Diferencias a nivel de desarrollo

MIDP 2.0 define cuatro nuevos paquetes. En la siguiente tabla se muestran los paquetes incluidos en cada uno de los perfiles existentes:

2. J2ME

Francisco Prieto Donate 57

Tipo Del Paquete Paquetes MIDP 1.0 Paquetes MIDP 2.0 Interfaz de Usuario javax.microedition.lcdui javax.microedition.lcdui

Juegos No disponible javax.microedition.lcdui.game

Ciclo de vida javax.microedition.midlet javax.microedition.midlet

Interconexión a Redes javax.microedition.io javax.microedition.io

Seguridad No disponible javax.microedition.pki

Sonido No disponible javax.microedition.media

No disponible javax.microedition.media.control

Persistencia de datos javax.microedition.rms javax.microedition.rms

Básicos Java.io Java.io

java.lang java.lang

java.util java.util

2.7.5.4 Mejoras en Formularios

MIDP 2.0 incluye soporte para interfaces de usuario mejoradas que permiten a los desarrolladores la creación de aplicaciones más atractivas, a través de nuevas clases e interfaces o la adición de métodos y atributos a las clases existentes:

• La clase Form describe un nuevo algoritmo de organización. Los elementos se ubican de izquierda a derecha y de arriba hacia abajo, como si fuera texto. Esta disposición se puede modificar pero la implementación es en último término la responsable de la correcta ubicación.

• La clase Item añade la posibilidad de definir un tamaño mínimo y un tamaño deseado.

• MIDP 2.0 extiende la gestión de órdenes. En MIDP 1.0, los Commands se añaden a las instancias de Displayable y un único objeto listener captura todos los eventos de orden generados. MIDP 2.0 extiende el modelo permitiendo añadir Commands a los Items. El comando se añade al Item con el método addItemCommand(). Para registrar un escuchador de eventos (listener), se implementa la interfaz ItemCommandListener y se registra el escuchador con el método setItemCommandListener() de la clase Item.

• Se añade un nuevo control Spacer para definir espacios en blanco y ajustar mejor la interfaz.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

58 Francisco Prieto Donate

• La clase ChoiceGroup se modifica con un nuevo tipo, POPUP, para que se pueda comportar como un cuadro combinado (ComboBox).

• Se pueden crear controles nuevos mediante la clase CustomItem.

A continuación destacamos las nuevas adiciones a nivel de interfaz y clases:

Nuevas Interfaces ItemCommandListener Se utiliza para recibir notificaciones de comandos que han sido

invocados a través de un objeto Item, permitiendo el manejo de múltiples comandos en la misma pantalla, dependiendo del Item que se esté seleccionando.

Nuevas Clases CustomItem Permite crear, dentro de un Form, items personalizados: nuevos

componentes visuales e interactivos que no pertenecen al estándar.

Spacer Es un Item en blanco, no interactivo que tiene un tamaño mínimo configurable. El ancho mínimo es útil para ubicar espacios variables entre Items en una misma fila de un Form. La altura mínima es útil para forzar la altura mínima de una fila del formulario.

2.7.5.5 La nueva API de juegos

MIDP 2.0, ha incluido el paquete javax.microedition.lcdui.game, que proporciona una serie de clases que posibilitan el desarrollo de juegos con alto contenido gráfico. Las cinco clases del API están estructuradas para proporcionar mucha libertad cuando se implemente sobre ellas, permitiendo el uso extensivo de código nativo, aceleración de hardware y formatos de imagen específicos del dispositivo cuando sea necesario. El concepto básico parte del hecho de que la pantalla puede estar compuesta de distintas capas. Una capa podría contener el fondo del juego, otra el personaje principal, etc. El API esta compuesto por las siguientes clases:�

GameCanvas

Es una subclase de lcdiu.Canvas que proporciona la funcionalidad de pantalla básica para un juego. Además de los métodos propios de Canvas, incorpora funcionalidad para sincronizar imágenes y conocer el estado actual de las teclas en un juego; estas características simplifican el desarrollo del juego y mejoran su rendimiento.

Layer Es una clase abstracta que representa un elemento visual en un juego como un Sprite o un TiledLayer. Proporciona atributos básicos como localización, tamaño y visibilidad.

2. J2ME

Francisco Prieto Donate 59

LayerManager Para juegos que emplean varios Layers, esta clase simplifica el desarrollo del juego brindando al programador un mejor control de las diferentes vistas del juego.

Sprite

Es una capa animada básica que puede mostrar uno o varios subelementos gráficos. Los subelementos gráficos son todos de igual tamaño y propocionan la imagen simple de un objeto. Además, permite animar estos subelementos de manera secuencial o arbitraria y proporciona varios métodos de transformación de imágenes (redimensionamiento y rotación), así como métodos para detección de colisión que simplifican la implementación de la lógica del juego.

TiledLayer

Esta clase permite al desarrollador crear grandes áreas de contenido gráfico sin que una imagen grande sea requerida. Se compone de una rejilla de celdas donde cada celda puede mostrar una de varias partes proporcionadas por un simple objeto de imagen. El relleno se hace como si se tratara de un mosaico.

Figura 2.18: Fondo de pantalla formado por un mosaico de celdas

2.7.5.6 Imágenes RGB�

Las imágenes se pueden representar como arrays de enteros, de modo que los datos de imagen se representan mediante un entero de 32 bits por píxel, con 8 bits que representan el valor de alfa (opacidad), y las componentes de color rojo, verde y azul. Los componentes se empaquetan en el entero con el formato 0xAARRVVZZ.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

60 Francisco Prieto Donate

2.7.5.7 Sonido

El API de sonido es un subconjunto para audio del Mobile Media API (MMAPI). La MIDP 2.0 Media API cuenta con una sola clase, Manager, la cual sirve como punto de acceso para obtener los diferentes recursos del sistema. Las demás funcionalidades son provistas a través de interfaces de los paquetes javax.microedition.media y javax.microedition.media.control. Con este API podremos producir un sonido o una serie de ellos, o bien reproducir sonidos codificados en formato WAV.

2.8 Descarga OTA

El ciclo de desarrollo de una aplicación para terminales que soporten MIDP implica algo más que codificar y depurar la aplicación. Es igualmente importante tener un medio para trasladar esa aplicación a un teléfono móvil, de forma que el proceso de descarga e instalación sea sencillo para el usuario final.

Los desarrolladores usan conexiones serie o USB para descargar sus aplicaciones a dispositivos inalámbricos, pero la mayoría de los usuarios carecen del hardware necesario para hacer lo mismo. Los usuarios quieren descargar sus aplicaciones sin necesidad de usar cables, al igual que realizan sus llamadas, escriben SMS o navegan por Internet. Este procedimiento se denomina aprovisionamiento iniciado por el usuario, vía aire (over-the-air user-initiated provisioning). Para abreviar se usan las siglas OTA.

Inicialmente OTA fue un añadido a la especificación del perfil MIDP 1.0. Aunque técnicamente no era parte de la especificación, el grupo de expertos recomendaba su uso. Posteriormente fue revisado y formalmente incorporado a la especificación MIDP 2.0, por lo que los nuevos dispositivos deben soportar el aprovisionamiento OTA. De esta forma podemos asegurar que cualquier MIDlet implementado apropiadamente puede ser descargado en un terminal.

Figura 2.19: Esquema de descarga OTA vía SMS

2. J2ME

Francisco Prieto Donate 61

2.8.1 Usos de la tecnología OTA

Una de las formas más sencillas de personalizar un móvil es descargar un contenido que lo haga característico. Normalmente una melodía de llamada o una imagen humorística. OTA es una forma sencilla de descargar contenidos de forma fácil y rápida. El usuario no tiene más que seleccionar el contenido que desea de una página dedicada de Internet y automáticamente la recibirá vía WAP o SMS.

El mercado de descargas vía OTA se ha desarrollado rápidamente. Casi todos los fabricantes tienen páginas dedicadas para descargar contenidos en sus móviles: imágenes, sonidos, melodías, logotipos... Además existen empresas dedicadas a crear y comercializar contenidos para móviles, de forma que cada vez existen más aplicaciones disponibles para su descarga OTA.

Esta forma de descarga también facilita el desarrollo a los programadores, ya que permite pasar las aplicaciones al teléfono móvil para realizar pruebas.

Últimamente los fabricantes de dispositivos móviles están utilizando OTA para actualizar el firmware de los teléfonos. Para los usuarios significa que se acabó la necesidad de tener cables y estar buscando desde dónde descargar la última versión del software de un equipo específico: solo hay que entrar en el portal de la operadora y elegir el modelo del terminal. Para las operadoras, implica la posibilidad de agregar nuevas aplicaciones con nuevas fuentes de ingreso (u ofrecer nuevos servicios a sus usuarios) y distribuirlo a todos sus clientes, sin que éstos tengan que acceder a un centro de servicios específico.

2.9 Consideraciones finales

En este capítulo hemos introducido J2ME, la tecnología que permite la ejecución de programas Java en dispositivos móviles. Las diferencias principales de J2ME con las otras dos tecnologías de Java, J2EE y J2SE, radican principalmente en la ausencia de clases opcionales que tienen un alto consumo de memoria, y la inclusión de nuevas clases específicas para los dispositivos de capacidades limitadas.

Su modelo de arquitectura interna se fundamenta en tres conceptos básicos: Máquina Virtual, Configuraciones y Perfiles. Cada uno de ellos establece una capa lógica que define las características a cumplir por los dispositivos inalámbricos.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

62 Francisco Prieto Donate

Hemos profundizado en el Perfil utilizado en los dispositivos móviles, MIDP, y la Configuración sobre la que se define, CLDC. En el estudio de MIDP hemos prestado especial atención a los distintos tipos de interfaces de usuario, detallando los métodos destinados a crear pantallas tanto de bajo como de alto nivel.

Por último centramos nuestra atención a la tecnología OTA, esencial para descargar cualquier aplicación a un dispositivo móvil sin necesidad de cables.

En el capítulo siguiente estudiaremos la tecnología que permite a un dispositivo móvil conectarse a Internet, recibir mensajes de correo electrónico y descargarse aplicaciones y juegos.

3. GPRS

Francisco Prieto Donate 63

3 GPRS

3.1 Introducción

En este apartado vamos a introducir la tecnología GPRS. Explicaremos su nacimiento, las causas por las que surgió, cómo funciona y la estructura de una red basada en GPRS.

Esta tecnología tiene gran importancia porque es la usada por el teléfono móvil que ejecuta nuestra aplicación para conectarse a Internet, e interactuar con el servidor de vídeo.

Entre otras cosas, GPRS nos marcará la velocidad de transmisión y recepción de los datos del móvil, lo cual será de gran importancia a la hora de probar nuestra aplicación sobre un dispositivo real.

3.2 Introducción histórica a GPRS

En la década de los noventa, las redes de telefonía móvil se encontraban en su Segunda Generación. Ésta se caracterizaba por usar sistemas digitales, frente a los analógicos que se venían usando hasta ese momento. Se conseguía de esta forma mejorar la calidad de la señal de voz y dar la posibilidad de transmitir paquetes de datos. El estándar que se impuso en Europa, y sigue usándose en la actualidad, es GSM (Global System for Mobile communications).

La red GSM preveía unos servicios de transmisión de datos desde su fase inicial. Sin embargo, se trataba de servicios con modalidad de transferencia por conmutación de circuitos. Esto quiere decir que la red, una vez establecida la conexión física entre dos usuarios, dedicaba los recursos propios hasta que no fuera solicitada expresamente la liberación de la conexión, independientemente del hecho de que los dos usuarios se intercambiaran datos o no durante todo el proceso de conexión.

Este modo de transferencia es adecuado para las señales de voz, ya que mantener los recursos ocupados durante todo el proceso de intercambio de información facilita el tráfico de señales sensibles a retardos. Sin embargo, no es adecuado para la transmisión de paquetes de datos.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

64 Francisco Prieto Donate

Las características de la tecnología GSM para el envío de datos inalámbricos desde cualquier lugar y en cualquier momento son las siguientes:

• Velocidad de transferencia de 9,6 Kbps.

• Tiempo de establecimiento de conexión entre 15 y 30 segundos.

• Pago por tiempo de conexión.

La baja velocidad de transferencia limita la cantidad de servicios que Internet nos ofrece. Por ejemplo, a 9,6 Kbps no se puede navegar por Internet de una manera satisfactoria. Si además tenemos en cuenta que estamos pagando por tiempo de conexión, en lugar de por volumen de tráfico, los costes se disparan.

La combinación de estos tres factores negativos hace que GSM sea una tecnología mayoritariamente utilizada para la voz y no para los datos.

La modalidad de transferencia basada en conmutación de circuitos solo es óptima en el caso en que los dos usuarios tengan que intercambiarse una cantidad significativa de datos (transferencia de ficheros o archivos). Resulta ineficiente en cuanto los datos a intercambiarse son de pequeña entidad o bien, en el caso más frecuente, el tráfico de datos es de tipo interactivo o transitorio, es decir, el tiempo de uso efectivo de los recursos de la red supone sólo una pequeña parte con respecto al tiempo total de conexión (como, por ejemplo, la navegación en Internet a través del World Wide Web).

Figura 3.1: Diferencias entre conmutación de paquetes y de circuitos.

3. GPRS

Francisco Prieto Donate 65

GPRS (General Packet Radio Service) es una tecnología que subsana las deficiencias de GSM en cuanto a la transmisión de datos, introduciendo una red de conmutación de paquetes que funciona de forma paralela a la de conmutación de circuitos de GSM.

GPRS aparece como una evolución no traumática de la actual red GSM: no conlleva grandes inversiones y reutiliza parte de las infraestructuras actuales de GSM. Por este motivo, GPRS tiene desde sus inicios la misma cobertura que la actual red GSM. Los principales objetivos de esta tecnología son:

• Mantener los equipos de transmisión y la misma interfaz radio que GSM.

• Lograr transmitir datos a mayor velocidad realizando las modificaciones mínimas en la red GSM ya existente.

Con el sistema GPRS, introducido por la ETSI para el sistema GSM, el acceso a la red de paquetes se lleva al nivel del usuario del móvil a través de protocolos como TCP/IP, X.25, y CLNP (Connectionless Network Protocol), sin necesidad de utilizar otro tipo de conexiones intermedias por conmutación de circuitos.

En un servicio de transferencia de datos con modalidad de conmutación de circuito, cada conexión establecida se dedica sólo al usuario que la ha solicitado. A diferencia de esto, GPRS permite la transmisión de paquetes en modalidad link by link, es decir, los paquetes de información se encaminan en fases separadas a través de los diversos nodos de soporte del servicio, denominados GSN (Gateway Support Node). Por ejemplo, una vez que un paquete ha sido transmitido por el interfaz de radio entre el móvil y su estación base, se vuelven a liberar los recursos, que así pueden ser utilizados por algún otro usuario. El paquete se vuelve a enviar sucesivamente de nodo a nodo hacia su destino.

En los servicios GSM los recursos son gestionados según la modalidad "resource reservation", o sea, se emplean hasta el mismo momento en que la petición de servicio concluye. En GPRS, sin embargo, se adopta la técnica del "context reservation", es decir, se tiende a preservar las informaciones necesarias para soportar o bien las peticiones de servicio de forma activa o bien las que se encuentran momentáneamente en espera. Por tanto, los recursos de radio se ocupan sólo cuando hay necesidad de enviar o recibir datos. Los mismos recursos de radio de una celda se dividen entre todas las estaciones móviles (MS), aumentando notablemente la eficacia del sistema. El servicio GPRS, por tanto, está dirigido a aplicaciones con las siguientes características:

• Transmisión poco frecuente de pequeñas o grandes cantidades de datos (por ejemplo, aplicaciones interactivas).

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

66 Francisco Prieto Donate

• Transmisión intermitente de tráfico de datos bursty o a ráfagas (por ejemplo, aplicaciones en las que el tiempo medio entre dos transacciones consecutivas es de duración superior a la duración media de una única transacción.)

Algunos ejemplos de aplicaciones que cumplen esas características son:

• RTI (Road Traffic Informatics)

• Telemetría

• Telealarma

• Control del tráfico ferroviario

• Acceso a internet usando la WWW (World Wide Web)

La tecnología GPRS convive con GSM y la complementa. Desde el punto de vista físico los recursos pueden ser reutilizados y existen algunos puntos comunes en la señalización, así en el mismo portador radio pueden coexistir simultáneamente tanto los time slots reservados a la conmutación del circuito, como los time slots reservados al uso del GPRS. La optimización en el empleo de los recursos se obtiene a través de la repartición dinámica de los canales reservados a la conmutación del circuito y de aquellos reservados al GPRS.

Cuando se presenta una llamada de voz, hay tiempo suficiente para liberar los recursos usados por el GPRS, de tal forma que la llamada por conmutación de circuito, con mayor prioridad, pueda ser efectuada sin problemas.

Figura 3.2: Red GPRS añadida a una red GSM

3. GPRS

Francisco Prieto Donate 67

Algunas características de GPRS son:

• Velocidad de transferencia máxima teórica de 171.2 Kbps

• Conexión permanente. Tiempo de establecimiento de conexión inferior al segundo.

• Pago por cantidad de información transmitida, no por tiempo de conexión.

Algunos inconvenientes de GPRS son:

• La red impide que las velocidades máximas puedan ser alcanzadas.

• Un canal que esté transmitiendo datos no podrá ser utilizado para una llamada telefónica normal.

• La denominada "información no solicitada" dificulta a la operadora cobrar la transmisión de la información. Este problema hizo que los fabricantes considerasen la hipótesis de los primeros terminales no pudieren recibir llamadas GPRS, tan solo efectuarlas, lo que limitaría las ventajas que el sistema podría traer.

• El hecho de que los paquetes viajen separados puede provocar que se pierdan o se dañen por el camino. A pesar del protocolo utilizado, en el que se previeron estos problemas y aplicaron estrategias de retransmisión y de integridad de los paquetes, pueden darse demoras en la recepción de la información.

3.3 Protocolo GPRS

El protocolo GPRS es un protocolo de nivel tres, transparente para todas las entidades de red comprendidas entre el terminal móvil y el nodo SGSN al que el móvil está conectado. Este protocolo soporta tanto el intercambio de informaciones de control como de paquetes PDP-PDU (Packet Data Protocol - Protocol Data Unit) entre el móvil y el nodo al que se encuentre conectado.

El formato de una trama GPRS contiene los siguientes campos:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

68 Francisco Prieto Donate

• Identificador del protocolo GPRS.

• Identificador del protocolo de los PDU (identificador de PDP).

• Mensaje GPRS.

3.3.1 Identificador del protocolo GPRS

El identificador del protocolo GPRS es una información numérica cuyo objetivo es el de distinguir las ráfagas (los burst) que contienen paquetes GPRS, de las ráfagas que contienen información GSM.

3.3.2 Identificador del protocolo de los PDU

Este identificador, encapsulado en las tramas GPRS, es necesario para direccionar dichas tramas hacia el correcto SAP (Service Access Point) en cuanto son desencapsuladas.

Al igual que el identificador del protocolo GPRS, esta información también es de tipo numérico. Se tendrá, por tanto, un valor que define los paquetes X25, uno que define los paquetes IP (Internet Protocol), uno que define los paquetes CLNP (Connectionless Network Protocol) y así sucesivamente.

Además, dicha información permite la interpretación del mensaje GPRS contenido en la trama GPRS. De hecho, las tramas GPRS son utilizadas tanto para el transporte de mensaje de control como para el transporte de paquetes de datos, por lo que se hace necesario el uso de un indicador que permita distinguir a cuál de las dos categorías posibles pertenece el mensaje GPRS.

3.3.3 Mensaje GPRS

Un mensaje GPRS puede contener o bien datos o bien información de control. Los mensajes GPRS de control son definidos por un valor preestablecido del identificador de PDP. Algunos de los posibles mensajes de control se enumeran a continuación:

• Petición de log-on (LOG-ON REQUEST).

3. GPRS

Francisco Prieto Donate 69

• Respuesta a una petición de log-on (LOG-ON RESPONSE).

• Activación del modo de transmisión cifrado (SET GPRS CIPHERING MODE).

• Petición de actualización de las informaciones de routing (ROUTING UPDATE REQUEST).

• Respuesta a una petición de actualización de las informaciones de routing (ROUTING UPDATE RESPONSE).

• Petición de actualización del indicador de routing area (área de encaminamiento) (GPRS RA UPDATE REQUEST).

• Respuesta a una petición de actualización del indicador de routing area (GPRS RA UPDATE RESPONSE).

Como veremos a continuación, el nodo SGSN realiza las funciones de encaminamiento. Este nodo encapsula los datos recibidos del terminal móvil, en el protocolo de red usado para el transporte de paquetes en su red de distribución (backbone network). Obviamente, también realiza la operación inversa para los paquetes dirigidos al usuario móvil.

3.4 Arquitectura de la red GPRS

En este apartado vamos a estudiar los todos los elementos de una red GPRS y sus interfaces.

3.4.1 Elementos de una red GPRS

En la siguiente figura detallamos todos los elementos de una red GPRS:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

70 Francisco Prieto Donate

Figura 3.3: Elementos de una red GPRS

El nodo de soporte GSN (Gateway Support Node) de GPRS es el elemento principal de la infraestructura. Existen dos tipos de nodos GSN: unos de entrada (Serving GPRS Support Node, SGSN), que proporcionan conectividad a las BSC de GSM y otros de salida (Gateway GPRS Support Node, GGSN), que interconectan el sistema con redes de datos externas. Estos routers pueden proporcionar la conexión y la intercomunicación con otras redes de datos, pueden administrar la movilidad de los usuarios a través de los registros de GPRS y son capaces de entregar los paquetes de datos a las estaciones móviles, independientemente de su posición. Físicamente los GSN pueden estar integrados en el MSC (Mobile Switching Center) o pueden ser elementos separados de la red.

Otro nuevo nodo que añade GPRS al sistema GSM es el BG (Border Gateway), que es necesario principalmente por razones de seguridad y está situado en la conexión con la red troncal (backbone) Inter-PLMN. Mediante él se pueden intercambiar datos con otras PLMNs (Public Land Mobile Network).

Las redes troncales Inter-PLMN e Intra-PLMN también son elementos nuevos y están basadas en redes IP. Una PLMN (Public Land Mobile Network) es una red de telefonía móvil.

Además, aparecen unas nuevas gateways en el sistema GPRS, las CG (Charging Gateway).

3. GPRS

Francisco Prieto Donate 71

Otros nodos que constituyen una novedad en la red son los firewalls o barreras de seguridad, cuya misión es proteger a la red de accesos no deseados, pues en GPRS los nodos tienen direcciones IP y son, por tanto, susceptibles de ataques externos.

Los sistemas GSM actuales fueron diseñados originariamente para las llamadas de voz, en tanto que el principal objetivo de GPRS es ofrecer acceso a las redes de datos estándar tanto con TCP/IP como con X.25. Esas redes consideran la red GPRS como una subred normal. El GGSN se comportará como un encaminador (router) y ocultará las características específicas de la red GPRS a las redes de datos externas.

A continuación vamos a describir los elementos específicos de una red GPRS:

3.4.1.1 SGSN

El SGSN es el principal componente de una red GPRS. Está conectado al BSC por medio de la interfaz Gb y constituye para el terminal móvil el punto de acceso al servicio de la red GPRS.

Un SGSN puede servir a un gran número de BSS (BTS+BSC). Sus funciones son:

• Retransmisión de los datos entre el terminal GPRS y el SGSN correspondiente. Esto se realiza en los dos sentidos, según de donde procedan los datos.

• Soportar la interfaz Gb con la BSC.

• Gestionar la autentificación de los terminales móviles GPRS y, si este proceso se completa con éxito, encargarse de su registro en la red GPRS y de su gestión de movilidad.

• Aviso (Paging). Este procedimiento lo inicia el SGSN para que el terminal móvil pase del estado STANDBY al READY con objeto de poder llevar a cabo el intercambio de datos.

• Recoger datos necesarios para generar CDRs (Call Detail Recordings) de facturación y enviarlos al CG.

• Gestionar la conversión del protocolo IP empleado en la red troncal a los protocolos SNDCP y LLC empleados entre el SGSN y el terminal móvil. Las capas SNDCP y LLC manejan el cifrado y la compresión de los datos.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

72 Francisco Prieto Donate

Básicamente se puede decir que el SGSN equivale a una MSC a nivel funcional, con la salvedad de que conmuta paquetes.

3.4.1.2 GGSN

El GGSN proporciona la interconexión entre la red GPRS y las redes de paquetes de datos externas, como por ejemplo Internet, Intranets corporativas, etc.

Desde el punto de vista de las redes externas, el GGSN es un encaminador a una subred, ya que el GGSN oculta la infraestructura de la red GPRS a las redes externas.

Cuando el GGSN recibe datos dirigidos a un terminal GPRS específico comprueba si la dirección está activa para, en ese caso, enviar los datos al SGSN que está atendiendo al terminal. En el caso en que la dirección esté inactiva, trata de activar dicho terminal.

Por consiguiente, las funciones que realiza el GGSN son:

• Recibir datos de usuario desde una Intranet o Internet y enviarlos hacia el SGSN que controla el terminal a través de la red troncal mediante el protocolo de tunnelling GTP (GPRS Tunelling Protocol).

• Recibir paquetes de datos de la red troncal GPRS (desde SGSN o BG), eliminar el túnel GTP y encaminar los datos de usuario hacia Intranet o Internet.

• Recibir datos de señalización desde la red troncal y configurar la operación correspondiente.

• Garantizar privacidad y seguridad para la red y el terminal GPRS. Para ello, el GGSN actúa como una puerta de acceso entre las redes externas y la red GPRS.

• Proporcionar direcciones IP a los terminales GPRS cuando se emplea direccionamiento dinámico.

• Proporcionar los servicios básicos para el acceso a ISPs.

• Realizar el traspaso entre SGSNs.

3. GPRS

Francisco Prieto Donate 73

Un GGSN puede soportar diferentes tipos de interfaz física, por ejemplo:

� V.35: se usa en conexiones WAN en el caso de que el SGSN esté localizado en un emplazamiento remoto respecto al GGSN. El protocolo que se emplea en este caso es IP sobre PPP. La capacidad es de hasta 2 Mbit/s.

� 100BaseTX: soporta configuraciones donde SGSN(s) y GGSN(s) están en el mismo lugar y conectados a una red local (LAN). La capacidad de la interfaz es de 100 Mbit/s. El protocolo empleado es IP sobre ATM.

� STM-1: soporta tanto configuraciones WAN como LAN. Es más adecuado para configuraciones donde los volúmenes de tráfico son altos. Esta interfaz permite 155 Mbit/s. Uno de los protocolos empleados es IP sobre ATM.

3.4.1.3 Otros elementos de la red GPRS

En la red GPRS hay otros elementos además del SGSN y el GGSN. Algunos son elementos comunes de las redes de datos, como por ejemplo los DNS o los Firewall.

• Border Gateway: la principal función del BG es que haya una conexión segura entre varias PLMNs interconectadas para soportar itinerancia. Su arquitectura exacta no está definida en las especificaciones GPRS, de manera que los operadores deberán llegar a oportunos acuerdos sobre esta interconexión.

• Domain Name System: el DNS es necesario en la red GPRS para que se pueda llevar a cabo la traducción de nombres lógicos en direcciones físicas de los GSNs.

• Charging Gateway: el CG recoge CDRs generados en los SSGNs y GGSNs, de manera que los consolida y preprocesa antes de pasarlos al sistema de facturación. Gracias a esto, el sistema de facturación soporta menos carga de procesamiento.

• Firewall: es igual que en cualquier otra red. Es un sistema o conjunto combinado de sistemas que crean una barrera segura entre dos redes. El propósito de un firewall es mantener a los intrusos fuera de la red GPRS, de manera que no puedan acceder a los nodos y provocar fallos.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

74 Francisco Prieto Donate

3.4.2 Interfaces de una red GPRS

Las conexiones del sistema GPRS a la parte de conmutación de la red GSM se implantan a través de la red SS7 (Gc, Gd, Gf, Gr, Gs), mientras que las otras interfaces y puntos de referencia están implementados a través de la red troncal Inter-PLMN (Gp) o de redes externas (Gi).

En esta figura se identifican todas ellas:

Figura 3.4: Interfaces de una red GPRS

A continuación vamos a describir todas estas interfaces:

• Interfaz Gb: Es la que conecta el SGSN con la BSS. Es la portadora del tráfico GPRS y de la señalización entre la parte radio de la red GSM (BSS) y la parte GPRS. Está basada en una conexión Frame Relay entre BSS y SGSN, bien mediante enlace directo o a través de una red Frame Relay.

• Interfaz Gi: Esta interfaz está presente solamente en el GGSN. Es la interfaz mediante la cual se accede a las redes de datos externas y en las especificaciones se definen los siguientes protocolos: IPv4, IPv6 y X.25.

• Interfaz Gn: Esta interfaz se encuentra presente tanto en el GGSN como en el SGSN, de manera que permite comunicarse a los SGSNs y GGSNs entre sí mediante una red troncal Intra-PLMN. En esta interfaz se emplea el protocolo

3. GPRS

Francisco Prieto Donate 75

GTP (GPRS Tunnelling Protocol), basado en IP, para llevar datos de usuario y señalización. Puede haber diferentes configuraciones para los canales físicos asociados a la interfaz Gn: Ethernet, ATM, etc.

• Interfaz Gp: Proporciona la misma funcionalidad que la interfaz Gn, pero también proporciona, con el BG y el Firewall, todas las funciones necesarias en la conexión Inter-PLMN como, por ejemplo, seguridad, encaminamiento, etc. También se emplea el protocolo GTP para llevar a cabo la creación de túneles, pero en este caso con un GGSN exterior. Por este motivo la pila de protocolos es la misma que en la interfaz Gn.

• Interfaz Gs: Esta interfaz existe entre el SGSN y la MSC. Permite hacer un uso efectivo de los recursos en una red GSM/GPRS combinada. El protocolo que se emplea en esta interfaz es el BSSAP+, el cual es un subconjunto del protocolo BSSAP.

• Interfaz Gr: Es la que existe entre el SGSN y el HLR para el intercambio de señalización. Permite al SGSN acceder a la información de usuario que reside en el HLR, el cual puede estar situado en una PLMN diferente que el SGSN. Es una interfaz MAP estándar. Su pila de protocolos está compuesta por MAP, TCAP, SCCP y MTP. Suele emplear enlaces físicos SS7. Algunas de las operaciones que soporta esta interfaz son:

� Actualización de localización GPRS.

� Inserción de datos de usuario.

� Borrado de datos de usuario.

� Purga de un MS.

� Cancelación de localización.

• Interfaz Gc: Esta interfaz, de carácter opcional, es la que permite intercambiar información de señalización entre el GGSN y el HLR empleando el protocolo MAP.

• Interfaz Gd: Es una interfaz MAP estándar para la conexión de SSGN con el centro de mensajes cortos (SMS). Con esta interfaz se consigue un uso más

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

76 Francisco Prieto Donate

eficiente de los servicios de mensajes cortos, ya que en GPRS se aprovecha mejor la interfaz radio que en GSM. Se soporta también sobre señalización SS7.

• Interfaz Gf: Se encuentra entre SGSN y EIR (Equipment Identity Register), y permite al SGNS acceder a información del terminal. En el EIR los terminales se pueden encontrar en una de estas tres listas: negra (terminales robados), gris (en observación) y blanca (sin problemas). Esta interfaz es también MAP estándar.

3.5 Tipología de servicios

El servicio GPRS pone a disposición de sus usuarios dos tipologías de servicio diferentes:

• Punto a Punto (Point To Point, PTP).

• Punto a Multipunto (Point To Multipoint, PTM).

Un servicio Point To Point es un servicio en el que el usuario envía uno o más paquetes a un único destinatario. Se pueden dar dos clases de servicios punto a punto:

• ConnectionLess Point To Point services (CLNS).

• Connection Oriented Point To Point services (CONS).

Un servicio PTP CLNS es un servicio en el que dos paquetes sucesivos son enviados a la red de forma independiente. Se define como un servicio de datagrama y puede ser útil para soportar aplicaciones bursty (a ráfagas) de tipo no interactivo.

Un servicio PTP CONS es, por el contrario, un servicio en el que se establece una relación lógica entre la fuente y el destinatario de los paquetes, relación que permanece activa durante el tiempo total de la conexión. El servicio es, por lo tanto, un circuito virtual, es decir, en la fase de set-up de la conexión se establece un recorrido para el routing de los paquetes. Con respecto a una conexión por conmutación de circuito, tiene la diferencia de que los recursos físicos se liberan en cuanto el paquete genérico se ha transmitido, manteniendo la conexión lógica. Las aplicaciones que se adaptan bien a un servicio bearer (portador) de este tipo son aquellas interactivas o transaccionales, en las que se mantiene un diálogo continuo entre las dos entidades en comunicación.

3. GPRS

Francisco Prieto Donate 77

Los servicios PTM, al contrario que los servicios PTP, implican a más de un usuario destinatario y ejecutan el envío de paquetes en base geográfica. Hay que tener en cuenta que estos servicios no pueden implicar, como usuarios destinatarios de paquetes, a los usuarios de las redes interconectadas a la GPRS PLMN, sino sólo a usuarios de móviles.

Se definen tres diferentes servicios PTM:

• PTM – Multicast, en el cual los mensajes son unidireccionales y se entregan en un área geográfica. Los mensajes incluyen un IMGI (International Mobile Group Identity) que indica al receptor de dónde procede el mensaje. La red no conoce los potenciales receptores de éste y no asegura su entrega.

• PTM – GroupCall, que permite enviar un mensaje unidireccional, bidireccional o multidireccional a un cierto grupo de usuarios dentro de un área geográfica determinada. Al igual que en el caso anterior, el mensaje incluye un IMGI. La red tiene conocimiento de la localización de los miembros activos del grupo, entregando el mensaje sólo en las celdas en las que éstos residen y garantizando la recepción del mismo.

• IP Multicast es un servicio definido como parte del conjunto IP. En IP-M los mensajes son enviados entre los miembros de un grupo IP, que puede ser interno a una PLMN o estar distribuido a través de Internet.

3.6 Terminales GPRS

GPRS puede combinar hasta 8 canales para transferir datos, y cada canal puede transferir a una velocidad de 8 a 12 Kbps. Esta tecnología permite desdoblar la transmisión de voz y datos en diferentes canales que transmiten de forma paralela, permitiendo mantener conversaciones sin cortar la transmisión de datos. Los terminales GPRS cuentan con diversas prestaciones en función del número de canales que utilicen. Debido a esto, contaremos con terminales 2 + 1 (dos canales para recibir información y un canal para el envío), 3 + 1, 4 + 1, etc.

El uso de GPRS no se limita sólo a los teléfonos móviles o PDAs; existen también tarjetas PCMCIA GPRS para conectar portátiles a Internet, tarjetas para conectar el ordenador de sobremesa, etc. El uso de este tipo de terminales como módem inalámbrico tiene una aplicación inmediata y evidente: los podemos conectar a ordenadores portátiles o de sobremesa como cualquier módem, pero evidentemente con la ventaja de ser inalámbrico.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

78 Francisco Prieto Donate

Igualmente, los terminales GPRS nos permiten visualizar contenidos y utilizar servicios de Internet directamente en su pantalla reducida, en una evolución continua de convergencia entre el teléfono móvil y los PDA.

Los terminales se pueden clasificar en cinco tipos, en función del uso que le vaya a dar el usuario:

• Teléfonos móviles, que permiten el uso de información escrita o gráfica de forma resumida.

• Terminales tipo agenda electrónica, con funciones mixtas de voz y datos, y pantallas de mayor tamaño y capacidad gráfica que un teléfono móvil.

• Terminales tipo ordenador personal de mano (PDA) con pantalla de mayor formato y gran capacidad gráfica.

• Ordenadores portátiles que utilicen para la conexión inalámbrica un teléfono móvil GPRS.

• Dispositivos diversos con comunicación móvil y funciones especiales como sistemas de navegación para coches y tarjetas de comunicación inalámbrica en máquinas autoservicio.

Figura 3.5: Terminales GPRS

3. GPRS

Francisco Prieto Donate 79

La introducción de un servicio de datos por conmutación de paquetes, como es GPRS, no asegura a los usuarios GSM la posibilidad de disfrutar simultáneamente de servicios por conmutación de circuito (voz, datos). Naturalmente el uso compartido de los servicios puede llevar a una degradación de las prestaciones en términos de throughput (rendimiento) de la llamada GPRS.

Con este propósito se definen tres clases de servicio en los terminales:

• Clase A: las estaciones móviles de este tipo permiten al usuario utilizar tanto una conexión por conmutación de circuito como una por conmutación de paquetes con el máximo throughput (rendimiento) posible. Para ello el terminal necesita dos transmisores y dos receptores, uno para cada servicio. Estas características hacen que los dispositivos de clase A resulten extremadamente caros.

• Clase B: las estaciones móviles de este tipo pueden registrarse tanto en redes GSM como en GPRS simultáneamente pero sólo pueden tener una llamada activa en un momento dado: o una llamada de voz o una conexión de datos. Cuando una llamada de voz termina, la conexión de datos puede volver a iniciarse. La mayoría de teléfonos hoy en día son de esta clase.

• Clase C: las estaciones móviles de este tipo no permiten el uso simultáneo de los servicios, por tanto, el usuario que está disfrutando de un servicio no puede utilizar también otro.

3.7 Tercera generación de móviles: UMTS

La evolución natural de GPRS es UMTS (Universal Mobile Telecommunications System), que pasamos a comentar brevemente.

Existen diversos factores que propiciaron el desarrollo de la tecnología de tercera generación. Por un lado las redes GSM estaban comenzando a saturarse, de modo que se hacía necesario conseguir una mayor eficiencia espectral. A su vez estaban comenzando a desarrollarse nuevos servicios que requerían un ancho de banda mucho mayor que el que proporcionaba GPRS.

Por todo ello se hacía necesario crear nuevas infraestructuras que soportaran estas nuevas características. UMTS requiere una nueva tecnología de radio (grandes inversiones en infraestructuras), una red de mayor capacidad (debido a que las velocidades de transferencia varían de 384 Kbps a 2 Mbps) y nuevos terminales.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

80 Francisco Prieto Donate

Estos factores hicieron prever que UMTS tardaría un cierto tiempo en establecerse y que GPRS, dada su mayor cobertura, mantendría un uso elevado. Hay que destacar que ninguna tecnología es excluyente entre sí. La aparición de GPRS no excluye GSM; igualmente, UMTS no implica la anulación de GPRS. Es más, la mayoría de los dispositivos UMTS actuales ofrecen soporte GPRS, de modo que si nos encontramos en un lugar sin cobertura 3G automáticamente se conmuta a una conexión 2,5G.

En la actualidad la tecnología UMTS continúa con su despliegue. En Noviembre de 2006 la cobertura de tercera generación en España es de un 80% con las operadoras Movistar y Vodafone, y de un 40% con Orange. Los teléfonos móviles actuales incorporan ya soporte para esta tecnología, aunque los servicios ofrecidos tienen aún un precio elevado. Existen también todo tipo de dispositivos que se conectan al PC para ofrecer conexión a Internet en cualquier lugar a través de la tecnología UMTS 3G.

En la tabla adjunta se ofrece una comparativa de la tasa máxima de transmisión de datos en los diferentes estándares de telefonía móvil que se utilizan en la actualidad:

Sistema Kbps max.

teóricos

Kbps max. reales

Comentarios

GSM 9,6 9,6 Conmutación de circuitos

HSCSD (High Speed Circuit Switched Data) 57,6 28,8

Se agrupan varios canales GSM para una

misma transmisión de datos GPRS

171,2 44 Conmutación de paquetes

EDGE (Enhanced Data Rates for Global

Evolution) 384 70 Cambio de sistema de modulación

UMTS De 384 a 2000 100 Interfaz radio UTRAN

Tabla 3.1: Velocidades de transmisión en telefonía móvil

3.8 Consideraciones finales

En este capítulo hemos estudiado GPRS, una de las tecnologías que usan los dispositivos móviles de segunda generación para conectarse a Internet.

3. GPRS

Francisco Prieto Donate 81

Tras comprobar las carencias de velocidad que aportaba GSM en transmisión de datos, nació GPRS como una extensión de ese estándar. Tuvo que adaptarse a la red GSM, introduciendo una red de conmutación de paquetes que funcinara de forma paralela a la de conmutación de circuitos ya existente. A lo largo de este tema hemos podido conocer la arquitectura de red sobre la que funciona GPRS.

Esta nueva red utiliza un nuevo protocolo para poder transmitir datos a través de la interfaz radio. En los apartados anteriores se ha descrito el formato de estas nuevas tramas GPRS.

Por último se presenta la gama de terminales disponibles en el mercado con soporte GPRS, así como una breve introducción a la UMTS, sucesora de GPRS.

En el capítulo siguiente explicaremos qué son los Servicios Web XML y se expondrán distintas formas de implementarlos en dispositivos móviles con soporte J2ME.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

82 Francisco Prieto Donate

4. Servicios Web XML

Francisco Prieto Donate 83

4 SERVICIOS WEB XML

4.1 Introducción

Los Servicios Web son aplicaciones autodescriptivas que se publican, se ubican y se invocan desde cualquier lugar de la Web, con el fin de simplificar el desarrollo de complejas aplicaciones distribuidas.

Estos servicios permiten invocar funciones software a través de Internet, permitiendo que programas basados en PHP, ASP, JSP, JavaBeans y otros muchos puedan hacer peticiones a servicios que se estén ejecutando en una máquina remota y obtener la respuesta para que pueda ser integrada en una página web, un servicio WAP o cualquier otra aplicación.

El concepto de servicio web comienza a extenderse impulsado por los grandes gigantes de la informática como Sun, Oracle, HP, Microsoft e IBM. No aporta muchas novedades en cuanto a implementación, pero sí en cuanto a concepto, facilitando y simplificando el acceso a software a través de la red.

La estandarización de los servicios web se realiza a través de dos comités: OASIS (Organization for the Advancement of Structured Information Standards) y W3C (World Wide Web Consortium). Para mejorar la interoperabilidad entre distintas implementaciones de servicios web surgió la organización WS-I (Web Services Interoperatibility Organization), que ha desarrollado una serie de perfiles para definir mejor los estándares implicados.

4.1.1 Evolución de los Servicios Web

En los años 80, los protocolos de comunicación no ocupaban un lugar demasiado importante para los desarrolladores, ya que conseguir que las aplicaciones se comunicaran entre sí ya era un reto más que suficiente. Es a partir de los años 90 cuando empiezan a sugir algunas estructuras de objetos, como COM (Modelo de Objeto Componente, desarrollado por Microsoft) y CORBA (Arquitectura de negociación de petición de objetos comunes), que permitían a los programadores invocar desde una aplicación la ejecución de código binario de otra aplicación que se ejecutaba en la misma máquina.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

84 Francisco Prieto Donate

Una vez que las redes locales empezaron a extenderse en los años 90 se hizo imprescindible la comunicación entre equipos. Se creó IIOP (Internet Inter-ORB Protocol) como protocolo de CORBA, DCOM (Distributed COM) como protocolo de COM y posteriormente RMI (Remote Method Invocation) para los usuarios de Java.

Mediante el uso de cualquiera de estos protocolos, una aplicación compatible puede invocar componentes que residan en otros ordenadores de la red. El problema radica en que estos protocolos no son interoperables, es decir, los usuarios que utilizan DCOM únicamente pueden llamar a servidores compatibles con DCOM. Por otro lado las soluciones anteriores tienen un requisito de simetría, de modo que no existe el paradigma cliente-servidor y por tanto es obligatoria la implantación del mismo modelo de distribución de objetos en ambos extremos de la comunicación. Esto no se puede garantizar en un entorno tan abierto como Internet.

Tras la aparición de XML a mediados de los 90 nació la posibilidad de estructurar la información de una manera uniforme y autodescriptiva, lo que dio pie a utilizar este lenguaje para aplicar un formato a los mensajes intercambiados entre sistemas. Se implementó un protocolo llamado XML-RPC que permitía llamar a procedimientos de equipos remotos sin tener en cuanta los detalles de sus sistemas operativos o entornos de lenguaje. La evolución del protocolo XML-RPC dio origen al actual SOAP (Simple Object Access Protocol).

4.1.2 Conceptos básicos

Muchas de las ideas detrás de los servicios web son asombrosamente simples y no son una novedad en el mundo de las redes e Internet:

• El proveedor de servicios web define un formato para las peticiones a un servicio y de las respuestas que generará.

• Un ordenador realiza una petición a través de una red.

• El servicio web realiza la acción solicitada y devuelve la respuesta

Esta acción puede consistir en buscar un valor actual de la bolsa, encontrar el mejor precio para un producto determinado, guardar una reunión en una agenda, traducir un fragmento de texto a cualquier lenguaje o validar el número de una tarjeta de crédito.

4. Servicios Web XML

Francisco Prieto Donate 85

La razón del repentino crecimiento de los servicios web es la incorporación de protocolos estándar para invocar servicios y transmitir datos, como son SOAP y WSDL, ambos basados en XML.

4.2 XML

4.2.1 Introducción

XML es un Lenguaje de Etiquetado Extensible muy simple y a la vez estricto, que juega un papel fundamental en el intercambio de una gran variedad de datos. Es un lenguaje que puede parecer muy similar a HTML pero su función principal es describir y estructurar datos y no mostrarlos como es el caso de HTML. XML permite la lectura de datos a través de diferentes aplicaciones. En definitiva, sirve para estructurar, almacenar e intercambiar información.

La especificación XML define un procedimiento estándar para añadir etiquetas (también llamadas marcas) a los documentos; de hecho XML es un meta-lenguaje para definir lenguajes de marcas. En otras palabras, XML ofrece unas reglas para definir etiquetas y relaciones estructurales entre ellas. Al no haber etiquetas predefinidas no existe una semántica a priori; toda la semántica de un documento XML debe ser definida bien por la aplicación que lo procesa o bien por hojas de estilo.

Un documento XML tiene dos estructuras, una lógica y otra física.

• Físicamente, el documento está compuesto por unidades llamadas entidades. Cada documento comienza con una entidad documento, también llamada raíz.

• Lógicamente, el documento está compuesto de declaraciones, elementos, comentarios, referencias a caracteres e instrucciones de procesamiento, todos los cuales están indicados por una marca explícita.

Las estructuras lógica y física deben encajar de manera adecuada.

Existen dos tipos de documentos XML: válidos y bien formados.

• Bien formados: son todos los que cumplen las especificaciones del lenguaje respecto a las reglas sintácticas.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

86 Francisco Prieto Donate

• Válidos: Además de estar bien formados, siguen una estructura y una semántica determinada por un fichero de definición (que es una especie de definición de la gramática del documento). Existen distintas formas de definir estos ficheros de definición, entre ellas DTD y XML Schema.

4.2.2 Reglas sintácticas

A continuación se expone un ejemplo muy simple de un archivo XML.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Alumno> <nombre>Fernando Jaime</nombre> <apellido>Pérez Borrero</apellido> <direccion>C\Gardenia 15</direccion> </Alumno>

En la primera línea se indica que lo que la sigue es XML. Puede tener varios atributos (los campos que van dentro de la declaración), algunos obligatorios y otros no:

• version: indica la versión de XML usada en el documento. La versión actual es la 1.0. Su uso es obligatorio, a no ser que sea un documento externo a otro que ya lo incluía.

• encoding: es la forma en que se ha codificado el documento. Por defecto es UTF-8, aunque podrían utilizarse otras, como UTF-16, US-ASCII, ISO-8859-1, etc. No es obligatorio salvo que sea un documento externo a otro principal.

• standalone: indica si el documento va acompañado de un DTD (standalone=”no”), o no lo necesita (standalone=”yes”); en principio no hay por qué ponerlo, porque más adelante se indica el DTD si se necesita.

En cuanto a la sintaxis del documento se han de resaltar las siguientes reglas:

• Los documentos XML son sensibles a mayúsculas, esto es, en ellos se diferencia las mayúsculas de las minúsculas. Por ello <alumno> sería una etiqueta diferente a <Alumno>.

• Todos los espacios y retornos de carro se tienen en cuenta (dentro de las etiquetas, en los elementos).

4. Servicios Web XML

Francisco Prieto Donate 87

• Hay algunos caracteres especiales reservados, que forman parte de la sintaxis de XML: <, >, &, " y '. En su lugar cuando queramos representarlos deberemos usar las entidades &lt; , &gt; , &amp; , &quot; y &apos; respectivamente.

• Los valores de los atributos de todas las etiquetas deben ir siempre entrecomillados. Son válidas las dobles comillas (") y la comilla simple (').

Observando el contenido del ejemplo se puede diferenciar entre elementos y etiquetas: los elementos son las entidades en sí, lo que tiene contenido, mientras que las etiquetas sólo describen a los elementos. Un documento XML está compuesto por elementos, y en su sintaxis éstos se nombran mediante etiquetas.

Hay dos tipos de elementos: los vacíos y los no vacíos. Hay varias consideraciones importantes a tener en cuenta al respecto:

• Toda etiqueta no vacía debe tener una etiqueta de cerrado: <etiqueta> debe tener su correspondiente </etiqueta>

• Todos los elementos deben estar perfectamente anidados, es decir, las etiquetas deben ser cerradas en orden inverso al que se abrieron.

<Alumno><nombre>Fernando Jaime</Alumno></nombre> -- > INCORRECTO

<Alumno><nombre>Fernando Jaime</nombre></Alumno> -- > CORRECTO

• Los elementos vacíos son aquellos que no tienen contenido dentro del documento. Un ejemplo en HTML son los saltos de línea (<br>). La sintaxis correcta para estos elementos implica que la etiqueta tenga siempre esta forma: <etiqueta/>.

4.2.3 DTD (Definición de Tipos de Documentos)

Un DTD no es más que un conjunto de definiciones de los elementos que puede incluir un documento XML, de la forma en que deben hacerlo (qué elementos van dentro de otros) y los atributos que se les puede dar.

Hay varios modos de referenciar un DTD en un documento XML:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

88 Francisco Prieto Donate

• Incluir dentro del documento una referencia al documento DTD en forma de URI (Universal Resource Identifier, o identificador universal de recursos) mediante la siguiente sintaxis:

<!DOCTYPE Alumno SYSTEM "http://www.esi.us.es/~fprieto/DTD/Alumno.dtd >

En este caso la palabra SYSTEM indica que el DTD se obtendrá a partir de un elemento externo al documento e indicado por el URI que lo sigue.

• O bien incluir dentro del propio documento el DTD de este modo:

<?xml version="1.0"?> <!DOCTYPE Alumno [ <!ELEMENT Alumno (nombre+, apellido+, direccion+, foto?)> <!ELEMENT nombre (#PCDATA)> <!ATTLIST nombre sexo (masculino|femenino) #IMPLIED> <!ELEMENT apellido (#PCDATA)> <!ELEMENT direccion (#PCDATA)> <!ELEMENT foto EMPTY>]> <Alumno> <nombre>Fernando Jaime</nombre> <apellido>Pérez Borrero</apellido> <direccion>C\Lagunilla 15</direccion> </ficha>

La forma de incluir el DTD directamente como en este ejemplo pasa por añadir a la declaración <!DOCTYPE y después del nombre del nombre del tipo de documento, en vez de la URI del DTD, el propio DTD entre los símbolos '[' y ']'. Todo lo que hay entre ellos será considerado parte del DTD.

En cuanto a la definición de los elementos, es bastante intuitiva: después de la cláusula <!ELEMENT se incluye el nombre del elemento (el que luego se indicará en la etiqueta), y después diferentes opciones en función del elemento:

• Entre paréntesis, si el elemento es no vacío, se indica el contenido que puede tener el elemento: la lista de elementos hijos o que descienden de él si los tiene, separados por comas; o el tipo de contenido, normalmente #PCDATA, indicando datos de tipo texto, que son los más habituales.

• Si es un elemento vacío, se indica con la palabra EMPTY.

4. Servicios Web XML

Francisco Prieto Donate 89

A la hora de indicar los elementos descendientes (los que están entre paréntesis) vemos que van seguidos de unos caracteres especiales: '+', '*', '?' y '|'. Sirven para indicar qué tipo de uso se permite hacer de esos elementos dentro del documento:

• + : uso obligatorio y múltiple; permite uno o más elementos de ese tipo dentro del elemento padre, pero como mínimo uno.

• * : opcional y múltiple; puede no haber ninguna ocurrencia, una o varias.

• ? : opcional y singular; puede no haber ninguno o como mucho uno.

• | : equivale a un OR, es decir, da la opción de usar un elemento de entre los que forman la expresión, y solo uno.

De este modo, si por ejemplo encontramos en un DTD la siguiente declaración:

<!ELEMENT Alumno (nombre+, apellido+, direccion*, foto?, telefono*|fax*)>

Indica que elemento Alumno puede contener los siguientes elementos: un nombre y un apellido como mínimo, pero puede tener más de uno de cada; opcionalmente puede incluirse una o varias direcciones, pero no es obligatorio; opcionalmente también se puede incluir una única foto; y por fin, pueden incluirse, aunque no es obligatorio en ninguno de los dos casos, uno o más teléfonos o uno o más números de fax.

4.2.4 XML Schema

XML Schema es algo similar a un DTD, es decir, que define qué elementos puede contener un documento XML, cómo están organizados, y qué atributos y de qué tipo pueden tener sus elementos.

Las ventajas de XML Schema con respecto a los DTDs son:

• Usan sintaxis de XML, al contrario que los DTDs.

• Permiten especificar los tipos de datos.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

90 Francisco Prieto Donate

• Son extensibles.

Por ejemplo, XML Schema permite definir el tipo del contenido de un elemento o de un atributo, y especificar si debe ser un número entero, o una cadena de texto, o una fecha, etc. Los DTDs no nos permiten llegar a tal grado de concreción.

Veamos un ejemplo de un documento XML, y su Schema correspondiente:

<documento xmlns="x-schema:personaSchema.xml"> <persona id="Fernando Jaime"> <nombre>Fernando Jaime Pérez Borrero</nombre> </persona> </documento>

Como se puede ver en el documento XML anterior, se hace referencia a un espacio de nombres llamado "x-schema:personaSchema.xml". Es decir, le estamos diciendo al analizador sintáctico XML que valide el documento contra el Schema "personaSchema.xml".

El Schema sería algo parecido a esto:

<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes"> <AttributeType name='id' dt:type='string' required='yes'/> <ElementType name='nombre' content='textOnly'/> <ElementType name='persona' content='mixed'> <attribute type='id'/> <element type='nombre'/> </ElementType> <ElementType name='documento' content='eltOnly'> <element type='persona'/> </ElementType> </Schema>

El primer elemento del Schema define dos espacios de nombres. El primero, xml-data, le dice al analizador que esto es un Schema y no otro documento XML cualquiera. El segundo, datatypes, nos permite definir el tipo de elementos y atributos utilizando el prefijo dt.

En la siguiente tabla se muestra el significado de cada uno de las etiquetas contenidas en el XML Schema.

4. Servicios Web XML

Francisco Prieto Donate 91

Nombre Significado

ElementType Define el tipo y contenido de un elemento, incluyendo los sub-elementos que pueda contener.

AttributeType Asigna un tipo y condiciones a un atributo.

Attribute Declara que un atributo previamente definido por AttributeType puede aparecer como atributo de un elemento determinado.

Element Declara que un elemento previamente definido por ElementType puede aparecer como contenido de otro elemento.

Tabla 4.1: Significado de las etiquetas contenidas en el XML Schema

Es necesario empezar el Schema definiendo los elementos más profundamente anidados dentro de la estructura jerárquica de elementos del documento XML. Las declaraciones de tipo ElementType y AttributeType deben preceder a las declaraciones de contenido Element y Attribute correspondientes.

4.2.5 Espacios de nombres XML

Los XML Namespaces (Espacios de nombres XML) proporcionan un método para evitar conflictos en los nombres de los elementos. Como los elementos en XML no están predefinidos, podría ocurrir un conflicto de nombres cuando dos elementos diferentes usan los mismos nombres de elementos

El siguiente documento XML lleva información sobre una tabla:

<table>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

92 Francisco Prieto Donate

<tr> <td>Apples</td> <td>Bananas</td> </tr> </table>

Y el documento que viene a continuación lleva información sobre una mesa:

<table> <name>African Coffee Table</name> <width>80</width> <length>120</length> </table>

Si estos dos documentos se unieran en uno solo, habría un conflicto en los nombres de elementos, ya que cada uno contiene un elemento <table> diferente con distinto contenido y definición.

Una forma de resolver el conflicto es usando un prefijo que se incluiría dentro de cada etiqueta, precediendo al nombre:

Para el caso de la tabla utilizaríamos el prefijo h:

<h:table> <h:tr> <h:td>Apples</h:td> <h:td>Bananas</h:td> </h:tr> </h:table>

Y para el caso de la mesa utilizaríamos el prefijo f:

<f:table> <f:name>African Coffee Table</f:name> <f:width>80</f:width> <f:length>120</f:length> </f:table>

Ahora no habrá conflictos de nombres porque los dos documentos usan un nombre diferente para su elemento <table>.

Según la especificación, las etiquetas deben ser Namespaces identificados por un URI (Uniform Resource Identifier). Este Identificador de Recursos Uniforme es un método que combina URNs y URLs, y que sirve para identificar de forma universal

4. Servicios Web XML

Francisco Prieto Donate 93

recursos de todo tipo existentes en la World Wide Web. Para asociar una etiqueta con un URI se utiliza el atributo xmlns.

Para el caso de la tabla utilizaríamos el espacio de nombres: http://www.w3.org/TR/html4/.

<h:table xmlns:h="http://www.w3.org/TR/html4/"> <h:tr> <h:td>Apples</h:td> <h:td>Bananas</h:td> </h:tr> </h:table>

Para el caso de la mesa utilizaríamos el espacio de nombres: http://www.w3schools.com/furniture.

<f:table xmlns:f="http://www.w3schools.com/furniture"> <f:name>African Coffee Table</f:name> <f:width>80</f:width> <f:length>120</f:length> </f:table>

Cuando se define un Namespace en la etiqueta inicial de un elemento, todos los elementos hijo con el mismo prefijo se asocian al mismo espacio de nombres. Cabe resaltar que la dirección usada para identificar al Namespace no va a ser usada por el parser de XML para buscar información; su único propósito es establecer un nombre único para el prefijo.

4.2.6 Analizadores XML

Los analizadores XML son un elemento clave en los servicios web, ya que se encargan de interpretar los datos contenidos en el documento y hacerlos accesibles a la aplicación. En dispositivos con baja capacidad de procesamiento son un factor decisivo, ya que suelen tener un gran tamaño y consumen mucha memoria.

Existen tres tipos principales de analizadores XML, cada uno con sus ventajas e inconvenientes:

• Analizador de modelo: Lee el documento XML completamente y crea en la memoria una representación estructurada de los datos. Su gran ventaja es que el análisis se realiza al principio y luego se pueden tratar los datos como una

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

94 Francisco Prieto Donate

estructura cualquiera. Su desventaja principal es el alto consumo de memoria. El analizador DOM se basa en esta idea.

• Analizador push: Se define un conjunto de eventos que pueden aparecer en un documento XML, como pueden ser el comienzo de una etiqueta o la presencia de datos de texto, y al encontrar uno de estos eventos llama a un método que lo procese adecuadamente. El analizador SAX, usado por JSR-172, es de este tipo.

• Analizador pull: El documento XML se va recorriendo poco a poco mediante un método que pide el siguiente elemento. El analizador kXML, usado por kSOAP, es de este tipo.

4.3 SOAP

El protocolo de acceso a objetos simples (Simple Object Access Protocol, SOAP) en un estándar de W3C que define el formato de las peticiones para los servicios web.

Los mensajes SOAP son enviados entre los dos extremos de la comunicación en los llamados sobres SOAP para hacer una petición o enviar una respuesta. Estos sobres están formateados en XML y son muy fáciles de descodificar.

Actualmente un sin fin de empresas se han decantado por el desarrollo de aplicaciones que puedan trabajar sobre Internet porque permite la distribución global de la información. Las tecnologías más usadas para el desarrollo de estas aplicaciones han sido hasta hace poco CORBA, COM y EJB. Cada una proporciona un marco de trabajo basado en la activación de objetos remotos mediante la solicitud de ejecución de servicios a un servidor de aplicaciones.

Estas tecnologías han demostrado ser muy efectivas para el establecimiento de sitios Web, sin embargo presentan una serie de desventajas, como son la total incompatibilidad e interoperabilidad entre ellas y la dependencia de la plataforma sobre la que corren, así como del lenguaje de programación.

Esto ha llevado a la necesidad de considerar un nuevo modelo de computación distribuida de objetos que no sea dependiente de plataformas, modelos de desarrollo ni lenguajes de programación. Por todos estos motivos surge el concepto de SOAP (Simple Object Access Protocol).

4. Servicios Web XML

Francisco Prieto Donate 95

4.3.1 Concepto de SOAP

La ventaja que aporta SOAP es la de proporcionar un mecanismo simple y ligero de intercambio de información entre dos puntos mediante documentos XML. SOAP no es más que un sencillo protocolo capaz de expresar la información mediante un modelo de empaquetado de datos modular y una serie de mecanismos de codificación de datos. Esto permite que SOAP sea utilizado en un amplio rango de servidores de aplicaciones que trabajen mediante el modelo de comunicación RPC (Remote Procedure Call).

La especificación SOAP consta de tres partes:

• El SOAP envelope, que define el marco de trabajo que determina qué se puede introducir en un mensaje, quién debería hacerlo y si esa operación es opcional u obligatoria.

• Las reglas de codificación SOAP que definen el mecanismo de serialización que será usado para encapsular en los mensajes los distintos tipos de datos.

• La representación SOAP RPC que define un modo de funcionamiento a la hora de realizar llamadas a procedimientos remotos y la obtención de sus resultados.

4.3.2 Objetivos de SOAP

A la hora de realizar el diseño de SOAP se han tenido en cuenta una serie de consideraciones con el fin de cumplir una serie de objetivos claros, objetivos que le darán el potencial que reside en SOAP y que le harán tan atractivo. Éstos son:

• Establecer un protocolo estándar de invocación a servicios remotos que esté basado en protocolos estándares de uso frecuente en Internet, como son HTTP (Hiper Text Transport Protocol) para la transmisión y XML (eXtensible Markup Language) para la codificación de los datos.

• Establecer un protocolo abierto y extensible, de modo que no existen restricciones en cuanto a datos o medio de transporte (la especificación define la manera en que los mensajes se intercambian por HTTP, pero no obliga a utilizar este protocolo).

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

96 Francisco Prieto Donate

• Independencia de plataforma hardware, lenguaje de programación e implementación del servicio Web.

El logro de estos objetivos ha hecho de SOAP un protocolo extremadamente útil, ya que el protocolo de comunicación HTTP es el empleado para la conexión sobre Internet, por lo que se garantiza que cualquier cliente con un navegador estándar pueda conectarse con un servidor remoto. Además, los datos en la transmisión se empaquetan o serializan con el lenguaje XML, que se ha convertido en algo imprescindible en el intercambio de datos ya que es capaz de salvar las incompatibilidades que existían en el resto de protocolos de representación de datos de la red.

Por otra parte, los servidores Web pueden procesar las peticiones de usuario empleando tecnologías tales como Servlets, páginas ASP (Active Server Pages) o páginas JSP (Java Server Pages).

La especificación SOAP 1.1 indica que las aplicaciones deben ser independientes del lenguaje de desarrollo, por lo que las aplicaciones cliente y servidor pueden estar escritas con HTML, DHTML, Java, Visual Basic o cualquier otra herramienta o lenguaje disponibles.

4.3.3 Un ejemplo sencillo de mensajes SOAP

Supongamos un servicio web que permita comprobar si un código postal es válido y pertenece realmente al país especificado. Este servicio web sería muy útil para asegurar la validez en un formulario de una página web. El código relativo a la petición SOAP sería:

<env:Envelope

xmlns:env="http://www.w3.org/2001/06/soap-envelope">

<env:Body>

<m:ValidatePostcode

env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"

xmlns:m="http://www.somesite.com/Postcode">

<Postcode>

WC1A8GH

</Postcode>

<Country>

UK

</Country>

4. Servicios Web XML

Francisco Prieto Donate 97

</m:ValidatePostcode>

</env:Body>

</env:Envelope>

Esta petición tiene dos parámetros (postcode y country) contenidos en un elemento llamado ValidatePostcode, que sería el nombre del servicio web al que estamos haciendo la petición. El resto de los datos del sobre, como la versión de SOAP y la codificación del texto, ayuda al servicio web a procesar la petición.

La respuesta al mensaje anterior tendría el siguiente formato:

<env:Envelope

xmlns:env="http://www.w3.org/2001/06/soap-envelope" >

<env:Body>

<m:ValidatePostcodeResponse

env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"

xmlns:m="http://www.somesite.com/Postcode">

<Valid>

Yes

</Valid>

</m:ValidatePostcodeResponse>

</env:Body>

</env:Envelope>

El elemento ValidatePostcodeResponse contesta al elemento ValidatePostcode de la petición, conteniendo un único elemento, Valid, que indica si el código postal introducido es válido o no.

4.3.4 Partes de un mensaje SOAP

Un mensaje SOAP no es más que un documento en formato XML que está constituido por tres partes bien definidas: el SOAP envelope, el SOAP header, de carácter opcional, y el SOAP body.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

98 Francisco Prieto Donate

Figura 4.1: Partes de un mensaje SOAP

Cada uno de estos elementos se detalla a continuación:

• El envelope es el elemento más importante y de mayor jerarquía dentro del documento XML y representa al mensaje que lleva almacenado dicho documento. Todo mensaje SOAP 1.1 debe tener un elemento envelope asociado al espacio de nombres http://schemas.xmlsoap.org/soap/envelope/. Si un mensaje recibido por una aplicación SOAP contiene en este elemento un valor distinto al anterior la aplicación trataría dicho mensaje como erróneo.

• El header es un mecanismo genérico que se utiliza para añadir características adicionales al mensaje SOAP sin tener que modificar su estructura. El modo en la que se añadan cada uno de los campos dependerá exclusivamente del servicio implementado, de forma que cliente y servidor deberán estar de acuerdo con la jerarquía con la que se hayan añadido los distintos campos. De esta forma será sencillo separar entre sí los distintos datos a transmitir dentro del mensaje.

Un ejemplo de uso del header, donde se indica un cierto parámetro útil para el servicio Web que le indica como debe procesar el mensaje, sería:

<?xml version="1.0"?>

<SOAP-Envelope

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

SOAP-ENV:encodingStyle=

"http://schemas.xmlsoap.org/soap/encoding/"/>

4. Servicios Web XML

Francisco Prieto Donate 99

<SOAP-ENV:Header>

<t:Transaction xmlns:t="some-URI"

SOAP-ENV:mustUnderstand="1">

5

</t:Transaction>

</SOAP-ENV:Header>

<SOAP-ENV:Body>

<getQuote

xmlns="http://namespaces.cafeconleche.org/xmljava/ch2/">

<symbol>

RHAT

</symbol>

</getQuote>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

• El body es un contenedor de información en el cual se almacenarán los datos que se quieran transmitir de lado a lado de la comunicación. Es aquí donde se aloja la carga útil del mensaje, de forma que para una comunicación RPC el body contendrá, entre otros, los datos referidos a la ubicación del servidor, nombre del método a invocar y parámetros necesarios. Debe depender únicamente del elemento envelope, y se sitúa inmediantamente después del elemento header en el caso de que exista. Dentro de este campo, SOAP define un elemento de uso opcional denominado Fault utilizado en los mensajes de respuesta para indicar al cliente algún error ocurrido en el servidor. Un ejemplo de uso de este nuevo elemento sería el siguiente, en el que se ha detectado un error en la aplicación que corre sobre el servidor que provoca que no opere convenientemente, por lo que se le indica al cliente:

<?xml version="1.0"?>

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >

SOAP-ENV:encodingStyle=

"http://schemas.xmlsoap.org/soap/encoding/"/>

<SOAP-ENV:Body>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

100 Francisco Prieto Donate

<SOAP-ENV:Fault>

<faultcode>

SOAP-ENV:Server

</faultcode>

<faultstring>

Server Error

</faultstring>

<detail>

<e:myfaultdetails xmlns:e="Some-URI">

<message>

My application didn't work

</message>

<errorcode>

1001

</errorcode>

</e:myfaultdetails>

</detail>

</SOAP-ENV:Fault>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

El atributo encodingStyle se utiliza para indicar las reglas de serialización utilizadas en el mensaje SOAP. No existe un formato de codificación por defecto, sino que existen una serie de posibles formatos a utilizar. El valor de este atributo es una lista ordenada de una o más URIs que identifican la regla o reglas de serialización que pueden ser utilizadas en el mensaje, en el orden en el que se han de aplicar. De entre todas las posibles, las más utilizadas son: http://schemas.xmlsoap.org/soap/encoding/ y http://my.host/encoding/ .

4. Servicios Web XML

Francisco Prieto Donate 101

4.3.5 Enlaces SOAP (bindings)

Podría pensarse que SOAP consiste en un documento XML transmitido por HTTP. Lo cierto es que la norma no especifica nada respecto al medio de transporte de los mensajes. Dicho de otra manera, se pueden utilizar otros protocolos de transporte (SMTP, FTP) o cualquier otro mecanismo que se nos ocurra (ficheros de texto). En el caso de elegir HTTP como transporte de SOAP, es necesario cumplir algunas reglas básicas:

• Los mensajes se deben enviar mediante el mecanismo HTTP POST.

• El tipo de contenido debe ser text/xml.

• En la cabecera de HTTP aparecerá un nuevo encabezamiento llamado SOAPAction, cuya misión es hacer saber el propósito del mensaje SOAP a los servidores que lo reciban, sin tener que acceder al cuerpo del mensaje para obtener dicha información.

• Si el mensaje de respuesta contiene un fallo, el código del estado de la respuesta HTTP debe ser 500.

Como curiosidad cabe citar que, debido a la flexibilidad que otorga la norma en cuanto al método de transmisión, hasta una paloma mensajera podría ser el mecanismo de transporte de nuestros mensajes SOAP.

4.3.6 SOAP 1.2

En Junio de 2003 el W3C publicó la especificación SOAP 1.2. Esta nueva versión establece algunas modificaciones y aporta muchas novedades tanto en la sintaxis como en la codificación con respecto a SOAP 1.1.

La librería que implementa el protocolo SOAP en este proyecto, kSOAP2, se basa en la especificación SOAP 1.1, por ello vamos a nombrar solamente los cambios más significativos que aporta la versión 1.2:

• Sintaxis

� No se permite ningún elemento detrás de body.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

102 Francisco Prieto Donate

� El atributo env:encodingStyle no debe aparecer en el envelope.

� En el elemento opcional Fault se ha sustituido client y server por Sender y Receiver. Asimismo los nombres de elementos faultcode y faultstring han sido renombrados por env:Code y env:Reason, respectivamente.

� Se define el nuevo elemento de cabecera env:NotUnderstood, utilizado cuando la información marcada con env:MustUnderstand no ha podido ser procesada.

� Los valores del atributo de la cabecera env:mustUnderstand toma los valores lógicos true o false, en lugar de 1 o 0.

• Enlace SOAP HTTP

� La cabecera Content-type debe ser application/soap+xml en lugar de text/xml.

• Codificaciones

� La sintaxis para la serialización de los arrays ha sido modificada.

� Se han eliminado valores compuestos genéricos del SOAP Data Model.

4.4 WSDL

WSDL (Web Services Definition Language) es un lenguaje basado en XML que usamos para describir un servicio web. Al publicar nuestro servicio es recomendable publicar conjuntamente un archivo WSDL que indique los métodos, dirección y estructura de éste. Cuando un cliente quiera consumir nuestro servicio bastará con que interprete el contenido del archivo WSDL, de modo que no es necesario conocer los detalles de la implementación, la plataforma o el sistema operativo sobre el que se está ejecutando.

4. Servicios Web XML

Francisco Prieto Donate 103

4.4.1 Elementos de un documento WSDL

Un documento WSDL está compuesto por definiciones. Éstas definen un servicio como un conjunto de una o más redes de puntos extremos o puertos. Cada puerto está asociado a un enlace específico que se encarga de definir la manera en que un conjunto abstracto de operaciones y mensajes está enlazado a un puerto de acuerdo a un protocolo específico. Un enlace asigna un protocolo específico a un tipo de puerto. El tipo de puerto está compuesto por una o más operaciones, que representan un conjunto abstracto de posibilidades que el servicio puede llevar a cabo. Cada operación está compuesta por un conjunto de mensajes abstractos que representan los datos comunicados durante una operación. Cada mensaje contiene una o más partes de datos, que se definen como tipos.

La siguiente figura muestra de forma esquematizada la estructura que sigue un documento WSDL:

���������

���������

�������

�������

����

����

��

��

nPuerto

Puerto

nOperación

Operación

nMensaje

Mensaje

nTipo

Tipo

Tipo

Mensaje

Operación

EnlacePuerto

Servicio

_...

2_

_...

2_

_...

2_

_...

2_1_

1_

1_

1_1_

Figura 4.2: Estructura esquematizada de un documento WSDL

Detallamos a continuación cada una de las partes:

• <definitions>: Dentro de este elemento se definirán los servicios asociados al documento. Generalmente cada documento WSDL describe un solo servicio, y suele seguir la siguiente estructura:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

104 Francisco Prieto Donate

<definitions>

<documentation>

Comentarios del servicio.....

</documentation>

<types>

Definición de tipos....

</types>

<message>

Definición de mensaje....

</message>

<portType>

Definición de operaciones....

</portType>

<binding>

Definición de invocación....

</binding>

<service>

Ubicación del servicio....

</service>

</definitions>

• <documentation>: Se utiliza para comentarios

• <types>: Define los tipos de datos contenidos en los mensajes. Ejemplo:

<types>

<complexType name="request">

<sequence>

<element name="String_1" type="string"/>

<element name="String_2" type="string"/>

</sequence>

4. Servicios Web XML

Francisco Prieto Donate 105

</complexType>

</types>

Aquí se define un tipo complejo llamado request formado por dos cadenas de caracteres, String_1 y String_2.

• <message>: Un mensaje es un contenedor de tipos de datos. Es importante saber que estos mensajes son abstractos, de manera que no hay que confundirlos con los mensajes físicos que se enviarán vía SOAP. Ejemplo:

<message name="Interface_request">

<part name="parameters" element="ns2:request"/>

</message>

Aquí se define el mensaje Interface_request, cuyo parámetro es un elemento del tipo request, anteriormente definido en <types>.

• <portType>: Define las operaciones que realiza el servicio y los mensajes correspondientes. Ejemplo:

<portType name="Interface">

<operation name="request">

<input message="tns:Interface_request"/>

<output message="tns:Interface_requestResponse"/>

</operation>

</portType>

Aquí define la operación request dentro del puerto Interface cuyo mensaje de entrada es Interface_request y el de salida es Interface_requestResponse.

• <binding>: Se traduce como enlace. Define el formato y detalles del protocolo para cada operación. Ejemplo:

<binding name="InterfaceBinding" type="tns:Interface">

<soap:binding

transport="http://schemas.xmlsoap.org/soap/http"

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

106 Francisco Prieto Donate

style="document"/>

<operation name="request">

<soap:operation soapAction=""/>

<input>

<soap:body use="literal"/>

</input>

<output>

<soap:body use="literal"/>

</output>

</operation>

</binding>

Aquí se especifica que los mensajes van a seguir el estilo document/literal.

• <service>: Define la ubicación del servicio. Ejemplo:

<service name="Serverscript">

<port name="InterfacePort" binding="tns:InterfaceBinding">

<soap:address location="http://localhost:8080/server/">

</port>

</service>

Se indica que el servicio estará situado en la dirección http://localhost:8080/server.

Cabe resaltar que los elementos de un documento WSDL siguen un orden tal que el primer elemento, types, se corresponde con el nivel más bajo de la estructura representada anteriormente. De la misma forma el último elemento, service, se corresponde con el nivel más alto de la estructura jerárquica representada en la figura anterior.

4.4.2 Estilo y uso de un documento WSDL

Un archivo WSDL puede tener un estilo de llamada a procedimiento remoto (RPC) o un estilo documento (document), que afectará al formato de los datos en dicho archivo y en los mensajes SOAP que se intercambien. Será el atributo opcional style el que indicará el estilo del mensaje.

4. Servicios Web XML

Francisco Prieto Donate 107

Un valor RPC indica que el mensaje utiliza una codificación de tipo RPC, cuyo objetivo es representar una llamada de método y una lista de parámetros. Un valor document indica que el mensaje tiene un estilo de tipo documento, esto es, el mensaje representa un solo documento. En el caso de no especificar ningún estilo, se asume document por defecto.

Un archivo WSDL con estilo RPC tendría la siguiente forma:

<message name="myMethodRequest">

<part name="x" type="xsd:int"/>

<part name="y" type="xsd:float"/>

</message>

<message name="empty"/>

<portType name="PT">

<operation name="myMethod">

<input message="myMethodRequest"/>

<output message="empty"/>

</operation>

</portType>

Define dos mensajes: El primero de petición, llamado myMethodRequest que recibe dos parámetros numéricos, uno entero y otro flotante. El segundo mensaje está vacío. Por último especifica la operación myMethod que recibe el mensaje myMethodRequest y devuelve el mensaje vacío empty. Este mismo ejemplo en estilo documento sería así:

<types>

<schema>

<element name="xElement" type="xsd:int"/>

<element name="yElement" type="xsd:float"/>

</schema>

</types>

<message name="myMethodRequest">

<part name="x" element="xElement"/>

<part name="y" element="yElement"/>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

108 Francisco Prieto Donate

</message>

<message name="empty"/>

<portType name="PT">

<operation name="myMethod">

<input message="myMethodRequest"/>

<output message="empty"/>

</operation>

</portType>

En este caso se crea un esquema con los elementos xElement e yElement de tipos entero y flotante respectivamente, y en el mensaje se especifican estos elementos en lugar de los tipos. RPC tiene la ventaja de ser más simple, pero el estilo documento es más correcto, ya que el archivo WSDL podría validarse con un analizador XML y además cumple con las especificaciones de WS-I, que promueve la interoperabilidad de servicios web.

Otro factor que afecta a los mensajes SOAP del servicio es el uso, que puede ser codificado (encoded) o literal. Un mensaje SOAP RPC/encoded tendría la siguiente forma:

<soap:envelope>

<soap:body>

<myMethod>

<x xsi:type="xsd:int">

5

</x>

<y xsi:type="xsd:float">

5.0

</y>

</myMethod>

</soap:body>

</soap:envelope>

4. Servicios Web XML

Francisco Prieto Donate 109

Como se puede apreciar en el propio mensaje se identifica el tipo del parámetro. Esto hace al mensaje más legible, aunque en realidad no aporta información ya que el que recibe el mensaje ya sabe el tipo de los parámetros, por lo que es poco eficiente. Además no es compatible con WS-I.

Un mensaje RPC/literal sería así:

<soap:envelope>

<soap:body>

<myMethod>

<x>

5

</x>

<y>

5.0

</y>

</myMethod>

</soap:body>

</soap:envelope>

En este caso no se envía el tipo en el mensaje lo que mejora la eficiencia, además este modo sí es compatible con WS-I. Sin embargo sigue sin poder validarse con facilidad.

Un mensaje document/literal tendría este aspecto:

<soap:envelope>

<soap:body>

<xElement>

5

</xElement>

<yElement>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

110 Francisco Prieto Donate

5.0

</yElement>

</soap:body>

</soap:envelope>

Este modo sí es validado fácilmente, y es compatible con WS-I siempre que el elemento soap:body tenga un sólo hijo. Esto provoca el problema de que en ocasiones es imposible distinguir a qué método remoto está dirigido el mensaje.

Para evitar los problemas de cada tipo Microsoft creó el modo document/literal wrapped, que no está definido en ningún sitio. Este modo complica mucho el archivo WSDL, que tendría el siguiente aspecto:

<types>

<schema>

<element name="myMethod">

<complexType>

<sequence>

<element name="x" type="xsd:int"/>

<element name="y" type="xsd:float"/>

</sequence>

</complexType>

</element>

<element name="myMethodResponse">

<complexType/>

</element>

</schema>

</types>

<message name="myMethodRequest">

<part name="parameters" element="myMethod"/>

</message>

<message name="empty">

<part name="parameters" element="myMethodResponse"/>

</message>

4. Servicios Web XML

Francisco Prieto Donate 111

<portType name="PT">

<operation name="myMethod">

<input message="myMethodRequest"/>

<output message="empty"/>

</operation>

</portType>

En este caso los elementos que se definen en el esquema no son los parámetros por separado, sino el conjunto de parámetros para cada mensaje. Ahora, el mensaje SOAP sí contendrá un elemento con el nombre de la operación

<soap:envelope>

<soap:body>

<myMethod>

<x>

5

</x>

<y>

5.0

</y>

</myMethod>

</soap:body>

</soap:envelope>

La diferencia entre document y wrapped podría verse de la siguiente forma: el mensaje document se mapearía en un método así:

public void method (myMethod m);

Es decir, myMethod se considera como un objeto que contiene dos elementos. En cambio, el mensaje wrapped sería:

public void myMethod (int x, int y);

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

112 Francisco Prieto Donate

4.4.3 Generación del documento WSDL

La mayoría de aplicaciones de desarrollo de servicios web cuentan con una herramienta de generación automática del archivo WSDL, por ejemplo, Java2WSDL. Si ejecutamos esta aplicación desde la línea de comandos basta pasar como parámetro la clase principal de nuestro servicio y obtenemos un documento WSDL perfectamente viable. En otros casos es el propio servidor web XML el que crea automáticamente el documento WSDL a partir del servicio web desplegado.

4.4.4 Interpretación del documento WSDL

El esquema general de un servicio web se muestra en la siguiente figura:

Figura 4.3: Esquema de un servicio web

El cliente obtendría el documento WSDL, generalmente de la dirección del servicio o por medio del descubrimiento UDDI, y a partir de ahí se comunicaría con el servicio mediante mensajes SOAP. Sin embargo los dispositivos móviles no tienen la capacidad suficiente como para interpretar el documento WSDL, por lo que el esquema de servicio web para móviles es ligeramente distinto. En el caso de kSOAP se debe tener en cuenta el formato de la comunicación a nivel de código, ya que la petición SOAP se crea añadiendo los parámetros necesarios a un objeto SOAP y enviándolo luego al servidor.

La aproximación kSOAP pierde mucha flexibilidad, ya que sería necesario retocar el código en caso de pequeños cambios en el servicio. El caso de JSR-172 es diferente y sigue el siguiente esquema:

4. Servicios Web XML

Francisco Prieto Donate 113

Figura 4.4: Esquema de un servicio web JSR-172

En este caso antes de incorporar la aplicación al dispositivo móvil es necesario obtener un stub a partir del documento WSDL. Una vez creado, el cliente puede llamar al servicio web a través del stub. Así el formato de la comunicación es totalmente transparente, ya que basta con invocar un método del stub para que se realice la petición y se reciba la respuesta.

4.5 UDDI

4.5.1 Concepto de UDDI

Ya tenemos desplegado nuestro Servicio Web y hemos determinado la forma de invocarlo mediante su correspondiente archivo WSDL. Lógicamente, el siguiente paso consiste en definir cómo se dará a conocer el servicio para que los clientes interesados puedan descubrirlo fácilmente y utilizarlo en sus aplicaciones. En la actualidad existe un mecanismo de descubrimiento que cumple estos requisitos: UDDI (Universal Description, Discovery and Integration), una iniciativa que permite hacer compatible el descubrimiento de servicios Web con todo tipo de tecnologías y plataformas.

Tres empresas, IBM, Microsoft y Ariba empezaron con la iniciativa UDDI. Su objetivo era definir criterios para permitir que las empresas se descubriesen las unas a las otras, que interactuasen y compartieran información en un registro global. Este registro, llamado UBR (UDDI Business Register), era distribuido por las empresas

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

114 Francisco Prieto Donate

IBM, Microsoft, y SAP. Desde Enero de 2006 ninguna de estas empresas publica ya el registro global de UDDI, aunque han implementado la especificación en sus productos.

UDDI es un registro público diseñado para almacenar de forma estructurada información sobre empresas y los servicios que éstas ofrecen. A través de UDDI se puede publicar y descubrir información de una empresa y de sus servicios. Se puede utilizar sistemas taxonómicos para clasificar estos datos y poder encontrarlos posteriormente en función de la categorización. Por tanto, UDDI puede responder a todas estas preguntas:

• ¿Qué interfaces de servicios Web basadas en WSDL se han publicado y establecido para un sector determinado?

• ¿Qué empresas han escrito una implementación basada en una de estas interfaces?

• ¿Qué servicios Web, categorizados de algún modo, se ofrecen actualmente?

• ¿Qué servicios Web ofrece una empresa determinada?

• ¿Con quién se debe poner en contacto el usuario para utilizar los servicios Web de una empresa?

• ¿Cuáles son los detalles de implementación de un servicio Web concreto?

4.5.2 Datos almacenados en el registro

UDDI almacena en su registro tres tipos de datos publicados por las empresas. Se puede hacer una analogía con las guías de teléfonos, ya que se ofrecen Páginas Blancas, Páginas Amarillas y Páginas Verdes.

• Las Páginas Blancas contienen información del tipo de nombre de la empresa, información para contactar y descripción de la compañía.

• Las Páginas Amarillas contienen información que clasifica a la empresa. Esta información se basa en mecanismos de clasificación de criterios industriales como la NAICS (North American Industry Classification System) o clasificaciones geográficas.

4. Servicios Web XML

Francisco Prieto Donate 115

• Las Páginas Verdes ofrecen información técnica sobre los servicios que ofrece la empresa.

4.5.3 Publicación en UDDI

La publicación en UDDI es un proceso relativamente sencillo. El primer paso consiste en determinar información básica sobre cómo definir la empresa y los servicios en UDDI. El siguiente paso, una vez determinada esta información, consiste en llevar a cabo el registro. Por último, se debe probar la entrada para asegurar que se registró correctamente y que aparece tal y como se esperaba en diferentes tipos de búsquedas y herramientas.

Partiendo del modelo de datos descrito anteriormente, la información necesaria para establecer una entrada de UDDI es la siguiente:

• Archivos WSDL que utilizan las implementaciones del servicio Web.

• Nombre de la empresa y una breve descripción de la misma en varios idiomas, si es necesario, así como los contactos principales para los servicios Web que ofrece.

• Las categorías e identificaciones adecuadas para la empresa.

• Los servicios Web que la empresa ofrece a través de UDDI.

• Las categorías adecuadas para los servicios.

Una vez recopilada esta información, se debe proceder al registro del servicio web. Actualmente cada compañía ofrece sus implementaciones de la especificación UDDI, de modo que cada una de ellas contará con un modo distinto de llevar a cabo el registro.

4.5.4 Búsqueda en UDDI

Anteriormente la búsqueda en UDDI consistía en acudir a cualquiera de las webs que los operadores UDDI ponían a disposición para la consulta de servicios web en el registro global. Tras la decisión tomada por estos operadores de cesar el servicio de

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

116 Francisco Prieto Donate

registro global, la búsqueda en UDDI implica tener que conocer nodos en los que se tenga la certeza que están publicando algún registro UDDI.

4.6 Servicios Web XML para dispositivos móviles

El uso de SOAP para transferir datos en lugar de otras tecnologías tiene sus ventajas. En primer lugar SOAP define más de 40 tipos de datos estándar a transmitir mediante lenguaje XML. En segundo lugar permite distintos esquemas de comunicación como pueden ser llamadas a procedimientos remotos (RPC), mensajes asíncronos, multicast, etc. En último lugar, y debido a que SOAP ha ganado tanta popularidad en los servicios Web, otros muchos protocolos han enfocado sus esfuerzos a poder interactuar con éste, como es el caso de WSDL o UDDI.

4.6.1 kSOAP

kSOAP es una API SOAP diseñada para ser utilizada con Java 2 Microedition. Está basado en kXML, un parser XML de tipo pull que funciona en todas las plataformas Java, incluida J2ME. Debido a su reducido tamaño y consumo de memoria, se suele utilizar en Applets de Java en PDAs o en dispositivos móviles con soporte MIDP.

kSOAP implementa un subconjunto de la especificación SOAP 1.1. La razón para no incluir todas las características se debe a las reducidas capacidades de memoria con que cuentan los dispositivos J2ME.

4.6.1.1 SOAP parsers

Una vez que se tenga un mensaje SOAP se pueden extraer de él los distintos datos que tenga almacenados mediante un parser XML, pero será más cómodo hacerlo mediante un parser SOAP ya que, con el primero habría que extraer la información en forma de texto para después pasarla a un objeto Java que la contenga, mientras que con el parser SOAP la extracción de datos es directa. En el caso concreto de este proyecto, el parser SOAP será kSOAP.

Un parser SOAP se construye sobre un parser genérico XML al cual se le añade una serie de mecanismos específicos con los cuales realizar el “mapeo” de datos. Dicho parser SOAP es capaz de comprender los tipos de datos de la información almacenada

4. Servicios Web XML

Francisco Prieto Donate 117

en el mensaje XML y de forma automática convertir texto en objetos Java, lo cual es una gran ventaja para el programador. Solo es necesario pasar los datos a un SOAP writer y quedarse a la espera de la respuesta del SOAP parser.

Un ejemplo de todo esto puede verse en el siguiente mensaje SOAP en el que se ha almacenado un String que contenga el típico ejemplo “Hola Mundo”.

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<SOAP-ENV:Body>

<message xsi:type="xsd:string">

Hola Mundo

</message>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Si a este mensaje SOAP le pasamos un parser SOAP podremos obtener fácilmente el String almacenado. Supongamos que el mensaje anterior se encuentra en el String “mesg”:

ByteArrayInputStream bis =

new ByteArrayInputStream (mesg.getBytes ());

InputStreamReader reader = new InputStreamReader (bis);

XmlParser xp = new XmlParser (reader);

// Se realiza un mapeo directo entre objetos Java

// y elementos Soap

SoapEnvelope envelope =

new SoapEnvelope (new ClassMap (Soap.VER12));

envelope.parse (xp);

// Obtenemos el texto almacenado

String result = (String) envelope.getBody();

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

118 Francisco Prieto Donate

En un mensaje SOAP el atributo xsi:type especifica el tipo de dato de un elemento del mensaje, por ejemplo <midato xsi:type="xsd:int">123</midato> especifica un entero de valor 123, en cambio <midato xsi:type="xsd:string">123</midato> especifica un string de valor “123”. Es decir, kSOAP es capaz de mapear de forma directa ciertos tipos de datos Java, concretamente:

Tipo SOAP Tipo Java

xsd:int java.lang.Integer

xsd:long java.lang.Long

xsd:string java.lang.String

xsd:boolean java.lang.Boolean

Tabla 4.2: Tipos de datos Java mapeados por kSOAP

A la hora de obtener los distintos datos almacenados en un mensaje SOAP el SOAP parser lee elemento a elemento cado uno de los elementos XML que hay en el mensaje y que contienen un dato y realiza el mapeo a un objeto Java de acuerdo con las siguientes reglas:

1. Si el elemento SOAP es uno de los elementos primitivos indicados en la tabla anterior el mapeo se hace directamente.

2. Si el elemento es un tipo primitivo pero no es uno de los de la tabla anterior, lo convierte a un objeto SoapPrimitive. De éste se puede obtener o bien información mediante los métodos SoapPrimitive.getNamespace() y SoapPrimitive.getName() o bien su valor mediante el método SoapPrimitive.toString().

4. Servicios Web XML

Francisco Prieto Donate 119

3. Si el elemento SOAP es un tipo complejo con varios subcampos, se convierte a un objeto de tipo KvmSerializable, concretamente al objeto SoapObject que pertenece a la interfaz KvmSerializable, y de este SoapObject se obtiene la información con los métodos SoapObject.getNamespace() y SoapObject.getName().

4.6.1.2 Composición/Descomposición de un mensaje SOAP

Supongamos que queremos montar un mensaje XML mediante los métodos que facilita kSOAP. Para ello utilizaremos una serie de métodos que montarán un mensaje que después almacenaremos en un String y que posteriormente transmitiremos por la red. Supongamos que el mensaje que queremos crear es el siguiente:

<SOAP-ENV:Envelope

xmlns:SOAP-ENC="http://www.w3.org/2001/12/soap-encoding"

xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<SOAP-ENV:Body

SOAP-ENV:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

<StockOrderParameters

id="o0"

SOAP-ENC:root="1">

<Symbol

xsi:type="xsd:string">

XYZ

</Symbol>

<From

xsi:type="xsd:string">

Michael Yuan

</From>

<Shares

xsi:type="xsd:int">

1000

</Shares>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

120 Francisco Prieto Donate

<Buy

xsi:type="xsd:boolean">

true

</Buy>

<LimitPrice

xsi:type="xsd:float">

123.45

</LimitPrice>

</StockOrderParameters>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Para montar todo este mensaje sencillamente tenemos que usar una serie de métodos Java proporcionados por la librería de kSOAP de forma que el código obtenido sería:

// Creamos el objetos SOAP que almacene el mensaje

SoapObject method = new SoapObject("", "StockOrderParameters");

//Añadímos cada uno de los parámetros

method.addProperty("Symbol", "XYZ");

method.addProperty("From", "Michael Yuan");

method.addProperty("Shares", new Integer (1000));

method.addProperty("Buy", new Boolean (true));

method.addProperty("LimitPrice", new SoapPrimitive

("http://www.w3.org/2001/XMLSchema", "float", "123.4"));

// Ensamblamos el mensaje pasándolo por un SoapEnvelope

// Después lo almacenamos en un String

ByteArrayOutputStream bos = new ByteArrayOutputStream ();

XmlWriter xw = new XmlWriter (new OutputStreamWriter (bos));

// En este caso el mapeo es directo

SoapEnvelope envelope = new SoapEnvelope (new ClassMap (Soap.VER12));

4. Servicios Web XML

Francisco Prieto Donate 121

envelope.setBody (method);

envelope.write (xw);

xw.flush ();

bos.write ('\r');

bos.write ('\n');

byte [] requestData = bos.toByteArray ();

String requestSOAPmesg = String (requestData);

Supongamos ahora el caso contrario, queremos extraer de un mensaje SOAP, que nos ha llegado como respuesta a una petición anterior, una serie de parámetros. Si el mensaje SOAP es el siguiente:

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<SOAP-ENV:Body>

<result>

<OrderStatus>

<CustomerName xsi:type="xsd:string">

Michael Yuan

</CustomerName>

<Symbol xsi:type="xsd:string">

XYZ

</Symbol>

<Share xsi:type="xsd:int">

1000

</Share>

<Buy xsi:type="xsd:boolean">

true

</Buy>

<Price xsi:type="xsd:float">

123.45

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

122 Francisco Prieto Donate

</Price>

<ExecTime xsi:type="xsd:dateTime">

2002-07-18T23:20:50.52Z

</ExecTime>

</OrderStatus>

</result>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Para extraer de este mensaje todos los parámetros, suponiendo que todo el mensaje está en el String soapRespMesg, el código que habría que ejecutar es:

ByteArrayInputStream bis = new ByteArrayInputStream

(soapRespMesg.getBytes ());

InputStreamReader reader = new InputStreamReader (bis);

XmlParser xp = new XmlParser (reader);

// El mapeo en este caso es directo

SoapEnvelope envelope = new SoapEnvelope (new ClassMap (Soap.VER12));

envelope.parse (xp);

// Obtenemos la estructura de datos.

SoapObject orderStatus = (SoapObject) envelope.getResult();

// Pasamos los datos a su correspondiente tipo Java

String customerName = (String) orderStatus.getProperty ("CustomerName");

String symbol = (String) orderStatus.getProperty ("Symbol");

Integer share = (Integer) orderStatus.getProperty ("Share");

Boolean buy = (Boolean) orderStatus.getProperty ("Buy");

// Puesto que MIDP no tiene tipo "Float" no existe correspondencia

// entre el tipo objeto Java y "xsd:float" tipo SOAP. Por lo que

// este elemento es mapeado a un objeto "SoapPrimitive".

4. Servicios Web XML

Francisco Prieto Donate 123

SoapPrimitive price = (SoapPrimitive) orderStatus.getProperty ("Price");

SoapPrimitive execTime = (SoapPrimitive) orderStatus.getProperty ("ExecTime");

4.6.1.3 Datos complejos en un mensaje SOAP

La importancia de SOAP reside en la facilidad que ofrece de poder representar datos de tipos con estructuras complejas, como pueden ser arrays, o incluso estructuras de datos que nosotros mismos definamos.

De esta forma, si queremos incluir en un mensaje SOAP un array con una serie de elementos, podemos hacerlo sin más problemas. Supongamos que un servicio Web realiza una serie de operaciones que le hemos solicitado y nos devuelve el siguiente mensaje SOAP en el que ha incluido un array:

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"

xmlns:SOAP-ENC="http://www.w3.org/2001/12/soap-encoding"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:n="http://www.javaworld.com/ksoap/test">

<SOAP-ENV:Body>

<result>

<OrderStatus xsi:type="n:orderStatus">

<CustomerName xsi:type="xsd:string">

Michael Yuan

</CustomerName>

<Transactions xsi:type="SOAP-ENC:Array"

SOAP-ENC:arrayType="n:transaction[2]">

<Transaction xsi:type="n:transaction">

<Symbol xsi:type="xsd:string">

ABC

</Symbol>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

124 Francisco Prieto Donate

<Share xsi:type="xsd:int">

500

</Share>

<Buy xsi:type="xsd:boolean">

true

</Buy>

<Price xsi:type="xsd:float">

43.21

</Price>

</Transaction>

<Transaction xsi:type="n:transaction">

<Symbol xsi:type="xsd:string">

XYZ

</Symbol>

<Share xsi:type="xsd:int">

1000

</Share>

<Buy xsi:type="xsd:boolean">

true

</Buy>

<Price xsi:type="xsd:float">

123.45

</Price>

</Transaction>

</Transactions>

</OrderStatus>

</result>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

4. Servicios Web XML

Francisco Prieto Donate 125

Al recibirse este mensaje, kSOAP lee el array y lo introduce en un objeto de tipo java.util.Vector y mediante el método Vector.elementAt(i) extrae de dicho array el elemento i-ésimo de entre todos los elementos que lo componen. Dependiendo del tipo del arrayType este objeto será almacenado en un SoapObject, en un SoapPrimitive, en un tipo por defecto Java, etc. Si suponemos que todo este mensaje SOAP se encuentra dentro del String arraySoapRespMesg, el código que realizaría la extracción del array sería:

ByteArrayInputStream bis = new ByteArrayInputStream

(arraySoapRespMesg.getBytes ());

InputStreamReader reader = new InputStreamReader (bis);

XmlParser xp = new XmlParser (reader);

SoapEnvelope envelope = new SoapEnvelope (new ClassMap (Soap.VER12));

envelope.parse (xp);

SoapObject orderStatus = (SoapObject) envelope.getResult();

String customerName = (String) orderStatus.getProperty ("CustomerName");

Vector transactions = (Vector) orderStatus.getProperty ("Transactions");

// Primer elemento del array

SoapObject transaction0 = (SoapObject) transactions.elementAt(0);

String symbol0 = (String) transaction0.getProperty ("Symbol");

Integer share0 = (Integer) transaction0.getProperty ("Share");

Boolean buy0 = (Boolean) transaction0.getProperty ("Buy");

SoapPrimitive price0 = (SoapPrimitive) transaction0.getProperty ("Price");

// Segundo elemento del array

SoapObject transaction1 = (SoapObject) transactions.elementAt(1);

String symbol1 = (String) transaction1.getProperty ("Symbol");

Integer share1 = (Integer) transaction1.getProperty ("Share");

Boolean buy1 = (Boolean) transaction1.getProperty ("Buy");

SoapPrimitive price1 = (SoapPrimitive) transaction1.getProperty ("Price");

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

126 Francisco Prieto Donate

4.6.1.4 Protocolo HTTP mediante SOAP

El gran potencial que tiene SOAP a la hora de serializar datos para transmitirlos a través de una red se complementa con una funcionalidad extremadamente útil, que es el uso del protocolo HTTP de forma directa. Dicho de otra manera, no vamos a tener que controlar HTTP explícitamente sino que esta tarea se deja en manos del API que implementa SOAP.

kSOAP cuenta con la clase HttpTransport que es la que aporta la funcionalidad de envío y recepción de mensajes SOAP vía HTTP. La forma de conexión que ofrece es una llamada a procedimiento remoto (RPC), tal que el método HttpTransport.call() toma como entrada un objeto KvmSerializable, lo serializa introduciéndolo en un mensaje SOAP completo que él mismo monta, envía dicho mensaje al servicio Web cuya dirección se haya indicado y recibe el mensaje respuesta que venga de vuelta. Tras esto pasa el mensaje recibido por un parser SOAP, llama al método SoapEnvelope.getResult() para que le devuelva el objeto Java correspondiente y dé como resultado este objeto. Y todo esto de forma automática.

La forma de utilizar este método es muy sencilla, lo vemos con el siguiente ejemplo:

// Resultado de la llamada al servicio Web

String result = null;

// Dato a transmitir al servicio Web

int dato = 100;

// Creamos el objeto SOAP para la llamada al servicio

SoapObject rpc = new SoapObject

("urn:nombre del método", "nombre del método");

// Introducimos el parámetro en el mensaje SOAP

rpc.addProperty ("dato", dato);

// Configuramos la llamada al servicio Web

HttpTransport ht = new HttpTransport("URL destino", nombre del método);

// Llamamos al servicio Web y recibimos su respuesta

4. Servicios Web XML

Francisco Prieto Donate 127

result = ht.call (rpc);

4.6.2 JSR-172

4.6.2.1 Introducción

Las APIs de servicios web (WSA) para J2ME se definen en la Java Specification Request 172 (JSR-172). Son dos paquetes independientes y opcionales, uno dedicado a la invocación de servicios remotos y otro dedicado al análisis XML. Están centrados en la CDC y las CLDC 1.0 y CLDC 1.1. La importancia de esto estriba en que la especificación JSR-172 proporciona servicios de invocación remota y análisis XML a nivel de dispositivo, evitando así que los desarrolladores de software tengan que incorporar dichas funcionalidades en sus aplicaciones.

Los servicios web en la J2ME, definidos por la JSR-172, siguen las mismas especificaciones, arquitectura y modelo de invocación que los servicios web estándar, es decir:

• SOAP 1.1 (Simple Object Access Protocol), que define el transporte y codificación de datos.

• XML 1.0, que define el lenguaje XML.

Hay una cantidad importante de especificaciones que cubren las distintas tecnologías relacionadas con servicios web, y su número continúa creciendo. Por ello la Organización para la Interoperabilidad de Servicios Web (WS-I) ha definido el WS-I Basic Profile 1.0, que establece las especificaciones mínimas y las reglas que todos los proveedores de servicios web básicos deben seguir. La especificación JSR-172 se ha desarrollado de acuerdo al WS-I Basic Profile, aunque no soporta la especificación UDDI.

4.6.2.2 Invocación remota

La WSA de JSR-172 afronta los servicios web desde el punto de vista del cliente del servicio: WSA proporciona la API de invocacion remota (JAX-RPC) y el entorno de ejecución que permite a las aplicaciones J2ME consumir servicios en la web, pero no funcionar como productores de servicios. Aparte de esta diferencia, el resto de la arquitectura sigue la estructura y organización estándar de los servicios web.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

128 Francisco Prieto Donate

Esta arquitectura de alto nivel está estructurada en:

• Un cliente, el consumidor de los servicios web. Consta de una aplicación J2ME, como MIDP, un stub de JSR-172 con las clases necesarias y la ejecución de JSR-172.

• La red: Hace referencia a la red inalámbrica y a los protocolos de comunicación. JSR-172 no impone el uso de XML en el propio dispositivo; permite otras implementaciones (siempre que sean transparentes al cliente y al servidor) para usar codificaciones más eficientes, como el uso de protocolos binarios entre el dispositivo y la pasarela inalámbrica.

• El servidor: Productor de servicios web. Es un servidor web, típicamente detrás de un firewall o una pasarela Proxy, que puede tener acceso a recursos de respaldo.

Las aplicaciones J2ME invocan servicios remotos a través de los stubs y de la ejecución de JSR-172, típicamente sobre HTTP y SOAP. Dichos stubs esconden toda la complejidad asociada a la invocación del servicio remoto, incluyendo cómo se van a codificar y decodificar los parámetros de la solicitud y la respuesta, y todo lo relacionado con la red de comunicaciones. La invocación de métodos sigue el modelo síncrono de petición-respuesta, como se ve en la figura:

Figura 4.5: Modelo de invocación de JSR-172

Para consumir un servicio web antes hay que crear stubs de invocación de servicio. Estos stubs realizan tareas como la codificación y descodificación de los valores enviados y recibidos, y actúan de interfaz de la ejecución de JSR-172 para invocar un punto de servicio remoto. Los stubs interactúan con la ejecución a través del Interfaz de Proveedor de Servicio (SPI), que abstrae los detalles de implementación y permite portabilidad de stubs entre distintas implementaciones.

4. Servicios Web XML

Francisco Prieto Donate 129

Los stubs son generados usando una herramienta que lee el documento WSDL relacionado con el servicio web. Desde el punto de vista del dispositivo móvil, el documento WSDL que queremos consumir por lo general suele existir a priori, así que lo único que hay que hacer es generar los stubs JSR-172 WSA, usando una herramienta como el generador de stubs incluído en J2ME Wireless Toolkit 2.1.

Figura 4.6: Generación del stub de JSR-172

Esto genera los ficheros Java del stub y las clases necesarias. También se ocupa del mapeado del tipo de datos de WSDL a Java, como se describirá con detalle más adelante.

Una vez se han generado los stubs y las clases necesarias, y la aplicación haya sido compilada e instalada en un dispositivo compatible con JSR-172, consumir los servicios web deseados es muy sencillo, y casi transparente. La invocación de métodos remotos se hace tan sencilla como la de métodos locales.

La API de invocación remota de métodos de JSR-172 está basada en un subconjunto de JAX-RPC 1.1 (API Java para RPC basada en XML). También está desarrollada según el WS-I Basic Profile. Soporta las siguientes características:

• SOAP 1.1

• Cualquier transporte que pueda entregar mensajes SOAP, como HTTP 1.1

• La representación literal de un mensaje SOAP que represente una petición o respuesta RPC

• Los siguientes tipos de datos y su correspondencia en Java:

� xsd:boolean a boolean o Boolean.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

130 Francisco Prieto Donate

� xsd:byte a byte o Byte.

� xsd:short a short o Short.

� xsd:int a int o Integer.

� xsd:long a long o Long.

� xsd:float a float, o Float. Para plataformas basadas en CLDC 1.0, este tipo de datos se mapea a String.

� xsd:double a double, o Double. Para plataformas basadas en CLDC 1.0, este tipo de datos se mapea a String.

� xsd:string a String.

� xsd:base64Binary a byte[].

� xsd:hexBinary a byte[].

� xsd:complexType a Sequence de tipos primitivos.

� xsd:QName a javax.xml.namespace.QName.

� Vectores de tipos primitivos y complejos (estructuras que contengan tipos primitivos y complejos) basados en el esquema de vector XML.

Las siguientes características no son soportadas:

• Mensajes SOAP con adjuntos.

• Manejadores (handlers) de mensaje SOAP.

• Representación codificada de mensajes SOAP.

4. Servicios Web XML

Francisco Prieto Donate 131

• Puntos de servicio (productor de servicio web).

• Soporte de descubrimiento de servicios (UDDI).

La codificación en XML no es obligatoria en el dispositivo. Así se puede reducir el tráfico de la red permitiendo que las implementaciones usen más eficientemente la codificación de los datos, como un protocolo binario entre el dispositivo y la pasarela inalámbrica, siempre que dicha codificación sea transparente tanto para el productor del servicio web como para el consumidor.

Una vez se hayan generado, compilado e instalado en el dispositivo el stub y los ficheros relacionados, consumir servicios remotos es muy simple. Si no contamos la inicialización específica dede JAX-RPC e importar RemoteException, el código de una aplicación que se desarrolle para consumir servicios web parece igual que el de una aplicación que no lo use. Esta simplicidad es posible gracias a que los stubs, como ya hemos mencionado, ocultan los detalles relacionados con la invocación remota.

4.6.2.3 Análisis XML

La API de JSR-172 para el análisis XML de J2ME se basa en un subconjunto de la API JAXP 1.2 de J2SE y la API simple para análisis XML (SAX) 2.0. El hecho de que sea un subconjunto se explica por la limitada memoria disponible en los dispositivos J2ME.

JAXP para J2ME proporciona las clases, interfaces y excepciones necesarias para analizar documentos XML. Debe ser compatible con XML 1.0, y puede validar (usando DTD) o no; el analizador seguirá las reglas de validación indicadas en la especificación de XML 1.0. Esta validación es una operación que consume muchos recursos, por eso la decisión de incluirla dependerá del fabricante del dispositivo y se basará en las limitaciones de almacenamiento y procesado del dispositivo. Para saber si el analizador está validando se puede llamar al método SAXParser.isValidating().

Los analizadores de JAXP para J2ME deben soportar espacios de nombre de XML, tal y como se define en la recomendación W3C XML Namespaces 1.0, codificación UTF-8 y UTF-16, y DTDs. No están soportados, debido a las causas ya comentadas, el Modelo de Objetos de Documento (DOM) y el Lenguaje de Transformación basado en Plantillas de Estilo (XSLT).

El uso de JAXP consiste en tres fases:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

132 Francisco Prieto Donate

• Definir el manejador específico para la aplicación, una subclase de DefaultHandler.

• Usar SAXParserFactory para crear una instancia del analizador SAX (SAXParser).

• Analizar el documento XML de entrada invocando el método SAXParser.parse().

El analizador SAX invoca las llamadas del manejador de eventos startDocument(), endDocument(), startElement(), endElement(), y characters() al procesar las distintas partes del documento XML.

Una vez se ha iniciado el análisis, SAXParser invoca las llamadas al manejador de eventos así:

• startDocument(): Se llama al principio del documento.

• startElement(): Se llama cuando se encuentra un nuevo elemento. Esta llamada también incluye los atributos del elemento, si hay alguno.

• characters(): Se llama cuando se encuentran caracteres de algún elemento.

• endElement(): Se llama cuando se cierra un elemento.

• endDocument(): Se llama al finalizar el análisis del documento.

4.7 Consideraciones finales

La aparición de los Servicios Web XML marcó un antes y un después en el ámbito de las aplicaciones distribuidas. En este capítulo hemos podido comprobar que gran parte de este éxito se debe a la utilización de protocolos estándar basados en XML para invocar servicios y transmitir datos, como SOAP y WSDL.

4. Servicios Web XML

Francisco Prieto Donate 133

Por ello se ha prestado una especial atención a XML, del que hemos detallado su estructura y reglas sintácticas, así como los dos métodos que existen para definir este tipo de documentos: DTD y Schema.

A continuación hemos descrito el protocolo SOAP, estándar del W3C para realizar peticiones a los servicios web. El apartado dedicado a este protocolo nos ha servido para conocer las partes de las que se compone y la función de cada una de ellas. Los ejemplos adjuntos de mensajes SOAP facilitan en gran medida la comprensión de su estructura.

Decimos que los Servicios Web XML son aplicaciones autodescriptivas que se publican, se ubican y se invocan desde cualquier lugar de la web. Esa autodescripción viene dada gracias a los documentos WSDL, también basados en XML, que ofrecen toda la información necesaria para utilizar un servicio web sin dar a conocer su implementación, sistema operativo o lenguaje de programación.

La forma de dar a conocer un nuevo servicio web pasa por incluirlo en una lista del tipo “Páginas Amarillas”. Existe un registro especialmente diseñado para los servicios web denominado UDDI. En los apartados anteriores hemos explicado el fundamento de publicación y búsqueda de servicios web en este tipo de registros.

Por último se han contemplado dos tecnologías que permiten implementar Servicios Web XML en dispositivos móviles: el paquete kSOAP y la especificación JSR-172. Hemos estudiado las características de cada uno de ellos y sus diferencias principales. Al igual que con SOAP, los ejemplos utilizados permiten asimilar fácilmente muchos de los conceptos que se han tratado.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

134 Francisco Prieto Donate

5. Protocolo HTTP

Francisco Prieto Donate 135

5 PROTOCOLO HTTP

En este capítulo vamos a conocer la forma de enviar un mensaje SOAP a través de la red. La especificación SOAP no indica ninguna manera específica de transportar la información, de modo que los mensajes podrían viajar a través de protocolos de transporte, archivos de texto o cualquier otro método de transferencia de datos.

El modelo TCP/IP cuenta con diversos protocolos en su capa de aplicación: HTTP, SMTP y FTP son tres de los más importantes. En principio, cualquiera de ellos puede ser utilizado para la transferencia de mensajes SOAP. En este proyecto utilizaremos HTTP, el protocolo estándar para la web y el más usado en los servicios web XML.

El Protocolo de Transferencia de HiperTexto (Hypertext Transfer Protocol) es un sencillo protocolo cliente-servidor que articula los intercambios de información entre los clientes web y los servidores HTTP. La especificación completa del protocolo HTTP/1.0 está recogida en el RFC 1945. Fue propuesto por Tim Berners-Lee, atendiendo a las necesidades de un sistema global de distribución de información como el World Wide Web. Actualmente la versión más reciente de HTTP es la 1.1, y su especificación se encuentra recogida en el documento RFC 2616.

5.1 Características y funcionamiento

Desde el punto de vista de las comunicaciones, HTTP se establece sobre la capa de conexión TCP/IP, y funciona de la misma forma que el resto de los servicios comunes de entornos UNIX: un proceso servidor escucha en un puerto de comunicaciones TCP (por defecto, el 80), y espera las solicitudes de conexión de los clientes web. Una vez que se establece la conexión, el protocolo TCP se encarga de mantener la comunicación y garantizar un intercambio de datos libre de errores.

HTTP se basa en sencillas operaciones de solicitud/respuesta. Un cliente establece una conexión con un servidor y envía un mensaje con los datos de la solicitud. El servidor responde con un mensaje similar, que contiene el estado de la operación y su posible resultado. Todas las operaciones pueden adjuntar un objeto o recurso sobre el que actúan; cada objeto web es identificado por su URL.

Las principales características del protocolo HTTP son:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

136 Francisco Prieto Donate

• Toda la comunicación entre los clientes y servidores se realiza a partir de caracteres US-ASCII de 7 bits.

• Permite la transferencia de objetos multimedia, codificando los archivos binarios en cadenas de caracteres. El contenido de cada objeto intercambiado está identificado por su clasificación MIME.

• Existen ocho verbos que permiten que un cliente pueda dialogar con el servidor. Los tres más utilizados son: GET, para recoger un objeto, POST, para enviar información al servidor y HEAD, para solicitar las características de un objeto (por ejemplo, la fecha de modificación de un documento HTML).

• Cada operación HTTP implica una conexión con el servidor, que es liberada al término de la misma. Es decir, en una operación se puede recoger un único objeto. Con la versión HTTP 1.1 se ha mejorado este procedimiento, permitiendo que una misma conexión se mantenga activa durante un cierto periodo de tiempo, de forma que sea utilizada en sucesivas transacciones. Este mecanismo, denominado HTTP Keep Alive, es empleado por la mayoría de los clientes y servidores modernos.

• No mantiene estado. Cada petición de un cliente a un servidor no es influida por las transacciones anteriores. El servidor trata cada petición como una operación totalmente independiente del resto.

• Cada objeto al que se aplican los verbos del protocolo está identificado a través de un localizador uniforme de recurso (URL) único.

Cada vez que un cliente realiza una petición a un servidor, se ejecutan los siguientes pasos:

1. Un usuario accede a una URL, seleccionando un enlace de un documento HTML o introduciéndola directamente en el navegador.

2. El cliente web descodifica la URL, separando sus diferentes partes. Así identifica el protocolo de acceso, la dirección DNS o IP del servidor, el puerto (de carácter opcional; el valor por defecto es 80) y el objeto requerido del servidor.

3. Se abre una conexión TCP/IP con el servidor, llamando al puerto TCP correspondiente.

5. Protocolo HTTP

Francisco Prieto Donate 137

4. Se realiza la petición. Para ello, se envía el comando necesario (GET, POST, HEAD,…), la dirección del objeto requerido (el contenido de la URL que sigue a la dirección del servidor), la versión del protocolo HTTP empleada y un conjunto variable de información, que incluye datos sobre las capacidades del navegador, datos opcionales para el servidor, etc.

5. El servidor devuelve la respuesta al cliente. Consiste en un código de estado y el tipo de dato MIME de la información de retorno, seguido de la propia información.

6. Se cierra la conexión TCP. Si no se utiliza el modo HTTP Keep Alive, este proceso se repite para cada acceso al servidor HTTP.

El diálogo con los servidores HTTP se establece a través de mensajes formados por líneas de texto, cada una de las cuales contiene los diferentes comandos y opciones del protocolo. Solo existen dos tipos de mensajes, uno para realizar peticiones y otro para devolver la correspondiente respuesta.

La estructura general de los dos tipos de mensajes se puede ver en el siguiente esquema:

Mensaje de solicitud

Comando HTTP + parámetros

Cabeceras de la petición

Línea en blanco

Información opcional

Mensaje de respuesta

Resultado de la solicitud

Cabeceras de la respuesta

Línea en blanco

Información opcional

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

138 Francisco Prieto Donate

Figura 5.1: Estructura de los mensajes HTTP

La primera línea del mensaje de solicitud contiene el comando que se solicita al servidor HTTP, mientras que la primera línea de la respuesta contiene el resultado de la operación identificado por un código numérico que permite conocer el éxito o fracaso de dicha operación. Después aparece, para ambos tipos de mensajes, un conjunto de cabeceras (unas obligatorias y otras opcionales) que condicionan y matizan el funcionamiento del protocolo.

La separación entre cada línea del mensaje se realiza con un par CR-LF (retorno de carro más nueva línea). El final de las cabeceras se indica con una línea en blanco, tras la cual se pueden incluir los datos transportados por el protocolo, por ejemplo, el documento HTML que devuelve un servidor.

A continuación se muestran los mensajes intercambiados por cliente y servidor cuando accedemos a la dirección web http://portal.us.es con el navegador Mozilla Firefox. Cada color de fondo se identifica con la estructura de los mensajes anteriormente explicada.

Petición del cliente:

GET /index.htm HTTP/1.1

Host: portal.us.es:80 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 Accept: text/xml,application/xml,application/xhtml+xml,text/html; q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: es,es-es;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive

Respuesta del servidor:

HTTP/1.0 200 OK

5. Protocolo HTTP

Francisco Prieto Donate 139

Server: Zope/(Zope 2.8.6-final, python 2.3.5, linux2) ZServer/1.1 Plone/Unknown Date: Wed, 09 Aug 2006 17:45:16 GMT Content-Length: 22496 Content-Language: X-Cache-Headers-Set-By: CachingPolicyManager: /us/caching_policy_manager Expires: Wed, 09 Aug 2006 17:55:16 GMT Cache-Control: max-age=600 Content-Type: text/html;charset=utf-8 Age: 198 X-Cache: HIT from vega2.us.es X-Cache-Lookup: HIT from vega2.us.es:80 Connection: keep-alive

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es"> ... </html>

5.2 Comandos de HTTP

El protocolo HTTP/1.1 consta de los siguientes comandos:

• GET: Sirve para recoger cualquier tipo de información del servidor. Se utiliza siempre que se pulsa sobre un enlace o se teclea directamente a una URL. Como resultado, el servidor HTTP envía el documento ubicado en la dirección especificada por dicha URL.

• HEAD: Es un comando similar a GET pero que pide solamente la cabecera del objeto. Lo utilizan principalmente los gestores de cachés de páginas o los servidores proxy para conocer cuándo es necesario actualizar la copia que se mantiene de un fichero.

• POST: Este comando envía datos de información al servidor, normalmente procedentes de un formulario web, para que el servidor los administre o los añada a una base de datos.

• PUT: Almacena un objeto en la URL especificada. Si la dirección de destino ya contenía un objeto, se considera que se está enviando una versión actualizada del mismo.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

140 Francisco Prieto Donate

• DELETE: Elimina el objeto especificado. Este comando es muy poco utilizado.

• TRACE: Realiza un eco de la solicitud recibida para que el cliente pueda conocer qué servidores intermedios están añadiendo información o modificando la petición.

• OPTIONS: Devuelve los métodos HTTP que soporta el cliente. Se suele utilizar para comprobar la funcionalidad de un servidor web.

• CONNECT: Se utiliza en los servidores proxy que puedan establecer un túnel dinámicamente (por ejemplo, un túnel SSL).

Ante cada transacción con un servidor HTTP, éste devuelve un código numérico en la primera línea del mensaje de respuesta que informa sobre el resultado de la operación. Estos códigos aparecen en algunos casos en la pantalla del cliente, cuando se produce un error.

Los códigos de estado están clasificados en cinco categorías.

• 1xx: Mensajes informativos.

• 2xx: Mensajes asociados con operaciones realizadas correctamente.

• 3xx: Mensajes de redirección, que informan de operaciones complementarias que se deben realizar para finalizar la operación.

• 4xx: Errores del cliente; el requerimiento contiene algún error, o no puede ser realizado.

• 5xx: Errores del servidor, que no ha podido llevar a cabo una solicitud.

En la siguiente tabla podemos ver una lista con los códigos que se utilizan con mayor frecuencia:

Código Comentario Descripción

5. Protocolo HTTP

Francisco Prieto Donate 141

200 OK Operación realizada satisfactoriamente.

201 Created La operación ha sido realizada correctamente, y como resultado se ha creado un nuevo objeto, cuya URL de acceso se proporciona en el cuerpo de la respuesta. Este nuevo objeto ya está disponible.

202 Accepted La operación ha sido realizada correctamente, y como resultado se ha creado un nuevo objeto, cuya URL de acceso se proporciona en el cuerpo de la respuesta. El nuevo objeto no está disponible por el momento. En el cuerpo de la respuesta se debe informar sobre la disponibilidad de la información.

204 No Content La operación ha sido aceptada, pero no ha producido ningún resultado de interés. El cliente no deberá modificar el documento que está mostrando en este momento.

301 Moved Permanently

El objeto al que se accede ha sido movido a otro lugar de forma permanente. El servidor proporciona, además, la nueva URL en el campo Location de la respuesta.

302 Found El objeto al que se accede ha sido movido a otro lugar de forma temporal. El servidor proporciona, además, la nueva URL en el campo Location de la respuesta. El cliente no debe modificar ninguna de las referencias a la URL errónea.

304 Not Modified

Se devuelve cuando se hace un GET condicional y el documento no ha sido modificado

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

142 Francisco Prieto Donate

400 Bad Request La petición tiene un error de sintaxis y no es entendida por el servidor.

401 Unauthorized La petición requiere una autorización especial, que normalmente consiste en un nombre y clave que el servidor verificará. El campo WWW-Autenticate informa de los protocolos de autentificación aceptados para este recurso.

403 Forbidden Está prohibido el acceso a este recurso. No es posible utilizar una clave para modificar la protección.

404 Not Found La URL solicitada no existe.

500 Internal Server Error

El servidor ha tenido un error interno, y no puede continuar con el procesamiento.

501 Not Implemented

El servidor no tiene capacidad, por su diseño interno, para llevar a cabo el requerimiento del cliente.

502 Bad Gateway El servidor, que está actuando como proxy o pasarela, ha encontrado un error al acceder al recurso que había solicitado el cliente.

503 Service Unavailable

El servidor está actualmente deshabilitado y no es capaz de atender el requerimiento.

Tabla 5.1: Lista de códigos HTTP

5. Protocolo HTTP

Francisco Prieto Donate 143

5.3 Codificación de la información

Una de las características de HTTP reside en que la comunicación entre cliente y servidor se realiza a partir de caracteres US-ASCII de 7 bits. El problema aparece cuando deseamos realizar la transmisión de un archivo binario, cuyo contenido no puede ser representado por este grupo tan reducido de caracteres.

Para solventar esta limitación se utiliza el estándar de Internet MIME (Extensiones de correo de Internet multipropósito). Son una serie de convenciones o especificaciones dirigidas a que se puedan intercambiar a través de Internet todo tipo de archivos (texto, audio, vídeo, etc.) de forma transparente para el usuario. Una parte importante de MIME está dedicada a mejorar las posibilidades de transferencia de texto en distintos idiomas y alfabetos. La especificación de este estándar se encuentra recogidas en las RFC 2045, 2046, 2047, 2048 y 2049.

Los recursos u objetos que actúan como entrada o salida de un comando HTTP están clasificados por su descripción MIME, que se especifica en el campo de cabecera “Content-Type”. De esta forma, el protocolo puede intercambiar cualquier tipo de dato sin preocuparse de su contenido. La identificación MIME permitirá que el receptor trate adecuadamente los datos. Existen nueve tipos definidos por la IANA: application, audio, example, image, message, model, multipart, text y video. Dentro de cada tipo existen multitud de subtipos: (text/html, image/gif, image/jpeg, audio/x-mpeg, video/quicktime…).

Existen tres métodos básicos de codificación:

• 7 bit: Utilizado por defecto, supone que los archivos son de texto.

• Quoted-printable: Se usa para codificar texto con caracteres que excedan de los 7 bits utilizados en US-ASCII. Con esto podremos representar caracteres de otros alfabetos como los idiomas procedentes del latín. Se codifica en 3 caracteres de 7 bits. Por ejemplo, la letra “ñ” se corresponderá con los caracteres “=F1”.

• Base64: Se utiliza para codificar contenido no legible por humanos, como por ejemplo archivos multimedia. Cada 3 octetos se codifican en 4 caracteres que pertenecen a un subconjunto de 64 caracteres imprimibles del US-ASCII. Los pasos para codificar un conjunto de octetos en caracteres codificados en Base64 son:

1. Se agrupan todos los bits, quedándose al principio el bit más significativo y al final el menos significativo.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

144 Francisco Prieto Donate

2. Se toman grupos de 6 bits. Si en el último grupo quedan menos de 6 bits, se rellena con ceros.

3. Obtenemos el valor decimal de cada uno de los grupos.

4. Identificamos cada valor con un carácter de la tabla adjunta:

0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y

5. Se añaden al final tantos signos “=” como parejas de ceros hayamos añadido en el paso 2.

Para comprender mejor estos pasos vamos a ilustrar el proceso de codificación con un sencillo ejemplo:

Figura 5.2: Ejemplo de codificación en Base64

5. Protocolo HTTP

Francisco Prieto Donate 145

5.4 Consideraciones finales

El protocolo cliente-servidor HTTP es el estándar en la web y el más utilizado en los Servicios Web XML. Sus características hacen que haya sido el protocolo preferido por los servidores web XML para realizar el intercambio de peticiones.

En primer lugar hemos comentado el funcionamiento básico del protocolo, y se ha mostrado la estructura de los mensajes de petición y respuesta. A continuación se han presentado los ocho comandos que se utilizan en las peticiones HTTP para facilitar la comunicación del cliente con el servidor.

Por último hemos hablado brevemente de MIME, el estándar que permite enviar dentro de HTTP información que no es de tipo texto. Tras enumerar los tres métodos básicos de codificación: 7 bit, Quoted-printable y Base64, nos hemos detenido en este último para detallar su funcionamiento, ya que nos basaremos en él para codificar las imágenes que se van a transmitir.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

146 Francisco Prieto Donate

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 147

6 TRANSMISIÓN DE VÍDEO EN INTERNET

6.1 Introducción

La evolución experimentada por las redes de comunicación en los últimos años (ADSL, fibra óptica…) ha permitido crear auténticas aplicaciones multimedia en la red. Realización de videoconferencias de una punta a otra de la geografía mundial, transmisiones de vídeo en tiempo real y sintonización de radios y cadenas de televisión en Internet son un ejemplo claro de las posibilidades que nos ofrece la tecnología multimedia a través de la red.

Actualmente existen dos maneras de reproducir contenidos multimedia en Internet. Por un lado podemos descargar el contenido y visualizarlo posteriormente, por el otro podríamos utilizar la tecnología streaming (flujo), capaz de reproduir audio y vídeo de forma continua a través de Internet sin la necesidad de descargar archivos en el equipo. En este capítulo detallamos cada uno de estos dos métodos.

6.2 Descarga y visualización del contenido

La forma más intuitiva de visualizar contenido multimedia consiste en descargar los archivos correspondientes para ser visualizados posteriormente. Centrándonos en las imágenes de vídeo, contamos con dos alternativas para su descarga y visualización.

En el primero de los casos se llevaría a cabo una descarga directa del archivo que contiene una secuencia de imágenes de vídeo. Una vez descargado, utilizaremos un reproductor adecuado que sea capaz de descodificar la información contenida en el archivo para realizar la representación en pantalla.

En el segundo de los casos contemplamos la visualización de imágenes de vídeo en dispositivos que, o bien cuentan con reducidas prestaciones en cuanto a memoria y muy poca capacidad de almacenamiento, o bien no cuentan con ninguna implementación que les permita reproducir archivos de vídeo pero sí puedan visualizar imágenes. En ese caso, la solución pasaría por descargar imágenes una por una y presentarlas por pantalla una detrás de otra para que se cree la ilusión de movimiento.

A continuación describimos los formatos de imagen más extendidos, analizando sus ventajas e inconvenientes desde el punto de vista de su transmisión a través de la

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

148 Francisco Prieto Donate

red. Posteriormente haremos un repaso de los formatos de vídeo más utilizados en la actualidad.

6.2.1 Formatos de imagen

En este apartado veremos los distintos formatos de codificación de imagen que pueden utilizarse en el cliente, evaluando el más indicado para realizar la transmisión a través de la red.

6.2.1.1 Formato BMP

Una imagen en formato BMP (Bitmap) es esencialmente un mapa de bits, donde se define el color de cada píxel de la imagen, uno por uno. Cada píxel viene representado por 3 bytes, donde cada uno de ellos indica la proporción de color en formato RGB. Es decir, el primer byte contiene la cantidad de rojo (Red), el segundo la cantidad de verde (Green) y el tercero la cantidad de azul (Blue).

Existen paletas de colores de 1, 4, 8 y 24 bits, siendo el número de colores posibles 2 elevado al número de bits de la paleta.

Un fichero BMP contiene los siguientes campos:

• Una cabecera.

• Información acerca de las dimensiones de la imagen.

• Una tabla de colores, representando los diferentes colores usados.

• Los datos de la imagen.

Este formato puede apreciarse claramente si abrimos un archivo BMP con un editor hexadecimal.

El formato BMP es el menos usado para el intercambio de imágenes. Este formato no introduce pérdidas ni ofrece ningún tipo de compresión, por tanto, genera archivos de gran tamaño.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 149

6.2.1.2 Formato GIF

Este formato fue popularizado en la década de los 80 por CompuServe. GIF (Graphic Interchange Format) permite transmitir imágenes de forma eficiente a través de las redes de datos.

A principios de los 90, los creadores del World Wide Web adoptaron GIF por su eficiencia y su experiencia con él. Por ello, la mayoría de las imágenes actuales de la Web están en este formato, y todos los navegadores con soporte gráfico pueden representar imágenes GIF.

Los ficheros GIF incorporan un sistema de compresión para que el tamaño del archivo sea lo mínimo posible. Las imágenes, en este formato, están limitadas a una paleta de colores de 8 bits (256 colores).

Existen dos variantes GIF87 y GIF89a. La diferencia entre ellas radica en que la segunda permite generar imágenes animadas, fondos transparentes y formato entrelazado.

6.2.1.2.1 Compresión de archivos GIF

Los archivos GIF utilizan una forma de compresión basada en el algoritmo LZW (Lempel Zev Welch). Este algoritmo optimiza el almacenamiento de la imagen, sin que se produzcan pérdidas ni distorsión.

El algoritmo LZW funciona, básicamente, comprobando las líneas horizontales que son del mismo color y guardándolas. Por ello, LZW funciona de forma óptima comprimiendo imágenes con grandes áreas de color homogéneo, ya que con una línea del fichero se tiene la información necesaria para reconstruir varias líneas de la imagen. Y es menos eficiente a la hora de comprimir imágenes con un gran número de colores y distintas texturas.

Figura 6.1: Comparativa entre imágenes para compresión GIF. La imagen de la izquierda soportará una compresión mayor

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

150 Francisco Prieto Donate

Es posible aprovecharse de las características de LZW para mejorar su eficiencia y reducir, por tanto, el tamaño de los archivos GIF. Para ello, basta reducir el número de colores de la imagen GIF al mínimo necesario para una correcta visualización y eliminar el resto.

El máximo número de colores que admite una imagen GIF es de 256 y el mínimo es 2. A menor número de colores, mayor es la eficiencia del algoritmo de compresión.

El formato de un archivo GIF es el siguiente:

• Firma.

• Descriptor global.

• Dimensiones de la imagen.

• Banderas y opciones.

• Otros campos.

• Datos de la imagen.

6.2.1.2.2 Entrelazado

Existen dos tipos de ficheros GIF, los convencionales y los progresivos, según usen o no la técnica del entrelazado.

Las imágenes GIF convencionales son las no entrelazadas. Esto significa que al acceder a una imagen de este tipo, descargamos los píxeles línea a línea, empezando por la superior y acabando por la inferior. Y la imagen se reconstruye en la pantalla de forma gradual.

Los gráficos GIF entrelazados inicialmente reproducen en la pantalla una versión de baja resolución de la imagen completa. A medida que se va reconstruyendo la imagen va mejorando la resolución. La principal ventaja del entrelazado es que da, desde el principio, una idea del tamaño que va a ocupar la imagen en la pantalla. Esta técnica se usa normalmente cuando tenemos imágenes muy grandes o conexiones muy lentas para descargar la imagen.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 151

Usar entrelazado es una buena elección para imágenes que ocupan mucho espacio como ilustraciones o fotografías. No es una buena opción para pequeños elementos tales como botones o iconos; éstos se cargarán más rápido si están en un formato no entrelazado.

Los gráficos entrelazados tienen un tamaño ligeramente superior a los convencionales, aunque este efecto no es muy significativo.

Figura 6.2: Comparativa entre gráfico no entrelazado (izquierda) y entrelazado (derecha), al detener la transmisión en la mitad de la descarga.

6.2.1.2.3 Transparencia

El formato GIF nos permite elegir qué colores queremos que sean transparentes. De esta forma, podemos hacer que el color del fondo de nuestra imagen tenga esa propiedad, mostrando así lo que queda debajo de ese color.

Figura 6.3: Imagen sin transparencia (izquierda) y con transparencia de fondo (derecha)

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

152 Francisco Prieto Donate

Esta propiedad no es selectiva: si etiquetamos un color con ella, cada píxel de la imagen que contenga ese color se volverá transparente, lo cual puede provocar resultados inesperados.

También pueden aparecer errores si se usan técnicas antialiasing, tales como introducir píxeles de un color intermedio entre la imagen en sí y su color de fondo.

6.2.1.2.4 GIF animados

El formato GIF permite combinar varias imágenes de este tipo en un único archivo para crear una animación. Si creamos una animación con cuatro ficheros GIF de 30KB, obtendremos un GIF animado de 120KB de tamaño. Sin embargo no realiza compresión entre imágenes.

Otro inconveniente de este tipo de GIF es que no hay forma de controlar cuándo se ejecuta la animación. Además, si está activada la función bucle, las animaciones se reproducen continuamente. Por esta característica, suelen distraer a los lectores del contenido de la página.

La ventaja principal de esta técnica es que el usuario, cuando recibe un GIF animado, puede comenzar a reproducirlo antes de que reciba el archivo completo.

Se recomienda usar este tipo de archivos cuando las animaciones son realmente necesarias, como en el paso de ilustrar una técnica en distintas fases. Si no se usa esta técnica de forma limitada, acabará resultando una molestia para lector.

6.2.1.3 Formato JPEG

Otro formato comúnmente usado en la web para minimizar el tamaño de los archivos gráficos es el JPEG (Joint Photographic Experts Group) o JPG.

A diferencia de las imágenes GIF, las JPEG son imágenes de 24 bits o color verdadero, con una paleta de colores muy superior. Debido a esta característica, este formato ha despertado interés en fotógrafos, artistas, diseñadores gráficos, especialistas en imágenes médicas y otros grupos de personas para los que la calidad de la imagen es muy importante, y para los que resultan escasos 8 bits para lograr colores fieles a la realidad.

Para lograr la compresión, JPEG hace uso de una técnica matemática llamada transformación del coseno discreto (DCT), que produce una escala variable de

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 153

compresión de gráficos. Se puede elegir el grado de compresión que se aplica a una imagen JPEG, pero al hacerlo también ser determina la calidad de la imagen, ya que este algoritmo produce pérdidas. La técnica de compresión consiste básicamente en dividir la imagen en bloques de 8x8 píxeles y aplicarles esta transformada.

Cuanto más se comprime una imagen JPEG, más degradamos su calidad. Es posible comprimir una imagen hasta lograr grandes tasas de compresión, del orden de cien veces el tamaño del archivo original. Pero esto es posible debido a que el algoritmo de compresión de JPEG descarta los datos innecesarios cuando comprime la imagen. Una vez que una imagen se ha comprimido con este formato, pierde parte de la información que guardaba originalmente.

Aún así, éste es uno de los formatos más usados a la hora de digitalizar imágenes, debido principalmente a su razonable calidad y su alta capacidad de compresión.

El formato de un fichero JPEG es el siguiente:

• Cabecera JPEG.

• Dimensiones de la imagen.

• Formato de la imagen (escala de grises, 24-bit, etc).

• Información acerca relativa al algoritmo de compresión.

• Datos de la imagen.

Existe una versión de archivos JPEG llamados progresivos, que hacen que la imagen aparezca en la pantalla como si se tratara de un fichero GIF entrelazado. Al igual que éstos, tardan más en cargarse y reproducirse por pantalla que el formato estándar JPEG, pero ofrecen al usuario una rápida vista previa de la imagen.

6.2.1.3.1 Artefactos en la imagen JPEG

Un artefacto en una imagen es cualquier estructura que aparezca en ella, y que no estaba originalmente presente en el objeto cuando se obtuvo la imagen. Todo aquello que aparezca en la imagen y no exista en la realidad, es un artefacto.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

154 Francisco Prieto Donate

Vamos a ver que JPEG puede producir ciertas distorsiones en las imágenes. Todos estos píxeles erróneos debidos a las técnicas de compresión son considerados como artefactos y deben ser eliminados ya que no aportan información real.

El algoritmo JPEG fue optimizado para la compresión de fotografías convencionales. Este formato se comporta de forma óptima en imágenes artísticas o ilustraciones complejas donde abundan los colores y existen muchas transiciones de tonos, pocas áreas de fuertes contrastes y fronteras muy delimitadas.

Cuando esto no sucede, el formato de compresión no se comporta correctamente y genera una serie de artefactos, como por ejemplo los píxeles de ruido, que emborronan las fronteras de un objeto.

La mayoría de los elementos que componen una página web tales como botones, diagramas e ilustraciones, están compuestos de gráficos con un fuerte contraste entre sus fronteras y el color de fondo. Estas características no suelen darse en fotografías reales, por ello, es mejor restringir el uso de este formato a aquellos casos para los que está optimizado.

A continuación observamos una imagen original (figura a), a la que vamos a comprimir usando GIF (figura b) y JPEG (figura c).

Artefactos producidos por una compresión JPEG.

Se observa que en la imagen GIF no aparecen artefactos y en la JPEG aparece ruido alrededor del texto y los bordes, debido a la compresión.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 155

JPEG está pensado para comprimir transiciones suaves entre tonos de una imagen y no es adecuado para comprimir las transiciones abruptas entre gráficos de un diagrama.

6.2.1.4 Formato PNG

Los formatos GIF y JPEG se encuentran patentados, y todo uso de ellos debe ser autorizado por los propietarios de las patentes. Éstos, normalmente, se lucran gracias a esta situación.

El formato PNG (Portable Network Graphics) fue desarrollado por el W3C como alternativa no propietaria al formato GIF. Como se mencionó anteriormente, CompuServe creó el formato GIF usando el algoritmo de compresión LZW, que es propiedad de la empresa Unisys Corporation. Cualquier desarrollador de herramientas gráficas, que cree un software capaz de almacenar imágenes en formato GIF, debe pagar unas tarifas periódicas (royalties) a Unisys y CompuServe.

El formato PNG fue diseñado específicamente para su uso en páginas Web, como sustituto de GIF, y ofrece unas serie de características que deberían lograr que PNG fuera el más común de los formatos gráficos.

Utiliza el algoritmo de compresión LZ77, libre de patentes. Este sistema es válido para comprimir cualquier tipo de dato, no sólo se reduce a imágenes; de hecho, es el usado en la creación de archivos ZIP. La idea básica del algoritmo es recorrer todos los datos, fijarse en los que aparecen repetidos, y sustituirlos por una referencia al dato inicial. Con este algoritmo se obtienen una compresión de entre un 5% y un 25% mejor que la que realiza un archivo GIF.

Al igual que GIF, puede usar entrelazado, admitiendo además hasta 256 niveles de transparencia.

Figura 6.4: Efecto de la transparencia en una imagen PNG

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

156 Francisco Prieto Donate

Algunas de las características del formato PNG son:

• Paleta de colores de 8 bits (256 colores) o 24 bits (16.7 millones).

• Soporte para realizar transparencia sofisticada de imágenes (canal alpha), permitiendo varios niveles de transparencia (hasta 256).

• Mejor entrelazado.

• Corrección automática del grado de contraste (gamma).

• Algoritmo de compresión sin pérdidas.

Las imágenes PNG también permiten describir el contenido de la imagen con una pequeña cadena de texto, lo cual facilita la búsqueda de imágenes en Internet basándose en esas descripciones.

PNG no soporta animaciones gráficas, sin embargo, el W3C ha desarrollado un formato libre llamado MNG que sí las soporta.

6.2.1.5 COMPARATIVA ENTRE LOS DISTINTOS FORMATOS

La mayoría de los navegadores actuales soportan adecuadamente tanto GIF como JPEG, pero no el formato PNG con toda su funcionalidad (transparencia).

A la hora de colocar elementos visuales en una página Web, es más eficiente usar el formato GIF o el PNG para los elementos de diseño, diagramas e imágenes de 8 bits, y usar JPEG para fotografías, ilustraciones complejas, imágenes médicas, o cualquier otro tipo de imagen en la que los artefactos surgidos por la compresión JPEG no comprometa la calidad de la imagen.

La ventaja de sustituir GIF por PNG reside en trabajar con una mayor funcionalidad y además estar libre de patentes.

6.2.1.5.1 Ventajas de los archivos GIF

• GIF es el formato con más soporte de todos los usados.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 157

• Los diagramas y elementos de diseño se representan mejor con GIF que con JPEG.

• GIF soporta transparencia y entrelazado.

• Soporta animación.

6.2.1.5.2 Ventajas del formato JPEG

• Permite una mayor tasa de compresión para imágenes de muchos colores y pocos contrastes, lo que se traduce en una descarga más rápida.

• JPEG logra excelentes resultados con fotografías e imágenes complejas.

• JPEG tiene una paleta de colores de 24 bits (color verdadero), soportando toda la gama de colores posibles.

6.2.1.5.3 Ventajas de los archivos PNG

• Libre de patentes.

• Ideal sustituto de GIF.

• Soporta varios niveles de transparencia y usa entrelazado.

• Paleta de colores de 8 o 24 bits (color verdadero).

En la siguiente tabla se resume las distintas características anteriormente comentadas:

BMP GIF JPEG PNG

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

158 Francisco Prieto Donate

Tamaño del archivo generado con una

imagen fotográfica. Grande Medio Pequeño Medio

Tamaño del archivo generado con una

imagen de tipo diagrama.

Grande Pequeño Medio Pequeño

Compresión No Sin pérdidas Con pérdidas Sin pérdidas con 5-25 %

mejor que GIF

Profundidad de color

1,4, 8 y 24 bits

8 bits/256 colores

24 bits

8 bits B/N

PNG-8: 8 bits/256 colores

PNG-24: 24 bits/16,7

millones de colores

Transparencia No

Permite establecer un color como transparente

No

Canal Alfa: varios

diferentes niveles de

transparencia (256 en PNG-

24)

Soporte de entrelazado No Sí Sí Sí

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 159

Animación No Sí No No (resuelto con MNG)

Tabla 6.1: Comparación entre los distintos formatos de imagen

Una vez analizados cuatro de los formatos de imagen más utilizados, pasamos a evaluarlos en función de su relación calidad-tamaño. Para transmitir imágenes de calidad con un tamaño de datos reducido, el formato más recomendable es JPEG. Entre los formatos GIF y PNG nos decantaremos por el segundo, ya que además de no provocar pérdidas, admite una paleta de colores mayor y mejor compresión. Cabe destacar además el hecho de que PNG se encuentra libre de patentes. Por último, indicar que el formato BMP no es recomendable para la transmisión de imágenes a través de Internet, ya que el tamaño de los archivos resulta excesivamente grande.

6.2.2 Formatos de codificación de vídeo

En este apartado vamos a realizar una introducción a la forma de codificar señales de vídeo. Una señal de vídeo no es nada más que la reproducción en forma secuencial de un conjunto de imágenes, que al verse con una determinada velocidad y continuidad dan la sensación al ojo humano de apreciar el movimiento natural.

Muchos formatos de vídeo están relacionados con formatos de almacenamiento de imágenes, como vamos a ver a continuación.

En una señal de vídeo aparecen dos tipos de redundancia:

• Dentro de una imagen: es la redundancia típica en un archivo gráfico, que se puede reducir utilizando algún formato de compresión como los vistos anteriormente.

• Entre imágenes: las diferencias entre dos imágenes consecutivas en la escala temporal son mínimas. Si podemos analizar qué bloque de la imagen es el que ha cambiado podemos aumentar la compresión. Existen algoritmos de predicción de movimiento que se basan en ese hecho. Para eliminar la redundancia entre imágenes, una opción es calcular la diferencia entre ellas.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

160 Francisco Prieto Donate

Los formatos que veremos a continuación intentarán eliminar dichas redundancias para obtener vídeo con un buen nivel de calidad y un tamaño de archivo lo menor posible. Primero veremos los formatos que no eliminan redundancias o sólo eliminan la redundancia de cada imagen (RBG, Motion JPEG, H263, AVI), para pasar después a los formatos que eliminan la redundancia entre imágenes (MPEG, Divx).

6.2.2.1 Formato RGB

RGB es el formato más simple de encapsulación de vídeo. Es el equivalente a BMP en imagen: capturamos los datos con un 100% de calidad y sin ningún tipo de compresión.

Las siglas RGB provienen del inglés, Red (rojo), Green (verde) y Blue (azul) haciendo referencia a la característica del ojo humano de percibir tan sólo estos tres colores básicos y, el resto de la gama de color, se crea a partir de la combinación de ellos. La información del color de cada píxel viene dada por el valor de 3 bytes, el primero indica la componente de rojo, el segundo la de verde, y el tercero la de azul. Podemos almacenar RGB con 24 bits o con 32 bits.

Figura 6.5: Combinando luz roja, azul y verde podemos obtener todos los colores

Aunque con este formato obtenemos la máxima calidad, los altos requerimientos de espacio y de ancho de banda para no perder cuadros (frames) en la captura harán que lo desestimemos en la mayor parte de las ocasiones.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 161

6.2.2.2 Formato M-JPEG

Motion JPEG (Joint Photographic Experts Group), o JPEG en movimiento, es una extensión para vídeo del estándar de ITU/ISO JPEG para imágenes estáticas. El Motion JPEG es un método de compresión simétrico y típicamente consigue niveles de compresión de 10:1 hasta 50:1.

M-JPEG utiliza el algoritmo JPEG para comprimir imágenes. Básicamente consiste en tratar al vídeo como una secuencia de imágenes estáticas independientes a las que se aplica el proceso de compresión del algoritmo JPEG una y otra vez para cada imagen de la secuencia de vídeo.

Disminuimos el tamaño de los ficheros a costa de perder información original, ya que JPEG es un algoritmo con pérdidas.

Como es una extensión del estándar JPEG, el Motion JPEG sólo elimina redundancia dentro de una imagen y no la redundancia entre imágenes. Esto se traduce en una compresión significantemente menor a la que efectuaría un método de compresión que eliminase los dos tipos de redundancia. Otro inconveniente del Motion JPEG es que el audio no está integrado en el método de compresión.

La falta de codificación entre imágenes puede ser positiva para algunas aplicaciones de vídeo. Si de desea tener acceso a una imagen de vídeo aleatoria, Motion JPEG permitir un acceso más rápido que otros formatos puesto que no se tendrá que esperar a la llegada de múltiples imágenes para decodificar una en específico, al no depender unas de las otras.

Existen cuatro modos de operación para el M-JPEG: secuencial, progresivo, sin pérdida, y jerárquico. Normalmente se utiliza el modo secuencial. Además hace uso de una técnica de compresión espacial, la intracuadros o DCT. Solamente utiliza este tipo de compresión al estar diseñado para comprimir imágenes individuales.

La ventaja de M-JPEG es que se puede realizar en tiempo real e incluso con poca inversión en hardware. El inconveniente de este sistema es que no se puede considerar como un estándar de vídeo pues ni siquiera incluye la señal de audio. Otro problema es que el índice de compresión no es muy grande.

Motion-JPEG suele utilizarse en las aplicaciones de difusión (broadcast) donde se envía la misma información a un conjunto de usuarios.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

162 Francisco Prieto Donate

Figura 6.6: Una secuencia de imágenes provocan sensación de movimiento

6.2.2.3 Formato H.263

Es un formato desarrollado por la ITU-T para la transmisión de vídeo (con audio incluido), basándose en un sistema anterior, el H.261.

El objetivo de H.263 era proporcionar mejor calidad de imagen que el algoritmo H.261. Para ello utiliza técnicas más sofisticadas a la hora de predecir el movimiento de una imagen y eliminar la redundancia entre imágenes.

El H.263, además de utilizar nuevas técnicas de codificación, emplea técnicas conocidas como la transformada discreta del coseno y la compensación de movimiento. Existe un método más novedoso, el H.263/L (algoritmo long-term) que mejora considerablemente la calidad de imagen del H.263 y la eliminación de los errores.

Por motivos de tiempo, el H.263 estaba basado en la tecnología existente en ese momento (1995), como la RDSI, por eso está diseñado para soportar sus tasas de transmisión.

H.263 es un estándar para las comunicaciones de bajo ancho de banda. Inicialmente estaba definido para tasas de transmisión menores de 64 Kbps, aunque también puede utilizarse en comunicaciones de banda ancha.

Este formato se utiliza principalmente en las videoconferencias, pero exige que el retardo entre la captura de la imagen en el emisor y su representación en el receptor sea inferior a 100 milisegundos.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 163

6.2.2.4 Formato AVI

Uno de los formatos más extendidos es el AVI. Su nombre viene de “Audio Video Interleave”, es decir, audio y vídeo intercalado o entrelazado. Fue creado por Microsoft e integrado en Windows 3.1.

En un fichero AVI las pistas de audio y vídeo se graban de forma consecutiva en distintas capas, de ahí su nombre de vídeo entrelazado, alternándose las capas de audio y vídeo de forma tan rápida que nuestros sentidos de la vista y el oído los perciben de forma paralela.

La capa de vídeo está formada por una sucesión de imágenes tipo bitmaps y audio tipo waveforms, que son los que mayor calidad de audio y vídeo dan, aunque esta ventaja se traduce en inconveniente si hablamos de tamaño, pues son los archivos que mayor tamaño ocupan.

El estándar AVI ha quedado casi en desuso debido a la aparición de AVI1, formato usado en el vídeo digital de videocámaras, pasándose aquél a llamarse AVI2. Posteriormente, del AVI1 (también llamado AVI DV), se crearon dos divisiones más, AVI DV tipo 1 y AVI DV tipo 2. Del mismo modo, multitud de fabricantes están aportando nuevos códecs para este formato.

Figura 6.7: El Media Player de Windows 3.1 permitía visualizar archivos AVI

6.2.2.5 Formato MPEG

Las iniciales MPEG significan “Motion Picture Experts Group” o “Grupo de Expertos de Imágenes en Movimiento”, y es el nombre de un grupo de estándares empleados para la codificación de información audiovisual, incluyendo vídeo y audio en formato digital comprimido. La organización que creó estos estándares fue la ISO.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

164 Francisco Prieto Donate

El sistema MPEG surgió como una respuesta a las necesidades de transmitir señales de televisión y vídeo por redes digitales, y está pensado para funcionar con aparatos diseñados específicamente para esta misión, que permitan comprimir y descomprimir las imágenes a gran velocidad.

Este formato no está orientado a videoconferencia como H263 sino a una señal de vídeo ya grabada. Este hecho nos permite comparar un fotograma no solo con los anteriores sino además con los posteriores, logrando una mayor compresión. Esto se conoce como estimación de movimiento bidireccional.

El algoritmo que utiliza MPEG, además de comprimir imágenes estáticas, compara los fotogramas presentes con los anteriores y los futuros para almacenar sólo las partes que cambian. La señal incluye sonido en calidad digital. El inconveniente de este sistema es que debido a su alta complejidad necesita apoyarse en hardware específico.

MPEG aplica la compresión temporal y la espacial. En primer lugar se aplica una transformada del coseno discreta, seguida de una cuantización para finalmente comprimir mediante un algoritmo RLE (Run Length Encoding). Los bloques de imagen y los de predicción de errores tienen una gran redundancia espacial, que se reduce gracias a la transformación de los bloques desde el dominio del espacio al dominio de frecuencia. MPEG requiere una intensiva computación para su codificación, aunque se consiguen ratios desde 50:1 hasta 200:1

Un factor de confusión es que MPEG no es un estándar, sino varios, y en muchas ocasiones no queda claro de cuál se habla.

6.2.2.5.1 MPEG-1

Este fue el primer estándar del grupo MPEG, que nació en 1991. Está orientado a sustituir a las cintas de vídeo VHS usando CDs (video CD o VCD). Permite una resolución de 352x288 píxeles.

MPEG-1 guarda una imagen, la compara con la siguiente y almacena sólo las diferencias. Se alcanzan así grados de compresión muy elevados. Define tres tipos de fotogramas:

• Fotogramas I o Intra-fotogramas, son los fotogramas normales o de imagen fija, proporcionando una compresión moderada, en JPEG.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 165

• Fotogramas P o Predichos: son imágenes predichas a partir de la inmediatamente anterior. Se alcanza una tasa de compresión muy superior.

• Fotogramas B o bidireccionales: se calculan en base a los fotogramas inmediatamente anterior y posterior. Consigue el mayor grado de compresión a costa de un mayor tiempo de cálculo.

La velocidad de la señal comprimida de aprox. 1.5 Mbps (incluyendo audio) para tener aprox. 1 hora de película en un CD (de 700 Mbytes). El factor de compresión obtenido es de 60:1 (aprox. 5Kbytes por fotograma).

6.2.2.5.2 MPEG-2

Surge en 1994 como alternativa al anterior, para dotar al vídeo de más calidad y mayor resolución (720x576), ya que la del MPEG1 (Video CD) se consideró insuficiente para la distribución de películas a gran escala.

MPEG-2 fue universalmente aceptado para transmitir vídeo digital comprimido con velocidades mayores de 1Mb/s aproximadamente. Con MPEG-2 pueden conseguirse elevadas tasas de compresión de hasta 100:1, dependiendo de las características del propio vídeo.

Este el estándar utilizado en los DVD-Video para las películas que se distribuyen en el mercado de consumo. También se utiliza para la transmisión de la Televisión Digital Terrestre y en algunos países para la televisión de alta definición (HDTV).

6.2.2.5.3 MPEG-3

Se intentó desarrollar para televisión con velocidades de transmisión altas pero acabó desechándose y fusionándose con MPEG-2.

6.2.2.5.4 MPEG-4

Es un estándar relativamente nuevo (1999) orientado inicialmente a las videoconferencias e Internet. El objetivo es crear un contexto audiovisual en el cual existen unas primitivas llamadas AVO (objetos audiovisuales). Se definen métodos para codificar estas primitivas que podrían clasificarse en texto y gráficos La comunicación con los datos de cada primitiva se realiza mediante uno o varios

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

166 Francisco Prieto Donate

"elementary streams" o flujos de datos, cuya característica principal es la calidad de servicio requerida para la transmisión.

Este estándar ha sido especialmente diseñado para distribuir vídeos con elevadas tasas de compresión sobre redes con bajo ancho de banda, manteniendo una excelente calidad para usuarios de banda ancha. Es rápido codificando el vídeo de alta calidad, por lo que se hace adecuado para contenidos en tiempo real y bajo demanda.

Permite un amplio rango de velocidades: desde 10kbps hasta 10Mbps, por lo que se hace idóneo para transmisión de datos por Internet a dispositivos móviles.

6.2.2.5.5 MPEG-7

Este estándar, aprobado por la ISO, se espera que sea el formato más utilizado para Internet y las nuevas tecnologías de televisión interactivas. MPEG-7 no sólo incluye codificación de imagen y sonidos, sino también datos en formato XML. Esto dará la posibilidad de hacer realidad la televisión a la carta, buscadores de contenidos, etc.

6.2.2.6 Formato DivX ;-)

El DVD nació con el objetivo de ofrecer un formato de vídeo encriptado de forma que fuera posible su reproducción pero no su copia. Este sistema de encriptación pronto fue publicado en Internet, de modo que no tardó mucho tiempo en ser desencriptado.

Una vez desencriptado el vídeo se hizo necesario contar con un sistema de compresión que permitiera grabar una película proveniente de un DVD (4,7 Gb) en un CD-ROM (700 Mb).

El fichero DivX es un fichero AVI que contiene, por un lado, el vídeo original (que estaba en formato MPEG) codificado en formato DivX, y por el otro, el audio original (que estaba en formato Dolby AC3) codificado en MP3. Esto provoca una reducción drástica del tamaño del archivo, aunque también se está sacrificando cierta calidad de imagen y sonido.

La popularidad de este formato ha provocado que muchos reproductores de DVD actuales ofrezcan la capacidad de descodificar el formato DivX.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 167

Figura 6.8: Muchos reproductores de DVD soportan DivX

6.2.2.7 Otros formatos de vídeo

Internet está favoreciendo el intercambio de gran cantidad de contenidos multimedia. En la red se puede ver que existen muchas otras codificaciones de vídeo, como pueden ser: MOV, ASF, Real Media, WMV… Todos estos formatos han sido desarrollados por distintos fabricantes y no introducen nuevas características con respecto a los que hemos estudiado anteriormente.

6.3 Tecnología de streaming

Esta opción permite la transmisión de vídeo en tiempo real, usando Internet como medio de transmisión.

La tecnología de streaming se utiliza para aligerar la descarga y ejecución de audio y vídeo en la web, ya que permite escuchar y visualizar los archivos mientras se están descargando. A grosso modo, la reproducción de la señal es al vuelo: cuando lo recibido alcanza un cierto tamaño es reproducido y después borrado.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

168 Francisco Prieto Donate

6.3.1 Funcionamiento

En primer lugar nuestro ordenador (el cliente) conecta con el servidor y éste le empieza a mandar el fichero. El cliente comienza a recibir los datos y construye un buffer, o espacio de memoria temporal, donde empieza a guardar la información. Cuando se ha llenado el buffer con una pequeña parte del archivo, se empieza a mostrar a la vez que continúa la descarga, como se indica en la figura siguiente.

Figura 6.9: Funcionamiento de la técnica de streaming

La parte ya mostrada no se almacena. El sistema está sincronizado para que el archivo pueda visualizarse a la vez que se descarga, de modo que cuando el fichero acaba de descargarse, también termina de visualizarse.

Si en algún momento la conexión sufre descensos de velocidad se utiliza la información que hay almacenada en el buffer mientras se recupera la velocidad óptima inicial. Si la velocidad de descarga sigue sin recuperarse, el buffer se vacía y la ejecución el archivo se cortaría hasta que se restaurase la señal. Para una comunicación por streaming es importante tener un cierto ancho de banda: mientras mayor sea éste, a más velocidad se llenará el buffer y más fluida será la reproducción.

Existen tres métodos de streaming:

• Diferido: Los archivos multimedia que se reproducen son digitalizados y codificados antes de ser transmitidos a los usuarios, de esta forma la imagen no llega a los ordenadores al mismo tiempo que está ocurriendo el evento.

• Bajo demanda: Es el método de streaming más común. En él, las imágenes de vídeo y audio (previamente codificadas) proceden de un servidor de streaming, y serán reproducidas en nuestros equipos cuando así lo deseemos.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 169

• Directo: Los archivos de audio y vídeo son codificados y transmitidos en tiempo real. Esto permitirá visualizar cualquier acontecimiento que se esté produciendo en el mismo instante. Es el método utilizado en las retransmisiones de radio y televisión por Internet.

6.3.2 Reproductores de streaming

Un usuario puede haber utilizado el proceso de streaming en muchas ocasiones sin tener consciencia de ello. Es lo que hacen programas como Real Player o Windows Media Player, programas que se instalan como plug-ins en los navegadores para recibir y mostrar contenidos multimedia por streaming a través de Internet.

Cuando pretendemos incluir audio o vídeo en las páginas web, lo mejor es utilizar la tecnología de streaming. Para ello simplemente tenemos que guardar los archivos multimedia con el formato de uno de los programas de streaming y seguir unas pequeñas normas a la hora de subirlos a Internet y colocarlos en la página. Las normas que seguir son propias de cada sistema. Para más información acerca de este tema se recomienda consultar las páginas web de los programas citados anteriormente.

Para convertir los archivos de audio y vídeo al formato de cada programa de streaming se utilizan unos programas especiales que se pueden descargar de las páginas de cada tecnología. Por ejemplo, el programa para convertir al formato que lee el Real Player se llama Real Producer.

Para que un usuario pueda recibir contenidos enviados por streaming es necesario que tenga un plug-in adecuado en su navegador. A continuación vamos a ver, a modo de ejemplo, tres tecnologías de streaming que se usan en este momento.

• Real Media es posiblemente la más popular. También es la empresa con más experiencia en el sector y desarrolla muchos productos orientados a la distribución de archivos multimedia.

• Windows Media es la apuesta de Microsoft. Ya posee una cuota de usuarios muy importante y seguramente aumentará con rapidez ya que Microsoft incluye el plug-in en la instalación típica de los sistemas operativos que está fabricando.

• Quick Time es la tercera en discordia. Tiene una cuota de mercado ligeramente menor debido a que tiene menor calidad de imagen y peores prestaciones.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

170 Francisco Prieto Donate

Figura 6.10: Los tres reproductores de streaming más utilizados

6.3.3 Servidores de streaming

En principio no es necesario contar con un servidor especial para colocar archivos de audio o vídeo con descarga streaming en nuestras webs. Cualquier servidor normal puede mandar la información y es el cliente el que se encarga de procesarla para poder mostrarla a medida que la va recibiendo.

En determinados casos, como la puesta en marcha de una radio o la transmisión de un evento en directo, sí que será imprescindible contar con un servidor de streaming al que mandaremos la señal de vídeo, para que éste la envíe a todos los clientes a medida que la va recibiendo, realizando multidifusión.

Sin embargo, existen servidores especiales preparados para transmitir streaming. Nos pueden ofrecer importantes prestaciones como control de flujo, velocidad adaptable (para mandar un archivo de mayor o menor calidad dependiendo de la velocidad de nuestra línea) o protección de los derechos de autor (ya que no permite realizar copia local de los archivos).

6.3.4 Protocolos de streaming

Son varios los protocolos que intervienen en esta tecnología y que facilitan en gran medida su eficacia. Éstos son:

• RTP (Protocolo de transporte en tiempo real): Es sin duda el más importante de todos, ya que fue desarrollado específicamente para esta tecnología. Todo flujo de datos con contenido multimedia es enviado por la red a través de paquetes RTP en tiempo real.

6. Transmisión de vídeo en Internet

Francisco Prieto Donate 171

• RTCP (Protocolo de control en tiempo real): Se utiliza junto con RTP para gestionar la comunicación entre cliente y servidor, informando de situaciones tales como el número de paquetes perdidos durante la transmisión. Este tipo de informes es muy útil para ir subsanando errores y optimizar el envío de flujo de datos.

• RTSP (Protocolo de streaming en tiempo real): Es el protocolo de la tecnología streaming encargado de controlar el flujo de datos en tiempo real, existente entre el servidor y el ordenador cliente. Ofrece al usuario la posibilidad de manejar la señal de vídeo mediante los controles típicos de cualquier reproductor de vídeo doméstico, es decir: rebobinado, avance rápido, pausa y acceso aleatorio a cualquier punto del elemento multimedia.

6.4 Consideraciones finales

A lo largo de este capítulo hemos considerado los dos métodos de transmisión de vídeo más usados en Internet: la descarga y posterior visualización del contenido, y la tecnología Streaming.

En el primer caso la solución pasa por descargarse el archivo de vídeo y visualizarlo con un reproductor adecuado. En los apartados anteriores hemos descrito los formatos de vídeo más significativos: RBG, M-JPEG, H.263, AVI, MPEG y DivX, enumerando en cada uno de ellos las ventajas y desventajas que presentan.

Para el caso de dispositivos con poca capacidad de almacenamiento y memoria, la solución pasaría por descargar imágenes estáticas y presentarlas en pantalla una detrás de otra. Por ello se han estudiado los formatos de imagen más utilizados en la actualidad: BMP, GIF, JPEG y PNG. Al final del apartado se ha realizado una comparativa en la que se demuestra que JPEG es el formato que consigue mejor relación calidad - tamaño.

Por último presentamos la tecnología Streaming, el método más utilizado actualmente en Internet para visualizar vídeos. Son dos las ventajas principales que han hecho tan popular a esta tecnología: por un lado no es necesario esperar a la descarga completa del vídeo para comenzar a visualizarlo; además permite la transmisión en tiempo real, de modo que se pueden visulizar eventos que están sucediendo en ese mismo instante.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

172 Francisco Prieto Donate

7. Aplicación desarrollada

Francisco Prieto Donate 173

7 APLICACIÓN DESARROLLADA

7.1 Introducción

El objetivo de este proyecto consiste en transmitir imágenes de vídeo desde un servidor hasta un teléfono móvil con soporte J2ME utilizando Servicios Web XML.

Como punto de partida contamos con un servidor de imágenes ya implementado. Este servidor captura imágenes de una webcam y espera a recibir peticiones por parte del cliente. Este servidor admite en principio dos tipos de peticiones:

• RTP, con el cual el servidor nos envía un flujo de vídeo continuo.

• HTTP, con el que podemos rebibir una imagen por cada petición.

Se trata, pues, de crear un servicio web XML con el servidor de vídeo ya existente, de modo que posibilite la transmisión de imágenes de vídeo utilizando XML. Asimismo se hará necesario acceder a dicho servicio web a través de un teléfono móvil que soporte J2ME y tenga acceso a Internet vía GPRS, con el fin de hacer la petición al servidor y recibir la secuencia de imágenes solicitada.

En los apartados posteriores vamos a estudiar las diferentes alternativas de las que disponemos para desarrollar el servidor web y el cliente de vídeo, y justificaremos la elección tomada para su implementación.

7.2 Desarrollo del servidor

Un servidor web XML es un servidor de aplicaciones capaz de ofrecer una interfaz a través de la cual se pueda invocar un método y se devuelva el resultado de su ejecución. El método se debe ejecutar en el propio servidor, de modo que el cliente sólo se tiene que encargar de aportar los parámetros necesarios y esperar la respuesta solicitada. Además la comunicación entre cliente y servidor debe realizarse mediante SOAP, un protocolo de mensajes formateados en XML que contienen la información necesaria para la invocación remota de servicios.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

174 Francisco Prieto Donate

7.2.1 Transformación del servidor de vídeo en servidor web XML

El servidor de vídeo del que partimos sólo soporta los protocolos RTP y HTTP, de modo que se nos plantean dos alternativas para convertirlo en servidor web: o bien implementar un servidor web en el propio servidor de vídeo o bien utilizar un servidor web XML ya existente y asociarlo al servidor de vídeo.

• Implementar un servidor web en el servidor de vídeo

Esta solución pasaría por ampliar el servidor de vídeo, aportándole la capacidad de interpretar llamadas a métodos remotos. Sería necesario además hacer que soporte el protocolo SOAP y que sea capaz de examinar documentos XML.

• Utilizar un servidor web XML ya existente

Utilizando un servidor web ya implementado, evitamos tener que desarrollar la interpretación de llamadas a métodos remotos. En este caso dispondríamos ya de soporte para el protocolo SOAP y paso de mensajes formateados en XML. El problema que se plantea en este caso es cómo relacionar el servidor web con el servidor de vídeo existente.

Si atendemos al criterio de mínima modificación del servidor de vídeo existente, nuestra solución pasa por utilizar el servidor de aplicaciones Apache Tomcat con el módulo Axis. Hemos elegido Tomcat por ser el servidor de aplicaciones en software libre más utilizado en la red.

7.2.2 Comunicación entre servidor de vídeo y servidor web

El siguiente paso consiste en hacer que cuando se invoque un método al servidor web, éste acuda al servidor de vídeo para obtener las imágenes de vídeo solicitadas. Normalmente cuando se invoca un servicio web, el servidor hace una llamada a un método interno y devuelve el resultado. Podríamos decir que el método es ejecutado cuando se invoca el servicio web.

El caso que se propone en este proyecto es distinto, pues el servidor de vídeo no está diseñado para iniciarse y detenerse en cada llamada. El ciclo de vida del servidor de vídeo pasa por:

7. Aplicación desarrollada

Francisco Prieto Donate 175

• Ejecución: Se inicia el servidor y se queda a la espera de ser configurado.

• Configuración: Indicamos la calidad y el formato de imagen que se va a transmitir, el dispositivo de captura que se va a utilizar (en el caso de que se disponga de varios) y el puerto a través del que escuchará el servidor.

• Captura y transmisión: El dispositivo capturador de vídeo comienza a recoger imágenes y las presenta por pantalla. Desde este momento el servidor queda a la espera de recibir peticiones para transmitir las imágenes capturadas.

• Finalización: En el momento que no se necesite utilizar más el servidor de vídeo, procedemos a su finalización. El dispositivo capturador deja de recibir imágenes y el servidor deja de esperar peticiones.

Como se puede observar, el servidor se inicia una sola vez, y cuando se encuentra correctamente configurado, queda a la escucha en el puerto seleccionado.

Por ello, la única forma que tenemos de relacionar ambos servidores es haciendo uso de los protocolos que el servidor de vídeo nos ofrece. De esta manera, el servicio web consistirá en un método que haga una petición al servidor de vídeo mediante alguno de los protocolos que éste reconozca, bien sea RTP o HTTP.

7.2.3 Protocolo de comunicación entre servidores

De entre los dos protocolos que soporta el servidor de vídeo, nos preguntamos cuál de ellos será más conveniente utilizar.

El protocolo RTP es un protocolo de transmisión en tiempo real, de modo que una vez se establece la comunicación, se envía un flujo continuo de datos que no cesa hasta que no se interrumpa dicha comunicación. Este principio de funcionamiento no está soportado por los servicios web, que están diseñados para atender a una petición y devolver una respuesta.

Se nos hace obligatorio, por tanto, realizar peticiones HTTP al servidor de vídeo para obtener una imagen en cada petición. Una sucesión de peticiones dará como resultado una sucesión de imágenes que, al ser visualizadas unas tras otras, darán la sensación de movimiento.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

176 Francisco Prieto Donate

Figura 7.1: Comunicación entre servidores

7.3 Desarrollo del cliente

Un cliente de servicios web XML se encarga de hacer una petición al servidor y obtener una respuesta. En este proyecto, el cliente de vídeo consiste en un teléfono móvil con conexión a Internet por GPRS y con soporte J2ME. Ya que estamos trabajando con servicios web, el teléfono móvil debe asimismo ser capaz de realizar una petición al servidor, formatear un mensaje en XML y transmitir y recibir datos a través del protocolo SOAP.

7.3.1 Servicios web en dispositivos móviles

Existen dos formas de ofrecer soporte a servicios web en un dispositivo móvil: por un lado existen teléfonos que integran la especificación JSR-172, de modo que soportan los servicios web de forma nativa. En caso contrario, debemos aportar dichas funcionalidades a través de librerías externas.

En este proyecto se van a tratar los dos casos, ya que son dos maneras muy distintas de implementar servicios web en teléfonos móviles. Además, la diferencia de ambos en cuanto al consumo de memoria y rendimiento de la conexión a Internet es notable. Otro motivo para estudiar ambos casos consiste en el dato de que aproximadamente existe en el mercado el mismo número de teléfonos que soportan la espeficiación JSR-172 que de dispositivos que no lo soportan. Normalmente los primeros son frecuentes en gama media-alta, y los segundos se ven principalmente en gama media-baja.

Como librería externa utilizaremos kSOAP 2, desarrollada por el proyecto Sourceforge y explicada con más detalle en el capítulo “Servicios Web XML”.

7. Aplicación desarrollada

Francisco Prieto Donate 177

7.3.2 Formato de imagen solicitada

Es necesario saber qué formatos de imagen puede devolvernos el servidor de imágenes y qué formatos de imagen se pueden visualizar en un dispositivo móvil.

El servidor de vídeo nos ofrece tres posibles formatos de imagen: PNG, JPG y BMP. Aún desconociendo los formatos permitidos por el cliente móvil, descartamos automáticamente el formato BMP, ya que el tamaño de archivo hace inviable su transmisión por una red GPRS. Se recomienda consultar el estudio comparativo realizado en el capítulo “Transmisión de vídeo en Internet” para justificar esta decisión.

Por otro lado sabemos que el dispositivo móvil debe soportar la especificación MIDP. Esta especificación, tanto en su versión 1.0 como en la posterior 2.0, impone que el único formato obligatorio a implementar por todos los dispositivos compatibles sea PNG. Afortunadamente este tipo de imágenes son soportadas por el servidor de vídeo.

Basándonos en el estudio comparativo de los distintos formatos de imagen realizado en el tema anterior, concluimos que sería recomendable utilizar el formato JPG para transmitir imágenes de alta calidad en una conexión con tan poco anche de banda como la red GPRS. Aunque la especificación MIDP obliga a que se soporte el formato PNG, no impide que se utilicen otros, siempre que el dispositivo móvil lo permita. Para ello vamos a utilizar una clase en Java, desarrollada en otro proyecto fin de carrera, que realiza la descodificación de una imagen JPG en dispositivos que no lo soportan de forma nativa. Así podremos comprobar las diferencias en tiempo de recepción entre imágenes JPG e imágenes PNG.

7.4 Comunicación cliente-servidor

Los servicios web XML están diseñados para abstraer al usuario de los detalles de comunicación entre cliente y servidor. De este modo, no es necesario conocer cómo se serializan elementos complejos tales como vectores, arrays o archivos binarios.

Sin embargo resulta interesante conocer cómo afecta la codificación de la información en este tipo de servicios. En el presente proyecto se pretende transmitir una secuencia de imágenes, de modo que cada imagen debe ser serializada para ser transmitida por la red. Al ser un documento binario (el contenido no se puede representar con caracteres imprimibles), el protocolo SOAP lo codifica automáticamente en formato Base64, que sí soporta caracteres imprimibles.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

178 Francisco Prieto Donate

Aunque Base64 es la codificación de SOAP por defecto, podemos forzar el uso de cualquier otra codificación. De esta manera vamos a transmitir una imagen codificada en un array de enteros, haciendo que cada octeto de la imagen sea convertido en su número entero equivalente. Al formar un array con el conjunto de todos los enteros obtenidos, estaremos utilizando otro método para codificar la imagen en caracteres imprimibles.

Figura 7.2: Esquema petición-respuesta. El servidor web codifica automáticamente la imagen en Base64.

��������

����

��

���� �����������

������

����

��

��������

��������� ������

Figura 7.3: Esquema petición-respuesta. Forzamos la codificación de la imagen a Array de enteros.

7. Aplicación desarrollada

Francisco Prieto Donate 179

7.5 Consideraciones finales

En este capítulo hemos establecido las bases para crear un entorno de desarrollo en el que sea posible transmitir imágenes de vídeo a través de Servicios Web XML.

Utilizaremos el servidor de aplicaciones Apache Tomcat con Axis como servidor web, de tal manera que se comunicará con el servidor de vídeo por medio de peticiones HTTP.

El cliente móvil se comunicará con el servidor Apache a través de mensajes SOAP. Se utilizarán dos tecnologías similares, kSOAP y JSR-172, para implementar servicios web en el dispositivo móvil.

Realizaremos peticiones de imágenes en formato JPG y PNG, y utilizaremos dos codificaciones para transformar los datos binarios en caracteres imprimibles: Base64 y Array de enteros.

La siguiente figura muestra todos los elementos que intervienen en la comunicación:

Figura 7.4: Elementos que intervienen en la comunicación

En el siguiente capítulo estableceremos un escenario de pruebas en el que veremos cómo se desarrolla y despliega un servicio web XML que permite transmitir imágenes de vídeo y describiremos el funcionamiento del cliente móvil que realizará las peticiones.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

180 Francisco Prieto Donate

8. Escenario de pruebas

Francisco Prieto Donate 181

8 ESCENARIO DE PRUEBAS

8.1 Introducción

En este capítulo pasamos a detallar las pruebas realizadas, teniendo en cuenta que pretendemos cumplir los siguientes objetivos:

• Transmitir imágenes de vídeo mediante Servicios Web XML partiendo de un servidor de vídeo existente.

• Utilizar Servicios Web XML en la J2ME, de modo que se pueda comunicar un servidor fijo con un cliente móvil.

• Integrar en nuestro programa cliente un descodificador JPEG ya desarrollado en un proyecto anterior.

• Encontrar una implementación que nos permita recibir imágenes de vídeo con una calidad aceptable, bajo tiempo de respuesta y consumo de memoria limitado.

8.2 Escenario de pruebas

Para cumplir los objetivos anteriores vamos a crear un escenario de pruebas en el que realizaremos las siguientes acciones:

1. Creación y despliegue de un servicio web XML que atienda peticiones por parte del cliente y se comunique con el servidor de vídeo para devolver la imagen.

2. Creación del cliente móvil, el cual realiza peticiones al servidor web, recibe la respuesta y representa por pantalla la imagen recibida.

3. Simulación del cliente móvil: Se realizarán peticiones de imágenes en formato PNG y en formato JPG. Asimismo, para cada uno de estos formatos de imagen utilizaremos la codificación Base64 y una codificación basada en un array de enteros.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

182 Francisco Prieto Donate

4. Recogida de datos en las dos variables que más afectan al rendimiento del cliente: tiempo entre imágenes y consumo de memoria en tiempo de ejecución.

Toda esta secuencia de pruebas se realizará por separado para las dos tecnologías de servicios web en J2ME que hemos estudiado: kSOAP y JSR-172.

El entorno en que se desarrollarán todas estas pruebas está compuesto por un ordenador personal y una webcam. En el PC, que tendrá conectada la webcam, se ejecutará el servidor de vídeo, el servidor web Apache Tomcat y el emulador J2ME Wireless Toolkit. El servidor de vídeo se comunica con Apache por HTTP, mientras que el emulador se comunica con Apache mediante SOAP sobre HTTP. El montaje se corresponde con el siguiente esquema de comunicaciones:

Figura 8.1: Escenario de pruebas

8.3 Escenario kSOAP

8.3.1 Desarrollo del servicio web

El servicio web desarrollado está compuesto de una sola clase, llamada VideoKsoap y cuatro métodos, dos de los cuales se utilizarán para escuchar las peticiones del cliente. El método más importante de la clase es el llamado conectar, que realiza la petición al servidor de vídeo especificando el formato y el tamaño de la imagen, y devuelve un array de bytes con la imagen solicitada.

public byte[] conectar(String formato, int tam) throws Exception{ InputStream is = null; DataInputStream dis = null; int len = 0; byte datos[] = null;

8. Escenario de pruebas

Francisco Prieto Donate 183

// Hacemos la petición al servidor de vídeo URL url = new URL("http", ip, puerto, "/?format=" + formato + "?resize=" + tam + "*" + tam + "?" + getCalidad(formato)); HttpURLConnection conexion = (HttpURLConnection)url.openConnection(); int rc = conexion.getResponseCode(); if (rc != HttpURLConnection.HTTP_OK) { conexion.disconnect(); throw new Exception("Codigo de respuesta HTTP: " + rc); } // Comprobamos el tipo de archivo devuelto String tipo = conexion.getContentType(); if (!tipo.equals("image/png") && !tipo.equals("image/jpeg")) { throw new Exception("Se esperaba una imagen, " + "pero se ha recibido " + tipo); } len = conexion.getContentLength(); // Almacenamos la información recibida en un array de bytes if (len > 0) { is = conexion.getInputStream(); dis = new DataInputStream(is); datos = new byte [len]; dis.readFully(datos); } // Cerramos el flujo de entrada if (dis != null) { dis.close(); dis = null; } // Cerramos la conexión if (conexion != null) { conexion.disconnect(); conexion = null; } return datos; }

La petición al servidor de vídeo necesita un parámetro que le indique la calidad de la imagen. Este parámetro va a ser fijo para cada uno de los formatos, y se especifica en el método getCalidad:

public String getCalidad(String formato) { String cadena; if (formato == "jpg") cadena = "quality=50"; else if (formato == "png") cadena = "comp=max";

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

184 Francisco Prieto Donate

else cadena = ""; return cadena; }

Los dos métodos restantes son los encargados de recibir la petición por parte del cliente. La diferencia entre ambos radica en que la codificación con la cual se enviará la imagen es distinta en cada caso.

En el primer caso vamos a enviar al cliente un array de bytes con la imagen solicitada. El módulo Axis en el lado del servidor y el paquete kSOAP en el lado del cliente se encargarán de codificar y descodificar automáticamente este array en formato Base64:

public byte[] getImagenBase64(String formato, int tam) throws Exception{ byte[] datos = conectar(formato, tam); return (datos); }

En el segundo de los casos enviaremos la imagen en un array de enteros. El fundamento de esta codificación es simple: cada byte que forma la imagen puede ser representado por un número entero de 8 bits. De este modo podemos formar un array de tantos enteros como bytes tenga la imagen. El método que realiza esta conversión es el siguiente:

public int[] getImagenIntArray(String formato, int tam) throws Exception{ byte datos[] = null; int cadena[] = null; int longitud; datos = conectar(formato, tam); longitud=datos.length; // Pasamos cada byte a su valor entero correspondiente cadena = new int[longitud]; for (int i=0; i<longitud; i++) cadena[i]=(int)datos[i]; return (cadena); }

8. Escenario de pruebas

Francisco Prieto Donate 185

Con esto ya tenemos preparado el código fuente de nuestro servicio web. El siguiente paso consiste en desplegarlo, es decir, integrarlo en el servidor web Apache Tomcat y hacer públicos los métodos disponibles.

8.3.2 Despliegue del servicio web

Para desplegar el servicio que acabamos de desarrollar debemos tener el servidor de aplicaciones Apache Tomcat con el módulo Axis correctamente instalado y configurado. Los pasos necesarios para llegar a este punto se explican detalladamente en el capítulo “ Guía de instalación” .

El PC en el que se realiza la instalación debe tener acceso a Internet, pues será el encargado de recibir y enviar las peticiones al teléfono móvil. Además es recomendable que Tomcat se ejecute en la misma máquina que el servidor de vídeo, aunque no es obligatorio. En este proyecto utilizaremos el mismo PC para implementar ambos servidores.

Una vez arrancado el servidor Apache Tomcat accedemos a la carpeta contenedora de servicios web XML, situada en la ruta C:\Tomcat 4.1\webapps\axis\WEB-INF\classes. Creamos aquí un directorio llamado ServVideoKsoap destinado a contener la clase del servicio web, así como la información de despliegue necesaria para la publicación. Dentro de este directorio ubicaremos los siguientes archivos:

• VideoKsoap.java: Clase que contiene el servicio web detallado anteriormente.

• deploy.wsdd: Archivo de despliegue del servicio web. Contiene la información necesaria para que el servidor de aplicaciones Apache Tomcat sepa cómo ejecutar y publicar el servicio web. En este documento XML se especifica el nombre con el que publicará el servicio (en nuestro caso VideoKsoap), el estilo de codificación de la petición (para kSOAP es obligatorio usar el estilo RPC), el espacio de nombres utilizado en los mensajes de petición/respuesta, la clase que implementa el servicio y por último, los métodos públicos que van a estar disponibles para realizar peticiones.

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="VideoKsoap" provider="java:RPC"> <parameter name="wsdlTargetNamespace" value="http://video.samples/"/> <parameter name="className" value="ServVideoKsoap.VideoKsoap"/>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

186 Francisco Prieto Donate

<parameter name="allowedMethods" value="getImagenBase64 getImagenIntArray"/> </service> </deployment>

• undeploy.wsdd: Archivo que elimina el despliegue del servicio web. Contiene la información necesaria para que el servidor de aplicaciones deje de publicar el servicio web. Este documento XML simplemente contiene el nombre del servicio web que se quiere dejar de publicar.

<undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="VideoKsoap"/> </undeployment>

Tras ubicar estos tres archivos en el directorio especificado, compilamos el archivo java:

javac VideoKsoap.java

A continuación realizamos el despliegue del servicio escribiendo en el intérprete de comandos:

java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService deploy.wsdd

Llegados a este punto es recomendable reiniciar el servidor Apache Tomcat para que todos los cambios se apliquen correctamente. Podemos comprobar que el servicio web ya está disponible accediendo a la página web de servicios desplegados que ofrece Axis en la dirección: http://127.0.0.1:8080/axis/servlet/AxisServlet

En la figura siguiente se puede apreciar que además de los nombres de los servicios desplegados, aparecen los métodos que cada uno publica, así como un enlace al documento WSDL generado automáticamente por el servidor.

El documento WSDL es el que indica los métodos a través de los cuales se puede invocar el servici web, así como los parámetros que se necesitan para la petición y los que se devuelven como resultado. Este documento se utiliza sobre todo en programas que generan automáticamente un cliente de servicios web a partir del WSDL dado.

8. Escenario de pruebas

Francisco Prieto Donate 187

Figura 8.2: Servicios web desplegados en Axis

Figura 8.3: Parte del documento WSDL generado automáticamente por Axis

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

188 Francisco Prieto Donate

8.3.3 Desarrollo del cliente

El cliente de nuestro servicio web XML será un programa Java especialmente diseñado para dispositivos móviles utilizando J2ME. Su objetivo es el de realizar peticiones al servidor web XML a través de Internet mediante una conexión GPRS. Tras realizar la petición, el cliente queda a la espera de recibir una imagen como respuesta, la cual imprimirá por pantalla inmediatamente después de descodificarla. Mientras no se indique lo contrario, se realizarán peticiones indefinidamente con el fin de recibir una secuencia continua de imágenes, de modo que la representación por pantalla de dicha secuencia ofrezca al usuario una sensación de movimiento.

El cliente está formado por seis clases y la librería ksoap2, que ofrece el soporte de Servicios Web XML, abstrayéndonos de la construcción de mensajes SOAP y de la representación de la información en XML.

Detallamos a continuación cada una de las clases utilizadas:

• Bienvenida.java: Contiene una clase que presenta por pantalla un mensaje de bienvenida. Esta pantalla se visualizará nada más iniciarse el programa. El método constructor inicia las variables:

public Bienvenida() { // Tipo de fuente utilizado fuente = null; // Texto de presentacion cadena1 = "PFC: Cliente J2ME"; cadena2 = "Versión kSOAP"; cadena3 = "Autor: F. Prieto"; cadena4 = "Tutor: A. Sierra"; // Altura y anchura de la pantalla del dispositivo CanvasWidth = getWidth(); CanvasHeight = getHeight(); }

Por su parte, el método paint representa por pantalla las cadenas de caracteres definidas anteriormente. Como se trata de una pantalla Canvas, es necesario especificar el punto exacto donde se deben ubicar cada una de las líneas de texto:

public void paint(Graphics g) { // Tipo de letra negrita y tamaño medio

8. Escenario de pruebas

Francisco Prieto Donate 189

fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); g.setFont(fuente); // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Escribimos las lineas de texto en negro centradas en la pantalla g.setColor(0); int x = CanvasWidth / 2; int y = CanvasHeight / 2 - 2*fuente.getHeight(); g.drawString(cadena1, x, y, Graphics.TOP|Graphics.HCENTER); g.drawString(cadena2, x, y+fuente.getHeight(), Graphics.TOP|Graphics.HCENTER); // Tipo de letra pequeña fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); g.setFont(fuente); g.drawString(cadena3, x, y+(3*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); g.drawString(cadena4, x, y+(4*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); }

• ClienteVideo.java: Ésta es la clase principal del Midlet, ya que implementa los métodos startApp, pauseApp y desproyApp. En esta clase definimos todas las pantallas tipo Screen, destinadas a recopilar la información de usuario.

El método startApp es el que se encarga de inicializar los comandos (botones) y variables, y representar la primera pantalla de usuario, en este caso la pantalla de bienvenida:

public void startApp() { /* Inicializamos los comandos */ okToFormDireccion = new Command("Cont", Command.OK, 1); okToListCodificacion = new Command("Cont", Command.OK, 0); okToImagen = new Command("Cont", Command.OK, 1); backToBienvenida = new Command("Atras", Command.BACK, 1); backToFormDireccion = new Command("Atras", Command.BACK, 1); backToListCodificacion = new Command("Atras", Command.BACK, 1); backToListFormato = new Command("Atras", Command.BACK, 1); exitCommand = new Command("Salir", Command.EXIT, 1); /* Inicializamos las variables */ ip = "127.0.0.1"; puerto = "8080"; fin=false;

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

190 Francisco Prieto Donate

pantallaImagen=null; /* Presentamos la pantalla de bienvenida */ display = Display.getDisplay(this); display.setCurrent(get_bienvenida()); }

Los siguientes métodos inicializan cada una de las pantallas en las que se pedirá información de usuario, como por ejemplo la dirección y puerto del servidor, el formato de la imagen o la codificación a utilizar. La información se recopila mediante listas, formularios y cuadros de texto:

/* Pantalla en la que se elige la direccion IP y el puerto del servidor */ public Form get_formDireccion() { if (formDireccion == null) { textFieldIP = new TextField("Direccion IP: ", ip, 15, TextField.ANY); textFieldPuerto = new TextField("Puerto: ", puerto, 5, TextField.NUMERIC); formDireccion = new Form("Direccion", new Item[] { textFieldIP, textFieldPuerto }); formDireccion.addCommand(okToListCodificacion); formDireccion.addCommand(backToBienvenida); formDireccion.setCommandListener(this); } return formDireccion; } /* Pantalla en la que se elige la codificacion de la imagen. * Se puede elegien entre Base64 y array de enteros */ public List get_listCodificacion() { if (listCodificacion == null) { listCodificacion = new List("Codificacion", Choice.IMPLICIT, new String[] { "Base64", "IntArray"}, null); listCodificacion.addCommand(backToFormDireccion); listCodificacion.setCommandListener(this); } return listCodificacion; } /* Pantalla en la que se elige el formato de la imagen (png o jpg) */ public List get_listFormato() { if (listFormato == null) { listFormato = new List("Formato de imagen", Choice.IMPLICIT, new String[] { "PNG", "JPG" }, null); listFormato.addCommand(backToListCodificacion); listFormato.setCommandListener(this); } return listFormato; }

8. Escenario de pruebas

Francisco Prieto Donate 191

/* Pantalla de resumen con todas las opciones elegidas */ public Form get_formResumen() { stringResumen = new StringItem("","Serv: " + ip + ":" + puerto + "\n" + "Codif: " + codificacion + "\n" + "Formato: " + formato); formResumen = new Form("Preferencias"); formResumen.append(stringResumen); formResumen.addCommand(okToImagen); formResumen.addCommand(backToListFormato); formResumen.setCommandListener(this); return formResumen; }

A continuación inicializamos las pantallas tipo Canvas, añadiéndole los botones o comandos:

/* Pantalla de bienvenida */ public Bienvenida get_bienvenida() { if (pantallaBienvenida == null) { pantallaBienvenida = new Bienvenida(); pantallaBienvenida.addCommand(okToFormDireccion); pantallaBienvenida.addCommand(exitCommand); pantallaBienvenida.setCommandListener(this); } return pantallaBienvenida; } /* Pantalla que presentará las imágenes */ public Imagen get_Imagen() { if (pantallaImagen == null) { pantallaImagen = new Imagen(); pantallaImagen.addCommand(exitCommand); pantallaImagen.setCommandListener(this); } return pantallaImagen; }

Las acciones que se realizarán al ejecutar un comando deben definirse dentro del método CommandAction:

/* Acciones que se ejecutaran al activar un comando */ public void commandAction(Command command, Displayable displayable) { if (command == okToFormDireccion) { display.setCurrent(get_formDireccion()); } else if (command == okToListCodificacion) { ip = textFieldIP.getString(); puerto = textFieldPuerto.getString(); display.setCurrent(get_listCodificacion()); }

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

192 Francisco Prieto Donate

else if (command == okToImagen) { display.setCurrent(get_Imagen()); (new Bucle()).start(); } else if (command == backToBienvenida) { display.setCurrent(get_bienvenida()); } else if (command == backToListCodificacion) { display.setCurrent(get_listCodificacion()); } else if (command == backToListFormato) { display.setCurrent(get_listFormato()); } else if (command == backToFormDireccion) { display.setCurrent(get_formDireccion()); } else if (displayable == listCodificacion && command == listCodificacion.SELECT_COMMAND) { switch (get_listCodificacion().getSelectedIndex()) { case 0: codificacion = "Base64"; display.setCurrent(get_listFormato()); break; case 1: codificacion = "IntArray"; display.setCurrent(get_listFormato()); break; } } else if (displayable == listFormato && command == listFormato.SELECT_COMMAND) { switch (get_listFormato().getSelectedIndex()) { case 0: formato = "png"; display.setCurrent(get_formResumen()); break; case 1: formato = "jpg"; display.setCurrent(get_formResumen()); break; } } else if (command == exitCommand) { exitMIDlet(); } }

8. Escenario de pruebas

Francisco Prieto Donate 193

Por último indicamos las acciones necesarias a realizar al salir del Midlet, tales como liberación de memoria:

/* Acciones que se ejecutarán al terminar la aplicación */ public void exitMIDlet() { display.setCurrent(null); fin = true; destroyApp(true); notifyDestroyed(); } public void pauseApp() { } public void destroyApp(boolean unconditional) { }

• Bucle.java: Tras la última pantalla de petición de datos, el Midlet ejecuta un bucle de peticiones al servidor web XML y tras recoger la imagen devuelta, utiliza la clase Imagen para representarla por pantalla. El métdo que realiza todo este proceso es el método run:

public void run() { try{ do { // Dormimos entre peticiones do sleep(intervalo); while(Imagen.cerrojo || kSOAP.capturando); // Petición al servicio web kSOAP peticion = new kSOAP(); Imagen.datos = peticion.CapturaImagen(direccion); // Presentación por pantalla if (Imagen.datos != null) ClienteVideo.pantallaImagen.repaint(); else ClienteVideo.fin=true; } while (ClienteVideo.fin == false); } catch (InterruptedException e) { Alert a = new Alert("Error ", e.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); } }

• kSOAP.java: Esta clase realiza la petición al servidor web con los parámetros que se le han pedido al usuario en las pantallas anteriores.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

194 Francisco Prieto Donate

Primero debemos crear el sobre SOAP, y posteriormente se crea el objeto SOAP que se enviará a través de la red. Tras recibir la imagen, distinguimos el tipo de codificación: si ésta es Base64, devolvemos el array de bytes directamente, en caso contrario debemos pasar el array de enteros a un array de bytes. El método CapturaImagen es el que realiza todas estas operaciones:

byte[] CapturaImagen(String direccion) { Image foto = null; DataInputStream dis = null; byte data[]; try { capturando = true; Runtime.getRuntime().gc(); // Peticion al servidor web //Creamos el SOAP Envelope SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); /* Creamos el objeto SOAP, indicando el * espacio de nombres, método y parámetros */ SoapObject client = new SoapObject( "urn:video.samples", "getImagen" + ClienteVideo.codificacion); client.addProperty("formato", new String(ClienteVideo.formato)); client.addProperty("tam", new Integer(ClienteVideo.TAM)); // Enviamos el sobre al servidor envelope.setOutputSoapObject(client); ht = new HttpTransport(direccion); ht.call("",envelope); // Si la codificación es Base64, devolvemos el array directamente if (ClienteVideo.codificacion == "Base64"){ data = Base64.decode(envelope.getResponse().toString()); } // Si la codificación es IntArray, pasamos los enteros a bytes else { Vector resObj = new Vector(); resObj =(Vector)envelope.getResponse(); int numBytes=resObj.size(); //Transformamos los enteros a bytes y los almacenamos en un array data = new byte[numBytes]; for (int j=0;j<numBytes;j++) data [j] = (byte)Integer.parseInt(resObj.elementAt(j).toString()); }

8. Escenario de pruebas

Francisco Prieto Donate 195

capturando = false; return data; }catch(Exception exception) { Alert a = new Alert("Error E/S", exception.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); return null; } }

• Imagen.java: Clase que representa por pantalla la imagen recibida del servidor web. Si el formato es JPG, se descodifica utilizando la clase DecodificadorJPEG.

El método constructor inicializa las variables relacionadas con el tamaño de la pantalla, así como el descodificador JPG en caso de que la imagen recibida tenga ese formato:

public Imagen() { datos = null; // Calculamos el centro de la pantalla CanvasWidth = getWidth(); CanvasHeight = getHeight(); centro_x = (CanvasWidth - ClienteVideo.TAM) / 2; centro_y = (CanvasHeight - ClienteVideo.TAM) / 2; if(centro_x < 0) centro_x = 0; if(centro_y < 0) centro_y = 0; // Iniciamos la clase DecodificadorJPEG iniciaJPEG(); } void iniciaJPEG(){ if (ClienteVideo.formato == "jpg") { // Inicializo el decodificador JPEG decod = new DecodificadorJPEG(); decod.setAncho(ClienteVideo.TAM); decod.setAlto(ClienteVideo.TAM); } }

El método paint representa la imagen por pantalla. Mientras se efectúa la representación se activa un cerrojo para que el bucle no efectúe peticiones a la vez, ya que el rendimiento de la aplicación disminuye considerablemente. Si el formato es PNG se llama al método createImage incluído en J2ME que se encarga de descodificar dicho

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

196 Francisco Prieto Donate

formato. En caso contrario, si la imagen es de tipo JPG, utilizaremos la clase DecodificadorJPEG.

public void paint(Graphics g) { cerrojo = true; // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Presenta la imagen por pantalla if(datos != null){ int numBytes = datos.length; // Si el formato es png, representamos directamente if (ClienteVideo.formato != "jpg"){ foto = Image.createImage(datos,0,numBytes); } // Si el formato es jpg, utilizamos el decodificador else { // Crea el buffer ARGB para la imagen decodificada imagenARGB = new int[ClienteVideo.TAM*ClienteVideo.TAM]; // Decodifica en imagenARGB[] decod.decodifica(datos,imagenARGB, numBytes); // Creamos la imagen foto = Image.createRGBImage(imagenARGB,ClienteVideo.TAM, ClienteVideo.TAM,false); } g.drawImage(foto, centro_x, centro_y, 0); } cerrojo = false; }

• DecodificadorJPEG.java: Clase que toma un array de bytes con una imagen JPG y la descodifica para poder representarla en pantalla.

Esta clase fue desarrollada en un proyecto final de carrera anterior y no vamos a realizar su análisis detallado debido a su extensión y complejidad. El código fuente de esta clase puede consultarse en el capítulo “ Planos de código” .

8. Escenario de pruebas

Francisco Prieto Donate 197

8.3.4 Simulación del cliente

Para simular el comportamiento de un teléfono móvil real, utilizamos el emulador J2ME Wireless Toolkit 2.2. Con él podemos probar el funcionamiento del cliente, así como realizar medidas de parámetros tales como tiempos de respuesta y consumo de memoria. La instalación y configuración de este programa se detalla en el capítulo “ Guía de instalación” .

Para simular el programa que hemos desarrollado, ejecutamos el J2ME Wireless Toolkit y creamos un nuevo proyecto, al que llamaremos ClienteVideoKsoap. En la siguiente pantalla de configuración tenemos que indicar que el perfil debe ser MIDP 2.0 y la configuración CDLC 1.1. Asimismo es necesario especificar el nombre de la clase principal del Midlet, en nuestro caso cliente.ClienteVideo. Automáticamente se habrá creado un directorio con el mismo nombre del proyecto en la ruta C:\WTK22\apps. Dentro de la carpeta src creamos una a la que llamaremos cliente, que corresponde con el paquete en el que contendremos el código fuente. Es en esta carpeta donde ubicaremos los archivos java con las clases especificadas anteriormente.

A continuación situamos el paquete ksoap2-j2me-core-2.1.1.jar en el directorio lib. Este paquete, como hemos comentado anteriormente, aporta la funcionalidad SOAP al cliente, realizando las tareas necesarias para intercambiar documentos XML y realizar las peticiones al servidor. Puede descargarse desde el siguiente enlace web: http://sourceforge.net/projects/ksoap2/.

Una vez hecho esto, compilamos el proyecto con la opción Build y creamos el paquete jar precompilado accediendo al menú Project→ Package→ Create Package. Esta opción crea tres archivos en el directorio C:\WTK22\apps\ClienteVideoKsoap\bin:

• ClienteVideoKsoap.jar: Fichero que contiene todas las clases necesarias para la ejecución del cliente.

• ClienteVideoKsoap.jad: Fichero descriptor de aplicaciones Java. Se encarga de verificar que su MIDlet Suite asociado se ajusta convenientemente al dispositivo sobre el que será descargado.

• MANIFEST.MF: Contiene información sobre el cliente, como por ejemplo el nombre y tamaño de la clase principal, la versión de MIDP y CLCD, nombre del fabricante, etc.

Estos tres ficheros son los que se deben descargar a un teléfono móvil real para ejecutar la aplicación.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

198 Francisco Prieto Donate

8.3.4.1 Descarga OTA

Para la instalación del cliente en un terminal móvil vamos a utilizar el método de descarga vía OTA, aprovechando el hecho de que el servidor de vídeo es también servidor de ficheros y viene además configurado para soportar este tipo de descargas. Para alojar nuestro Midlet-Suite en el servidor es necesario realizar los siguientes pasos:

5. Crear una carpeta dentro del directorio de trabajo del servidor de vídeo y alojar allí los tres archivos que hemos obtenido. En nuestro caso, el directorio de trabajo es C:, así que creamos la carpeta C:/descarga y copiamos los ficheros mencionados.

6. Editar el archivo ClienteVideoKsoap.jad, para que la línea que contiene información sobre la URL muestre lo siguiente:

MIDlet-Jar-URL: http://127.0.0.1/descarga/ClienteVideoKsoap.jar

7. Crear una sencilla página web con el enlace al archivo jad. El archivo debe situarse en el directorio de trabajo del servidor de vídeo, y el contenido se muestra a continuación:

<html> <head> <title>Cliente Video - Descarga</title> </head> <body> <a href="http://127.0.0.1/descarga/ClienteVideoKsoap.jad">Instalar Cliente Video Ksoap</a> </body> </html>

8. Ejecutar el servidor de vídeo, ya que hasta que el servidor no comience a capturar imágenes, los archivos no van a estar disponibles para su descarga.

Para simular una descarga vía OTA, utilizamos el emulador OTA Provisioning que viene incluido en el paquete J2ME Wireless Toolkit 2.2. Al ejecutarlo, se muestran los paquetes ya instalados y la opción de instalar un nuevo paquete. Si seleccionamos esa opción pasamos a una pantalla en la que se nos pide la URL del Midlet. En nuestro caso, la dirección será: http://127.0.0.1/index.html. Tras descargarse la página web que creamos anteriormente, se visualiza por pantalla el enlace “ Instalar Cliente Video Ksoap” . Si pulsamos sobre el botón “ Install” , comenzará la descarga e instalación del Midlet. En las siguientes capturas de pantalla se muestra el proceso:

8. Escenario de pruebas

Francisco Prieto Donate 199

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

200 Francisco Prieto Donate

8.3.4.2 Ejecución del cliente

Por último ejecutamos el cliente. A continuación mostramos una captura de cada una de las pantallas que componen la interfaz de usuario.

8. Escenario de pruebas

Francisco Prieto Donate 201

8.4 Escenario JSR-172

8.4.1 Desarrollo del servicio web

El servicio web desarrollado está compuesto de una sola clase, llamada VideoJSR y cuatro métodos, dos de los cuales se utilizarán para escuchar las peticiones del cliente. Esta clase es muy parecida a la utilizada para el caso Ksoap, aunque tiene algunas variaciones. El método más importante de la clase es el llamado conectar, que realiza la

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

202 Francisco Prieto Donate

petición al servidor de vídeo especificando el formato y el tamaño de la imagen, y devuelve un array de bytes con la imagen solicitada.

public byte[] conectar(String formato, int tam) throws Exception{ InputStream is = null; DataInputStream dis = null; int len = 0; byte datos[] = null; // Hacemos la petición al servidor de vídeo URL url = new URL("http", ip, puerto, "/?format=" + formato + "?resize=" + tam + "*" + tam + "?" + getCalidad(formato)); HttpURLConnection conexion = (HttpURLConnection)url.openConnection(); int rc = conexion.getResponseCode(); if (rc != HttpURLConnection.HTTP_OK) { conexion.disconnect(); throw new Exception("Codigo de respuesta HTTP: " + rc); } // Comprobamos el tipo de archivo devuelto String tipo = conexion.getContentType(); if (!tipo.equals("image/png") && !tipo.equals("image/jpeg")) { throw new Exception("Se esperaba una imagen, " + "pero se ha recibido " + tipo); } len = conexion.getContentLength(); // Almacenamos la información recibida en un array de bytes if (len > 0) { is = conexion.getInputStream(); dis = new DataInputStream(is); datos = new byte [len]; dis.readFully(datos); } // Cerramos el flujo de entrada if (dis != null) { dis.close(); dis = null; } // Cerramos la conexión if (conexion != null) { conexion.disconnect(); conexion = null; } return datos; }

8. Escenario de pruebas

Francisco Prieto Donate 203

La petición al servidor de vídeo necesita un parámetro que le indique la calidad de la imagen. Este parámetro va a ser fijo para cada uno de los formatos, y se especifica en el método getCalidad:

public String getCalidad(String formato) { String cadena; if (formato == "jpg") cadena = "quality=50"; else if (formato == "png") cadena = "comp=max"; else cadena = ""; return cadena; }

Los dos métodos restantes son los encargados de recibir la petición por parte del cliente. La diferencia entre ambos radica en que la codificación con la cual se enviará la imagen es distinta en cada caso.

En el primer caso vamos a enviar al cliente un array de bytes con la imagen solicitada. En este escenario el módulo Axis en el lado del servidor y las librerías de la especificación JSR-172 en el lado del cliente no codifican ni descodifican automáticamente este array en formato Base64, ya que como veremos más adelante, la codificación de los mensajes intercambiados no es RPC. No obstante podemos obligar al servidor web a codificar el array de bytes en Base64, con lo que devolverá el String resultante.

public String getImagenBase64(String formato, int tam) throws Exception{ byte[] datos = conectar(formato, tam); return (Base64.encode(datos)); }

En el segundo de los casos enviaremos la imagen en un array de enteros. El fundamento de esta codificación es simple: cada byte que forma la imagen puede ser representado por un número entero de 8 bits. De este modo podemos formar un array de tantos enteros como bytes tenga la imagen. El método que realiza esta conversión es el siguiente:

public int[] getImagenIntArray(String formato, int tam) throws Exception{ byte datos[] = null; int cadena[] = null;

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

204 Francisco Prieto Donate

int longitud; datos = conectar(formato, tam); longitud=datos.length; // Pasamos cada byte a su valor entero correspondiente cadena = new int[longitud]; for (int i=0; i<longitud; i++) cadena[i]=(int)datos[i]; return (cadena); }

Con esto ya tenemos preparado el código fuente de nuestro servicio web. El siguiente paso consiste en desplegarlo, es decir, integrarlo en el servidor web Apache Tomcat y hacer públicos los métodos disponibles.

8.4.2 Despliegue del servicio web

Para desplegar el servicio que acabamos de desarrollar debemos tener el servidor de aplicaciones Apache Tomcat correctamente instalado y configurado con el módulo Axis. Los pasos necesarios para llegar a este punto se explican detalladamente en el capítulo “ Guía de instalación” . El PC en el que se realiza la instalación debe tener acceso a Internet, pues será el encargado de recibir y enviar las peticiones al teléfono móvil. Además es recomendable que Tomcat se ejecute en la misma máquina que el servidor de vídeo por motivos de rendimiento, aunque no es obligatorio. En este proyecto utilizaremos el mismo PC para implementar ambos servidores.

Una vez arrancado el servidor Apache Tomcat accedemos a la carpeta contenedora de servicios web XML, situada en la ruta C:\Tomcat 4.1\webapps\axis\WEB-INF\classes. Creamos aquí un directorio llamado ServVideoJSR destinado a contener la clase del servicio web, así como la información de despliegue necesaria para la publicación. Dentro de este directorio ubicaremos los siguientes archivos:

• VideoJSR.java: Clase que contiene el servicio web detallado anteriormente.

• deploy.wsdd: Archivo de despliegue del servicio web. Contiene la información necesaria para que el servidor de aplicaciones Apache Tomcat sepa cómo ejecutar y publicar el servicio web.

En este documento XML se especifica el nombre con el que publicará el servicio (en nuestro caso VideoJSR), el estilo de codificación de la petición (para JSR-172 es

8. Escenario de pruebas

Francisco Prieto Donate 205

obligatorio usar el estilo literal/wrapped), el espacio de nombres utilizado en los mensajes de petición/respuesta, la clase que implementa el servicio y los métodos públicos que van a estar disponibles para realizar peticiones.

Para este escenario hemos ampliado la información contenida en el documento WSDD. Se han añadido las etiquetas operation, que aportan flexibilidad a la hora de definir el servicio web que implementamos. En este caso podemos observar que hemos especificado, para cada método, los tipos de datos que se esperan recibir como parámetros en la petición, así como el tipo de parámetro devuelto en la respuesta. Otra variación con respecto a kSOAP es la utilización del estilo wrapped, único soportado por JSR-172.

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="VideoJSR" provider="java:RPC" style="wrapped" use="literal"> <parameter name="wsdlTargetNamespace" value="http://video.samples/"/> <parameter name="className" value="ServVideoJSR.VideoJSR"/> <operation name="getImagenBase64" qname="operNS:getImagenBase64" xmlns:operNS="http://video.samples/" returnQName="retNS:getImagenBase64Result" xmlns:retNS="http://video.samples/" returnType="rtns:string" xmlns:rtns="http://www.w3.org/2001/XMLSchema" > <parameter qname="pns:formato" xmlns:pns="http://video.samples/" type="tns:string" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> <parameter qname="pns:tam" xmlns:pns="http://video.samples/" type="tns:int" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> </operation> <operation name="getImagenIntArray" qname="operNS:getImagenIntArray" xmlns:operNS="http://video.samples/" returnQName="retNS:getImagenIntArrayResult" xmlns:retNS="http://video.samples/" returnType="rtns:int[]" xmlns:rtns="http://www.w3.org/2001/XMLSchema" > <parameter qname="pns:formato" xmlns:pns="http://video.samples/" type="tns:string" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> <parameter qname="pns:tam" xmlns:pns="http://video.samples/" type="tns:int" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> </operation> <parameter name="allowedMethods" value="getImagenBase64 getImagenIntArray"/>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

206 Francisco Prieto Donate

</service> </deployment>

• undeploy.wsdd: Archivo que elimina el despliegue del servicio web. Contiene la información necesaria para que el servidor de aplicaciones deje de publicar el servicio web. Este documento XML simplemente contiene el nombre del servicio web que se quiere dejar de publicar.

<undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="VideoJSR"/> </undeployment>

Tras ubicar estos tres archivos en el directorio especificado, compilamos el archivo java:

javac VideoJSR.java

A continuación realizamos el despliegue del servicio escribiendo en el intérprete de comandos:

java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService deploy.wsdd

Llegados a este punto es recomendable reiniciar el servidor Apache Tomcat para que todos los cambios se apliquen correctamente. Podemos comprobar que el servicio web ya está disponible accediendo a la página web de servicios desplegados que ofrece Axis en la dirección: http://127.0.0.1:8080/axis/servlet/AxisServlet

En la figura siguiente se puede apreciar que además de los nombres de los servicios desplegados, aparecen los métodos que cada uno publica, así como un enlace al documento WSDL generado automáticamente por el servidor.

El documento WSDL es el que indica los métodos a través de los cuales se puede invocar el servici web, así como los parámetros que se necesitan para la petición y los que se devuelven como resultado. Este documento se utiliza sobre todo en programas que generan automáticamente un cliente de servicios web a partir del WSDL dado.

8. Escenario de pruebas

Francisco Prieto Donate 207

Figura 8.4: Servicios web desplegados en Axis

Figura 8.5: Parte del documento WSDL generado automáticamente por Axis

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

208 Francisco Prieto Donate

8.4.3 Desarrollo del cliente

El cliente de nuestro servicio web XML será un programa Java especialmente diseñado para dispositivos móviles utilizando J2ME. Su objetivo es el de realizar peticiones al servidor web XML a través de Internet mediante una conexión GPRS. Tras realizar la petición, el cliente queda a la espera de recibir una imagen como respuesta, la cual imprimirá por pantalla inmediatamente después de descodificarla. Mientras no se indique lo contrario, se realizarán peticiones indefinidamente con el fin de recibir una secuencia continua de imágenes, de modo que la representación por pantalla de dicha secuencia ofrezca al usuario una sensación de movimiento.

El cliente está formado por seis clases que conforman el programa principal y seis clases más que forman parte del stub, ofreciendo el soporte de Servicios Web XML y abstrayéndonos de la construcción de mensajes SOAP y de la representación de la información en XML.

Detallamos a continuación cada una de las clases utilizadas:

• Bienvenida.java: Contiene una clase que presenta por pantalla un mensaje de bienvenida. Esta pantalla se visualizará nada más iniciarse el programa. El método constructor inicia las variables:

public Bienvenida() { // Tipo de fuente utilizado fuente = null; // Texto de presentacion cadena1 = "PFC: Cliente J2ME"; cadena2 = "Versión JSR-172"; cadena3 = "Autor: F. Prieto"; cadena4 = "Tutor: A. Sierra"; // Altura y anchura de la pantalla del dispositivo CanvasWidth = getWidth(); CanvasHeight = getHeight(); }

Por su parte, el método paint representa por pantalla las cadenas de caracteres definidas anteriormente. Como se trata de una pantalla Canvas, es necesario especificar el punto exacto donde se deben ubicar cada una de las líneas de texto:

public void paint(Graphics g) { // Tipo de letra negrita y tamaño medio

8. Escenario de pruebas

Francisco Prieto Donate 209

fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); g.setFont(fuente); // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Escribimos las lineas de texto en negro centradas en la pantalla g.setColor(0); int x = CanvasWidth / 2; int y = CanvasHeight / 2 - 2*fuente.getHeight(); g.drawString(cadena1, x, y, Graphics.TOP|Graphics.HCENTER); g.drawString(cadena2, x, y+fuente.getHeight(), Graphics.TOP|Graphics.HCENTER); // Tipo de letra pequeña fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); g.setFont(fuente); g.drawString(cadena3, x, y+(3*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); g.drawString(cadena4, x, y+(4*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); }

• ClienteVideo.java: Ésta es la clase principal del Midlet, ya que implementa los métodos startApp, pauseApp y desproyApp. En esta clase definimos todas las pantallas tipo Screen, destinadas a recopilar la información de usuario.

El método startApp es el que se encarga de inicializar los comandos (botones) y variables, y representar la primera pantalla de usuario, en este caso la pantalla de bienvenida:

public void startApp() { /* Inicializamos los comandos */ okToListCodificacion = new Command("Cont", Command.OK, 0); okToImagen = new Command("Cont", Command.OK, 1); backToBienvenida = new Command("Atras", Command.BACK, 1); backToListCodificacion = new Command("Atras", Command.BACK, 1); backToListFormato = new Command("Atras", Command.BACK, 1); exitCommand = new Command("Salir", Command.EXIT, 1); /* Inicializamos las variables */ fin=false; pantallaImagen=null; /* Presentamos la pantalla de bienvenida */ display = Display.getDisplay(this);

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

210 Francisco Prieto Donate

display.setCurrent(get_bienvenida()); }

Los siguientes métodos inicializan cada una de las pantallas en las que se pedirá información de usuario, como por ejemplo el formato de la imagen o la codificación a utilizar. En este escenario el usuario no puede elegir la dirección ni el puerto del servidor, ya que el stub contiene esta información y no puede ser modificada en tiempo de ejecución. La información se recopila mediante listas, formularios y cuadros de texto:

/* Pantalla en la que se elige la codificacion de la imagen. * Se puede elegien entre Base64 y array de enteros */ public List get_listCodificacion() { if (listCodificacion == null) { listCodificacion = new List("Codificacion", Choice.IMPLICIT, new String[] { "Base64", "IntArray"}, null); listCodificacion.addCommand(backToBienvenida); listCodificacion.setCommandListener(this); } return listCodificacion; } /* Pantalla en la que se elige el formato de la imagen (png o jpg) */ public List get_listFormato() { if (listFormato == null) { listFormato = new List("Formato de imagen", Choice.IMPLICIT, new String[] { "PNG", "JPG" }, null); listFormato.addCommand(backToListCodificacion); listFormato.setCommandListener(this); } return listFormato; } /* Pantalla de resumen con todas las opciones elegidas */ public Form get_formResumen() { stringResumen = new StringItem("", "Codif: " + codificacion + "\n" + "Formato: " + formato); formResumen = new Form("Preferencias"); formResumen.append(stringResumen); formResumen.addCommand(okToImagen); formResumen.addCommand(backToListFormato); formResumen.setCommandListener(this); return formResumen; }

A continuación inicializamos las pantallas tipo Canvas, añadiéndole los botones o comandos:

8. Escenario de pruebas

Francisco Prieto Donate 211

/* Pantalla de bienvenida */ public Bienvenida get_bienvenida() { if (pantallaBienvenida == null) { pantallaBienvenida = new Bienvenida(); pantallaBienvenida.addCommand(okToListCodificacion); pantallaBienvenida.addCommand(exitCommand); pantallaBienvenida.setCommandListener(this); } return pantallaBienvenida; } /* Pantalla que presentará las imágenes */ public Imagen get_Imagen() { if (pantallaImagen == null) { pantallaImagen = new Imagen(); pantallaImagen.addCommand(exitCommand); pantallaImagen.setCommandListener(this); } return pantallaImagen; }

Las acciones que se realizarán al ejecutar un comando deben definirse dentro del método CommandAction:

/* Acciones que se ejecutaran al activar un comando */ public void commandAction(Command command, Displayable displayable) { if (command == okToListCodificacion) { display.setCurrent(get_listCodificacion()); } else if (command == okToImagen) { display.setCurrent(get_Imagen()); (new Bucle()).start(); } else if (command == backToBienvenida) { display.setCurrent(get_bienvenida()); } else if (command == backToListCodificacion) { display.setCurrent(get_listCodificacion()); } else if (command == backToListFormato) { display.setCurrent(get_listFormato()); } else if (displayable == listCodificacion && command == listCodificacion.SELECT_COMMAND) { switch (get_listCodificacion().getSelectedIndex()) { case 0: codificacion = "Base64"; display.setCurrent(get_listFormato());

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

212 Francisco Prieto Donate

break; case 1: codificacion = "IntArray"; display.setCurrent(get_listFormato()); break; } } else if (displayable == listFormato && command == listFormato.SELECT_COMMAND) { switch (get_listFormato().getSelectedIndex()) { case 0: formato = "png"; display.setCurrent(get_formResumen()); break; case 1: formato = "jpg"; display.setCurrent(get_formResumen()); break; } } else if (command == exitCommand) { exitMIDlet(); } }

Por último indicamos las acciones necesarias a realizar al salir del Midlet, tales como liberación de memoria:

/* Acciones que se ejecutarán al terminar la aplicación */ public void exitMIDlet() { display.setCurrent(null); fin = true; destroyApp(true); notifyDestroyed(); } public void pauseApp() { } public void destroyApp(boolean unconditional) { }

• Bucle.java: Tras la última pantalla de petición de datos, el Midlet ejecuta un bucle de peticiones al servidor web XML y tras recoger la imagen devuelta, utiliza la clase Imagen para representarla por pantalla. El métdo que realiza todo este proceso es el método run:

public void run() { try{ do {

8. Escenario de pruebas

Francisco Prieto Donate 213

// Dormimos entre peticiones do sleep(intervalo); while(Imagen.cerrojo || JSR172.capturando); // Petición al servicio web JSR172 peticion = new JSR172(); Imagen.datos = peticion.CapturaImagen(); // Presentación por pantalla if (Imagen.datos != null) ClienteVideo.pantallaImagen.repaint(); else ClienteVideo.fin=true; } while (ClienteVideo.fin == false); } catch (InterruptedException e) { Alert a = new Alert("Error ", e.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); } }

• JSR172.java: Esta clase realiza la petición al servidor web con los parámetros que se le han pedido al usuario en las pantallas anteriores. Gracias al stub, realizar una petición a un servicio web remoto es exactamente igual que invocar a un método local.

Tras recibir la imagen, distinguimos el tipo de codificación: si ésta es Base64, descodificamos el String recibido en el array de bytes original ayudándonos de una librería externa. En caso contrario debemos pasar el array de enteros a un array de bytes. El método CapturaImagen es el que realiza todas estas operaciones:

byte[] CapturaImagen() { Image foto = null; DataInputStream dis = null; byte data[]; try { capturando = true; Runtime.getRuntime().gc(); // Peticion al servidor web // Si la codificación es Base64, pasamos el String a array de bytes if (ClienteVideo.codificacion == "Base64"){ /* Hacemos la petición al servidor web invocando * el método correspondiente del stub */

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

214 Francisco Prieto Donate

String cadena = proxy_VideoJSR_Stub.getImagenBase64(ClienteVideo.formato,ClienteVideo.TAM); /* JSR-172 no codifica los arrays de bytes a Base64, * de modo que tenemos que forzar la decodificación */ data = Base64.decode(cadena); } // Si la codificación es IntArray, pasamos los enteros a bytes else { /* Hacemos la petición al servidor web invocando * el método correspondiente del stub */ int cadena[] = proxy_VideoJSR_Stub.getImagenIntArray(ClienteVideo.formato,ClienteVideo.TAM); int numBytes = cadena.length; //Transformamos los enteros a bytes y los almacenamos en un array data = new byte[numBytes]; for (int j=0;j<numBytes;j++) data [j] = (byte)cadena[j]; } capturando = false; return data; }catch(Exception exception) { Alert a = new Alert("Error E/S", exception.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); return null; } }

• Imagen.java: Clase que representa por pantalla la imagen recibida del servidor web. Si el formato es JPG, se descodifica utilizando la clase DecodificadorJPEG.

El método constructor inicializa las variables relacionadas con el tamaño de la pantalla, así como el descodificador JPG en caso de que la imagen recibida tenga ese formato:

public Imagen() { datos = null; // Calculamos el centro de la pantalla CanvasWidth = getWidth(); CanvasHeight = getHeight();

8. Escenario de pruebas

Francisco Prieto Donate 215

centro_x = (CanvasWidth - ClienteVideo.TAM) / 2; centro_y = (CanvasHeight - ClienteVideo.TAM) / 2; if(centro_x < 0) centro_x = 0; if(centro_y < 0) centro_y = 0; // Iniciamos la clase DecodificadorJPEG iniciaJPEG(); } void iniciaJPEG(){ if (ClienteVideo.formato == "jpg") { // Inicializo el decodificador JPEG decod = new DecodificadorJPEG(); decod.setAncho(ClienteVideo.TAM); decod.setAlto(ClienteVideo.TAM); } }

El método paint representa la imagen por pantalla. Mientras se efectúa la representación se activa un cerrojo para que el bucle no efectúe peticiones a la vez, ya que el rendimiento de la aplicación disminuye considerablemente. Si el formato es PNG se llama al método createImage incluído en J2ME que se encarga de descodificar dicho formato. En caso contrario, si la imagen es de tipo JPG, utilizaremos la clase DecodificadorJPEG.

public void paint(Graphics g) { cerrojo = true; // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Presenta la imagen por pantalla if(datos != null){ int numBytes = datos.length; // Si el formato es png, representamos directamente if (ClienteVideo.formato != "jpg"){ foto = Image.createImage(datos,0,numBytes); } // Si el formato es jpg, utilizamos el decodificador else { // Crea el buffer ARGB para la imagen decodificada imagenARGB = new int[ClienteVideo.TAM*ClienteVideo.TAM]; // Decodifica en imagenARGB[] decod.decodifica(datos,imagenARGB, numBytes); // Creamos la imagen

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

216 Francisco Prieto Donate

foto = Image.createRGBImage(imagenARGB,ClienteVideo.TAM, ClienteVideo.TAM,false); } g.drawImage(foto, centro_x, centro_y, 0); } cerrojo = false; }

• DecodificadorJPEG.java: Clase que toma un array de bytes con una imagen JPG y la descodifica para poder representarla en pantalla.

Esta clase fue desarrollada en un proyecto final de carrera anterior y no vamos a realizar su análisis detallado debido a su extensión y complejidad. El código fuente de esta clase puede consultarse en el capítulo “ Planos de código” .

• Stub: El stub es un conjunto de clases generadas automáticamente a partir del documento WSDL proporcionado por el servidor web, y cuyo objetivo es el de abstraer al programador del cliente tanto de la conexión con el servidor web como de la comunicación entre éste y el cliente.

La generación del stub es muy sencilla. Utilizaremos la utilidad “ Stub Generator” incluida en el J2ME Wireless Toolkit 2.2 de Sun. Una vez ejecutada se nos piden 4 parámetros:

� URL del documento WSDL

En nuestro caso, http://127.0.0.1:8080/axis/services/VideoJSR?wsdl

� Ruta de salida

Aquí especificaremos C:\WTK22\apps\ClienteVideoJSR\src\cliente

� Paquete de salida

Indicaremos “ Stub”

� Configuración

8. Escenario de pruebas

Francisco Prieto Donate 217

Elegimos “ CLDC 1.1”

Una vez hecho esto, se creará un paquete en la ruta especificada que contiene las seis clases que conforman el stub.

8.4.4 Simulación del cliente

Para simular el comportamiento de un teléfono móvil real, utilizamos el emulador J2ME Wireless Toolkit 2.2. Con él podemos probar el funcionamiento del cliente, así como realizar medidas de parámetros tales como tiempos de respuesta y consumo de memoria. La instalación y configuración de este programa se detalla en el capítulo “ Guía de instalación” .

Para simular el programa que hemos desarrollado, ejecutamos el J2ME Wireless Toolkit y creamos un nuevo proyecto, al que llamaremos ClienteVideoJSR. En la siguiente pantalla de configuración tenemos que indicar que el perfil debe ser MIDP 2.0 y la configuración CDLC 1.1. Asimismo es necesario especificar el nombre de la clase principal del Midlet, en nuestro caso cliente.ClienteVideo, e indicar que se añadan las librerías JSR-172. Automáticamente se habrá creado un directorio con el mismo nombre del proyecto en la ruta C:\WTK22\apps. Dentro de la carpeta src creamos una llamada cliente, que corresponde con el paquete en el que contendremos el código fuente. Es en esta carpeta donde ubicaremos los archivos java con las clases especificadas anteriormente.

A continuación situamos el paquete ksoap2-j2me-core-2.1.1.jar en el directorio lib. Aunque para JSR-172 no es necesario, este paquete nos permite descodificar un String Base64 en un array de bytes. Puede descargarse desde el siguiente enlace web: http://sourceforge.net/projects/ksoap2/.

Una vez hecho esto, compilamos el proyecto con la opción Build y creamos el paquete jar precompilado accediendo al menú Project→ Package→ Create Package. Esta opción crea tres archivos en el directorio C:\WTK22\apps\ClienteVideoJSR\bin:

• ClienteVideoJSR.jar: Fichero que contiene todas las clases necesarias para la ejecución del cliente.

• ClienteVideoJSR.jad: Fichero descriptor de aplicaciones Java. Se encarga de verificar que su MIDlet Suite asociado se ajusta convenientemente al dispositivo sobre el que será descargado.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

218 Francisco Prieto Donate

• MANIFEST.MF: Contiene información sobre el cliente, como por ejemplo el nombre y tamaño de la clase principal, la versión de MIDP y CLCD, nombre del fabricante, etc.

Estos tres ficheros son los que se deben descargar a un teléfono móvil real para ejecutar la aplicación.

8.4.4.1 Descarga OTA

Para la instalación del cliente en un terminal móvil vamos a utilizar el método de descarga vía OTA, aprovechando el hecho de que el servidor de vídeo es también servidor de ficheros y viene además configurado para soportar este tipo de descargas. Para alojar nuestro Midlet-Suite en el servidor es necesario realizar los siguientes pasos:

1. Crear una carpeta dentro del directorio de trabajo del servidor de vídeo y alojar allí los tres archivos que hemos obtenido. En nuestro caso, el directorio de trabajo es C:, así que creamos la carpeta C:/descarga y copiamos los ficheros mencionados.

2. Editar el archivo ClienteVideoJSR.jad, para que la línea que contiene información sobre la URL muestre lo siguiente:

MIDlet-Jar-URL: http://127.0.0.1/descarga/ClienteVideoJSR.jar

3. Crear una sencilla página web con el enlace al archivo jad. El archivo debe situarse en el directorio de trabajo del servidor de vídeo, y el contenido se muestra a continuación:

<html> <head> <title>Cliente Video - Descarga</title> </head> <body> <a href="http://127.0.0.1/descarga/ClienteVideoJSR.jad">Instalar Cliente Video JSR</a> </body> </html>

4. Ejecutar el servidor de vídeo, ya que hasta que el servidor no comience a capturar imágenes, los archivos no van a estar disponibles para su descarga.

8. Escenario de pruebas

Francisco Prieto Donate 219

Para simular una descarga vía OTA, utilizamos el emulador OTA Provisioning que viene incluido en el paquete J2ME Wireless Toolkit 2.2. Al ejecutarlo, se muestran los paquetes ya instalados y la opción de instalar un nuevo paquete. Si seleccionamos esa opción pasamos a una pantalla en la que se nos pide la URL del Midlet. En nuestro caso, la dirección será: http://127.0.0.1/index.html. Tras descargarse la página web que creamos anteriormente, se visualiza por pantalla el enlace “ Instalar Cliente Video JSR” . Si pulsamos sobre el botón “ Install” , comenzará la descarga e instalación del Midlet.

En las siguientes capturas de pantalla se muestra el proceso:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

220 Francisco Prieto Donate

8.4.4.2 Ejecución del cliente

Por último ejecutamos el cliente. A continuación mostramos una captura de cada una de las pantallas que componen la interfaz de usuario. Se puede apreciar la ausencia de la pantalla que pedía en kSOAP la dirección y el puerto del servidor.

8. Escenario de pruebas

Francisco Prieto Donate 221

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

222 Francisco Prieto Donate

8.5 Consideraciones finales

En este capítulo hemos desarrollado un escenario que nos permite simular la utilización de un teléfono móvil para recibir imágenes de vídeo a través de servicios web.

Una vez que hemos probado que el software funciona adecuadamente y que la comunicación entre el cliente, el servidor web XML y el servidor de vídeo es correcta, podemos pasar a realizar la batería de pruebas que nos aportarán la información necesaria para valorar el rendimiento que ofrece esta implementación.

9. Pruebas y resultados

Francisco Prieto Donate 223

9 PRUEBAS Y RESULTADOS

9.1 Introducción a las pruebas

Las pruebas realizadas están diseñadas para obtener información detallada acerca de:

• Las diferencias entre las tecnologías kSOAP y JSR-172 en cuanto a la estructura de los mensajes enviados y recibidos, tiempo de tratamiento de la información y consumo de memoria del dispositivo móvil.

• Comparación de los formatos de imagen JPG y PNG respecto a la relación calidad - tiempo de respuesta.

• Comparación de la codificación de la información utilizada automáticamente por el protocolo SOAP con una codificación creada por nosotros mismos, para demostrar cuál ofrece mejor rendimiento en tiempo y consumo de memoria.

Para ello vamos a realizar las siguientes pruebas en cada uno de los escenarios definidos. Las pruebas consisten en ejecutar el cliente, elegir una codificación, elegir un formato y recibir un número determinado de imágenes:

Para la codificación Base64, se recibirán 10 imágenes seguidas de tamaño 80x80 píxeles y se cerrará el cliente. Tras ello calcularemos el tiempo medio entre imágenes y el consumo en memoria en tres momentos de la ejecución del cliente (al inicio, tras representar la primera imagen y tras representar la segunda imagen) con la utilidad Memory Monitor que incluye J2ME Wireless Toolkit. Asimismo capturaremos las peticiones en el nivel de enlace para analizar el formato de los mensajes transmitidos y calcular así el aumento de información que introduce el protocolo SOAP.

Para la codificación Array de enteros, se recibirán dos imágenes de 80x80 píxeles y se cerrará el cliente. Calcularemos el tiempo medio entre imágenes y hallaremos el consumo de memoria en los mismos tres momentos de la ejecución que en el caso anterior (al inicio, tras representar la primera imagen y tras representar la segunda imagen). Al igual que con la codificación anterior, capturaremos las peticiones en el nivel de enlace para analizar el formato de los mensajes transmitidos y el tamaño de los datos enviados.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

224 Francisco Prieto Donate

9.2 Escenario kSOAP

9.2.1 Codificación Base64

En la siguiente tabla adjuntamos información, para cada uno de los formatos, del tamaño medio del archivo enviado, tiempo medio entre imágenes, y consumo de memoria en tres momentos distintos de la ejecución del cliente.

Tamaño medio de la imagen

(Kb)

Información enviada por el servidor

(Kb)

Tiempo medio entre

imágenes (s)

Consumo de

memoria al inicio

(Kb)

Consumo de

memoria tras la 1ª imagen

(Kb)

Consumo de

memoria tras la 2ª imagen

(Kb)

JPG 1,76 2,95 4,52 103,86 268,86 315,98

PNG 13,57 25,73 12,68 103,86 355,43 401,37

Tabla 9.1: Resultados para el escenario kSOAP con Base64

A continuación mostramos el formato de los mensajes de petición y respuesta intercambiados por el cliente y el servidor. Mostramos exclusivamente los mensajes para el caso JPG, ya que para el caso PNG los mensajes son idénticos salvo por la longitud de la cadena de texto que contiene la imagen codificada.

• Petición del cliente

POST /axis/services/VideoKsoap HTTP/1.1 SOAPAction: Content-Type: text/xml Content-Length: 412 User-Agent: kSOAP/2.0 User-Agent: UNTRUSTED/1.0 Host: 127.0.0.1:8080

9. Pruebas y resultados

Francisco Prieto Donate 225

<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><n0:getImagenBase64 id="o0" c:root="1" xmlns:n0="urn:video.samples"><formato i:type="d:string">jpg</formato><tam i:type="d:int">80</tam></n0:getImagenBase64></v:Body></v:Envelope>

• Respuesta del servidor

HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Transfer-Encoding: chunked Date: Wed, 20 Dec 2006 22:06:09 GMT b73 <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><ns1:getImagenBase64Response soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:video.samples"><getImagenBase64Return xsi:type="xsd:base64Binary">/9j/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABQAFADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDyWL/WD25qQnP40yIZkpxGGpvcCzZAG7hz03r/ADr3SxmEOgXcuMGVkhXj/gR/kPzrxDS136jbLjrIo/WvcL+2a2stPswwBWHzpB/tPz/ILUS3GU1lIOe5FPa4YYBPFMEDYHT8aRrdmJORjvis7Fj5ZCcBSfp61CYiy55pyxyB1TB5967bwppVvLaXIurdJCWGN4yQK0UXb0IbOBeP7y4HFQSQN1/Ku7utPtYLvEclrs6Hcq8c+9WfFmmQP4chls4IhsZSZIwB8pGP54qnGxKdz5agGS30p235iKbCTlgByanBBpyeoy/ocTSa5ZqoyfOX3r3LWR5uqu44Qxx7cemwYrxbw2RFr9m5zhZQSBX0dPpUWtQW1xZRfZ4wgw8uRuGOmP60gOPRePug04L8pB25JrT1DR7nSlDzKjRscb05FZE1wvK5xznOKkpMcCfN3d+g4ru/CsLJp8krZ/ePx+FcAs6KSd57YArvfDN0raG7B1GyQgF+nQf41pfQjqV9Re1W8xHZK21iG/c5zWlLbf2noYtYysIkXBDJjGD6VNbanDN8plXeASQqnoKamqI92ieYFR8bA0ZBfPpU3BI+OYThjUwODn1NRR4DNUvoPem9xmzoDgaxa8dHz+lfU+n3cV1pNncRITGyABV7dsV8p6DzrFvjOcn+VfQ3gS8klsJrInmIiRPoeoqeopbHTahZ/bLOa0ZNqSr8rZzhu39K8puw8MzwuNrqxUg+or1+e4QRBSpLsQAuOc1wPjbSzBqC3cafJOMtjsw6/wBDRJXFF2ZyhYA9a7fwzcxx+G7veplPnABASCeBXC7GOSRgfSux8Hz2sdrNFcXEkUpcFNq9sY64oXmORpabrNotw0RSNISmSJn4DDqc4/SoLLVGudSBNulw4kyZvm4XIwQB0xXTWunWunwBIoJGwxbJAJJIxWdeTaTYmO5ktLkEERKycHjseRRZkto+TVGScetOz601Cce+aQtzV9Szc8NHGtwc+v8AKvYPC2pfYdZgdnAjY7G9MHivGvDjhdahJIwA3X6V6JDOo2kEexFSI95bhSyqC2PzrE8TKkvh2ZphtdCCn1zjj8Ca4vTPGWo2qrC1xHIhOAZhnH41p+MnuUFsJr5ZkcZ2IAoHvjPP1oBs5F/vcjgd66jwhYS3d3JKj7EjAViMZ59iCD0rkWdTn8utdb4PFzcJfQ2jxKzBDl2PY+1MCrr2pXR1W5w7oFcrtDHAxxml8Ovf3T3Nra3CwtIocysSGGOwPvml8QeI

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

226 Francisco Prieto Donate

rq31iaOAQRBH2kCNG5HXkjnmoLK/1TxF59goimdk3rkKmzHcYFO5PQ+ewcLmkOSaMjGKb36U7FGtoX/IVj+h/lXcozHGBXDaCCdWjA/umu3QiPHG496zluNFtZCSDng9sVejlNw4SSRskj94fmwPp+VZiOc8jANdb4CiWfxAqS42eW2VI+9jt/X8KSE9jM1fTv7MuI4xP5qvGsgIXbwR3HY1Y8MTXzX80On3KwTvER8xxnBBx7V2Xje00mTT2l3RRXqkbNo5f2P4V5eWKMSjEEcVbWlyU+ZFzXrtJdUlkVOC3z85+b+I5zzzmmaZdunmJHcR2shGVm3lWHsCOefSs2XnHPLDrVd2YAZPPuKSY1tY/9k=</getImagenBase64Return></ns1:getImagenBase64Response></soapenv:Body></soapenv:Envelope> 0

9.2.2 Codificación Array de enteros

En la siguiente tabla adjuntamos información, para cada uno de los formatos, del tamaño medio del archivo enviado, tiempo medio entre imágenes, y consumo de memoria en tres momentos distintos de la ejecución del cliente.

Tamaño medio de la imagen

(Kb)

Información enviada por el servidor

(Kb)

Tiempo medio entre

imágenes (s)

Consumo de

memoria al inicio

(Kb)

Consumo de memoria tras la 1ª

imagen (Kb)

Consumo de memoria

tras la 2ª imagen

(Kb)

JPG 1,76 130,94 84,18 103,86 422,18 422,18

PNG 13,57 1.381,06 732 103,86 Se excede el límite de memoria (500Kb)

Se excede el límite de memoria (500Kb)

Tabla 9.2: Resultados para el escenario kSOAP con Array de enteros

Tras la realización de esta prueba comprobamos que en el caso del formato PNG no se muestra por pantalla ninguna imagen, pues obtenemos un error de falta de memoria. Esto se produce cuando se intenta representar la imagen recibida, aunque los datos sí se reciben por completo en el emulador. Por ello, en el campo de “ Tiempo medio entre imágenes” del formato PNG no hemos expresado el tiempo entre imágenes sino el tiempo que transcurre desde que el cliente realiza la petición hasta que recibe todos los datos.

9. Pruebas y resultados

Francisco Prieto Donate 227

A continuación mostramos el formato de los mensajes de petición y respuesta intercambiados por el cliente y el servidor. Aparecen exclusivamente los mensajes para el caso JPG, ya que para el caso PNG los mensajes son idénticos salvo por el número de enteros codificados que aparecen en la respuesta. La respuesta del servidor ha sido recortada, ya que si cada entero representa un byte de la imagen, en el fichero resultante aparecería unas 1.800 veces repetida la estructura: <getImagenIntArrayReturn xsi:type="xsd:int">Número</getImagenIntArrayReturn>.

• Petición del cliente

POST /axis/services/VideoKsoap HTTP/1.1 SOAPAction: Content-Type: text/xml Content-Length: 416 User-Agent: kSOAP/2.0 User-Agent: UNTRUSTED/1.0 Host: 127.0.0.1:8080 <v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><n0:getImagenIntArray id="o0" c:root="1" xmlns:n0="urn:video.samples"><formato i:type="d:string">jpg</formato><tam i:type="d:int">80</tam></n0:getImagenIntArray></v:Body></v:Envelope>

• Respuesta del servidor

HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Transfer-Encoding: chunked Date: Wed, 20 Dec 2006 22:12:28 GMT 2000 <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><ns1:getImagenIntArrayResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:video.samples"><getImagenIntArrayReturn soapenc:arrayType="xsd:int[1752]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"><getImagenIntArrayReturn xsi:type="xsd:int">-1</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">-40</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">-1</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">-

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

228 Francisco Prieto Donate

37</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">0</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">67</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">0</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">8</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">6</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">6</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">7</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">6</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">5</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">8</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">7</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">7</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">7</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">9</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">9</getImagenIntArrayReturn><getImagenIntArrayReturn xsi:type="xsd:int">8</getImagenIntArrayReturn> ... <getImagenIntArrayReturn xsi:type="xsd:int">-39</getImagenIntArrayReturn></getImagenIntArrayReturn></ns1:getImagenIntArrayResponse></soapenv:Body></soapenv:Envelope> 0

9.3 Escenario JSR-172

9.3.1 Codificación Base64

En la siguiente tabla adjuntamos información, para cada uno de los formatos, del tamaño medio del archivo enviado, tiempo medio entre imágenes, y consumo de memoria en tres momentos distintos de la ejecución del cliente.

Tamaño medio de la imagen

(Kb)

Información enviada por el servidor

(Kb)

Tiempo medio entre

imágenes (s)

Consumo de

memoria al inicio (Kb)

Consumo de

memoria tras la 1ª imagen

(Kb)

Consumo de

memoria tras la 2ª imagen

(Kb)

JPG 1,76 2,77 3,89 103,55 230,80 289,44

9. Pruebas y resultados

Francisco Prieto Donate 229

PNG 13,57 25,63 7,09 103,55 228,98 324,31

Tabla 9.3: Resultados para el escenario JSR-172 con Base64

A continuación mostramos el formato de los mensajes de petición y respuesta intercambiados por el cliente y el servidor. Mostramos exclusivamente los mensajes para el caso JPG, ya que para el caso PNG los mensajes son idénticos salvo por la longitud de la cadena de texto que contiene la imagen codificada.

• Petición del cliente

POST /axis/services/VideoJSR HTTP/1.1 User-Agent: Profile/MIDP-1.0 Configuration/CLDC-1.0 Content-Language: en-US Content-Type: text/xml SOAPAction: " User-Agent: UNTRUSTED/1.0 Content-Length: 386 Host: 127.0.0.1:8080 User-Agent: UNTRUSTED/1.0 <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://video.samples/"> <soap:Body> <tns:getImagenBase64> <tns:formato>jpg</tns:formato> <tns:tam>80</tns:tam> </tns:getImagenBase64> </soap:Body> </soap:Envelope>

• Respuesta del servidor

HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Transfer-Encoding: chunked Date: Wed, 20 Dec 2006 22:24:23 GMT 8bd <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

230 Francisco Prieto Donate

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><getImagenBase64Response xmlns="http://video.samples/"><getImagenBase64Result>/9j/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABQAFADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDyeP7pzxzzSkZOcUJwuM5oxz2qnuA0j/61KB9KXIPNHegBR0NagI8tBz90ZrMGcHFaUikIh7EAVnIpD7Q5uoyf74/nX1P4XH/FJaR/16Rf+givlywXN1ED/fFfU/hoKvhfSgmdv2SLGf8AdFTu7CZp4paKKuwj4pj+4MilPTPWhMbBS5q2Ah96AB060jUoxnpQA5e/PNasqEAAjjAwKyl4rZDeYd38OOM1nMqJZ02INeRZHVhX074aG3wvpQ9LSL/0AV836Dbefq9rEMYaQDmvpfRkEeh2CDotvGP/AB0Uo73Je9i7RRRVgfFI4UD+VB6mtPWdHTTbwLFM0kTcjd1FVVgBHQHPqKXOmrlWZVJHPtS7vpVwWyEcqKa1soPANHOmHK7FZM5OSK1FJMaKW9KoyQ7V4q6hJVQO1KTuC0N7QpCmq2rbcgSetfS2jnOh2GRj/Ro8j/gIr5u8MWs82s2RUcGSvpTToymk2kZ4KwIv/joqrWRF7yZPA4kiDDp0qSooIfIQruyM8U25laNcL1NRfljdjPlHV5RcXbsTlQSV+hbNVVgLJvAz61FcbhcENnOec+taNi43bG6EVm04o2WrKRManDOAfQmmmWIjhxVXUY9t3Iozw1VDxz35/rWijdEORoyYZQV6BhnipclWJ96owElv+BVZkkIc445p8upNzsfCl2YtRtQCMoxbn6V9G2D+Zp9s/HzRKePoK+XdAmEd7CxwMZ/ka+ndGcSaHYODkNbRnP8AwEVo9kZR+Jlt2Crk1mzNLcS/J9wd602XcMVX8howRGAc9c9qylG7Kk2j5a8QWDQ6hOyD5Qd/4Gs6ByMc/jXVeLLTfDFcDPB2t9O1cksUsYL7D5fZsVjF80Td6MjuyWndu5P9Kg5qS4OXYnvjFQg5NbR2IYJuLjPPIxTmYmQ+xpEJEinvmkBJfP8ASrRLNOxkZJxgfwn+Rr6n8MOX8K6Sxxk2cXT/AHBXyzYRebOFDYO1jz7Ka+pfDkBh8MaZFvzi1jAIH+yKbRC3NaikUFRgkn60tIs//9k=</getImagenBase64Result></getImagenBase64Response></soapenv:Body></soapenv:Envelope>0

9.3.2 Codificación Array de enteros

En la siguiente tabla adjuntamos información, para cada uno de los formatos, del tamaño medio del archivo enviado, tiempo medio entre imágenes, y consumo de memoria en tres momentos distintos de la ejecución del cliente.

Tamaño medio de la imagen

(Kb)

Información enviada por el servidor

(Kb)

Tiempo medio entre imágenes (s)

Consumo de

memoria al inicio

(Kb)

Consumo de memoria

tras la 1ª imagen

(Kb)

Consumo de memoria

tras la 2ª imagen

(Kb)

JPG 1,76 130,62 60,11 103,55 473,37 473,37

9. Pruebas y resultados

Francisco Prieto Donate 231

PNG 13,57 1.380,82 565 103,55 Se excede el límite de memoria (500Kb)

Se excede el límite de memoria (500Kb)

Tabla 9.4: Resultados para el escenario JSR-172 con Array de enteros

Tras la realización de esta prueba comprobamos que en el caso del formato PNG no se muestra por pantalla ninguna imagen, pues obtenemos un error de falta de memoria. Esto se produce cuando se intenta representar la imagen recibida, aunque los datos sí se reciben por completo en el emulador. Por ello, en el campo de “ Tiempo medio entre imágenes” del formato PNG no hemos expresado el tiempo entre imágenes sino el tiempo que transcurre desde que el cliente realiza la petición hasta que recibe todos los datos.

A continuación mostramos el formato de los mensajes de petición y respuesta intercambiados por el cliente y el servidor. Mostramos exclusivamente los mensajes para el caso JPG, ya que para el caso PNG los mensajes son idénticos salvo por el número de enteros codificados que aparecen en la respuesta. La respuesta del servidor ha sido cortada, ya que si cada entero representa un byte de la imagen, en el fichero resultante aparecería unas 1800 veces la estructura: <getImagenIntArrayReturn xsi:type="xsd:int">Número</getImagenIntArrayReturn>.

• Petición del cliente

POST /axis/services/VideoJSR HTTP/1.1 User-Agent: Profile/MIDP-1.0 Configuration/CLDC-1.0 Content-Language: en-US Content-Type: text/xml SOAPAction: " User-Agent: UNTRUSTED/1.0 Content-Length: 390 Host: 127.0.0.1:8080 <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://video.samples/"> <soap:Body> <tns:getImagenIntArray> <tns:formato>jpg</tns:formato> <tns:tam>80</tns:tam> </tns:getImagenIntArray> </soap:Body>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

232 Francisco Prieto Donate

</soap:Envelope>

• Respuesta del servidor

HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Transfer-Encoding: chunked Date: Wed, 20 Dec 2006 22:26:18 GMT 2000 <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><getImagenIntArrayResponse xmlns="http://video.samples/"><getImagenIntArrayResult xsi:type="xsd:int">-1</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">-40</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">-1</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">-37</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">0</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">67</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">0</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">8</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">6</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">6</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">7</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">6</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">5</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">8</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">7</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">7</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">7</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">9</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">9</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">8</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">10</getImagenIntArrayResult>... xsi:type="xsd:int">-120</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">-1</getImagenIntArrayResult><getImagenIntArrayResult xsi:type="xsd:int">-39</getImagenIntArrayResult></getImagenIntArrayResponse></soapenv:Body></soapenv:Envelope> 0

9. Pruebas y resultados

Francisco Prieto Donate 233

9.4 Análisis de los resultados

9.4.1 Consumo de memoria

El siguiente gráfico muestra el consumo de memoria de todas las pruebas realizadas. Con esto comprobaremos qué escenario, formato y codificación consiguen un menor consumo de memoria en tiempo de ejecución.

En el diagrama se ha omitido el análisis para la codificación array de enteros y formato PNG en ambos escenarios, ya que el consumo de memoria es mayor que el máximo soportado por el emulador y por tanto no se recibe imagen alguna.

0,00050,000

100,000150,000200,000250,000300,000350,000400,000450,000500,000

Inicio 1ª imagen 2ª imagen

Instante de ejecución

Mem

oria

con

sum

ida

(Kb)

JSR-172 - Array int -JPG

kSOAP - Array int -JPG

kSOAP - Base64 -PNG

JSR-172 - Base64 -PNG

kSOAP - Base64 -JPG

JSR-172 - Base64 -JPG

Figura 9.1: Consumo de memoria en las distintas ejecuciones

Como podemos comprobar, en el momento de la carga todos los casos realizan el mismo consumo de memoria. En caso de haber diferencias, éstas sólo se apreciarían entre escenarios, ya que el formato y la codificación sólo influyen a la hora de recibir y representar la imagen.

Tras representar la primera imagen se aprecian cambios significativos en el consumo. Las ejecuciones que más consumen son las que utilizan como codificación el array de enteros, debido a que la información que reciben del servidor es mucho mayor.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

234 Francisco Prieto Donate

Para Base64, obtienen un mayor consumo las pruebas realizadas con el escenario kSOAP. Los mejores valores obtenidos resultan ser del escenario JSR-172 con codificación Base64.

A la vista de los resultados obtenidos, comprobamos que el formato de la imagen no es un dato relevante en cuanto a consumo de memoria se refiere.

9.4.2 Tiempo entre imágenes

Agrupando los datos de los tiempos entre imágenes de todas las pruebas realizadas podemos elaborar la gráfica que mostramos a continuación.

Al igual que en el caso anterior, se ha omitido el análisis para la codificación array de enteros y formato PNG en ambos escenarios, ya que al tener valores ser mucho mayores que los demás, no se podrían visualizar correctamente los datos con valores pequeños, que son los que realmente interesan.

kSOAP JSR-1720

10

20

30

40

50

60

70

80

90

Tiem

po e

ntr

e im

ágen

es (s

)

Base64 - JPGBase64 - PNGArray int - JPG

Figura 9.2: Tiempo entre imágenes en las distintas ejecuciones

Es fácil apreciar que los mayores valores de tiempo entre imágenes se obtienen con las pruebas realizadas eligiendo como codificación el array de enteros. Para la

9. Pruebas y resultados

Francisco Prieto Donate 235

codificación Base64, se aprecian valores menores en el escenario JSR-172 que en kSOAP. Para un mismo escenario y codificación, el formato que consigue menor tiempo entre imágenes es JPG.

9.4.3 Información enviada por el servidor

Por último queremos comprobar en qué medida influye el protocolo SOAP en el tamaño de los datos enviados al cliente. Como sabemos, SOAP, al igual que la mayoría de los protocolos de red, inserta unas cabeceras antes de la transmisión del paquete de datos con información necesaria para la correcta interpretación por parte del cliente. Igualmente, envuelve con etiquetas cada uno de los datos individuales que se van a transmitir, de modo que el tamaño de los datos enviados será siempre mayor que el tamaño de la imagen enviada.

A continuación mostramos la comparación entre el tamaño de la imagen solicitada y el tamaño de los datos enviados por el servidor. La información se ha recogido para todas las pruebas realizadas.

Escenario Codificación Formato Tamaño imagen

original (Kb)

Tamaño de la imagen codificada

(Kb)

Aumento

JPG 1,76 2,95 67,61% Base64

PNG 13,57 25,73 89,61%

JPG 1,76 130,94 7.339,77%

kSOAP

Array de enteros

PNG 13,57 1.381,06 10.077,30%

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

236 Francisco Prieto Donate

JPG 1,76 2,77 57,39% Base64

PNG 13,57 25,63 88,87%

JPG 1,76 130,62 7.321,59%

JSR-172

Array de enteros

PNG 13,57 1.380,82 10.075,53%

Tabla 9.5: Aumento del tamaño de la información debido a la codificación

En líneas generales, el aumento de la información debido a la codificación es sensiblemente menor en el escenario JSR-172 para una codificación y formato fijos. A la vista de los resultados obtenidos, la codificación con array de enteros utiliza una cantidad excesiva de información para enviar una imagen, ya que para cada uno de los números enteros que representan la imagen, el protocolo inserta cabeceras de inicio y de cierre. Centrándonos en la codificación Base64, se consigue un mayor rendimiento en el envío de imágenes JPG que PNG en ambos escenarios.

9.5 Consideraciones finales

Los resultados obtenidos en las pruebas realizadas nos han servido para comparar montajes con distintas tecnologías, formatos y codificaciones. Con esto ha sido posible cuantificar el rendimiento obtenido por cada una de las implementaciones en términos de retrasos y consumos de memoria.

En el capítulo siguiente haremos uso de toda la información adquirida durante el desarrollo de las pruebas para discutir los resultados y comprobar que se han cumplido los objetivos marcados.

10. Conclusiones

Francisco Prieto Donate 237

10 CONCLUSIONES

10.1 Conclusiones

A continuación se exponen las conclusiones obtenidas de la realización de este proyecto fin de carrera.

En primer lugar nos centramos en los dos escenarios que se han utilizado para las pruebas. A la vista de los resultados obtenidos, el escenario JSR-172 presenta mejores resultados respecto a kSOAP en cuanto a consumo de memoria en tiempo de ejecución, tiempo de recepción de datos y tamaño de la información intercambiada. En cuanto a las librerías utilizadas, JSR-172 está diseñado para ser incluido en el propio dispositivo, de modo que el tamaño de la aplicación cliente se reduce drásticamente. Según estos criterios, JSR-172 resulta ser el escenario más recomendable para la implementación del cliente y servidor.

Por su parte kSOAP, por el hecho de tratarse de una librería externa, se puede utilizar en cualquier dispositivo con soporte J2ME y acceso a Internet vía GPRS. Por este motivo se recomienda el uso de esta tecnología sólo en el caso de que el dispositivo móvil destinado al cliente no disponga de la especificación JSR-172.

En cuanto al formato de imagen enviado, siempre buscaremos aquél que nos ofrezca una mejor relación calidad/tamaño. Tras las pruebas realizadas, se observa que las imágenes JPG y PNG mostradas en pantalla no presentan diferencias apreciables en su calidad. El tamaño sí es un factor decisivo a la hora de elegir el formato de imagen, y teniendo en cuenta que una imagen JPG es siete veces menor que una imagen PNG del mismo tamaño, podemos concluir que el formato más recomendable es JPG.

El hecho de elegir JPG como formato de imagen recomendado nos obliga a utilizar la librería externa que descodifica este formato en clientes móviles que no tengan soporte para ello. Los resultados nos indican que la utilización de este descodificador influye de manera mínima en el consumo de memoria durante la ejecución, lo cual nos permite poder visualizar imágenes JPG en cualquier cliente móvil sin tener que preocuparnos por el consumo extra de memoria.

En cuanto a la codificación utilizada podemos comprobar que Base64, utilizada en Internet, correo eletrónico y servicios web, es sin duda la más recomendable en cuanto a rendimiento se refiere. Si estudiamos detenidamente esta codificación, utilizada por defecto por el protocolo SOAP, observamos que convierte un archivo binario en un

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

238 Francisco Prieto Donate

archivo capaz de ser transmitido por la red aumentando un 33% el tamaño del archivo original. Según los resultados obtenidos, la codificación de array de enteros que hemos forzado en la transmisión de datos ha resultado ser absolutamente ineficiente, provocando que incluso el emulador de teléfono móvil quedara bloqueado por excesivo consumo de memoria. Es curioso observar cómo la información enviada por el servidor puede llegar a ser hasta un 10.000% mayor que la imagen que se desea transmitir.

En el lado del servidor, es importante comentar que Apache Tomcat con el módulo Axis es una herramienta muy potente para desplegar Servicios Web XML. Por un lado, posee facilidades que permiten desplegar y probar servicios web simples sin complicaciones mediante el desplegado automático, y por otro lado permite mucha libertad en la configuración de servicios más complejos o con restricciones gracias al lenguaje WSDD.

El hecho de no encontrarse integrado el servidor web con el servidor de vídeo nos aporta gran flexibilidad, ya que no estamos obligados a ejecutar ambos servidores en la misma máquina. No obstante, los retrasos sufridos en ese caso podrían apreciarse en el tiempo de recepción de imágenes, de modo que se recomienda ejecutar ambos servidores en el mismo equipo.

Un factor decisivo en el tiempo de recepción de datos es la conexión GPRS. Su limitada velocidad provoca un cuello de botella en el tiempo de recepción de la información. Mientras que a velocidades GPRS nos vemos obligados a enviar una secuencia de imágenes independientes, con UMTS podríamos enviar secuencias completas de vídeo incluyendo sonido. Estas limitaciones nos obligan a reducir el abanico de posibilidades que conlleva la recepción de vídeo: con la tecnología que estamos utilizando no podemos intercambiar contenido multimedia. Por lo tanto una de las aplicaciones ideales de este proyecto es el de realizar videovigilancia, ya que por un lado no es necesario tener sonido ni tampoco es decisivo el hecho de que la secuencia de vídeo no sea continua. El tiempo mínimo entre imágenes que se ha obtenido como resultado, 3,89 segundos, es suficiente para esta finalidad.

La utilización de XML para la representación de la información ha resultado ser una opción completamente adecuada. Flexibilidad, legibilidad, integración e independencia son cuatro de las cualidades que hacen de este lenguaje una herramienta de comunicación indispensable. No en vano, la tendencia actual en Internet consiste en normalizar protocolos como HTML para adecuarlos al estándar XML.

Por último comentar las ventajas aportadas por el hecho de utilizar Servicios Web XML. En primer lugar destacar el uso de un protocolo basado en XML para el intercambio de información. Otro punto a favor resulta ser la facilidad que aportan los documentos WSDL asociados a los servicios web, lo que conlleva una total abstracción de la implementación del servidor a la hora de crear el cliente. Además tanto el lenguaje de programación como el sistema operativo utilizado son factores irrelevantes para la

10. Conclusiones

Francisco Prieto Donate 239

comunicación entre cliente y servidor, lo que permite una flexibilidad absoluta en este sentido.

El punto negativo del uso de servicios web lo encontramos al aplicarlo en clientes de reducidas prestaciones. Hemos podido comprobar cómo en el mejor de los casos el tamaño de un archivo aumenta un 57% para ser transmitido vía SOAP, y este valor aumenta al incrementar el tamaño de los datos enviados, con lo que los retrasos también aumentan. Este factor debe ser tenido muy en cuenta, ya que por un lado los dispositivos móviles no cuentan con mucha capacidad de almacenamiento de datos, y por otro lado tenemos que a mayor tamaño de datos, mayor tiempo de espera para el usuario.

10.2 Líneas de desarrollo futuras

Existen varios aspectos que se podrían desarrollar a partir de la implementación de este proyecto.

Por un lado, y teniendo en cuenta que la mayor limitación nos viene dada por la conexión GPRS, parece razonable utilizar la ya implantada red UMTS para la transmisión de datos.

Por otro lado sería interesante aplicar seguridad en nuestro servicio web. Se podría, por ejemplo, pedir nombre de usuario y contraseña para poder hacer uso de los servicios ofrecidos.

En último lugar sería recomendable estudiar otras alternativas al uso de Servicios Web XML para poder soportar ampliaciones de los servicios. Una de las desventajas que conllevan los servicios web radica en que el cliente se encuentra programado e instalado en el dispositivo móvil. Esto tiene el problema de que si se quiere ampliar el servicio web para ofrecer nuevas funcionalidades, sería necesario actualizar el cliente o incluso descargárselo de nuevo. Como alternativa se propone el acceso a la información a traves de un navegador web. De esta manera, el servidor ofrecería una página web con las opciones disponibles en un momento dado. Para ampliar funcionalidades solamente habría que cambiar la página web ofrecida.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

240 Francisco Prieto Donate

11. Temporización

Francisco Prieto Donate 241

11 TEMPORIZACIÓN

La realización del proyecto se ha dividido en cinco fases:

• Documentación: lectura de artículos, libros y proyectos sobre J2ME, servicios web y XML. Desde el 15 de Septiembre hasta el 15 de Noviembre de 2005.

• Herramientas necesarias para el montaje de la plataforma y el desarrollo de aplicaciones: Recopilación de información, instalación y testeo. Realización de tutoriales, ejemplos y pruebas simples para familiarizarse con dichas herramientas. Desde el 16 de Noviembre de 2005 hasta el 15 de Enero de 2006.

• Desarrollo de la aplicación: Creación y despliegue de los servicios web, creación del cliente J2ME, adaptación de la librería que descodifica JPEG. Desde el 16 de Enero hasta el 1 de Abril de 2006.

• Ámbito de pruebas: Programación de batería de pruebas, realización de las pruebas, análisis de resultados. Desde el 2 de Abril hasta el 31 de Mayo de 2006.

• Redacción de la memoria: Redacción de los capítulos, ajuste de formato. Desde el 15 de Septiembre de 2006 hasta el 15 de Enero de 2007.

La dedicación al proyecto durante estas etapas ha sido variable debido a exámenes, vacaciones, etc. Desde el 1 de Junio hasta el 15 de Septiembre de 2006 no hubo dedicación alguna al proyecto debido al estudio de asignaturas para Septiembre y la incorporación al mundo laboral.

Para una mejor visualización del tiempo utilizado en cada fase, se presenta el siguiente diagrama de Gantt:

Figura 11.1: Tiempo empleado en la realización del proyecto

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

242 Francisco Prieto Donate

12. Presupuesto

Francisco Prieto Donate 243

12 PRESUPUESTO

El proyecto desarrollado se ha realizado sin ningún tipo de remuneración ni gasto específico. Sin embargo es interesante calcular cuánto habría costado a una empresa desarrollar un proyecto similar. Para ello hay que tener en cuenta:

• El proyecto ha sido realizado por una sola persona, cuyo nivel profesional se puede comparar con el de un ingeniero junior.

• La duración aproximada de la realización del proyecto ha sido de un año.

12.1 Coste de recursos humanos

El coste se ha estimado suponiendo una dedicación media de dos horas por día, todos los días laborables durante un año. Hemos supuesto que el salario medio de un ingeniero junior a jornada completa es de 1200 � / mes y que la duración del proyecto ha sido de un año. En este caso, el salario anual sería de 14.400 �/año para jornada completa y 3.600 �/año para una jornada de 2 horas.

12.2 Coste de hardware

El hardware utilizado ha sido un ordenador personal, una impresora de inyección de tinta y una webcam.

12.3 Coste de software

Exceptuando el sistema operativo y el software para la redacción de la memoria, todo el software usado es gratuito.

12.4 Coste de consumibles

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

244 Francisco Prieto Donate

En el coste de consumibles tendremos en cuenta el gasto eléctrico, la conexión a Internet mediante ADSL y material diverso de oficina como cartuchos de tinta, papel o CDs.

12.5 Resumen de costes

Descripción Unidades Coste unitario (�)

Total (�)

Recursos humanos Horas de trabajo, Ingeniero Junior 12 meses 300 �/mes 3.600 Hardware Ordenador AMD K7 1 700 700 Impresora inyección de tinta 1 60 60 Webcam 1 18 18 Software Windows XP Profesional SP2 1 93,14 93,14 Microsoft Office 2003 1 184,61 184,61 Consumibles Gasto eléctrico 12 meses 10 �/mes 120 Conexión a Internet 12 meses 40 �/mes 480 Material de oficina 1 30 30 TOTAL 5.285,75 �

Tabla 12.1: Coste total del proyecto

13. Guía de instalación

Francisco Prieto Donate 245

13 GUÍA DE INSTALACIÓN

En este capítulo vamos a detallar el software que será necesario tener instalado para el correcto funcionamiento de la aplicación. Asimismo detallaremos los pasos seguidos para proceder a la instalación, configuración y puesta en marcha de los mismos.

Vamos a estructurar la instalación en dos partes:

• Servidor de la aplicación, que comprende:

� Servidor de vídeo, encargado de capturar imágenes de vídeo a través de una webcam y enviarlas a través de peticiones HTTP.

� Servidor web Apache Tomcat 4.1, cuya misión es hacer de contenedor de la aplicación web que pondrá en contacto el cliente móvil y el servidor de vídeo.

� Apache Axis 1.4, aplicación que se ejecuta sobre Apache Tomcat y permite desplegar servicios web utilizando el protocolo SOAP.

• Cliente móvil, que comprende:

� J2ME Wireless Toolkit 2.2, entorno de desarrollo que nos permitirá emular el comportamiento de un dispositivo móvil real.

� NetBeans IDE 5.5 con Mobility Pack, entorno de desarrollo que facilita la programación del cliente móvil.

� Dispositivo móvil de pruebas, teléfono móvil real en el que probaremos las aplicaciones realizadas.

13.1 Servidor de vídeo

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

246 Francisco Prieto Donate

13.1.1 Instalación

El ordenador en el que se vaya a ejecutar el servidor de vídeo debe tener instalado y correctamente configurado un dispositivo de captura de imágenes, como puede ser una webcam. Asimismo será necesario tener instalado el siguiente software:

• Plataforma de Java J2SE 5.0, que lo podemos descargar de la página web de Sun: http://java.sun.com/javase. Esta plataforma nos permite ejecutar código Java en nuestro ordenador.

• JMF 2.1.1 - Java Media Framework, que lo podemos obtener en la siguiente dirección web: http://java.sun.com/products/java-media/jmf. Aporta funcionalidad de audio y vídeo en tiempo real a la plataforma Java.

Para instalarlo en cualquier versión de Windows, se ejecutará el fichero que se ha descargado y se instalará JMF 2.1.1 en el directorio que se le indique. En el proceso de instalación se actualizará el CLASSPATH del sistema. Se puede comprobar si la instalación se realizó correctamente desde una página de diagnóstico proporcionada por Sun, cuya dirección es: http://java.sun.com/products/java-media/jmf/2.1.1/jmfdiagnostics.html

Figura 13.1: Página de diagnóstico de JMF para una instalación correcta

13. Guía de instalación

Francisco Prieto Donate 247

Si se realiza la instalación de JMF antes que la instalación de los drivers de los dispositivos de captura, en nuestro caso la webcam, deberemos ejecutar el programa JMStudio que se instala con JMF para detectar el dispositivo. En el menú File, seleccionamos la opción Preferences. En la pestaña llamada Capture Device, pulsamos en Detect capture device, para que JMF detecte los nuevos dispositivos instalados y podamos utilizarlos en el proyecto.

• JDK 5.0 - Java SE Development Kit, que lo podemos descargar de la página web de Sun: http://java.sun.com/javase/downloads. Nos proporciona un kit de desarrollo que permite compilar el código fuente del servidor

• Jimi 1.0, que podemos obtenerlo en la siguiente dirección: http://java.sun.com/products/jimi. Jimi es una librería de clases destinadas al manejo de imágenes.

Para su instalación en Windows XP descomprimimos el archivo en la ruta que se desee y después se deberá añadir el archivo JimiProClasses.zip que se descomprime en el CLASSPATH. Para ello se deberá ir al Panel de control de Windows, seleccionar Sistema y después Avanzado. Ahora se tiene que pulsar el botón de Variables de entorno y localizar la variable CLASSPATH en la lista superior. Después se añadirá la ruta del archivo y el nombre utilizando un punto y coma (;) para separar esta nueva entrada de las demás: C:\Jimi\JimiProClasses.zip;

13.1.2 Funcionamiento

Los archivos correspondientes al servidor se encuentran en la carpeta Aplicacion/Servidor/. Dentro de esta carpeta se encuentran otras dos carpetas: una llamada src que contiene los archivos del código fuente del servidor y otra que se llama classes que contiene los archivos compilados de la aplicación.

Para poner en marcha la aplicación, dentro de la carpeta classes se deberá ejecutar la siguiente instrucción:

java ProyectoFinCarrera/VideoServer

El primer paso antes de capturar las imágenes de vídeo es configurar el servidor. Para ello pulsamos el botón Configuración, donde accederemos a un menú que nos permite configurar varios parámetros:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

248 Francisco Prieto Donate

Figura 13.2: Pantalla de configuración del servidor de vídeo

Los parámetros de configuración son los siguientes:

• Dispositivo de vídeo: Permite seleccionar el dispositivo capturador de vídeo en el caso de que existieran varios.

• Formato de vídeo: Formato en el que se capturarán las imágenes de vídeo a partir de la webcam. Este dato resulta irrelevante en este proyecto, ya que vamos a realizar peticiones de imágenes estáticas cuyo formato especificaremos a la hora de realizar la petición.

• Puerto del servidor: Puerto a través del cual el servidor recibe las peticiones.

• Directorio de trabajo y archivo con la web a mostrar: Ruta en la que se ubicará el archivo index.html, página que muestra un interfaz web para interactuar con el servidor. En este proyecto no vamos a utilizar este archivo, aunque debe existir para que el servidor funcione correctamente.

13. Guía de instalación

Francisco Prieto Donate 249

Una vez elegida la configuración adecuada iniciamos la captura de imágenes con la opción Iniciar dentro del menú Acciones.

Figura 13.3: Ejecución del servidor de vídeo

13.1.3 Formato de la petición al servidor

Si queremos que el servidor nos envíe una imagen, los parámetros que podemos modificar son los siguientes:

• Formato de la imagen. Los formatos posibles son:

� JPEG, en el cual podemos configurar la calidad que deseemos tenga la imagen.

� PNG, en el cual podemos configurar el nivel de compresión.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

250 Francisco Prieto Donate

� BMP, sin ningún parámetro adicional configurable.

• Escala de grises: si queremos que la captura de la imagen sea en escala de grises.

• Tamaño de la imagen: especificamos el número de píxeles de alto y de ancho.

Para que el servidor acepte una petición de captura de imagen, ésta debe tener un formato específico. La petición de captura debe comenzar por un signo de interrogación cerrado y a continuación se deben indicar los parámetros que se quieren modificar separados por signos de interrogación cerrados.

http://direccionIP:puerto/?parametro1?parametro2?...?

Los parámetros a modificar se especifican usando el siguiente formato:

• Formato de la imagen. Se debe usar el comando format= seguido del valor correspondiente al formato deseado. Los valores posibles son:

� jpg o jpeg para obtener la imagen en formato JPEG.

� png para obtener la imagen en formato PNG.

� bmp para obtener la imagen en formato BMP.

• Escala de grises. Para obtener la imagen en gris se debe utilizar el comando gray.

• Tamaño de la imagen. Para modificar el tamaño se debe usar el comando resize= seguidos de los valores de altura y anchura de la imagen en píxeles y separados por un asterisco.

• Calidad de la imagen en formato JPG. Se debe utilizar el comando quality= seguido de un valor entero entre cero y cien. Si no se especifica la calidad, se toma por defecto cincuenta.

• Nivel de compresión de la imagen en formato PNG. Para especificar el nivel de compresión se usa el comando comp= seguido del nivel de compresión. Existen tres niveles posibles:

13. Guía de instalación

Francisco Prieto Donate 251

� none, para indicar que no se use compresión.

� max para usar compresión máxima.

� def para usar el nivel de compresión por defecto.

Si no se especifica el nivel de compresión, no se realizará ninguna.

Una vez estudiadas las características de la petición de imagen, vamos a ver un ejemplo:

http://192.168.0.1:80/?format=png?grey?resize=80*80?comp=max?

Solicitamos una imagen en formato PNG, de tamaño 80 por 80 píxeles, con un nivel de compresión máximo y en escala de grises. El acceso al servidor se realiza a través del puerto 80 en la dirección 192.168.0.1.

13.2 Servidor web Apache Tomcat 4.1

13.2.1 Instalación

El servidor de aplicaciones se puede instalar en cualquier PC conectado a Internet, aunque es recomendable que se encuentre instalado en el mismo equipo que el servidor de vídeo para reducir los retardos de comunicación entre ambos.

Para descargarnos el archivo de instalación en Windows XP tenemos que acceder a la siguiente web: http://tomcat.apache.org/download-41.cgi. La versión más reciente de este servidor de aplicaciones es la 6.0, pero el módulo Axis que instalaremos posteriormente no ofrece soporte para versiones de Tomcat posteriores a la 4.1.

En la página de descargas tenemos varias opciones. Elegiremos “ Windows Installer” en el apartado “ Full distributions for JDK 1.2 or later” .

La instalación de este paquete es muy sencilla, basta con dejar las opciones que vienen marcadas por defecto. Los únicos datos que debemos proporcionar son el

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

252 Francisco Prieto Donate

directorio de instalación C:\Tomcat 4.1 y el nombre de usuario y contraseña para acceder al administrador y al gestor.

Antes de ejecutar el servidor necesitamos crear la variable de entorno JAVA_HOME, que es la que usará Tomcat para localizar el entorno Java. Para ello añadimos una nueva variable de entorno al sistema (al igual que hacíamos con la librería Jimi) con el nombre JAVA_HOME y como valor la ruta de instalación del JDK 1.5, en nuestro caso: C:\Archivos de programa\Java\jdk1.5.0_09.

13.2.2 Funcionamiento

Para arrancar el servidor ejecutaremos el siguiente fichero de procesamiento por lotes: C:\Tomcat 4.1\bin\startup.bat. Para comprobar que nuestro servidor está funcionando correctamente podemos acceder desde cualquier navegador a la siguiente dirección: http://localhost:8080

Figura 13.4: Pantalla de inicio de Apache Tomcat

Para detener el servidor ejecutaremos el fichero: C:\Tomcat 4.1\bin\shutdown.bat.

13. Guía de instalación

Francisco Prieto Donate 253

Dentro del directorio C:\Tomcat 4.1 la jerarquía de directorios es la siguiente:

• bin - arranque, cierre, y otros scripts y ejecutable

• common - clases comunes que pueden utilizar el contenedor y las aplicaciones web

• conf - ficheros XML y los correspondientes DTDs para la configuración de Tomcat

• logs - logs del contenedor y de las aplicaciones

• server - clases utilizadas solamente por el contenedor

• shared - clases compartidas por todas las aplicaciones web

• temp - usado por la JVM para almacenamiento temporal de ficheros

• webapps - directorio que contiene las aplicaciones web

• work - almacenamiento temporal de ficheros y directorios

Por otra parte, cada aplicación web que se encuentre en webapps tendrá un directorio con su nombre y la siguiente jerarquía:

• Raíz - los archivos HTML y JSP que utilice la aplicación

• WEB-INF - Directorio que contiene todos los recursos relacionados con la aplicación web que no deben servirse al cliente. Aquí se encuentra el archivo web.xml, que contiene la configuración de la aplicación.

• WEB-INF/classes - Contiene las clases necesarias para la aplicación.

• WEB-INF/lib - Contiene las librerías y APIs necesarias para la aplicación.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

254 Francisco Prieto Donate

13.3 Apache Axis 1.4

13.3.1 Instalación

Para la instalación de Axis supondremos que disponemos ya del servidor web Apache Tomcat instalado y configurado para escuchar por el puerto 8080.

Tras descargar el paquete de la última versión de Axis en http://ws.apache.org/axis/java/releases.html, lo descomprimiremos en el directorio C:\Axis. A continuación copiamos el contenido del directorio C:\Axis\webapps en C:\Tomcat 4.1\webapps. De esta manera tendremos Axis como un servicio más del servidor Tomcat.

Seguidamente necesitamos hacer saber a Java la localización de los paquetes de Axis. Para ello es necesario crear nuevas variables de entorno que contengan la dirección de dichos paquetes:

Nombre de la variable Valor de la variable

AXIS_HOME c:\axis

AXIS_LIB %AXIS_HOME%\lib

AXISCLASSPATH %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar

CLASSPATH %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_HOME%;c:\tomcat 4.1\common\lib\activation.jar;c:\tomcat 4.1\common\lib\mail.jar;

En el caso de que el sistema operativo permita la introducción de variables de entorno en modo texto, habría que escribir lo siguiente:

13. Guía de instalación

Francisco Prieto Donate 255

set AXIS_HOME=c:\axis

set AXIS_LIB=%AXIS_HOME%\lib

set AXISCLASSPATH=%AXIS_LIB%\axis.jar; %AXIS_LIB%\commons-discovery-0.2.jar; %AXIS_LIB%\commons-logging-1.0.4.jar; %AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar; %AXIS_LIB%\log4j-1.2.8.jar

set CLASSPATH=%AXIS_LIB%\axis.jar; %AXIS_LIB%\commons-discovery-0.2.jar; %AXIS_LIB%\commons-logging-1.0.4.jar; %AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\wsdl4j-1.5.1.jar; %AXIS_HOME%; c:\tomcat 4.1\common\lib\activation.jar; c:\tomcat 4.1\common\lib\mail.jar;

Para que todos los cambios se apliquen correctamente es necesario reiniciar el equipo. Iniciamos ahora el servidor y con un navegador accedemos a la siguiente URL: http://localhost:8080/axis/happyaxis.jsp, una página que comprueba que las librerías obligatorias y opcionales estén presentes.

Si todo ha ido bien, se mostrará por pantalla una página titulada “ Axis Happiness Page” que nos indicará que se han hallado todos los paquetes obligatorios y que falta el paquete que aporta seguridad XML. Si no vamos a usar esta funcionalidad, podemos obviar este mensaje.

Figura 13.5: Pantalla de instalación correcta de Axis (1)

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

256 Francisco Prieto Donate

Figura 13.6: Pantalla de instalación correcta de Axis (2)

Una vez instalado y correctamente configurado, podremos visualizar la página de inicio de Axis accediendo a la siguiente dirección: http://127.0.0.1:8080/axis/

Figura 13.7: Página de inicio de Axis

13. Guía de instalación

Francisco Prieto Donate 257

13.3.2 Despliegue de servicios

Llamamos “ desplegar” al hecho de hacer público un servicio web integrándolo en el servidor. Supongamos que tenemos una clase como ésta:

public class Calculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } }

Axis dispone de dos procedimientos para hacer que esta clase se encuentre disponible vía SOAP: mediante JWS o ayudándonos de un archivo WSDD.

13.3.2.1 Despliegue utilizando JWS (Java Web Service)

Ésta es la forma instantánea de desplegar un servicio. Los servicios web JWS son archivos java que se almacenan en el directorio webapps de Axis: C:\Tomcat 4.1\webapps\axis. El archivo necesita que se le cambie la extensión de .java a .jws. Cuando se solicite el archivo .jws dando su URL, éste será compilado y ejecutado automáticamente.

El método JWS se utiliza para servicios web muy simples. Por un lado no se pueden utilizar paquetes adicionales. Por otro lado el código es compilado y ejecutado en tiempo de ejecución, por lo que no se pueden localizar posibles errores hasta que no se encuentre desplegado.

Con el servicio ya publicado, accedemos con nuestro navegador a: http://localhost:8080/axis/Calculator.jws, y nos aparecerá una página que nos indica: “ There is a Web Service here, Click to see the WSDL” . Siguiendo el enlace nos encontramos con el Axis nos ha generado automáticamente en archivo WSDL, que se muestra a continuación:

<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://localhost:8080/axis/Calculator.jws" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/axis/Calculator.jws" xmlns:intf="http://localhost:8080/axis/Calculator.jws"

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

258 Francisco Prieto Donate

xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)--> <wsdl:message name="subtractRequest"> <wsdl:part name="i1" type="xsd:int"/> <wsdl:part name="i2" type="xsd:int"/> </wsdl:message> <wsdl:message name="subtractResponse"> <wsdl:part name="subtractReturn" type="xsd:int"/> </wsdl:message> <wsdl:message name="addResponse"> <wsdl:part name="addReturn" type="xsd:int"/> </wsdl:message> <wsdl:message name="addRequest"> <wsdl:part name="i1" type="xsd:int"/> <wsdl:part name="i2" type="xsd:int"/> </wsdl:message> <wsdl:portType name="Calculator"> <wsdl:operation name="add" parameterOrder="i1 i2"> <wsdl:input message="impl:addRequest" name="addRequest"/> <wsdl:output message="impl:addResponse" name="addResponse"/> </wsdl:operation> <wsdl:operation name="subtract" parameterOrder="i1 i2"> <wsdl:input message="impl:subtractRequest" name="subtractRequest"/> <wsdl:output message="impl:subtractResponse" name="subtractResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CalculatorSoapBinding" type="impl:Calculator">

13. Guía de instalación

Francisco Prieto Donate 259

<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="add"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="addRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="addResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/Calculator.jws" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="subtract"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="subtractRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="subtractResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/Calculator.jws" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CalculatorService"> <wsdl:port binding="impl:CalculatorSoapBinding" name="Calculator"> <wsdlsoap:address location="http://localhost:8080/axis/Calculator.jws"/>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

260 Francisco Prieto Donate

</wsdl:port> </wsdl:service> </wsdl:definitions>

Los archivos JWS son una forma rápida de convertir las clases en servicios web, pero no siempre va a ser la mejor elección. Por un lado es necesario tener el código fuente (puede ser que queramos desplegar un servicio web y dispongamos de la clase precompilada pero no del código fuente). Por otro lado la configuración utilizada para indicar cómo se puede acceder al servicio es muy limitada: no se puede, por ejemplo, controlar manejadores que sean invocados cuando alguien utilice un servicio.

13.3.2.2 Despliegue utilizando WSDD

Para utilizar toda la flexibilidad que nos aporta Axis usaremos el “ Descriptor de Despliegue de Servicios Web” (WSDD). Un archivo WSDD es un archivo XML que describe cómo desplegar un servicio web. El descriptor de despliegue contiene un gran abanico de opciones a la hora de la publicación de servicios en Axis: es el encargado de informar al contenedor de servicios web XML de las particularidades del archivo WSDL y de la comunicación SOAP, y si fuera necesario también del formato del método remoto en que consiste el servicio web.

El descriptor de despliegue para el servicio básico mostrado arriba sería:

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="Calculadora" provider="java:RPC"> <parameter name="wsdlTargetNamespace" value="http://calculator.samples/"/> <parameter name="className" value="Calculator"/> <parameter name="allowedMethods" value="add"/> <parameter name="allowedMethods" value="subtract"/> </service> </deployment>

Este ejemplo es bastante sencillo. El elemento raíz de un archivo WSDD es <deployment>, indicando que estamos ante un WSDD de despliegue y especificando el espacio de nombres. El elemento <service> define precisamente el servicio a utilizar. Un servicio es una “ cadena objetivo” , que significa que puede contener uno o varios de estos elementos:

13. Guía de instalación

Francisco Prieto Donate 261

• Un flujo de entrada

• Un manejador (llamado proveedor)

• Un flujo de respuesta

En este caso, nuestro proveedor es java:RPC, el cual está integrado en Axis e indica que es un servicio Java RPC.

Necesitamos también indicarle al proveedor RPC que debe instanciar la clase correcta (en nuestro ejemplo, Calculator), y lo hacemos incluyendo etiquetas de parámetro <parameter>. Estas etiquetas le aportan al servicio una serie de parámetros para configurar el nombre de la clase y para indicarle al motor qué métodos públicos deben ser llamado vía SOAP (si queremos hacer públicos todos los métodos de la clase escribiremos un asterisco en el campo value).

Otra etiqueta interesante es <operation>, que permite definir parámetros sobre una operación determinada.

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="PurchaseService" provider="java:RPC" xmlns:ns="http://osmoticweb.com/PurchaseService/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <parameter name="className" value="com.osmoticweb.axisdemo.PurchaseService"/> <operation qname="ns:orderItem" returnType="xsd:boolean" returnQName="ns:orderItemResponse">

<parameter qname="pns:name" type="tns:string" /> </operation> </service> </deployment>

En el ejemplo anterior <operation> define una operación llamada orderItem que devuelve un elemento de tipo boolean llamado orderItemResponse, y toma como parámetro una cadena de caracteres de nombre name.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

262 Francisco Prieto Donate

También es recomendable crear un fichero para retirar el servicio web. Basta con hacer una versión reducida del archivo anterior, siendo en este caso el elemento raíz <undeployment>, como en el ejemplo siguiente:

<undeployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"> <service name="ElementService"/> </undeployment>

El lenguaje WSDD es muy potente y permite controlar muchos aspectos del servicio web, como administración remota, contador de llamadas, puertos, enlaces... sin embargo, para el desarrollo de este proyecto basta con conocer lo ya comentado.

Para desplegar el servicio web descrito por un archivo WSDD basta con escribir el siguiente comando:

java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService deploy.wsdd

Una vez hecho esto podremos ver el nuevo servicio al seleccionar “ View the list of deployed web services” en la página de inicio de Axis.

Los descriptores WSDD pueden contener también otra información acerca de los servicios, e indicar al motor SOAP que realice distintas operaciones. Por ejemplo, podríamos lanzar un servicio que cuente las veces que se ha visitado otro servicio, o incluso sería posible llevar a cabo una administración remota del servidor Axis.

13.3.2.3 Monitorización

Para poder ver los mensajes SOAP que se intercambian el cliente y el servidor se usará la aplicación TCPMonitor, que se ejecuta así:

java -cp %AXISCLASSPATH% org.apache.axis.utils.tcpmon

Para usarla debemos cambiar en nuestra aplicación el puerto al que accede el cliente. Por ejemplo, en vez del 8080 se sustituye por el 8081 y se lanza el monitor para que escuche en ese puerto. TCPMonitor actuará como intermediario, recibiendo los datos del cliente por el puerto 8081 y enviándoselos al servidor al puerto 8080 y viceversa, mientras refleja por pantalla el contenido de las comunicaciones.

13. Guía de instalación

Francisco Prieto Donate 263

Figura 13.8: Pantalla inicial de TCPMonitor

13.4 J2ME Wireless Toolkit 2.2

Java 2 Micro Edition Wireless Toolkit es un conjunto de herramientas que permite el desarrollo de aplicaciones inalámbricas basadas en CLDC y MIDP, diseñadas para ejecutarse en teléfonos móviles, PDA’s y otros dispositivos móviles.

Para instalarlo debemos descargar el archivo de instalación de la siguiente página: http://java.sun.com/products/sjwtoolkit/download-2_2.html, y ejecutarlo. Siguiendo las instrucciones, la instalación se completa en poco más de un minuto. La aplicación se instala en el directorio por defecto C:\WTK22.

Para comenzar el programa basta con ejecutar KToolbar, situado en C:\WTK22\bin\KToolbar.exe, o bien en el acceso directo creado por el instalador en

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

264 Francisco Prieto Donate

Inicio→ Programas → Wireless Toolkit 2.2 → KToolbar. El aspecto del programa es el siguiente:

Figura 13.9: Pantalla principal del J2ME Wireless Toolkit

Una vez abierto podemos visualizar y ejecutar los distintos proyectos de prueba para familiarizarnos con su funcionamiento, o bien crear nuestro proyecto especificando su nombre y su clase principal.

Al crear el nuevo proyecto se creará en el directorio C:\WTK22\apps un nuevo proyecto con la siguiente estructura de directorios:

• Bin - Contiene los ficheros de manifiesto y los ficheros .jad y .jar resultantes de la compilación de la aplicación en un paquete.

• Lib - Contiene las distintas librerías que debamos añadir al proyecto.

• Res - Contiene los ficheros necesarios para la aplicación, como ficheros de gráficos o cualquier otro tipo.

• Src - Contiene todos los ficheros .java que forman el código fuente de la aplicación.

13. Guía de instalación

Francisco Prieto Donate 265

Tras la primera compilación aparecerán tres nuevos directorios:

• Classes - Contiene el conjunto de clases resultado de la compilación.

• Tmpclasses - Contiene las clases temporales resultantes de la compilación.

• Tmplib - Contiene las librerías temporales resultantes de la compilación.

Para compilar el proyecto se selecciona la opción Project→ Build y la aplicación se encargará de obtener las clases necesarias y ubicarlas en los directorios correspondientes. Si queremos obtener un archivo .jar para mejorar la seguridad y facilitar el envío al dispositivo móvil habrá que seleccionar Project→ Package→ Create Package.

Una aplicación muy útil del Wireless Toolkit es el generador de stubs para los servicios web. Al seleccionar Project→ Stub generator nos preguntará la ruta del archivo WSDL que define al servicio y el paquete de salida donde se crearán las clases de stub.

Otra utilidad de este programa es la aplicación Memory Monitor. Al activarse mientras se realiza una emulación, presenta por pantalla un gráfico que representa el consumo de memoria que está realizando el MIDlet en ejecución.

Wireless Toolkit no proporciona ningún editor de código, para ello se usará NetBeans 5.5 con el módulo NetBeans Mobility Pack.

13.5 NetBeans IDE 5.5

NetBeans es un entorno de desarrollo Java gratuito y de código abierto. El paquete NetBeans Mobility Pack contiene los paquetes necesarios para programar dispositivos móviles usando J2ME, así como un emulador indispensable para hacer pruebas de funcionamiento.

El uso del entorno de desarrollo NetBeans IDE 5.5 con el módulo NetBeans Mobility Pack proporciona muchas ventajas, entre ellas:

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

266 Francisco Prieto Donate

• Editor de texto inteligente que detecta fallos en el código mientras se está escribiendo.

• Compilación y ejecución rápida del código usando un emulador propio.

• Integración con el J2ME Wireless Toolkit.

• Depurador de código.

• Creación automática de clientes JSR-172 a partir del archivo WSDL, ideal para testear el correcto funcionamiento de los servicios web.

El software puede ser descargado desde la siguiente dirección: http://www.netbeans.org/. La instalación del NetBeans IDE 5.5 es automática y no requiere de ningún ajuste especial. A continuación instalamos el NetBeans Mobility Pack. Una vez instalado se puede ejecutar con el acceso directo creado en el escritorio, mostrándonos la pantalla de bienvenida:

Figura 13.10: Pantalla principal de NetBeans IDE 5.5 con Mobility Pack

13. Guía de instalación

Francisco Prieto Donate 267

Todo código fuente debe estar enmarcado en un proyecto. Para crear un nuevo proyecto accedemos al menú File y se selecciona New Project, donde se nos presentará la siguiente pantalla:

Elegimos la opción Mobile Application marcada por defecto. Posteriormente se nos pedirá un nombre para el proyecto y otros datos referidos a la versión de CLDC y MIDP que se desea utilizar.

Cuando hayamos escrito los fichero podemos compilarlos (opción Build), ejecutarlos abriendo el emulador que trae integrado (opción Run) o depurarlo (opción Debug).

Otra utilidad de NetBeans IDE 5.5 con Mobility Pack que ya se ha comentado es la de generar de forma automática un cliente simple para un servicio web. Para conseguirlo basta con seleccionar File→New File, y buscar dentro de las plantillas de MIDP la que está marcada con J2ME Web Service Client. Nos pedirá que le demos un nombre y que especifiquemos la situación del archivo WSDL, la ruta en que se va a guardar el código generado y la versión del CLDC que deseamos. Tras unos segundos, y si el archivo WSDL es correcto, se obtiene el stub y una pequeña aplicación muy simple que permite llamar al servicio con los parámetros que deseemos.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

268 Francisco Prieto Donate

14. Planos de código

Francisco Prieto Donate 269

14 PLANOS DE CÓDIGO

14.1 Escenario kSOAP

Para el escenario en el que hemos utilizado la tecnología kSOAP, mostramos los planos de código utilizados para crear un servicio web, desplegarlo y acceder a él a través de un cliente móvil.

14.1.1 Servidor Web

Los tres archivos que se muestran a continuación se alojan en el servidor Apache Tomcat. El primero de los archivos es el servicio web propiamente dicho. Los dos siguientes son los archivos de despliegue y de anulación de despliegue.

• VideoKsoap.java

/************************************************ * Implementación del servicio web VideoKsoap. * * Esta clase contiene los métodos necesarios * * para comunicarse con el cliente móvil vía * * SOAP y con el servidor de vídeo a través del * * protocolo HTTP * ************************************************/ package ServVideoKsoap; import java.net.*; import java.io.*; public class VideoKsoap { final String ip = "127.0.0.1"; //IP del servidor final int puerto = 80; //Puerto del servidor /* Método accesible en el Servicio Web VideoKsoap. * Recibe el formato y el tamaño de la imagen * y devuelve un array de bytes */ public byte[] getImagenBase64(String formato, int tam) throws Exception{ byte[] datos = conectar(formato, tam); return (datos); } /* Método accesible en el Servicio Web VideoKsoap.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

270 Francisco Prieto Donate

* Recibe el formato y el tamaño de la imagen * y devuelve un array de enteros */ public int[] getImagenIntArray(String formato, int tam) throws Exception{ byte datos[] = null; int cadena[] = null; int longitud; datos = conectar(formato, tam); longitud=datos.length; // Pasamos cada byte a su valor entero correspondiente cadena = new int[longitud]; for (int i=0; i<longitud; i++) cadena[i]=(int)datos[i]; return (cadena); } /* Método no accesible en el servicio web VideoKsoap. * Realiza una petición al servidor de vídeo, solicitando * una imagen con un tamaño y formato determinados. */ public byte[] conectar(String formato, int tam) throws Exception{ InputStream is = null; DataInputStream dis = null; int len = 0; byte datos[] = null; // Hacemos la petición al servidor de vídeo URL url = new URL("http", ip, puerto, "/?format=" + formato + "?resize=" + tam + "*" + tam + "?" + getCalidad(formato)); HttpURLConnection conexion = (HttpURLConnection)url.openConnection(); int rc = conexion.getResponseCode(); if (rc != HttpURLConnection.HTTP_OK) { conexion.disconnect(); throw new Exception("Codigo de respuesta HTTP: " + rc); } // Comprobamos el tipo de archivo devuelto String tipo = conexion.getContentType(); if (!tipo.equals("image/png") && !tipo.equals("image/jpeg")) { throw new Exception("Se esperaba una imagen, " + "pero se ha recibido " + tipo); } len = conexion.getContentLength(); // Almacenamos la información recibida en un array de bytes if (len > 0) { is = conexion.getInputStream(); dis = new DataInputStream(is); datos = new byte [len]; dis.readFully(datos); }

14. Planos de código

Francisco Prieto Donate 271

// Cerramos el flujo de entrada if (dis != null) { dis.close(); dis = null; } // Cerramos la conexión if (conexion != null) { conexion.disconnect(); conexion = null; } return datos; } /* Método no accesible en el servicio web VideoKsoap. * Devuelve un parámetro que se añadirá a la URL de * conexión con el servidor de vídeo para indicar * la calidad de la imagen según el formato. */ public String getCalidad(String formato) { String cadena; if (formato == "jpg") cadena = "quality=50"; else if (formato == "png") cadena = "comp=max"; else cadena = ""; return cadena; } }

• Deploy.wsdd

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="VideoKsoap" provider="java:RPC"> <parameter name="wsdlTargetNamespace" value="http://video.samples/"/> <parameter name="className" value="ServVideoKsoap.VideoKsoap"/> <parameter name="allowedMethods" value="getImagenBase64 getImagenIntArray"/> </service> </deployment>

• Undeploy.wsdd

<undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="VideoKsoap"/>

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

272 Francisco Prieto Donate

</undeployment>

14.1.2 Cliente J2ME

A continuación mostramos el código fuente que conforma el cliente J2ME.

• ClienteVideo.java

/******************************************************** * Clase principal con el MIDlet que se ejecuta en el * * cliente móvil. Implementa todas las pantallas tipo * * Screen y el control de comandos. * ********************************************************/ package cliente; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class ClienteVideo extends MIDlet implements CommandListener { public ClienteVideo() { } /* Constantes */ public static final int TAM = 80; /* Variables */ public static String codificacion; public static String formato; public static String ip; public static String puerto; public static boolean fin; /* Comandos */ private Command okToFormDireccion; private Command okToListCodificacion; private Command okToImagen; private Command backToBienvenida; private Command backToFormDireccion; private Command backToListCodificacion; private Command backToListFormato; private Command exitCommand; /* Pantallas tipo Screen */ private Form formDireccion; private Form formResumen; private List listCodificacion; private List listFormato; /* Subtipos de Form */ private TextField textFieldIP; private TextField textFieldPuerto;

14. Planos de código

Francisco Prieto Donate 273

private StringItem stringResumen; /* Pantallas tipo Canvas */ public static Display display; public static Imagen pantallaImagen; private Bienvenida pantallaBienvenida; /* Método que arranca el Midlet */ public void startApp() { /* Inicializamos los comandos */ okToFormDireccion = new Command("Cont", Command.OK, 1); okToListCodificacion = new Command("Cont", Command.OK, 0); okToImagen = new Command("Cont", Command.OK, 1); backToBienvenida = new Command("Atras", Command.BACK, 1); backToFormDireccion = new Command("Atras", Command.BACK, 1); backToListCodificacion = new Command("Atras", Command.BACK, 1); backToListFormato = new Command("Atras", Command.BACK, 1); exitCommand = new Command("Salir", Command.EXIT, 1); /* Inicializamos las variables */ ip = "127.0.0.1"; puerto = "8080"; fin=false; pantallaImagen=null; /* Presentamos la pantalla de bienvenida */ display = Display.getDisplay(this); display.setCurrent(get_bienvenida()); } /* Métodos que inicializan cada una de las pantallas tipo Screen */ /* Pantalla en la que se elige la direccion IP y el puerto del servidor */ public Form get_formDireccion() { if (formDireccion == null) { textFieldIP = new TextField("Direccion IP: ", ip, 15, TextField.ANY); textFieldPuerto = new TextField("Puerto: ", puerto, 5, TextField.NUMERIC); formDireccion = new Form("Direccion", new Item[] { textFieldIP, textFieldPuerto }); formDireccion.addCommand(okToListCodificacion); formDireccion.addCommand(backToBienvenida); formDireccion.setCommandListener(this); } return formDireccion; } /* Pantalla en la que se elige la codificacion de la imagen. * Se puede elegien entre Base64 y array de enteros */ public List get_listCodificacion() { if (listCodificacion == null) { listCodificacion = new List("Codificacion", Choice.IMPLICIT,

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

274 Francisco Prieto Donate

new String[] { "Base64", "IntArray"}, null); listCodificacion.addCommand(backToFormDireccion); listCodificacion.setCommandListener(this); } return listCodificacion; } /* Pantalla en la que se elige el formato de la imagen (png o jpg) */ public List get_listFormato() { if (listFormato == null) { listFormato = new List("Formato de imagen", Choice.IMPLICIT, new String[] { "PNG", "JPG" }, null); listFormato.addCommand(backToListCodificacion); listFormato.setCommandListener(this); } return listFormato; } /* Pantalla de resumen con todas las opciones elegidas */ public Form get_formResumen() { stringResumen = new StringItem("","Serv: " + ip + ":" + puerto + "\n" + "Codif: " + codificacion + "\n" + "Formato: " + formato); formResumen = new Form("Preferencias"); formResumen.append(stringResumen); formResumen.addCommand(okToImagen); formResumen.addCommand(backToListFormato); formResumen.setCommandListener(this); return formResumen; } /* Métodos que inicializan cada una de las pantallas tipo Canvas */ /* Pantalla de bienvenida */ public Bienvenida get_bienvenida() { if (pantallaBienvenida == null) { pantallaBienvenida = new Bienvenida(); pantallaBienvenida.addCommand(okToFormDireccion); pantallaBienvenida.addCommand(exitCommand); pantallaBienvenida.setCommandListener(this); } return pantallaBienvenida; } /* Pantalla que presentará las imágenes */ public Imagen get_Imagen() { if (pantallaImagen == null) { pantallaImagen = new Imagen(); pantallaImagen.addCommand(exitCommand); pantallaImagen.setCommandListener(this); } return pantallaImagen; }

14. Planos de código

Francisco Prieto Donate 275

/* Acciones que se ejecutaran al activar un comando */ public void commandAction(Command command, Displayable displayable) { if (command == okToFormDireccion) { display.setCurrent(get_formDireccion()); } else if (command == okToListCodificacion) { ip = textFieldIP.getString(); puerto = textFieldPuerto.getString(); display.setCurrent(get_listCodificacion()); } else if (command == okToImagen) { display.setCurrent(get_Imagen()); (new Bucle()).start(); } else if (command == backToBienvenida) { display.setCurrent(get_bienvenida()); } else if (command == backToListCodificacion) { display.setCurrent(get_listCodificacion()); } else if (command == backToListFormato) { display.setCurrent(get_listFormato()); } else if (command == backToFormDireccion) { display.setCurrent(get_formDireccion()); } else if (displayable == listCodificacion && command == listCodificacion.SELECT_COMMAND) { switch (get_listCodificacion().getSelectedIndex()) { case 0: codificacion = "Base64"; display.setCurrent(get_listFormato()); break; case 1: codificacion = "IntArray"; display.setCurrent(get_listFormato()); break; } } else if (displayable == listFormato && command == listFormato.SELECT_COMMAND) { switch (get_listFormato().getSelectedIndex()) { case 0: formato = "png"; display.setCurrent(get_formResumen()); break; case 1: formato = "jpg"; display.setCurrent(get_formResumen());

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

276 Francisco Prieto Donate

break; } } else if (command == exitCommand) { exitMIDlet(); } } /* Acciones que se ejecutarán al terminar la aplicación */ public void exitMIDlet() { display.setCurrent(null); fin = true; destroyApp(true); notifyDestroyed(); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } }

• Bienvenida.java

/******************************************** * Clase que hereda de Canvas y representa * * la pantalla de bienvenida que se muestra * * al usuario al iniciarse la aplicación. * ********************************************/ package cliente; import javax.microedition.lcdui.*; public class Bienvenida extends Canvas { private int CanvasWidth; private int CanvasHeight; private Font fuente; private String cadena1; private String cadena2; private String cadena3; private String cadena4; public Bienvenida() { // Tipo de fuente utilizado fuente = null; // Texto de presentacion cadena1 = "PFC: Cliente J2ME"; cadena2 = "Versión kSOAP"; cadena3 = "Autor: F. Prieto"; cadena4 = "Tutor: A. Sierra";

14. Planos de código

Francisco Prieto Donate 277

// Altura y anchura de la pantalla del dispositivo CanvasWidth = getWidth(); CanvasHeight = getHeight(); } /* Método que representa por pantalla el mensaje de bienvenida.*/ public void paint(Graphics g) { // Tipo de letra negrita y tamaño medio fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); g.setFont(fuente); // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Escribimos las lineas de texto en negro centradas en la pantalla g.setColor(0); int x = CanvasWidth / 2; int y = CanvasHeight / 2 - 2*fuente.getHeight(); g.drawString(cadena1, x, y, Graphics.TOP|Graphics.HCENTER); g.drawString(cadena2, x, y+fuente.getHeight(), Graphics.TOP|Graphics.HCENTER); // Tipo de letra pequeña fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); g.setFont(fuente); g.drawString(cadena3, x, y+(3*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); g.drawString(cadena4, x, y+(4*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); } }

• Bucle.java

/***************************************************** * Clase que realiza peticiones al servidor web para * * obtener la imagen requerida. Las peticiones se * * repetirán cada cierto intervalo de tiempo * *****************************************************/ package cliente; import javax.microedition.lcdui.Alert; class Bucle extends Thread { private final static int intervalo = 1000; // Milisegundos

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

278 Francisco Prieto Donate

private String direccion = "http://" + ClienteVideo.ip + ":" + ClienteVideo.puerto + "/axis/services/VideoKsoap"; Bucle() { } /* Metodo que se encarga de hacer la peticion cada cierto * intervalo de tiempo y presentar la imagen por pantalla. */ public void run() { try{ do { // Dormimos entre peticiones do sleep(intervalo); while(Imagen.cerrojo || kSOAP.capturando); // Petición al servicio web kSOAP peticion = new kSOAP(); Imagen.datos = peticion.CapturaImagen(direccion); // Presentación por pantalla if (Imagen.datos != null) ClienteVideo.pantallaImagen.repaint(); else ClienteVideo.fin=true; } while (ClienteVideo.fin == false); } catch (InterruptedException e) { Alert a = new Alert("Error ", e.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); } } }

• Imagen.java

/******************************************************** * Clase que hereda de Canvas y representa la imagen * * recibida del servidor web. Si el formato es jpg, se * * decodifica utilizando la clase DecodificadorJPEG * ********************************************************/ package cliente; import javax.microedition.lcdui.*; public class Imagen extends Canvas { public static byte[] datos; private Image foto; private int CanvasWidth; private int CanvasHeight; private int centro_x; private int centro_y;

14. Planos de código

Francisco Prieto Donate 279

public static boolean cerrojo; private DecodificadorJPEG decod; int imagenARGB[]; public Imagen() { datos = null; // Calculamos el centro de la pantalla CanvasWidth = getWidth(); CanvasHeight = getHeight(); centro_x = (CanvasWidth - ClienteVideo.TAM) / 2; centro_y = (CanvasHeight - ClienteVideo.TAM) / 2; if(centro_x < 0) centro_x = 0; if(centro_y < 0) centro_y = 0; // Iniciamos la clase DecodificadorJPEG iniciaJPEG(); } void iniciaJPEG(){ if (ClienteVideo.formato == "jpg") { // Inicializo el decodificador JPEG decod = new DecodificadorJPEG(); decod.setAncho(ClienteVideo.TAM); decod.setAlto(ClienteVideo.TAM); } } /* Método que realiza la representación en pantalla de la imagen */ public void paint(Graphics g) { cerrojo = true; // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Presenta la imagen por pantalla if(datos != null){ int numBytes = datos.length; // Si el formato es png, representamos directamente if (ClienteVideo.formato != "jpg"){ foto = Image.createImage(datos,0,numBytes); } // Si el formato es jpg, utilizamos el decodificador else { // Crea el buffer ARGB para la imagen decodificada imagenARGB = new int[ClienteVideo.TAM*ClienteVideo.TAM]; // Decodifica en imagenARGB[] decod.decodifica(datos,imagenARGB, numBytes);

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

280 Francisco Prieto Donate

// Creamos la imagen foto = Image.createRGBImage(imagenARGB,ClienteVideo.TAM, ClienteVideo.TAM,false); } g.drawImage(foto, centro_x, centro_y, 0); } cerrojo = false; } }

• kSOAP.java

/********************************************************** * Clase que realiza la petición al servidor web mediante * * el protocolo SOAP utilizando la librería kSOAP. * **********************************************************/ package cliente; import java.util.*; import java.io.DataInputStream; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.Alert; import org.ksoap2.SoapEnvelope; import org.ksoap2.transport.HttpTransport; import org.ksoap2.serialization.*; import org.kobjects.base64.Base64; public class kSOAP { public static boolean capturando = false; HttpTransport ht; public kSOAP(){ } /* Metodo que recibe como parametro la peticion que hay que hacer al * servidor, y devuelve la imagen reconstruida que envia el servidor. */ byte[] CapturaImagen(String direccion) { Image foto = null; DataInputStream dis = null; byte data[]; try { capturando = true; Runtime.getRuntime().gc(); // Peticion al servidor web

14. Planos de código

Francisco Prieto Donate 281

//Creamos el SOAP Envelope SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); /* Creamos el objeto SOAP, indicando el * espacio de nombres, método y parámetros */ SoapObject client = new SoapObject( "urn:video.samples", "getImagen" + ClienteVideo.codificacion); client.addProperty("formato", new String(ClienteVideo.formato)); client.addProperty("tam", new Integer(ClienteVideo.TAM)); // Enviamos el sobre al servidor envelope.setOutputSoapObject(client); ht = new HttpTransport(direccion); ht.call("",envelope); // Si la codificación es Base64, devolvemos el array directamente if (ClienteVideo.codificacion == "Base64"){ data = Base64.decode(envelope.getResponse().toString()); } // Si la codificación es IntArray, pasamos los enteros a bytes else { Vector resObj = new Vector(); resObj =(Vector)envelope.getResponse(); int numBytes=resObj.size(); //Transformamos los enteros a bytes y los almacenamos en un array data = new byte[numBytes]; for (int j=0;j<numBytes;j++) data [j] = (byte)Integer.parseInt(resObj.elementAt(j).toString()); } capturando = false; return data; }catch(Exception exception) { Alert a = new Alert("Error E/S", exception.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); return null; } } }

• DecodificadorJPEG.java

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

282 Francisco Prieto Donate

/************************************************** * Clase que contiene los metodos necesarios para * * decodificar una imagen en formato JPEG. * **************************************************/ package cliente; public class DecodificadorJPEG { // Matrices private int matriz[][] = new int[8][8]; private int matrizY00[][] = new int[8][8]; private int matrizY01[][] = new int[8][8]; private int matrizY10[][] = new int[8][8]; private int matrizY11[][] = new int[8][8]; private int matrizCb[][] = new int[8][8]; private int matrizCr[][] = new int[8][8]; private int matrizResultado[][] = new int[8][8]; private double matrizIDCT[][] = new double[8][8]; private int orden[] = {0,0,0,1,1,0,2,0,1,1,0,2,0,3,1,2, 2,1,3,0,4,0,3,1,2,2,1,3,0,4,0,5, 1,4,2,3,3,2,4,1,5,0,6,0,5,1,4,2, 3,3,2,4,1,5,0,6,0,7,1,6,2,5,3,4, 4,3,5,2,6,1,7,0,7,1,6,2,5,3,4,4, 3,5,2,6,1,7,2,7,3,6,4,5,5,4,6,3, 7,2,7,3,6,4,5,5,4,6,3,7,4,7,5,6, 6,5,7,4,7,5,6,6,5,7,6,7,7,6,7,7}; // Luminancia Y private int matrizCuantizacionY[][] = new int[8][8]; private byte bitsYDC[] = new byte[17]; private byte huffvalYDC[] = new byte[500]; private int maxcodeYDC[] = new int[18]; private int mincodeYDC[] = new int[18]; private int valptrYDC[] = new int[18]; private int predY; private byte bitsYAC[] = new byte[17]; private byte huffvalYAC[] = new byte[500]; private int maxcodeYAC[] = new int[18]; private int mincodeYAC[] = new int[18]; private int valptrYAC[] = new int[18]; // Crominancia (tablas compartidas para Cb y Cr) private int matrizCuantizacionC[][] = new int[8][8]; private byte bitsCDC[] = new byte[18]; private byte huffvalCDC[] = new byte[500]; private int maxcodeCDC[] = new int[18]; private int mincodeCDC[] = new int[18]; private int valptrCDC[] = new int[18]; private byte bitsCAC[] = new byte[18]; private byte huffvalCAC[] = new byte[500]; private int maxcodeCAC[] = new int[18]; private int mincodeCAC[] = new int[18]; private int valptrCAC[] = new int[18]; private int predCb; private int predCr; private int maxcode[] = new int[18]; private int mincode[] = new int[18]; private int valptr[] = new int[18]; // Gestion del fichero

14. Planos de código

Francisco Prieto Donate 283

private byte fichero[]; private int offset; private int cntbit; private byte bytefichero; // Imagen private int ancho; private int alto; private int Hluminancia; private int Vluminancia; // Constructor de la clase public DecodificadorJPEG() { inicializaMatrizIDCT(); } /* * Para ajustar la variable "ancho" que indica el ancho de la imagen */ public void setAncho(int anch) { ancho = anch; } /* * Para ajustar la variable "alto" que indica el alto de la imagen */ public void setAlto(int alt) { alto = alt; } /* * Decodifica un fichero JPEG */ public int decodifica(byte [] entrada, int imagenARGB[], int longitud) { fichero = entrada; int mequeda; int leido2bytes; byte leido1byte; offset = 0; cntbit = 0; // BUCLE PRINCIPAL while (true) { leido2bytes = lee2bytes(); if (leido2bytes == 0xFFD8) { // cabecera comienzo de imagen } else if (leido2bytes == 0xFFC0) { // cabecera comienzo de frame offset += 2; leido1byte = fichero[offset++]; if (leido1byte != 8) { fichero = null; return 1; // Formato no reconocido

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

284 Francisco Prieto Donate

} alto = lee2bytes(); ancho = lee2bytes(); leido1byte = fichero[offset++]; if (leido1byte != 3) { fichero = null; return 1; // Formato no reconocido } offset++; leido1byte = fichero[offset++]; Hluminancia = (leido1byte & 0xF0) >> 4; Vluminancia = (leido1byte & 0x0F); if ((fichero[offset] != 0) || (fichero[offset+2] != 0x11) || (fichero[offset+3] != 1) || (fichero[offset+5] != 0x11) || (fichero[offset+6] != 1)) { fichero = null; return 1; // Formato no reconocido } offset += 7; } else if (leido2bytes > 0xFFE0) { // cabeceras reservadas mequeda = lee2bytes(); offset += (mequeda - 2); } else if (leido2bytes == 0xFFE0) { // cabecera JFIF mequeda = lee2bytes(); offset += (mequeda - 2); } else if (leido2bytes == 0xFFDB) { // cabecera tabla cuantizacion int coefs[] = new int[64]; mequeda = lee2bytes(); mequeda -= 2; do { leido1byte = fichero[offset++]; mequeda--; for (int k = 0; k < 64; k++) { coefs[k] = (fichero[offset++] & 255); mequeda--; } if (leido1byte == 0x00) { // es tabla de cuantizacion de luminancia rellenaZigzagCuantizacionY(coefs); } else if (leido1byte == 0x01) { // es tabla de cuantizacion de crominancia rellenaZigzagCuantizacionC(coefs); } } while (mequeda > 0); } else if (leido2bytes == 0xFFC4) { // cabecera Huffman mequeda = lee2bytes(); mequeda -= 2;

14. Planos de código

Francisco Prieto Donate 285

do { leido1byte = fichero[offset++]; mequeda--; if (leido1byte == 0x00) { // luminancia DC (YDC) for (int k = 1; k < 17; k++) { // rellena bitsYDC bitsYDC[k] = fichero[offset++]; mequeda--; } for (int k = 0; k < longhuffval(bitsYDC); k++) { // rellena huffvalYDC huffvalYDC[k] = fichero[offset++]; mequeda--; } // genero las tablas maxcode, mincode y valptr // correspondientes creaTablas(generaHUFFCODE(generaHUFFSIZE(bitsYDC)), bitsYDC); System.arraycopy(maxcode,0,maxcodeYDC,0,18); System.arraycopy(mincode,0,mincodeYDC,0,18); System.arraycopy(valptr,0,valptrYDC,0,18); } else if (leido1byte == 0x10) { // luminancia AC (YAC) for (int k = 1; k < 17; k++) { // rellena bitsYAC bitsYAC[k] = fichero[offset++]; mequeda--; } for (int k = 0; k < longhuffval(bitsYAC); k++) { // rellena huffvalYAC huffvalYAC[k] = fichero[offset++]; mequeda--; } // genero las tablas maxcode, mincode y valptr // correspondientes creaTablas(generaHUFFCODE(generaHUFFSIZE(bitsYAC)), bitsYAC); System.arraycopy(maxcode,0,maxcodeYAC,0,18); System.arraycopy(mincode,0,mincodeYAC,0,18); System.arraycopy(valptr,0,valptrYAC,0,18); } else if (leido1byte == 0x01) { // crominancia DC (CDC) for (int k = 1; k < 17; k++) { // rellena bitsCDC bitsCDC[k] = fichero[offset++]; mequeda--; } for (int k = 0; k < longhuffval(bitsCDC); k++) { // rellena huffvalCDC huffvalCDC[k] = fichero[offset++]; mequeda--; } // genero las tablas maxcode, mincode y valptr

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

286 Francisco Prieto Donate

// correspondientes creaTablas(generaHUFFCODE(generaHUFFSIZE(bitsCDC)), bitsCDC); System.arraycopy(maxcode,0,maxcodeCDC,0,18); System.arraycopy(mincode,0,mincodeCDC,0,18); System.arraycopy(valptr,0,valptrCDC,0,18); } else if (leido1byte == 0x11) { // crominancia AC (CAC) for (int k = 1; k < 17; k++) { // rellena bitsCAC bitsCAC[k] = fichero[offset++]; mequeda--; } for (int k = 0; k < longhuffval(bitsCAC); k++) { // rellena bitsCAC huffvalCAC[k] = fichero[offset++]; mequeda--; } // genero las tablas maxcode, mincode y valptr // correspondientes creaTablas(generaHUFFCODE(generaHUFFSIZE(bitsCAC)), bitsCAC); System.arraycopy(maxcode,0,maxcodeCAC,0,18); System.arraycopy(mincode,0,mincodeCAC,0,18); System.arraycopy(valptr,0,valptrCAC,0,18); } } while (mequeda != 0); } else if (leido2bytes == 0xFFD9) { // cabecera fin de imagen fichero = null; return 0; } else if (leido2bytes == 0xFFDA) { // cabecera comienzo de scan offset += 2; leido1byte = fichero[offset++]; if (leido1byte != 3) { fichero = null; return 1; } leido2bytes = lee2bytes(); if (leido2bytes != 0x0100) { fichero = null; return 1; } leido2bytes = lee2bytes(); if (leido2bytes != 0x0211) { fichero = null; return 1; } leido2bytes = lee2bytes();

14. Planos de código

Francisco Prieto Donate 287

if (leido2bytes != 0x0311) { fichero = null; return 1; } offset += 3; /* * Todo preparado aqui ya para decodificacion (no mas cabeceras) */ int indice = 0; predY = 0; predCb = 0; predCr= 0; for (int i = 0; i < alto/16; i++) { for (int k = 0; k < ancho/16; k++) { decodificaBloqueY(matrizY00); decodificaBloqueY(matrizY01); decodificaBloqueY(matrizY10); decodificaBloqueY(matrizY11); decodificaBloqueCb(); decodificaBloqueCr(); rellenaBloque(imagenARGB, matrizY00, matrizCb, matrizCr, indice, ancho, alto); rellenaBloque(imagenARGB, matrizY01, matrizCb, matrizCr, indice+8, ancho, alto); rellenaBloque(imagenARGB, matrizY10, matrizCb, matrizCr, indice+8*ancho, ancho, alto); rellenaBloque(imagenARGB, matrizY11, matrizCb, matrizCr, indice+8*ancho+8, ancho, alto); indice+=16; } indice += (alto*16)-ancho; } } else if (leido2bytes > 0xFF00) { mequeda = lee2bytes(); offset += (mequeda - 2); } } // fin while } /* * Rellena un bloque de 8x8 pixels dadas las matrices de 8x8 de Y,Cb y

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

288 Francisco Prieto Donate

* Cr y el indice en imagenARGB */ private void rellenaBloque(int imagenARGB[], int matrizY[][], int matrizCb[][], int matrizCr[][], int indice, int ancho, int alto) { int r, g, b; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { r = matrizY[i][j] + 1402*(matrizCr[i][j]-128)/1000; if (r > 255) { r = 255;} if (r < 0) { r = 0;} g = matrizY[i][j] - 34414*(matrizCb[i][j]-128)/100000 - 71414*(matrizCr[i][j]-128)/100000; if (g > 255) { g = 255;} if (g < 0) { g = 0;} b = matrizY[i][j] + 1772*(matrizCb[i][j]-128)/1000; if (b > 255) { b = 255;} if (b < 0) { b = 0;} imagenARGB[indice+(ancho*i)+j] = 65536*(r & 255) + 256*(g & 255) + (b & 255); } } } /* * Decodifica un bloque de 8x8 de Y y lo deja en "matrizYii" */ private void decodificaBloqueY(int matrizYii[][]) { int coefs[] = new int[64]; decodificaDC(coefs, predY, valptrYDC, mincodeYDC, maxcodeYDC,huffvalYDC); predY = coefs[0]; decodificaAC(coefs,valptrYAC,mincodeYAC,maxcodeYAC,huffvalYAC); rellenaZigzag(coefs); descuantizaMatriz(matrizCuantizacionY); inversaDCT(); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { matrizYii[i][j] = matrizResultado[i][j]; } } } /* * Decodifica un bloque de 8x8 de Cb y lo deja en "matrizCb" */ private void decodificaBloqueCb() { int coefs[] = new int[64]; decodificaDC(coefs, predCb, valptrCDC, mincodeCDC, maxcodeCDC, huffvalCDC); predCb = coefs[0]; decodificaAC(coefs,valptrCAC,mincodeCAC,maxcodeCAC,huffvalCAC);

14. Planos de código

Francisco Prieto Donate 289

rellenaZigzag(coefs); descuantizaMatriz(matrizCuantizacionC); inversaDCT(); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { matrizCb[i][j] = matrizResultado[i][j]; } } } /* * Decodifica un bloque de 8x8 de Cr y lo deja en "matrizCr */ private void decodificaBloqueCr() { int coefs[] = new int[64]; decodificaDC(coefs,predCr,valptrCDC,mincodeCDC,maxcodeCDC,huffvalCDC); predCr = coefs[0]; decodificaAC(coefs,valptrCAC,mincodeCAC,maxcodeCAC,huffvalCAC); rellenaZigzag(coefs); descuantizaMatriz(matrizCuantizacionC); inversaDCT(); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { matrizCr[i][j] = matrizResultado[i][j]; } } } /* * Calcula la DCT inversa de la matriz "matriz" y deja el resultado en * "matrizResultado" */ private void inversaDCT() { double temp[][] = new double[8][8]; double temp1; for (int i=0; i<8; i++) { for (int j=0; j<8; j++) { temp[i][j] = 0.0; for (int k=0; k<8; k++) { temp[i][j] += matriz[i][k] * matrizIDCT[k][j]; } } } for (int i=0; i<8; i++) { for (int j=0; j<8; j++) { temp1 = 0.0; for (int k=0; k<8; k++) { temp1 += matrizIDCT[k][i] * temp[k][j];

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

290 Francisco Prieto Donate

} temp1 += 128.0; if (temp1 < 0) { matrizResultado[i][j] = 0; } else if (temp1 > 255) { matrizResultado[i][j] = 255; } else { matrizResultado[i][j] = (int)Math.ceil(temp1); } } } } /* * Inicializa la matriz de coeficientes fijos para el calculo de la * DCT inversa */ private void inicializaMatrizIDCT() { for (int i = 0; i < 8; i++) { double nn = (double)(8); matrizIDCT[0][i] = 1.0 / Math.sqrt(nn); } for (int i = 1; i < 8; i++) { for (int j = 0; j < 8; j++) { double jj = (double)j; double ii = (double)i; matrizIDCT[i][j] = Math.sqrt(2.0/8.0) * Math.cos(((2.0 * jj + 1.0) * ii * Math.PI) / (2.0 * 8.0)); } } } /* * Descuantiza "matriz" con los coeficientes de la matriz * "matrizCuantizacion" */ private void descuantizaMatriz(int matrizCuantizacion[][]) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { matriz[i][j] *= matrizCuantizacion[i][j]; } } } /* * Devuelve la longitud que tendra la HUFFVAL[] correspondiente a una * BITS[] determinada */

14. Planos de código

Francisco Prieto Donate 291

private int longhuffval(byte bits[]) { int longitud = 0; for (int k = 1; k < 17; k++) { longitud += (bits[k] & 255); } return longitud; } /* * Genera la tabla "HUFFSIZE" a partir de la tabla "BITS" dada */ private int[] generaHUFFSIZE(byte bits[]) { int[] huffsize = new int[500]; int k = 0; for (int clen = 1;clen <= 16; clen++) { for (int i=1; i<= (bits[clen] & 255); i++) { huffsize[k++] = clen; } } huffsize[k] = 0; return huffsize; } /* * Genera la tabla "HUFFCODE" a partir de la tabla "HUFFSIZE" dada */ private int[] generaHUFFCODE(int huffsize[]) { int[] huffcode = new int[500]; int k=0, code=0, si=huffsize[0]; while (huffsize[k] != 0) { while (huffsize[k] == si) { huffcode[k++] = code; code++; } code <<= 1; si++; } return huffcode; } /* * Extiende V codificado en complemento a 2 en Tbits a precision de * 32bit (int) */ private int extend(int v, int t) { int aux = 1; aux <<= (t-1); if (v < aux) { aux = (-1 << t) + 1; v = v + aux; } return v; }

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

292 Francisco Prieto Donate

/* * Devuelve un int con el siguiente bit leido del fichero * El fichero en fichero[] y "offset" indica por donde se va leyendo * "cntbit" indica dentro del byte por el bit que vamos * "bytefichero" contiene siempre el ultimo byte recibido */ private int siguienteBit() { if (cntbit == 0) { bytefichero = fichero[offset++]; cntbit = 8; if (bytefichero == -1) { byte bytefichero2 = fichero[offset++]; if (bytefichero2 != 0) { if (bytefichero2 == 123) { System.out.println("marca DNL"); return 0; } // procesa marca DNL else { System.out.println("Error!!"); return 0; } // error } } } int bit = (bytefichero & 128) >> 7; cntbit--; bytefichero <<= 1; return bit; } /* * Devuelve un int con los n siguientes bits extraidos del fichero */ private int recibe(int n) { int i = 0, v= 0; while (i != n) { i++; v = (v << 1) + siguienteBit(); } return v; } /* * Crea las tablas MINCODE, MAXCODE y VALPTR a partir de HUFFCODE y BITS */ private void creaTablas(int huffcode[], byte bits[]) { int p = 0; for (int l=1; l<=16; l++) { if (bits[l] != 0) { valptr[l] = p; mincode[l] = huffcode[p]; p += (bits[l] & 255); maxcode[l] = huffcode[p-1];

14. Planos de código

Francisco Prieto Donate 293

} else { maxcode[l] = -1; } maxcode[17] = -1; } } /* * Decodifica un valor byte del fichero codificado por tablas de Huffman */ private byte decode(int valptr[], int mincode[], int maxcode[], byte huffval[]) { int i = 1, code = siguienteBit(); while (code > maxcode[i]) { i++; code = (code << 1) + siguienteBit(); } int j = valptr[i]; j = j + code - mincode[i]; return huffval[j]; } /* * Decodifica el coeficiente DC y lo deja en la primera posición * del array dado "coefs[]" */ private void decodificaDC(int coefs[], int pred, int valptr[], int mincode[], int maxcode[], byte huffval[]) { byte t = decode(valptr, mincode, maxcode, huffval); coefs[0] = extend(recibe((t & 255)), t); coefs[0] += pred; } /* * Decodifica los 63 coeficientes AC y los deja en linea en el array * dado "coefs[]" */ private void decodificaAC(int coefs[], int valptr[], int mincode[], int maxcode[], byte huffval[]) { int k = 1, ssss, rrrr, v; byte rs; // pone a 0 todos los coeficientes AC para empezar for (int i = 1; i < 64; i++) { coefs[i] = 0; } while (true) { rs = decode(valptr, mincode, maxcode, huffval); ssss = rs & 15;

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

294 Francisco Prieto Donate

rrrr = rs & 255; rrrr >>>= 4; if (ssss == 0) { if (rrrr != 15) { return; } k += 16; } else { k += rrrr; coefs[k] = extend(recibe(ssss), ssss); if (k == 63) { return; } k++; } } } /* * Dada una lista de ints "coefs[]" rellena "matriz[][]" poniendo estos * coefs en zig-zag */ private void rellenaZigzag(int coefs[]) { for (int k = 0; k < 64; k++) { matriz[orden[2*k]][orden[(2*k)+1]] = coefs[k]; } } /* * Dada una lista de ints "coefs[]" rellena "matrizCuantizacionY[][]" * poniendo estos coefs en zig-zag */ private void rellenaZigzagCuantizacionY(int coefs[]) { for (int k = 0; k < 64; k++) { matrizCuantizacionY[orden[2*k]][orden[(2*k)+1]] = coefs[k]; } } /* * Dada una lista de ints "coefs[]" rellena "matrizCuantizacionC[][]" * poniendo estos coefs en zig-zag */ private void rellenaZigzagCuantizacionC(int coefs[]) { for (int k = 0; k < 64; k++) { matrizCuantizacionC[orden[2*k]][orden[(2*k)+1]] = coefs[k]; } } /*

14. Planos de código

Francisco Prieto Donate 295

* Devuelve un int con el valor de los 2 bytes siguientes leidos de * fichero[] (MSB primero) * (los dos bytes son tratados como un solo valor de 16bits) */ private int lee2bytes() { byte b1 = fichero[offset++]; byte b2 = fichero[offset++]; int v = (b1 & 255) * 256 + (b2 & 255); return v; } // Fin de la clase DecodificadorJPEG }

14.2 Escenario JSR-172

Para el escenario en el que hemos utilizado la tecnología JSR-172, mostramos los planos de código utilizados para crear un servicio web, desplegarlo y acceder a él a través de un cliente móvil.

14.2.1 Servidor web

Los tres archivos que se muestran a continuación se alojan en el servidor Apache Tomcat. El primero de los archivos es el servicio web propiamente dicho. Los dos siguientes son los archivos de despliegue y de anulación de despliegue.

• VideoJSR.java

/************************************************ * Implementación del servicio web VideoJSR. * * Esta clase contiene los métodos necesarios * * para comunicarse con el cliente móvil vía * * SOAP y con el servidor de vídeo a través del * * protocolo HTTP * ************************************************/ package ServVideoJSR; import java.net.*; import java.io.*; import org.apache.axis.encoding.Base64; public class VideoJSR { final String ip = "127.0.0.1"; //IP del servidor

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

296 Francisco Prieto Donate

final int puerto = 80; //Puerto del servidor /* Método accesible en el Servicio Web VideoKsoap. * Recibe el formato y el tamaño de la imagen * y devuelve un array de bytes */ public String getImagenBase64(String formato, int tam) throws Exception{ byte[] datos = conectar(formato, tam); return (Base64.encode(datos)); } /* Método accesible en el Servicio Web VideoKsoap. * Recibe el formato y el tamaño de la imagen * y devuelve un array de enteros */ public int[] getImagenIntArray(String formato, int tam) throws Exception{ byte datos[] = null; int cadena[] = null; int longitud; datos = conectar(formato, tam); longitud=datos.length; // Pasamos cada byte a su valor entero correspondiente cadena = new int[longitud]; for (int i=0; i<longitud; i++) cadena[i]=(int)datos[i]; return cadena; } /* Método no accesible en el servicio web VideoKsoap. * Realiza una petición al servidor de vídeo, solicitando * una imagen con un tamaño y formato determinados. */ public byte[] conectar(String formato, int tam) throws Exception{ InputStream is = null; DataInputStream dis = null; int len = 0; byte datos[] = null; // Hacemos la petición al servidor de vídeo URL url = new URL("http", ip, puerto, "/?format=" + formato + "?resize=" + tam + "*" + tam + "?" + getCalidad(formato)); HttpURLConnection conexion = (HttpURLConnection)url.openConnection(); int rc = conexion.getResponseCode(); if (rc != HttpURLConnection.HTTP_OK) { conexion.disconnect(); throw new Exception("Codigo de respuesta HTTP: " + rc); } // Comprobamos el tipo de archivo devuelto String tipo = conexion.getContentType();

14. Planos de código

Francisco Prieto Donate 297

if (!tipo.equals("image/png") && !tipo.equals("image/jpeg")) { throw new Exception("Se esperaba una imagen, " + "pero se ha recibido " + tipo); } len = conexion.getContentLength(); // Almacenamos la información recibida en un array de bytes if (len > 0) { is = conexion.getInputStream(); dis = new DataInputStream(is); datos = new byte [len]; dis.readFully(datos); } // Cerramos el flujo de entrada if (dis != null) { dis.close(); dis = null; } // Cerramos la conexión if (conexion != null) { conexion.disconnect(); conexion = null; } return datos; } /* Método no accesible en el servicio web VideoKsoap. * Devuelve un parámetro que se añadirá a la URL de * conexión con el servidor de vídeo para indicar * la calidad de la imagen según el formato. */ public String getCalidad(String formato) { String cadena; if (formato == "jpg") cadena = "quality=50"; else if (formato == "png") cadena = "comp=max"; else cadena = ""; return cadena; } }

• Deploy.wsdd

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="VideoJSR" provider="java:RPC" style="wrapped" use="literal">

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

298 Francisco Prieto Donate

<parameter name="wsdlTargetNamespace" value="http://video.samples/"/> <parameter name="className" value="ServVideoJSR.VideoJSR"/> <operation name="getImagenBase64" qname="operNS:getImagenBase64" xmlns:operNS="http://video.samples/" returnQName="retNS:getImagenBase64Result" xmlns:retNS="http://video.samples/" returnType="rtns:string" xmlns:rtns="http://www.w3.org/2001/XMLSchema" > <parameter qname="pns:formato" xmlns:pns="http://video.samples/" type="tns:string" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> <parameter qname="pns:tam" xmlns:pns="http://video.samples/" type="tns:int" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> </operation> <operation name="getImagenIntArray" qname="operNS:getImagenIntArray" xmlns:operNS="http://video.samples/" returnQName="retNS:getImagenIntArrayResult" xmlns:retNS="http://video.samples/" returnType="rtns:int[]" xmlns:rtns="http://www.w3.org/2001/XMLSchema" > <parameter qname="pns:formato" xmlns:pns="http://video.samples/" type="tns:string" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> <parameter qname="pns:tam" xmlns:pns="http://video.samples/" type="tns:int" xmlns:tns="http://www.w3.org/2001/XMLSchema"/> </operation> <parameter name="allowedMethods" value="getImagenBase64 getImagenIntArray"/> </service> </deployment>

• Undeploy.wsdd

<undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="VideoJSR"/> </undeployment>

14.2.2 Cliente J2ME

A continuación mostramos el código fuente que conforma el cliente J2ME. Tras los ficheros correspondientes al programa se adjuntan también los correspondientes al

14. Planos de código

Francisco Prieto Donate 299

stub generado automáticamente. También se omite el código fuente del archivo DecodofocadorJPEG.java, ya que resulta demasiado extenso y es idéntico al utilizado en el escenario kSOAP.

• ClienteVideo.java

/******************************************************** * Clase principal con el MIDlet que se ejecuta en el * * cliente móvil. Implementa todas las pantallas tipo * * Screen y el control de comandos. * ********************************************************/ package cliente; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class ClienteVideo extends MIDlet implements CommandListener { public ClienteVideo() { } /* Constantes */ public static final int TAM = 80; /* Variables */ public static String codificacion; public static String formato; public static boolean fin; /* Comandos */ private Command okToListCodificacion; private Command okToImagen; private Command backToBienvenida; private Command backToListCodificacion; private Command backToListFormato; private Command exitCommand; /* Pantallas tipo Screen */ private Form formResumen; private List listCodificacion; private List listFormato; /* Subtipos de Form */ private StringItem stringResumen; /* Pantallas tipo Canvas */ public static Display display; public static Imagen pantallaImagen; private Bienvenida pantallaBienvenida; /* Método que arranca el Midlet */ public void startApp() { /* Inicializamos los comandos */ okToListCodificacion = new Command("Cont", Command.OK, 0);

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

300 Francisco Prieto Donate

okToImagen = new Command("Cont", Command.OK, 1); backToBienvenida = new Command("Atras", Command.BACK, 1); backToListCodificacion = new Command("Atras", Command.BACK, 1); backToListFormato = new Command("Atras", Command.BACK, 1); exitCommand = new Command("Salir", Command.EXIT, 1); /* Inicializamos las variables */ fin=false; pantallaImagen=null; /* Presentamos la pantalla de bienvenida */ display = Display.getDisplay(this); display.setCurrent(get_bienvenida()); } /* Métodos que inicializan cada una de las pantallas tipo Screen */ /* Pantalla en la que se elige la codificacion de la imagen. * Se puede elegien entre Base64 y array de enteros */ public List get_listCodificacion() { if (listCodificacion == null) { listCodificacion = new List("Codificacion", Choice.IMPLICIT, new String[] { "Base64", "IntArray"}, null); listCodificacion.addCommand(backToBienvenida); listCodificacion.setCommandListener(this); } return listCodificacion; } /* Pantalla en la que se elige el formato de la imagen (png o jpg) */ public List get_listFormato() { if (listFormato == null) { listFormato = new List("Formato de imagen", Choice.IMPLICIT, new String[] { "PNG", "JPG" }, null); listFormato.addCommand(backToListCodificacion); listFormato.setCommandListener(this); } return listFormato; } /* Pantalla de resumen con todas las opciones elegidas */ public Form get_formResumen() { stringResumen = new StringItem("", "Codif: " + codificacion + "\n" + "Formato: " + formato); formResumen = new Form("Preferencias"); formResumen.append(stringResumen); formResumen.addCommand(okToImagen); formResumen.addCommand(backToListFormato); formResumen.setCommandListener(this); return formResumen; }

14. Planos de código

Francisco Prieto Donate 301

/* Métodos que inicializan cada una de las pantallas tipo Canvas */ /* Pantalla de bienvenida */ public Bienvenida get_bienvenida() { if (pantallaBienvenida == null) { pantallaBienvenida = new Bienvenida(); pantallaBienvenida.addCommand(okToListCodificacion); pantallaBienvenida.addCommand(exitCommand); pantallaBienvenida.setCommandListener(this); } return pantallaBienvenida; } /* Pantalla que presentará las imágenes */ public Imagen get_Imagen() { if (pantallaImagen == null) { pantallaImagen = new Imagen(); pantallaImagen.addCommand(exitCommand); pantallaImagen.setCommandListener(this); } return pantallaImagen; } /* Acciones que se ejecutaran al activar un comando */ public void commandAction(Command command, Displayable displayable) { if (command == okToListCodificacion) { display.setCurrent(get_listCodificacion()); } else if (command == okToImagen) { display.setCurrent(get_Imagen()); (new Bucle()).start(); } else if (command == backToBienvenida) { display.setCurrent(get_bienvenida()); } else if (command == backToListCodificacion) { display.setCurrent(get_listCodificacion()); } else if (command == backToListFormato) { display.setCurrent(get_listFormato()); } else if (displayable == listCodificacion && command == listCodificacion.SELECT_COMMAND) { switch (get_listCodificacion().getSelectedIndex()) { case 0: codificacion = "Base64"; display.setCurrent(get_listFormato()); break; case 1: codificacion = "IntArray";

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

302 Francisco Prieto Donate

display.setCurrent(get_listFormato()); break; } } else if (displayable == listFormato && command == listFormato.SELECT_COMMAND) { switch (get_listFormato().getSelectedIndex()) { case 0: formato = "png"; display.setCurrent(get_formResumen()); break; case 1: formato = "jpg"; display.setCurrent(get_formResumen()); break; } } else if (command == exitCommand) { exitMIDlet(); } } /* Acciones que se ejecutarán al terminar la aplicación */ public void exitMIDlet() { display.setCurrent(null); fin = true; destroyApp(true); notifyDestroyed(); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } }

• Bienvenida.java

/******************************************** * Clase que hereda de Canvas y representa * * la pantalla de bienvenida que se muestra * * al usuario al iniciarse la aplicación. * ********************************************/ package cliente; import javax.microedition.lcdui.*; public class Bienvenida extends Canvas { private int CanvasWidth; private int CanvasHeight; private Font fuente;

14. Planos de código

Francisco Prieto Donate 303

private String cadena1; private String cadena2; private String cadena3; private String cadena4; public Bienvenida() { // Tipo de fuente utilizado fuente = null; // Texto de presentacion cadena1 = "PFC: Cliente J2ME"; cadena2 = "Versión JSR-172"; cadena3 = "Autor: F. Prieto"; cadena4 = "Tutor: A. Sierra"; // Altura y anchura de la pantalla del dispositivo CanvasWidth = getWidth(); CanvasHeight = getHeight(); } /* Método que representa por pantalla el mensaje de bienvenida.*/ public void paint(Graphics g) { // Tipo de letra negrita y tamaño medio fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); g.setFont(fuente); // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Escribimos las lineas de texto en negro centradas en la pantalla g.setColor(0); int x = CanvasWidth / 2; int y = CanvasHeight / 2 - 2*fuente.getHeight(); g.drawString(cadena1, x, y, Graphics.TOP|Graphics.HCENTER); g.drawString(cadena2, x, y+fuente.getHeight(), Graphics.TOP|Graphics.HCENTER); // Tipo de letra pequeña fuente = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); g.setFont(fuente); g.drawString(cadena3, x, y+(3*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); g.drawString(cadena4, x, y+(4*fuente.getHeight()), Graphics.TOP|Graphics.HCENTER); } }

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

304 Francisco Prieto Donate

• Bucle.java

/***************************************************** * Clase que realiza peticiones al servidor web para * * obtener la imagen requerida. Las peticiones se * * repetirán cada cierto intervalo de tiempo * *****************************************************/ package cliente; import javax.microedition.lcdui.Alert; class Bucle extends Thread { private final static int intervalo = 1000; // Milisegundos Bucle() { } /* Metodo que se encarga de hacer la peticion cada cierto * intervalo de tiempo y presentar la imagen por pantalla. */ public void run() { try{ do { // Dormimos entre peticiones do sleep(intervalo); while(Imagen.cerrojo || JSR172.capturando); // Petición al servicio web JSR172 peticion = new JSR172(); Imagen.datos = peticion.CapturaImagen(); // Presentación por pantalla if (Imagen.datos != null) ClienteVideo.pantallaImagen.repaint(); else ClienteVideo.fin=true; } while (ClienteVideo.fin == false); } catch (InterruptedException e) { Alert a = new Alert("Error ", e.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); } } }

• Imagen.java

/******************************************************** * Clase que hereda de Canvas y representa la imagen * * recibida del servidor web. Si el formato es jpg, se * * decodifica utilizando la clase DecodificadorJPEG *

14. Planos de código

Francisco Prieto Donate 305

********************************************************/ package cliente; import javax.microedition.lcdui.*; public class Imagen extends Canvas { public static byte[] datos; private Image foto; private int CanvasWidth; private int CanvasHeight; private int centro_x; private int centro_y; public static boolean cerrojo; private DecodificadorJPEG decod; int imagenARGB[]; public Imagen() { datos = null; // Calculamos el centro de la pantalla CanvasWidth = getWidth(); CanvasHeight = getHeight(); centro_x = (CanvasWidth - ClienteVideo.TAM) / 2; centro_y = (CanvasHeight - ClienteVideo.TAM) / 2; if(centro_x < 0) centro_x = 0; if(centro_y < 0) centro_y = 0; // Iniciamos la clase DecodificadorJPEG iniciaJPEG(); } void iniciaJPEG(){ if (ClienteVideo.formato == "jpg") { // Inicializo el decodificador JPEG decod = new DecodificadorJPEG(); decod.setAncho(ClienteVideo.TAM); decod.setAlto(ClienteVideo.TAM); } } /* Método que realiza la representación en pantalla de la imagen */ public void paint(Graphics g) { cerrojo = true; // Borramos la pantalla pintandola de blanco g.setColor(0xffffff); g.fillRect(0, 0, CanvasWidth, CanvasHeight); // Presenta la imagen por pantalla if(datos != null){ int numBytes = datos.length; // Si el formato es png, representamos directamente if (ClienteVideo.formato != "jpg"){

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

306 Francisco Prieto Donate

foto = Image.createImage(datos,0,numBytes); } // Si el formato es jpg, utilizamos el decodificador else { // Crea el buffer ARGB para la imagen decodificada imagenARGB = new int[ClienteVideo.TAM*ClienteVideo.TAM]; // Decodifica en imagenARGB[] decod.decodifica(datos,imagenARGB, numBytes); // Creamos la imagen foto = Image.createRGBImage(imagenARGB,ClienteVideo.TAM, ClienteVideo.TAM,false); } g.drawImage(foto, centro_x, centro_y, 0); } cerrojo = false; } }

• JSR172.java

/******************************************************************** * Clase que realiza la petición al servidor web mediante el * * protocolo SOAP utilizando la librería la especificación JSR-172 * ********************************************************************/ package cliente; import java.io.DataInputStream; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.Alert; import org.kobjects.base64.Base64; public class JSR172 { public static boolean capturando = false; protected static cliente.stub.VideoJSR_Stub proxy_VideoJSR_Stub; public JSR172(){ // Instanciamos el stub proxy_VideoJSR_Stub = new cliente.stub.VideoJSR_Stub(); } /* Metodo que recibe como parametro la peticion que hay que hacer al * servidor, y devuelve la imagen reconstruida que envia el servidor. */

14. Planos de código

Francisco Prieto Donate 307

byte[] CapturaImagen() { Image foto = null; DataInputStream dis = null; byte data[]; try { capturando = true; Runtime.getRuntime().gc(); // Peticion al servidor web // Si la codificación es Base64, pasamos el String a array de bytes if (ClienteVideo.codificacion == "Base64"){ /* Hacemos la petición al servidor web invocando * el método correspondiente del stub */ String cadena = proxy_VideoJSR_Stub.getImagenBase64(ClienteVideo.formato,ClienteVideo.TAM); /* JSR-172 no codifica los arrays de bytes a Base64, * de modo que tenemos que forzar la decodificación */ data = Base64.decode(cadena); } // Si la codificación es IntArray, pasamos los enteros a bytes else { /* Hacemos la petición al servidor web invocando * el método correspondiente del stub */ int cadena[] = proxy_VideoJSR_Stub.getImagenIntArray(ClienteVideo.formato,ClienteVideo.TAM); int numBytes = cadena.length; //Transformamos los enteros a bytes y los almacenamos en un array data = new byte[numBytes]; for (int j=0;j<numBytes;j++) data [j] = (byte)cadena[j]; } capturando = false; return data; }catch(Exception exception) { Alert a = new Alert("Error E/S", exception.toString(), null, null); a.setTimeout(Alert.FOREVER); ClienteVideo.display.setCurrent(a); return null; } } }

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

308 Francisco Prieto Donate

14.2.3 Stub del cliente J2ME

• VideoJSR_Stub.java

// This class was generated by 172 StubGenerator. // Contents subject to change without notice. // @generated package cliente.stub; import javax.xml.rpc.JAXRPCException; import javax.xml.namespace.QName; import javax.microedition.xml.rpc.Operation; import javax.microedition.xml.rpc.Type; import javax.microedition.xml.rpc.ComplexType; import javax.microedition.xml.rpc.Element; public class VideoJSR_Stub implements cliente.stub.VideoJSR, javax.xml.rpc.Stub { private String[] _propertyNames; private Object[] _propertyValues; public VideoJSR_Stub() { _propertyNames = new String[] {ENDPOINT_ADDRESS_PROPERTY}; _propertyValues = new Object[] {"http://127.0.0.1:8080/axis/services/VideoJSR"}; } public void _setProperty(String name, Object value) { int size = _propertyNames.length; for (int i = 0; i < size; ++i) { if (_propertyNames[i].equals(name)) { _propertyValues[i] = value; return; } } // Need to expand our array for a new property String[] newPropNames = new String[size + 1]; System.arraycopy(_propertyNames, 0, newPropNames, 0, size); _propertyNames = newPropNames; Object[] newPropValues = new Object[size + 1]; System.arraycopy(_propertyValues, 0, newPropValues, 0, size); _propertyValues = newPropValues; _propertyNames[size] = name; _propertyValues[size] = value; } public Object _getProperty(String name) { for (int i = 0; i < _propertyNames.length; ++i) {

14. Planos de código

Francisco Prieto Donate 309

if (_propertyNames[i].equals(name)) { return _propertyValues[i]; } } if (ENDPOINT_ADDRESS_PROPERTY.equals(name) || USERNAME_PROPERTY.equals(name) || PASSWORD_PROPERTY.equals(name)) { return null; } if (SESSION_MAINTAIN_PROPERTY.equals(name)) { return new java.lang.Boolean(false); } throw new JAXRPCException("Stub does not recognize property: "+name); } protected void _prepOperation(Operation op) { for (int i = 0; i < _propertyNames.length; ++i) { op.setProperty(_propertyNames[i], _propertyValues[i].toString()); } } // // Begin user methods // public java.lang.String getImagenBase64(java.lang.String formato, int tam) throws java.rmi.RemoteException { // Copy the incoming values into an Object array if needed. Object[] inputObject = new Object[2]; inputObject[0] = formato; inputObject[1] = new java.lang.Integer(tam); Operation op = Operation.newInstance(_qname_getImagenBase64, _type_getImagenBase64, _type_getImagenBase64Response); _prepOperation(op); op.setProperty(Operation.SOAPACTION_URI_PROPERTY, ""); Object resultObj; try { resultObj = op.invoke(inputObject); } catch (JAXRPCException e) { Throwable cause = e.getLinkedCause(); if (cause instanceof java.rmi.RemoteException) { throw (java.rmi.RemoteException) cause; } throw e; } java.lang.String result; // Convert the result into the right Java type. // Unwrapped return value Object getImagenBase64ResultObj = ((Object[])resultObj)[0]; result = (java.lang.String)getImagenBase64ResultObj; return result; } public int[] getImagenIntArray(java.lang.String formato, int tam) throws java.rmi.RemoteException {

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

310 Francisco Prieto Donate

// Copy the incoming values into an Object array if needed. Object[] inputObject = new Object[2]; inputObject[0] = formato; inputObject[1] = new java.lang.Integer(tam); Operation op = Operation.newInstance(_qname_getImagenIntArray, _type_getImagenIntArray, _type_getImagenIntArrayResponse); _prepOperation(op); op.setProperty(Operation.SOAPACTION_URI_PROPERTY, ""); Object resultObj; try { resultObj = op.invoke(inputObject); } catch (JAXRPCException e) { Throwable cause = e.getLinkedCause(); if (cause instanceof java.rmi.RemoteException) { throw (java.rmi.RemoteException) cause; } throw e; } int[] result; // Convert the result into the right Java type. // Unwrapped return value Object getImagenIntArrayResultObj = ((Object[])resultObj)[0]; result = (int[]) getImagenIntArrayResultObj; return result; } // // End user methods // protected static final QName _qname_formato = new QName("http://video.samples/", "formato"); protected static final QName _qname_getImagenBase64 = new QName("http://video.samples/", "getImagenBase64"); protected static final QName _qname_getImagenBase64Response = new QName("http://video.samples/", "getImagenBase64Response"); protected static final QName _qname_getImagenBase64Result = new QName("http://video.samples/", "getImagenBase64Result"); protected static final QName _qname_getImagenIntArray = new QName("http://video.samples/", "getImagenIntArray"); protected static final QName _qname_getImagenIntArrayResponse = new QName("http://video.samples/", "getImagenIntArrayResponse"); protected static final QName _qname_getImagenIntArrayResult = new QName("http://video.samples/", "getImagenIntArrayResult"); protected static final QName _qname_tam = new QName("http://video.samples/", "tam"); protected static final Element _type_getImagenBase64; protected static final Element _type_getImagenBase64Response; protected static final Element _type_getImagenIntArray; protected static final Element _type_getImagenIntArrayResponse; static { // Create all of the Type's that this stub uses, once. Element _type_formato; _type_formato = new Element(_qname_formato, Type.STRING); Element _type_tam; _type_tam = new Element(_qname_tam, Type.INT);

14. Planos de código

Francisco Prieto Donate 311

ComplexType _complexType_getImagenBase64; _complexType_getImagenBase64 = new ComplexType(); _complexType_getImagenBase64.elements = new Element[2]; _complexType_getImagenBase64.elements[0] = _type_formato; _complexType_getImagenBase64.elements[1] = _type_tam; _type_getImagenBase64 = new Element(_qname_getImagenBase64, _complexType_getImagenBase64); Element _type_getImagenBase64Result; _type_getImagenBase64Result = new Element(_qname_getImagenBase64Result, Type.STRING); ComplexType _complexType_getImagenBase64Response; _complexType_getImagenBase64Response = new ComplexType(); _complexType_getImagenBase64Response.elements = new Element[1]; _complexType_getImagenBase64Response.elements[0] = _type_getImagenBase64Result; _type_getImagenBase64Response = new Element(_qname_getImagenBase64Response, _complexType_getImagenBase64Response); _type_getImagenIntArray = new Element(_qname_getImagenIntArray, _complexType_getImagenBase64); Element _type_getImagenIntArrayResult; _type_getImagenIntArrayResult = new Element(_qname_getImagenIntArrayResult, Type.INT, 1, -1, false); ComplexType _complexType_getImagenIntArrayResponse; _complexType_getImagenIntArrayResponse = new ComplexType(); _complexType_getImagenIntArrayResponse.elements = new Element[1]; _complexType_getImagenIntArrayResponse.elements[0] = _type_getImagenIntArrayResult; _type_getImagenIntArrayResponse = new Element(_qname_getImagenIntArrayResponse, _complexType_getImagenIntArrayResponse); } }

• VideoJSR.java

// This class was generated by 172 StubGenerator. // Contents subject to change without notice. // @generated package cliente.stub; public interface VideoJSR extends java.rmi.Remote { public java.lang.String getImagenBase64(java.lang.String formato, int tam) throws java.rmi.RemoteException; public int[] getImagenIntArray(java.lang.String formato, int tam) throws java.rmi.RemoteException; }

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

312 Francisco Prieto Donate

• GetImagenBase64.java

// This class was generated by the JAXRPC SI, do not edit. // Contents subject to change without notice. // JSR-172 Reference Implementation wscompile 1.0, using: JAX-RPC Standard Implementation (1.1, build R59) package cliente.stub; public class GetImagenBase64 { protected java.lang.String formato; protected int tam; public GetImagenBase64() { } public GetImagenBase64(java.lang.String formato, int tam) { this.formato = formato; this.tam = tam; } public java.lang.String getFormato() { return formato; } public void setFormato(java.lang.String formato) { this.formato = formato; } public int getTam() { return tam; } public void setTam(int tam) { this.tam = tam; } }

• GetImagenBase64Response.java

// This class was generated by the JAXRPC SI, do not edit. // Contents subject to change without notice. // JSR-172 Reference Implementation wscompile 1.0, using: JAX-RPC Standard Implementation (1.1, build R59) package cliente.stub; public class GetImagenBase64Response { protected java.lang.String getImagenBase64Result; public GetImagenBase64Response() { }

14. Planos de código

Francisco Prieto Donate 313

public GetImagenBase64Response(java.lang.String getImagenBase64Result) { this.getImagenBase64Result = getImagenBase64Result; } public java.lang.String getGetImagenBase64Result() { return getImagenBase64Result; } public void setGetImagenBase64Result(java.lang.String getImagenBase64Result) { this.getImagenBase64Result = getImagenBase64Result; } }

• GetImagenIntArray.java

// This class was generated by the JAXRPC SI, do not edit. // Contents subject to change without notice. // JSR-172 Reference Implementation wscompile 1.0, using: JAX-RPC Standard Implementation (1.1, build R59) package cliente.stub; public class GetImagenIntArray { protected java.lang.String formato; protected int tam; public GetImagenIntArray() { } public GetImagenIntArray(java.lang.String formato, int tam) { this.formato = formato; this.tam = tam; } public java.lang.String getFormato() { return formato; } public void setFormato(java.lang.String formato) { this.formato = formato; } public int getTam() { return tam; } public void setTam(int tam) { this.tam = tam; } }

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

314 Francisco Prieto Donate

• GetImagenIntArrayResponse.java

// This class was generated by the JAXRPC SI, do not edit. // Contents subject to change without notice. // JSR-172 Reference Implementation wscompile 1.0, using: JAX-RPC Standard Implementation (1.1, build R59) package cliente.stub; public class GetImagenIntArrayResponse { protected int[] getImagenIntArrayResult; public GetImagenIntArrayResponse() { } public GetImagenIntArrayResponse(int[] getImagenIntArrayResult) { this.getImagenIntArrayResult = getImagenIntArrayResult; } public int[] getGetImagenIntArrayResult() { return getImagenIntArrayResult; } public void setGetImagenIntArrayResult(int[] getImagenIntArrayResult) { this.getImagenIntArrayResult = getImagenIntArrayResult; } }

15. Referencias bibliográficas

Francisco Prieto Donate 315

15 REFERENCIAS BIBLIOGRÁFICAS

15.1 Libros de consulta

• CAULDWELL, P. et al. “ Servicios Web XML”. Madrid: Anaya Multimedia, 2002.

• AKIF, M. et al. “ Java y XML: referencia para programadores”. Madrid: Anaya Multimedia, 2002.

• GUTIÉRREZ, A.; Martínez, R. “ XML a través de ejemplos”. Madrid: Ra-Ma, 2001.

• KNUDSEN, J. “ Wireless Java: Developing with J2ME”. Berkeley, CA: Apress, 2003.

• RUBIALES, R.; BENÍTEZ, A. “ Vídeo digital”. Madrid: Anaya Multimedia, 2003.

15.2 Proyectos fin de carrera

• Francisco Prieto Piñero: “Cliente para la recepción de imágenes de vídeo en dispositivos móviles usando CLDC sobre J2ME”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2005.

• Alfredo Barroso Mata: “Instalación de una plataforma para prueba de Servicios Web XML sobre la J2ME”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2005.

• José María Lora Moreno: “Implementación de decodificación JPEG para cliente receptor de imágenes en J2ME”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2006.

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

316 Francisco Prieto Donate

• Diego Ruiz Macías: “Servidor para captura de imágenes y vídeo con tecnología Java (JMF y JIMI)”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2004.

• Antonio Albéndiz Varela: “ Aplicación de la serialización sobre la J2ME”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2004.

• José Miguel Cotrino Benavides: “Servicio web SOAP ‘Diccionario conceptual’ con acceso a base de datos XML”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2003.

• José Luis Sánchez Jurado: “SCAIT: Servicio de calificaciones del Área de Ingeniería Telemática”. Escuela Superior de Ingenieros, Universidad de Sevilla. 2005.

15.3 Páginas web

J2ME

• http://grasia.fdi.ucm.es/j2me/HomeJ2ME.html

• http://www.it.uc3m.es/celeste/docencia/j2me/tutoriales/midp1_0/PracticaHTTP/

GPRS

• http://www.newlc.com/Clases-de-GPRS.html

• http://www.iberprensa.com/todolinux/articulos/TL64_gnome-gprs.pdf

XML

• http://www.w3schools.com/xml/xml_namespaces.asp

• http://www.xml.com/pub/a/1999/01/namespaces.html

15. Referencias bibliográficas

Francisco Prieto Donate 317

• http://www.zvon.org/xxl/NamespaceTutorial/Output/index.html

SOAP

• http://www.w3.org/TR/soap12-part0/

UDDI

• http://www.uddi.org/pubs/the_evolution_of_uddi_20020719.pdf

• http://www-306.ibm.com/software/solutions/webservices/uddi/shutdown_faq.html

• http://uddi.org/

• http://www.microsoft.com/spanish/msdn/articulos/archivo/281201/voices/service10032001.asp

kSOAP

• http://ksoap.objectweb.org/software/documentation/index.html

• http://sourceforge.net/projects/ksoap2/

NetBeans

• http://www.netbeans.org/products/mobility/

Sun Java Wireless Toolkit

• http://java.sun.com/products/sjwtoolkit/download-2_2.html

Formatos de imágenes

• http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt

Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME

318 Francisco Prieto Donate

• http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/JPEG.txt

• http://www.w3.org/TR/PNG/

15.4 Apuntes de asignaturas

• “Redes y servicios de radio”, 5º curso de Ingeniería de Telecomunicación. Escuela Superior de Ingenieros, Universidad de Sevilla.

• “Fundamentos de telemática”, 3er curso de Ingeniería de Telecomunicación. Escuela Superior de Ingenieros, Universidad de Sevilla.

15.5 Artículos

• Francisco Prieto, Antonio J. Sierra, María Carrión García. “ Transmisión de imágenes de vídeo en Servicios Web XML”, publicado en actas del II Congreso Iberoamericano sobre Computación Ubicua, ISBN: 84-8138-703-7, 2006, págs. 305-312. Alcalá de Henares. 2006.