miércoles, marzo 25, 2015

Enviar y recibir informacion via HTTP desde y hacia objetos Genexus

Tradicionalmente se focaliza este tipo de soluciones de integracion a generar servicios web SOAP y RestFull, que de muchas maneras soluciona la problema de integracion, pero al mismo tiempo por la diversidad de IDEs que se utiliza para su desarrollo, dificulta el proceso de mantenimiento o mejoras, ya sea por un tema propio de los servicios web SOAP o por el incremento y mejoras a las librerias que soportan los servicios web restfull.

Estuve por algunos dias con muchas dificultades en poner a punto unos servicios web restfull que habia generado con las versiones anteriores de Jersey, debido a que tenia que migrar hacia un nuevo servidor de aplicacion tipo WebProfile o FullProfile, intente inicialmente migrar hacia Jboss y resulta complicado el proceso, ya que dichas servicios dejaron de funcionar, en base algunas consultas en la web por medio del Google, se pudo detectar que uno debe hacer una configuracion especial para tener la posibilidad de utilizar las mismas versiones de los jar que sirve para los servicios web restfull y que son utilizados por Genexus especialmente las ultimas versiones GxEvo1 GxEvo2 GxEvo3.

Estos servicios web restfull fueron generados con el IDE Eclipse Luna, con jdk1.6 y Tomcat7.

Se intento utilizar otro IDE como es el caso del NETBEANS 7.x pero se encontro con el mismo problema debido a que la nueva version de Jersey es full compatible con la version Jdk1.7 y Jdk1.8, ademas que incluye ciertas configuraciones propias de la version, lo que limitaba en sumo grado la migracion.

En virtud de ello se procedio a investigar como hacer un proceso de transferencia de informacion desde y hacia objetos Genexus generados principalmente con el Generador Java.

Existe ejemplos en el WIKI de Genexus donde evidencia la facilidad de intercambiar informacion entre dos objetos mediante solo la utilización de http y con xml, en virtud de ello reproduzco dicha solucion que fueron creados para el ejemplo en la misma KB.

1.- Consumidor de informacion, en el caso se crea un procedimiento con la propiedad de CALL PROTOCOL seteada a HTTP, cuyo comportamiento seria de EMISOR.

No hace uso de los parametros, simplemente se tiene que crear las siguientes variables:
//&HttpClien de tipo HttpClient
//&XmlWriter de tipo XMLWriter
//&XmlReader de tipo XMLReader
&DatoUno = 888 (Númericos)
&DatoDos = 999  (Númericos)


// Determino el host y el puerto a donde hacer el request

 

&HttpClient.host = "localhost"
&HttpClient.port = 8080
&HttpClient.BaseUrl = '/carpetaplicacion/'
 

// Agrego el XML al request, con valores  iniciales
 

&XmlWriter.openRequest(&HttpClient)
&XmlWriter.WriteStartElement("parametros")
&XmlWriter.WriteElement("a", &DatoUno)
&XmlWriter.WriteElement("b", &DatoDos)
&XmlWriter.WriteEndElement()
&XmlWriter.close()


          // Ejecuto el GET al webproc
 

&HttpClient.execute("GET", "gxobjeto")  // Procedimiento con Call Protocol = HTTP.
&EstatusCode    = &HttpClient.StatusCode
&Resultado = &HttpClient.ToString()


// Se procede a la lectura del XML que devuelve via HTTP con los nuevos valores a las variables

&XmlReader.openResponse(&HttpClient)
&XmlReader.read()
&XmlReader.read()
&DatoUno = Val(&XmlReader.value)
&XmlReader.read()  
&DatoDos = val(&XmlReader.value)
&XmlReader.close()
Return


2.- Procedimiento Gx Emisor. ( en mi caso gxobjeto, referencia en el punto 1)

Se debe crear las siguientes variables:
//&HttpRequest de tipo HttpRequest
//&HttpResponse de tipo HttpResponse
//&XmlWriter de tipo XMLWriter
//&XmlReader de tipo XMLReader

// &DatoUno numerico
// &DatoDos numerico
 

          // Leo los parámetros del XML
 

&XmlReader.openRequest(&HttpRequest)
&XmlReader.read()
&XmlReader.read()
&DatoUno = Val(&XmlReader.value)
&XmlReader.read()  
&DatoDos = Val(&XmlReader.value)
&XmlReader.close()

// Ejecuto algunas modificaciones a las variables

&DatoUno = &DatoUno + 1
&DatoDos = &DatoDos + 10
     
      // Registro los datos modificados en el response


&XmlWriter.openResponse(&HttpResponse)
&XmlWriter.WriteStartElement("parameters")
&XmlWriter.WriteElement("a", &DatoUno)
&XmlWriter.WriteElement("b", &DatoDos)
&XmlWriter.WriteEndElement()
&XmlWriter.close()
Return


Esto resulta una simple forma de intercambiar informacion entre dos aplicaciones o KB, generadas por Genexus, sin recurrir a los tipicos procesos de inspeccion tanto para WSDL y WADL .

3.- En el siguiente punto vamos a utilizar un servlet generado con Eclipse, el mismo que invocara a un procedimiento creado en genexus, para enviar y recibir información.

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

public class EnviaryRecibirDatosConGET_A_Genexus
{
     private final static String USER_AGENT = "Mozilla/5.0";
  
    // Metodo pricnipal
    public static void main(String[] args) throws Exception
    {
        EnviaryRecibirDatosConGET_A_Genexus http = new EnviaryRecibirDatosConGET_A_Genexus();
         System.out.println("Proceso de prueba con el METODO GET EN HTTP");
        http.EnviarPorGet();
    }

    // Enviar Datos y receptar respuesta con el metodo get invocando un OBJETO GENEXUS.
    // Metodo para Enviar y Recibir datos por medio de GET HTTP

    private void EnviarPorGet() throws Exception
    {
         String url     = "http://localhost:8080/aplicacion/servlet/gxobjeto";
         URL laUrl     = new URL(url);
        HttpURLConnection conexion = (HttpURLConnection) laUrl.openConnection();
      
        // Asignar por omision el metodo GET
        conexion.setRequestMethod("GET");

        //adicionar al request header el agente
        conexion.setRequestProperty("User-Agent", USER_AGENT);

        conexion.setDoOutput(true);
        DataOutputStream grabaXml = new DataOutputStream(conexion.getOutputStream());
        // Escribir el XML
        grabaXml.writeBytes("<parametros>");
        grabaXml.writeBytes("        <DatoUno>77</DatoUno>");
        grabaXml.writeBytes("        <DatoDos>34</DatoDos>");
        grabaXml.writeBytes("</parametros>");  
        grabaXml.flush();
        grabaXml.close();
      
        int estatusCode = conexcion.getResponseCode();
        System.out.println("\nEnviando 'GET' request al URL : " + url);
        System.out.println("\EstatusCode : " + estatusCode);

        BufferedReader entrada = new BufferedReader(new InputStreamReader(conexion.getInputStream()));
        String lineaDatos;
        StringBuffer retorno = new StringBuffer();

        while ((lineaDatos = entrada.readLine()) != null)
        {
            retorno.append(lineaDatos);
            System.out.println(lineaDatos);
        }
        entrada.close();
 
        //Imprimir en Consola el Resultado de la consulta

        System.out.println(retorno.toString());
     }
 }
 

Se desplegaran datos en consola indicando como quedaron las variables respectivas.

