Etiqueta

Mostrando entradas con la etiqueta #OMNIS. Mostrar todas las entradas
Mostrando entradas con la etiqueta #OMNIS. Mostrar todas las entradas

28 diciembre 2018

Nueva herramienta de migración de Omnis DF1 a SQLite o PostgreSQL

Otra de las novedades que incluye Omnis Studio 10, supone una garantía de estabilidad y longevidad para nuestras aplicaciones, especialmente en lo que al uso de la base de datos nativa (los llamados df1) se refiere. La gran ventaja que supondrá el uso de ésta herramienta es, que tras su conversión a una base de datos SQLite o PostgreSQL, los antiguos comandos denominados "Omnis DML" permanecerán en la biblioteca convertida, pero, (y este es el importante detalle) se ejecutarán contra la base de datos seleccionada (SQLite o PostgreSQL), sin problemas y automáticamente, en lugar del antiguo fichero de datos Omnis. Por ejemplo, comandos como "Prepare for edit" o "Update files" se ejecutaran contra la nueva base de datos (SQLite o PostgreSQL). 



Sin duda ésta opción, es muy bien recibida por todos aquellos que hemos deseado por mucho tiempo, disponer de un almacenamiento de datos más robusto, proporcionándonos a la vez, una cómoda puerta de salida, en la migración de nuestras antiguas aplicaciones hacia el soporte de código SQL. Un mejorado "OmnisSQL DAM" será el encargado de producir el "milagro" de acceder a un fichero SQLite como si se tratase de un antiguo fichero .df1

Se han realizado pruebas con el nuevo "OmnisSQL DAM" contra archivos de datos SQLite y Omnis, tanto directamente como utilizando "Data Bridge". Las pruebas se han realizado insertando ~ 2.5MB y leyendo ~ 20MB de un archivo de datos. Los tiempos de finalización de la prueba se muestran en segundos.


27 diciembre 2018

Objetos "JavaScript Worker"

Omnis Studio 10, ahora tiene embebido (integrado) el "framework" "node.js", el cual incluye gran cantidad de módulos de código abierto desarrollados por terceros y que (por tanto) podremos usar libremente desde nuestro código Omnis. Un nuevo "Worker Object" denominado "JavaScript Worker Object" nos permitirá ejecutar métodos de "node.js", mediante simplemente invocarlo desde nuestro código Omnis, para posteriormente recibir los resultados en el método indicado como retorno del mismo. A modo de ejemplo, Omnis incluye la librería "xml2js" la cual permite convertir un XML a JSON.

Construcción de métodos JavaScript


Con éste fin Omnis dispone de un nuevo archivo JS, denominado "ow3javascript.js", el cual podremos localizar bajo el directorio "clientserver/server/remotedebug" y que es el punto de partida para todas las llamadas a los métodos de "node.js". Éstas llegaran desde Omnis como solicitudes HTTP y retornaran sus resultados también como contenido HTTP. Cada "Worker" ejecutará sus métodos secuencialmente.

Un nuevo directorio o carpeta denominada "node_modules", contendrá los módulos que serán requeridos desde el "ow3javascript.js". Es aquí, donde deberemos ubicar lo módulos "node.js" que deseemos utilizar, mediante el comando "npm -i" ejecutado desde ésta misma carpeta; éstos serán los módulos que ineraccionaran con nuestras aplicaciones Omnis.

Existen al menos dos archivos clave que siempre deberán estar ubicados y presentes en ésta carpeta:

  • omnis_calls.js - Módulo que encargado de devolver los resultados a Omnis.
  • omnis_modules.js - Módulo encargado de suministrar la lista de los que podrán ser invocados desde Omnis.

En ésta misma carpeta, podremos localizar dos módulos suministrados a modo de ejemplo denominados: "omnis_test.js" y "omnis_xml2js.js". Vistos desde Omnis sus nombres son "test" y "xml2js", a cada uno de ellos le corresponderá una entrada en el "omnis_modules.js" proporcionándose así la lista de métodos que podrán ser invocados desde Omnis.

Creación de un "Worker"


Asigne el subtipo del objeto externo "OW3 Worker Objects\JAVASCRIPTWorker", a una variable de tipo "Object" u "Object Reference", , también puede hacerse mediante crear una clase objeto a la que asignar el "subtipo" ya indicado, para luego asignarlo a una variable Omnis.

¡¡Importante!! Antes de invocar su método "$init", será necesario configurar su propiedad "$callbackinst", para indicar dónde recibir los resultados. Por ejemplo: "Calculate Object.$callbackinst as $cinst"

Propiedades


El "Worker JavaScript" soporta las propiedades "Worker" estándar: $state, $threadcount, $errorcode y $errortext.

Métodos de invocación


$init([cPath, bDebugNodeJs=kFalse])


Permite preparar el objeto, de forma que esté listo para ejecutar llamadas a métodos JavaScript. Devuelve "true" si tiene éxito. Debe ejecutarse antes que cualquier otro método.

  • cPath
    Permite cambiar la ruta de búsqueda de módulos predeterminada "NODE_PATH". La ruta predeterminada es "≤Carpeta de datos Omnis≥/node_modules". Tenga en cuenta, que sí cambia esta ruta, el resto de módulos que son obligatorios también deberán ser alojados en la nueva ruta.

  • bDebugNodeJs
    Booleano que indica si se desea poder depurar "node.js", por ejemplo, mediante Chrome. Es posible que no pueda iniciarse el "Worker" si se configura para más de un "Worker JavaScript" en activo, ya que "node.js" requiere de un puerto para depuración disponible. Para su depuración en Chrome, introduzca "chrome://inspect", y luego abra las herramientas de depuración dedicadas para "node.js". 

$start()


Ejecuta el "Worker JavaScript" en segundo plano. Devuelve "true" sí ha sido iniciado correctamente. El método $start(), se encargará de iniciar "node.js" he invocar los métodos JavaScript. Seguramente realizaremos llamadas a diferentes métodos del mismo proceso, por lo que no será necesario ejecutar $start() con frecuencia, lo que significa que la sobrecarga debida a la ejecución de procesos "node.js" es mínima.

