Comunicación Python web service, Oracle y Android

Visitas: 195  
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/>"

Para recibir boletines de información, por favor escribe tu correo electrónico:

Por favor ingrese un correo electrónico valido.
Registrado correctamente!