4.- Servlet para intercambia información con  Genexus, mediante el metodo POST del HTTP.



jueves, marzo 19, 2015

Códigos de error y estado de HTTP

Códigos de error y estado de HTTP

Todas las respuestas HTTP contienen un código de estado de HTTP. Los números de código de respuesta HTTP correctos oscilan entre 200 y 399. Los números de código de respuesta de error HTTP estándar oscilan entre 400 y 599.
La lista siguiente muestra los números de código de respuesta de error y correcta que la API REST devuelve para cada uno de los métodos HTTP.
GET (único)
200, 400, 401, 404, 409
GET (recopilación)
200, 400, 401
PUT
200, 400, 401, 404, 409
DELETE
204, 400, 401, 409
POST
201, 400, 401, 409
Nota: Para las operaciones PUT y DELETE, la API no intenta determinar en un principio la validez del ID. En cambio, la API intenta ejecutar la actualización y suprimir las consultas directamente. Si se produce un error, la API devuelve el código 409 Conflicto. Si la API devuelve un código 404 No encontrado en esta situación, el rendimiento se ve afectado.
Asimismo, se reciben los mensajes de error siguientes en estos casos:
  • Si la solicitud HTTP contiene una dirección URI no válida o inaccesible, el servidor responde con un código de respuesta 404 No encontrado.
  • Si la solicitud HTTP contiene un método HTTP no compatible para una dirección URI válida, el servidor responde con un código de respuesta 405 Método no permitido.
  • Si la solicitud HTTP solicita un tipo de medio no compatible (encabezado Acepto), el servidor responde con un código de respuesta 406 No aceptable.
  • Si la solicitud HTTP envía un tipo de medio no compatible (encabezado de tipo de contenido), el servidor responde con un código de respuesta 415 Tipo de medio no soportado.
  • Varios errores de sintaxis o de servidor Web internos pueden devolver un error interno 500.

sábado, marzo 14, 2015

Apuntes de TOMEE

1.- Configurar ActiveMQ como componente externo.
    <tomee>
        <Resource id="MyJmsResourceAdapter" type="ActiveMQResourceAdapter">
            # Esto indica que el ActiveMQ broker no inicia cuando arranca el TOMEE
            BrokerXmlConfig  =
            ServerUrl = tcp://someHostName:61616
        </Resource>

        <Resource id="MyJmsConnectionFactory" type="javax.jms.ConnectionFactory">
            ResourceAdapter = MyJmsResourceAdapter
        </Resource>

        <Container id="MyJmsMdbContainer" ctype="MESSAGE">
            ResourceAdapter = MyJmsResourceAdapter
        </Container>

        <Resource id="FooQueue" type="javax.jms.Queue"/>
        <Resource id="BarTopic" type="javax.jms.Topic"/>
    </tomee>
 
