jueves, 11 de agosto de 2016

Modificar un tag específico de un Archivo XML en Genexus

Bueno entre idas y venidas las necesidades apremian, por hoy modificar un tag específico de un Archivo XML.

Ahora si manos a la obra.

Primero obtener el contenido del tag que necesitamos modificar. Para ello leyendo un poco del Data Type XMLReader notamos que podemos usar la función ReadType para obtener el contenido del tag especificado y mediante la función Value obtener su valor.

&XMLReader.Open(&filePath)
&XMLReader.ReadType(1,"tag")
&tagValue = &XMLReader.Value
&XMLReader.Close()

En segundo lugar necesitamos obtener el contenido del archivo mediante el DataType File (más información del manejo de archivos aquí) y almacenar su contenido en un Varchar, en mi caso en la variable de nombre &XML.

&File.Source = &filePath
&File.OpenRead()
&XML = &File.ReadAllText()
&File.Close()

Tercero, armar dos Strings o Varchar, uno para búsqueda y otro para reemplazo dentro del String o Varchar obtenido anteriormente, que usaremos con la función StrReplace.

&search = "<tag>" + &tagValue + "</tag>"
&replace = "<tag>"+ &newTagValue.ToString().Trim()+"</tag>"
&XMLModified = StrReplace(&XML, &search, &replace)

Por último sobreescribimos el archivo XML con el nuevo contenido.

&File.OpenWrite(&filePath)
&File.WriteAllText(&XMLModified)
&File.Close()

PD: Para control de errores

sobre el XMLReader

&XMLReader.ErrCode
&XMLReader.ErrDescription

sobre el Data Type File

&File.ErrCode
&File.ErrDescription


lunes, 8 de agosto de 2016

Aplicación Java no despliega sobre Tomcat 8 en Genexus

Bueno hoy tocó hacer algunas pruebas sobre Java y Tomcat 8 con Genexus y me encuentro con la sorpresa de qué no se desplegaba mi app en el servidor de aplicaciones.

Tengo el servicio de tomcat levantado en forma manual asi que debo ingresar a la página de administración y arrancar la aplicación, al hacerlo me doy cuenta de un error en la app que no permite arrancarla:



Revisando el log de Tomcat ([path de instalación]/logs) me encuentro con un error relacionado con el GAM de Genexus, el cual no estoy usando:


Caused by: java.lang.NoClassDefFoundError: artech/security/api/gamrefreshtoken

pero googleando un poco me topo con el SAC#31566 que explica las configuraciones pertinentes para Tomcat 7, asi que a probar un poco las mismas para ver si funcionan sobre Tomcat 8.

Se editó justo lo que piden las configuraciones:
  • Asegurarse que la propiedad "use annotations for servlet definition" en web information se habilita (valor "Yes"). Propiedad ubicada en el Generador del ambiente Java correspondiente.

  • Utilizar la propiedad Java Package name y especificar un valor. (Por defecto ya venía configurada)


Y arrancando la app y accediendo al path correspondiente ya se despliega correctamente.

PD: Antes tocó solucionar otro error de clases no encontradas para la libreria gxscanner.jar:

java.lang.ClassNotFoundException: com.genexus.webpanels.GXJarScanner

o

Caused by: java.lang.ClassNotFoundException: com.genexus.webpanels.GXJarScanner

Que se solucionó incorporando la librería correspondiente en la carpeta lib de la aplicación en Tomcat descargada del site oficial de Genexus. Download. Les dejó tambien el acceso al SAC#36031  correspondiente (deben estar registrados en el site de Genexus para su descarga)

jueves, 16 de junio de 2016

Cliente Nativo Android para consumir Servicios Web SOAP y Restful generados en Genexus

De manera similar a la usada en Genexus con el HttpClient para configurar la llamada al servicio (Ver Entrada Anterior para Consumir y Generar Servicios desde Genexus), de la misma forma se usará un tipo de objeto específico para esta tarea en Android. 

