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

Document related concepts
no text concepts found
Transcript
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
Sevilla, Febrero de 2007
Francisco Prieto Donate
III
IV
Francisco Prieto Donate
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.
Francisco Prieto Donate
V
VI
Francisco Prieto Donate
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.
Francisco Prieto Donate
VII
VIII
Francisco Prieto Donate
Í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.6
2.7
2.5.1
Objetivos......................................................................................... 17
2.5.2
Requisitos ....................................................................................... 18
2.5.3
Alcance ........................................................................................... 19
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
MIDP (Mobile Information Device Profile)................................................... 31
Francisco Prieto Donate
IX
2.8
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
Descarga OTA ................................................................................................ 60
2.8.1
2.9
Usos de la tecnología OTA............................................................. 61
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.4
3.3.1
Identificador del protocolo GPRS .................................................. 68
3.3.2
Identificador del protocolo de los PDU.......................................... 68
3.3.3
Mensaje GPRS................................................................................ 68
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
4.2
X
Introducción.................................................................................................... 83
4.1.1
Evolución de los Servicios Web..................................................... 83
4.1.2
Conceptos básicos .......................................................................... 84
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
4.3
4.4
4.5
4.6
4.7
4.2.5
Espacios de nombres XML ............................................................ 91
4.2.6
Analizadores XML ......................................................................... 93
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
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
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
Servicios Web XML para dispositivos móviles ........................................... 116
4.6.1
kSOAP .......................................................................................... 116
4.6.2
JSR-172 ........................................................................................ 127
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
Francisco Prieto Donate
XI
6.3
6.4
6.2.1
Formatos de imagen ..................................................................... 148
6.2.2
Formatos de codificación de vídeo............................................... 159
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
Consideraciones finales ................................................................................ 171
7 APLICACIÓN DESARROLLADA ................................ 173
7.1
Introducción.................................................................................................. 173
7.2
Desarrollo del servidor ................................................................................. 173
7.3
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
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.4
XII
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
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
8.4.4
8.5
Simulación del cliente .................................................................. 217
Consideraciones finales ................................................................................ 222
9 PRUEBAS Y RESULTADOS ........................................ 223
9.1
Introducción a las pruebas ............................................................................ 223
9.2
Escenario kSOAP ......................................................................................... 224
9.3
9.4
9.5
10
9.2.1
Codificación Base64..................................................................... 224
9.2.2
Codificación Array de enteros...................................................... 226
Escenario JSR-172........................................................................................ 228
9.3.1
Codificación Base64..................................................................... 228
9.3.2
Codificación Array de enteros...................................................... 230
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
Consideraciones finales ................................................................................ 236
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
13.1
GUÍA DE INSTALACIÓN......................................... 245
Servidor de vídeo.......................................................................................... 245
Francisco Prieto Donate
XIII
13.2
13.3
13.1.1
Instalación..................................................................................... 246
13.1.2
Funcionamiento ............................................................................ 247
13.1.3
Formato de la petición al servidor ................................................ 249
Servidor web Apache Tomcat 4.1 ................................................................ 251
13.2.1
Instalación..................................................................................... 251
13.2.2
Funcionamiento ............................................................................ 252
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
14.1
14.2
15
PLANOS DE CÓDIGO ............................................. 269
Escenario kSOAP ......................................................................................... 269
14.1.1
Servidor Web................................................................................ 269
14.1.2
Cliente J2ME ................................................................................ 272
Escenario JSR-172........................................................................................ 295
14.2.1
Servidor web................................................................................. 295
14.2.2
Cliente J2ME ................................................................................ 298
14.2.3
Stub del cliente J2ME................................................................... 308
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
XIV
Francisco Prieto Donate
1. Introducción
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.
Francisco Prieto Donate
1
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
inalámbricos
XML
en
dispositivos
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
2
Francisco Prieto Donate
1. Introducción
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.
Francisco Prieto Donate
3
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
4
•
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.
Francisco Prieto Donate
1. Introducción
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.
Francisco Prieto Donate
5
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
6
Francisco Prieto Donate
2. J2ME
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
(J2METM)
Platform
Micro
Edition
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:
Francisco Prieto Donate
7
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
8
•
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.
Francisco Prieto Donate
2. J2ME
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:
Francisco Prieto Donate
9
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
10
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
11
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
12
•
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.
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
13
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
14
Francisco Prieto Donate
2. J2ME
á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:
Francisco Prieto Donate
15
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
16
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
17
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
18
Francisco Prieto Donate
2. J2ME
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:
Francisco Prieto Donate
19
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
Configuration)
Limited
Device
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.
20
Francisco Prieto Donate
2. J2ME
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
Francisco Prieto Donate
21
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
Specification
con
JavaTM
Virtual
Machine
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.
22
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
23
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
24
Francisco Prieto Donate
2. J2ME
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
Francisco Prieto Donate
25
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
26
Francisco Prieto Donate
2. J2ME
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
Francisco Prieto Donate
27
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
28
Francisco Prieto Donate
2. J2ME
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
Francisco Prieto Donate
29
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
public Datagram
IOException
public Datagram
IOException
public Datagram
addr) throws
newDatagram(int size, String addr) throws
newDatagram(byte[] buf, int size) throws
newDatagram(byte[] buf, int size, String
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:
30
•
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:
Francisco Prieto Donate
2. J2ME
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
Profile)
(Mobile
Information
Device
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:
Francisco Prieto Donate
31
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
•
32
Soporte de interfaz de usuario: LCDUI (Limited Connected Device User
Interface)
Francisco Prieto Donate
2. J2ME
•
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){
Francisco Prieto Donate
33
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
34
•
En primer lugar 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.
HolaMundo
extiende
a
la
clase
Francisco Prieto Donate
2. J2ME
•
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
Francisco Prieto Donate
35
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
36
•
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.
Francisco Prieto Donate
2. J2ME
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
Francisco Prieto Donate
37
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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á:
38
•
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.
Francisco Prieto Donate
2. J2ME
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:
Francisco Prieto Donate
39
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
40
•
Control de lo que se está dibujando en la pantalla.
•
Captura de eventos primitivos tales como pulsación de teclas concretas del
teclado.
Francisco Prieto Donate
2. J2ME
•
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 superiorizquierda del rectángulo y los parámetros width y height especifican el ancho y el alto
Francisco Prieto Donate
41
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
42
Francisco Prieto Donate
2. J2ME
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).
Francisco Prieto Donate
43
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
44
Francisco Prieto Donate
2. J2ME
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
Francisco Prieto Donate
45
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
46
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
47
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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)
48
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
49
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
50
Francisco Prieto Donate
2. J2ME
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());
Francisco Prieto Donate
51
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
52
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
53
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
54
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
55
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
56
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
57
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
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
GameCanvas 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.
Es una clase abstracta que representa un elemento visual en un juego
Layer
como un Sprite o un TiledLayer. Proporciona atributos básicos como
localización, tamaño y visibilidad.
58
Francisco Prieto Donate
2. J2ME
Para juegos que emplean varios Layers, esta clase simplifica el
LayerManager desarrollo del juego brindando al programador un mejor control de las
diferentes vistas del juego.
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
Sprite
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.
Esta clase permite al desarrollador crear grandes áreas de contenido
gráfico sin que una imagen grande sea requerida. Se compone de una
TiledLayer
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.
Francisco Prieto Donate
59
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
60
Francisco Prieto Donate
2. J2ME
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.
Francisco Prieto Donate
61
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
62
Francisco Prieto Donate
3. GPRS
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.
Francisco Prieto Donate
63
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
64
Francisco Prieto Donate
3. GPRS
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).
Francisco Prieto Donate
65
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
66
Francisco Prieto Donate
3. GPRS
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:
Francisco Prieto Donate
67
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
•
68
Petición de log-on (LOG-ON REQUEST).
Francisco Prieto Donate
3. GPRS
•
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:
Francisco Prieto Donate
69
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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).
70
Francisco Prieto Donate
3. GPRS
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.
Francisco Prieto Donate
71
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
72
•
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.
Francisco Prieto Donate
3. GPRS
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.
Francisco Prieto Donate
73
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
74
•
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
Francisco Prieto Donate
3. GPRS
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
Francisco Prieto Donate
75
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
76
Francisco Prieto Donate
3. GPRS
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.
Francisco Prieto Donate
77
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
78
Francisco Prieto Donate
3. GPRS
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.
Francisco Prieto Donate
79
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
GSM
HSCSD (High Speed
Circuit Switched Data)
GPRS
EDGE (Enhanced Data
Rates for Global
Evolution)
UMTS
Kbps
max.
teóricos
Kbps
max.
reales
Comentarios
9,6
9,6
Conmutación de circuitos
57,6
28,8
Se agrupan varios canales GSM
para una
misma transmisión de datos
171,2
44
Conmutación de paquetes
384
70
Cambio de sistema de modulación
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.
80
Francisco Prieto Donate
3. GPRS
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.
Francisco Prieto Donate
81
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
82
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
83
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
84
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
85
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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 UTF8, 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:
86
•
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).
Francisco Prieto Donate
4. Servicios Web XML
•
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:
Francisco Prieto Donate
87
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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:
88
•
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.
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
89
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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, xmldata, 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.
90
Francisco Prieto Donate
4. Servicios Web XML
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>
Francisco Prieto Donate
91
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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
92
Francisco Prieto Donate
4. Servicios Web XML
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
http://www.w3.org/TR/html4/.
tabla
utilizaríamos
el
espacio
de
nombres:
de
nombres:
<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
http://www.w3schools.com/furniture.
utilizaríamos
el
espacio
<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
Francisco Prieto Donate
93
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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).
94
Francisco Prieto Donate
4. Servicios Web XML
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).
Francisco Prieto Donate
95
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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>
96
Francisco Prieto Donate
4. Servicios Web XML
</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.
Francisco Prieto Donate
97
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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/"/>
98
Francisco Prieto Donate
4. Servicios Web XML
<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>
Francisco Prieto Donate
99
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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/ .
100
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
101
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
102
Francisco Prieto Donate
4. Servicios Web XML
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:
Tipo _ 1
Tipo _ 2
Mensaje _ 1
...
Operación _ 1
Tipo _ n
Mensaje _ 2
...
Mensaje _ n
Puerto _ 1 → Enlace _ 1
Servicio
Operación _ 2
...
Operación _ n
Puerto _ 2
...
Puerto _ n
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:
Francisco Prieto Donate
103
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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>
104
Francisco Prieto Donate
4. Servicios Web XML
</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"
Francisco Prieto Donate
105
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
http://localhost:8080/server.
servicio
estará
situado
en
la
dirección
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.
106
Francisco Prieto Donate
4. Servicios Web XML
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"/>
Francisco Prieto Donate
107
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
</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>
108
Francisco Prieto Donate
4. Servicios Web XML
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>
Francisco Prieto Donate
109
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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>
110
Francisco Prieto Donate
4. Servicios Web XML
<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);
Francisco Prieto Donate
111
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
112
Francisco Prieto Donate
4. Servicios Web XML
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
Francisco Prieto Donate
113
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
114
Francisco Prieto Donate
4. Servicios Web XML
•
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
Francisco Prieto Donate
115
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
116
Francisco Prieto Donate
4. Servicios Web XML
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();
Francisco Prieto Donate
117
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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().
118
Francisco Prieto Donate
4. Servicios Web XML
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>
Francisco Prieto Donate
119
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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));
120
Francisco Prieto Donate
4. Servicios Web XML
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
Francisco Prieto Donate
121
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
</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".
122
Francisco Prieto Donate
4. Servicios Web XML
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>
Francisco Prieto Donate
123
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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>
124
Francisco Prieto Donate
4. Servicios Web XML
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");
Francisco Prieto Donate
125
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
126
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
127
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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 JSR172.
•
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.
128
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
129
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
130
Francisco Prieto Donate
4. Servicios Web XML
•
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:
Francisco Prieto Donate
131
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
SAXParser.parse().
XML
de
entrada
invocando
el
método
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.
132
Francisco Prieto Donate
4. Servicios Web XML
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.
Francisco Prieto Donate
133
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
134
Francisco Prieto Donate
5. Protocolo HTTP
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:
Francisco Prieto Donate
135
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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.
136
Francisco Prieto Donate
5. Protocolo HTTP
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
Mensaje de respuesta
Comando HTTP
+ parámetros
Resultado de la
solicitud
Cabeceras de la
petición
Cabeceras de la
respuesta
Línea en blanco
Línea en blanco
Información
opcional
Información
opcional
Francisco Prieto Donate
137
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
138
Francisco Prieto Donate
5. Protocolo HTTP
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.
Francisco Prieto Donate
139
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
140
Comentario
Descripción
Francisco Prieto Donate
5. Protocolo HTTP
200
OK
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
Francisco Prieto Donate
Operación realizada satisfactoriamente.
141
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
501
Not
El servidor no tiene capacidad, por su diseño interno, para
Implemented llevar a cabo el requerimiento del cliente.
El servidor ha tenido un error interno, y no puede continuar
con el procesamiento.
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
142
Francisco Prieto Donate
5. Protocolo HTTP
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.
Francisco Prieto Donate
143
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
R
S
T
U
V
W
X
Y
Z
a
b
c
d
e
f
g
h
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
51
52
53
54
55
56
57
58
59
60
61
62
63
z
0
1
2
3
4
5
6
7
8
9
+
/
(pad) =
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
144
Francisco Prieto Donate
5. Protocolo HTTP
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.
Francisco Prieto Donate
145
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
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
Francisco Prieto Donate
147
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
148
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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
Francisco Prieto Donate
149
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
150
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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)
Francisco Prieto Donate
151
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
152
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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.
Francisco Prieto Donate
153
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
154
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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
Francisco Prieto Donate
155
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
•
156
GIF es el formato con más soporte de todos los usados.
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
•
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
Francisco Prieto Donate
GIF
JPEG
PNG
157
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
24 bits
PNG-8: 8
bits/256 colores
1,4, 8 y 24
bits
8 bits/256
colores
Transparencia
No
Permite
establecer un
color como
transparente
No
Canal Alfa:
varios
diferentes
niveles de
transparencia
(256 en PNG24)
Soporte de
entrelazado
No
Sí
Sí
Sí
158
8 bits B/N
PNG-24: 24
bits/16,7
millones de
colores
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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.
Francisco Prieto Donate
159
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
160
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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.
Francisco Prieto Donate
161
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
162
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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.
Francisco Prieto Donate
163
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
•
164
Fotogramas I o Intra-fotogramas, son los fotogramas normales o de imagen fija,
proporcionando una compresión moderada, en JPEG.
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
•
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
Francisco Prieto Donate
165
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
"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.
166
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
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.
Francisco Prieto Donate
167
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
168
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
•
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.
Francisco Prieto Donate
169
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
•
170
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.
Francisco Prieto Donate
6. Transmisión de vídeo en Internet
•
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.
Francisco Prieto Donate
171
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
172
Francisco Prieto Donate
7. Aplicación desarrollada
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.
Francisco Prieto Donate
173
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
174
Francisco Prieto Donate
7. Aplicación desarrollada
•
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.
Francisco Prieto Donate
175
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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”.
176
Francisco Prieto Donate
7. Aplicación desarrollada
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.
Francisco Prieto Donate
177
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
178
Francisco Prieto Donate
7. Aplicación desarrollada
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.
Francisco Prieto Donate
179
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
180
Francisco Prieto Donate
8. Escenario de pruebas
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.
Francisco Prieto Donate
181
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
182
Francisco Prieto Donate
8. Escenario de pruebas
// 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";
Francisco Prieto Donate
183
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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);
}
184
Francisco Prieto Donate
8. Escenario de pruebas
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"/>
Francisco Prieto Donate
185
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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.
186
Francisco Prieto Donate
8. Escenario de pruebas
Figura 8.2: Servicios web desplegados en Axis
Figura 8.3: Parte del documento WSDL generado automáticamente por Axis
Francisco Prieto Donate
187
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
188
Francisco Prieto Donate
8. Escenario de pruebas
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;
Francisco Prieto Donate
189
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
}
190
Francisco Prieto Donate
8. Escenario de pruebas
/* 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());
}
Francisco Prieto Donate
191
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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();
}
}
192
Francisco Prieto Donate
8. Escenario de pruebas
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.
Francisco Prieto Donate
193
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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());
}
194
Francisco Prieto Donate
8. Escenario de pruebas
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
Francisco Prieto Donate
195
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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” .
196
Francisco Prieto Donate
8. Escenario de pruebas
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.
Francisco Prieto Donate
197
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
198
Francisco Prieto Donate
8. Escenario de pruebas
Francisco Prieto Donate
199
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
200
Francisco Prieto Donate
8. Escenario de pruebas
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
Francisco Prieto Donate
201
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
}
202
Francisco Prieto Donate
8. Escenario de pruebas
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;
Francisco Prieto Donate
203
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
204
Francisco Prieto Donate
8. Escenario de pruebas
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"/>
Francisco Prieto Donate
205
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
</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.
206
Francisco Prieto Donate
8. Escenario de pruebas
Figura 8.4: Servicios web desplegados en Axis
Figura 8.5: Parte del documento WSDL generado automáticamente por Axis
Francisco Prieto Donate
207
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
208
Francisco Prieto Donate
8. Escenario de pruebas
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);
Francisco Prieto Donate
209
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
210
Francisco Prieto Donate
8. Escenario de pruebas
/* 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());
Francisco Prieto Donate
211
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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 {
212
Francisco Prieto Donate
8. Escenario de pruebas
// 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 */
Francisco Prieto Donate
213
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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,ClienteVide
o.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();
214
Francisco Prieto Donate
8. Escenario de pruebas
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
Francisco Prieto Donate
215
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
216
Francisco Prieto Donate
8. Escenario de pruebas
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.
Francisco Prieto Donate
217
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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.
218
Francisco Prieto Donate
8. Escenario de pruebas
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:
Francisco Prieto Donate
219
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
220
Francisco Prieto Donate
8. Escenario de pruebas
Francisco Prieto Donate
221
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
222
Francisco Prieto Donate
9. Pruebas y resultados
9
PRUEBAS Y RESULTADOS
9.1 Introducción a las pruebas
de:
Las pruebas realizadas están diseñadas para obtener información detallada acerca
•
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.
Francisco Prieto Donate
223
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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 Información
medio de enviada por
la imagen el servidor
(Kb)
(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
224
Francisco Prieto Donate
9. Pruebas y resultados
<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/XMLSchemainstance"><soapenv:Body><ns1:getImagenBase64Response
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="urn:video.samples"><getImagenBase64Return
xsi:type="xsd:base64Binary">/9j/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw
8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgN
DRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
IyMjL/wAARCABQAFADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcI
CQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwR
VS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq
c3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJyt
LT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAEC
AwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFE
KRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj
ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6ws
PExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDyWL/W
D25qQnP40yIZkpxGGpvcCzZAG7hz03r/ADr3SxmEOgXcuMGVkhXj/gR/kPzrxDS136jbLj
rIo/WvcL+2a2stPswwBWHzpB/tPz/ILUS3GU1lIOe5FPa4YYBPFMEDYHT8aRrdmJORjvis
7Fj5ZCcBSfp61CYiy55pyxyB1TB5967bwppVvLaXIurdJCWGN4yQK0UXb0IbOBeP7y4HFQ
SQN1/Ku7utPtYLvEclrs6Hcq8c+9WfFmmQP4chls4IhsZSZIwB8pGP54qnGxKdz5agGS30
p235iKbCTlgByanBBpyeoy/ocTSa5ZqoyfOX3r3LWR5uqu44Qxx7cemwYrxbw2RFr9m5zh
ZQSBX0dPpUWtQW1xZRfZ4wgw8uRuGOmP60gOPRePug04L8pB25JrT1DR7nSlDzKjRscb05
FZE1wvK5xznOKkpMcCfN3d+g4ru/CsLJp8krZ/ePx+FcAs6KSd57YArvfDN0raG7B1GyQg
F+nQf41pfQjqV9Re1W8xHZK21iG/c5zWlLbf2noYtYysIkXBDJjGD6VNbanDN8plXeASQq
noKamqI92ieYFR8bA0ZBfPpU3BI+OYThjUwODn1NRR4DNUvoPem9xmzoDgaxa8dHz+lfU+
n3cV1pNncRITGyABV7dsV8p6DzrFvjOcn+VfQ3gS8klsJrInmIiRPoeoqeopbHTahZ/bLO
a0ZNqSr8rZzhu39K8puw8MzwuNrqxUg+or1+e4QRBSpLsQAuOc1wPjbSzBqC3cafJOMtjs
w6/wBDRJXFF2ZyhYA9a7fwzcxx+G7veplPnABASCeBXC7GOSRgfSux8Hz2sdrNFcXEkUpc
FNq9sY64oXmORpabrNotw0RSNISmSJn4DDqc4/SoLLVGudSBNulw4kyZvm4XIwQB0xXTWu
nWunwBIoJGwxbJAJJIxWdeTaTYmO5ktLkEERKycHjseRRZkto+TVGScetOz601Cce+aQtz
V9Szc8NHGtwc+v8AKvYPC2pfYdZgdnAjY7G9MHivGvDjhdahJIwA3X6V6JDOo2kEexFSI9
5bhSyqC2PzrE8TKkvh2ZphtdCCn1zjj8Ca4vTPGWo2qrC1xHIhOAZhnH41p+MnuUFsJr5Z
kcZ2IAoHvjPP1oBs5F/vcjgd66jwhYS3d3JKj7EjAViMZ59iCD0rkWdTn8utdb4PFzcJfQ
2jxKzBDl2PY+1MCrr2pXR1W5w7oFcrtDHAxxml8Ovf3T3Nra3CwtIocysSGGOwPvml8QeI
Francisco Prieto Donate
225
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
rq31iaOAQRBH2kCNG5HXkjnmoLK/1TxF59goimdk3rkKmzHcYFO5PQ+ewcLmkOSaMjGKb3
6U7FGtoX/IVj+h/lXcozHGBXDaCCdWjA/umu3QiPHG496zluNFtZCSDng9sVejlNw4SSRs
kj94fmwPp+VZiOc8jANdb4CiWfxAqS42eW2VI+9jt/X8KSE9jM1fTv7MuI4xP5qvGsgIXb
wR3HY1Y8MTXzX80On3KwTvER8xxnBBx7V2Xje00mTT2l3RRXqkbNo5f2P4V5eWKMSjEEcV
bWlyU+ZFzXrtJdUlkVOC3z85+b+I5zzzmmaZdunmJHcR2shGVm3lWHsCOefSs2XnHPLDrV
d2YAZPPuKSY1tY/9k=</getImagenBase64Return></ns1:getImagenBase64Respons
e></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.
226
Francisco Prieto Donate
9. Pruebas y resultados
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/XMLSchemainstance"><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/"><getImagenIn
tArrayReturn 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">-
Francisco Prieto Donate
227
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
37</getImagenIntArrayReturn><getImagenIntArrayReturn
xsi:type="xsd:int">0</getImagenIntArrayReturn><getImagenIntArrayReturn
xsi:type="xsd:int">67</getImagenIntArrayReturn><getImagenIntArrayRetur
n
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:getImagenI
ntArrayResponse></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.
JPG
228
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)
1,76
2,77
3,89
103,55
230,80
289,44
Francisco Prieto Donate
9. Pruebas y resultados
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"
Francisco Prieto Donate
229
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"><soapenv:Body><getImagenBase64Response
xmlns="http://video.samples/"><getImagenBase64Result>/9j/2wBDAAgGBgcGB
QgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTg
yPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM
jIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABQAFADASIAAhEBAxEB/8QAHwAAAQUBAQE
BAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhM
UEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkd
ISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipq
rKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwE
AAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECA
xEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg
5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmao
qOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn
6/9oADAMBAAIRAxEAPwDyeP7pzxzzSkZOcUJwuM5oxz2qnuA0j/61KB9KXIPNHegBR0Nag
I8tBz90ZrMGcHFaUikIh7EAVnIpD7Q5uoyf74/nX1P4XH/FJaR/16Rf+givlywXN1ED/fF
fU/hoKvhfSgmdv2SLGf8AdFTu7CZp4paKKuwj4pj+4MilPTPWhMbBS5q2Ah96AB060jUox
npQA5e/PNasqEAAjjAwKyl4rZDeYd38OOM1nMqJZ02INeRZHVhX074aG3wvpQ9LSL/0AV8
36Dbefq9rEMYaQDmvpfRkEeh2CDotvGP/AB0Uo73Je9i7RRRVgfFI4UD+VB6mtPWdHTTbw
LFM0kTcjd1FVVgBHQHPqKXOmrlWZVJHPtS7vpVwWyEcqKa1soPANHOmHK7FZM5OSK1FJMa
KW9KoyQ7V4q6hJVQO1KTuC0N7QpCmq2rbcgSetfS2jnOh2GRj/Ro8j/gIr5u8MWs82s2RU
cGSvpTToymk2kZ4KwIv/joqrWRF7yZPA4kiDDp0qSooIfIQruyM8U25laNcL1NRfljdjPl
HV5RcXbsTlQSV+hbNVVgLJvAz61FcbhcENnOec+taNi43bG6EVm04o2WrKRManDOAfQmmm
WIjhxVXUY9t3Iozw1VDxz35/rWijdEORoyYZQV6BhnipclWJ96owElv+BVZkkIc445p8up
NzsfCl2YtRtQCMoxbn6V9G2D+Zp9s/HzRKePoK+XdAmEd7CxwMZ/ka+ndGcSaHYODkNbRn
P8AwEVo9kZR+Jlt2Crk1mzNLcS/J9wd602XcMVX8howRGAc9c9qylG7Kk2j5a8QWDQ6hOy
D5Qd/4Gs6ByMc/jXVeLLTfDFcDPB2t9O1cksUsYL7D5fZsVjF80Td6MjuyWndu5P9Kg5qS
4OXYnvjFQg5NbR2IYJuLjPPIxTmYmQ+xpEJEinvmkBJfP8ASrRLNOxkZJxgfwn+Rr6n8MO
X8K6Sxxk2cXT/AHBXyzYRebOFDYO1jz7Ka+pfDkBh8MaZFvzi1jAIH+yKbRC3NaikUFRgk
n60tIs//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.
JPG
230
Tamaño
medio de
la imagen
(Kb)
Información
enviada por
el servidor
(Kb)
1,76
130,62
Tiempo
Consumo Consumo
medio entre
de
de memoria
imágenes (s) memoria
tras la 1ª
al inicio
imagen
(Kb)
(Kb)
60,11
103,55
473,37
Consumo
de memoria
tras la 2ª
imagen
(Kb)
473,37
Francisco Prieto Donate
9. Pruebas y resultados
PNG
13,57
1.380,82
565
103,55
Se excede el Se excede el
límite de
límite de
memoria
memoria
(500Kb)
(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>
Francisco Prieto Donate
231
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
</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/XMLSchemainstance"><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><getImagenIntArrayResul
t
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
232
Francisco Prieto Donate
9. Pruebas y resultados
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.
Memoria consumida (Kb)
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.
500,000
450,000
400,000
350,000
300,000
250,000
200,000
150,000
100,000
50,000
0,000
JSR-172 - Array int JPG
kSOAP - Array int JPG
kSOAP - Base64 PNG
JSR-172 - Base64 PNG
kSOAP - Base64 JPG
Inicio
1ª imagen
2ª imagen
Instante de ejecución
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.
Francisco Prieto Donate
233
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
Tiempo entre imágenes (s)
90
80
70
60
50
Base64 - JPG
Base64 - PNG
40
Array int - JPG
30
20
10
0
kSOAP
JSR-172
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
234
Francisco Prieto Donate
9. Pruebas y resultados
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
kSOAP
Base64
JPG
1,76
2,95
67,61%
PNG
13,57
25,73
89,61%
JPG
1,76
130,94
7.339,77%
PNG
13,57
1.381,06
10.077,30%
Array de
enteros
Francisco Prieto Donate
235
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
JSR-172
Base64
Array de
enteros
JPG
1,76
2,77
57,39%
PNG
13,57
25,63
88,87%
JPG
1,76
130,62
7.321,59%
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.
236
Francisco Prieto Donate
10. Conclusiones
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
Francisco Prieto Donate
237
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
238
Francisco Prieto Donate
10. Conclusiones
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.
Francisco Prieto Donate
239
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
240
Francisco Prieto Donate
11. Temporización
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
Francisco Prieto Donate
241
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
242
Francisco Prieto Donate
12. Presupuesto
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
Francisco Prieto Donate
243
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
Recursos humanos
Horas de trabajo, Ingeniero Junior
Coste
unitario ( )
Total ( )
12 meses
300 /mes
3.600
Hardware
Ordenador AMD K7
Impresora inyección de tinta
Webcam
1
1
1
700
60
18
700
60
18
Software
Windows XP Profesional SP2
Microsoft Office 2003
1
1
93,14
184,61
93,14
184,61
12 meses
12 meses
1
10 /mes
40 /mes
30
120
480
30
Consumibles
Gasto eléctrico
Conexión a Internet
Material de oficina
TOTAL
5.285,75
Tabla 12.1: Coste total del proyecto
244
Francisco Prieto Donate
13. Guía de instalación
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
Francisco Prieto Donate
245
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
http://java.sun.com/products/java-media/jmf.
Aporta
dirección
web:
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/javamedia/jmf/2.1.1/jmfdiagnostics.html
Figura 13.1: Página de diagnóstico de JMF para una instalación correcta
246
Francisco Prieto Donate
13. Guía de instalación
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:
Francisco Prieto Donate
247
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
248
Francisco Prieto Donate
13. Guía de instalación
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.
Francisco Prieto Donate
249
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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:
250
Francisco Prieto Donate
13. Guía de instalación
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
Francisco Prieto Donate
251
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
252
Francisco Prieto Donate
13. Guía de instalación
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.
Francisco Prieto Donate
253
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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%\commonsdiscovery-0.2.jar;%AXIS_LIB%\commons-logging1.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%\commonsdiscovery-0.2.jar;%AXIS_LIB%\commons-logging1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.
jar;%AXIS_LIB%\wsdl4j1.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:
254
Francisco Prieto Donate
13. Guía de instalación
set AXIS_HOME=c:\axis
set AXIS_LIB=%AXIS_HOME%\lib
set AXISCLASSPATH=%AXIS_LIB%\axis.jar; %AXIS_LIB%\commons-discovery0.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-discovery0.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)
Francisco Prieto Donate
255
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
256
Francisco Prieto Donate
13. Guía de instalación
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"
Francisco Prieto Donate
257
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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">
258
Francisco Prieto Donate
13. Guía de instalación
<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"/>
Francisco Prieto Donate
259
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
</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:
260
Francisco Prieto Donate
13. Guía de instalación
•
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.
Francisco Prieto Donate
261
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
262
Francisco Prieto Donate
13. Guía de instalación
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
Francisco Prieto Donate
263
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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.
264
Francisco Prieto Donate
13. Guía de instalación
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:
Francisco Prieto Donate
265
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
266
Francisco Prieto Donate
13. Guía de instalación
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.
Francisco Prieto Donate
267
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
268
Francisco Prieto Donate
14. Planos de código
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.
Francisco Prieto Donate
269
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
* 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);
}
270
Francisco Prieto Donate
14. Planos de código
// 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"/>
Francisco Prieto Donate
271
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
</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
private Command
private Command
private Command
private Command
private Command
private Command
private Command
/* Pantallas
private Form
private Form
private List
private List
okToFormDireccion;
okToListCodificacion;
okToImagen;
backToBienvenida;
backToFormDireccion;
backToListCodificacion;
backToListFormato;
exitCommand;
tipo Screen */
formDireccion;
formResumen;
listCodificacion;
listFormato;
/* Subtipos de Form */
private TextField textFieldIP;
private TextField textFieldPuerto;
272
Francisco Prieto Donate
14. Planos de código
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,
Francisco Prieto Donate
273
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
}
274
Francisco Prieto Donate
14. Planos de código
/* 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());
Francisco Prieto Donate
275
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
private
private
private
private
private
private
int CanvasWidth;
int CanvasHeight;
Font fuente;
String cadena1;
String cadena2;
String cadena3;
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";
276
Francisco Prieto Donate
14. Planos de código
// 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
Francisco Prieto Donate
277
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
278
Francisco Prieto Donate
14. Planos de código
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);
Francisco Prieto Donate
279
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
// 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
import
import
import
import
import
import
import
java.util.*;
java.io.DataInputStream;
javax.microedition.lcdui.Image;
javax.microedition.lcdui.Alert;
org.ksoap2.SoapEnvelope;
org.ksoap2.transport.HttpTransport;
org.ksoap2.serialization.*;
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
280
Francisco Prieto Donate
14. Planos de código
//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
Francisco Prieto Donate
281
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
/**************************************************
* 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
282
Francisco Prieto Donate
14. Planos de código
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
Francisco Prieto Donate
283
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
}
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) {
mequeda = lee2bytes();
offset += (mequeda - 2);
}
// cabeceras reservadas
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) {
mequeda = lee2bytes();
mequeda -= 2;
284
// cabecera Huffman
Francisco Prieto Donate
14. Planos de código
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
Francisco Prieto Donate
285
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
// 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();
286
Francisco Prieto Donate
14. Planos de código
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
Francisco Prieto Donate
287
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
* 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);
288
Francisco Prieto Donate
14. Planos de código
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];
Francisco Prieto Donate
289
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
}
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
*/
290
Francisco Prieto Donate
14. Planos de código
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;
}
Francisco Prieto Donate
291
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
/*
* 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
y BITS
*/
private
int
for
292
las tablas MINCODE, MAXCODE y VALPTR a partir de HUFFCODE
void creaTablas(int huffcode[], byte bits[]) {
p = 0;
(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];
Francisco Prieto Donate
14. Planos de código
} 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;
Francisco Prieto Donate
293
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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];
}
}
/*
294
Francisco Prieto Donate
14. Planos de código
* 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";
Francisco Prieto Donate
//IP del servidor
295
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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();
296
Francisco Prieto Donate
14. Planos de código
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">
Francisco Prieto Donate
297
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
<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
298
Francisco Prieto Donate
14. Planos de código
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
private Command
private Command
private Command
private Command
private Command
/* Pantallas
private Form
private List
private List
okToListCodificacion;
okToImagen;
backToBienvenida;
backToListCodificacion;
backToListFormato;
exitCommand;
tipo Screen */
formResumen;
listCodificacion;
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);
Francisco Prieto Donate
299
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
}
300
Francisco Prieto Donate
14. Planos de código
/* 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";
Francisco Prieto Donate
301
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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;
302
Francisco Prieto Donate
14. Planos de código
private
private
private
private
String
String
String
String
cadena1;
cadena2;
cadena3;
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);
}
}
Francisco Prieto Donate
303
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
*
304
Francisco Prieto Donate
14. Planos de código
********************************************************/
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"){
Francisco Prieto Donate
305
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
import
import
import
java.io.DataInputStream;
javax.microedition.lcdui.Image;
javax.microedition.lcdui.Alert;
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.
*/
306
Francisco Prieto Donate
14. Planos de código
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,ClienteVide
o.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;
}
}
}
Francisco Prieto Donate
307
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
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
import
import
import
import
import
javax.xml.rpc.JAXRPCException;
javax.xml.namespace.QName;
javax.microedition.xml.rpc.Operation;
javax.microedition.xml.rpc.Type;
javax.microedition.xml.rpc.ComplexType;
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) {
308
Francisco Prieto Donate
14. Planos de código
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 {
Francisco Prieto Donate
309
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
// 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);
310
Francisco Prieto Donate
14. Planos de código
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;
}
Francisco Prieto Donate
311
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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() {
}
312
Francisco Prieto Donate
14. Planos de código
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;
}
}
Francisco Prieto Donate
313
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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;
}
}
314
Francisco Prieto Donate
15. Referencias bibliográficas
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.
Francisco Prieto Donate
315
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
316
Francisco Prieto Donate
15. Referencias bibliográficas
•
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://www306.ibm.com/software/solutions/webservices/uddi/shutdown_faq.html
•
http://uddi.org/
•
http://www.microsoft.com/spanish/msdn/articulos/archivo/281201/voices/service
10032001.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
Francisco Prieto Donate
317
Transmisión de Imágenes de Vídeo mediante Servicios Web XML sobre J2ME
•
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
•
318
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.
Francisco Prieto Donate