$cancel


Cancela la ejecución del proceso "node.js". Cualquier método ya en progreso no será completado.


$callmethod(cModule, cMethod, vListOrRow [,bWait=kFalse, &cErrorText])



Permite la invocación de un método, al cual se pasa un solo parámetro desde el objeto JavaScript ("vListOrRow"). Opcionalmente se esperará a que el método complete su ejecución ("bWait"). El método devolverá "true" si la invocación es exitosa. "cModule" y "cMethod" identifican al módulo y al método dentro del módulo, que será invocado. "vListOrRow" será convertido a formato JSON antes de su paso al método como parámetro. El uso de "bWait" indicará que deseamos suspender la ejecución, hasta que el método haya terminado. "cErrorText" recibirá un texto descriptivo del error, en caso de fallo de "$callmethod".



Métodos de retorno




$cancelled


Se puede reescribir este método (Override) si se desea controlar la notificación correspondiente a una cancelación del "Worker" realizada correctamente.

$workererror(wError)


La reescritura de éste método (Override), permite recibir notificaciones de error del "Worker" no relacionados con la invocación a alguno de sus métodos, como, por ejemplo, un error producido al iniciarse "node.js". El sub-proceso del "Worker" se cerrará tras la generación de dicha notificación. "wError" contiene dos columnas, un entero llamado "errorCode" y un texto llamado "errorInfo".

$methoderror(wError)


La re-escritura de éste método (Override), permite recibir notificaciones de error tras el intento de invocar un método mediante "$callmethod". "wError" tiene dos columnas, un entero llamado "errorCode" y un texto llamada "errorInfo".

$methodreturn(wReturn)


Éste es el método al cual llegarán los resultados tras la ejecución de un "$callmethod". "wReturn" es una variable de tipo "row". Si el método de JavaScript devuelve un objeto, será el equivalente Omnis creado al convertir el JSON en una "row". Si el método de JavaScript devuelve otros datos, como por ejemplo. una imagen, esta consistirá en una "row" con una sola columna denominada "content", con los datos devueltos por el método.

26 diciembre 2018

El nuevo Depurador Remoto

La depuración remota permite depurar el código Omnis de una librería compartida en la red. Omnis usa para ello una versión “developer” independiente, el llamado “remote debug client”, el cual se conectará a través de la red a otro Omnis Studio, denominado “remote debug server”.


Algunos aspectos a tener en cuenta:

  • El “remote debug server” es quien ejecuta el código a depurar, y puede residir en cualquier tipo de instalación: “development”, “runtime”, “server” o “headless server”.
  • El código Omnis es ejecutado en modo “multi-threaded server”, creándose para ello pilas de procesos independientes de la principal.
  • El “remote debug server” y el “client” no precisan estar ejecutándose en el mismo sistema operativo.
  • La versión “client” debe ser la misma o posterior a la versión “server”.
  • Las clases protegidas y las bibliotecas bloqueadas también pueden ser depuradas.

Aunque hablamos de “depurador remoto”, en realidad, tanto el cliente como el servidor podrían residir en la misma máquina, de hecho cliente y servidor podrían contener los mismos procesos Omnis. En este último caso, el “remote debug client” es ejecutado con algunas restricciones, indicadas mas adelante en este artículo.

Conectividad


El “client” y el “server” se conectan entre sí a través de un WebSocket. Una conexión WebSocket es una conexión directa entre cliente y servidor, por lo que puede requerir de la apertura del puerto correspondiente en el “firewall”. Puesto que las conexiones WebSocket se inician como conexiones HTTP, un WebSocket puede soportar una conexión TLS segura, así como el requerimiento de un certificado de autenticación para el cliente. El “remote debug”, usa siempre una conexión TLS, por lo que el WebSocket es iniciado como HTTPS.

La conexión entre un cliente y un servidor es denominada “remote debug session” o simplemente “session”. Omnis podrá ejecutar una sola “session” a la vez.

El "Remote Debug Server"


Desde la versión “developer”, podremos configurar el “remote debug server” tras hacer clic sobre su nodo en el “Browser”, y seleccionar la opción “Remote Debug Server”.

Para una versión “runtime” de Omnis (no “headless”), y si la librería “remotedebug.lbs” está en la carpeta “startup”, se dispondrá de un menú denominado “Remote Debug”. El cual contiene una sola opción, que permite abrir la ventana de configuración. Si se trata de un servidor “headless” podremos llevar a cabo la configuración desde la ventana de administració (osadmin).

La ventana de configuración muestra dos pestañas, una para controlar el servidor y otra para configurarlo.

La pestaña “Control Server” tiene un solo botón, utilizado para arrancar o detener el servidor. De no encontrarse arrancado, no aceptará conexiones desde un cliente.

La pestaña “Configure Server” permite llevar a cabo su configuración, muestra los campos que corresponden a las entradas en el archivo de configuración y que describiremos a continuación.

El fichero de configuración


La configuración se guarda en el fichero denominado  “remote_debug_server_config.json”, ubicado en “clientserver/server/remotedebug” de la carpeta de instalación Omnis. Podemos optar por editar este archivo JSON directamente con cualquier editor o usar la opción descrita anteriormente.

Debemos tener en cuenta que Omnis hace uso de un servidor “node.js” ejecutado junto con Omnis, desde el se construye el servidor WebSocket. Como consecuencia, parte de la información de configuración es compartida también con “node.js”.

Configuración ejemplo:

{
   "debugPort": 8080, 
  "serverPfx": "server.pfx", 
  "pfxPassPhrase": "xxxxxx", 
   "ca": [ "server_cert.pem" ], 
  "requestCert": false, 
  "rejectUnauthorized":  false, 
  "userName": "myUser",
 "hashedPassword":   
 "AAGGoAAAABBSEkknQUIeHQHu1sIyWxlSAAAAIHw9kvCVF4tE//S   MpbSGVD/RKJLekoR7TlTvZVy3MbkJ", 
   "startRemoteDebugServerAtStartup": true,
   "pauseAtStartupUntilDebuggerClientStartsExecution": false,
   "logConnectionSetup": false
}