Antes se usaban las clases de la biblioteca de Apache como el HttpClient, HttpRequest y HttpRespose para manejar las solicitudes al Servidor, pero a partir del Android 6.0 (API 23) se ha cambiado (ver cambios de la API 23) al uso de la Clase HttpURLConnection, más eficiente en el uso de la red y el manejo de la caché. La misma que usaremos en el presente ejemplo para los clientes de los servicios que creamos en Genexus anteriormente.

Cliente Nativo Android para servicio REST de Genexus

Bueno ahora si vamos con la implementación del Cliente para el servicio REST construido en Genexus, El código a explicar no fue implementado desde cero sino adaptado principalmente de Aquí y otras cositas traídas desde Aquí.

Así que lo que haré es proceder a explicar un poco la lógica del código y las Clases usadas. Para posteriormente dejarlos con el código completo implementado en la clase respectiva.

Como mencionábamos ahora se usará la clase HttpURLConnection que mediante un cast desde un objeto url permite configurar todas las opciones de la conexión como son tiempo de timeout, entre otras. Principalmente nos interesa las opciones setRequestMethod como POST y setReuqestProperty como “Content-Type” application/json“ ya que son los parámetros con los que Genexus construye el servicio Web.
HttpURLConnection urlConnection = null;
URL urlToRequest = new URL(serviceUrl);
urlConnection = (HttpURLConnection) urlToRequest.openConnection();
urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);
urlConnection.setReadTimeout(DATARETRIEVAL_TIMEOUT);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
Otro punto importante es no olvidar setear las configuraciones necesarias para permitir el envio de parametros y la recepcion de una respuesta.
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);}
Por último para manejar el parámetro a enviar al servicio web se usa el Formato JSON, basándonos en el nombre del parámetro del procedure (ApplicationId) y en la respuesta obtenida en el cliente construido en Genexus anteriormente en formato JSON, construimos a mano en un String el parámetro a Enviar. Adicionalmente configuramos el tamaño del cuerpo a enviar en la petición.
String body = "{\"ApplicationId\":1}";
urlConnection.setFixedLengthStreamingMode(body.getBytes().length);
Para enviar el parámetro respectivo al servidor en nuestra petición se debe usar un OutputSteam que se encargara de esta tarea.
byte[] outputInBytes = body.getBytes("UTF-8");
OutputStream os = new BufferedOutputStream(urlConnection.getOutputStream());
os.write(outputInBytes);
os.flush();
os.close();
Por último de manera similar para manejar la respuesta del server se usa un objeto de la Clase InputStream obtenido del objeto urlConnection. El mismo que ya puede ser usado para convertirlo a un String o JSON.
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
Bueno ahora si la Clase completa como se prometió anteriormente.

Y uso estas líneas para imprimir el resultado obtenido del servicio Rest en consola pasando como parámetro la url del Servicio Rest construido en Genexus:
JSONObject response = restservice.requestWebService("http://192.168.2.128/IAMEV3.NetEnvironment/rest/getapplicationsrest");
if (response.length() == 0){
    Log.i("MyHttpClientLibrary", "is null");
}else {
    Log.i("MyHttpClientLibrary", response.toString());
}
Importando la librerías respectivas
import org.json.JSONObject;
import android.util.Log;

Cliente Nativo Android para servicio SOAP de Genexus

De manera similar al Cliente Rest construido anteriormente se usará el objeto HttpUrlConnection un OutputStream para enviar el body construido mediante un String con la única diferencia que en este caso será con estructura xml, y un ImputStream para manejar la respuesta del servidor. El código base usado lo pueden ver Aquí.

Si revisan el código básicamente es el mismo salvo la requestProperty “Content-Type” que ahora es “text/xml”
httpURLConnection.setRequestProperty("Content-Type", "text/xml");
y las funciones createSoapHeader y getReqData que construyen el parámetro o body a enviar el server en fomato xml recibido por el Servicio Soap de Genexus. De manera similar al servicio explicado anteriormente, para construir el body o parámetro a enviar al servidor, se uso el wsdl del servicio, y las pruebas por Genexus para conocer como estructura Genexus la respuesta y el SOAClient mencionado en la entrada anterior para ver la trama cruda devuelta y configurar la cabecera y el cuerpo a enviar.

