Etiqueta

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

04 noviembre 2015

Omnis Data Access Module (DAM) (Parte 1 de 3)

Para su conexión con las diferentes bases de datos de uso más habitual (tales como Omnis Data, SQLite, MySQL y PostgreSQL) necesitamos disponer de la versión Professional de Omnis Studio y dependiendo de que base de datos se trate, puede que también sea necesario la instalación de software de terceros para el enlace con esa base de datos en particular. A continuación mostramos el esquema de conexión a bases de datos que utiliza Omnis Studio.

 

Algunos apuntes sobre DAM


La conexión a Omnis Data (.df1) se lleva a cabo a través del DAM OmnisSQL, aunque también es posible hacer uso del controlador estándar ODBC con éste mismo fin. No obstante, se debe hacer notar que OmnisSQL sólo soporta un subconjunto muy limitado de instrucciones de entre estándar SQL.

Los DAM para SQLite y MySQL no requieren de la instalación de software adicional, ya que todos los ficheros necesarios desde el lado del cliente están ya incorporadas en el DAM, aunque, debemos indicar que algunos DAM (como por ejemplo DAMAZON) dependen para su correcto funcionamiento de ciertas librerías del sistema, que deberán estar presentes.

Otros, (como Oracle y Sybase) requieren de la instalación del interface correspondiente en la máquina cliente, mientras que para PostgreSQL, (aunque todo lo necesario está incluido en el DAM) podrá requerirse de una configuración adicional para su uso.

El DAM JDBC está diseñado para su uso con el driver JDBC “type 4”, el cual no requiere de la instalación de software adicional, pero “types” inferiores a éste, si que pueden depender de la instalación de software-cliente adicional.

El DAM ODBC está diseñado para ser usado junto con un driver ODBC. Su conexión es gestionada desde el propio gestor/administrador del driver ODBC, el cual deberá haber sido instalado en la máquina cliente. Normalmente los driver’s ODBC se conectan directamente a la base de datos y no requieren del uso de software adicional.

En plataformas como Mac OS X, donde el driver ODBC no está sujeto al uso de una determinada base de datos, (lo que se denomina “multi-tier” o driver genérico) puede (por ejemplo) utilizarse para crear conexiones ODBC hacia una máquina Windows.

28 octubre 2015

Creación de documentos XML mediante oXML

El componente externo oXML hace fácil la gestión de documentos XML desde nuestras aplicaciones Omnis. Cada nodo es tratado como un objeto independiente, lo cual facilita su localización y edición. Para la creación de un documento XML será necesario componer un objeto Omnis con el elemento DOM como subtipo, al cual iremos añadiendo los diferentes elementos que lo compondrán, mediante los métodos disponibles al efecto en el objeto DOM construido.

 

Creación de un documento XML


Para crear un documento XML, primero deberemos crear un objeto “DOM document” (“external objects-≥DOM document”). Este será el objeto principal del documento, mediante el cual podremos crear, buscar, editar y eliminar cualquiera de los nodos de que conste nuestro documento.

 

Adición de un elemento


Un documento XML está compuesto de varios “elementos” (también considerados objetos para oXML). Cada elemento posee un nombre, pero también puede poseer otras propiedades asociadas (explicados más adelante), tales como atributos, texto y comentarios. Cada elemento puede a su vez contener otros (conocidos como hijos), creándose así una estructura de tipo árbol, asociada al documento XML.

Tanto éstos elementos, como todos los demás objetos, son creados por el “DOM document”, mediante su conjunto de métodos “$createXXX()”. Por ejemplo, el método siguiente nos devuelve un objeto-elemento “oRoot”, de nombre “Root”:
; oXML es de tipo “Object”, con “DOM document” como subtipo
; lError es de tipo “Character”
; oRoot es de tipo “Object”, con “DOM Types-≥DOM Element” como subtipo
; oObj es de tipo “Object”, sin subtipo
; oElement es de tipo “Object”, con “DOM Types-≥DOM Element” como subtipo
Do oXML.$createelement("Root",lError) returns oRoot

Una vez obtenido el objeto-elemento, deberá ser insertado en el documento. Esto, deberá hacerse desde el propio objeto-elemento, el cual (en nuestro caso) se convertirá en el elemento padre del documento. Para hacer esto los objetos-elemento disponen de los siguientes dos métodos:

  • $appendchild() …que inserta el elemento al final de su lista de hijos.
  • $insertbefore() …que inserta el elemento delante del indicado.

Puesto que aún no existen otros elementos, al crear el primero, deberemos utilizar el objeto “DOM document” como padre: esto creará lo que se conoce como elemento “Root” o elemento-raíz, el elemento-raíz es único, es decir sólo puede existir uno y todos los demás elementos son descendientes de este.
Do oXML.$appendchild(oRoot ,lError)
Do oXML.$createelement("Elemento1",lError) returns oObj
Do oRoot.$appendchild(oObj, lError)

Mediante el método expuesto anteriormente insertamos el elemento-raíz en el documento y a continuación, obtenemos un segundo elemento (de nombre “Elemento1”), que es retornado sobre oObj (oObj ha sido declarado como un objeto sin subtipo, ya que es definido al obtenerse el elemento). Después insertamos el elemento como hijo de “oRoot”.

 

Propiedades de los Elementos


A pesar de que en nuestro ejemplo, ahora disponemos de algunos elementos-objeto, éstos aún no contienen información. Un elemento-objeto puede tener asociadas varias propiedades. Todos ellas son añadidas como hijos del propio elemento, esta operación es llevada a acabo del mismo modo que se añaden elementos-hijos a sus primarios. Los cuales pueden ser insertados delante o detrás del propio elemento.

 

Adición de textos


Existen dos modos diferentes de incluir un texto, los cuales denominaremos como “analizado” y “no analizado”. El método mas habitual es el “analizado”, lo que significa que su “analizador XML” deberá evaluar el texto. Por ejemplo, que el texto “Manzanas & amp; Peras” esté equiparado al texto “Manzanas & Peras”. El uso del modo “no analizado” no llevará a cabo la evaluación del texto, lo que significa que sea expresado literalmente, en nuestro caso, “Manzanas & amp; Peras”, sin filtrado de sus elementos.
; para crear un texto “PARSED” o “analizado”
Do oXML.$createtextnode("Manzanas & Peras", lError) returns oObj

; para crear un texto “UNPARSED” o “no analizado”
Do oXML.$createcdatasection("Manzanas & Peras", lError) returns oObj

Lo anterior, obtendrá un nodo de tipo texto con su texto, que después deberemos agregar del modo siguiente:
Do oElement.$appendchild(oObj, lError)

Adición de atributos


Los atributos son añadidos de modo muy sencillo. Tan sólo se requiere un nombre y un valor y son asociados al elemento mediante el uso de su propio método “$setattribute()”, tal y como mostramos a continuación:
Do oElement.$setattribute('Color','rojo',lError)

Lo anterior agregará el atributo Color = "rojo" al elemento oElement. Para añadir otros atributos al mismo elemento tan sólo deberemos repetir el proceso. Los atributos también pueden ser añadidos mediante el método “oXML.$createattribute()”, pero, en éste caso el atributo será añadido como un hijo.

 

Adición de comentarios


