Etiqueta

5 de enero de 2011

Actualización automática de bibliotecas a los usuarios finales

Problemática

A menudo los desarrolladores realizamos cambios sobre las bibliotecas Omnis Studio para adaptarlas a las necesidades de los usuarios o para corregir posibles deficiencias, esto obliga a actualizar las versiones que estos tiene instaladas. Se necesita por tanto un procedimiento que actualice de forma automática los ordenadores de los usuarios.

Escenario previo (Requerimientos):

Partimos de la base de que disponemos de un servidor FTP, donde existe un directorio llamado “ForUpdate”, que contendrá una copia de las bibliotecas a actualizar, es el lugar donde el desarrollador dejará la nueva biblioteca, cada vez que se produzca un cambio en la misma y por tanto debe ser actualizada al usuario.

Resolución:

Ahora construiremos una nueva biblioteca llamada “Actualiza” en nuestro ejemplo y que una vez terminada situaremos en la carpeta “startup” de Omnis Studio, la idea es que sea la primera biblioteca que Omnis Studio ejecutará.

Todos los procedimientos descritos pertenecen a la clase Task “Startup_Task”

Las variables del caso son las siguientes:

No. Instance Variable Type Subtype Init.Val/Calc

1 iActualizado Boolean
2 iArchivo Character 100
3 iDirArchi Character 100
4 iDirFTP List
5 iDirLocal List
6 iFTPSocket Long integer
7 iPassword Character 100 ‘******’
8 iServerDirec Character 100 '192.33.20.20'
9 iServerError Character 500
10 iUsuario Character 100 'librerias'

En primer lugar construiremos el método $construct de la librería “Actualiza”, todos los procesos que tendrán lugar se ejecutarán desde este procedimiento.

Después de haber definido las variables del caso, debemos hacer lo mismo con las siguientes variables locales:


No. Local Variable Type Subtype

1 lErrCode Short integer (0 to 255)
2 lExportPath Character 100
3 ok Boolean

Además del método público $construct, crearemos un total de seis métodos privados: EnFTP, EnUsuario, Guardarropa, Compara, SolicitaCopia y CopiaFTP.

El método $construct se compondrá finalmente de las siguientes líneas de código:

;; obtiene el contenido del directorio FTP a actualizar
1 Do method EnFTP Returns ok
2 If ok
;; obtiene el contenido del directorio correspondiente a la última actualización
3 Do method EnUsuario
;; selecciona de la lista FTP los archivos que necesitarán actualizarse
4 Do method Compara
;; pregunta al usuario y permite la copia de la nueva versión de la biblioteca
5 Do method SolicitaCopia
6 If iActualizado
;; guarda la lista de archivos FTP en un documento local denominado UltimoUpdate.txt
7 Do method Guardaropa
8 End If
9 End If

El procedimiento “EnFTP”, tiene como objetivo leer la entrada del directorio de los archivos contenidos en el servidor FTP y guardarlo sobre la lista “iDirFTP”, para posteriormente compararla con las entradas de directorio correspondientes a la última actualización que realizo el usuario.


No. Local Variable Type Subtype

1 lErrCode Short integer (0 to 255)