debugPort

El puerto TCP/IP en el que el servidor WebSocket escucha las conexiones entrantes desde el cliente.

serverPfx

Este es un archivo que contiene el certificado del servidor y la clave privada. Debe estar en el mismo directorio que el “remote_debug_server_config.json”. La instalación por defecto consta de un certificado auto-firmado y una clave generada mediante el comando openssl (disponible en cualquier sistema con openssl instalado). Tendrá que proporcionar su propia clave privada y su certificado. Puede generar una nueva clave privada y un certificado auto-firmado utilizando los siguientes comandos:

openssl req -x509 -newkey rsa:4096 -keyout server_key.pem -out server_cert.pem -nodes -days 1024 -subj "/CN=localhost/O=Demo" -passin pass:xxxxxx
openssl pkcs12 -export -out server.pfx -inkey server_key.pem -in server_cert.pem

Este archivo deberá ser indicado bajo la opción “PFX” y es invocado por el método https.createServer() de “node.js”. Podrá encontrar más información sobre esto, en la documentación de “node.js”:

https://nodejs.org/docs/latest-v8.x/api/https.html#https_class_https_serve 
https://nodejs.org/docs/latest-v8.x/api/tls.html#tls_tls_createsecurecontext_options

pfxPassPhrase

Esta es la frase-contraseña utilizada para proteger el archivo PFX en el servidor. En nuestro ejemplo es "xxxxxx".

ca

Ver https://nodejs.org/docs/latest-v8.x/api/tls.html#tls_tls_createsecurecontext_options para más detalles. Normalmente, usted sólo tendrá un CA, puesto que tiene un sólo certificado auto-firmado, en cuyo caso tendremos una sola entrada. En nuestro ejemplo el certificado fue firmado usando “server_cert.pem”. Generalmente su valor es una lista separada por comas de certificados de confianza, nombres de archivos los cuales deben residir en el mismo directorio que el “remote_debug_server_config.json”.

requestCert

Valor booleano. Si es verdadero, el servidor “node.js” solicitará un certificado para autenticar al cliente. Los certificados de cliente se explican más adelante, en la entrada conectividad del cliente.

rejectUnauthorized

Valor booleano. Si es verdadero, el servidor rechazará cualquier conexión no incluida en la lista de CA’s suministrada. Esta opción solo tiene efecto si “requestCert” es cierto.

userName

Si no está vacío, la conexión WebSocket también usará autenticación básica HTTP con el usuario, en cuyo caso este campo deberá contener el nombre del usuario utilizado para la autenticación básica HTTP.

hashedPassword

Si “userName” no está vacío, será el "hash" PBKDF2 de la contraseña requerida para la autenticación básica HTTP.

startRemoteDebugServerAtStartup

Esta opción booleana indica si el “remote debug server” debe iniciarse  automáticamente al iniciarse Omnis.

pauseAtStartupUntilDebuggerClientStartsExecution

Si el “remote debug server” está configurado para iniciarse automáticamente cuando se inicia Omnis, podremos configurar esta opción booleana a “true” para causar que Omnis pause su ejecución durante el momento de ejecutar la “startup_task” y otras "tasa" iniciales de nuestra librería Omnis.

Cuando se utiliza esta opción, Omnis muestra un mensaje de trabajo (Waiting for remote debug client to start execution…), entrando en un bucle de espera, hasta que se reciba un comando desde el cliente para ejecución. Durante este bucle, el cliente podrá ver y depurar el código remotamente, mediante (por ejemplo) establecer puntos de interrupción.

El bucle termina cuando el cliente envía un comando de inicio de ejecución, cuando la sesión con el “remote debug server” es cerrada o cuando un usuario hace clic sobre el botón “cancel” situado junto al mensaje de trabajo mostrado en el servidor. Cuando el bucle termina, Omnis ejecutará la “startup_task” de la librería.

El “Remote Debug Client”


El “remote debug client” es accesible a través de un nuevo nodo situado sobre el árbol del navegador de Studio denominado, "Remote Debug Client". Utiliza un modelo de sesión similar al de VCS. Tras hacer clic sobre el nodo, se mostrarán los enlaces “Session Manager”, y “Open Session”.

El “Session Manager” permite configurar las sesiones de depuración remotas. Cada sesión contendrá los parámetros que permitirá al cliente iniciar un WebSocket de conexión con un “remote debug server”. A continuación describimos cada uno de sus parámetros:

Name

Nombre que identifica el sesión.

Server

Dirección IP o nombre DNS del “remote debug server”.

Debug Port

Puerto configurado en el “remote debug server”. En su conexión al servidor, el cliente construirá la URL siguiente:
wss://Server:DebugPort

Client Certificate

Si el servidor requiere un certificado de cliente, deberá especificarse aquí. Podrá generar un certificado de cliente usando los siguientes comandos openssl:
openssl req -newkey rsa:4096 -keyout client_key.pem -out client_csr.pem -nodes -days 1024 -subj "/CN=192.168.1.11" -passin pass:xxxxxx
openssl x509 -req -in client_csr.pem -CA server_cert.pem -CAkey server_key.pem -out client_cert.pem -set_serial 01 -days 1024
Tenga en cuenta que en este ejemplo usamos la clave y el certificado de servidor utilizados con el ejemplo para el “PFX”. Paro, el certificado del cliente necesitará ser instalado en la máquina del cliente.

Para Windows, genere un archivo “client.pfx”:
openssl pkcs12 -export -out client.pfx -inkey client_key.pem -in client_cert.pem
Añada el “client.pfx” al almacén de certificados de Windows, mediante hacer doble clic  en el archivo, agregándolo a “Personal certificates” del usuario en curso.