El "ServerUrl" debe ser modificado para que comtemple el host y el puerto que el 
Proceso ActiveMQ. Los diferentes formatos de URL que ActiveMQ.
 
 
2.- Configurar ActiveMQ como componente interno
 
   
    <tomee>
        <Resource id="MyJmsResourceAdapter" type="ActiveMQResourceAdapter">
            BrokerXmlConfig =  broker:(tcp://someHostName:61616)
            ServerUrl       =  tcp://someHostName:61616
        </Resource>

        <Resource id="MyJmsConnectionFactory" type="javax.jms.ConnectionFactory">
            ResourceAdapter = MyJmsResourceAdapter
        </Resource>

        <Container id="MyJmsMdbContainer" ctype="MESSAGE">
            ResourceAdapter = MyJmsResourceAdapter
        </Container>

        <Resource id="FooQueue" type="javax.jms.Queue"/>
        <Resource id="BarTopic" type="javax.jms.Topic"/>
    </tomee>

La propiedad "BrokerXmlConfig" invoca a ActiveMQ para que inicie 
en conjunto cuando arranca el TOMEE con su host y puerto asignado 
en este caso `someHostName` and `61616` 
 
3.- Estructura de los archivos 

  • aplicacion.war
    • pages
      • *.jsp
    • images
      • *.jpg
    • META-INF
      • ejb-jar.xml
      • MANIFEST.MF
      • openejb-jar.xml ( Opcional )
    • stylesheet
      • *.css
    • WEB-INF
      • classes
        • de
          • Directorio con las clases
        • log4j.xml
        • hibernate.cfg.xml
      • lib
        • *.jar
      • web.xml
    • index.jsp
 4.- Configurar Propiedades del MDB.
 
En esta URL: CONFIGURACION DEL EJB-JAR.XML 
Aqui un ejemplo: Un Ejemplo
 
5.- Configurar Persistencia de activemq con Mysql.
 
Tomado desde esta url: Persistencia Activemq y Mysql 
 
Revisar el archivo activemq.xml que esta ubicado en la carpeta donde esta instalado 
el activemq/conf 


<broker xmlns="http://activemq.apache.org/schema/core" brokerName="mibroker" persistent="true"
    useShutdownHook="false" >
    ...
    <persistenceAdapter>
        <jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#mysql-ds"/>
    </persistenceAdapter>
    ...
</broker>
<!-- Fuera del tag 'broker' -->
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
    <property name="username" value="usuario"/>
    <property name="password" value="passwordBBDD"/>
    <property name="poolPreparedStatements" value="true"/>
</bean>
Se tiene que copiar el driver de Mysql a la carpeta lib del activemq.


Tambien es posible utilizar una base de datos que es muy eficiente para este tipo de cosas, aqui un pequeño ejemplo de como hacerlo:



<broker xmlns="http://activemq.apache.org/schema/core" brokerName="mibroker" persistent="true"
    useShutdownHook="false" destroyApplicationContextOnStop="false">
    ...
    <persistenceAdapter>
        <kahaPersistenceAdapter directory="${activemq.base}/activemq-data" maxDataFileLength="33554432"/>
    </persistenceAdapter>
    ...
</broker>

viernes, marzo 13, 2015

Apuntes Eclipse

Apuntes de Eclipse


  1. Herramientas para el analisis de la calidad

En esta ocasión quiero compartir contigo 7 herramientas que se usan para la calidad de nuestro código java. Lo importante es mejorar día a día en el desarrollo de aplicaciones mas robustas, tenemos:
  • Code Quality
  • Coding Convention
  • CheckStyle
  • PMD
  • Find Bugs
  • Sonar
  • CodePro
2.- TimerEJB – JEE6

3.- Abrir o Importar Proyecto desde Eclipse a NeatBeans

4.- FIRMAR DIGITALMENTE DOCUMENTOS PDF

5.- Tips para Eclipse

6.- Configurar TOMEE en Eclipse Luna.
  •  Windows, Preferences, Servers , RunTime, seleccionar el servidor y Remove.
  • En la Ventana donde se ubica las pestañas de Markers Propierties Servers Console etc, dar click en en link para agregar el servidor a incluir.
  • Seleccionar Apache, Tomcat7.x.x.
  • En Servername asignar TOMEE, presionar Next.
  • Seleccionar la carpeta donde esta descomprimido el TOMEE.
  • Seleccionar el JDK que se utilizar en este caso JR6, click en Next.
  •  Click en Finish.
  • Doble Click sobre TOMEE en tab de servidores.
  • En la parte de Servers Locations, dar Click en User Tomcat Instalacion.
  • En la parte de Servers Options desactivar Modules autoreload for default.
  • Luego presionar CTRL-S, para grabar los cambios.
  • Listo ahora ya podemos iniciar el TOMEE.
7.- Buscar el proceso que utiliza ese puerto 

            C:\WINDOWS\system32>netstat -o -n -a | findstr 8080
           TCP    0.0.0.0:8080           0.0.0.0:0              LISTENING       4184


            C:\WINDOWS\system32> taskkill /F /PID 4184
            SUCCESS: Sent termination signal to the process with PID 4184.


8.- Configurar colores y formato del texto para eclipse.
    Consultar en esta URL: Configurar Eclipse,  
Cambio de Colores 

9.- Configurar LOG4j en Eclipse.
 a.- Descargar el LOG4J y copiar a la carpeta lib del proyecto, el archivo log4.xxx.jar, se puede descargar desde aqui 
b.- Configurar las propiedades del proyecto en un archivo log4j.propierties que debe estar ubicado dentro de WEB-INF.
Debe contener lo siguiente: 

# Log4j configuration file.
log4j.rootCategory=DEBUG,A4,stdout

#
# stdout is ConsoleAppender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=[%d] [%C{1}.%M(%L)] - %-5p - %m%n

#
# A4 is a DailyRollingFileAppender
log4j.logger.clases.Principal=ALL,FILE
log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A4.file=c:\\log\\log4j.log
log4j.appender.A4.MaxFileSize=10000KB

#
# Keep three backup files.
log4j.appender.A4.MaxBackupIndex=10
log4j.appender.A4.datePattern='.'yyyy-MM-dd
log4j.appender.A4.append=true
log4j.appender.A4.layout=org.apache.log4j.PatternLayout
log4j.appender.A4.layout.ConversionPattern=[%d] [%c.%M(%L)] - %-5p - %m%n
El código fuente para poder probar la configuración anterior es el siguiente:






 

c.- Luego creamos un servlet para que active dicha aplicacion:

import org.apache.log4j.PropertyConfigurator;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InicializaLog4j extends HttpServlet
{

 public void init()
 {
     String prefix =  getServletContext().getRealPath("/");
     String file = getInitParameter("log4j-init-file");

     if(file != null)
     {
             PropertyConfigurator.configure(prefix+file);
     }
 }

 public void doGet(HttpServletRequest req, HttpServletResponse res)
     {
   
     }
}
 

d.- Configuramos en el web.xml para que inicialice dicha aplicacion.

  <servlet>
     <servlet-name>log4j-init</servlet-name>
     <servlet-class>swrest.InicializaLog4j</servlet-class>
     <init-param>
         <param-name>log4j-init-file</param-name>
         <param-value>WEB-INF/log4j.properties</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
</servlet>



Configurar Log4j en Tomcat

Cómo configurar Log4j en Tomcat se describe en la documentación de Tomcat, pero la configuración de ejemplo la documentación no es correcta. Así que en este post vamos a ver lo que tenemos que hacer para reemplazar el valor por defecto de Java Util Registro de configuración (JUL) y usar Log4j en Tomcat. Una gran ventaja es que si una aplicación utiliza Log4j entonces podemos configurar el registro en un lugar central para la instancia de Tomcat. Y otra ventaja es que podemos utilizar nuestro conocimiento sobre la forma de configurar el registro Log4j y no tenemos que aprender extensiones de sintaxis de Tomcat para la configuración de registro de julio..



Configura el classpath

Es necesario descargar unos JAR que luego seran ubicados en el classpath del Tomcat. Se debe reemplazar la utilizacion JUL una libreria propia del Tomcat. En virtud de ello vamos a adicionar LOG4J--> LIBRERIA LOG4J en el classpath.
Tomcat provee archivo JAR que se requiere para implementar Log4j en Tomcat. Estos archivo no se distribuyen en el paquete normal del TOMCAT, por eso debemos descargar desde el sitio web  PAGINA DE DESCARGA. Desde bin/extras aqui existe dos archivos que debemos descargar: tomcat-juli.jar y tomcat-juli-adapters.jar. Debemos reemplazar el archivo tomcat-juli.jar en la carpeta $CATALINA_BASE/bin. El archivo tomcat-juli-adapters.jar debe ser copiado a la  $CATALINA_BASE/lib.
Seguidamente descargamos la libreria log4j 1.2 desde PAGINA DE DESCARGA LIBRERIA LOG4J. Debemos desempaquetar y copiar el archivo log4j-1.2.<version>.jar a la carpeta $CATALIN_BASE/lib.

Configurar Log4j

Hemos adicionado log4j y configurado en el TOMCAT, ademas hemos desactivado TOMCAT JUL, que es el sistema de log propio del tomcat. Ahorta vamos configurar en $CATALINA_BASE/conf . El nombre del archivo logging.properties debemos movelo a la carpeta $CATALINA_BASE/conf/logging.properties.jul. Tomcat no puede utilizar este archivo en virtud de ello hacemos un resplado de la configuracion anterior. Ahora procederemos a configura el nuevo archivo para utilizar el Log4j. En la carpeta $CATALINA_BASE/lib debemos crear el archivo log4j.properties. existe un ejemplo Configuracion de LOG4J en TOMCAT pero tiene algunos errores y para ello describimos mas abajo como debe quedar. Los errores se presentan en conversionPattern que no esta configurado en la propiedad layout. Aqui un pequeño ejemplo de Log4j:



log4j.debug=true
log4j.rootLogger=INFO, CATALINA, CONSOLE
# Define all the appenders
log4j.appender.CATALINA=org.apache.log4j.FileAppender
log4j.appender.CATALINA.file=${catalina.base}/logs/catalina.log
log4j.appender.CATALINA.encoding=UTF-8
log4j.appender.CATALINA.layout=org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.CATALINA.append=true
log4j.appender.LOCALHOST=org.apache.log4j.FileAppender
log4j.appender.LOCALHOST.file=${catalina.base}/logs/localhost.log
log4j.appender.LOCALHOST.encoding=UTF-8
log4j.appender.LOCALHOST.layout=org.apache.log4j.PatternLayout
log4j.appender.LOCALHOST.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.LOCALHOST.append=true
log4j.appender.MANAGER=org.apache.log4j.FileAppender
log4j.appender.MANAGER.file=${catalina.base}/logs/manager.log
log4j.appender.MANAGER.encoding=UTF-8
log4j.appender.MANAGER.layout=org.apache.log4j.PatternLayout
log4j.appender.MANAGER.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.MANAGER.append=true

log4j.appender.HOST-MANAGER=org.apache.log4j.FileAppender
log4j.appender.HOST-MANAGER.file=${catalina.base}/logs/host-manager.log
log4j.appender.HOST-MANAGER.encoding=UTF-8
log4j.appender.HOST-MANAGER.layout=org.apache.log4j.PatternLayout
log4j.appender.HOST-MANAGER.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.HOST-MANAGER.append=true
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.conversionPattern=%d [%t] %-5p %c - %m%n
# Configure which loggers log to which appenders
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOST
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]=\
INFO, MANAGER
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]=\
INFO, HOST-MANAGER