1 ; establece la conexión con el servidor FTP
2 FTPConnect (iServerDirec,iUsuario,iPassword) Returns iFTPSocket
3 If iFTPSocket; entra en el directorio "ForUpdate"
8 FTPCwd (iFTPSocket,'ForUpdate') Returns lErrCode
9 If lErrCode
10 OK message Error FTP {[con("Error al acceder al directorio FTP de
actualización ",kCr,"Código : ",lErrCode)]}
11 Else
12 Do iDirFTP.$define(iDirArchi)
13 ; devulve la lista de archivos en el directorio FTP sobre la variable iDirFTP en formato extendido
14 FTPList (iFTPSocket,iDirFTP,,1) Returns lErrCode
15 If lErrCode
16 FTPGetLastStatus (iServerError) Returns lErrCode
17 OK message Error FTP {[con("Error obteniendo la lista de archivos del
servidor FTP",kCr,"Devolvio: ",kCr,iServerError)]}
18 Quit method kFalse
19 Else
20 Quit method kTrue
21 End If
22 End If
23 End If

El procedimiento “EnUsuario”, la idea es compara la lista de los archivos a actualizar (servidor FTP), con los de la última actualización realizada, pero note que en caso de tratarse de la primera actualización dicha lista no existirá, por lo que deberá ser creada.

Finalmente la lista se guardará en un archivos de texto local denominado “UltimoUpdate.txt” y es desde este archivo que se cargará la lista de archivos para su comparación, la lista de archivos contenida en “UltimoUpdate.txt” se guardará en la variable de lista “iDirLocal”.

Finalmente y a estas alturas del proceso abremos obtenido dos listas, “iDirFTP” (con el directorio del servidor FTP) e “iDirLocal” (con el directorio correspondiente a la última actualización)
No. Local Variable Type Subtype

1 lExportPath Character 100

1 ; confecciona una lista con los últimos archivos actualizados
2 Calculate lExportPath as con(sys(115),'UltimoUpdate.txt')
3 Test if file exists {[lExportPath]}
4 If flag false
5 Do method Guardaropa ;; guarda la lista de archivos FTP en un documento
local denominado UltimoUpdate.txt
6 End If
7 Do iDirLocal.$define(iDirArchi)
8 Set import file name {[lExportPath]}
9 Prepare for import from file {Delimited (commas)}
10 Import data iDirLocal
11 End import
12 Close import file
El procedimiento “Guardarropa”, tiene como único objetivo actualizar el archivo local “UltimoUpdate.txt”, que como ya sabe el lector, contiene las entradas del directorio FTP, correspondientes a la última actualización.

No. Local Variable Type Subtype

1 lExportPath Character 100

1 Calculate lExportPath as con(sys(115),'UltimoUpdate.txt')
2 Set print or export file name {[lExportPath]}
3 Prepare for export to file {Delimited (commas)}
4 Export data iDirFTP
5 End export
6 Close print or export file
El procedimiento “Compara”, halla las diferencias entra las listas “iDirFTP” e “iDisLocal”, el resultado final es que únicamente quedan seleccionadas las entradas del directorio FTP, que deberán ser actualizadas (“iDirFTP”)

No. Local Variable Type Subtype

1 lComapara Character 100

1 Set current list iDirLocal
2 For each line in list from 1 to #LN step 1
3 Load from list
4 Calculate lComapara as iDirArchi
5 Do iDirFTP.$search(iDirArchi=lComapara,kTrue,kFalse,kTrue,kFalse)
6 End For
7 Set current list iDirFTP
8 Invert selection for line(s) (All lines)
A continuación describimos el procedimiento “SolicitaCopia”, cuya única misión es solicitar al usuario el lugar de destino para albergar la nueva biblioteca actualizada.

1 Calculate iActualizado as kFalse
2 For each line in list (Selected lines only) from 1 to #LN step 1
3 Load from list
4 Calculate iArchivo as right(iDirArchi,len(iDirArchi)-pos(':',iDirArchi)-3)
5 Yes/No message ¡Nueva versión! (Icon,Sound bell) {Existe una nueva versión
de [iArchivo][kCr]¿Desea instalarla ahora?}
6 If flag true
7 Do method CopiaFTP
8 End If
9 End For
Finalmente tan sólo nos queda describir el último de los procedimientos “CopiaFTP”, que es donde finalmente se copiaran los archivos o biblioteca a actualizar desde el servidor FTP al ordenador del usuario. La variable “iActualizado”, nos permitirá saber si todo el proceso termino con éxito.

Note que sólo si todo el proceso termina con éxito se actualizará el archivo “UltimoUpdate.txt”, de este modo se podría volver a intentar la actualización tantas veces como se requiera.


No. Local Variable Type Subtype

1 lError Short integer (0 to 255)
2 lPath Character 500

1 Do FileOps.$selectdirectory(lPath,con('Elija destino para ',iArchivo)) Returns
lError
2 If lError=1
3 FTPType (iFTPSocket,1) Returns iServerError
4 If not(iServerError)
5 Calculate lPath as con(lPath,':',iArchivo)
6 Working message Descargando.../-1073735809,-1073735805;50;0;60 {Copiando
librería [iArchivo]...}
7 FTPGet (iFTPSocket,iArchivo,lPath) Returns iServerError
8 If iServerError
9 OK message Error FTP {[con("Error al copiar el archivo
",upp(iArchivo),kCr,"Código de error : ",iServerError)]}
10 Calculate iActualizado as kFalse
11 Else
12 Calculate iActualizado as kTrue
13 End If
14 Else
15 Calculate iActualizado as kFalse
16 End If
17 Else
18 Calculate iActualizado as kFalse
19 End If
Bueno… esto ha sido todo, se trata de la primera entrega de las muchas cosas que deseo compartir con todos los desarrolladores de Omnis Studio.

Cuento con vuestro ánimo para seguir poniendo mis experiencias, en este blog.

Migrando de Omnis 7 a Omnis Studio

Desde la aparición 1997 de Omnis Studio, Raining Data ha esperado que los desarrolladores dejaran Omnis 7 y adaptaran sus aplicaciones al nuevo Omnis Studio, pero realmente se trataba de una labor ardua, puesto que representaba todo un cambio en la filosofía de programación (Programación OO).
Seguramente debido en parte a esto y en otra al desembolso económico necesario, muchos desarrolladores continuaron manteniendo sus aplicaciones en Omnis 7, alentados también por el compromiso de Raining Data a dar continuidad a dicho producto.
Pero con la llegada de los Mac Intel, Raining Data anuncia que no seguirá dando soporte a Omnis 7 para la nueva plataforma Mac, es decir que no hay actualización para Mac OS X, ni la habrá.
¿Qué haremos ahora con nuestras actuales aplicaciones en Omnis 7, bajo plataforma Mac?
Posibilidades:
1) Cambiar de plataforma, es decir pasar de Mac OS X a Windows
2) Convertir la aplicación a Omnis Studio
La primera opción puede que le atraiga a usted si es desarrollador, pero no creo que resulte muy popular entre los usuarios de ordenadores Macintosh, entre los cuales me incluyo.
La segunda opción parece la más razonable y cómoda para el usuario, pues aunque suponga un esfuerzo adicional por parte del desarrollador, el resultado final será de mayor agrado al usuario, además Omnis Studio proporciona mayor funcionalidad y flexibilidad, ahorrando en tiempo de desarrollo y costes, además de ser la herramienta idónea, para entrar en el llamado “e-business”, Internet e Intranets.
¿Cómo migraremos nuestra antigua aplicación Omnis 7 a Omnis Studio?
Raining Data asegura que usted puede realizar esta tarea con no mucho esfuerzo de su parte (ver http://www.omnis.net/products/omnis7/conversion.html) pero mi experiencia es que se trata de una ingente y eso sólo para que funcione. Si lo que queremos es que además aproveche toda la funcionalidad de Omnis Studio, la tarea puede llevar hasta semanas de arduo trabajo.
¿Qué otra opción tengo?
Por supuesto usted puede solicitar ayuda externa, migrar de Omnis 7 a Omnis Studio bajo plataforma Mac OS X o Windows, incluso migrar de Mac OS X a Windows o de Windows a Mac OS X, puede ser mucho más sencillo para usted.
Pídame presupuesto sin compromiso alguno, usted sólo tendrá que enviarme su librería Omnis 7 y tendrá a vuelta de correo una nueva librería Omnis Studio completamente funcional y adaptada a las nuevas funcionalidades y filosofía de trabajo en Omnis Studio.
Póngase en contacto conmigo para más información.

4 de enero de 2011

¿Cómo crear, mantener y visualizar un archivo "log"?

Casi todas las aplicaciones cuentan con un archivo "log", donde guardar las incidencias que se vayan produciendo durante su ejecución, normalmente se trata de un archivo de texto "txt" con varias columnas tabuladas.

A continuación se muestra como crear, mantener y visualizar un archivo "log" para nuestra librería Omnis Studio, se describen un total de tres procedimientos:

1) Crear archivo 2) Añadir entradas 3) Visualizar contenido.

1) Método para crear el archivo, (toma su nombre del que ya tiene la librería)

Calculate ArchivoLog as con(mid(sys(10),1,len(sys(10))-3),'log')
Do FileOps.$doesfileexist(ArchivoLog) Returns ExisteLog
If not(ExisteLog)
Do FileOps.$createFile(ArchivoLog)
End If
2) Método para añadir entradas al archivo (Denominado: $grabalog)

Variable de parámetro

"PTextoLog" de tipo Carácter (Contiene el texto a grabar en el archivo de log)

; Inserta una línea en el archivo de log, con el texto contenido en "PTextoLog"Calculate lPathname as con(mid(sys(10),1,len(sys(10))-3),'log')Do FileLog.$openfile(lPathname)Do FileLog.$getfilesize() Returns FileEndDo FileLog.$writefile(con(#D,' ',tim(#T,'H:N:S'),chr(9),PTextoLog,chr(9), iUserName,chr(13)),FileEnd)Do FileLog.$closefile()

Ejemplo de llamada al método "$grabalog"

Do method $grabalog (con('Sesión iniciada con éxito en ',iSessionName))
Esto añadiría una nueva entrada (el texto se pasa en el parámetro "PTextoLog")

3) El siguiente procedimiento transfiere el contenido del archivo de log a una lista.

Set current list lListaLogDefine list {IFechaLog,ITextoLog,IUsuarioLog}Calculate lPathname as con(mid(sys(10),1,len(sys(10))-3),'log')Set import file name {[lPathname]}Prepare for import from file {Delimited (tabs)}Import data lListaLogEnd importClose import file
Y esto es todo, sencillo pero eficaz, sigo animando a todos los lectores de este blog a que dejéis vuestros animadores comentarios, eso permitirá que continúe añadiendo mis experiencias al mismo.

Ya sabéis que también podéis contactar conmigo a través de Skipe e incluso (si así lo deseáis) podríais colaborar con la publicación de vuestras propias experiencias, sería estupendo que este blog se convirtiera en un punto de encuentro para todos los que “nos pegamos” con el desarrollo de aplicaciones en Omnis Studio.