Para macOS, genere un archivo “pkcs12”:
openssl pkcs12 -export -out client.p12 -inkey client_key.pem -in client_cert.pem
Haga doble clic sobre el archivo para agregarlo al llavero.
Puede encontrar más detalles sobre esto en la documentación sobre CURL en:
https://curl.haxx.se/libcurl/c/CURLOPT_SSLCERT.html
Tenga en cuenta que el parámetro “Client Certificate” pasa su valor al comando CURL bajo la opción CURLOPT_SSLCERT.

En caso de Windows, el parámetro es la ruta hacia el lugar donde está almacenado…
CurrentUser\MY\afe2179599460d20da08c12e8c328d84bd300735
…donde afe2179599460d20da08c12e8c328d84bd300735 es la huella digital, visible mediante hacer doble clic en “certificate” del MMC (MMC certificate snap-in view, pestaña “details”, campo “thumbprint”).

En caso de macOS, se puede especificar la ruta del archivo “p12” o el nombre que tiene en el llavero del cliente.

User Name

Si el servidor utiliza autenticación básica HTTP, es el nombre de usuario requerido.

Password

Si el servidor usa autenticación básica HTTP, será la contraseña requerida.  Alternativamente, podrá dejarse vacía, causando que se le solicite al cliente la cuando sea necesaria.

Server Connection Logging

Mediante ésta opción podremos monitorizar la conexión con el “remote debug server”, para poder observar cualquier problema de conexión. También deberemos habilitar ésta opción en el archivo de configuración, bajo la entrada “logConnectionSetup”.

Si está habilitado, se creará un archivo de registro  denominado: “.htm” en el directorio “logs/remotedebug , con el registro de lo que ha ocurrido al conectarse al “remote debug server”. Tenga en cuenta que el registro no se escribe hasta que la conexión es cerrada.

Preparación del código para su depuración remota


Deberemos habilitar en nuestras librerías e instancias de tipo tarea “task” la capacidad “remote debugging” mediante configurar su propiedad $remotedebug.

Library


Por defecto, una librería no puede ser depurada remotamente, lo que significa que cuando el cliente intente conectarse para depuración, normalmente no aparecerá en el interfaz de cliente. Si queremos que aparezca necesitaremos establecer su propiedad “$clib.$remotedebug”, como “True”, lo cual no podrá realizarse sobre librerías ya marcadas como privadas, lo que significa que deberemos fijar esta propiedad como “true” antes de hacerla privada.

Task


La configuración de “$clib.$remotedebug” permite que la librería y sus clases aparezcan sobre la ventana cliente de depuración remota. Permitiéndonos manipular su código y establecer “break points”.

Sin embargo, sólo las clases “task” y “remote task” marcadas para depuración remota, reaccionarán ante los “breack points” que fijemos. Esto permitirá un mayor control sobre lo que podrá o no podrá ser depurado remotamente y del lado del servidor, permitirá evitar que un “breack point” detenga la ejecución para otros posibles clientes en uso.

Para marcar una “task” o “remote task” para depuración remota, configure su propiedad
“$remotedebug” a kTrue.

Tabién podremos activar ésta propiedad, cómo un parámetro en el URL de conexión, hacia un “remote form” (omnisRemoteDebug = 1), por ejemplo:
http://127.0.0.1:5981/jschtml/jsDragDrop.htm?omnisRemoteDebug=1

Interfaz del depurador remoto 

Abriendo un sesión

Para usar el “remote debugger client” tras configurar una sesión, haga clic sobre el nodo “Remote Debug Client” y después sobre el enlace “Open Session”, luego haga clic sobre el enlace correspondiente a la sesión que deseemos utilizar.

Esto hará que el cliente inicie una conexión WebSocket con el servidor. Mientras se establece, se mostrará su progreso sobre el panel del navegador, aunque suele ser muy rápido. Además, aparecerá un nuevo enlace durante éste proceso denominado “Cancel Open Session”.

Browsing Libraries

Una vez abierta la sesión, se mostrarán las bibliotecas marcadas para depuración remota.

Los nodos secundarios del “Remote Debug Client” tienen un comportamiento similar al de los habituales para la edición de librerías. Cuando seleccionamos alguno de éstos nodos secundarios, el panel del navegador se actualizará para mostrar su contenido permitiendo la edición de todo el contenido de la librería.

Si se selecciona una sola clase en el panel del navegador, se mostrará un enlace denominado "Open debug window". Haga clic sobre él para abrir la ventana de depuración remota para esa clase.

Finalmente, si el servidor está en pausa y por tanto a la espera de ejecutar el inicio, entre los enlaces podrá ver uno con el nombre “Run Startup”, mediante el cual podrá indicar al servidor que debe continuar y ejecutar su proceso inicial.

La ventana del “Remote Debug”

Esta ventana muestran un diseño muy similar al del editor de métodos. Su diferencia principal está en que siempre muestra el panel de depuración y no existe un panel de edición, y en su esquina inferior derecha aparece un nuevo panel de variables.

La barra de herramientas (Instance)

Permite mostrar los métodos u objetos específicos de una instancia actualmente en uso. El menú “Instance” nos permitirá cerrarla, así como también retirarla o añadirla a la lista del depurador.

Tenga en cuenta que este menú se desactiva tan pronto como la ventana de depuración remota es asociada, es decir durante el proceso de depuración de una instancia.

Observaciones

Deberemos tener presente que el conjunto de librerías e instancias, susceptibles de ser depuradas pueden cambiar en el servidor. Omnis mantiene al cliente constantemente actualizado con respecto a la situación en que se encuentre el servidor. Por ejemplo, si una librería se cierra en el servidor, se informa al cliente y se actualiza su interfaz lo que significa su eliminación del navegador y el cierre de cualquier ventana de depuración remota relacionada. Sin embargo, si se producen cambios en un método en el servidor, el cliente no recibirá el método actualizado hasta que sea de nuevo solicitado, debe tenerse en cuenta que cada vez que el cliente realiza una operación de depuración, el cliente solicita el método y retiene una copia del mismo, hasta que la acción termina, si durante ese proceso, el método ha cambiado en el servidor, el cliente no lo recibirá hasta necesitar una nueva copia.


