Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

Índice


Índice
outlinetrue
exclude.*ndice
stylenone


Consideraciones Generales

La información contenida en este documento tiene el objetivo de demostrar cómo realizar la integración entre TOTVS Fluig Plataforma y aplicaciones externas. Para una comprensión completa de esta información, algunos conocimientos se consideran requisitos previos, incluyendo entre ellos:

...

Con el fin de facilitar la comprensión de la información que se presenta y la simulación de los conceptos presentados, los ejemplos citados en este documento utilizan la funcionalidad de Datasets como un ejemplo del uso de las capacidades de integración del producto. Sin embargo, es importante señalar que otros puntos del producto tienen disponibles las mismas características de integración existentes en los Datasets, especialmente las personalizaciones de procesos y formularios.

Visión General

Aunque empíricos, todas las empresas tienen procesos de negocio que permiten que la empresa cumpla con su objetivo, ya sea la prestación de un servicio, la producción de bienes materiales o el comercio de mercancías. Una empresa posee una infinidad de procesos, así cada persona en la organización participa obligatoriamente en al menos uno de estos procesos, y todos ellos comparten información entre sí en algún momento. Los procesos pueden ser formales (como la contratación de un profesional) o informales (como un incentivo para la innovación), críticos (facturación) o satélites (control de envío de tarjetas de cumpleaños).

...

La otra forma de integración es a través de llamadas a Progress® Open AppServer, que se recomienda para usuarios que necesitan integrar TOTVS Fluig Plataforma con aplicaciones desarrolladas en esta plataforma.

WebServices

La integración a través de WebServices utiliza el protocolo SOAP y, al ser un estándar abierto, permite que sistemas desarrollados en plataformas completamente diferentes como Java ™, Microsoft® .Net, C, C ++, PHP, Ruby, Pearl, Python, entre otras, puedan intercambiar información entre sí de manera transparente.

Acceso a WebServices de TOTVS Fluig Plataforma

TOTVS Fluig Plataforma ofrece un conjunto de WebServices que permiten el acceso a la información del producto o la ejecución de tareas, como por ejemplo iniciar solicitudes de procesos. Para tener la lista de los WebServices disponibles, ingrese a: 

...

Nota

Tenga en cuenta que cada tipo de atributo que se espera, por ejemplo el atributo expirationDate del objeto DocumentDto[] es una fecha, pero cada lenguaje lo interpreta de manera diferente, vea a continuación algunos ejemplos:

  • C#: dateTime
  • Java™: XMLGregorianCalendar
  • Progress®: DATETIME-TZ


Vía Apache Flex®

Al igual que la mayoría de las herramientas de desarrollo, Apache Flex® permite crear stubs para acceder a web services. Estos stubs encapsulan todas las operaciones de empaquetado y desempaquetado de la información del estándar XML para los tipos nativos de la plataforma.

...

Nota

Existe un bug de Flex® que impide el funcionamiento correcto de servicios que trabajan con matrices multidimensionales de datos, como en el ejemplo anterior, donde se devuelve un array (de líneas del Dataset) de array (de las columnas de cada registro).

Para solucionar este problema, es necesario cambiar la clase generada por Flex™ Builder™ que encapsulará el array multidimensional. En el ejemplo anterior, esta clase es DatasetDto, que deberá cambiarse (línea 11) como se muestra en el siguiente ejemplo:

Bloco de código
languageactionscript3
themeEclipse
firstline1
linenumberstrue
public class DatasetDto
{
	/**
	 * Constructor, initializes the type class
	 */
	public function DatasetDto() {}
            
	[ArrayElementType("String")]
	public var columns:Array;
	[ArrayElementType("ValuesDto")]
	public var values:Array = new Array(); //iniciando el array
}

Otros servicios que no trabajan con arrays multidimensionales no exigen cambios en el código generado.


Via Java™

Existen muchas implementaciones de uso de WebServices en Java ™ y en este ejemplo vamos a utilizar las bibliotecas disponibles en Java ™ 7.

...

Nota

Al utilizar los WebServices vía Java ™, se debe prestar atención al tipo de cada atributo y al tipo de devolución de WebService. Por ejemplo, para valores del tipofecha se debe utilizar la clase XMLGregorianCalendar:

Bloco de código
languagejava
themeEclipse
firstline1
linenumberstrue
DocumentDto document = new DocumentDto();

