Árvore de páginas

Versões comparadas

Chave

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

Index:


Índice
outlinetrue
exclude.*ndice
stylenone


General Considerations

The information contained in this document is intended to demonstrate how to perform the integration between Fluig and external applications. In order to have a full understanding of this information, some knowledge is considered a prerequisite, including:

...

With the intent of making it easier to understand the information presented and simulation of the concepts presented, the examples mentioned in this document use the Dataset feature as an example of the use of the product integration resources. However, it is important to note that other points of the product have the same integration characteristics available as those existing in Datasets, especially customizations of forms and processes.

Overview

Although empirical, every company has business processes that enable the company to fulfill its objective, whether it is the provision of a service, the production of products or trading goods. A company has a multitude of processes, with each person in the organization being part of at least one of these processes, and all of them exchange information with each other at some point. The processes can be formal (such as hiring a professional) or informal (such as an incentive to innovation), critical (billing) or satellite (birthday card send control).

...

The other form of integration is through calls to Progress® Open AppServer and is recommended for users who need to integrate TOTVS Fluig Platform with applications developed in that platform.

WebServices

Integration through WebServices uses the SOAP protocol and, since it is an open standard, allows systems developed in entirely different platforms, such as Java™, Microsoft® .Net, C, C++, PHP, Ruby, Pearl, Python, among others, to exchange information with each other in a seamless way.

Accessing Fluig WebServices

Fluig provides a set of WebServices that allow access to product information or running tasks, such as starting process requests. For the list of WebServices available, go to: 

...

Nota

Watch out for each type of attribute that is expected, for example, the expirationDate attribute of the DocumentDto[] object is a date, however, each language interprets it differently, see some examples below:

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


Via Apache Flex®

As the vast majority of development tools, Apache Flex® allows you to create stubs to access to web services. These stubs include all the packing and unpacking operations of XML standard information for the platform native types.

...

Nota

Flex® has a bug that prevents proper functioning of services that work with multidimensional arrays of data, as in the above example, where an array (of Dataset lines) of array (of the columns of each record) is returned.

To work around this problem, you must change the class generated by Flex™ Builder™, which will encapsulate the multidimensional array. In the above example, this class is the DatasetDto, which should be changed (line 11) as shown in the example below:

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 o array
}

Other services that do not work with multidimensional arrays do not require changes in the generated code.


Via Java™

There are many implementations of WebServices use in Java™ and, in this example, we will use the libraries available in Java™ 7.

...

Nota

When using WebServices via Java™, you must pay attention to the type of each attribute and to the type of return of the WebService. For example, for values of the date type, you should use the XMLGregorianCalendar class:

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);


Via Progress® 4GL

So, as in the previous examples, the first step to use a Webservice in Progress® is to use a utility that will read the ESDL address and generate the required information for accessing it. Different from Java™ and Flex®, Progress® does not generate stub objects, but only a documentation on how to consume the services described in the WSDL file. Although in some situations you can use the Progress® native types as parameters, depending on the data type used, you need to handle the SOAP XML to extract or send information.

...