25 diciembre 2018

Omnis Developers Conference, Mexico City – Lunes 11 de Marzo 2019

Lunes 11 de Marzo 2019,  Omnis Developers Conference, Mexico City

Martes 12 + Miercoles 13 Marzo 2019,  Omnis Academy, Mexico City
Objetivos
  • Conocer OMNIS Studio
  • Presentar de la nueva versión 10
  • Componer aplicaciones que traspasan las fronteras
  • Componer aplicaciones Web y Moviles (Android, iOS, Windows 10)
  • Establecer contactos, conociendo más detalle sobre aplicaciones y proyectos.

Consulte la agenda e inscríbase hoy mismo...

04 julio 2018

¿Que habrá en Omnis Studio 9?

En la conferencia "Omnis Developer" celebrada en mayo de este año en Alemania, Bob Mitchell, (Omnis Engineering Manager) desveló algunas de las características que podremos ver en el futuro Omnis Studio 9. De todas ellas, con seguridad la más atrayente es su totalmente renovado editor de código, realmente un paso esperado por la comunidad de desarrolladores y que hace de Omnis Studio una herramienta aún más rápida y eficaz en el desarrollo de aplicaciones web y dispositivos móviles.

En su exposición (disponible en YouTube) Bob describe los cambios de sintaxis, que también se introducen junto con la entrada del nuevo editor de código Omnis.


El nuevo editor reemplazará al actual de disposición en lista, ampliando las opciones del actual "Code Assistant". La escritura de código se realiza al estilo de un editor de texto convencional, pero cuando es necesario, el "Code Assistant" hace su aparición de forma totalmente automática ayudándonos a completar expresiones, nombres, opciones y parámetros de los comandos. No obstante y en cualquier momento, se puede presionar Ctrl-espacio para abrir el asistente de código y obtener así ayuda relativa al contexto, incluso con una descripción completa del comando y ejemplos de uso.

A continuación enumeramos algunas de sus características:

  1. Diseño rígido (el código aún se guarda de forma codificada)
  2. Utiliza una fuente de ancho fijo.
  3. Aumento de la capacidad de "deshacer" y "rehacer" (disponible también desde otros ámbitos del futuro Omnis Studio 9)
  4. Coloración de sintaxis: nuevos colores para indicar el alcance de las variables, opciones de comandos, funciones, etc.
  5. Las construcciones de comandos con cierres se auto-completan, por ejemplo, al escribir "If" se añade automáticamente el "End If".
  6. El panel de ayuda muestra tanto su sintaxis, como una descripción completa del comando.
  7. Los errores en el código, son marcados mediante un subrayado rizado.
  8. Diferentes opciones seleccionables desde la paleta situada en la parte superior del editor, permiten obtener ayuda sobre parámetros así como la localización y corrección de errores, entre otras muchas funciones.
  9. Permite la declaración de variables con ámbito y tipo automático indicado por medio de prefijos y sufijos, por ejemplo, "iVarList" será una variable de instancia (prefijo "i") de tipo "list" (sufijo "List").
  10. Nuevas opciones tales como, "Goto line number", "Select line", "Upper/Lower case", triple-clic para seleccionar una línea de código para (por ejemplo) eliminarla y búsqueda por palabras, entre otras.
  11. Una nueva propiedad denominada "$keys" que funciona en conjunción con un fichero de nombre "keys.json", permite configurar y guardar todos los atajos de teclado que queramos usar con éste nuevo y magnífico editor de código Omnis.

Otras características y disponibilidad:

Bob también nos hablo sobre algunas otras cosas que se espera incluirá Omnis Studio 9, "Remote Objects" los cuales podrán contener métodos de ejecución exclusiva en el cliente, "Omnis Datafile Migration", una herramienta para la conversión automática de archivos ".df1" a SQLite o PostgreSQL, soporte para los estándares de accesibilidad en la Web (WCAG 2.0), "Remote Debugging" el cual nos permitirá depurar nuestras aplicaciones para la web y dispositivos móviles de modo más cómodo y eficaz, nuevos controles JavaScript, entre ellos el denominado "iCalendar"".

La primera versión Beta de Omnis Studio 9, estará disponible para los desarrolladores a finales de año.

14 diciembre 2017

Android Studio vs Omnis Studio

En éste artículo quiero comparar lo que supone crear una aplicación sencilla para un dispositivo Android, con dos diferentes herramientas para el desarrollo de "App's": Android Studio (exclusiva de la plataforma y gratuita) y Omnis Studio (multi-plataforma y de pago). Queremos que la aplicación sea capaz de crear una base de datos SQLite en el dispositivo, con tres campos: ID, Nombre y Apellido y cuatro botones para iteracción con el usuario: "Buscar", "Insertar", "Actualizar" y "Borrar", su aspecto y código necesarios se muestran a continuación:

Aspecto con Android Studio

Aspecto con Omnis Studio

Para añadir los elementos de la "interface" en ambos casos sólo ha sido necesario arrastrar y soltar componentes desde sus respectivas paletas, pero a la hora de girar el dispositivo, "Android Studio" a requerido programación adicional, mientras que con "Omnis Studio" no ha sido necesario incluir programación alguna.

A continuación indicaremos el código que ha sido necesario escribir en cada caso, empezando por la creación de la BBDD SQLite en el dispositivo:

Creación de la BBDD en Android Studio

public class Estructura_BBDD {

private Estructura_BBDD() {}

        public static final String TABLE_NAME = "datosPersonales";
        public static final String NOMBRE_COLUMNA1 = "id";
        public static final String NOMBRE_COLUMNA2 = "nombre";
        public static final String NOMBRE_COLUMNA3 = "apellido";