XMLGregorianCalendar date = DatatypeFactory.newInstance().newXMLGregorianCalendar();
date.setYear(2013);
date.setMonth(10);
date.setDay(16);
date.setHour(0);
date.setMinute(0);
date.setSecond(0);

document.setExpirationDate(date);


Vía Progress® 4GL

Al igual que en los ejemplos anteriores, el primer paso para consumir un Webservice en Progress® es utilizar una utilidad que leerá la dirección WSDL y generará la información necesaria para su acceso. A diferencia de Java™ y Flex®, Progress® no genera objetos de stub, pero sí una documentación sobre cómo consumir los servicios descritos en el archivo WSDL. Aunque en algunas situaciones es posible utilizar los tipos nativos de Progress® como parámetros, dependiendo del tipo de dato utilizado es necesario manipular el XML SOAP para extraer o enviar una información.

...

Bloco de código
languagejavafx
themeEclipse
firstline1
titlewsECMDatasetService.p
linenumberstrue
/* Parte I - Invocar o WebService */
DEFINE VARIABLE hWebService     AS HANDLE NO-UNDO.
DEFINE VARIABLE hDatasetService AS HANDLE NO-UNDO.

DEFINE VARIABLE cFields  AS CHARACTER EXTENT 0 NO-UNDO.
DEFINE VARIABLE cOrder   AS CHARACTER EXTENT 0 NO-UNDO.
DEFINE VARIABLE cDataset AS LONGCHAR NO-UNDO.

DEFINE TEMP-TABLE item NO-UNDO
    NAMESPACE-URI ""
    FIELD contraintType AS CHARACTER
	FIELD fieldName     AS CHARACTER
	FIELD finalValue    AS CHARACTER
	FIELD initialValue  AS CHARACTER.
 
DEFINE DATASET dConstraints NAMESPACE-URI "http://ws.dataservice.ecm.technology.totvs.com/"
	FOR item.

CREATE SERVER hWebService.
hWebService:CONNECT("-WSDL 'http://localhost:8080/webdesk/ECMDatasetService?wsdl'").
RUN DatasetService SET hDatasetService ON hWebService.

RUN getDataset IN hDatasetService(INPUT 1,
                                  INPUT "adm",
                                  INPUT "adm",
                                  INPUT "colleague",
                                  INPUT cFields,
                                  INPUT DATASET dConstraints,
                                  INPUT cOrder,
                                  OUTPUT cDataset).

DELETE OBJECT hDatasetService.
hWebService:DISCONNECT().
DELETE OBJECT hWebService.

/* Parte II - Faz o parser do XML e criar um arquivo texto separado por tabulacao */
DEFINE VARIABLE iCount  AS INTEGER   NO-UNDO.
DEFINE VARIABLE iCount2 AS INTEGER   NO-UNDO.
DEFINE VARIABLE hDoc    AS HANDLE    NO-UNDO.
DEFINE VARIABLE hRoot   AS HANDLE    NO-UNDO.
DEFINE VARIABLE hValues AS HANDLE    NO-UNDO.
DEFINE VARIABLE hEntry  AS HANDLE    NO-UNDO.
DEFINE VARIABLE hText   AS HANDLE    NO-UNDO.
DEFINE VARIABLE cValue  AS CHARACTER NO-UNDO.

OUTPUT TO c:\dataset.txt.

CREATE X-DOCUMENT hDoc.
CREATE X-NODEREF hRoot.
CREATE X-NODEREF hEntry.
CREATE X-NODEREF hText.
CREATE X-NODEREF hValues.

hDoc:LOAD("longchar", cDataset, FALSE).
hDoc:GET-DOCUMENT-ELEMENT(hRoot).

/* Percorre as colunas <columns> */ 
DO iCount = 1 TO hRoot:NUM-CHILDREN WITH 20 DOWN:
    hRoot:GET-CHILD(hEntry, iCount).
    IF hEntry:NAME <> "columns" THEN
        NEXT.

    hEntry:GET-CHILD(hText, 1).
    PUT UNFORMATTED hText:NODE-VALUE "~t".
    DOWN.
END.
PUT UNFORMATTED SKIP.