Ahora ya podemos iniciar nuestro TOMCAT utilizando mensajes de log con LOG4J.
A veces es necesario trabajo bien pero no requerimos que el archivo de configuracion Log4j  este  $CATALINA_BASE/lib sino en la carpeta $CATALINA_BASE/conf. Para ello debemos mover el archivo de configura de log5j llamado log4j.properties desde la carpeta $CATALINA_BASE/lib a la carpeta  $CATALINA_BASE/conf. Pero debemos configurar una propiedad de sistema -Dlog4j.configuration=file://$CATALINA_BASE/conf/log4j.properties cuando inicia el  Tomcat 6 y 7 se puede utilizar la variable de ambiente LOGGING_CONFIG y asignar el valor que sera utiliza por los scrips de CATALINA cuando inicie el Tomcat.
Tomado de: Configurar Log4j en Tomcat

 Que es MAVEN.
Articulo que orienta mucho sobre el tema

Como instalar Maven en Eclipse.

Configurar Eclipse para generar un JAR con librerias adicionales:


Incluir plugin FATJAR

Como incluir el plugin en Eclipse MARS


Monitorear Tcp/IP desde ECLIPSE.

Monitorear TCP/IP En Eclipse

Crear un JAR ejecutable con librerias externas.


En Eclipse ejecuto lo siguiente
Clicc en el proyecto > Runnable JAR file
Donde dice Library Handling escojo la 2da opcion:
Package required libraries into generated JAR y luego elijo Finish.

Asi los .jar necesarios son agregados a mi propio JAR y no es necesario agregarlos al classpath.

Apuntes NeatBeans

Seccion apuntes de NeatBeans

1.- Ejemplo JFreeChart

 En el presente video tutorial se crea un reporte grafico basado en JFreeChart, a su vez es exportado a pdf para poderlo almacenar en disco. El ide utilizado es Netbeans 6.5 y lo puedes visualizar desde aqui. El ejemplo con las librerias puedes descargarlo desde aqui. Aprovecho tambien para que puedan visitar y registrarse en http://cursosvirtuales.comunidadtic.com
Conmigo Sera hasta otra. La verdad por estos dias ando cargado de mucho trabajo y me di este tiempo para cumplir con la creacion de este video tutorial para mis alumnos de la UPA y ponerlo disponible para todos los que quieran aprender.

Trucos de Genexus





  1. Obtener el usuario y nombre de equipo.

    &IpAddress = &HttpRequest.GetHeader("X-FORWARDED-FOR").Trim()
    If &IpAddress = ''
    &IpAddress = &HttpRequest.RemoteAddress
    EndIf

    &IpAddress -> Varchar(15)
    &HttpRequest -> HttpRequest


2.- Enviar PDF por medio de HTTP.

 Generar el pdf usando en Call Protocol Internal. Si luego necesitás que se vea el pdf en Linea, seguidamente despues de generarlo, a continuacion crea un procedure (con protocolo Http y main=true) en cuyo Source debe tener lo siguiente:

&Respuesta.AddHeader('Content-Type','content = application/pdf')
&Respuesta.AddHeader('Content-Disposition','inline; filename='+&FileName)
&Respuesta.AddFile(&FileName)

SI deseas copiar el archivo se debe proceder de la siguiente formaí:
Considerando que &FileNameOutputServer un parámetro donde se incluye el path.

Para el ejemplo se dispone de un servidor Linux y dichos pdfs se copian a un servidor Windows. 
Seguidamente en Linux montamos al directorio compartido de Windows como un filesystem.

&FileSource.Source  =      &FileName
&FileSource.Copy(&FileNameOutput)
&ErrCode                   =      &FileSource.ErrCode
&ErrDescription            =      &FileSource.ErrDescription

/*     Ahora copio el Archivo al Servidor donde se almacenan los PDF      */
if not &DirectorioCopiaFactElect.IsEmpty()
       &FileNameOutputServer=&DirectorioCopiaFactElect+&FileNameOutput
       &FileSource.Copy(&FileNameOutputServer)
       &ErrCode                   =      &FileSource.ErrCode
       &ErrDescription            =      &FileSource.ErrDescription
endif


3.- Conocer la ubicacion fisica donde esta instalado el servidor de aplicacion:
java [!&PathServidor!] = getHttpContext().getDefaultPath();

La variable PathServidor puede ser VarChar o Character.

Solo se debe ejecutar desde un Webpanel o TRN, pero no desde un Procedimiento.
Es mejor ubicarlo en el Start de una MasterPage luego asignarle a una variable de Session para que este disponible para todos los objetos.

4.- Configurar Hover y Selecction color en RWD:
Configurar Hover y Selection Color en RWD

5.- Crear un Menu com GAM y Genexus.
Un ejemplo de Menu con GAM

6.-Cuando te desplega un error de COMPILACIÓN que falta el OBJETO SDT.
Consejo para generar las SDT que no existen o fueron modificadas

Se sugiere en el BlogSpot de Enrique Almeida, crear un PROCEDURE tipo Main, luego le adicionan todas las SDT inluido los Bussines Components, luego compilar y solucionado el problema.

7.- Problemas cuando utilizas BC con WWP.

Para superar ese tema se debe realizar lo siguiente:
  • Tools, Explore Kno.....Directory, eliminar los .ARI.
  • en la carpeta compile, elimine los objetos en mencion que tengan _bc que identifican que tienen relacion con los BC.
  • En la carpeta state de forma similar en el punto anterior eliminar los que tengan relacion con el objeto y cuya extension es .ARI.
8.- Aplicaciones GeoEspaciales.
Aplicaciones de Genexus con Mapas

9.- User Controls para convertir HTML o cualquier texto en PDF.
URL donde descargar la UC  

10.- UC para enviar mensajes de confirmacion.
UC para realizar mensaje de confirmacion
Documentación sobre la UC de confirmación

11.- Un cliente SQL para la mayoria de las bases de datos.
Un Cliente SQL para muchos gestores de base de datos

13.- Libreria para convertir HTML en PDF.
LIbreria para convertir HTML en PDFs

14.- Generar PDF masivos.
Para ello utilizar el comando SUBMIT en lugar de CALL, recuerde que se debe incorporar un parametro mas al inicio.
Se puede incluir tambien una ruta del archivo pdf, por ejemplo c:/temporal/mipdf.pdf.

15.- Ejecutar en modo linea de comanos un WEBPANEL, muy util cuando se tiene que ejecutar tareas programas tanto en Linux como en Windows.
  •  Descargar el CURL seleccione su versión de Windows desde esta URL: Descargar CURL 
  • Se crea un carpeta en Archivos de Programas (x86) o en otra ubicación donde sea mas comodo para ejecutar.
  • Copiar los dos archivos a esa carpeta.
  • Crear un BAT con lo siguiente:
cls
c:\curl\curl.exe http://mihost:8080/aplicacion/servlet/hwebpanel
cls
  • Luego crea una tarea programa donde ejecute este script a la hora y fecha señalada.
 Para el caso de Linux Centos, seguimos las siguientes recomendaciones:
  1. yum remove curl curl-devel
  2. clear
  3. wget http://curl.haxx.se/download/curl-7.24.0.tar.bz2
  4. tar xfj curl-7.24.0.tar.bz2
  5. cd curl-7.24.0
  6. ./configure --prefix=/usr
  7. make
  8. make install
  9. #check version
  10. curl -V
  11. ./configure --with-curl=/usr --with-curlwrappers  // Instalar Soporte 
    Otra Forma: Tomado de: Documentacion para Instalar CURL en CENTOS
    
    1) crear un nuevo archivo /etc/yum.los repos.d/ciudad-ventilador.repo
    
    2) Pegar el siguiente contenido: 
     
       [CityFan]
        name=City Fan Repo
        baseurl=http://www.city-fan.org/ftp/contrib/yum-repo/rhel5/x86_64/
        enabled=1
        gpgcheck=0
    3) yum clean all
    yum install curl 
     
    Desde un paquete: 
    http://download.fedora.redhat.com/pub/fedora/linux/development/rawhide/x86_64/os/Packages/?P=*curl* 
    rpm –Uvh packagename
 De forma similar crear un .sh por ejemplo en /usr/local/procesos, de la siguiente forma:

#!/bin/sh
clear
DIA=`date +%d`
MES=`date +%m`
ANO=`date +%Y`
HORA=`date +%H:%M:%S`
HORA=`date +%H-%M-%S`
echo PROCESANDO...
HORA=`date +%H-%M-%S`
ARCHIVO=CALCULOS_inicia_$DIA-$MES-$ANO-$HORA.txt
ls >/usr/local/coactivas/$ARCHIVO
curl http://localhost:8080/roles/servlet/hprocesos130

HORA=`date +%H-%M-%S`
ARCHIVO=CALCULOS_termina_$DIA-$MES-$ANO-$HORA.txt
ls >/usr/local/coactivas/$ARCHIVO
echo FINALIZA CALCULOS.

echo FIN DEL PROCESO.

 cd /usr/local/procesos
curl http://mihost:8080/miapl/servlet/hwebpanel
clear
Crear una tarea programada con el comando CRONTAB -e
Asigna la el dia la hora para que se ejecute dicho script.

NOTA: Al crear el Shell, mejor copy paste y haga los ajustes necesarios, por el asunto de los signos especiales.

16.- Problemas con Tomcat7 y Genexus.
Errores al utilizar el Tomcat7

17.- Problemas al imprimir un PDF en un servidor en produccion Linux.
Para solventar aquello se tiene que copia desde su origen los archivos con extensión RPT, que estan ubicados en la raiz de la carpeta donde se genero los la aplicacion con genexus, ejemplo:
copiar desde:
c:/tomcat7/webapps/miaplicacion/reporte_pdf.rpt

Copiar el archivo reporte_pdf.rpt a la ubicacion en el servidor de produccion.

/usr/local/tomcat/webappp/miaplicacion

 18.- UTILIZAR UC - DVelop_Bootstrap_ConfirmPanel

Siempre interactuar con el usuario en una aplicación web sobre todo es muy util, debido aquello se ve la necesidad de utilizar esta UC.

Aqui un ejemplo: 

Event Start
     DVelop_Bootstrap_ConfirmPanel1.ConfirmationText='TEXTO DEL MENSAJE'
    DVelop_Bootstrap_ConfirmPanel1.Title ='TITULO'
    DVelop_Bootstrap_ConfirmPanel1.YesButtonCaption = 'BOTONSI'
    DVelop_Bootstrap_ConfirmPanel1.NoButtonCaption  = 'BOTONNO'

    DVelop_Bootstrap_ConfirmPanel1.CancelButtonCaption= 'CANCEL'
    DVelop_Bootstrap_ConfirmPanel1.ConfirmType='0' 
    // 0 = Desplega un Boton de Confirmar BOTONSI
       // 1 = Desplega dos Botones BOTONSI y BOTONSI
       // 2 = Desplega Tres Botones BOTONSI BOTONNO CANCEL
Endevent


Event Enter

    DVelop_Bootstrap_ConfirmPanel1.ConfirmationText = 'PRUEBAS TEXTO DEL MENSAJE'
          DVelop_Bootstrap_ConfirmPanel1.Title                  = 'PRUEBAS TITULO'

    DVelop_Bootstrap_ConfirmPanel1.Confirm()
Endevent





Event Refresh

    // Es posible modificar el tipo de Boton, en tiempo de ejecucion
    // Asignando un valor a esta propiedad, dichos estan    
    // descritos en la parte superior
    DVelop_Bootstrap_ConfirmPanel1.ConfirmType = '0'   
Endevent


Event DVelop_Bootstrap_ConfirmPanel1.onYes
    Msg('CLICK EN BOTONSI')
Endevent

Event DVelop_Bootstrap_ConfirmPanel1.onNo
    Msg('CLICK EN BOTONNO')
Endevent

Event DVelop_Bootstrap_ConfirmPanel1.onCancel
    MSG('CLICK BOTON CANCEL...')
Endevent


19.- CREAR UN PROCEDIMIENTO QUE SE EJECUTE CON CURL y CRONTAB en LINUX

Asignar en la propiedad:
Call Protocol   =  HTTP

20.- EJECUTAR SQL DENTRO DE GENEXUS


En ocasiones especiales es necesario poder incluir sentencias SQL en los programas generados de las aplicaciones Client/Server. 

El uso más común, es para modificar los permisos de las tablas de la aplicación, aunque puede utilizarse para realizar cualquier acción..



¿Cómo funciona?



Se debe incluir la constante “SQL” delante de la sentencia que se va a ejecutar.



Por ejemplo:

SQL DELETE * FROM CLIENTES



En el código generado aparecerá un comentario indicando que se está ejecutando una sentencia SQL del usuario.



Es posible ejecutar sentencias SQL creadas en  tiempo de ejecución. Si se incluyen atributos y/o variables dentro de la sentencia SQL con la notación [!att/var!], su valor es considerado en tiempo de ejecución.

Por ejemplo, si en Oracle se quiere cambiar el rol de un usuario:



          &Role = "MyRole"

          SQL SET ROLE TO [!&Role!]



Otro ejemplo:



&Sent = 'DELETE FROM CLIENTES WHERE CLICOD = 2'

SQL [!&Sent!]



Ha sido implementado en la versión 7.5 en los upgrade 1 de cada uno de los generadores en la versión 7.0



Consideraciones


  • Es importante recordar que las sentencias SQL que se utilicen en el comando SQL de GeneXus NO pueden retornar valores (retornar un status, devolver registros  RPC, etc.).  Esto también implica que no se tiene un manejo de errores, por lo cual si la sentencia produce un error cancelará la aplicación (el usuario no tiene permisos, la tabla sobre la que se opera no existe, etc)



  • El comando NO hace diferencia en lo que al DBMS se refiere, debiendo ser previsto por parte del desarrollador posibles diferencias de sintáxis entre ellos.



  • Es importante tener en cuenta que si la sentencia actualiza datos, puede requerir un commit. Por lo tanto, si el objeto GeneXus en el que es utilizado el comando SQL no actualiza los datos de la base, debe agregarse un comando commit, o incluirse en una UTL que lo haga.



  • El comando es ignorado en modelos no Client/Server.
  •  
 21.- WEBNOTIFICATIONS CON GENEXUS EVO3 U8 Y JDK1.7 Y TOMCAT7

En un Web panel a receptar la NOTIFICACION escribe lo siguiente:
Event OnMessage(&NotificationInfo)
        Msg(&NotificationInfo.Message + ' -- ' + &NotificationInfo.Id.ToFormattedString() )
EndEvent 
  
Event Enter
           PROCEDIMIENTO.SUBMIT("", &Par01)
Event En el Procedimiento llamado con SubMit, escribes lo siguiente: 
&NotificationInfo.Id        =    '1'
&NotificationInfo.Message    =    'TERMINO PROCESO DE REVISION ' + &Registros.ToFormattedString()
&webnotification.Broadcast(&NotificationInfo)

Cada vez que se utilice esta opcion se enviara un mensaje al WEBPANEL.

 22.- Descargar o Visualizar PDF
 
