Webservices para Mobiles: Comunicacion entre j2me y SOAPpy
En este artículo voy a describir los pasos necesarios para la comunicacion por medio de webservices (SOAP + wsdl) entre un cliente movil - celular por ejemplo - y un servidor remoto en internet implementado en python con el uso de SOAPpy.
El cliente movil en teoría puede ser cualquier dispositivo que implemente midp-2.0 con el soporte especificado en jsr - 172.
Herramientas necesarias:
- Java sdk, y Java toolkit para desarrollo de aplicaciones j2me.
- Sun Java Wireless Toolkit 2.5.2
- Python v 2.4 o 2.5 (www.python.org)
- SOAPpy (http://pywebsvcs.sourceforge.net)
Esquema:
- El servidor esta implementado en python, y utilizando la libreria SOAPpy que es muy simple de usar. Esta contiene algunos bugs, (tal vez desprendidos de la simpleza), pero la idea es saltar estos para lograr conectividad.
- El cliente es una aplicacion java para dispositivos moviles. Las caracteriscas necesarias del movil deberan ser: soporte para midp-2.0 y una coneccion a internet.
Destaco que las pruebas que realizo las hago en el simulador incluido en Netbeans.
- Un fichero WSDL que describe como se implementan los metodos ofrecidos por el servidor.
Problemas:
- En primer punto SOAPpy no ofrece mecanismos para generar ficheros WSDL (o por lo menos no descubrí ninguna utilidad). Este fichero es necesario para la generacion del codigo java de la aplicacion cliente, para lo que se utiliza una aplicacion del Wireless Toolkit distribuido por Sun.
- El problema de conectividad surge en el uso de SOAPpy, la cual tiene algunos defectos en sus mecanismos de conectividad y en su documentacion que es MUY pobre.
Manos a la obra:
1. Diseñando el metodo para el servicio.
En primer lugar definimos el metodo para compartir. Nuestro metodo en python se define de la siguiente manera:
Como se ve en la declaracion, este metodo es simple, recive como parametros dos Strings y retorna un String.
2. Creando un fichero WSDL.
Esta es la tarea mas complicada si no sabemos nada de WSDL; sus siglas significan Web Services Description Language, y su utilidad es esa misma, definir todos los aspectos necesarios para poder describir como se comporta un Servicio Web. Lo que mas nos importa acá es:
- Una Seccion de definicion de tipos de datos: esto se hace en la seccion "types" del documento, e incluye:
- Tipos de datos de entrada (ej: parametros de un metodo).
- Tipos de datos de salida (ej:retorno de un metodo).
- Secciones de definicion de los mensajes: en la cual se define la forma en que se envian y reciben mensajes para los metodos.
- Secciones de definicion de Servicios: estas corresponden con las secciones portType, binding, operation y service, las cuales se encargan de todos los aspectos restantes de definicion de los servicios, es decir nombrar metodos, asociarles tipos de mensajes de ida y vuelta (parametros y retorno), y finalmente enlazarlos a un servicio dado.
El fichero WSDL es generado como un fichero XML, con tags y atributos especificos que reflejen la semántica antes detallada.
Si miramos en los ejemplos de wireless toolkit tendremos un fichero WSDL de ejemplo, nosotros lo modificamos a discrecion para poder reflejar los detalles de nuestro propio servicio, y la cosa nos queda así:
Bueno, es necesario explicar ahora los puntos relevantes. En primer lugar el namespace para los tipos es: http://serverscript.org/types. Como se ve, no me tome el trabajo de cambiar el nombre del namespace con el que trae el fichero ejemplo de WTK, esto es un cambio minimo, así que si se quiere puede hacerce.
Ademas es claro que hay dos definiciones de tipos:
- El tipo "request", el cual anida dos strings en su interior: String_1 y String_2. Es importante notar que para que la comunicacion funcione, debe definirse un tipo con el mismo nombre que el metodo --request--, y que internamente tenga las definiciones de los parametros.
- El tipo "requestResponse", el cual anida un subtipo "Result", el cual anida el tipo de retorno de nuestro metodo. Hay dos cosas importantes en este, la primera es (como en el caso anterior) el nombre; para que la comunicacion funcione, debe existir definido en el WSDL un tipo para el mensaje de retorno del metodo el cual debe ser de la forma NombreDelMetodoResponse. En segundo lugar el subtipo "Result" en el interior debe ponerse así ya que SOAPpy maneja de esta manera el retorno desde metodos.
Estas dos definiciones de tipos anteriores deben ser así por limitaciones en SOAPpy. Para empezar este espera nombres de tipos en esta forma para sus metodos (metodo y metodoResponse). En segundo lugar el retorno del metodo (cuando hacemos return desde nuestra funcion) es manejado por SOAPpy con un subtipo "Result".
3. Generacion del codigo del Servidor.
Para el Servidor, el codigo es el siguiente:
Las cosas relevantes son:
- La definicion del metodo "request".
- La creacion del servidor, el cual se enlaza a localhost en el port 8080.
- La definicion del namespace. Ojo que esto es importante, si no se hace nuestro servidor no podrá interpretar correctamente los mensajes de entrada (para la invocacion del metodo con sus parametros).
- Registro del metodo.
4. Generacion del Cliente.
Bueno para esta tarea se utilizan dos herramientas:
- WTK 2.5: Exclusivamente para la creacion del código de conexion el WebService.
- Netbeans: Para la creacion de la aplicacion java en su respectivo jar.
4.1. Creacion de las clases java para conexion.
Bueno en esta etapa vamos a generar 4 clases java:
- La clase request. Correspondiente con el tipo ya nombrado.
- La clase requestResponse, correspondiente con el tipo ya nombrado.
- La clase con todo el codigo java necesario para acceder al ws (Interface_Stub).
- Una clase que hereda de la anterior, implementa interfaces necesarias, y nos deja todo bien simple para interactuar con el servicio (Interface).
Para esto es necesario como ya dije utilizar el WTK distribuido por Sun.
Pasos necesarios:
4.1.1. Ejecutamos el Toolkit:
$ ./ktoolbar

4.1.2. Creamos el projecto.

4.1.3. Generamos las clases nombradas al principio. Para esto vamos al meno Project, y elejimos la opcion "Stub Generation". Se abrirá un dialogo en el cual tenemos que especificar nuestro fichero wsdl (como el que pongo mas arriva) y nombre para el paquete java que vamos a generar.

Todo el codigo que generamos estará en el directorio de nuestro proyecto, en linux, el directorio sera: :"~/j2mewtk/2.5.2/apps/DummyProject/src/Conectividad/":

Bueno con esto ya tenemos todo el codigo para conectividad. Solo nos restan unas pequeñas cosas para que todo funcione:
- Primero editamos el fichero Interface_Stub, y hacemos las siguientes modificaciones:
- Luego solo nos resta incluir todos los ficheros java que nos generó el toolkit en nuestro proyecto, y simplemente invocar el servicio:
- Finalmente, ya podemos probar la conectividad, (obviamente en primer lugar hay que ejecutar el servidor):



Bueno, con esto queda demostrada la conectividad entre cliente y servidor. Si por algún motivo no se logra la conección, puede verificarse en la salida por consola del servidor, para asegurarse de que la petición está llegando y que el servidor responde correctamente.
Obviamente si lo que se quiere es hacer algo mas complejo, simplemente debería investigarse un poco más, pero creo que con estos parametros que dí en esta entrada, se le puede simplificar un poco la investigación a cualquiera que tenga que luchar con este problema.
El cliente movil en teoría puede ser cualquier dispositivo que implemente midp-2.0 con el soporte especificado en jsr - 172.
Herramientas necesarias:
- Java sdk, y Java toolkit para desarrollo de aplicaciones j2me.
- Sun Java Wireless Toolkit 2.5.2
- Python v 2.4 o 2.5 (www.python.org)
- SOAPpy (http://pywebsvcs.sourceforge.net)
Esquema:
- El servidor esta implementado en python, y utilizando la libreria SOAPpy que es muy simple de usar. Esta contiene algunos bugs, (tal vez desprendidos de la simpleza), pero la idea es saltar estos para lograr conectividad.
- El cliente es una aplicacion java para dispositivos moviles. Las caracteriscas necesarias del movil deberan ser: soporte para midp-2.0 y una coneccion a internet.
Destaco que las pruebas que realizo las hago en el simulador incluido en Netbeans.
- Un fichero WSDL que describe como se implementan los metodos ofrecidos por el servidor.
Problemas:
- En primer punto SOAPpy no ofrece mecanismos para generar ficheros WSDL (o por lo menos no descubrí ninguna utilidad). Este fichero es necesario para la generacion del codigo java de la aplicacion cliente, para lo que se utiliza una aplicacion del Wireless Toolkit distribuido por Sun.
- El problema de conectividad surge en el uso de SOAPpy, la cual tiene algunos defectos en sus mecanismos de conectividad y en su documentacion que es MUY pobre.
Manos a la obra:
1. Diseñando el metodo para el servicio.
En primer lugar definimos el metodo para compartir. Nuestro metodo en python se define de la siguiente manera:
def request(String_1,String_2):
r = "%s, sos %s" % (str(String_1), str(String_2))
return r
Como se ve en la declaracion, este metodo es simple, recive como parametros dos Strings y retorna un String.
2. Creando un fichero WSDL.
Esta es la tarea mas complicada si no sabemos nada de WSDL; sus siglas significan Web Services Description Language, y su utilidad es esa misma, definir todos los aspectos necesarios para poder describir como se comporta un Servicio Web. Lo que mas nos importa acá es:
- Una Seccion de definicion de tipos de datos: esto se hace en la seccion "types" del documento, e incluye:
- Tipos de datos de entrada (ej: parametros de un metodo).
- Tipos de datos de salida (ej:retorno de un metodo).
- Secciones de definicion de los mensajes: en la cual se define la forma en que se envian y reciben mensajes para los metodos.
- Secciones de definicion de Servicios: estas corresponden con las secciones portType, binding, operation y service, las cuales se encargan de todos los aspectos restantes de definicion de los servicios, es decir nombrar metodos, asociarles tipos de mensajes de ida y vuelta (parametros y retorno), y finalmente enlazarlos a un servicio dado.
El fichero WSDL es generado como un fichero XML, con tags y atributos especificos que reflejen la semántica antes detallada.
Si miramos en los ejemplos de wireless toolkit tendremos un fichero WSDL de ejemplo, nosotros lo modificamos a discrecion para poder reflejar los detalles de nuestro propio servicio, y la cosa nos queda así:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
3 xmlns:tns="http://serverscript.org/wsdl"
4 xmlns:ns2="http://serverscript.org/types"
5 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
6 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
7 name="serverscript"
8 targetNamespace="http://serverscript.org/wsdl">
9 <types>
10 <schema xmlns="http://www.w3.org/2001/XMLSchema"
11 xmlns:tns="http://serverscript.org/types"
12 xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/"
13 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
15 targetNamespace="http://serverscript.org/types">
16 <import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
17 <complexType name="request">
18 <sequence>
19 <element name="String_1" type="string" nillable="true"/>
20 <element name="String_2" type="string" nillable="true"/>
21 </sequence>
22 </complexType>
23 <complexType name="requestResponse">
24 <sequence>
25 <!-- este debe llamarse Result para que funcione -->
26 <element name="Result" type="string" nillable="true"/>
27 </sequence>
28 </complexType>
29 <element name="request" type="tns:request"/>
30 <element name="requestResponse" type="tns:requestResponse"/>
31 <!-- esto lo agrego -->
32 </schema>
33 </types>
34 <message name="Interface_request">
35 <part name="parameters" element="ns2:request"/>
36 </message>
37 <message name="Interface_requestResponse">
38 <part name="result" element="ns2:requestResponse"/>
39 </message>
40 <portType name="Interface">
41 <operation name="request">
42 <input message="tns:Interface_request"/>
43 <output message="tns:Interface_requestResponse"/>
44 </operation>
45 </portType>
46 <binding name="InterfaceBinding" type="tns:Interface">
47 <operation name="request">
48 <input>
49 <soap:body use="literal"/>
50 </input>
51 <output>
52 <soap:body use="literal"/>
53 </output>
54 <soap:operation soapAction=""/>
55 </operation>
56 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/></binding>
57 <service name="Serverscript">
58 <port name="InterfacePort" binding="tns:InterfaceBinding">
59 <soap:address xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
60 location="http://localhost:8080"/>
61 </port>
62 </service>
63 </definitions>
Bueno, es necesario explicar ahora los puntos relevantes. En primer lugar el namespace para los tipos es: http://serverscript.org/types. Como se ve, no me tome el trabajo de cambiar el nombre del namespace con el que trae el fichero ejemplo de WTK, esto es un cambio minimo, así que si se quiere puede hacerce.
Ademas es claro que hay dos definiciones de tipos:
- El tipo "request", el cual anida dos strings en su interior: String_1 y String_2. Es importante notar que para que la comunicacion funcione, debe definirse un tipo con el mismo nombre que el metodo --request--, y que internamente tenga las definiciones de los parametros.
- El tipo "requestResponse", el cual anida un subtipo "Result", el cual anida el tipo de retorno de nuestro metodo. Hay dos cosas importantes en este, la primera es (como en el caso anterior) el nombre; para que la comunicacion funcione, debe existir definido en el WSDL un tipo para el mensaje de retorno del metodo el cual debe ser de la forma NombreDelMetodoResponse. En segundo lugar el subtipo "Result" en el interior debe ponerse así ya que SOAPpy maneja de esta manera el retorno desde metodos.
Estas dos definiciones de tipos anteriores deben ser así por limitaciones en SOAPpy. Para empezar este espera nombres de tipos en esta forma para sus metodos (metodo y metodoResponse). En segundo lugar el retorno del metodo (cuando hacemos return desde nuestra funcion) es manejado por SOAPpy con un subtipo "Result".
3. Generacion del codigo del Servidor.
Para el Servidor, el codigo es el siguiente:
1 from SOAPpy import SOAPServer
2 tns=u"http://serverscript.org/types"
3 def request(String_1,String_2):
4 r = "%s, sos %s" % (str(String_1), str(String_2))
5 return r
6 ss = SOAPServer (("localhost",8080))
7 ss.namespace=tns
8 ss.registerFunction (request)
9 # debug, obviamente es opcional.
10 ss.config.debug=1
11 # a servir
12 ss.serve_forever ()
Las cosas relevantes son:
- La definicion del metodo "request".
- La creacion del servidor, el cual se enlaza a localhost en el port 8080.
- La definicion del namespace. Ojo que esto es importante, si no se hace nuestro servidor no podrá interpretar correctamente los mensajes de entrada (para la invocacion del metodo con sus parametros).
- Registro del metodo.
4. Generacion del Cliente.
Bueno para esta tarea se utilizan dos herramientas:
- WTK 2.5: Exclusivamente para la creacion del código de conexion el WebService.
- Netbeans: Para la creacion de la aplicacion java en su respectivo jar.
4.1. Creacion de las clases java para conexion.
Bueno en esta etapa vamos a generar 4 clases java:
- La clase request. Correspondiente con el tipo ya nombrado.
- La clase requestResponse, correspondiente con el tipo ya nombrado.
- La clase con todo el codigo java necesario para acceder al ws (Interface_Stub).
- Una clase que hereda de la anterior, implementa interfaces necesarias, y nos deja todo bien simple para interactuar con el servicio (Interface).
Para esto es necesario como ya dije utilizar el WTK distribuido por Sun.
Pasos necesarios:
4.1.1. Ejecutamos el Toolkit:
$ ./ktoolbar

4.1.2. Creamos el projecto.

4.1.3. Generamos las clases nombradas al principio. Para esto vamos al meno Project, y elejimos la opcion "Stub Generation". Se abrirá un dialogo en el cual tenemos que especificar nuestro fichero wsdl (como el que pongo mas arriva) y nombre para el paquete java que vamos a generar.

Todo el codigo que generamos estará en el directorio de nuestro proyecto, en linux, el directorio sera: :"~/j2mewtk/2.5.2/apps/DummyProject/src/Conectividad/":

Bueno con esto ya tenemos todo el codigo para conectividad. Solo nos restan unas pequeñas cosas para que todo funcione:
- Primero editamos el fichero Interface_Stub, y hacemos las siguientes modificaciones:
Lo que hice fué cambiar la linea 103 por la linea 104. La idea de esta acción es que java vea el namespace del tipo que se está haciendo referencia como un namespace vacion ("" en lugar de "http://serverscript.org/types") ya que SOAPpy devuelve el tipo indicando un namespace de esta forma (un poco raro, tal vez sea un bug o tal vez sea que tengo mal codificado mi servidor, pero no encontré como hacerlo correctamente en la documentacion).
94 //
95 // End user methods
96 //
97
98 protected static final QName _qname_String_1 = new QName("", "String_1");
99 protected static final QName _qname_String_2 = new QName("", "String_2");
100 protected static final QName _qname_result = new QName("", "Result");
101 protected static final QName _qname_request = new QName("http://serverscript.org/types", "request");
102 // cambiamos la siguiente linea
103 // protected static final QName _qname_requestResponse = new QName("http://serverscript.org/types", "requestResponse");
104 protected static final QName _qname_requestResponse = new QName("", "requestResponse");
105 protected static final QName _qname_wsdl_request = new QName("http://serverscript.org/wsdl", "request");
106 protected static final Element _type_request;
107 protected static final Element _type_requestResponse;
108 static {
109 // Create all of the Type's that this stub uses, once.
- Luego solo nos resta incluir todos los ficheros java que nos generó el toolkit en nuestro proyecto, y simplemente invocar el servicio:
Interface_Stub is = new Interface_Stub ();la forma más sencilla de probar la conectividad, sería ponerlo en el método startApp(), o por lo menos lo es para mi.
is._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8080");
is._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, new Boolean(true));
String ret = is.request("River Plate","el mas grande");
- Finalmente, ya podemos probar la conectividad, (obviamente en primer lugar hay que ejecutar el servidor):
(1) Ejecutamos el servidor:

(2) Ejecutamos el software para testing:

(4) - El resultado final:

Bueno, con esto queda demostrada la conectividad entre cliente y servidor. Si por algún motivo no se logra la conección, puede verificarse en la salida por consola del servidor, para asegurarse de que la petición está llegando y que el servidor responde correctamente.
Obviamente si lo que se quiere es hacer algo mas complejo, simplemente debería investigarse un poco más, pero creo que con estos parametros que dí en esta entrada, se le puede simplificar un poco la investigación a cualquiera que tenga que luchar con este problema.
Etiquetas: conectividad j2me - python, conectividad j2me - soappy, j2me, j2me ws stub generation, java, midp-2.0, python, soap, soappy, wsdl, wtk


0 comentarios:
Publicar un comentario en la entrada
Suscribirse a Enviar comentarios [Atom]
<< Página principal