/* Percorre os registros <values> */
DO iCount = 1 TO hRoot:NUM-CHILDREN WITH 20 DOWN:
    hRoot:GET-CHILD(hValues, iCount).
    IF hValues:NAME <> "values" THEN
        NEXT.

    /* Percorre os campos <value> */
    DO iCount2 = 1 TO hValues:NUM-CHILDREN:
        hValues:GET-CHILD(hEntry, iCount2).

        IF hEntry:NUM-CHILDREN = 0 THEN
            cValue = "".
        ELSE DO:
            hEntry:GET-CHILD(hText, 1).
            cValue = hText:NODE-VALUE.
        END.
        PUT UNFORMATTED cValue "~t".
    END.

    PUT UNFORMATTED SKIP.
END.

OUTPUT CLOSE.

DELETE OBJECT hValues.
DELETE OBJECT hText.
DELETE OBJECT hEntry.
DELETE OBJECT hRoot.
DELETE OBJECT hDoc.

Acceso a WebServices desde TOTVS Fluig Plataforma

TOTVS Fluig Plataforma permite realizar llamadas a WebServices de terceros a través del registro de Servicios en la visualización de Servicios de Fluig Studio.

...

Una vez implementado el código del Dataset, es posible visualizarlo, como muestra la siguiente figura:


WebServices con Autenticación Básica

Para consumir WebServices que utilizan la autenticación básica (WSS o WS-Security), es necesario utilizar el método getBasicAuthenticatedClient localizado en provider del servicio (el mismo que se obtiene vía ServiceManager). Este método proporciona un client autenticado.

...

Bloco de código
languagejavascript
themeEclipse
firstline1
linenumberstrue
var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable');
var service = serviceLocator.getPeriodictableSoap();
var authenticatedService = serviceHelper.getBasicAuthenticatedClient(service, "net.webservicex.PeriodictableSoap", 'usuario', 'senha');
var result = authenticatedService.getAtoms();
WebService con client personalizado
Nota
titleAtención

Esta técnica es válida para atualización 1.3.7 o superior.

En integraciones que utilizan los servicios creados con CXF con sistemas que no soportan el protocolo HTTP/1.1 (Protheus, por ejemplo), se debe utilizar este método configurando el parámetro "disable.chunking" con el valor "true".

...

Tenga en cuenta que los ejemplos que aquí se presentan pretenden demostrar la dinámica de la integración entre Progress® y TOTVS Fluig Plataforma sin entrar en detalles específicos de las tecnologías involucradas. La capa de servicios Progress® de TOTVS Fluig Plataforma crea una interfaz en JavaScript para la biblioteca Java Open AppServer Client, de Progress® y, por lo tanto, para más información sobre cómo integrar aplicaciones Java ™ y Progress® vea la documentación suministrada por Progress®.

Caso de Uso

Los ejemplos que se muestran a continuación, tienen como objetivo crear cuatro Datasets 1 en TOTVS Fluig Plataforma:

...

Los dos códigos presentados tienen diferencias significativas en la forma en la que se utilizan y en cómo van a ser expuestos por Progress®. En el primer caso, el programa se carga de manera persistente y sus procedures se pueden ejecutar de forma independiente. En el segundo, el programa se ejecuta de manera no persistente y la lógica principal se encuentra en el main-block. Los procedures internos, si existen, están destinados a mejorar la organización del código y no se pueden utilizar de manera aislada.

Configuración de AppServer

Algunas informaciones importantes en la configuración del AppServer:

  1. AppServer debe cargarse en el modo Stateless;
  2. En la configuración del agente, en el campo Propath, se debe agregar el directorio donde están ubicados los archivos compilados (.r).

    Nota

    Importante: Cuando se utiliza una ruta relativa (\\servidor\carpeta), el servicio Windows® de Progress® (AdminService) se debe iniciar con un usuario de la red que posea permiso para acceder al directorio informado.

Exponiendo códigos 4GL con ProxyGen

El primer paso para poder ejecutar rutinas en Progress® 4GL es crear la biblioteca cliente, que se realiza mediante la aplicación ProxyGen, que acompaña a la instalación de Progress®, como se muestra a continuación.

...

Informações

Dependiendo de la versión de Progress®, las pantallas pueden sufrir alguna variación en la cantidad y disposición de los campos. En caso de dudas consulte la documentación



Configuración del Servicio en Fluig

El registro de un servicio se realiza a través de Fluig Studio, en la view Visualización de Servicios, en la opción  Incluir Servicio. La siguiente pantalla muestra el asistente del nuevo servicio y los campos utilizados para el registro del servicio Progress®:

...

Cuando el servicio se haya agregado, se pueden ver las clases disponibles y los métodos existentes en cada una de ellas. Esta información es importante para guiar el desarrollo de los códigos de personalización que harán uso de este servicio. Para ver las clases y los métodos del servicio, utilice la opción Consulta Servicio en Visualización de Servicios, como muestra la siguiente pantalla:



Visión general de los objetos involucrados

El acceso a los procedures expuestos en AppServer implica cuatro elementos que interactúan entre sí de acuerdo al siguiente diagrama:

...

  • Script Code: es el código en JavaScript que hará uso de los procedures expuestos en AppServer. Como se mencionó anteriormente, este JavaScript puede ser de cualquier naturaleza, tales como la implementación de un Dataset o la personalización de un evento de proceso.
  • Service Provider: Objeto recuperado a través del método ServiceManager.getService que proporciona el acceso a las funcionalidades del servicio. Este objeto se encarga de gestionar la conexión y los recursos asignados por el servicio durante la ejecución del script.
  • Service Helper: Objeto recuperado a través del método getBean en ServiceProvider que pone a disposición un conjunto de métodos de utilidad que permiten, entre otras cosas, crear objetos específicos de Progress® (StringHolder, ResultSetHolder, etc.), tener acceso al objeto remoto de ProxyGen e instanciar clases. Para más información sobre Service Helper consulte aquí.
  • ProxyGen Clases: Clases generadas por ProxyGen y serán utilizadas por el desarrollador para la ejecución de las rutinas en Progress®. La lista de las clases disponibles, así como sus métodos, se pueden ver en la Visualización de Servicios de Fluig Studio.

Procedures Persistentes y No Persistentes

Cuando se agrega un procedure al proyecto de ProxyGen, éste debe configurarse en dos listas: Procedures Persistentes o No Persistentes Esta decisión implica directamente en la forma en la que se accede a estos objetos por la biblioteca generada y, por consiguiente, en la forma en la que el desarrollador accederá a ella en los códigos JavaScript.

...

Los procedures expuestos de forma persistente dan origen a nuevas clases que pueden instanciarse a través de llamadas a métodos en el Objeto Remoto (a través de la Visualización de Servicios en Fluig Studio se pueden verificar los métodos disponibles en la clase), o por el método createManagedObject. La llamada a través del método createManagedObject permite que  Fluig tenga control sobre el ciclo de vida de este objeto, liberándolo de forma automática al final del método. Si el objeto es instanciado de forma manual, el desarrollador debe codificar la liberación del objeto (método _release()), bajo pena de bloquear un nuevo agente de AppServer en cada invocación del método.


Parámetros de Entrada y Salida

Otro punto importante en la invocación de las rutinas en 4GL es observar cuales son tipos de parámetros de entrada y salida de cada procedure o programa. Dependiendo del tipo de dato (CHARACTER, INTEGER, TEMP-TABLE, etc.), del tipo de parámetro (INPUT, INPUT-OUTPUT, BUFFER, etc.) y de la versión utilizada de Progress®, la forma de manipular estos parámetros puede variar.

...

Los tipos de datos utilizados por cada método se pueden consultar a través de la Visualización de Servicios en Fluig Studio. Tenga en cuenta que dependiendo de la versión de Progress® puede existir variación en los tipos de parámetros utilizados y en la manera de utilizarlos. En caso de duda, consulte la documentación suministrada por Progress®.

Creación de los Datasets

Cuando el servicio Progress® se haya agregado en Fluig, es posible utilizarlo en los puntos donde el producto permite la personalización utilizando JavaScript, como en los scripts para eventos globales, eventos de procesos, eventos de definición de formulario o Datasets.

...

Como ya se ha visto anteriormente, los Datasets que se presentarán aquí son Tipos de Centro de CostoNaturaleza de los Centros de CostoCentros de Costo yUsuarios en Común.


Tipos de Centro de Costo

El siguiente código presenta la implementación del Dataset de Tipos de Centro de Costo. La explicación de cada paso de la implementación se presentará después del código:

...

La siguiente pantalla presenta la visualización de los datos del Dataset creado:

Image Modified
Naturaleza de los Centros de Costo

El Dataset de Naturaleza de los Centros de Costo es muy similar al Dataset de tipo de centros de costo. En la práctica, el único cambio es que el procedure se llama:

...

Después del registro del Dataset, se puede ver su contenido:


Centros de Costo

El Dataset de Centro de Costo posee una estructura muy similar a la de los dos Dataset visto anteriormente. La principal diferencia es que, en este caso, el procedure devuelve una temp-table con los centros de costos, lo que cambia la forma en la que se manipulan los datos.