Una alternativa es crear una carpeta donde pueda ubicar los archivos para que luego puedan ser depurados en ciertos periodos de tiempo, una forma podria ser crear en el caso del Tomcat en linux /usr/local/tomcat/webapps/descargas/ o en Windows c:/Tomcat7/webapps/descargas/
 

Otra solución es recurrir a un servidor de archivos o file server.
Documentos: /DocumentosSitioPrueba/pdf/
                      /DocumentosSitioPrueba/xls/
                      /DocumentosSitioPrueba/xml/
                      /DocumentosSitioPrueba/img/


Y para obtener los archivos desde una ubicación fuera de la publicación podrías utilizar lo siguiente en un procedimiento main + HTTP:
//Tipo de variables
&httpResponse     : HTTPResponse
&contenido         : Varchar
&nombreArchivo     : Varchar
&tipoContenido     : Varchar
&pathArchivo     : Varchar


//Contenido de variables para archivos pdf
&contenido         : 'application/pdf'
&nombreArchivo     : 'archivopdf.pdf'
&tipoContenido     : 'inline'//Se utiliza inline para que se muestre en el navegador, si se desea que se descargue el archivo se utiliza attachment
&pathArchivo     : '/DocumentosSitioPrueba/pdf/archivopdf.pdf'


&httpResponse.AddHeader('Content-Type',&contenido)
&httpResponse.AddHeader('Content-Disposition',Format('%2; filename='+ "%1", &nombreArchivo.Trim(), &tipoContenido))
&httpResponse.AddFile(&pathArchivo)



 23.- Impresiòn en WEB.


1. Deberias revisar esta informacion del wiki: 


2. Existe un ejemplo para gx9 en el gxopen: pero creo que si se importa a evo sin problemas 


3. Deberias configurar para que en lugar de que genere pdf llame aun reporte txt automaticamente: 
yo tengo el codigo moficado de esta manera:

&loops= 0

do while &loops <= 4 // endless loop
   &loops= &loops+1
    msg(concat("printing loop #", str(&loops), " "), status)
    for each
        where PrintFileStatus='1'      // files to be printed
            msg(concat("printing ", PrintFileName," "),status)
            //&Printed= PrintDocument(PrintFileName)  // printing the file
            call(RGelatoNotaPedidoTexto2,PrintFileName)
            If &Printed=0               
                PrintFileStatus="P"                 // setting with "Printed" value
                PrintFileDatePrinted=now()          // updating the printed date and the flag
                msg("successfully printed", status) 
            else
                msg("print failed",status)
            endif
        commit
    endfor
    &seconds=sleep(5)   // waiting 5 seconds for to search again (files to be printed)
enddo

23.- Recuperar KB desde un MDF

Tomado de: Articulo Original









Para todas las bases de conocimiento se recuerda que son almacendas en  SQL Server, en cada base de datos (MDF), es posible crear un KB desde esta y construir todo de nuevo. Lo que se requiere es una copia de base de datos, en una carpeta diferenter.
Se debe crear una KB desde un MDF, justo como indica la figura:
Open KB from MDF

Pasos para restaurar manualmente una KB desde otro carpeta.

Suponemos que se tiene los siguientes archivos GX_KB_TEST.mdf y  GX_KB_TEST.LDF, se desea abrir dicha KB con GeneXus, para ello se debe hacer lo siguiente:
  1. Copiar los archivos GX_KB_TEST.mdf y GX_KB_TEST.LDF a una carpeta diferente, por ejemplo, c:\Modelos\Test.
  2. Crear un archivo vacio Test.gxw in C:\Modelos\Test.
  3. Crear un archivo de texto llamado 'knowledgebase.connection'. Editar con notepad, escriba lo siguiente:
<ConnectionInformation>
    <DBName>GX_KB_Test</DBName>
    <IntegratedSecurity>True</IntegratedSecurity>
    <ServerInstance>SERVERNAME\SQLEXPRESS</ServerInstance>
    <CreateDbInKbFolder>False</CreateDbInKbFolder>
</ConnectionInformation>
Asegurarse de que los parametros de conexion este acorde al ambiente de trabajo.
  1. Abrimos SQL Server Management Studio, en  SERVERNAME\SQLEXPRESS con seguridad incluidad (trusted connection) y  ADJUNTEel archivo MDF.
  2. Esta listo en Genexus vaya a File/Open/Open Knowledgebase seleccione  C:\Modelos\Test\Test.gxw. y con eso listo!
Si por alguna razon encuentra problemas revise esta URL: Problemas con SQLServer.

Copiando mdf desde otra PC

Este camino es mucho mas facil para crear un KB desde un archivo MDF, desde otra PC.
Realice los siguientes pasos.
  1. Copiar archivo GX_KB_TEST.mdf a una carpeta, por ejemplo c:\Modelos\Test.
  2. En GeneXus  File/Open/Open Knowledgebase y selecione C:\Modelos\Test\GX_KB_TEST.mdf - Listo! 
24.- Grabar una String BASE64 a un archivo PDF
&RutaArchivo = &Carpeta.Trim() + &NombreArchivo.Trim()    +    ".pdf"                           
// PARA GUARDAR EL COMO ARCHIVO
java try {
              java sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
              java byte[] decodedBytes = decoder.decodeBuffer([!&CadenaBase64!]);
              java java.io.File file = new java.io.File([!&RutaArchivo!]);
              java java.io.FileOutputStream fop = new java.io.FileOutputStream(file);
              java fop.write(decodedBytes);
              java fop.flush();
              java fop.close();
java    } catch (java.io.IOException ex) {
java            System.out.println("IOException:"+ex.toString());
java        }

25.- Recuperar Carpeta donde esta Instalado el Tomcat

    Se debe ejecutar solo desde un WEBPANEL.
    java [!&UbicacionServidor!] = getHttpContext().getDefaultPath();   
    &sSesion.Set("UBICACION_SERVIDOR_APL&", &UbicacionServidor)   
    &BaseUrl            =    &HttpRequest.ScriptPath

26.- Recuperar Carpeta donde esta Instalado el Tomcat y grabar PDFs

Solo es factible cuando se ejecuta desde un WebPanel o Transaccion Web.
java [!&UbicacionServidor!] = getHttpContext().getDefaultPath();   

&CarpetaApl       =    &HttpRequest.ScriptPath
&BaseUrl            =    &HttpRequest.BaseUrl

&UbicacionArchivo  Tiene lo siguiente:  C:\Tomcat7\webapps\consultas
&CarpetaApl Tiene lo siguiente: http://localhost:8080/consultas/servlet/
&BaseUrl Tiene lo siguiente   /sapconsultas/servlet/