Se recomienda observar principalmente la línea o el tag siguiente que contiene como namespace el nombre de la KB usada y el nombre de la función a usar “getApplications.Execute”
<getApplications.Execute xmlns="IAMEV3"> </getApplications.Execute>
Observar el tag ApplicationId que acogen el parámetro usado en el servicio.
<Applicationid xmlns="IAMEV3">1</Applicationid>
Y por último los tags que acogen el cuerpo y los tags internos respectivos.
<SOAP-ENV:Body> </SOAP-ENV:Body>
<SOAP-ENV:Envelope> </SOAP-ENV:Envelope>
A continuación se muestra el código completo de la clase creada.

Por último para llamar a la clase correspondiente usamos:
SoapConsumer soapConsumer = new SoapConsumer();
String response = soapConsumer.callSOAPWebService("http://192.168.2.128/IAMEV3.NetEnvironment/agetapplications.aspx?wsdl");
Log.i("Soap Service: " , response);
Obsérvese que se envía como url el wsdl creado en Genexus.

Todo el código mostrado es solo un ejemplo básico de como consumir los servicios Web creados en Genexus usando las nuevas clases del API de Android y enfocándose en el formato que debe tener los parámetros de entrada principalmente.

Adicionalmente se podría usar clases especializadas para crear el body o los parámetros a usar para la petición al servidor ya sean XML o JSON, o incluso manejar unos parsers adecuados para tratar la respuesta del Servidor.

martes, 14 de junio de 2016

Generar Web Services SOAP y RESTful en Genexus y Consumirlos desde Cliente Nativo Android y App Web Genexus

Cabe mencionar que los ejemplos mostrados a continuación quieren mostrar la creación y el consumo de servicios Web, nada complejo en seguridad ni adicionales como Login en los servicios o manejo sobre protocolo https o cualquier otra cosa por el estilo.

Para está entrada se creará dos tipos de servicios (SOAP y RESTful) desde el IDE de Genexus en Ambiente Web para C# (C sharp). Adicionalmente se creará sus respectivos Clientes que consuman dichos servicios tanto desde Genexus como desde un Cliente Nativo Android.

Servidor

Para ambos servicios se usará el objeto "Procedure" de Genexus más ciertas configuraciones adicionales para establecer el servicio necesitado. Se tiene una "Transacción" Application con tres campos Id (Numeric), Name (VarChar), ClientId (VarChar) (Figura 1.), ClientSecret (VarChar). Se ha creado un objeto "SDT" basado en estos tres campos (Figura 2).

Fig 1. Transsacción

Fig 2. SDT


Servicio Web Tipo SOAP

Como ya se mencionó para habilitar los servicios Web se usa el objeto "Procedure". Así que crearemos un objeto de dicho tipo del nombre "getApplications" para el servicio SOAP.

En el código correspondiente al objeto tendremos una consulta mediante "For each" a la Tx Creada. Observesé la condición "where ApplicationId = &ApplicationId" que nos permitirá filtrar la información a obtener de la Tx y a ser almacenada en la variable SDT correspondiente.

for each
where ApplicationId = &ApplicationId
&sdtApplication =  new()
&sdtApplication.ApplicationName = ApplicationName
&sdtApplication.ApplicationClientId = ApplicationClientId
&sdtApplication.ApplicationClientSecret = ApplicationClientSecret
endfor


Posteriormente, en la sección de parámetros tenemos como entrada la variable "ApplicationId" y como salida la variable "sdtApplication".

parm(in: &ApplicationId, out:&sdtApplication);

En las propiedades del objeto configuramos las opciones:
  • Call Protocol: SOAP
  • Main Program: True
Para probar la generación del servicio se puede acceder a la url:

http://[localhost o ip local]/[Nombre de la la KB].[Ambiente Web de la KB]/a[nombre del procedure].aspx