    public static final String SQL_CREATE_ENTRIES =
            "CREATE TABLE " + Estructura_BBDD.TABLE_NAME + " (" +
                    Estructura_BBDD.NOMBRE_COLUMNA1 + " INTEGER PRIMARY KEY," +
                    Estructura_BBDD.NOMBRE_COLUMNA2 + " TEXT," +
                    Estructura_BBDD.NOMBRE_COLUMNA3 + " TEXT)";

    public static final String SQL_DELETE_ENTRIES =
            "DROP TABLE IF EXISTS " + Estructura_BBDD.TABLE_NAME;
}

Creación de la BBDD en Omnis Studio

Do $cinst.$sqlobject.$execute('CREATE TABLE Empleados (Id INTEGER UNIQUE, Nombre TEXT, Apellido TEXT)')
      Returns IDcreatetable

Un apunte antes de continuar en cuanto a la programación asociada a cada botón, en el caso de "Andriod Studio" ha sido necesario añadir código adicional para poner los botones en modo "OnClickListener", cosa totalmente innecesaria en "Omnis Studio", salvando ésta diferencia, (no trivial) indicamos el asociado a cada botón:

Botón "Buscar" en Android Studio

botonBuscar.setOnClickListener(new View.OnClickListener() {
   @Override   public void onClick(View v) {
       SQLiteDatabase db = helper.getReadableDatabase();
       String[] projection = {
               Estructura_BBDD.NOMBRE_COLUMNA2,
               Estructura_BBDD.NOMBRE_COLUMNA3       };

       String selection = Estructura_BBDD.NOMBRE_COLUMNA1 + " = ?";
       String[] selectionArgs = { textoId.getText().toString() };

       try {
           Cursor c = db.query(
                   Estructura_BBDD.TABLE_NAME,         
                   projection,                         
                   selection,                          
                   selectionArgs,                      
                   null,                               
                   null,                               
                   null                                
           );

           c.moveToFirst();
           textoNombre.setText(c.getString(0));
           textoApellido.setText(c.getString(1));

       }catch (Exception e){
           Toast.makeText(getApplicationContext(),"No se han encontrado registros.", Toast.LENGTH_LONG).show();
       }
   }
});

Botón "Buscar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$selectfetch("Select * from Empleados where Id = @[i_ID]";lRow;kFetchAll) 
              Returns IDselectfetch

Botón "Insertar" en Android Studio

botonInsertar.setOnClickListener(new View.OnClickListener() {
    @Override    public void onClick(View v) {
        SQLiteDatabase db = helper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(Estructura_BBDD.NOMBRE_COLUMNA1, textoId.getText().toString());
        values.put(Estructura_BBDD.NOMBRE_COLUMNA2, textoNombre.getText().toString());
        values.put(Estructura_BBDD.NOMBRE_COLUMNA3, textoApellido.getText().toString());

        long newRowId = db.insert(Estructura_BBDD.TABLE_NAME, null, values);
        Toast.makeText(getApplicationContext(),"Insertado ID: " + newRowId, Toast.LENGTH_LONG).show();
    }
});

Botón "Insertar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$insert("INSERT INTO Empleados (Id, Nombre, Apellido) VALUES (@[i_ID],@[i_Nombre],@[i_Apellido])";lRow)
             Returns IDinsert

Botón "Actualizar" en Android Studio

botonActualizar.setOnClickListener(new View.OnClickListener() {
    @Override    public void onClick(View v) {

        SQLiteDatabase db = helper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(Estructura_BBDD.NOMBRE_COLUMNA2, textoNombre.getText().toString());
        values.put(Estructura_BBDD.NOMBRE_COLUMNA3, textoApellido.getText().toString());

        String selection = Estructura_BBDD.NOMBRE_COLUMNA1 + " LIKE ?";
        String[] selectionArgs = { textoId.getText().toString() };

        int count = db.update(
                Estructura_BBDD.TABLE_NAME,
                values,
                selection,
                selectionArgs);
        Toast.makeText(getApplicationContext(),"Registro actualizado.", Toast.LENGTH_LONG).show();
    }
});

Botón "Actualizar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$update("UPDATE Empleados SET Nombre=@[i_Nombre], Apellido=@[i_Apellido] where Id = @[i_ID]";lRow;lRow)
              Returns IDupdate

Botón "Borrar" en Android Studio

botonBorrar.setOnClickListener(new View.OnClickListener() {
    @Override    public void onClick(View v) {

        SQLiteDatabase db = helper.getWritableDatabase();
        String selection = Estructura_BBDD.NOMBRE_COLUMNA1 + " LIKE ?";
        String[] selectionArgs = { textoId.getText().toString() };
        db.delete(Estructura_BBDD.TABLE_NAME, selection, selectionArgs);
        Toast.makeText(getApplicationContext(),"Registro borrado.", Toast.LENGTH_LONG).show();
        textoId.setText("");
        textoNombre.setText("");
        textoApellido.setText("");
    }
});

Botón "Borrar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$delete("DELETE FROM Empleados WHERE Id = @[i_ID]";lRow)
              Returns IDdelete

Notemos que en el código Android se ha evitado deliberadamente la incorporación del código necesario para tratar las excepciones, salvo en el caso del botón "Buscar" donde se usa un "try-catch", para controlar el hecho que pueda no encontrarse el registro buscado. Omnis predefine un método para tratar las excepciones denominado "$sqldone", a continuación mostramos un ejemplo de uso:

;  Se ejecuta cada vez que concluye una operación SQL (asíncrona)
;  Abandona el método con el mensaje de error, si se produce.

Do $cinst.$sqlobject.$getlasterrortext() Returns lErr
If lErr<>"OK"
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage(lErr;"Error")
Quit method
End If

