viernes, 9 de febrero de 2018

Despedida del blog

Buenas días con tod@s,

Siendo las 10 horas con 35 minutos de la mañana del día 09 de febrero del año 2018, me despido de este blog. Y aunque quedaron muchas cosas pendientes de las que publicar y comentar, las mismas ya no podrán ser realizadas ya que estoy cambiando de ambiente de trabajo y por ende de algunas herramientas a ser usadas. Ya que dejaré de trabajar con Genexus y me pasaré a otros IDEs más clásicos.

Así que está es la despedida de al menos este blog (aclarando que las entradas no serán eliminadas, ni nada de eso, aunque posiblemente ya no se responda a los comentarios ya que no poseeré de la herramienta respectiva para solventar ciertas dudas). Aunque si desean seguir leyendo algunas publicaciones tengo otros tres blogs para temas diferentes.

  1. Blog técnico para Software Libre y Sistemas informáticos, un poco abandonado por el momento. Pero en el cambio de ambiente esperamos retomar el mismo con nuevas entradas. Ej: Código Limpio, TDD, buenas prácticas de desarrollo, etc. Ver blog Aprendiendo con Sw Libre.
  2. Blog personal sobre todo tipo de inquietudes: poesía, libros, música, guitarra, etc. Ver blog En Busca de Identidad.
  3. Blog de Arte, Cultura y Guitarra Popular: a tratar temas de educación, arte, cultura, herramientas y guitarra de la cultura popular. Ver Gitaro Blog.
Y quién sabe tal vez por ahí algún día vuelva Genexus y retomemos este blog.

Saludos y pasen un excelente día.


martes, 22 de agosto de 2017

Imagen tipo blob desde una imagen agregada en Genexus

Buenas con todos.

Bueno después del respectivo saludo, explico un poco a que debe el nombre de la entrada. Estoy mostrando en un web panel los registros ingresados que tienen una imagen tipo blob en uno de sus campos, adicionalmente necesito mostrar una imagen por defecto para aquellos que no tenían configurada una.

Bueno entonces lo que necesito es poder cargar una imagen tipo blob ya no desde los campos de mi base sino con una imagen que yo decida. Tuve algunos inconvenientes, por ejemplo use la función FromBase64String y convertí mi imagen a este formato, peno no funcionó.

Así que la solución fue usar la función FromString que recibe la Url de la imagen, y para ello utilice una imagen ya cargada en el IDE de Genexus y la Función Link, quedando de este modo.

&ImageVarBlob.FromString(MyGenexusImage.Link())

viernes, 23 de junio de 2017

Encrypt URL parameters: Cifrado Manual de Parámetros con Site Key

Bueno en la anterior entrada revisamos la configuración para Cifrar los parámetros de la URL mediante Site Key y una forma automática de generar dichos enlaces. Para los que no, revisen el enlace aquí.

Pero si les paso lo que a mí, se deben de haber topado con la necesidad de generar esta URL de forma manual.

Bueno aquí corresponde una breve explicación de como Genexus realiza este cifrado de la URL.

Genexus utiliza el algoritmo TwoFish el cual está contenido en las funciones:

GetEncryptionKey, para obtener una llave o key de cifrado válida.
Encrypt64, para el cifrado en base a dicha llave.
Decrypt64, para el descifrado en base a una llave.

Genexus no solo cifra los parámetros sino que arma un string específico para el cifrado de los parámetros de la URL unido a un CheckSum de seis cifras, en el enlace pueden ver la documentación respectiva, aunque es del 2004, por lo que no ayudó mucho ya que ha habido un pequeño cambio en como se arma el String a cifrar.

Como vieron en la entrada anterior se mostró cómo configurar el Application.Key para administrar nuestras propias llaves. Gracias a esto se puede descifrar una URL y ver como está armada. Para mi caso actual usando Genexus Evolution 3 Upgrade 9. El cifrado de la URL corresponde a:

?objeto.aspxParametrosCheckSum

Siendo:

Objeto, nombre del web panel o transacción en minúsculas.
Parametros, los parámetros necesarios recibidos por el objeto separados por coma.
CheckSum, check sum del string formado por el objeto y los parámetros.

Entonces para cifrar correctamente de forma manual los parámetros de la url necesitamos armar dicho string y cifrarlo con las funciones ya mencionadas.

El código sería:

//cifrar parametros de url con Site Key
CSHARP [!&tempkey!] = Crypto.GetSiteKey( );
&toEnc = "webpanel" + '.aspx' + "param1" + ',' + "param2"
CSHARP [!&chkSum!] = Crypto.CheckSum( [!&toEnc!], 6);
&URL= &DominioSitio + '/webpanel.aspx?' + encrypt64(&toEnc+&chkSum, &tempkey)


Nótese que debemos usar las funciones Crypto.GetSiteKey() para obtener la llave usada en el cifrado y CryptoCheckSum() para generar el check sum de seis dígitos (por ello el parámetro de 6) con código Nativo C#.

Encrypt URL Parameters: Site Key para compartir enlaces con parámetros cifrados basados en Web Panel

Bueno hoy el objetivo fue cifrar los parámetros usados en los Web Panels de Genexus para evitar la manipulación de los mismos y adicionalmente poder compartir estos enlaces (Ej: Por un correo electrónico como un enlace).

Así que a buscar y probar. Basándonos en la Wiki de Genexus (enlace) respecto a este tema tenemos que existen dos formas de cifrar los parámetros:
  1. Basado en Web Session (Session Key): es decir que se usan características de la sesión del usuario para cifrar los parámetros. En la wiki recalca que es el más seguro pero ya que depende de los valores de la sesión y cookies del usuario el cifrado es diferente para cada sesión.
  2. Basado en una key por el sitio (Site Key): menos segura pero permite poder compartir los enlaces generados ya que el mismo cifrado es usado en todo la aplicación Web.
Para cifrar los parámetros use la segunda opción configurándola de la siguiente manera:
  1. En las propiedades del Ambiente de la KB se usa la propiedad Encrypt URL Parameters usando la opción Site Key.


  2. Rebuild de toda la KB para que se compile el uso de parámetros cifrados en todos los objetos pertinentes.
Para generar mi propia "key" y brindar mayor seguridad y administración a mi site y no usar la key por defecto de Genexus se usó los siguientes pasos:
  1. Generar un llave o dos (según la documentación de Genexus, ver SAC 29369, una es usada para cifrar los parámetros de conexión a la Base de datos y la otra para el cifrado de los parámetros) mediante la función GetEncryptionKey() (ver doc respectivo de la función para más detalles). 
  2. Crear el archivo de texto plano Application.Key (ubicarla en la raiz de la KB, del proyecto, para que el archivo web.config pueda ser actualizado con los parámetros respectivos cifrados y en la carpeta Web del modelo generado para que las clases respectivas puedan descifrar los parámetros).
  3. Editar el archivo creado con las "keys" generadas.


  4. Compilar y probar, si observan el archivo web.config tendrá un nuevo cifrado ya que se alteraron las "keys respectivas" y ya no se usan las que genera Genexus por defecto.
Para generar de forma automática los enlaces cifrados para poder compartirlos, se usó el método Link del objeto recibiendo los parámetros respectivos.

&Var = &urlsite + Link(WebPanel, &param1, &param2)

o

&Var = &urlsite + WebPanel.Link(&param1, &param2)

En la captura pueden observar el cifrado de los parámetros llamando una Transacción.


Quedó pendiente para una próxima entrada el cifrado manual de los parámetros (ver enlace).

Si desean configurar una clase (dll) y no un archivo que controle las "keys" ver el SAC 29874.

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.