Dependiendo de la versión de Progress®, los objetos utilizados pueden variar. A continuación, se presentan ejemplos de la codificación para Progress® 9 y OpenEdge® 10, respectivamente. En ambos casos, el resultado presentado por Dataset será el mismo.

Codificación Progress® 9

Las temp-table en Progress® 9 son manejadas por los objetos que implementan la interfaz java.sql.ResultSet:

Bloco de código
languagejavascript
themeEclipse
firstline1
titledsCentroCustoP9.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
	//Crea la estructura del Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("cuenta");
    dataset.addColumn("titulo");
    dataset.addColumn("naturaleza");
    dataset.addColumn("tipo");
    
	//Recupera el servicio y carga el objeto remoto
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
    var remoteObj = serviceHelper.createManagedObject("CostCenterUtils");
    
    //Lee las cuentas corrientes
    var holder = serviceHelper.createResultSetHolder();
    remoteObj.readCostCenters(holder);
    
    //Recorre los registros, cargando el Dataset con los datos
    var rs = holder.getResultSetValue();
    while (rs.next()) {
        var cuenta 	 = rs.getObject("cuenta");
        var naturaleza = rs.getObject("naturaleza");
        var tipo 	 = rs.getObject("tipo");
        var titulo   = rs.getObject("titulo");
	
        dataset.addRow(new Array(cuenta, titulo, naturaleza, tipo));
    }
    
    return dataset;
}
Codificación OpenEdge® 10

En OpenEdge® 10, las temp-tables devueltas se encapsulan como objetos de la clase ProDataGraph. Esta clase también se utiliza cuando se usan parámetros del tipo DATASET:

...

Visualización del Dataset:


Usuarios en Común

La primera diferencia entre el Dataset de usuarios comunes y los ejemplos anteriores, es que en este caso es necesario pasar una temp-table como parámetro al procedure invocado.

...

La tercera diferencia que se puede observar en este caso es que es posible transformar un Dataset en los tipos de datos requeridos por Progress® (ResultSet o ProDataGraph).

Codificación Progress® 9
Bloco de código
languagejavascript
themeEclipse
firstline1
titledsUsuariosComunsP9.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
    //Crea el nuevo Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("usuario");
    dataset.addColumn("nombre");
    
	//Recupera los usuarios de TOTVS Fluig Plataforma
    var campos = new Array("colleaguePK.colleagueId", "colleagueName");
    var colleaguesDataset = DatasetFactory.getDataset("colleague", campos, null, null);
    
    //Instancia el servicio
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
    
    //Transforma el dataset en un ResultSet (v9) y crea holder de salida
    var inputTT = colleaguesDataset.toResultSet();
    var holder = serviceHelper.createResultSetHolder();
    
    //Invoca el procedure en el Progress
    serviceHelper.getProxy().verifyUsers(inputTT, holder);
    
    var rs = holder.getResultSetValue();
    while (rs.next()) {
        dataset.addRow(new Array(rs.getObject("cod_usuar"), rs.getObject("nom_usuario")));
    }
    
    return dataset;
}
Codificación OpenEdge® 10
Bloco de código
languagejavascript
themeEclipse
firstline1
titledsUsuariosComunsOE10.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
	//Crea el nuevo Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("usuario");
    dataset.addColumn("nombre");
    
	//Recupera los usuarios de TOTVS Fluig Plataforma
    var campos = new Array("colleaguePK.colleagueId", "colleagueName");
    var colleaguesDataset = DatasetFactory.getDataset("colleague", campos, null, null);
    
    //Instancia el servicio
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
	
    //Transforma el dataset en un ProDataGraph (v10) y crea holder de salida
    var inputTT = serviceHelper.toProDataGraph(colleaguesDataset);
    var holder = serviceHelper.createProDataGraphHolder();
    
    //Invoca el procedure en el Progress
    serviceHelper.getProxy().verifyUsers(inputTT, holder);
    
    var ttCC = holder.getProDataGraphValue().getProDataObjects("ttOutUsers");
    for (var row_index = 0; row_index < ttCC.size(); row_index++) {
        var row = ttCC.get(row_index);
        dataset.addRow(new Array(row.get("cod_usuar"), row.get("nom_usuario")));
    }
    
    return dataset;
}

...

Visualización del Dataset:


Service Helper

La siguiente tabla presenta la lista de métodos existentes en la clase utilidad para servicios Progress®:

...