Fig 3. URL de Servicio SOAP

Para unas pruebas más exhaustivas se puede instalar "SOA Client" en mi caso el add-On para el Navegador Firefox (Descarga Aquí) y añadiendo en la ruta anterior el parámetro ?wsdl usar directamente el servicio Web como se puede observar en la figura 4.

Fig 4. Consumo de SOAP mediante SOA Client

Servicio Web Tipo RESTful

De manera similar podemos usar un objeto "Procedure" para un servicio tipo RESTful, Para mantener el código y parámetros anteriores podemos hacer un Save As del objeto anterior (Poniendo por default las configuraciones cambiadas anteriormente) o usar un nuevo "Procedure" con el mismo código y parámetros. El nombre del procedure será "getApplicationsRest".

Pero en el cual configuramos las siguientes opciones de las propiedades:
  • Expose as a web Service: True
  • Rest Protocol: True
Para probar la generación del servicio se puede acceder a la url:

http://[localhost o ip local]/[Nombre de la la KB].[Ambiente Web de la KB]/rest/[nombre del Procedure]

De manera similar para otro tipo de pruebas se puede instalar el Add-On "Rest Client" sobre el Navegador Firefox (Descarga Aquí) ver la figura 5.

Fig 5. Consumo de REST mediante Rest Client


Cliente

Cliente Web Genexus para servicio SOAP

Bueno si recuerdan la Url del servicio SOAP, aquella compuesta por la terminación wsdl, pues esta misma url es vital para construir el Cliente para el consumo del servicio. Esta url si la abrimos en el navegador como muestra la figura 6, nos muestra en formato xml principalmente:

  • El NameSpace en el que se ejecuta el Servicio, en este caso el nombre de la KB.
  • El nombre del método o Acción a llamar.
  • Los parámetros de entrada y el tipo de dato.
  • Los parámetros de salida y su tipo de dato.

Fig 6. WSDL del servicio SOAP construido en Genexus.

Toda esta información es usada por Genexus en un Wizard para construir un "External Object" y un "SDT", que consuma el servicio y lo almacene respectivamente.

Podemos usar una nueva KB, o la misma si se desea, y nos ubicamos en la opción del menú Tools / Application Integration / WSDL Import

Fig 7. Acceso al WSDL Import.

Obtendremos la pantalla correspondiente donde ingresaremos la url respectiva. Ver figura 7.

Fig 8. WSDL Import.

Una vez realizado el import del WSDL, podemos observar que se ha creado un External Object para la llamada al servicio SOAP y un SDT para su almacenamiento.

Fig 9. External Object creado por WSDL Import.


Fig 10. SDT creado por WSDL Import.

Para consumir los mismos podemos hacer una llamada desde una pantalla Web mediante el uso de una variable basada en el External Object creado por el wizard y almacenándolo en el SDT respectivo:

&getAppsdtApplication = &getApplications.Execute(&ApplicationId)

Nótese que mediante el método Execute del External Object se pasan los parámetros del web Service, en este caso recibe la variable &ApplicationId de tipo Numeric. Otra cosa a notar es que para Genexus es transparente el uso de xml para el intercambio de información, tanto para el servidor al momento de enviar los datos por el servicio como para el cliente al momento de consumir el mismo.

Cliente Web Genexus para servicio RESTful

Bueno para consumir un servicio Rest en Genexus es un poco más complicado ya que no existe ningún wizard como en el caso de Soap, pero se puede usar un tipo de objeto llamado HttpClient para realizar la llamada al mismo y capturar la respuesta del servidor.

Adicionalmente en el HttpClient, se debe configurar:
  • El Servidor al cual se va a acceder.
  • La Url base del Servicio Rest.
  • El puerto usado para la conexión.
  • El cuerpo o body, es decir los parámetros de entrada en formato JSON.
  • La cabecera como tipo 'Content-type' y 'application/json'.
  • El nombre del servicio (en este caso el nombre del procedure) y el Método Http a usar (en base a la documentación de la Wiki de Genexus se debe usar siempre el método POST).
