Comunicación Python web service, Oracle y Android
Tiempo total: 5 días con 6:36:54 hrs
En esta publicación muestro el código necesario para realizar las conexiones Python – Oracle y Android – Python. El entorno del servidor Python es la distribución de GNU/Linux Ubuntu, el único detalle que debo omitir es la instalación de la librería cx_Oracle (Necesaria para comunicar Python y Oracle) y SOAPpy (Necesaria para publicar los servicios web) – debido a que no registre historial alguno de los comandos que utilice.
Servidor Python
El servidor a continuación, publica la función iniciar_sesion que se encuentra en el archivo sesion.py recibiendo dos parámetros: usuario y contraseña.
#!/usr/bin/env python import SOAPpy import sesion #Se crea la instancia del servicio SOAP en el equipo por el puerto 8080. PUERTO = 8001 server = SOAPpy.SOAPServer(("", PUERTO)) print "Servidor PYTHON Webservice iniciado en el puerto: %d." % PUERTO server.registerFunction(sesion.iniciar_sesion) #Levantar el servicio SOAP. server.serve_forever()
De la misma manera se pueden importar otros archivos Python con las funciones requeridas. A continuación, el archivo sesion.py funciona de la siguiente manera:
#!/usr/bin/env python import db #valida datos de inicio de sesion def iniciar_sesion(usuario, password): /* implementación */ if(resultado==""): resultado="NOT OK" else: resultado = "%s;WORD;%s;WORD;%s;WORD;%s;WORD;%s;WORD;%s;WORD;%s" % (nombres,apellido,fecha_nacimiento,genero,pais,telefono,tiempo) return resultado
La conexión Android lo que realiza es enviar ambos parámetros, y a través de una consulta a la base de datos validamos si la información es correcta, si lo es, la función devuelve una cadena de parámetros de sesión, si no devuelve el texto “NOT OK”. Aquí se observa cómo se importa el archivo db.py, que contiene las funciones básicas que utilizamos para establecer la conexión a la base de datos:
#!/usr/bin/env python import cx_Oracle import os # se crea la conexcion ip = '192.168.1.12' port = 1521 SID = 'orcl' dsn_tns = cx_Oracle.makedsn(ip, port, SID) conexion = cx_Oracle.connect('android', 'archivos', dsn_tns) # se crea el cursor cursor = conexion.cursor() #eventos de bases de datos def close_cursor(): cursor.close() def commit_db(): conexion.commit() def rollback_db(): conexion.rollback() def close_db(): conexion.close() login=1
El código anterior es el archivo db.py, la pregunta es cómo se realizan las consultas a la base de datos usando Python? Este es un ejemplo del código que utilice en la función de inicio de sesión:
query = "SELECT id,nombres,apellido,fecha_nacimiento,genero,pais,telefono,tiempo FROM usuario WHERE usuario = '%s' AND password = '%s'" % (usuario, password) db.cursor.execute(query) id = "" nombres = "" apellido = "" fecha_nacimiento = "" genero = "" pais = "" telefono = "" tiempo = "" for column_1, column_2, column_3, column_4, column_5, column_6, column_7, column_8 in db.cursor: id = column_1 nombres = column_2 apellido = column_3 fecha_nacimiento = column_4 genero = column_5 pais = column_6 telefono = column_7 tiempo = column_8
Para ver si los datos son correctos, solo asignamos la variable id a la variable resultado, si la consulta es falsa resultado estará vacio, si no podemos devolver las variables adecuadas utilizando el web service:
resultado = "%s" % id
Este practica que realice, era un gestor de correo electrónico en el cual las personas podían enviar y recibir mensajes, por esto a continuación un ejemplo de la instrucción INSERT hacia la base de datos:
def redactar_crear_correo(asunto, mensaje, ip, usuario): regresar="72826;ERROR;No ha iniciado sesion" if(db.login==1): query = "INSERT INTO correo (id,asunto,cuerpo,timestamp,ip,usuario) VALUES ( (SELECT COUNT(id)+1 FROM correo), '%s', '%s', CURRENT_TIMESTAMP, '%s', '%s')" % (asunto, mensaje, ip, usuario) regresar = "" try: db.cursor.execute(query) regresar="OK" except db.cx_Oracle.DatabaseError, exc: error, = exc.args regresar="%s;ERROR;%s" % (error.code, error.message) if(regresar=="OK"): query = "SELECT COUNT(id) FROM correo" db.cursor.execute(query) regresar = "" for column_1 in db.cursor: regresar = "%s" % (column_1) if(regresar==""): regresar="NOT OK" db.rollback_db() else: db.commit_db() return regresar
La publicación del servicio web es la misma, en este caso el archivo que utilice se llama redactar.py, entonces importamos de primer el archivo y luego registramos su función:
import bandeja server.registerFunction(redactar.redactar_crear_correo)
Ahora, ejemplos de eliminación y actualización de información:
#editar contacto def editar_contacto(nombre, relacion, spam, etiqueta, grupo, usuario, contacto): regresar="72826;ERROR;No ha iniciado sesion" if(db.login==1): query = "UPDATE contacto SET nombre = '%s', relacion = '%s', spam = '%s', etiqueta = '%s', grupo = '%s' WHERE usuario = '%s' AND contacto = '%s'" % (nombre, relacion, spam, etiqueta, grupo, usuario, contacto) try: db.cursor.execute(query) db.commit_db() regresar="OK" except db.cx_Oracle.DatabaseError, exc: error, = exc.args regresar="%s;ERROR;%s" % (error.code, error.message) return regresar #crea contacto def eliminar_contacto(usuario, contacto): regresar="72826;ERROR;No ha iniciado sesion" if(db.login==1): query = "DELETE contacto WHERE usuario = '%s' AND contacto = '%s'" % (usuario, contacto) try: db.cursor.execute(query) db.commit_db() regresar="OK" except db.cx_Oracle.DatabaseError, exc: error, = exc.args regresar="%s;ERROR;%s" % (error.code, error.message) return regresar
El archivo utilizado es contacto.py, lo que hacemos es registrar ambas funciones en el archivo inicial del servidor:
import contacto server.registerFunction(contacto.editar_contacto) server.registerFunction(contacto.eliminar_contacto)
Archivo del servidor Python final
Recordemos las funciones publicadas para este ejemplo:
#!/usr/bin/env python import SOAPpy import sesion import bandeja import contacto #Se crea la instancia del servicio SOAP en el equipo por el puerto 8080. PUERTO = 8001 server = SOAPpy.SOAPServer(("", PUERTO)) print "Servidor PYTHON Webservice iniciado en el puerto: %d." % PUERTO #Levantar el servicio SOAP. server.serve_forever() server.registerFunction(sesion.iniciar_sesion) server.registerFunction(redactar.redactar_crear_correo) server.registerFunction(contacto.editar_contacto) server.registerFunction(contacto.eliminar_contacto)
De nuevo debo mencionar mis errores, en el código de las funciones editar y eliminar contacto, se puede observar que no hay ninguna validación si el usuario ya ha iniciado sesión, lo único que se puede observar es la validación de la variable db.login==1 pero no funciona en absoluto. Cuando se utilizan servicios web se crea una sesión completamente nueva, para solucionar esto se puede crear una tabla en la base de datos llamada tokens, aquí podemos crear un token de acuerdo a la fecha y hora exacta (hora, minutos, segundos) en que el usuario se conecto, almacenando un token cifrado, nombre de usuario e IP, así cada vez que se usa una función privada el cliente deberá de enviar el token que el sistema le proporciona, validar su IP y si todo es correcto, devolver su nombre de usuario, o id y a partir de esto, nuestras funciones privadas identificaran la identidad del usuario que realiza la consulta. Cuando el usuario cierre sesión, este registró en la base de datos deberá de destruirse.
Consumiendo servicio web con Android
Para poder consumir las funciones publicadas, debemos buscar en internet la librería ksoap2-android-assembly-3.0.0-RC.2-jar-with-dependencies.jar (O descargarla en el siguiente enlace) y agregarla a nuestro proyecto.
http://www.elconspirador.com/media/ksoap2-android-assembly-3.0.0-RC.2-jar-with-dependencies.jar
Para esta práctica, realice una función general que me facilito bastante consumir los servicios web, a continuación su código:
package com.example.proyecto2_200915162; import java.util.Iterator; import java.util.LinkedList; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import android.annotation.SuppressLint; import android.os.StrictMode; @SuppressLint({ "NewApi", "NewApi" }) public class webservice { public static String NAMESPACE=""; public static String URL = "http://192.168.1.13:8001"; public static String METHOD_NAME=""; public static String SOAP_ACTION = ""; //lista general public static LinkedList<String> variables; @SuppressLint("NewApi") public webservice(){ load(""); //android fix? if (android.os.Build.VERSION.SDK_INT > 9) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); } } //carga datos del servidor public static void load(String metodo){ NAMESPACE=Proyecto2.datos.NAMESPACE; URL = Proyecto2.datos.URL; SOAP_ACTION = Proyecto2.datos.SOAP_ACTION; METHOD_NAME=metodo; } //consume un webservice. Variables = nombre de variable = valor public static String consumir(String metodo, LinkedList<String> variables){ String resultado=""; load(metodo); SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); if(variables!=null){ Iterator<String> it=variables.iterator(); while(it.hasNext()){ String variable=it.next(); String valor=it.next(); request.addProperty(variable, valor); } } SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.dotNet = true; envelope.setOutputSoapObject(request); HttpTransportSE httpRequest = new HttpTransportSE(URL); httpRequest.debug=true; try { httpRequest.call(SOAP_ACTION, envelope); SoapObject result = (SoapObject)envelope.bodyIn; resultado=result.getProperty(0).toString(); } catch(Exception e) { resultado=e.toString(); } return resultado; } //metodos //implementación! }
Observamos la clase datos donde se almacena la configuración del proyecto Android, para implementar el código anterior, utilizamos las siguientes funciones ejemplo de esta publicación:
public static String iniciar_sesion(String usuario, String password){ variables=new LinkedList<String>(); variables.add("usuario"); variables.add(usuario); variables.add("password"); variables.add(password); String resultado=consumir("iniciar_sesion", variables); if(!resultado.equals("NOT OK")){ try{ String[] v=resultado.split(";WORD;"); Proyecto2.datos.vector[0]=usuario; Proyecto2.datos.vector[1]=password; Proyecto2.datos.vector[2]=v[0]; Proyecto2.datos.vector[3]=v[1]; Proyecto2.datos.vector[4]=v[2].split(" ")[0]; Proyecto2.datos.vector[5]=v[3]; Proyecto2.datos.vector[6]=v[4]; Proyecto2.datos.vector[7]=v[5]; Proyecto2.datos.vector[8]=v[6]; resultado="OK"; }catch(Exception e){ //error en el servidor } }else resultado="El usuario o contraseña son incorrectos"; return resultado; } public static String redactar_crear_correo(String asunto, String mensaje, String ip, String usuario){ String regresar=""; variables=new LinkedList<String>(); variables.add("asunto"); variables.add(asunto); variables.add("mensaje"); variables.add(mensaje); variables.add("ip"); variables.add(ip); variables.add("usuario"); variables.add(usuario); return error(consumir("redactar_crear_correo", variables), "contacto"); } //crea un contacto public static String editar_contacto(String nombre, String relacion, int spam, String etiqueta, String grupo, String usuario, String contacto){ variables=new LinkedList<String>(); variables.add("nombre"); variables.add(nombre); variables.add("relacion"); variables.add(relacion); variables.add("spam"); variables.add(String.valueOf(spam)); variables.add("etiqueta"); variables.add(etiqueta); variables.add("grupo"); variables.add(grupo); variables.add("usuario"); variables.add(usuario); variables.add("contacto"); variables.add(contacto); return error(consumir("editar_contacto", variables), "contacto"); } //crea un contacto public static String eliminar_contacto(String usuario, String contacto){ variables=new LinkedList<String>(); variables.add("usuario"); variables.add(usuario); variables.add("contacto"); variables.add(contacto); return error(consumir("eliminar_contacto", variables), "contacto"); }
Finalmente, puedo concluir que para levantar un proyecto de este tipo necesitas bastante tiempo de digitación, que es sinónimo de desvelo y una excelente nota. Espero que el resumen sea de ayuda al lector.
Adjuntos
Puedes probar las funciones creadas en el servidor Python en otro servidor Python, como? Con el siguiente ejemplo, suponiendo que has creado dos funciones llamadas suma y prueba, observaras si el resultado es el correcto o no:
#!/usr/bin/env python #Se importa el modulo SOAPpy import SOAPpy print "Content-type: text/html" print #Se crea la instancia del proxy SOAP #a el servidor SOAP server = SOAPpy.SOAPProxy("http://192.168.1.100:8001") #Se llama las funciones registradas en el servidor SOAP print "El resultado de la suma es: ", server.suma(5,10),"<br/>" print "El resultado de la prueba es: ",server.prueba(),"<br/>"