Bloco de código
languagejavafx
themeEclipse
firstline1
titlewsECMDatasetService.p
linenumberstrue
/* Part I - Call 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.
/* Part II - Parse XML and create a text file separated by tabs */
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).
/* Goes through the columns <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.
/* Goes through the records <values> */
DO iCount = 1 TO hRoot:NUM-CHILDREN WITH 20 DOWN:
    hRoot:GET-CHILD(hValues, iCount).
    IF hValues:NAME <> "values" THEN
        NEXT.
    /* Goes through the fields <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.

Accessing WebServices from Fluig

Fluig allows call to third-party WebServices through the Fluig Studio Service View Service registration.

...

Once the Dataset code is implemented, you can view it, as shown in the figure below:

WebServices with Basic Authentication

In order to use WebServices that use basic authentication (WSS or WS-Security), you need to use the getBasicAuthenticatedClient method located in the service provider (the same obtained through the ServiceManager). This method provides an authenticated client.

...

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 with customized client
Nota
titleAttention

This technique is valid for Fluig 1.3.7 or higher.

In integrations that use services created with CXF with systems that do not support the HTTP/1.1 protocol (Protheus, for example), you need to use this method by setting the "disable.chunking" parameter to "true".

...

Note that the examples presented here intend to demonstrate the integration dynamics between Progress® and Fluig without going into specific details of the technologies involved. The Fluig Progress® service layer creates a JavaScript interface for the Progress® Open AppServer Client Java library and, therefore, for more information on how to integrate Java™ and Progress® applications, refer to the documentation provided by Progress®.

Use Case

The examples shown below, intend to create four Datasets 1 in Fluig:

...

Both codes presented have significant differences in the way they are used and the way they will be exposed by Progress®. In the first one, the program is loaded persistently and its procedures can be run independently. In the second case, the program is run in a non-persistent way and the main logic is in the main-block. The internal procedures, if any, are intended to improve code organization and cannot be used in isolation.

AppServer Configuration

Some important information in the AppServer configuration:

  1. The AppServer should be loaded in Stateless mode;
  2. In the agent configuration, in the Propath field, you should add the directory where compiled files are located (.r)

    Nota

    Important: When a relative path (\\server\folder) is used, the Progress® Windows®service (AdminService) should be started with a network user that has access permission to the directory provided.

Exposing 4GL codes with ProxyGen

The first step to be able to run routines in Progress® 4GL is to create the client library, which is done by using the ProxyGen application, which is shipped with the Progress® installation, as shown in the example below.

...

Informações

Depending on the version of Progress®, the screens can suffer some variation in the amount and placement of fields. See the documentation in case of doubt



Service Configuration in Fluig

The registration of a service is performed through Fluig Studio, in the Services View through the Add Service option. The screen below shows the new service wizard and the fields used to register the Progress® service:

...

Once the service has been added, you can view the available classes and the methods that exist in each one of them. This information is important to guide the development of customization codes that will use this service. To view the service classes and methods, use the Service Query option in Services View, as in the screen below:



Overview of Objects Involved

Access to procedures presented in the AppServer involves four elements that interact with each other, as shown in the diagram below:

...

  • Script Code: is the JavaScript code that will make use of the procedures presented in the AppServer. As previously mentioned, this JavaScript can be of any nature, such as the implementation of a Dataset or the customization of a process event.
  • Service Provider: Object retrieved through ServiceManager.getService method that provides access to service features. This object is responsible for managing the connection and resources allocated by the service during script execution.
  • Service Helper: Object retrieved through the getBean method in the ServiceProvider and that provides a set of utility methods that allow, among other things, to create Progress® specific objects (StringHolder, ResultSetHolder, etc.), to have access to the ProxyGen remote object and to instantiate classes. For more information about the Service Helper, query here.
  • ProxyGen Classes: Classes generated by ProxyGen and that will be used by the developer for the Progress® routine execution. The list of available classes, as well as their methods, can be viewed in the Fluig Studio Service View.

Persistent and Non-Persistent Procedures

When a procedure is added to the ProxyGen project, it must be configured in two lists: Persistent or Non-Persistent Procedures This decision affects directly how these objects are accessed by the generated library and, consequently, how the developer will access them in JavaScript codes.

...

The procedures presented in a persistent way give rise to new classes that can be instantiated through calls to methods in the Remote Object (through the Service View in Fluig Studio, you can check the available methods in the class) or through the createManagedObject method. The call through the createManagedObject method allows Fluig to have control over this object life cycle, freeing it automatically at the end of the method. If the object is instantiated, the developer must manually encode the object release (_ release () method), otherwise there is the risk of blocking a new AppServer agent at each call to the method.


Input and Output Parameters

Another important point in 4GL routine calls is to observe the input and output parameter types for each procedure or program. Depending on the data type (CHARACTER, INTEGER, TEMP-TABLE, etc.), the parameter type (INPUT, INPUT-OUTPUT, BUFFER, etc.) and the Progress® version used, the way to handle these parameters may vary.

...

The data types used in each method can be consulted through the Fluig Studio Service View. Note that, depending on the Progress® version, there may be a variation in the types of parameters used and the way they are used. If in doubt, check the documentation provided by Progress®.

Dataset Creation

Once the Progress® service is added to Fluig, you can use it at the points where the product allows customization using JavaScript, such as in the scripts for global events, process events, form definition events or Datasets.

...

As previously seen, the Datasets that will be presented here are Cost Center TypesNature of the Cost CentersCost Centers and Users in Common.


Cost Center Types

The code below shows the implementation of the Cost Center Types Dataset. The explanation of each step of the implementation will be presented after the code:

...

The screen below shows the Dataset data view created:


Nature of Cost Centers

The Nature of Cost Centers Dataset is very similar to the cost center type Dataset. In practice, the only change is the called procedure:

...

After Dataset registration, you can view its content:


Cost Centers

The Cost Centers Dataset has a structure that is very similar to the two Datasets previously seen. The main difference is that, in this case, the procedure returns a temp-table with cost centers, which changes the way data is handled.

Depending on the Progress® version, the objects used may vary. The following are examples of encoding for Progress® 9 and OpenEdge® 10, respectively. In both cases, the result presented by the Dataset will be the same.

Progress® 9 Encoding

The temp-table in Progress® 9 are treated through objects that implement the java.sql.ResultSet interface:

Bloco de código
languagejavascript
themeEclipse
firstline1
titledsCentroCustoP9.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
	//Creates the structure of the Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("conta");
    dataset.addColumn("titulo");
    dataset.addColumn("natureza");
    dataset.addColumn("tipo");
    
	//Retrieves the service and loads the remote object
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
    var remoteObj = serviceHelper.createManagedObject("CostCenterUtils");
    
    //Reads the current accounts
    var holder = serviceHelper.createResultSetHolder();
    remoteObj.readCostCenters(holder);
    
    //Goes through the records, loading the Dataset with data
    var rs = holder.getResultSetValue();
    while (rs.next()) {
        var conta 	 = rs.getObject("conta");
        var natureza = rs.getObject("natureza");
        var tipo 	 = rs.getObject("tipo");
        var titulo   = rs.getObject("titulo");
	
        dataset.addRow(new Array(conta, titulo, natureza, tipo));
    }
    
    return dataset;
}
OpenEdge® 10 Encoding

In OpenEdge® 10, the temp-tables returned are encapsulated as objects of the ProDataGraph class. This class is also used when you use parameters of the DATASET type:

Bloco de código
languagejavascript
themeEclipse
firstline1
titledsCentroCustoOE10.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
	//Creates the structure of the Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("conta");
    dataset.addColumn("titulo");
    dataset.addColumn("natureza");
    dataset.addColumn("tipo");
    
	//Retrieves the service and loads the remote object
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
    var remoteObj = serviceHelper.createManagedObject("CostCenterUtils");
    
    //Reads the current accounts
    var holder = serviceHelper.createProDataGraphHolder();
    remoteObj.readCostCenters(holder);
    
	//Goes through the records, loading the Dataset with data
    var ttCC = holder.getProDataGraphValue().getProDataObjects("ttCC");
    for (var row_index = 0; row_index < ttCC.size(); row_index++) {
        var row = ttCC.get(row_index);
        dataset.addRow(new Array(row.get("conta"),
                                 row.get("titulo"),
                                 row.get("natureza"),
                                 row.get("tipo")));
    }
    
    return dataset;
}


Dataset View:


Users in Common

The first difference between the users in common Dataset and the previous examples is that, in this case, you must pass a temp-table as a parameter to the procedure called.

...

The third difference that can be observed in this case is that it is possible to transform a Dataset into the data types required by Progress® (ResultSet or ProDataGraph).

Progress® 9 Encoding


Bloco de código
languagejavascript
themeEclipse
firstline1
titledsUsuariosComunsP9.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
    //Creates the new Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("usuario");
    dataset.addColumn("nome");
    
	//Retrieves Fluig users
    var campos = new Array("colleaguePK.colleagueId", "colleagueName");
    var colleaguesDataset = DatasetFactory.getDataset("colleague", campos, null, null);
    
    //Instantiates the service
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
    
    //Transforms the dataset in a ResultSet (v9) and creates holder for the output
    var inputTT = colleaguesDataset.toResultSet();
    var holder = serviceHelper.createResultSetHolder();
    
    //Calls the procedure in 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;
}
OpenEdge® 10 Encoding


Bloco de código
languagejavascript
themeEclipse
firstline1
titledsUsuariosComunsOE10.js
linenumberstrue
function createDataset(fields, constraints, sortFields) {
    
	//Creates the new Dataset
    var dataset = DatasetBuilder.newDataset();
    dataset.addColumn("usuario");
    dataset.addColumn("nome");
    
	//Retrieves Fluig users
    var campos = new Array("colleaguePK.colleagueId", "colleagueName");
    var colleaguesDataset = DatasetFactory.getDataset("colleague", campos, null, null);
    
    //Instantiates the service
    var servico = ServiceManager.getService("EMS2");
    var serviceHelper = servico.getBean();
	
    //Transforms the dataset in a ProDataGraph (v10) and creates holder for output
    var inputTT = serviceHelper.toProDataGraph(colleaguesDataset);
    var holder = serviceHelper.createProDataGraphHolder();
    
    //Calls the procedure in 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;
}


Dataset:



Service Helper

A tabela abaixo apresenta a lista de métodos existentes na classe utilitária para serviços Progress®:

...