;  Se ejecuta uno u otro proceso según el resultado
Switch pID
Case IDselecttables
If pResult.$linecount=0
Do $cinst.$creaTabla()     ;; Si no existe se crea la tabla
End If
Case IDselectfetch
Calculate lRows as pResult.$linecount
If lRows=0
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage("No existe el ID";"Respuesta")
Quit method
End If
Calculate i_Nombre as pResult.C2
Calculate i_Apellido as pResult.C3
Case IDcreatetable
Do $cinst.$showmessage("Tabla creada";"Respuesta")
Case IDinsert
Do $cinst.$showmessage("Inserción realizada";"Respuesta")
Case IDdelete
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage("Entrada borrada";"Respuesta")
Case IDupdate
Do $cinst.$showmessage("Actualización realizada";"Respuesta")
Default
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage("Error inesperado")
End Switch

En ocasiones los programadores y compañías dedicadas al desarrollo y mantenimiento de software, nos preguntamos ¿Porqué pagar por una herramienta, cuando existe otra que es gratis?, pero definitivamente puedo decir que en muchas ocasiones lo "barato" sale caro. Omnis Studio permite el desarrollo de aplicaciones para dispositivos móviles (Android, iOS y Windows), aplicaciones de escritorio (MacOS, Windows, Linux) o aplicaciones para la Web, sin necesidad de usar más herramientas que el propio Omnis Studio. El ejemplo de eficacia que hemos expuesto, compara una herramienta que sólo permite el desarrollo para dispositivos Android, por lo que el código resultante no podrá ser ejecutado en (por ejemplo) un dispositivo iOS, en cambio el código Omnis, puede ser ejecutado sin cambio alguno, sobre dispositivos iOS o Windows 10.

Juzguen ustedes mismos sobre si lo "barato" sale caro, llevo trabajando con Omnis Studio por unos 20 años ya, período durante el que las tecnologías han sufrido muchos y diferentes cambios que han hecho, al mismo tiempo, aparecer y desaparecer lenguajes de programación, pero Omnis Studio a sabido adaptarse a los tiempos y a tiempo con gran lujo y esmero.

Programar con Omnis Studio hace que me guste éste trabajo.

21 septiembre 2017

Nuevo Servidor de Aplicaciones Omnis para Linux

Puedo decir que Omnis expande sus oportunidades de negocio, así como la robustez de su plataforma para el despliegue de aplicaciones en la Web, con la nueva versión "headless" del "Omnis App Server" para Linux, ya que permite la ejecución de aplicaciones web y móviles basadas en su tecnología jsClient bajo el entorno de comandos linux y sin necesidad de interface gráfica alguna, aunque permitiendo su administración remota desde un navegador Web. El denominado servidor "headless" está disponible sólo para Linux.

Todas las opciones del servidor podrán ser controladas remotamente desde la línea de comandos del terminal de la máquina Linux o (como ya hemos comentado) hacer uso de su herramienta "Admin" para la Web, incluida en el directorio "clientserver\server".

Consideraciones


Comandos de consola


Encontraremos un nuevo parámetro boleano en el fichero "config.json" denominado "headlessAcceptConsoleCommands". Puesto a "true" (su valor predeterminado), el servidor dejará disponible para su uso la interfaz de línea de comandos.

Funciones


Cuando el servidor está funcionando en modo línea de comandos, la nueva función "isheadless()" devolverá "true", "sys(231)" devolverá cero y "sys(233)" devolverá una cadena vacía, de otro modo devolvería el título de la ventana situada en primer plano sobre el Servidor Omnis.

Java


En caso de usarse el modo comandos y para iniciar la (Maquina Virtual Java) JVM deberá fijar a "ture" el elemento "startjvm" del fichero "config.json".


Creación de clases desde código Omnis


Si en su código Omnis crea nuevas clases dinámicamente mediante notación, ahora dispone de un mecanismo para crear objetos nuevos mediante plantillas, las cuales deberán estar ubicadas bajo la carpeta "componenttemplates" de "Studio". Las carpetas son...

"componenttemplates/window"
"componenttemplates/remoteform"
"componenttemplates/report"

...éstas contiene respectivamente los archivos de plantilla para la creación de ventanas, formularios remotos e informes. Cada nombre de plantilla deberá tener la forma "complibrary_compcontrol.json", con _ (subrayado) en lugar de espacios: Son copias de los archivos "object.json" con sus propiedades. "complibrary" y "compcontrol" identifican respectivamente un componente y un nombre de control.

Restricciones


Existen varias diferencias o (mejor dicho) restricciones en comparación con el Servidor de Aplicaciones Omnis convencional o de entorno gráfico y son las siguientes:

  • La inclusión de imágenes en un PDF está sólo permitido con PNG's (o a imágenes compartidas "true-color").
  • No está soportado el uso de "port".
  • Deberá usarse la entrada "start" bajo la sección "server" del "config.json" para iniciar el servidor en modo "multi-threaded"
  • El comando "Test if running in background" siempre devolverá "true".
  • Algunos comandos y métodos de notación producirán error si son ejecutados, tales como:  open window $open sobre una clase-ventana, etc.
  • Las funciones de conversión de imágenes no están soportadas: pictconvto, pictconvfrom, pictconvtypes, pictformat pictsize (producirán un error).
  • Los mensajes estándar generados por el servidor ("OK messages" y mensajes de error) se enviarán al archivo de "log" del servidor o bien al Terminal si fuese necesario.

Instalación


Descargue el instalador desde: www.omnis.net/download/

Esta instalación supone que se está ejecutando como "root" o utilizando "sudo".

Actualice su versión de Linux usando los siguientes comandos, según el entorno linux de que disponga:

  • Centos/redhat: sudo yum update
  • Suse: sudo zypper update
  • Ubuntu/debian: sudo apt-get update


Una vez actualizado, tendrá que instalar las dependencias que Omnis requiere para su ejecución y que son las siguientes:

  • Centos/redhat: cups, pango
  • Suse/Debian: Runs out of box
  • Ubuntu: cups, libpango1.0


Una vez instalados, deberá iniciar el instalador del siguiente modo:

./Omnis-Headless-App-Server-8.1-x64.run

Siga los pasos que le mostrará el instalador, tal y como lo haría en una instalación normal de Omnis Studio, asegurándose de que su número de serie sea el correcto, de otro modo, la instalación fallará.