&Url                =    &BaseUrl.Replace(&CarpetaApl, "/tempopdf/")
&Dato             =    &CarpetaApl.Replace("/servlet/", "")
&Dato             =    &Dato.Replace("/", "")
&CarpetaPdf    =    &UbicacionServidor.Replace(&Dato,"tempopdf\")
&Dato             =    &CarpetaApl.Replace("\", "/")
&Dato             =    "" 

Quedarian las variables de la siguiente forma:
&Url               =    http://localhost:8080/tempopdf/
&CarpetaPdf    =   C:/Tomcat7/webapps/tempopdf/

Guardar en variables de sesion:
    &sSesion.Set("CARPETA_SERVIDOR_TOMCAT", &UbicacionServidor)   
    &sSesion.Set("CARPETA_ARCHIVOS_TEMPORAL", &CarpetaPdf)
    &sSesion.Set("URL_ARCHIVOS_TEMPORAL", &Url)

27.- Probar Servicio web REST con parametros Jersey, tipo MultivaluedMap.

 En Genexus se tiene el siguiente ejemplo de invocacion de un servicio web hecho en Eclipse:
  • &Url                = "procesosri/enviardocto" 
  • &HttpClient.Host    = '192.168.100.6' 
  • &HttpClient.Port    = 8080        
  • &HttpClient.BaseUrl    = '/swsri2015/rest/' 
  • &HttpClient.AddVariable('par01',    &NroDoc)  
  • &HttpClient.AddVariable('par02',    '1')  
  • &HttpClient.AddVariable('par03',    "celcer.sri.gob.ec")
            &HttpClient.Execute("POST", &Url)       
            &StatusCode         = &HttpClient.StatusCode
            &Resultado             = &HttpClient.ToString() 
          

Al probarlo con SOAPUI, invocando la URL:
http://192.168.100.6:8080/swsri2015/rest/procesosri/enviardocto

 Retorna un error:

Se tiene que realizar lo siguiente:
  1. Seleccionar metodo POST.
  2. Incluir en Media Type: application/x-www-form-urlencoded
  3. En una Linea digitar los parametros separados por & como se detalla a continuacion:           par01=1&par02=FAC-001-003-000043871.xml&par03=celcer.sri.gob.ec                



De esa manera es posible probarlos servicios Web Rest con SOAPUI cuando se utiliza MultiValuedMap.

28.- Ejemplo de WEBRAPPER
Event SendMail
    &DirTo.Address = 'ejemplo@yahoo.com'    
    &DirTo.Name = 'Ejemplo'
    &mailmsg.To.Clear()
    &mailmsg.To.Add(&dirto)
    &mailmsg.Subject = 'GeneXus Nuevas'
    &SMTPSession.Host = &host
    &Sender.Address = 'GeneXus'
    &Sender.Name = 'GeneXus'
    &SMTPSession.Sender = &Sender
    &RetCode = &SMTPSession.Login()
    &Wrap.Object = Create(SearchStudents)
    &infoContent = &Wrap.GetResponse()
    &MailMsg.HTMLText = &infoContent
    &SMTPSession.Send(&MailMsg)
    &smtpsession.Logout() 
EndEvent  // SendMail
 

29.- Blog de muchos trucos de Genexus.

https://genexustipsblog.wordpress.com/

30.- Ejecutar un WebPanel que no se visualice los parametros.


Crear una variable tipo HttpClient.

&HttClient.AddHeader("Content-Type", "application/x-www-form-urlencoded")
&HttpClient.Secure = 0
&HttpClient.Host = 'localhost'
&HttpClient.Port =  80
&HttpClient.BaseUrl = '/'
&HttpClient.Timeout = 100
&HttpClient.AddVariable('MONTO',&monto.ToString().Trim())
&BaseUrl = 'webpaytst/webpanel'
&HttpClient.Execute('POST',&BaseUrl.Trim())
 Link(webpanel)
 


Webpanel llamado:
 

En el Evento Start
Event Start
      &Url     = &httprequest.Referrer
      &monto = &httprequest.GetVariable('MONTO').Trim()
      &error = &httprequest.ErrDescription
EndEvent


30.- Impresion directa desde WEB con Java y Tomcat.


Se debe realizar lo siguiente:
  1. Instalar Tomcat.
  2. Luego de haber instalado Tomcat se debe asignar un usuario de inicio al Tomcat, se lo puede realizar de la siguiente manera:
    1. Click en el Boton Inicio.
    2.  Boton derecho sobre la opcion Equipo.
    3. Seleccionar Administrar.
    4.  Expandir Servicios y Aplicaciones.
    5. Click en Servicios.
    6. Buscar  Apache Tomcat.
    7. Se abre un Popup con las Propiedades del Tomcat.
    8. Seleccionar la pestaña INICIAR SESION.
    9. Seleccionar ESTA CUENTA.
    10. Asignar el USUARIO Y PASSWORD.
    11. Reiniciar el Tomcat.
  3. Descargar desde esta URL: Programa para Impresion con PDF en forma Silenciosa.
  4.  Descargar: http://cdn.biopdf.com/download/acw/AcroWrap_11_2_0_51.exe o ultima versión.
  5. Instalar dicho programa.
  6. En modalidad de Linea de Comandos se puede ejecutar lo siguiente:
    acrowrap.exe /acceptlicense /t "pdf_file_name" ["printer_name"] ["printer_driver"] ["printer_port"] 
  7. Instalar el Acrobat Reader 8.
  8. Descargar desde esta ubicación: Descargar Acrobat Reader V8
  9. Modificar las variables de entorno con el fin de poder acceder a estos dos programas via linea de comandos.
  10.  Desde linea de comandos ejecutar lo siguiente: acrowrap.exe /acceptlicense /t nombrepdf.pdf
  11. De esa manera se puede imprimir directamente PDF a una impresora conectada a la computadora via USB o Puerto Paralelo.
31.- Trucos de Genexus.  


 32.- Error al crear BASE DE DATOS de GAM. 

8. Unable to load DLL 'libmySQL.dll': The specified module could not be found.

\========== Retrieve GAM Version From Database started ==========
error: Unable to load DLL 'libmySQL.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
  • Current GAM version:
  • Retrieve GAM Version From Database Success
  • Causa: Los procesos del GAM que ejecutan en el IDE de Genexus usan csharp y ADO Net para conectarse a la BD del GAM (detectar la versión del GAM en la BD, registrar aplicaciones, generar permisos).
  • Por ese motivo se requiere el cliente ADO Net correspondiente al DBMS que se está usando, en el caso de Mysql bajarlo de aquí.
  • Se debe instalar el driver para 32 bits, aunque la máquina de desarrollo sea de 64 bits, ésto es porque los procesos dentro del IDE corren en 32 bits. Por ende, la libmysql.dll de 32 bits se debe copiar al directorio c:\windows\syswow64.
  • En ejecución de la aplicación (en producción incluso) sí se puede usar 64 bits si se quiere.
 33.- Scroll en una Grilla.
  •  Dentro del Webpanel desde el ToolBox arrastramos el Componente Section al webform.http://kapateandoengenexus.esy.es/wp-content/uploads/2014/04/1.png
  • El elemento SECTION CREA UN DIV en nuestro código HTML,  un div es un contenedor que cumple una función similar a una tabla pero con la posibilidad de asignarle mas propiedades.
  •  
    3
  •  Solo queda darle la propiedad de SCROLL a nuestro SECTION desde CSS Para esto creamos una nueva clase dentro de SECTION llamada scroll (botón derecho en section add class)
    Buscamos la propiedad OVERFLOW y le asignamos el valor AUTO. Esta propiedad va a mostrar un scroll horizontal o vertical según sea necesario, en caso de que el contenido no sobrepase al contenedor no se mostrara el scroll.
     5
    Ahora agregamos la grilla que queremos mostrar al SECTION

     
    4
    • Finalmente toca asignarle la nueva clase a nuestro section desde el lado del form y modificando el whith y height logramos una vista similar a esta
     http://kapateandoengenexus.esy.es/wp-content/uploads/2014/04/6.png



 34.- PAGINADO MANUAL CUANDO TENEMOS UN GRID SIN TABLA BASE
Tomado de: Paginado 

Cuando un grid no tiene tabla base no se calcula el ‘recordcount’ ni el ‘pagecount’ que son las funciones para calcular los registros, dado que el paginado no se hace en la consulta de la DB sino que se hace del lado servidor. Por ende, en ocasiones cuando damos clic en el botón ‘Last Page’ de un GRID STB con paginado, si debería haber 5 registros en la última página, intenta llenar los faltantes con más registros y pareciera que es un bug, sin embargo es un comportamiento normal.
Lo que debemos aplicar para que funcione correctamente el paginado en GX es hacerlo manualmente de la siguiente manera*:
Suponiendo que en mi KB tengo una transacción película con estos atributos: Id, Nombre y Año. Coloco en mi web panel un grid sin tabla base con las variables basadas en dichos atributos y dos imágenes para eliminar y editar.
El código a usar es el siguiente:
Event Load
&RecordCount = 0
For each order PeliculaNombre
where PeliculaId >= &FilterPeliculaId
&Eliminar.FromImage(Eliminar)
&ImgEditar.FromImage(Editar)
&PeliculaId = PeliculaId
&PeliculaNombre = PeliculaNombre
&PeliculaAnio = PeliculaAnio
LOAD
&RecordCount +=1
Endfor
Endevent
Event ‘FirstPage’
Grid1.FirstPage()
Endevent
Event ‘NextList’
Grid1.NextPage()
Endevent
Event ‘Last’
&RecordCount = 0
For each //Este FE es indentico al Load, sin el comando load
Where PeliculaId >= &FilterPeliculaId
&PeliculaId = PeliculaId
&PeliculaNombre = PeliculaNombre
&PeliculaAnio = PeliculaAnio
&RecordCount +=1
Endfor
&PageCount = int(&RecordCount / Grid1.Rows) + iif(mod(&RecordCount,Grid1.Rows)=0,0,1)
Grid1.GotoPage(&PageCount)
Endevent
Event ‘BackList’
Grid1.PreviousPage()
Endevent
El resultado al dar clic a la última página vemos que es el correcto y sería de esta manera:
 *NOTA: El código descrito solamente aplica para GRIDs Sin Tabla Base

 35.- Habilitar servicios Web Rest en un servidor LINUX con un WAR.

  • Se debe Copiar las siguientes sentencias.
  • En la parte de SERVLET.
       <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>gob.ec.GXApplication</param-value>
                                </init-param>                          
       </servlet>
                            
  •  En la parte de MAPPING.
        <servlet-mapping>
                       <servlet-name>JerseyListener</servlet-name>
                    <url-pattern>/rest/*</url-pattern>
       </servlet-mapping>       


36.- Configurar PrinterServer
  • Implementación y uso desde GeneXus
  • La aplicación GeneXus se comunica con el servicio de impresión via ajax desde el navegador de la máquina cliente.
  • Profundizando en los detalles de la implementación, la misma consiste en dos partes:
  1. Llamada a servicio via ajax
  2. Servicio de impresión
1 - En la aplicación que va a invocar al reporte debe incluirse el javascript estándar gxprint.js (distribuido por GeneXus). Se puede hacer en cada Web Panel o en toda la aplicación, incluyéndolo en la Master Page.
Event Start
    Form.JScriptSrc.Add("gxprint.js")
Endevent
 
Mayor referencia: Utilizar PrintServer

37.- Stored Procedures en el ISERIES.
De vez en cuando surge la necesidad de crear stored procedures, aquello se torna un dolor de cabeza principalmente por la
SINTAXIS, sobre todo por la POQUISIMA INFORMACION sobre el tema referente a la Herramienta Genexus
, para ello se recomienda principalmente la siguiente:
1.- Utilizar la version Gx15.
2.- Crear un Data Stored para Stored Procedures,
      - Asignar Servidor, Schema de la base de datos, Usuario y password.

Luego Crear Objeto Stored Procedure, donde se describe todo los campos que requiere el Stored Procedure
para su ejecucion.


3.- Para la Version 6 de OS400 solo se permite parametros de INPUT, desde la Version 7 ya existe la posibilidad de recibir datos en los parametros descritos como INOUT.
4.- En un modelo RPG o COBOL, crear los programa en RPG o COBOL pero con la opcion IDLE, son mas eficiente.
5.- Crear en el MODELO DE JAVA WEB, un procedimiento tipo MAIN.
6.- En el Source ubicar lo siguiente, acorde a la definicion del Objeto Stored Procedure.

java        String cmdBuffer = " DROP PROCEDURE STORED/PONCLI ";
java        ExecuteDirectSQL.execute(context, remoteHandle, "DEFAULT", cmdBuffer) ;
//java        cmdBuffer = " CREATE PROCEDURE STORED/PONCLI (INOUT CHAR(3), INOUT CHAR(5), INOUT CHAR(40)) EXTERNAL NAME STORED/PONCLI LANGUAGE RPG GENERAL ";
java        cmdBuffer = " CREATE PROCEDURE STORED/PONCLI(IN MODO CHAR ( 3), IN CLICOD CHAR (5), IN CLINOM CHAR ( 40)) LANGUAGE RPGLE SPECIFIC STORED/PONCLI NOT  DETERMINISTIC NO SQL CALLED ON NULL INPUT EXTERNAL NAME STOREP/PONCLI PARAMETER STYLE GENERAL WITH NULLS";
java       ExecuteDirectSQL.execute(context, remoteHandle, "DEFAULT", cmdBuffer) ;
java        System.out.println("STORED PROCEDURE PONCLI CREADO");
java       cmdBuffer = " DROP PROCEDURE STORED/REVCLI ";
java       ExecuteDirectSQL.execute(context, remoteHandle, "DEFAULT", cmdBuffer) ;
//java       cmdBuffer = " CREATE PROCEDURE STORED/REVCLI (INOUT CHAR(3), INOUT CHAR(5), INOUT CHAR(40)) EXTERNAL NAME STORED/REVCLI LANGUAGE RPG GENERAL ";
java        cmdBuffer = " CREATE PROCEDURE STORED/REVCLI(IN MODO CHAR ( 3), IN CLICOD CHAR (5), IN CLINOM CHAR ( 40)) LANGUAGE RPGLE SPECIFIC STORED/REVCLI NOT  DETERMINISTIC NO SQL CALLED ON NULL INPUT EXTERNAL NAME STOREP/REVCLI PARAMETER STYLE GENERAL WITH NULLS";
java       ExecuteDirectSQL.execute(context, remoteHandle, "DEFAULT", cmdBuffer) ;
java       Application.commitDataStores(context, remoteHandle, null, "CRTJDBCCALLS");
java        System.out.println("STORED PROCEDURE REVCLI CREADO");
java       System.exit(0); 


7.- Compilar y luego ejecutar de esa manera se crean los Stored Procedure desde el mismo Genexus, he intentado
de algunas maneras pero nunca se ejecuta la clase crtjdbccalls, en virtud de ello se tiene que hacerlo mediante
el NAVIGATOR o en pantalla VERDE ejecutar STRSQL seguidamente ejecutar las sentencias DROP y CREATE.
8.- En el mismo entorno de pantalla VERDE es posible ejecutar el comando CALL que invoca al Stored Procedure
recien creado de la siguiente forma:
 CALL STORED/PONCLI ('2', '5', '5')            
     Sentencia CALL completada.                     
9.- Si no responde Sentencia CALL completada, existe algun error al crear los SP.

Referencia: Stored Procedures para DB2