viernes, 9 de agosto de 2013

Consumir servicio Rest hecho en Gx Evo2 desde Android.

El objetivo de este post es mostrar todo el ciclo para poder utilizar desde una aplicación Java para Android, un servicio Rest hecho en Genexus Evolution 2.

Lo primero que precisamos es un servicio hecho en Genexus Evolution 2, esto es muy fácil ya que basta con cualquier procedimiento (por ejemplo) marcar que va a ser un servicio y va a ser Rest, no el clásico SOAP que ya hace mucho trabajamos.

La forma de definir un servicio Rest es un poco distinto a los SOAP, pero es bastante fácil igual lo único que hay que hacer es marcar la propiedad del procedimiento como se muestra en la imagen.





Bueno ya tenemos el servicio, esto en mi caso lo genere en Java y va a correr en un tomcat, especifico esto porque no sé si en algún otro lenguaje o motor de servlet (probarlo y comentar).

Ahora vamos a ver si este servicio funciona, para esto voy a usar una aplicación para Firefox, para poder consumir este servicio, la aplicación se llama RestClient, la agregan en las extensión de FF, luego de reiniciar en las Herramientas queda un punto para llamar al programa, lo ejecutamos y tenemos varias cosas para tener en cuenta que cambian un poco de lo que ya deberíamos de manejar.

Primero al ser un procedimiento genexus, el método es POST. Además la url cambia la parte de servlet por rest. También en la url, el nombre debe de ser idéntico, es decir con mayúsculas y minúsculas como se llama el programa. En el Body agregamos los parámetros que recibe el procedimiento, los de in, no los de out, de la siguiente forma:
   { "usuario": "pepe" }





Podemos agregar varios parámetros separado por coma. En el Header, agregamos en "Content-Type" como "application/json".

En resumen debe de quedar como la imagen.



Para probar que nuestro servicio funcione, solo con ejecutarlo con SEND, no se devuelve abajo lo que el servicio retorna.



Ahora vamos a ver el código que tenemos que utilizar en Java/Android para consumir este servicio.



try
        {
            HttpClient httpClient = new DefaultHttpClient();
            JSONObject dato = new JSONObject();
            dato.put("usuario", "miusuario");
            HttpPost post = new HttpPost(URL+"wsRestMiWS");
            post.setHeader("content-type", "application/json");
            post.setEntity(new StringEntity(dato.toString()));
            HttpResponse resp = httpClient.execute(post);
            String respStr = EntityUtils.toString(resp.getEntity());
            Log.i("DEBUGGER", respStr);

            JSONObject respJSON = new JSONObject(respStr);
            String Resultado1= respJSON.getString("ResultadoDevuelto1");
            Log.i("DEBUGGER", "Resultado1:"+Resultado1);
            JSONArray Resultado2= respJSON.getJSONArray("ResultadoDevuelto2");

            for(int i=0; i                JSONObject unRes = Resultado2.getJSONObject(i);
                Log.i("DEBUGGER", "Atributo1:"+unRes .getString("Atr1"));
                Log.i("DEBUGGER", "Atributo2:"+unRes .getString("Atr2"));
            }
        }

        catch(Exception ex)
        {
            Log.e("DEBUGGER", "Error!", ex);
        }


Vamos a explicar las lineas que tenemos que cambiar para que esto funcione.

dato.put("usuario", "miusuario");

aca agregamos todos los parámetros que recibe nuestro procedimiento genexus, en mi caso solo recibe el parámetro "usuario" y el valor que le paso es "miusuario", un punto a tener en cuenta y muy importante es que la variable que se definió en genexus debe de ser identica en cuanto a las mayúsculas y minúsculas, sino el servicio no responde correctamente.

HttpPost post = new HttpPost(URL+"wsRestMiWS");

URL es la ruta del server hasta la parte del "rest/"  y wsRestMiWS es el nombre de mi procedimiento genexus (es decir el servicio Rest) y también debe de respetarse las mayúsculas y minúsculas.


Log.i("DEBUGGER", respStr);


Este Log, y como todos los otros, son solo para debugger, este nos va a tirar todo lo que devolvió el servicio.

String Resultado1= respJSON.getString("ResultadoDevuelto1");

Nuestro primero parámetro de out en el servicio genexus, se es una variable que se debe de llamar ResultadoDevuelto1, respetando mayúsculas y minúsculas, y es una variable simple que nos devuelve un solo valor.


JSONArray Resultado2= respJSON.getJSONArray("ResultadoDevuelto2");
Log.i("DEBUGGER", "Atributo1:"+unRes .getString("Atr1"));
Log.i("DEBUGGER", "Atributo2:"+unRes .getString("Atr2"));
 


Nuestro segundo parámetro de out, es ResultadoDevuelto2, y es una colección de datos, con Atr1 y Atr2 en cada uno de sus campos





Estas pocas lineas de código nos van a tirara en el log los valores que nuestro servicio nos devolvió, luego debemos de acomodarlas en donde nos quede mejor.




             

viernes, 2 de agosto de 2013

Update en mysql con subconsulta

El problema al que me enfrento es a tener que actualizar un registro en una tabla muy grande, que debe de ser igual que el valor que me devuelve una subconsulta, abajo pongo un ejemplo


update tabla1 set atributo1 = (select valor1 from tblvalores where valor2 = 'XXXXX') where ..........;

La subconsulta devuelve un solo registro para valor1, pero lo que hace es al recorrer toda la tabla1 para cada uno de los registros a actualizar se va a realizar la consulta anterior, haciendo que esto sea menos performante que un update sin la subconsulta, sino que con el valor1 directamente.

Entonces buscando soluciones encontramos  que en un script podemos con @id podemos registrar el valor de la subconsulta y luego hacer el update utilizando este valor.

Ejemplo de como quedaría la consulta de arriba.

select @id:= valor1 from tblvalores where valor2 = 'XXXXX';
update
tabla1 set atributo1 = @id where .......;

Esto es mas performante, ya que en la primer consulta realizamos 2n consultas, mientras que en la segunda n+1.