En caso de Centos 7 o Redhat el servicio omnis no se iniciará automáticamente tras un reinicio, necesitará agregar manualmente Omnis a la lista "autostart" del siguiente modo:

sudo /sbin/chkconfig --add homnis
sudo /sbin/chkconfig --list homnis
                (Esta línea es para verificar que se ha agregado correctamente "homnis")
sudo /sbin/chkconfig homnis on

Ahora deberemos configurar el servidor utilizando la herramienta "Admin", tal y como mostramos a continuación y para según que plataforma:

CENTOS7 y REDHAT


Comandos necesarios para que Omnis funcione en Centos:

sudo yum update
sudo yum install cups
sudo yum install pango
sudo /sbin/chkconfig --add homnis
sudo /sbin/chkconfig --list homnis
sudo /sbin/chkconfig homnis on

SUSE


El servidor debe funcionar fuera del "box" de SUSE, pero recomendamos su actualización por si acaso:

sudo zypper update

Ubuntu 16.04, 17.04 y DEBIAN 9


sudo apt-get update
sudo apt-get install unzip
sudo apt-get install libpango1.0
sudo apt-get install cups

Herramienta Web de Administración


Disponemos de una herramienta "Admin" para configurar y mantener el servidor: la herramienta "Admin" se implementa por medio de un "remote-form" ubicado en la carpeta "clientserver\server" y puede ser cargado desde un navegador web, mediante abrir la página web llamada "osadmin.htm". Deberá tener en cuenta que, (para poder abrir esta página) deberá configurar antes en el servidor, el parámetro "data-webserverurl" de la página html mencionada, (URL, dirección IP o nombre y número de puerto, por ejemplo, http://192.1.1.68.5000), además de colocar el archivo html, bajo una ubicación que le permite abrirlo desde un navegador web.


La herramienta Administrador tiene varias pestañas que le permiten ver o configurar el servidor Activity, Logs, Settings y Users. Cuando abre la herramienta por primera vez en su navegador, se le pedirá que inicie la sesión: use el nombre de usuario predeterminado: omnis, contraseña: 0mn1s (el primer carácter es un cero). Una vez iniciada la sesión, podrá cambiar la contraseña predeterminada y crear otros usuarios.

Activity


La pestaña "Activity" le permite ver todas las librerías abiertas en el servidor. Puede utilizar el botón "Refresh" para actualizar la lista.

El botón "Open" le permite abrir una librería sobre el servidor; tenga en cuenta que eso ocasionará la ejecución de su método "construct". Puede hacer clic sobre cualquier librería para cerrarla con el botón "Close"; tenga en cuenta que al cerrar una librería se perderán todos las conexiones de los posibles clientes conectados a ella.

La pestaña "Active Tasks" mostrará todas las instancias "task" actualmente activas o (lo que es lo mismo) todas las conexiones de clientes actuales; mediante seleccionar una "task" o conexión, podrá ver sus detalles. También podremos matar o cerrar una instancia "task" o conexión mediante el botón "Kill Task"; tenga en cuenta que al eliminar una tarea o conexión se perderán las acciones en curso para ese cliente.

Logs


La pestaña "Logs" nos permite ver la siguiente información:

  • Server. Muestra un registro de la actividad del servidor (su ubicación puede indicarse en la pestaña "Settings")
  • Monitor. Muestra un registro de todas las conexiones de cliente activas (instancias "task")
  • Service. Muestra un registro de todos los errores o mensajes generados por el servidor, incluyendo cualquier mensaje de rastreo o información sobre cualquier solicitud "Web Service".


Bajo la pestaña "Service", el botón "Configure" le permite configurar los mensajes que se guardarán en el registro, incluyendo los atributos "folder" de "logToFile", los cuales indican la ruta hacia el lugar donde se encuentran los ficheros de registros en el servidor. Estos ajustes están localizados en el "config.json" del servidor, bajo el miembro "log", del siguiente modo:

"log": {
        "logcomp": "logToFile",
        "datatolog": [
            "restrequestheaders",
            "restrequestcontent",
            "restresponseheaders",
            "restresponsecontent",
            "tracelog",
            "seqnlog",
            "soapfault",
            "soaprequesturi",
            "soaprequest",
            "soapresponse",
            "cors",
            "headlessdebug",
            "headlesserror",
            "headlessmessage",
            "systemevent"
        ],
        "overrideWebServicesLog": true,
        "logToFile": {
            "stdout": true,
            "folder": "logs",
            "rollingcount": 10
},
        "windowssystemdragdrop": true
    }

Settings


Bajo la pestaña "Settings" podremos especificar la ubicación de los ficheros de registro del servidor y del monitor, además del período (temporizador) y el tamaño de los mismos. También podremos configurar el puerto que deberá usar el servidor ("Server Port"), el número de pilas de ejecución ("Server Stacks") y su "Timeslice" (todo quedará guardado en el archivo "config.json"), también podremos reiniciar el servicio desde aquí.

El nombre de servicio predeterminado es "homnis" y es especificado bajo la entrada "server" del archivo "config.json" del siguiente modo:

{
     "server": {
          …
               "service": "homnis"

Users


Bajo la pestaña "Users" podremos tanto modificar usuarios, como crear nuevos. El usuario predeterminado es "omnis" y podremos cambiarlo desde aquí. La selección, de la opción "Re-start Option" permite que un usuario reinicie el servidor.

Nota del autor


Decíamos al principio de éste artículo que "Omnis expande sus oportunidades de negocio" y la razón es que (en mi opinión) el nuevo servidor "headless", resulta en una opción muy apropiada, para poner en marcha un servicio "hosting" para el despliegue de aplicaciones Omnis en la Web, algo que me consta ha sido demandado por los desarrolladores de aplicaciones Omnis Studio.

Aunque aún no he tenido oportunidad de probarlo, parece sencillo el disponer de una o más máquinas virtuales Linux con servicios OAS (Omnis Application Server) instaladas en nuestro Data Center. ¿Que os parece la idea?