jueves, octubre 29, 2015
Conocer que aplicación, puerto que utiliza y como terminar el proceso en Windows
Como saber que puertos estan ocupados y que programa los utiliza en windows.
De esas veces que necesitas saber si un puerto esta abierto y no
estas en linux, sino en windows.. no tienes herramientas gráficas y solo
puedes acceder a la consola y sus comandos..
Lo primero es utilizar netstat y unos cuantos parámetros desde la
consola en windows (-o muestra el PID, -a todas las conexiones y -n
direcciones ip)
c:\netstat -oan
Luego que ya sabemos si o no está en uso.. ahí mismo con el parámetro
-o podemos tener acceso al no. de proceso o PID .. ya con ese dato
podemos abrir el administrador de tareas, eso bastaría para saber su
nombre y matarlo si es lo que necesitan.. pero si es un proceso global y
no aparece en el administrador de tareas, no hay de otra más que seguir
utilizando la consola para averiguar de donde diablos salío la
aplicación que utiliza el puerto que necesitan.
Bueno, lo siguiente entonces es saber el nombre de la aplicación
dueña del proceso y para esto utilizamos el comando tasklist con otro
par de parámetros (-svc para obtener el nombre del servicio, -FI para
aplicar un filtro de búsqueda)
En este caso de ejemplo quiero conocer el nombre de la aplicación con
PID 15820 que fue lo que encontré utilizando netstat .. y el resultado
de la ejecución de tasklist es el nombre de la aplicación.
Ya para finalizar vamos a utilizar el comando taskkill enviando como
parámetros -F para forzar el cierre de la aplicacion y -PID para
especificar el número de proceso a matar.
c:\taskkill /F /PID 15820
Perfecto desde hoy no tendremos que reiniciar la PC para liberar los puerto y las aplicaciones que lo utilizan.
Tomado de: Articulo Original
domingo, octubre 25, 2015
Desplegar campos BLOB en un Webpanel y Reporte PDF desde una cadena CODE64 resultado de un Servicio REST.
Un de las situaciones mas interesantes cuando se tiene un balanceador de carga de aplicaciones web basadas en java, es tener la posibilidad de transferir el archivo de imagenes en una cadena de datos CODE64, lo que facilita el proceso de trasnferenciad e informacion entre diferentes usuarios de las aplicaciones, adicional permite que se invoque un servicio web RESP/SOAP para que genera dicha imagen y luego pueda ser desplegada en la aplicacion muy agilmente, aqui citamos un ejemplo.
&MiBlob es de tipo BLOB.
&Imagen es de tipo Image
&MiBlob.FromBase64String(&CadenaCode64)
&Imagen.FromURL(&MiBlob)
Se desplega la variable &Imagen en un webpanel o en reporte PDF.
Como resultado de un servicio web se obtiene lo siguiente:
&Url = "graficar"
&HttpClient.Host = 'localhost'
&HttpClient.Port = 8080
&HttpClient.BaseUrl = '/graficador/rest/'
&HttpClient.AddVariable('DATOSAGRAFICAR', &XmlConDatos)
&HttpClient.Execute("POST", &Url)
&StatusCode = &HttpClient.StatusCode
&Resultado = &HttpClient.ToString()
&MiBlob.FromBase64String(&Resultado)
&Imagen.FromURL(&MiBlob)
Articulo de Referencia:Articulo de Refrencia
A partir de la version X existen métodos de Blob para hacer el To y FromBase64. en la versión 90 no existen pero se pueden programar con un prograna externo. | ||
Descripción Detallada | ||
El código nativo seria (**) y se invocaría de la siguiente forma en el código GX. En .NET ser invoca así: csharp [!&tst!] = context.FileToBase64( "prompt.gif"); csharp [!&txt1!] = context.FileFromBase64( [!&tst!], "gif" ); msg( &txt1, nowait) En Java se invoca así (para usarlo en java hay que usar una gxlcassr actualizada, solicitarla a soporte): java [!&txt!] = GXutil.blobToBase64( "prompt.gif"); java [!&txt1!] = GXutil.blobFromBase64( [!&txt!], "gif" ); msg( &txt1, nowait) (**) using System; using System.IO; public class Base64Utils { static public string ToBase64(string fileName) { try { FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fs); byte[] bContent = br.ReadBytes((int)fs.Length); br.Close(); fs.Close(); return Convert.ToBase64String(bContent); } catch { return ""; } } static public void FromBase64( string fileName, string b64) { byte[] bContent = Convert.FromBase64String(b64); try { FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter( fs); bw.Write(bContent, 0, bContent.Length); bw.Close(); fs.Close(); } catch { } } } Tambien se puede invocar directamente a la funcionalidad del framework, en cualquier version, algo como: csharp byte[] array = System.Text.Encoding.ASCII.GetBytes([!&var!]); csharp [!&base64cred!] = System.Convert.ToBase64String(array); | ||
Buenas Prácticas de programación en GeneXus
Considerar estas buenas practicas cuando se enfrenta un desarollo con la herramienta Genexus
Tomado de: Buenas Prácticas de programación en GeneXus
Las Buenas prácticas de programación en GeneXus sirven para mejorar
la comprensión y claridad del código, aparte de permitir unificar
criterios entre los distintos programadores de la comunidad.
Las Buenas prácticas de programación en GeneXus parten de la base que el
código es la mejor documentación que puede tener un sistema, por esto
también es la mejor herramienta que tiene un programador de comunicar su
trabajo con el resto de los programadores.
Al utilizar las Buenas prácticas de programación en GeneXus el código de la KB obtiene un valor agregado ya que adquiere:
- Fácil integración y reutilización
- Fácil comprensión por parte del programador
- Unificación de criterios
- Eliminación de zonas oscuras de código
- Fácil comunicación entre programadores
- Claridad y correctitud en el código
- Incremento significable en la mantención del Software
(Ver tambien Design Tips por recomendaciones de design).
Las Buenas prácticas de programación en GeneXus están compuestas por reglas y recomendaciones.
Reglas
- Al nombrar atributos se debe utilizar la nomenclatura GIK
- Los atributos deben tener descripción y Help
Nombre: CliCod
Descripción: Código de Cliente
Help: Identificador del Cliente en el Sistema
- Las Tablas deben tener nombres que representen la realidad y no el nombre heredado por la transacción que las crea.
Trn: Cli2SisPro Tabla: Clientes
- Las variables que hagan referencia a un atributo deben ser basadas en el mismo y tener el mismo nombre del Atributo, si la lógica lo permite.
Atributo: CliCod - C(20) - Código de Cliente
Variable: &CliCod - C(20) - Código de Cliente
- Las variables que hagan referencia a un atributo deben ser basadas en el mismo y tener el mismo nombre del Atributo, agregando uno más sufijos para calificarla en el caso que sea necesario (Agregado AdeL 05jul08).
Atributo: CliCod - C(20) - Código de Cliente
Variable: &CliCodOri - C(20) - Código de Cliente de Origen <----- Correcto
Variable: &CliCodDst - C(20) - Código de Cliente de Destino <----- Correcto
Variable: &CliDstCod - C(20) - Código de Cliente de Destino <----- Incorrecto
Variable: &CliCodOri - C(20) - Código de Cliente de Origen <----- Correcto
Variable: &CliCodDst - C(20) - Código de Cliente de Destino <----- Correcto
Variable: &CliDstCod - C(20) - Código de Cliente de Destino <----- Incorrecto
- Definición de Subtipos
Se recomienda que al definir subtipos estos pertenezcan a un grupo especifico y no sean definidos en el grupo "None"
Cada grupos de subtipos debería tomar el nombre del Atributo Subtipo que identifica al Grupo (primario), o una concatenación de nombres si hay varios primarios, como en el siguiente ejemplo (Agregado AdeL 05jul08)
Nombre del Grupo: BancoCodOrigen
Subtipos Supertipo
BancoCodOrigen BancoCod
BancoNombreOrigen BancoNombre
- Reporte de Especificación
- Definición de Reglas
Ej:
Parm(in:EmpCod, in:&Usuario, in:&CliCod, in:&Mode);
noaccept(CiuCod);
&CliSaldoAux = udp(PcalcSaldo, EmpCod, &CliCod, CliSaldo);
error('Mensaje') If Null(&Usuario);
allownulls(EmpCod, LocCod ) ;
Call(PActInfo, EmpCod, CliCod) if <cond>;
error('Mensaje') IF CliDir = nullvalue(CliDir ) and after(CliDir) ;
prompt(Wclientes, EmpCod, CliCod);
default(CliFchCrea, Now() ) ;
noaccept(EmpCod);
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
nocheck(EmpCod, LocCod);
msg('Saldo menor que cero') if CliSaldo < 0;
Refcall(Wclientes, EmpCod, CliCod);
Call(Pprocedure, EmpCod, CliCod) if <cond>;
default(CliArea, 'A' ) ;
Si observamos este código nos damos cuenta que para buscar algo tenemos que recorrer hasta el final ya que no muestra ningún criterio a seguir. Existen muchas maneras de definir las rules para que sean fáciles de entender, pero vamos a tomar dos criterios que serán vistos como buenas prácticas.
Criterio Nro. 1
Definir las rules agrupadas por atributo:
De está manera podemos seguir el comportamiento que se programo para un atributo o variable en particular.
Ej: Parm(in:EmpCod, in:&Usuario, in:&CliCod, in:&Mode);
error('Mensaje') If Null(&Usuario);
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
allownulls(EmpCod, LocCod );
nocheck(EmpCod, LocCod);
Call(PActInfo, EmpCod, CliCod) if <cond>;
Call(Pprocedure, EmpCod, CliCod) if <cond>;
prompt(Wclientes, EmpCod, CliCod);
Refcall(Wclientes, EmpCod, CliCod);
error('Mensaje') IF CliDir = nullvalue(CliDir ) and after(CliDir); default(CliFchCrea, Now() );
default(CliArea, 'A' );
noaccept(EmpCod);
noaccept(CiuCod);
msg('Saldo menor que cero') if CliSaldo < 0;
&CliSaldoAux = udp(PcalcSaldo, EmpCod, &CliCod, CliSaldo);
Criterio Nro. 2 (Recomendado)
Agrupar las Rules por comportamiento
De está manera podemos ir directamente al sector del código en donde detectamos que está el error o para agregar comportamiento.
Ej:
Parm(in:EmpCod, in:&Usuario, in:&CliCod, in:&Mode);
noaccept(EmpCod);
noaccept(CiuCod);
allownulls(EmpCod, LocCod ) ;
nocheck(EmpCod, LocCod);
default(CliFchCrea, Now() ) ;
default(CliArea, 'A' ) ;
error('Mensaje') If Null(&Usuario);
error('Mensaje') IF CliDir = nullvalue(CliDir ) and after(CliDir) ;
msg('Saldo menor que cero') if CliSaldo < 0;
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
Call(PActInfo, EmpCod, CliCod) if <cond>;
Call(Pprocedure, EmpCod, CliCod) if <cond>;
&CliSaldoAux = udp(PcalcSaldo, EmpCod, &CliCod, CliSaldo);
prompt(Wclientes, EmpCod, CliCod);
Refcall(Wclientes, EmpCod, CliCod);
/* Comentario: Andrés CuñarroPara el caso de agrupar las reglas por comportamiento resulta práctico indicar el cometido ya que algunas veces se deben utilizar rules distintas para cumplir un cometido.
Si se incluyen éstas (u otras) secciones en un style, se define un criterio standard para una Kb.*/
Por ejemplo:
parm( parm1, parm2, ...);
//INSTANCIAR REGISTRO (PARAMETRO)
//VALORES POR DEFECTO
default(CliFchCrea, Now() ) ;
//INTERFASE
noaccept(EmpCod);
//DEPENDENCIAS FUNCIONALES
CliEdad = Age(CliFchNac);
//INTEGRIDAD REFERENCIAL
allownulls(EmpCod, LocCod ) ;
nocheck(EmpCod, LocCod);
//VALIDACION DE CAMPO
error("Nombre de cliente incorrecto.") if null(CliNom);
//VALIDACION DE REGISTRO
error("La fecha de vencimiento no puede ser menor a la del documento.") if DocFchVenc < DocFch;
//PROMPTS
prompt(WClientes, CliCod);
//ACCIONES
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
Recomendaciones
La descripción de los objetos de la KB debe ser clara independientemente del nombre del mismo.
Nombre: ModCliDeuda
Descripción: Modificación de Cliente con Deuda
Se debe tener un método para dar nombre a los objetos. Esto depende mucho del tamaño de la(s) KB(s), tipo de instalación, criterios heredados y otra cantidad de factores, pero algunas cosas a tener en cuenta serían (Agregado por AdeL 05jul08).
Al principio del objeto, un par de letras que identificara la aplicación (p.e. 'PE' para una aplicación de Personal, 'CO' para una aplicación de Compras). Esto podría ser opcional, dependiendo del ambiente.
Un identificador de la Entidad sobre la cual trabaja el objeto (p.e. Clientes, Facturas, Impuestos), la cual también podría ser nemotécnica (p.e. Cli, Fact, Imp)
Uno o más verbos, combinados con palabras o abreviaturas que identiquen someramente qué hace el objeto (Calcular, Borrar, Modificar, Crear).
La descripción de los objetos debe contener primero el objeto y después la acción que se ejecuta.
Nombre Descripción
CliDeudaModificar Cliente con Deuda - Modificar
FactIngresar Factura - Ingresar
COOrdenCompraImpCalcular Orden de Compra - Impuestos - Calcular (este sería un objeto de la KB de Compras, p.e. en un ambiente de desarrollo distribuido)
VEClientesTrabCon Clientes - Trabajar con (este sería un objeto de la KB de Ventas, p.e. en un ambiente de desarrollo distribuido)
Utilizar nombres nemotécnicos para las variables que no correspondan a ningún atributo del sistema.
Se quiere cargar en una variable la existencia de un cliente.
Forma correcta: ExisteCliente
Forma Incorrecta: Flag
Utilizar nombres nemotécnicos para los objetos de la KB
TrabajarConClientes
En el encabezado de los programas se debe hacer un cuadro con una pequeña descripción del propósito del mismo y datos útiles.
/*
Autor: Cristhián Gómez (urulinux@adinet.com.uy)
Fecha de Creación: 26-06-2004
Ultima modificación: 27-06-2004
Versión: 1.2
Descripción: Cambia el estado de los movimientos luego de la autorización del Usuario
*/
Colocar una línea en blanco entre las definiciones de eventos o subrutinas para separar los mismos y hacer más comprensibles los programas.
Dentro de los eventos se debe comenzar a escribir código luego de hacer un tab., esto facilita la visualización del código
// Forma incorrecta:
Event 'NuevoCli'
If &CliCod = &Cliente
//Codigo
Endif
EndEvent
// Forma Correcta:
Event 'NuevoCli'
If &CliCod = &Cliente
//Codigo
Endif
EndEvent
Para que los ForEach queden más claros y fáciles de identificar dentro de los eventos o del código en general, se recomienda que se escriban de la siguiente manera:
// Forma Incorrecta:
Event 'NuevoCli'
For Each
where CliCod = &CliCod
//Còdigo
EndFor
EndEvent
// Forma correcta:
Event 'NuevoCli'
For Each
where CliCod = &CliCod
//Còdigo
EndFor
EndEvent
Para que los filtros de los ForEach queden más claros se recomienda tener un where para cada condición y no utilizar AND.
//Forma incorrecta:
For Each
where CliCod = &CliCod and CliStatus = &CliStatus and CliTipo = &CliTipo
//Còdigo
EndFor
// Forma correcta:
For Each
where CliCod = &CliCod
where CliStatus = &CliStatus
where CliTipo = &CliTipo
//Código
EndFor
/* Comentario de Gabriel Icasuriaga
Otra opcion es definir toda la declaracion del for each sin indentar y recien indentar cuando comienza el codigo
aparte de eso, prefiero poner todos los atributos aunque esto sea redundante, asi de esta forma, cuando otra persona ve el codigo
la comprension es mas rapida. Tambien me gusta como quedan los "=" a la misma altura.
For Each Clicod, CliStatus
Where CliCod = &CliCod
Where CliStatus = &CliStatus
Where CliTipo = &CliTipo
//Codigo
EndFor
/* Comentario de Nicolas Jodal: me gusta mas la version original */
/* Comentario de: Jorge Ronald Cribb - Vikam Corporation
Sugiero esta otra forma:
Las palabras reservadas de GENEXUS con MAYUSCULAS
Indentación de 4 caracteres para las opciones del FOR EACH.
Los conectores AND e OR indentados dentro de la opción WHERE.
FOR EACH Clicod, CliStatus
WHERE CliCod = &CliCod
AND CliStatus = &CliStatus
AND CliTipo = &CliTipo
//Codigo
ENDFOR
/* Comentario de Edson Geovane - Vikam Corporation
Eu só acrescentaria o uso da clausula 'defined by' após as sentenças WHERE. Acho importante porque define a tabela que será lida e ajuda ao programador identificar rapidamente esta tabela. Vamos incentivar os programadores ler os programas e entender como se fosse um idioma.
/* Comentario de: Jorge Ronald Cribb - Vikam Corporation
Para mejorar la compresión del programa sin embargo yo preferiría que el ESPECIFICADOR de Genexus escribiese al lado de cada FOR EACH (como comentario) la relación de TABLAS que está usando ese FOR EACH con toda la secuencia de JOINS e OPCIONES DE ORDER que será efectuada.
Ejemplo:
FOR EACH Clicod, CliStatus // GX: CLIENTES
WHERE CliCod = &CliCod
AND CliStatus = &CliStatus
AND CliTipo = &CliTipo
//Codigo
ENDFOR
Nota: En este caso el comentario que dice "// GX: CLIENTES" seria colocado automaticamente por Genexus después de la especificación del objeto.
Aclarando un poco mas todavía: La información que sería colocada por Genexus en el fuente sería del mismo tipo que coloca en el informe/listado de navegación del objeto (pero un poco mas resumida).
/* Comentario de Demetrio Toledo.
Generalmente acostumbro identificar siempre a la tabla base donde voy a trabajar con el For Each utilizando la Sentencia Defined By, de la siguiente manera.
FOR EACH Clicod, CliStatus // GX: CLIENTES
Where CliCod = &CliCod
Where CliStatus = &CliStatus
Where CliTipo = &CliTipo
Defined By CliEstReg
//Codigo
ENDFOR
De esta manera se identifica correctamente la tabla base.
Lo cual definitivamente da la posibilidad de que cada tabla tenga por definicion un atributo que contemple la situacion del registro, en una especie de auditoria, en este caso el CliEstReg, no indicara la situacion del registro 2=MODIFICADO 4=ELIMINADO O 1=CREADO...
/* Comentario de Adilson Costa.
Aproveitando o comentário anterior onde é identificada a tabela base, além de informar o nome da tabela, identifico também a sua descrição.
Utilizo também a mesma informação no fechamento do For Each para facilitar quando estamos utilizando For Each aninhados.
For Each Order Clicod, CliStatus // Clientes -> Tabela de Clientes
Where CliCod = &CliCod
Where CliStatus = &CliStatus
Where CliTipo = &CliTipo
//Codigo
EndFor // Clientes -> Tabela de Clientes
/* Comentário de Fabiano Gorziza
Me parece que a boa prática aqui é, independente da forma escolhida, definir um padrão para toda a empresa.
/* Comentario de Andrés Rodríguez
Mi forma es parecida a estas últimas pero mientras genexus no describa automáticamente la tabla que se recorre, yo lo escribo manualmente para ayudar a otros que entiendan el código y para que, en el futuro al colocar cosas dentro del for each sea posible verificar que siga recorriendo lo mismo que antes. Estoy de acuerdo en poner los = a la misma altura y a indentar los where. En lo personal coloco un espacio en blanco luego de los where o defined by.
For Each Order Clicod, CliStatus // TBL: CLIENTES
Where CliCod = &CliCod
Where CliStatus = &CliStatus
Where CliTipo = &CliTipo
//Codigo
EndFor // TBL: CLIENTES
Colocar un espacio después de cada coma(,) en las rules, call, udp,etc. para hacer los programas más fáciles de entender.
// Forma incorrecta:
parm(&CliCod,&UsuCod,&Tipo);
call(MiObjeto,CliCod,UsuCod,&Tipo)
// Forma correcta:
parm(&CliCod, &UsuCod, &Tipo);
call(MiObjeto, CliCod, UsuCod, &Tipo)
Evitar abreviar excesivamente
Los nombres de las variables, subrutinas, objetos, etc deben de ser lo más claro posibles ya que si alguien externo debe trabajar con el código deberá, además de entender el código en general, deberá estar descifrando los nombres de cada variable, etc. Ej: Se quiere cargar en una variable el cliente por proveedor
//Forma Incorrecta:
&CPProv
//Forma correcta:
&ClientePorProveedor
Claridad en el código
La claridad en el código también se considera una buena práctica de programación, en muchos casos por costumbre los programadores abusan del uso del "if" olvidando que existe el comando "Do Case". En muchas ocasiones esto se debe a que las primeras versiones de GeneXus no soportaban este comando y la costumbre es más fuerte que el cambio.
Los atributos deben estar basados en Domains
Hay que tratar que todos los atributos estén siempre basados en algún Domain, de esta manera es más fácil adaptarse a los cambios de tipos o largos.
Utilización de Patterns
Se recomienda que toda aplicación web utilice Patterns, los patterns de GeneXus nos ofrecen una herramienta ideal para crear aplicaciones web. Facilitan la migración de ambiente win a web y nos ofrecen una forma práctica de solucionar problemas que antes nos llevaban mucho tiempo. Por más información leer Patterns.
Evitar constante en el codigo
Usar los enumerators en vez de constantes en el codigo. De esa manera si se cambia la constante no es necesario cambiar en todos los lados que se usa.
&Type = "CR" // BAD
&Type = BalanceType.Credit // GOOD
Mantenimiento de Kb´s
La naturaleza de la mayoría de los proyectos nos lleva a que estemos haciendo cambios constantemente en el conocimiento inicial que tenemos almacenado en una KB. Los cambios en los requerimientos de los clientes disparan un montón de acciones que en ocasiones hace que modifiquemos gran parte de nuestra lógica de negocio.
Esto lleva a que existan KB´s que tienen muchos objetos, atributos y tablas que no se utilizan o que se dejaron de utilizar por algún cambio o refactoring en el código. Esto hace que en la KB exista conocimiento duplicado o innecesario y a medida que una KB crece también crecen los tiempos de producción.
Existen tareas que se hacen a menudo que sin darnos cuenta podemos optimizar haciendo un mantenimiento del conocimiento existente en una KB. Haciendo un buen mantenimiento podemos bajar los tiempos de:
Build All
Copy Model
Update Model
Generate Help
Publicación de Información con GXPublic
Respaldos
Seria bueno si en ocasiones nos tomamos un tiempo para borrar todos los objetos, atributos, dominios, subtipos y tablas que no utilicemos. Esto mejorara los tiempos de producción y ayudara a que mi KB tenga el conocimiento que necesita para responder a mis necesidades.
Una de las cosas que hace que una KB crezca es tener modelos sin utilizar, en muchos casos no queda más remedio que tener varios
modelos de prototipo y producción. Como recomendación seria bueno eliminar todos los modelos que no se utilicen en una KB.
Encapsular código mediante el uso de Atributos Fórmula
Un aspecto muy relevante a la hora de mantener el software es tener centralizado la definición de los distintos cálculos que se realizan sobre los datos. Para ello lo recomendado es tener incorporado estos cálculos como Atributos Fórmula. De esta manera nos aseguramos que cuando cambia el cálculo que se requiere realizar para obtener una determinada información, se cambia el atributo fórmula y esto tiene incidiencia sobre TODO el sistema.
Por último una nomenclatura Propuesta para los casos en que la definición de un Att fórmula esté basada en un procedimiento Ej: CliSdoRes = udp(P...) el Nombre del Procedimiento debe ser igual al nombre del Atributo. Para el Ejemplo anterior quedaría CliSdoRes = udp(PCliSdoRes,...), otra opción es anteponer en el nombre del procedimiento la partícula "Frm", en el ejemplo citado quedaría CliSdoRes = udp(PFrmCliSdoRes,...)
Sobre base64. Para que usarlo, para que no, y como manejarlo
Articulo Original
¿Que es base64?
Base64 no es en principio otra cosa mas que un sistema numérico, el
cual debido a sus características se emplea en muchos ámbitos de la
informática para representar información binaria.
Todos los sistemas de numeración tienen una lista de símbolos que utilizan para representar valores, por ejemplo:
Binario: ’01’
Decimal: ‘0123456789’
Hexadecimal: ‘0123456789ABCDEF’
y para base64 el conjunto es:
‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/’
Como vemos, es un subconjunto de ASCII, y tiene como particularidad que todos sus caracteres son imprimibles, de hecho 64 es la mayor potencia de 2 que permite ser representada por un subconjunto de caracteres ASCII imprimibles, por eso, si pasamos cualquier información a su representación de base64, tenemos la seguridad de que no tendremos problemas al transmitirla, almacenarla o leerla, incluso aunque esta contega los más remotos caracteres unicode, una imagen o un mp3, ya que para convertir algo a base64 trataremos directamente con los bits.
¿Como codificamos en base64?
Veamos (en este ejemplo flagrantemente robado de Wikipedia) como se codifica la palabra “Man”.
Texto de entrada | M | a | n | |||||||||||||||||||||
ASCII | 77 | 97 | 110 | |||||||||||||||||||||
Bits | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
Índice | 19 | 22 | 5 | 46 | ||||||||||||||||||||
Resultado en Base64 | T | W | F | u |
Tenemos que la M es en ASCII el caracter 77 (01001101 en binario), y
como el primer paso para nuestra tarea es convertir la información de
origen en bits (más sobre esto en un momento), transformamos toda la
cadena en una secuencia de unos y ceros, los cuales tomamos en grupos de
a seis.
El primero de estos grupos (010011) representa 19, y si tomamos la
posición 19 en la lista de símbolos de base64 (empezando a contar desde
cero, claro) obtenemos la T, y continuando con este algoritmo llegamos
al resultado “TWFu”.
Caracteres de Relleno
base64 se codifica tomando los bytes de tres como entrada en cuatro
sextetos, o sea de a 24 bits. Cuando esta cantidad no coincide,
completamos con el caracter de relleno “=” los sextetos restantes.
Por ejemplo, si hubiéramos codificado solamente el texto “Ma”,
veríamos que no coincide la cantidad de octetos con la de sextetos,
luego de “TW” me quedaría 0001, por lo que completo con ocho ceros y
obtengo “TWE”. El sexteto vacío que queda se completa con el caraceter
“=” quedando como resultado: “TWE=”
Hasta aquí como se codifica. De la misma manera, podría codificar un
archivo ejecutable, una imagen, archivos de sonido o simplemente como en
este caso, Texto Plano.
Ooops, acabo de decir “texto plano”, pero como bien dice Joel Spolsky (parafraseando a famoso economista que parafraseaba a conocido escritor de ciencia ficción): “No existe tal cosa como el texto plano”. Y acá es donde entra a fastidiarnos la palabra “Encoding”.
Encoding
La representación lógica de una cadena de texto, como puede serlo un
String de .net, se puede convertir a bits de muchas maneras. No es lo
mismo la representación binaria de texto en ASCII que en Unicode, al
respecto recomiendo encarecidamente leer el citado post de Joel Spolsky,
pero lo que quiero destacar ahora a los efectos prácticos de comprender
el código es que, cuando trabamos con texto, este es para nosotros la
representación lógica de la información, la cual se perderá al
momento de trabajar directramente con los bits, y como la conversión de
esta información lógica a bits puede realizarse de muchas maneras
distintas, debemos tener control de este paso al momento de codificar y
decodificar texto en y desde base64.
Una referencia de como se lo hace en Genexus X en adelante:
Una referencia de como se lo hace en Genexus X en adelante:
Iconos gratuitos
En fase de diseño de una aplicacion siempre es importante considerar el utilizar ICONOS DE USO LIBRE, a continuacion se detalla dos sitios donde podemos encontrar un buen numero de iconos para este proposito:
sábado, octubre 24, 2015
Ejecutar una KB de genexus generado en java pasarlo a Eclipse.
|
|
|
Muchas de las es necesario conocer el comportamiento de ciertas funciones y objetos que genera el Genexus, justamente para evidenciar su comportamiento correcto o no, en virtud de ello se ve la necesidad de pasarlo a un IDE como el ECLIPSE, en la siguiente URL se detallan todos los pasos a seguir para alcanzar este objetivo.
Tener en cuenta basicamente que la KB debe tener la propiedad de Modulos, luego se tiene que copiar el web.xml para que todos los servlets esten activos y poderlos ejecutar en la linea de comandos:
Como elemento adicional si requieren simplemente realizar una pueba de concepto pueden utilizar la siguiente URL donde estan subidas las KB por los compañeros del foro de Genexus.
REPOSITORIO de KB de genexus que son migradas a ECLIPSE.
Les dejo la URL donde se detalle muy minuciosamente los pasos:
Migrar un KB en java a Eclipse.
Verificar servicios web de SRI si estan o no en Linea
Con esta funcion en Java es posible revisar si los servicios web del SRI estan activos o no:
Es posible que a futuro se modifique las URL de los servicios web, en ese caso se tendria que actualizar.
package com.sri.;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.bind.DatatypeConverter;
public class RevisarSwSri
{
public RevisarSwSri()
{
}
public static void main(String[] args)
{
String url0 = "https://celcer.sri.gob.ec/comprobantes-electronicos-ws/RecepcionComprobantes?wsdl";
String url1 = "https://celcer.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantes?wsdl";
String url2 = "https://cel.sri.gob.ec/comprobantes-electronicos-ws/RecepcionComprobantes?wsdl";
String url3 = "https://cel.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantes?wsdl";
try {
VerificarUrl(url0, 0);
VerificarUrl(url1, 1);
VerificarUrl(url2, 0);
VerificarUrl(url3, 1);
}
catch (Exception ex)
{
}
}
public static boolean VerificarUrl(String url, int recEnv)
{
String claveAcceso = "";
String cadenaBytes = "";
String xmlEnviar = "";
String xmlRecibir = "";
String xml = "";
boolean retorno = false;
try {
cadenaBytes = DatatypeConverter.printBase64Binary(cadenaBytes.getBytes("UTF-8"));
xmlEnviar = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ec='http://ec.gob.sri.ws.recepcion'>"+
"<soapenv:Header/>"+
"<soapenv:Body>"+
"<ec:validarComprobante>"+
"<xml>"+ cadenaBytes +"</xml>"+
"</ec:validarComprobante>"+
"</soapenv:Body>"+
"</soapenv:Envelope>";
xmlRecibir = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ec='http://ec.gob.sri.ws.autorizacion'>"+
"<soapenv:Header/>"+
"<soapenv:Body>"+
"<ec:autorizacionComprobante>"+
"<claveAccesoComprobante>"+ claveAcceso+"</claveAccesoComprobante>"+
"</ec:autorizacionComprobante>"+
"</soapenv:Body>"+
"</soapenv:Envelope>";
if(recEnv <= 0)
xml = xmlEnviar;
else
xml = xmlRecibir;
if(RevisarEstadoSw(url, xml))
{
System.out.println("EN LINEA URL-->" + url);
retorno = true;
}
else
{
System.out.println("FUERA DE LINEA URL-->" + url);
retorno = false;
}
}
catch (Exception ex)
{
retorno = false;
}
return retorno;
}
public static boolean RevisarEstadoSw(String url, String xml)
{
URL oURL;
boolean retorno;
try {
oURL = new URL(url);
HttpURLConnection con = null;
con = (HttpURLConnection) oURL.openConnection();
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "text/xml; charset=utf-8");
con.setRequestProperty("SOAPAction", "");
con.setRequestProperty("Host", "celcer.sri.gob.ec");
OutputStream reqStreamOut = con.getOutputStream();
reqStreamOut.write(xml.getBytes());
System.out.println("Codito HTTP--> " + String.valueOf(con.getResponseCode()) + " Mensaje--> " +con.getResponseMessage());
if(con.getResponseCode() > 200)
return false;
return true;
}
catch (MalformedURLException e)
{
retorno = false;
}
catch (Exception ex)
{
retorno = false;
}
return retorno;
}
}
Instalar mi propio servicio para acortar URLs
Resulta interesante que podamos contar con un servicio para a cortar URLs en la empresa, pero muchos de ellos esta disponibles en hosting externas, con algunas ventajas y desventajas.
He aqui algunos tutoriales que nos pueden ayudar tener una solucion propia.
SITIO DONDE PODEMOS DESCARGAR LA SOLUCION Y MAS INFORMACION
He aqui algunos tutoriales que nos pueden ayudar tener una solucion propia.
SITIO DONDE PODEMOS DESCARGAR LA SOLUCION Y MAS INFORMACION
- Acortador de URLs en Wordpress
- Un Pequeño tutorial de como instalar el Yourls - recomendado
- Otro tutorial para instalar a YoUrls
- Tutorial para instalar YOURLS
- Iinstalando un acortador de urls para wordpress paso a paso
- Video como instalar Yourls
- Tutorial de YOURLS
- Tutorial de Yourls
- Tutorial en Ingles de como instalar URLS cortas YOURLS
lunes, octubre 19, 2015
Consumo Servicios Web para FACTURACION ELECTRONICA del SRI
Gracias a Christian Carreño, me permito publicar este sitio donde existe mucha informaciòn para quienes estamos involucrados en el tema de la Facturacion eletronica a nivel de nuestro Pais Ecuador.
Por sobre todo rompiendo ese PARADIGMA DEL INDIVIDUALISMO SOMETIDO AL CONSUMISMO VORAZ Y EGOISTA, donde quienes conocen algo en base a su esfuerzo NO SON CAPACES DE COMPARTIR UNA PARTE DE AQUELLO, sino se VALEN DE ESO PARA EVIDENCIAR UN CLIMA DE EXCLUSION, no estare nunca de acuerdo con esas practicas porque el conocimiento es ETERNO EN EL TIEMPO y los SERES HUMANOS MUY CONCIENTES ESTAMOS COMPROMETIDOS EN DARLE SIEMPRE VIGENCIA reconociendo a quienes lo engrandecieron con su esfuerzo. Es notorio que vivimos una sociedad del INDIVIDUALISMO PERTINAZ A ULTRANZA no somos capaces todavia de evolucionar, pensamos que la unica forma de ENGRANDECERSE que tiene el SER HUMANO ES POSEER Y TENER, nunca SER osea el SER no es nada solo es un componente mas del humano que cada dia se parece mas a una procesadora de basura en todas las dimensiones.
INSISTO CRISTIAN gracias por creer todavia en aquello que el conocimiento es parte evolutiva del ser HUMANO...
Cito textualmento los Temas que pueden ser de mucho interes.
Por sobre todo rompiendo ese PARADIGMA DEL INDIVIDUALISMO SOMETIDO AL CONSUMISMO VORAZ Y EGOISTA, donde quienes conocen algo en base a su esfuerzo NO SON CAPACES DE COMPARTIR UNA PARTE DE AQUELLO, sino se VALEN DE ESO PARA EVIDENCIAR UN CLIMA DE EXCLUSION, no estare nunca de acuerdo con esas practicas porque el conocimiento es ETERNO EN EL TIEMPO y los SERES HUMANOS MUY CONCIENTES ESTAMOS COMPROMETIDOS EN DARLE SIEMPRE VIGENCIA reconociendo a quienes lo engrandecieron con su esfuerzo. Es notorio que vivimos una sociedad del INDIVIDUALISMO PERTINAZ A ULTRANZA no somos capaces todavia de evolucionar, pensamos que la unica forma de ENGRANDECERSE que tiene el SER HUMANO ES POSEER Y TENER, nunca SER osea el SER no es nada solo es un componente mas del humano que cada dia se parece mas a una procesadora de basura en todas las dimensiones.
INSISTO CRISTIAN gracias por creer todavia en aquello que el conocimiento es parte evolutiva del ser HUMANO...
Cito textualmento los Temas que pueden ser de mucho interes.
Artículos más populares
Últimas novedades
- Presentación Facturas en La Web usando Vaadin (Framework Java)
- Consumo de Web Services SRI - Envío de Comprobantes .net ( C# )
- Consumo de Web Services SRI - Envío y Recepción de Autorización
- Como guardar y leer archivo tipo byte en BD PostgreSQL
- Consumo de Web Services SRI - Envío de Comprobantes
Prototipos de Firmado
Adictos al trabajo un explciacion del proceso de firmado electronicamente
Formas adicionales de realizar la firma eletronica
Adictos al trabajo un explciacion del proceso de firmado electronicamente
Formas adicionales de realizar la firma eletronica
Si alguien tiene interes en utilizar dichos fuentes por favor dejeme un comentario y cuenta de correo para hacerle llegar inmediatamente dichos archivos. Utilizo el IDE Eclipse para el desarrollo y puedo participar el proyecto completo de Firmado, Envio y Autorizacion de Documentos.
viernes, octubre 16, 2015
Genexus Emisor y Consumidor servicios web Rest
Resulta un poco complicado por primera vez inciarse en la utilización de los servicios web rest con el genexus.
Para el caso citamos algunas recomendaciones y tener exito al momento de emprender el desarrollo de servicios web tipo rest.
Para el caso se utilizo la versión Genexus Evolution 3 Upgrade 4.
SERVICIO WEB REST EMISOR
1.- Crear un procedimiento, para el caso asignamos el siguiente nombre (swrestconsultacliente).
2.- Modificar las propiedades del Procedmiento, como nos indica la siguiente imagen:
3.- La forma que hemos encontrado es utilizar solo parametros de Salida con datos complejos es decir utilizar SDT estructura de datos.
Se sugiere crear las siguiente variables.
// Crear una variable SDTParametros tipo SDT, debe concordar con la variable que utiliza el servicio web consumidor como parametro.
// SDTEnTexto variable tipo de LonvarChar.
Debemos crear en la RULES lo siguiente:
// Parametros de Salida.
Parm(Out:&SDTParametros);
4.- En el SOURCE debemos crear lo siguiente como parte basica, cuando se recibe parametros por parte del Servicio Web consumidor:
// Parametros de Entrada al Servicio web Rest consumidor.
&SDTEnTexto = &HttpRequest.ToString()
&SDTParametros.FromJson(&SDTEnTexto)
// Leer archivo de Clientes.
For Each
Order By ClienteCodigo
Where ClienteCodigo = &SDTParametros.ClienteCodigo
Defined By ClienteEstReg
&SDTParametros.ClienteNombre = ClienteNombre
EndFor
Return
Si no existe envio de parametros de entrada para el servicio web consumidor simplemente se ignora las dos primeras lineas.
Con estas instrucciones queda listo el servicio web rest emisor.
SERVICIO WEB REST CONSUMIDOR.
1.- Para el caso vamos a crear un WEBPANEL, pero de la misma forma podriamos crear un Procedimiento o cualquier otro objeto que consume el servicio web rest.
2.- Creamos la siguiente variables:
// SDTParametros una variable tipo SDT que puede contener un campo o mas campos de cualquier tipo de dato.
// HttpClient basada en el tipo de dato HttpClient.
// HttpRequest basado en el tipo de dato HttpRequest.
// StatusCode tipo de dato Númerico con Logitud de 8 digitos.
// Resultado tipo de dato LongVarChar
// SDTEnTexto tipo de dato LongVarChar.
// Url tipo de dato URL
Event Enter
&SDTParametros.ClienteCodigo = 59394884
&SDTParametros.ClienteNombre = ''
&SDTEnTexto = &SDTParametros.ToJson()
&HttpClient.AddString(&SDTEnTexto)
&HttpClient.Host = &HttpRequest.ServerHost // Servidor donde esta el SW Rest
&HttpClient.Port = &HttpRequest.ServerPort // Puerto donde esta el SWRest
&HttpClient.BaseUrl = "/swrestemisor/rest/" // Carpeta del SWRest
&Url = "swresconsultacliente" // Nombre del Procemiento EMISOR // no debe incluir el nombre de los modulos.
&HttpClient.Execute("POST", &Url)
&StatusCode = &HttpClient.StatusCode
&Resultado = &HttpClient.ToString()
&SDTParametros.FromJson(&Resultado)
EndEvent
3.- Creamos en la RULES.
// Parametros de Salida.
Parm(Out:&SdtParametros);
Como resultado final tendremos la información del nombre de cliente en la variable &SDTParametros.ClienteNombre.
Cuando lo llevemos a produccion, tenemos que modificar en la aplicacion del consumidor (webapps) el archivo web.xml, incluyendo los siguientes datos:
================
<servlet>
<servlet-name>JerseyListener</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>**packagename.GXApplication</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
</servlet>
<servlet-name>JerseyListener</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>**packagename.GXApplication</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>JerseyListener</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet-name>JerseyListener</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
================
**En caso de tener la propiedad java package name vacia escribir solamente GXApplication, en caso contrario escribir el nombre del package (desde XEV3 por defecto se incluye un package nameen las Knowledge base)
Tomado del articulo: Publicar Servicios web
Como elemento importante se puede utilizar las siguientes herramientas para realizar TESTING de los servicios web:
1.- WizTool
2.- SOAP UI - 32 Bits
3.- FireFox RestClients
4.- Chrome Rest Client
Suscribirse a:
Entradas (Atom)