Todas estas configuraciones son visibles en el siguiente código:

&httpclient.Host = "localhost" //Servidor
&httpclient.Port = 80 //Puerto
&httpclient.BaseUrl = "/IAMEV3.NetEnvironment/rest/" //Url Base
&httpclient.AddHeader('Content-type','application/json') //Cabecera
&httpclient.AddString('{"ApplicationId":1}') // body o parámetros de entrada en formato JSON

Para ejecutar el cliente http se usa el método Execute especificando el método Http y el nombre del procedure.

&httpclient.Execute('POST','getapplicationsrest')

Para la captura de la respuesta simplemente se puede hacer un String del HttpClient.

&httpclient.ToString()

Y para la visualización de Errores se puede usar los métodos ErrCode y ErrDescription del HttpClient.


&httpclient.ErrCode
&httpclient.ErrDescription


Cliente Nativo Android para servicio SOAP y RESTful (Ver Aquí)

lunes, 22 de febrero de 2016

Leer XML desde un String

Bueno el objetivo de esta entrada es permitir leer un XML desde un string (que puede ser obtenido mediante un Archivo o un Web Service, que no será tratado en la misma) y mediante el uso del Data type XMLReader procesarlo para que pueda ser usado en un SDT y todas las ventajas que este ofrece. Sin más que acotar empecemos.

Se declaran las variables:
  • mensaje de tipo Varchar(200) o LongVarChar (2M) dependiendo del tamaño del texto. Esta variable contendrá el XML en forma de cadena de caracteres o de String.
  • XMLReader de tipo XMLReader. Este tipo de objeto permitirá crear un lector para el procesamiento del formato XML. click aquí para más información.
  • XML de tipo Varchar(200) o LongVarChar (2M) dependiendo del tamaño del texto, esta variable almacenará el XML crudo como String o cadena.
  • SDT de tipo del SDT especialmente construido para guardar la información del XML.

Y mediante el código fuente a explicar:

Básicamente en las variables anteriores ya se definió el funcionamiento del siguiente código salvó la merecida explicación de las funciones Read() que permite procesar la información desde el string hacia el objeto XMLReader; y la función ReadRawXML() que permite enviar el contenido del lector como XML hacia una variable, para que esta pueda ser usada en el llenado del SDT con la función FromXML().

&XMLReader.OpenFromString(&mensaje)
&XMLReader.Read()
&XML = &XMLReader.ReadRawXML()
&SDT.FromXml(&XML)

viernes, 19 de febrero de 2016

Atajos de Teclado IDE Genexus

Aquí dejo un listado de los atajos de teclado que al menos yo uso más para el IDE de Genexus.


F12

Permite navegar directo y abrir el objeto sobre el cual se encuentra ubicado el cursor.


F4

Permite desplegar la vista de propiedades del objeto.



F5

Permite Ejecutar la base de conocimiento (Run).


Ctrl + F

Permite desplegar un cuadro de diálogo para hacer búsquedas de texto sobre el código.



Ctrl + H

Permite desplegar un cuadro de diálogo para hacer reemplazos de texto sobre el código.



Ctrl + S

Permite guardar los cambios del objeto sobre el que se está trabajando.


Ctrl + J

Permite desplegar la pestaña Work With Objects.


Ctrl + F12

Permite desplegar la pestaña de References (Referencias) del objeto.


Ctrl + Shift + H

Permite desplegar la pestaña de History (Histórico de cambios) del objecto.


Ctrl + Shift + S

Permite guardar los cambios de todos los objetos que están siendo editados.


Nota

Adicionalmente los atajos ya conocidos de Ctrl + C, Ctrl + V, Ctrl + X (copy, paste and cut). Algunos de estos nos sirven solo para copiar, pegar o cortas objetos o código sino incluso para trabajar con variables en el paso de un objeto a otro.

Y obviamente los infaltables Ctrl + Z (deshacer un cambio) y Ctrl + Y (rehacer un cambio).


Referencia Completa de los comandos

Genexus, Wiki, site.