Los comentarios no son procesados por los analizadores XML, sólo están presentes para mejorar la legibilidad del documento XML. Son creados del siguiente modo:
Do oXML.$createcomment(‘Nuestro comentario', lError) Returns oObj
Do oElement.$appendchild(oObj, lError)

Instrucciones de procesamiento


Las instrucciones de procesamiento, proporcionan al XML, el modo específico en que deberá gestionarse la información contenida en el texto del documento. Formados por una “etiqueta” y un valor, proporciona la información necesaria para cumplir con su objetivo. (por ejemplo. Etiqueta = “xml-stylesheet”, valor = “type=’text/xsl’ href=’template.xsl’”. Estos también son considerados objetos, por lo que, deberemos hacer uso de un método predefino para la obtención de éste tipo de objetos, en éste caso será “oXML.$createprocessinginstruction()”, después deberemos añadirlo como hijo de un elemento.

 

Entidades


Las entidades están declaradas en el propio objeto “DOM DocumentType”. oXML utiliza el nivel 2 del DOM, el cual no permite la edición o creación de objetos “DocumentType”. Por lo tanto, el componente oXML sólo permite la lectura de las entidades ya incluidas en el propio documento XML.

 

Generación del fichero XML


Una vez construido el documento DOM en Omnis con todos sus elementos, tendremos que guardarlo en un archivo con extensión “.xml”. Para ello, disponemos del método “$savefile()” del propio objeto DOM, su modo de uso es el siguiente:
Do oXML.$savefile("C:\MiCarpeta\MiXML.xml", lError, kFalse, kXMLFormatFull)

El último argumento del método “$savefile()” nos permite especificar el formato del archivo XML a grabar. Las opciones de formato permiten especificar si se desea o no, añadir retornos de carro y saltos de línea, eliminar espacios, etc. diferentes “analizadores” podrán requerir de  ajustes en el formato del archivo XML resultante.

Existen otros métodos ya definidos para el objeto DOM, que podrían resultarnos útiles, pero en éste artículo, sólo les hemos presentado los básicos y a su vez suficientes en la mayoría de los casos, también nos proporciona una idea sobre como hacer uso de estos otros.

En Aula Omnis, podrá encontrar para su libre descarga, la librería de ejemplo “XMLex.zip” que muestra los métodos utilizados en éste artículo.

21 octubre 2015

Uso del Servidor de Sincronización Omnis

El “Omnis Synchronization Server” hace posible que una base de datos SQLite localizada en un dispositivo remoto (mantenida mediante una solución jsClient) pueda ser sincronizada con cualquier base de datos compatible, situada en un servidor.

En éste artículo mostramos su funcionamiento, usando para ello la librería de demostración denominada “syncdemo” la cual podrá encontrar lista para su descarga en Aula Omnis. La librería ha sido optimizada para dispositivos móviles iOS, pero puede ser fácilmente adaptada para su uso en otras plataformas.

 

Requerimientos


Para realizar lo expuesto en éste artículo, necesitará disponer de Omnis Studio 6.1 o superior, con capacidad para activar la propiedad “$serverlessclient” de los “remote form”. Propiedad necesaria para poder construir aplicaciones móviles independientes.

 

Configuración del “Synchronization Server”


Para conectar el “Synchronization Server” a una base de datos, debemos en primer lugar, definir una sesión específica en el “SQL browser”. Nuestro ejemplo está preparado para su uso con una base de datos SQLite, a continuación mostramos como configurarla.

 

Configurando la sesión


Seleccione “SQL Browser” desde el “Studio Browser”, haga clic sobre el hipervínculo “Session Manager” y después sobre “New Session”. Construya  una nueva sesión con el nombre “SYNCDEMO” tal y como mostramos a continuación, para terminar pulse OK.

 

Configurando el “Synchronization Server”


Abra el “Synchronization Server” desde la opción de menú “Tools≥≥Add-Ons”. Desde la pestaña “CDB Config” seleccione la sesión construida anteriormente y denominada “SYNCDEMO”, a continuación pulse “Save Details”, seguido de “Connect”.



Desde la pestaña “Sync Groups” añada dos grupos con los nombres “group1” y “group2”. Ambos con la palabra “syncdemo” como contraseña (no incluya las comillas).



En la pestaña “CDB Tables” active “Sync” y “SSR” para la clave primaria “nat_ID” de la tabla “naturetable” y finalmente pulse “Save Changes”.



 

Probando la conexión


Si la conexión con SQLite ha tenido éxito, se habrá abierto la sesión “CDBSESS” sobre el “SQL Browser”, permitiendo el acceso a los datos de “syncdemo” y la posibilidad de probar el “remote form” “jsServer”, para ello, haga clic derecho sobre el “remote form” y seleccione la opción “Test Form”.




Tenga en cuenta, que para poder ver correctamente la información de la pestaña “Map View” deberá disponer de una “Google ApiKey” activa y fijada sobre la propiedad “$apikey” del control “map” situado en el “remote form” “jsServer”.

 

Configurando las conexiones desde los clientes


Para poder recibir conexiones desde los clientes, deberá previamente determinarse el puerto del servidor sobre el que Omnis estará a la escucha, para ello, haga clic sobre el hipervínculo “Prefs” y localice la preferencia “$serverport”.

Por último, será necesario crear la página HTML “jsClient.htm” que utilizará la aplicación cliente cuando esté en modo “on-line”. Para ello, haga clic sobre el “remote form” “jsClient” y seleccione “Test Form”, esto causará la creación automática del fichero “jsClient.htm” sobre la carpeta “html” (situada en el directorio raíz de instalación Omnis) además será abierta sobre el navegador web. Tenga en cuenta que éste “remote form” no es funcional en éste momento, puesto que no está siendo ejecutado sobre el dispositivo del cliente, sólo hacemos esto con la intención de que se generé la pagina “html” de forma automática, de modo que simplemente cierre el formulario.

 

Construcción de la aplicación cliente “JavaScript Wrapper App”


Para activar la capacidad de sincronización en un dispositivo móvil, deberemos configurar y compilar la aplicación utilizando el “wrapper” Omnis JavaScript, disponible desde la página web de TigerLogic.

Consulte la información sobre su configuración y uso, como aplicación independiente desde en ésta misma página web, su dirección es:  (http://www.tigerlogic.com/tigerlogic/omnis/documentation/wrappers.jsp):

Edite el “wrapper”, y modifique las entradas que mostramos a continuación del fichero de configuración “config.xml”, donde “99.99.99.99” es la dirección IP de su servidor de sincronización Omnis y “1234” el puerto especificado en ese mismo servidor (tal como se ha descrito anteriormente en éste mismo artículo), recuerde que deberá usarse el esquema del “wrapper” específico para SQLite, concretamente el denominado “OmnisJSWrapper_SQLite” .
≤SettingsOnlineMode≥0≤/SettingsOnlineMode≥
≤ServerOmnisWebUrl≥http://99.99.99.99:1234≤/ServerOmnisWebUrl≥
≤ServerOnlineFormName≥jschtml/jsClient.htm≤/ServerOnlineFormName≥
≤ServerOfflineFormName≥jsClient≤/ServerOfflineFormName≥
≤ServerOmnisServer≥≤/ServerOmnisServer≥
≤ServerOmnisPlugin≥≤/ServerOmnisPlugin≥
≤ServerAppScafName≥syncdemo≤ServerAppScafName≥

Conexión desde la “app” cliente, al servidor de sincronización


La primera vez que ejecutemos la aplicación o “wrapper”, nos aparecerá el mensaje “no such table: naturetable”. Lo cual significa, que la tabla aún no existe en el dispositivo cliente, ya que aún no se ha producido su sincronización con el servidor.

Use la pestaña “Settings” de la aplicación cliente, para indicar la dirección del servidor de sincronización, además del grupo y su contraseña para su identificación en el servidor de sincronización (tal como hemos visto anteriormente) y pulse “Save”.



Asegúrese de que la ventana “Synchronization Server” este abierta sobre el servidor para así poder observar las conexiones entrantes y a continuación, pulse el botón “Syncinit” del cliente, seguidamente observe las entradas que se producen en el registro de la sincronización del servidor.



Una vez finalizada la sincronización, sitúese en su dispositivo sobre la pestaña “Data” y pulse “refresh”, esto causará que los datos del dispositivo se sincronicen con los del servidor.


Ahora podremos agregar nuevos registros o editar los ya existentes en nuestra base de datos SQLite local, es decir la ubicada en el dispositivo y después sincronizarla con el servidor, para ello deberemos hacer clic sobre el botón “Sync”.


Si nos situamos sobre la pestaña “Cache” antes de pulsar el botón “sync” podremos ver las solicitudes pendientes de sincronizar, junto con la lista de tablas existentes en el dispositivo. La pulsación (en éste momento) del botón “Sync” actualizará la base de datos del servidor y borrará la memoria caché.



Si así lo desea esta pestaña, puede ser fácilmente ocultada editando el “remote form” denominado “jsClient”, para establecer el valor inicial de la variable “iShowCache” a kFalse.

14 octubre 2015

Uso de comandos HTTP con Omnis

Caso ejemplo


Queremos hacer uso de comandos HTTP, para obtener una imagen ubicada en algún lugar de Internet y guardarla sobre un control JPEG de nuestro propio “remote form”, como por ejemplo la localizada en la dirección de internet: http://www.tigerlogic.com/omnis/images/omnis_studio_box.png.

 

HTTP Request y HTTP Response


Antes de entrar en detalles sobre el uso de comandos HTTP con Omnis, echemos un vistazo a lo que ocurre cuando se solicita una imagen, (o cualquier otro dato) mediante HTTP. Si introducimos la URL de un archivo imagen, (como por ejemplo la indicada en el párrafo anterior) en un navegador ésta será mostrada sobre la ventana del navegador, pero, lo que realmente ha sucedido es que el navegador (como cliente) a enviado un “HTTP Request” al servidor web “www.tigerlogic.com” solicitándole el fichero “/omnis/images/omnis_ studio_box.png” (parte de la URL, denominada URI), como consecuencia de esto, el servidor envía de vuelta un “HTTP Response” al navegador, que contiene, (entre otras cosas) el fichero solicitado. El formato de los paquetes de datos transferidos obedecen al protocolo estándar definido en el RFC 2616, consulte: www.faqs.org/rfcs/rfc2616.html

El “HTTP Request” está compuesto principalmente por una cabecera, que contiene los datos de identificación del cliente,  la información de lo solicitado por éste y su formato, mientras que el servidor responde con un “HTTP Response”, que a su vez consta de una cabecera y un cuerpo con la información requerida.

La cabecera de ambos es transferida en forma de texto ASCII estándar y por lo tanto puede ser “atrapada” mediante el uso de programas para el análisis de paquetes denominados “Sniffer’s”. Véase, por ejemplo: www.wireshark.org

Están compuestos por líneas individuales, cada una de ellas terminada con un retorno de carro (CR = Código ASCII 13) y un salto de línea (LF = Código ASCII 10). En cada línea, se asigna un valor a un campo, su formato es ≤nombre de campo≥":"≤valor≥. Entre la cabecera y el cuerpo hay una línea en blanco. De modo que, delante del cuerpo siempre encontraremos la cadena CR + LF + CR + LF.

 

¿Es Omnis un navegador?


Lo que podemos decir es que Omnis, soporta algunos comandos 4GL para la ejecución del ciclo “HTTP request/response”. Volviendo al caso planteado, podemos hacer uso de éstos comandos para obtener una imagen desde una ubicación remota. En primer lugar, Omnis deberá enviar una petición HTTP al servidor para recuperar o “conseguir” el archivo imagen. A continuación mostramos el código necesario: (“host” y “uri” son las variables locales de tipo “Character”, “socket” es de tipo “Long Integer”)

Calculate host as 'www.tigerlogic.com'
Calculate uri as '/omnis/images/omnis_studio_box.png'
HTTPGet (host,uri) Returns socket

Si la solicitud es aceptada, la variable “socket” contendrá un valor positivo, por su parte, Omnis habrá enviado lo siguiente:

GET /omnis/images/omnis_studio_box.png HTTP/1.1
Host: www.tigerlogic.com
Accept: */*
User-Agent: Raining Data - OMNIS


Si se desea definir parámetros adicionales para incluirlos en la cabecera de la solicitud o bien para nuestra propia versión de la URI utilizada por defecto, disponemos del comando “HTTPGet” el cual permite el uso de parámetros adicionales; en éste caso el código sería algo como lo siguiente:

Do cgiList.$define()
Do cgiList.$cols.$add(‘atributo’,kCharacter,kSimplechar,2000)
Do cgiList.$cols.$add(‘valor’,kCharacter,kSimplechar,2000)
Do cgiList.$add( ... )
Do headerList.$define()
Do headerList.$cols.$add(‘nombre’,kCharacter,kSimplechar,2000)
Do headerList.$cols.$add(‘valor’,kCharacter,kSimplechar,2000)
Do headerList.$add( ... )
HTTPGet (host,uri,cgiList,headerList) Returns socket

Si el “socket” es válido podremos recuperar datos del servidor, e ir guardándolos (en un primer momento) sobre (por ejemplo)  la variable “buffer” (definida como tipo “Character”):

HTTPRead (socket,buffer) Returns charCount

Los datos obtenidos tras el primer “HTTPRead” pueden no ser todos los esperados, por lo que, (como medida de precaución) es mejor crear un bucle (la variable “bufferPart” también es tipo “Character”). Así el código completo para leer una respuesta HTTP sería:

If socket>0
  Calculate buffer as ''
  Repeat
    Calculate bufferPart as ''
    HTTPRead (socket,bufferPart) Returns charCount
    Calculate buffer as con(buffer,bufferPart)
  Until (len(bufferPart)=0)|(charCount=0)
  HTTPClose (socket)
  ...(hacer algo)...
End If

Tras la obtención de todos los datos, será muy conveniente hacer uso del comando “HTTPClose” (socket) y después, comprobar que al inicio de la variable “buffer”; disponemos de algo como  lo siguiente:

HTTP/1.1 200 OK Server: Zeus/3.3
Date: Tue, 08 Dec 2007 12:34:57 GMT Content-Length: 4351
Content-Type: image/jpeg
Last-Modified: Thu, 01 Dec 2007 10:04:25 GMT
 

Tras la cabecera, vendrá una línea en blanco y luego los datos binarios.

Si se envía un “URI” inválido, como por ejemplo, solicitando el archivo “studio4_box.jpg” que no existe en el subdirectorio “/products/studio/” del servidor web, no se nos devolverá el número “2xx”, si no (generalmente) el correspondiente al error 404. De modo que, nuestra aplicación debería comprobar la presencia de este número sobre la primera línea devuelta, comprobando que su primer dígito sea igual a 2. Por ejemplo:

If not(mid(buffer,pos(' ',buffer)+1,1)='2')
  OK message Error {[uri] no localizado.}
  Quit method
End If


Ahora deberemos separar el cuerpo de su cabecera. Recuerde que todo lo que nos llega después de la línea en blanco, son los datos referenciados. Por lo tanto deberemos declarar las siguientes variables locales:

posEmptyLine (Long integer)
bufferStripped (Binary)
picFormat (Character)
 

y las variables-instancia:

iPicture (Binary)

finalmente deberemos añadir el siguiente código antes del comando “End If”:

Calculate posEmptyLine as pos(chr(kCr,kLf,kCr,kLf),buffer)
Calculate bufferStripped as mid(buffer,posEmptyLine+4,len(buffer))
Calculate picFormat as pictformat(bufferStripped)
Calculate iPicture as pictconvfrom(picFormat,bufferStripped)

Ahora podríamos asignar la variable IPicture a la propiedad “$dataname” de un control JPEG para así mostrar la imagen sobre nuestro “remote form”.

07 octubre 2015

RESTful con Omnis Studio (Parte 3 de 3)

En éste último artículo sobre el tema que nos ocupa, describimos cómo configurar un servidor web para que soporte autenticación para nuestros servicios web RESTfull construidos con Omnis Studio.

Sin duda queda de nuestra parte el construir un método de autenticación seguro para nuestra librerías Omnis. Pero cuando se utiliza un verdadero servidor Web (en lugar del servidor Tomcat), deberemos configurar su dirección URL para que soporte autenticación de tipo “basic” y/o “digest”. Por supuesto, también podemos hacer uso de https, y certificados de cliente para que las conexiones sean más seguras.

En las siguientes secciones, se han incluido algunas notas acerca de cómo configurar Tomcat, Apache Web Server y IIS para que soporten autenticación de tipo “basic” y/o “digest”. Configurar nuestro servidor de éste modo, significará que a Omnis sólo llegará la solicitud si el cliente se ha autenticado correctamente; en este caso, las cabeceras HTTP incluirán la “Authorization header”, con los detalles de la autenticación.

Omnis Studio incluye una nueva función denominada “parsehttpauth(auth)”, la cual analiza el valor (auth) del http “Authorization header” y devuelve una variable de tipo “row” con la información extraída. La primera columna denominada “named scheme” contiene la denominación del esquema (por ejemplo “basic”). El contenido del resto de sus columnas dependerá del tipo de esquema. A continuación mostramos algunos ejemplos:

Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
  • La “row” devuelta tendrá las siguientes tres columnas:
    • scheme: basic 
    • username: Aladdin 
    • password: open sesame

Digest username="Mufasa",realm="testrealm@host.com",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/dir/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"

  • La “row” devuelta tendrá las siguientes diez columnas:
    • scheme: digest 
    • username: Mufasa 
    • realm: testrealm@host.com
    • nonce: dcd98b7102dd2f0e8b11d0f600bfb0c093 
    • uri: /dir/index.html 
    • qop: auth 
    • nc: 00000001 
    • cnonce: 0a4f113b 
    • response: 6629fae49393a05397450978507c4ef1 
    • opaque: 5ccc069c403ebaf9f0171e9517f40e41

OAuth realm="Example",oauth_consumer_key="0685bd9184jfhq22", oauth_token="ad180jjd733klru7",oauth_signature_method="HMAC-SHA1", oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D",oauth_timestamp="137131200", oauth_nonce="4572616e48616d6d65724c61686176",oauth_version="1.0"

  • La “row” devuelta tendrá las siguientes nueve columnas:
    • scheme: oauth 
    • realm: Example 
    • oauth_consumer_key: 0685bd9184jfhq22 
    • oauth_token: ad180jjd733klru7 
    • oauth_signature_method: HMAC-SHA1 
    • oauth_signature: wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D 
    • oauth_timestamp: 137131200 
    • oauth_nonce: 4572616e48616d6d65724c61686176 
    • oauth_version: 1.0

Bearer 0b79bab50daca910b000d4f1a2b675d604257e42

  • La “row” devuelta tendrá las siguientes dos columnas:
    • scheme: bearer 
    • token: 0b79bab50daca910b000d4f1a2b675d604257e42
Para cualquier otro esquema:

  • La “row” devuelta tendrá las siguientes dos columnas:
    • scheme: denominación del esquema en minúsculas 
    • data: resto de la información de cabecera

Tomcat


Lo mostrado a continuación ha sido probado con Tomcat 7.0.42, ejecutado en Windows 8.1. Reinicie Tomcat después de cambiar los archivos de configuración.

Autenticación “Basic”


Configuración de usuarios: edite el fichero “conf/tomcat-users.xml”:

  • Añada perfiles y usuarios dentro de elementos ≤tomcat-users≥ por ejemplo:
≤role rolename="omnisrest"/≥
≤user username="bobm" password="bobm" roles="omnisrest"/≥

Edite el fichero “web.xml” del webapp omnisrestservlet (carpeta WEB-INF);

  • Añada lo siguiente después del elemento “servlet-mapping”:
≤security-constraint≥
≤web-resource-collection≥
≤web-resource-name≥All resources≤/web-resource-name≥
≤url-pattern≥/*≤/url-pattern≥
≤/web-resource-collection≥
≤auth-constraint≥
≤role-name≥omnisrest≤/role-name≥
≤/auth-constraint≥
≤user-data-constraint≥
≤!-- transport-guarantee can be CONFIDENTIAL, INTEGRAL, or NONE --≥
≤transport-guarantee≥NONE≤/transport-guarantee≥
≤/user-data-constraint≥
≤/security-constraint≥
≤login-config≥
≤auth-method≥BASIC≤/auth-method≥
≤realm-name≥omnisrest≤/realm-name≥
≤/login-config≥

Autenticación “Digest”


Igual que lo anterior, excepto que el “auth-method” debe ser “DIGEST”.

Probando localmente SSL


En el “conf/server.xml”:

Des-comente el conector SSL y modifíquelo, por algo como lo siguiente:

≤Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="C:\apache-tomcat-7.0.42\mykeystore" keystorePass="xxxxxx"/≥

Creación de un certificado de servidor auto-firmado, para el almacén de claves tomcat:

  • Nota: Es necesario especificar un nombre y apellido para componer el localhost (a fin de permitir la realización de pruebas locales con OWEB como cliente)
  • "C:\Program Files (x86)\Java\jdk1.6.0_37\bin\keytool" -genkeypair -alias mycert -keyalg RSA -validity 10000 -keystore c:\apache-tomcat-7.0.42\mykeystore

Uso del cliente Omnis OWEB para pruebas:


Extraiga el certificado:

"C:\Program Files (x86)\Java\jdk1.6.0_37\bin\keytool" -exportcert -alias mycert -keystore c:\apache-tomcat-7.0.42\mykeystore -file my_root_cert

Impórtelo al “omnisTrustStore”:

cd ≤omnis path≥\secure\cacerts
"C:\Program Files (x86)\Java\jdk1.6.0_37\bin\keytool" -importcert -alias my_tomcat -keystore omnisTrustStore -file c:\apache-tomcat-7.0.42\my_root_cert

Ahora podrá usar con Tomcat, URLs como la siguiente: https://localhost:8443/omnisrestservlet/ws/5988/api/phase2/myapi/first

Nota: Para eliminar copias antiguas del certificado use:
"C:\Program Files (x86)\Java\jdk1.6.0_37\bin\keytool" -delete -alias my_tomcat -keystore omnisTrustStore

Apache Web Server

 

Autenticación “Basic”


Creación de usuario y contraseña:

  • c:\apache24\bin\htpasswd -c c:\apache24\test_passwords test
Nota: -c es opcional, sólo es requerido para la primera vez que se crea el fichero de contraseñas

Edite el fichero “httpd.conf”, la entrada “omnisrest” deberá ser como sigue:

≤Location /omnisrest≥
SetHandler omnisrest
AuthType Basic
AuthName "omnisrest"
AuthBasicProvider file
AuthUserFile c:\apache24\test_passwords
Require user test
≤/Location≥

Require” puede tener la forma, “Require user...”, “Require valid-user” o “Require group...”, consulte la documentación en línea de Apache, para más información.

Autenticación “Digest”


Creación de usuario y contraseña:

  • c:\apache24\bin\htdigest -c c:\apache24\test_digest_passwords omnisrest test
Nota: -c es opcional, sólo es requerido para la primera vez que se crea el fichero de contraseñas

Edite el fichero “httpd.conf”, la entrada “omnisrest” deberá ser como sigue

≤Location /omnisrest≥
SetHandler omnisrest
AuthType Digest
AuthName "omnisrest"
AuthDigestDomain /omnisrest/
AuthDigestProvider file
AuthUserFile c:\apache24\test_digest_passwords
Require valid-user
≤/Location≥

Des-comente la línea “LoadModule auth_digest_module modules/mod_auth_digest.so” del “httpd.conf”.

Require” puede tener la forma, “Require user...”, “Require valid-user” o “Require group...”, consulte la documentación en línea de Apache, para más información.

IIS


Autenticación “Basic”


IIS es bastante difícil de configurar (o al menos IIS Express que es el que hemos probado). En primer lugar, es necesario habilitar la autenticación “basic” y desactivar la autenticación “anonymous” en el archivo “AppServer\applicationhost.config” (que podremos encontrar bajo el directorio de instalación de IIS Express). Haga una búsqueda de la cadena “authentication” y modifique lo que sea pertinente.

Agregue el código siguiente al final del fichero “applicationhost.config”, justo después del elemento “location” principal:

≤location path="Default Web Site/cgi-bin/omnisrestisapi.dll"≥
≤system.webServer≥
≤security≥
≤authentication≥
≤basicAuthentication enabled="true" /≥
≤/authentication≥
≤/security≥
≤/system.webServer≥
≤/location≥

A continuación, puede utilizar el usuario y su contraseña, con URL’s protegidas - tuvimos que crear una nueva cuenta de usuario estándar para conseguir que esto funcionase.

30 septiembre 2015

RESTful con Omnis Studio (Parte 2 de 3)

Éste artículo describe cómo configurar un servidor Web Tomcat con interfaz de usuario “Swagger” para su uso con los Servicios Web REST de Omnis, le animamos a descargarse la librería de ejemplo que ilustra lo mostrado aquí, disponible en la web de Aula Omnis.

 

Creando nuestros propios “Web Services”


Un plug-in “Web Server” permite publicar el código de nuestras aplicaciones Omnis, que permitirá a los posibles cliente hacer uso de nuestros “Web Services”. La interfaz para éstos servicios web es vista por los clientes como una API o conjunto de APIs. Omnis genera las API’s RESTful (o ORAs) usando una definición "Swagger", que es el estándar más utilizado con las API’s RESTful.

Podrá ver las Omnis APIs RESTul desde el navegador de Omnis Stido (Studio Browser) como hijos del nodo de su librería bajo el grupo “Web Service Server” (tal cómo ya venia ocurriendo con los servicios basados en WSDL). Cada “ORA” se muestra bajo un nodo separado en el árbol, y varias opciones o acciones con hipervínculos. Podrá ver su definición “Swagger” navegando a trabes de los hipervínculos.

A la hora de crear un servicio Web o una API Omnis RESTful, será necesario ajustar algunas propiedades de la “remote-task” a usar, además de añadirle algunos métodos RESTful. Las clases “remote-task” contiene dos nuevas propiedades que nos permiten configurar un servicio Web de éste tipo, en concreto, la propiedad “$restful” deberá establecerse a “kTrue” para indicar que la “remote-task” es de tipo RESTful, y la propiedad “$restfulapiname” deberá contener el nombre de la API RESTful.

Cuando una “remote task” ha sido definida como RESTful, dispone de un grupo de objetos (localizados bajo el habitual grupo $objs) que son las URI publicadas para los posibles clientes. Una URI contiene uno o más componentes que comienzan por “/”. También podrán incluirse parámetros en la forma “{paramName}” donde cada “paramName” deberá ser único (sensible al uso de mayúsculas y minúsculas) en cada URI. Los URI’s son como clases objeto con sus propias instancias, ya que pueden contener sus propios métodos. Existen algunos métodos especialmente construidos para las URI’s, denominados métodos HTTP. Estos se corresponden directamente con métodos de protocolo HTTP utilizados de forma estándar en todas las API RESTful, y son: “$delete”, “$get”, “$head”, “$options”, “$patch”, “$post” y “$put”.

Los métodos HTTP que conforman una URI contienen algunas características y propiedades especiales, pero todos ellos muestran un parámetro de cabecera denominado “pHeaders”, el cual referencia a la variable “row”, que contiene las cabeceras HTTP recibidas tras la petición RESTful, dicha variable dispone de una columna por cada encabezado HTTP.

En el caso los métodos que aceptan contenidos (“$patch”, “$post” y “$put”) existe un segundo parámetro denominado “pContent”, que referencia al contenido recibido tras la solicitud. Para cada nuevo método HTTP, Omnis creará automáticamente los parámetros “pHeaders” y “pContent”, además de agregar un parámetro de tipo carácter, por cada uno de los incluidos en la URI.

El editor de métodos Omnis contiene algunas características adicionales para su uso con las “remote-task” RESTful. Algunas opciones añadidas al su menú nos permiten insertar nuevos URI, eliminarlos o cambiar sus nombres, además de permitir la inserción de un nuevo método HTTP. También, y cuando el método seleccionado es un método HTTP, el panel de variables mustra dos pestañas adicionales: “RESTful” y “RESTful notes” los cuales nos permiten ajustar los valores de tipo “input”, “output”, así como los códigos de respuesta HTTP y la consignación de notas sobre el método escrito bajo definición “swagger”.

La ventana de diálogo para la configuración del servidor de aplicaciones Omnis (Omnis App Server) contiene dos nuevas propiedades configurables: la “RESTful URL”, que es la dirección URL base, utilizada para invocar al servicio Omnis RESTful, y la “RESTful connection” que controla cómo interacciona el plugin Omnis Web Server RESTful con el propio Omnis.

 

Requerimientos


Para Windows Vista o superior:
  • Omnis Studio dev kit con número de serie valido para el Web Services Plugin.
  • Java Development kit (JDK) o Java SE Runtime environment (JRE) versión 7.
  • Consignar en la variable de entorno de usuario “OMNISJVM” o “OMNISJVM64” la ruta hacia el jvm.dll dentro de su instalación de Java (por ejemplo: c:.\Archivos de programa\java\ jre1.8.0_25\bin\server jvm.dll)

 

Configuración de un servidor web Tomcat para su uso con Servicios Web RESTful

  1. Descargue Tomcat 8.0 o superior, distribución de 32 bits para Windows desde el sitio web http://tomcat.apache.org
  2. Extraiga el archivo zip descargado y muévalo a la carpeta apache-tomcat-8.0.15 adecuada, por ejemplo a: c:\Archivos de programa\apache-tomcat-8.0.15.
  3. Tomcat requiere configurar dos variables de entorno del sistema. Puede optar por configurarlas vía: “System⇒Advanced System Settings” o desde el panel de control de Windows, son las siguientes:
    • CATALINA_HOME necesaria para indicar la ubicación de la carpeta de Tomcat, por ejemplo: c:\Archivos de programa\apache-tomcat-8.0.15.
    • JAVA_HOME necesaria para indicar la ubicación de la instalación del Java JDK o JRE, por ejemplo: c:\Archivos de programa\java\jdk1.8.0_25.
  4. Copie la carpeta “omnisrestservlet” del directorio “clientserver\server” del raiz Omnis Studio sobre la carpeta “webapps” de Tomcat.

 

Instalación de la interfaz de usuario “Swagger”


La interfaz de usuario “Swagger” nos permitirá ver y probar nuestros servicios web Omnis RESTful, desde un navegador web.
  1. Descargue el archivo “swagger-ui-master.zip” desde el sitio web: https://github.com/wordnik/swagger-ui, pulsando el botón “Download ZIP” situado a la derecha de la página web.
  2. Extraiga el contenido del archivo descargado y cópielo sobre la carpeta “dist” del directorio “webapps” de Tomcat, después renómbrelo como “swagger-ui”.

 

Arrancando Tomcat


Una vez completados los pasos anteriores, Tomcat estará listo para iniciarse mediante la ejecución del “startup.bat” ubicado en la carpeta “bin” de Tomcat. Si ya se está ejecutándose, deberá detenerlo primero mediante el “shutdown.bat”, si se esta usando un servidor web alternativo como IIS también se deberá primero detenerlo, para iniciarlo después.

 

Usando Omnis Developer como servidor WS RESTful


Para utilizar el servidor Tomcat que acabamos de instalar como servidor web RESTful será necesario fijar los parámetros “Server port”, “RESTful URL” y “RESTful Connection” desde el diálogo de configuración del servidor, tal y como se muestra a continuación, cambie el 99.99.99.99 por su dirección IP. Para abrir este cuadro de diálogo, despliegue el nodo “Web Service Server” del navegador Omnis Studio (Studio Browser) y haga clic sobre el hipervínculo “Server Configuration”.

 

La librería de ejemplo RESTful Server


Abra el ejemplo RESTful de la librería “swaggerdemo.lbs” (incluida en restfuldemo.zip de Aula Omnis) y observe las entradas “wizard” bajo el nodo “Web Service Server” en el navegador. Este es el valor asignado a la propiedad “restfulapiname” para el “remote task” “rtWizard”. El hipervínculo “Show Method List” muestra los métodos HTTP de la “remote task” de la URI “data”.


Éste ejemplo crea una base de datos SQLite a partir de un archivo de texto separado por comas, que puede ser consultada y actualizada mediante el servicio web RESTful.


Para utilizarlo, abra la ventana “wWizard”, arrastre el archivo de texto “phonelist.txt” suministrado, sobre la ventana abierta y siga los pasos que se indican a continuación, para su acceso a través del servicio web RESTfull.

 

Invocando el servicio RESTful desde “Swagger UI”


Swagger UI (interface de usuario swagger) utiliza un URI para invocar a un servicio web RESTful, al hacer clic sobre el hipervínculo “Web Service Server” podrá ver la URI necesaria, sobre la parte superior del “swagger data”.



Abra el “Swagger UI” sobre un navegador web, mediante introducir la dirección http://99.99.99.99:8080/swagger-ui/index.html, donde 99.99.99.99 es su dirección IP. Introduzca la URI como se muestra arriba y pulse “Explore” para ver el servicio web Omnis RESTful, haga uso del hipervínculo “Show/Hide” para sus métodos.


Pulse “Try it out!” sobre GET, para que el método HTTP “$get” de la URI “/ data” de la “remote-task” “rtWizard” se ejecute, devolviendo la lista de contactos localizados en la base de datos SQLite.

Para insertar un nuevo contacto utilizando PUT, haga clic sobre el “model schema box” y su opción “set as parameter value” para cambiar el valor de los parámetros, después pulse “Try it Out”.



Para ver el registro recién insertado en el servidor junto con el resto de datos existentes, escoja la opción “test” del “”remote-form” 'jsWizard' de la librería “swaggerdemo”.

 

Invocando el servicio RESTful desde Omnis Studio


El objeto “HTTP Web Worker” es el encargado de invocar los servicios web RESTful. La librería de ejemplo “swaggerclient.lbs” incluida, muestra cómo hacer uso de éste objeto para invocar un servicio web RESTful desde una hipotética máquina cliente, en lugar de tener que utilizar la interfaz de usuario Swagger con éste mismo próposito.

Para utilizar la demo en modo cliente, abra la ventana “wRestfulClient”, y escriba la URI “http://99.99.99.99:8080/omnisrestservlet/ws/1234/api/swaggerdemo/wizard/data” donde “99.99.99.99” es la dirección IP de su servidor Tomcat.

 
Seleccione “HTTPGet” y pulse “Test” para recuperar datos del servidor o “HTTPPut” para introducir nuevos valores y enviarlos al servidor para su inserción.

23 septiembre 2015

RESTful con Omnis Studio (Parte 1 de 3)

Para la implementación de servicios web basados en REST, Omnis Studio dispone de un componente externo y un “plugin” encargado de publicar el código Omnis como Servicio Web, ambos son complementados mediante el nuevo componente externo JSON denominado “OJSON”, que permite la adecuada gestión de objetos basados en JSON, profusamente utilizados con REST.

¿Qué es REST? REST es sin lugar a dudas el modelo más extendido hoy en día para usar y publicar servicios web, está considerado como la mejor alternativa al uso de otras tecnologías como SOAP. Un servicio web RESTful es identificado mediante una URI, donde los clientes interactúan con el recurso a través de solicitudes HTTP, obteniendo respuestas mediante un conjunto ya predeterminado de métodos HTTP.

 

Creación de un “Web Service” cliente


Dentro del grupo de objetos externos “Web Worker Objects”, podemos encontrar el “HTTPClientWorker” que es un objeto de tipo “Worker”. Esto significa que funciona de modo similar a como lo hacen los ya conocidos objetos DAM de este mismo tipo, es decir que son ejecutados en segundo plano.

Para utilizar el objeto, deberemos crear una “Object Class” con el “HTTPClientWorker” como subclase. Tal como mostramos en la siguiente imagen:


En la clase-objeto así creada, será necesario definir dos métodos, “$completed” y “$cancelled”, los cuales serán respectivamente invocados tras la obtención del resultado de una solicitud o al producirse su cancelación. A continuación, deberemos crear una variable-instancia de tipo objeto sobre una clase “remote-form” JavaScript, desde donde poder instanciar la clase-objeto anteriormente creada, con la finalidad de poder interactuar con el servicio Web mediante sus métodos. De entre ellos el objeto “HTTPClientWorker” incluye: El “$init()” que lo inicializa de forma que quede listo para realizar las peticiones HTTP que se especifiquen; El “$run()” que ejecuta un hilo en primer plano; El “$start()” que ejecuta un hilo en segundo plano y el “$cancel()” que cancela el subproceso en marcha. El método “$cancel()” es invocado cuando se cancela la solicitud y el “$completed()” cuando se complete la solicitud, la cual retornará una única variable-parámetro de tipo “row” con diversas columnas, el contenido de la respuesta estará incluido en la última columna.

 

Ejemplo de cliente “Web Sercice” basado en REST.


Desde la web de Aula Omnis, podrá descargar una librería dispuesta a modo de ejemplo, sobre el uso de un Servicio Web basado en REST.


Dicha librería permite mostrar información básica sobre la previsión del tiempo, mediante el acceso a un servicio web público proporcionado por WorldWeatherOnline.com. La compañía ofrece dos versiones de su API; una gratuita y otra de pago. El ejemplo se basa en el servicio gratuito, éste puede ser invocado con un límite de 12.000 accesos diarios y 5 veces por segundo, lo cual es más que suficiente para nuestro propósito. Para hacer uso del servicio, deberá obtener antes una clave de la API desde WorldWeatherOnline.com e introducirla al ejecutar la librería por primera vez.

Para probar el servicio y conseguir mostrar el pronóstico del tiempo, abra primero la librería de ejemplo, haga clic derecho sobre el “remote-form” “jsWeather” y seleccione “Test Form” desde el menú contextual. El formulario deberá abrirse en su navegador y mostrar el pronóstico del tiempo para 5 días en Saxmundham. Tenga en cuenta que se ésta utilizando la versión gratuita de la API, la cual tiene un límite de 5 consultas por segundo, por lo que se hace uso de un temporizador para evitar la devolución de un error desde el servidor. Si publica el formulario a un servidor web, el servicio tratará de identificar su ubicación mediante su dirección IP en uso.

Cuando examine el código de la librería de ejemplo, notará que los métodos clave son “GetWeather”, “getData”, “readCurrentData” y “readForecastData” en el caso del “remote-form”  “jsWeather”. “$completed, “$returnVa” en el caso de la clase-objeto “Orest”. A continuación mostramos el método de iniciación “$init()” encargado de inicializar el objeto “Web Services”, configurando los parámetros principales e invocando el servicio web.

; iURI (Char) inicializado como "http://api.worldweatheronline.com"
; iHTTPMethod (Int) iniciado con el valor “kOWEBhttpMethodGet”
; iHeadersList (List)
; iContentChar (Char)
Do iHeadersList.$define(iHeaderName,iHeaderValue)
; call the web service
Do iRestfulObj.$init(iURI,iHTTPMethod,iHeadersList,iContentChar)
Do iRestfulObj.$run() Returns lStatus

A continuación mostramos, el método “$completed” del objeto “Orest”:

; invocado desde el “worker” del cliente con los resultados
Calculate iResponse as pRow
Calculate iResponseHeaders as pRow.responseHeaders
Do OJSON.$formatjson(pRow.responseContent) Returns iReturnStr
Do OJSON.$jsontolistorrow(pRow.responseContent) Returns iJSONRow

Para procesar la salida que nos llega en formato JSON, se hace uso del  nuevo componente externo “OJSON”.

Creando nuestros propios “Web Services”

Un plug-in “Web Server” permite publicar el código de nuestras aplicaciones Omnis, que permitirá a los posibles cliente hacer uso de nuestros “Web Services”. La interfaz para éstos servicios web es vista por los clientes como una API o conjunto de APIs. Omnis genera las API’s RESTful (o ORAs) usando una definición "Swagger", que es el estándar más utilizado con las API’s RESTful.

Podrá ver las Omnis APIs RESTul desde el navegador de Omnis Stido (Studio Browser) como hijos del nodo de su librería bajo el grupo “Web Service Server” (tal cómo ya venia ocurriendo con los servicios basados en WSDL). Cada “ORA” se muestra bajo un nodo separado en el árbol, y varias opciones o acciones con hipervínculos. Podrá ver su definición “Swagger” navegando a trabes de los hipervínculos.

16 septiembre 2015

Configurando un trabajo de impresión (Job Setup)

El diálogo “job setup” o “configuración de impresión” permite al usuario escoger cosas como bandejas de salida, páginas a imprimir, etc. Además de los comandos “Print report” y “Prepare for print” que tradicionalmente permitían mostrar éste diálogo al usuario, podemos hacer uso del comando de notación, con éste único fin.

Toda instancia-informe contiene un nuevo método denominado “$openjobsetup()”, que permite mostrar el diálogo de impresión una vez que creada la instancia-informe. Si se especifica kTrue en el parámetro “$openjobsetup”, el diálogo se abrirá independientemente de cual sea el destino del mismo.

Debemos tener en cuenta que el diálogo sólo se puede abrir una vez creada la instancia-informe y antes de la impresión del primer registro. De modo que deberá usarse durante o inmediatamente después de la ejecución del método “$construct”.

El ejemplo siguiente muestra como hacer uso del método durante la construcción del informe.

Método: “$construct
Parametro         Tipo
pPrompt           Boolean   

Variable local    Tipo
ok                Boolean   

Código del método
If pPrompt
  Do $cinst.$openjobsetup(kTrue) Returns ok
  If not(ok) ;; si el usuario cancela el trabajo se cierra la instancia
    Do $cinst.$close()
    Quit method
  End If
End If

Guardado de la selección


Todo lo establecido en el diálogo de configuración de impresión quedará automáticamente guardado junto con el informe. Sin embargo, debemos tener en cuenta que tal información no es multiplataforma, por lo que sólo será válida si se está imprimiendo en la misma plataforma.

09 septiembre 2015

Introducción a la abstracción y la herencia

Éste artículo está especialmente dirigido a los desarrolladores que tras una larga experiencia programando con Omnis 7, han decidido dar el salto a la programación con Omnis Studio. Mostramos una pequeña introducción sobre cómo utilizar las posibilidades de la herencia que aporta Omnis Studio, atendiendo a lo que en programación orientada a objeto (OO) significa la “abstracción”. La abstracción y la herencia (en Omnis Studio) se entiende como la creación de elementos genéricos, con la intención de ser usados muchas veces en nuestra aplicación, consiguiendo que su tiempo de programación sea menor a la vez que más consistente, más sencilla y más fácil de mantener.

Imaginemos que disponemos de una ventana donde mostrar el domicilio y otros datos de un registro de direcciones, seguramente también deseemos disponer de algunos botones en ella, que permitan al usuario buscar, editar, insertar y eliminar registros. Sin embargo éste tipo de funciones a menudo serán también necesarias en muchas otras ventanas, tales como contactos, proveedores, etc. Por supuesto podríamos optar por programar de nuevo todas estas funciones para cada ventana, pero naturalmente no es eso lo que pretendemos.

Aquí es donde la abstracción y la herencia entran en juego. La idea es crear una clase-ventana principal con los botones estándar de manejo de datos, mientras que los campos en sí, estarían dibujados sobre otras ventanas secundarias y los datos a manejar sobre una única variable de tipo “row”, como por ejemplo "ivDataRow", la cual sería una variable del ámbito instancia, definida sobre la clase-ventana principal. Note que ésta variable “row” no se llama algo así como "ivDireccionesRow", sino que tiene un nombre genérico, pues la idea es que pueda ser usada con todas las tablas de datos y no sólo con la de direcciones, además (en este momento del diseño de nuestra aplicación), se supone que aún no sabemos qué tablas vamos a manejar, por lo tanto, deberemos disponer de una segunda variable de instancia de tipo “Item Reference”, a la que llamaremos “ivTableRef”, la cual apuntará a la hipotética tabla en uso.

Usaremos la variable “Item Reference”, en el método “$construct()” de la ventana, posteriormente éste método será abstraído (Overwrite) en cada sub-ventana, para sustituir la asignación de la clase-tabla a su correspondiente. Su código sería el siguiente:

Do ivDataRow.$definefromsqlclass(ivTableRef)

Ahora heredaríamos la clase-ventana principal, junto con el método anterior, a continuación mostramos una imagen de una posible ventana para la edición de datos, naturalmente tendremos que añadir los botones de buscar, editar, y así por el estilo, en la super-clase, junto con la programación que cada uno necesite.

 
A modo de ejemplo, mostramos lo que podría ser el código para el botón “Borrar”:

On evClick
  No/Yes message (Icon,Sound bell) {¿Desea realmente eliminar el
   registro "[IvDataRow.[ivColsToBeDisplayed.c1]]"?}
  If flag true
    If ivDataRow.$delete()
      Do ivDataRow.$clear() 
      Do $cinst.$redraw()
    Else
      OK message Database message (Sound bell) {El registro no 
      ha podido    eliminarse.//Error: [ivDataRow.$getErrorText()]}
    End If
  End If

Puesto que no sabemos cual es el nombre de la columna que queremos mostrar en el mensaje genérico, usamos la forma corta “c1” para mostrar la primera columna de “ivDataRow”. Atendiendo a nuestra filosofía de trabajo, deberemos programar todos los métodos específicos de cada tabla de datos en su propia clase-tabla. Para crear una sub-clase, podemos hacer clic sobre la clase-principal en el navegador (Studio Browser) y seleccionar la opción del menú contextual “Make Subclass”, tal y como mostramos a continuación:


Ahora vamos a ver cómo crear una ventana para la edición de registros, especificando la tabla a usar. Por ejemplo, creamos la clase ventana “wAddress”, que a su vez hereda los elementos de la ventana principal. A continuación abstraemos (Overwrite) el método “$construct()” haciendo clic sobre él con él botón derecho del ratón y seleccionando la opción “Overwrite”, ha continuación configuramos la variable de instancia “ivTableRef” mediante el comando “Set Reference” y finalmente (no olvidar) activamos la ejecución del código en la ventana principal mediante el comando “Do inherited”. Por ejemplo:

Set reference ivTableRef to $tables.T_Address
Do inherited

Ahora sólo tendríamos que añadir los campos a la ventana, asignándole sus respectivos “$dataname” referenciados des la variable “ivDataRow”, tal y como se muestra en el ejemplo siguiente:


De éste modo podemos crear nuestras ventanas en sólo unos pocos pasos y poner en práctica el uso de ventanas heredadas. Las funciones generales pueden ser escritas de forma genérica en la super-clase y en el futuro agregar otras nuevas que serán automáticamente heredadas o puestas a disposición de todas las sub-clases.

02 septiembre 2015

Uso de “String Tables” para la localización de aplicaciones en diferentes idiomas

Para poder seguir las explicaciones que se ofrecen en éste articulo, deberá descargar las librerías de ejemplo, disponibles en Aula Omnis. Encontrará dos ficheros que podrán ser usados a partir de la versión de Omnis Studio 2.1, para Windows descargue el fichero “Strngtab.zip” y para MacOS el “Strngtab.sit.hqx”, descomprimirlos sobre una misma carpeta, en ella deberá encontrar las siguientes librerías:

STRTEST.LBS
  • Esta librería muestra cómo hacer uso de las “String Tables” para añadir soporte multi-idioma a nuestras aplicaciones. Al hacer clic sobre el botón “language”, se nos permitirá seleccionar uno de entre lista desplegable, después bastará con pulsar el botón “Set Language” para que todos los controles se redibujen, mostrando el idioma seleccionado. El ejemplo muestra el uso de las principales características de la interfaz “String Table” y su función “$getText()”.

TABLE.LBS
  • Esta librería muestra cómo configurar los controles “String Label” para muestren la información obtenida de entre varias “String Table”.

A continuación mostramos las funciones implicadas en el uso de “String Tables”, atendiendo a su creación, almacenado, eliminación y uso.

 

Funciones para la creación de “String Tables”:


$loadtablefromlist(≤Nombre de Tabla≥,≤Ruta≥,≤List≥)
Crea una “String Table” a partir de una variable de tipo “List”. Como cabe suponer, la tabla es creada en memoria. Para guardarla se deberá usar la función “$savestringtable”.

$loadcolumn(≤Nombre de columna≥,≤Nombre de Tabla≥,≤Ruta≥) 
Crea una “String Table” usando una sola, de las columnas de la tabla.

$loadstringtable(≤Nombre de Tabla≥,≤Ruta≥) 
Carga completa de la “String Table” indicada.

 

Funciones para guardar “String Tables”:


$savestringtable(≤Nombre de Tabla≥) 
Guarda una “String Table” de entre las anteriormente creadas.
Nota: No se especifica ruta, puesto que éste parámetro solo es necesario durante su creación.

 

Funciones para la eliminación “String Tables”:


$removestringtable(≤Ruta≥) 
Elimina del disco una “String Table”.

$unloadstringtable(≤Nombre de Tabla≥) 
Descarga de la memoria una “String Table”.

$unloadall() 
Descarga de la memoria todas las “String Tables”.

Nota: Ambas funciones son opcionales, ya que todas las “String Tables” se descargan automáticamente al salir de Omnis.

 

Funciones para el acceso y uso de “String Tables”:


$setcolumn(≤Nombre de Columna≥) 
Establece la columna actual a la indicada ≤Nombre de Columna≥. Se puede indicar tanto un nombre, como un número.

Nota: Es sensible al uso de mayúsculas y minúsculas. Si se están utilizando varias “String Tables”, deberá usarse la forma ≤Nombre de Tabla≥.≤Nombre de Columna≥, por ejemplo, “StringTable.$setcolumn(“Table1.French”)” o bien “StringTable.$setcolumn(“Table1.3”)

$getcolumnname([≤Nombre de Tabla≥] ) 
Obtiene el nombre de la columna actual. No es necesario especificar ≤Nombre de Tabla≥ si se está trabajando con una sola “String Table”.

$getcolumnnumber([≤Nombre de Tabla≥] ) 
Trabaja del mismo modo que la función anterior, pero devuelve el número de la columna en lugar de su nombre.

$redraw(≤Hwnd≥) 
Esta función puede utilizarse para volver a dibujar una ventana completa. En la librería de ejemplo “STRTEST”, se usa la función “StringTable.$redrawAll()” para volver a dibujar todas las ventanas tras la selección un nuevo idioma. Seguramente es el mejor modo de refrescar los controles de tipo “String Label” de nuestras aplicaciones.

$colcnt([≤Nombre de Tabla≥]) 
Devuelve el número de columnas de .

 
$rowcnt([≤Nombre de Tabla≥]) 
Devuelve el número de filas en .

 
$loadlistfromtable(≤Nombre de Tabla≥) 
Copia una “String Table” sobre una variable de tipo “List”.

26 agosto 2015

Creando nuestro propio escritorio Omnis

Por defecto, Omnis Studio presenta un escritorio con el fondo gris, es decir, el área de trabajo de la ventana principal es de color gris (al menos en la plataforma Windows). Sin embargo es posible personalizar dicho color de fondo o incluso insertar una imagen. El “truco” que exponemos a continuación, nos puede ayudar a hacer esto con facilidad.

Para lograrlo, empezaremos por añadir una nueva clase-ventana a la librería que estemos construyendo, su nombre será: “wBackground”. Una vez creada, ábrala en modo diseño y (por ejemplo) coloque una foto en ella mediante la opción del menú “Edición”, “Pegar desde archivo”. La imagen seleccionada deberá ser lo suficientemente grande, como para cubrir todo el fondo de la ventana o incluso mayor, la idea es asegurarse de que se siga viendo correctamente aún cuando se amplíe la ventana principal de Omnis, una imagen en formato JPG de 1280x1024 píxeles y a 72 dpi, puede ser suficiente, al final de éste artículo puede un ejemplo. Una vez hecho esto, deberemos modificar las siguientes propiedades de nuestra ventana “wBackground”:

$closebox = kFalse
$growbox = kFalse
$style = kSimple


Además de éstas deberemos cambiar la propiedad “$edgefloat” para fijar su valor a “kEFrightBottom” de éste modo nos aseguraremos de que la imagen en la ventana será automáticamente ajustada, cada vez que cambie su tamaño por acción del usuario. Ahora, y en el método “$construct()” de la ventana “wBackground” deberemos añadir el siguiente código:

Do $cinst.$width.$assign($root.$modes.$width)
Do $cinst.$height.$assign($root.$modes.$height)
Do $cinst.$top.$assign(0)
Do $cinst.$left.$assign(0)


A continuación, añadiremos una segunda clase-ventana con el nombre “wSuper”, a la cual añadiremos un método “$event()”con el código siguiente:

On evWindowClick

   If pClickedWindow.$name='wBackground'
     Quit event handler (Discard event)
   End If


Este código nos permitirá asegurarnos de que la ventana “wBackground” permanezca en todo momento anclada al fondo.

Ahora tan sólo nos faltará asignar la ventana “wSuper”, como superclase en todas y cada una de las clases-ventana que contenga nuestra librería. Podemos optar por hacer esto manualmente, cambiando la propiedad “$superclase” para asignarle el valor “wSuper” o bien (mi preferida) mediante el siguiente comando:

Do $windows.$sendall($Ref.$superclass.$assign('wSuper'))

Finalmente deberemos  añadir el código necesario para hacer visible la ventana “wBackground”, lo cal haremos escribiendo el comando mostrado a continuación, sobre el método “$construct” de la clase “Startup_Task” de nuestra librería en construcción:

Do $windows.wBackground.$openonce()


18 agosto 2015

Polimorfismo en Omnis

Una ventaja de usar encapsulación en objetos con Omnis, es la posibilidad de que éstos puedan reaccionar de manera diferente ante un mismo mensaje. Veamos un ejemplo. Supongamos que disponemos de tres ventanas diferentes con información relativa a la actividad de nuestros clientes y una cuarta ventana con la lista con todos ellos, la idea es que tras pulsar sobre la línea de un cliente cualquiera, pueda reflejarse la información pertinente sobre las restantes tres ventanas. Este evento deberá enviar un mensaje a las otras ventanas con la información del cliente seleccionado, por su parte, cada una de ellas deberán reaccionar de manera diferente: La primera deberá mostrar la dirección del cliente (Address list) y otros detalles, la segunda (Invoices) deberá mostrar todas sus facturas, mientras que la tercera (Delivery notes) deberá mostrar una lista con todos los albaranes entregados.


Lo mejor que podemos hacer para enviar el mensaje a todas las instancias-ventana, (en nuestro caso a todos los objetos del cliente), es empezar primero por construir un método público para cada ventana, el cual será receptor de nuestro mensaje. Para evitar que se nos pueda olvidar alguna de las ventanas implicadas, podríamos optar por crear un clase común con un método público denominado “$setCustomer”, a fin de que sea la superclase de todas las ventanas implicadas. El método no contendrá código alguno, excepto el comentario sobre que éste puede ser anulado (desheredado). Después, (en cada subclase ventana) podremos observar éste mismo método mostrado en color azul y que por tanto podremos “desheredar”. El método deberá contener el parámetro “pCustID”, éste nos permitirá (en función de la ventana de que se trate) cargar los datos generales, datos de facturas y albaranes localizados en la base de datos, según en el identificador (pCustID) pasado a la ventana.


Ahora sólo nos falta saber, cómo enviar el mensaje desde la ventana con la lista de clientes, hacia las otras instancias-ventana. Para ello utilizaremos el método “$sendall” que (como sabemos) permite enviar un mensaje a todos los miembros de un grupo. En nuestro caso, lo escribiremos dentro del método “$event()” correspondiente a la lista de clientes (Customer list):

On evClick
    Do $iwindows.$sendall($ref.$setCustomer(ivCustomerList.ID))

Tras un clic sobre la lista de clientes, se enviará un mensaje a todas las instancias-ventana abiertas, para que sea ejecutado el método “$setCustomer()”, pasándose el ID del cliente seleccionado.

Tenga en cuenta que Omnis podrá mostrar un mensaje de error, en el caso de que alguna de las ventanas abiertas no contenga el método “$setCustomer”. Pero no hay que alarmarse, pues existen varias posibilidades para cambiar este comportamiento. Una modo sencillo, sería ir a las “Prefs” (Preferencias) de la biblioteca y cambiar su propiedad “$reportnotationerror” por “kFalse”.

Otra posibilidad, es enviar el mensaje sólo a los objetos que contengan el método “$setCustomer”. Para ello, deberemos añadir un parámetro adicional al “$sendall” el cual actuará a modo de filtro, enviando el mensaje sólo a las instancias que lo contengan:

On evClick
   Do $iwindows.$sendall($ref.$setCustomer(ivCustomerList.ID),
      $ref.$methods.//$setCustomer//)

Las dos barras invertidas dobles, permite indicar a Omnis, cual es el nombre del método que buscamos.

12 agosto 2015

Objetos externos (External objects)

Los objetos externos pueden ser manejados mediante la creación de un tipo especial de componente referenciado como “no visual”. Todos ellos se encuentran ubicados dentro de la carpeta Xcomp que (a su vez) podemos encontrar dentro del directorio raíz de instalación de Omnis Studio. Pero no todos los Xcomp pueden ser utilizados de éste modo. De hecho, la mayoría de los Xcomp sólo contienen objetos “visuales”, los cuales podemos colocar en ventanas, formularios e informes, pero, incluso algunos de éstos también contienen algún componente “no visual” que podemos utilizar como clase base, en la construcción de la variable objeto (variable de tipo “”Object”) o bien como superclase de una clase de tipo objeto (clase de tipo “Object”).

Existen relativamente pocos de estos Xcomps especiales. Una manera de descubrirlos es navegar a través de la lista de componentes externos disponibles, mediante abrir el enlace correspondiente desde el Explorador de Omnis Studio. Tal y como se muestra el siguiente imagen:



Explorando los componentes externos


Cómo podrá comprobar existe un gran número de componentes externos. Pero sólo el hecho de su aparición, no significa que esté siendo usado por Omnis Studio, ya que primero deberán ser cargados en memoria. La forma más sencilla de hacerlo es mediante indicar su estado de precarga, tal como se puede observar a continuación:



En éste artículo nos centraremos en los componentes recogidos bajo el grupo “External Components”. Si lo ampliamos podremos ver algo similar a los siguiente:



Podríamos mantener componentes alojados en cualquier parte de nuestro sistema, pero lo mejor es agruparlos en la carpeta Xcomp.

Los componentes actualmente cargados se muestran en la lista con un punto verde y los que no, con un punto rojo. Podemos configurar cualquiera de ellos para que sea cargado al iniciarse Omnis o bien al abrirse la librería en uso, mediante hacer clic en el botón de la opción correspondiente. Tenga en cuenta que el color del punto no cambiará inmediatamente, ya que los cambios no se verán reflejados hasta la próxima vez que abramos ésta ventana de configuración. Pero si podremos hacer uso de los cambios introducidos sin necesidad de reiniciar Omnis Studio, no cerrar y volver a abrir nuestra librería.

Los elementos se muestran bajo la denominación “libraries”, y es una denominación apropiada, pues a medida que vamos recorriendo los diferentes elementos de la lista, enseguida nos damos cuenta de que muchos de ellos contienen a su vez varios componentes. Mostrados a la derecha, podemos ver los nombres de dichos componentes, junto con iconos representativos del tipo al que pertenecen. Éstos pueden ser: Ventana, Informe y Objeto. Los componentes “Remote Form”” están localizados en la lista bajo un grupo diferente denominado “Form External Components”, pero en este artículo, deseamos centrarnos en el uso de los componentes de tipo Objeto (Object), son los mostrados mediante un icono en forma de caja y con un enchufe saliendo de ella.




En el dibujo anterior, podemos ver los controles que integran el componente “Graph2”. Observe la existencia de tres controles, uno de tipo ventana, otro de tipo informe y otro de tipo objeto.

Una vez que el componente externo ha sido cargado por Omnis, podrá ser usado con diversos fines dentro de nuestra librería. Un modo de hacerlo, es mediante localizar cualquier componente con interfaz gráfica de usuario, desde el “Component Store” y arrastrarlo sobre la posición que deseemos durante el diseño de una clase apropiada para su uso. Pero cuando se trata de componentes de tipo objeto “no visuales” su modo de uso es diferente.

 

Uso de un objeto externo (External Object)


Existen dos formas básicas de uso. 1) Seleccionar el componente de tipo objeto, como subtipo en una variable de tipo objeto o especificarlo más adelante mediante el método “$new()”. 2) Disponer el componente de tipo objeto, bajo el atributo superclase (superclass) en una “Object Class”. Pueden existir diferentes razones por las que preferir una u otra técnica.

Por el momento, vamos a utilizar la segunda técnica, ya que nos da la oportunidad de explorar fácilmente las propiedades y métodos del objeto. De modo que vamos a crear una nueva “Object Class” con el nombre “timerObject”, después y mediante el “Property Manager”, vamos a asignarle el xcomp “Timer” como superclase de nuestra recién creada “Object Class”. Tras hacer clic sobre el valor para ésta propiedad, aparecerá el diálogo que nos permite realizar su elección de entre la lista de componentes. Observe que sólo se muestran los xcomps de tipo objeto:




Ahora podemos abrir la clase “timerObject” y ver su contenido. Observe que la “Object Class” ha heredado los métodos y propiedades del componente externo. Tras abrir la clase, podemos visualizar dichos métodos en el editor:



Los elementos heredados aparecen (por defecto) en azul. (ver $root.$prefs): 



La “Inheritance”  (herencia) es una característica de la programación orientación a objetos soportada por Omnis Studio. Cada vez que se cree una instancia de nuestro objeto, recibirá los métodos y propiedades de la superclase.

Puede darse el caso de que queramos sustituir un método heredado, por otro nuestro, pero manteniendo su actual nombre, con el único fin de sustituir su código o acción por defecto. Puede que incluso tangamos imperiosas razones para hacerlo así en éste caso, ya que el método denominado “$timer” es el método invocado cuando el cronómetro (en su cuenta atrás) llega a cero. Tras su herencia, está vacío, por lo que debemos hacer un “overriding”, a fin de anular su acción por defecto. A continuación mostramos como hacerlo:




En éste caso el método se hereda vacío, pero también puede suceder que deseemos reemplazar un método que realmente hace algo. Por ejemplo, tal vez necesitemos añadir un par de pasos adicionales al método “$resettimer” a fin de reiniciar otras variables. Tenga en cuenta que aunque hayamos anulado y sustituido el método por el nuestro propio, podemos seguir invocándolo para su ejecución desde cualquier punto del método mediante el comando “Do inherited”, tal y como mostramos a continuación:



El editor de métodos nos permite ver los nombres de los métodos heredados, pero el “Interface Manager” nos permite ver un poco más. Accedemos a la “Interface Manager” desde el menú “View” del editor de métodos. En la siguiente imagen, puede observar como es posible ver los métodos y las propiedades, así como información adicional de ayuda:



Desde aquí, podemos examinar los parámetros disponibles para el método seleccionado y leer su descripción. En el caso de métodos no heredados o anulados, podemos optar por incluir nuestras propias descripciones. La pestaña de propiedades nos permite leer la descripción de la propiedad seleccionada. A continuación veremos un segundo modo de hacer uso de un objeto externo.

Consiste en simplemente heredar (inherit) la funcionalidad del Xcomp directamente sobre una variable de tipo objeto. La forma más sencilla de hacerlo es mediante indicar la xcomp a utilizar, reflejándola como subtipo de la variable de objeto, desde el panel de definición de variables.




Una variable “Object” definida de esta forma, hereda todos los métodos y propiedades que vimos anteriormente para la “Object Class”.

Si deseamos examinar sus métodos y propiedades con mayor detalle, puede optar por abrir el “Interface Manager” desde el menú contextual de la propia variable:




Si lo preferimos, podemos hacer uso del método “$new()” para crear una instancia de la variable objeto, indicando al mismo tiempo el xcomp a utilizar. Dado que la mayoría de éstos xcomps no contienen un método “$construct”, no hay mucha razón para hacerlo, pero ciertamente está permitido. El modo sería la siguiente:


Tenga en cuenta que debemos indicar el nombre de la librería de componentes, seguido de “$objects”, con el fin de poder localizar el nombre del elemento de entre los tres, que la componen.

Por último, indicar también que podríamos hacer uso de una variable de tipo “Object reference” en lugar de una variable “Object”. Recuerde que esta variable (o puntero) deben ser usadas mediante  el método “$newref()” en lugar de “$new()”, tal y como mostramos a continuación:


La única desventaja de esto, es que no se nos permite utilizar el “Interface Manager” para ver los métodos y propiedades del objeto mientras trabajamos.

Gracias por su atención.