Histórico da Página
Índice
Índice | ||||||
---|---|---|---|---|---|---|
|
Consideraciones Generales
La información contenida en este documento tiene el objetivo de demostrar cómo realizar la integración entre Fluig y aplicaciones externas. Para una comprensión completa de esta información, algunos conocimientos se consideran requisitos previos, incluyendo entre ellos:
- Visión general del producto Fluig
- Visión general de la integración de sistemas
- JavaScript
- WebServices
- SOAP
Progress® 4GL
- Progress® Open App Server
- Progress® Open Client for Java
- Datasets (Fluig)
- Java™
- Apache Flex®
En varias partes de este documento se presentarán fragmentos de código en diferentes lenguajes de programación, con el fin de demostrar el uso de las capacidades de integración de Fluig. Sin embargo, este documento no pretende capacitar al lector en el uso de estas tecnologías más allá de los fines anteriormente descritos, siendo responsabilidad del lector buscar información en profundidad sobre estos lenguajes.
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).
Con la llegada de las tecnologías de Sistema de Información, varios sistemas comenzaron a apoyar estos procesos de negocio, en especial aquellos considerados más críticos para la operación de la empresa. El mejor ejemplo de ello es la adopción de los sistemas ERP que ofrecen soporte a los procesos de varias áreas de la empresa.
Fluig pretende ser una plataforma agnóstica de gestión de procesos, documentos e identidades a través de una interfaz de comunicación colaborativa. Esto se puede percibir en mayor o menor grado en cada una de sus funcionalidades, desde las más simples (como la colaboración) hasta las más complejas (como DM y BPM).
No obstante, parte de estos procesos dependen en gran medida de los sistemas de información ya existentes en la empresa y por esta razón, la arquitectura de Fluig está diseñada para permitir la integración a estos sistemas, permitiendo que los procesos modelados tengan mayor valor agregado.
Fluig permite tanto el acceso por el producto a los sistemas externos (para consultar o alimentar la información) como también posibilita que otros sistemas se conecten para consultar información o para ejecutar operaciones de transacción.
El principal canal de integración del producto es a través de WebServices, que se están convirtiendo en el estándar más común de integración con cualquier aplicación. A través de ellos, se puede tener acceso a las funcionalidades de Fluig y ofrecer acceso por medio del producto a aplicaciones externas. Este documento dedica una sección específica a la integración a través de WebServices.
La otra forma de integración es a través de llamadas a Progress® Open AppServer, que se recomienda para usuarios que necesitan integrar Fluig 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 Fluig
Fluig 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:
Sem Formato |
---|
http://<host>:<porta>/webdesk/services |
Cada link que se muestra dirige el navegador a la URL de WSDL del servicio. WSDL (Web Servicio Description Language) tiene la descripción del servicio en formato XML y lo utilizan las herramientas de desarrollo para crear componentes que representarán este servicio.
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:
|
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.
Utilice el paso a paso para visualizar el proceso de creación de los stubs para un servicio ofrecido por Fluig:
Deck of Cards | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Informações |
---|
Para o exemplo apresentado abaixo, foi utilizado a IDE Adobe® Flex™ Builder™ 3.0 com Flex® SDK 3.2. Para outras versões da IDE e/ou SDK, o processo para criação dos stubs pode sofrer algumas variações. |
O trecho de código abaixo apresenta um exemplo de invocação do WebService de acesso aos Datasets do Fluig:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="{this.start()}">
<mx:Script>
<![CDATA[
import generated.webservices.ValuesDto;
import generated.webservices.DatasetDto;
import generated.webservices.GetDatasetResultEvent;
import generated.webservices.SearchConstraintDtoArray;
import generated.webservices.StringArray;
import generated.webservices.ECMDatasetServiceService;
import mx.rpc.events.FaultEvent;
import mx.collections.ArrayCollection;
//Cria uma instância do Stub de acesso ao serviço
private var ds:ECMDatasetServiceService = new ECMDatasetServiceService();
public function start() : void {
//Cria tipos auxiliares, que serão utilizados na chamado do serviço
var fields:StringArray = new StringArray();
var constraints:SearchConstraintDtoArray = new SearchConstraintDtoArray();
var order:StringArray = new StringArray();
//Define as funções para tratamento do retorno
ds.addEventListener(GetDatasetResultEvent.GetDataset_RESULT, resultGetDataset);
ds.addEventListener(FaultEvent.FAULT,faultGetDataset);
//invoca o método getDataset do serviço
ds.getDataset("adm", 1, "adm", constraints, order, fields, "colleague");
}
//Tratamento dos dados retornados do serviço invocado.
public function resultGetDataset(ev:GetDatasetResultEvent) : void {
//Recupera o retorno do serviço, na forma de um DatasetDto
var dataset:DatasetDto = ev.result as DatasetDto;
//Monta uma string com todos os dados do dataset
var line:String = "";
//Cabeçalho com o nome dos campos
var columnsArray:ArrayCollection = new ArrayCollection(dataset.columns);
for (var j:int = 0; j < columnsArray.length; j++) {
line += columnsArray.getItemAt(j) + "\t";
}
//Linha de dados
var valuesArray:ArrayCollection = new ArrayCollection(dataset.values);
for (var j:int = 0; j < valuesArray.length; j++) {
var row:ValuesDto = valuesArray.getItemAt(j) as ValuesDto;
line += "\n" + j + ":";
for (var i:int = 0; i < row.length; i++) {
line += row.getItemAt(i) + "\t";
}
}
//Mostra a string criada em um textarea na tela
this.sysout.text = line;
}
public function faultGetDataset(ev:FaultEvent) : void {
this.sysout.text = ev.fault.faultString;
}
]]>
</mx:Script>
<mx:TextArea id="sysout" name="sysout" width="100%" height="100%"
paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5"/>
</mx:Application> |
Nota | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Existe um bug do Flex® que impede o funcionamento correto de serviços que trabalhem com matrizes multidimensionais de dados, como no exemplo acima, onde é retornado um array (de linhas do Dataset) de array (das colunas de cada registro). Para contornar este problema, é preciso alterar a classe gerada pelo Flex™ Builder™ que irá encapsular o array multidimensional. No exemplo acima, este classe é a DatasetDto, que deverá ser alterada (linha 11) conforme o exemplo abaixo:
Outros serviços que não trabalhem com arrays multidimensionais não exigem alterações no código gerado. |
Via Java™
Existem muitas implementações de uso de WebServices em Java™ e neste exemplo vamos utilizar as bibliotecas disponíveis no Java™ 7.
Da mesma forma como no exemplo anterior, em Apache Flex®, o primeiro passo consiste em utilizar o endereço WSDL para a geração dos stubs em Java™. O comando abaixo apresenta um exemplo de como gerar estes stubs:
Sem Formato |
---|
wsimport -d <output_directory> <wsdl_url> |
Através deste comando são gerados os stubs no diretório de destino (output_directory), conforme a descrição do arquivo wsdl (wsdl_url).
Integração Com Aplicativos Externos > image2013-8-20 16:0:2.png" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-20%2016%3A0%3A2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/image2013-8-20%2016%3A0%3A2.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406803" data-linked-resource-type="attachment" data-linked-resource-default-alias="image2013-8-20 16:0:2.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > image2013-8-20 16:0:2.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-20%2016%3A0%3A2.png?version=1&modificationDate=1377284793000&api=v2">
A partir dos stubs gerados, é possível consumir o WebService como no exemplo abaixo:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
package com.fluig.examples;
import javax.xml.ws.BindingProvider;
import net.java.dev.jaxb.array.StringArray;
import com.totvs.technology.ecm.dataservice.ws.DatasetDto;
import com.totvs.technology.ecm.dataservice.ws.DatasetService;
import com.totvs.technology.ecm.dataservice.ws.ECMDatasetServiceService;
import com.totvs.technology.ecm.dataservice.ws.SearchConstraintDtoArray;
import com.totvs.technology.ecm.dataservice.ws.ValuesDto;
/*
* Classe para invocar serviço DatasetService
*/
public class ECMDatasetServiceClient {
//Instancia DatasetServiceService.
private ECMDatasetServiceService ecmDatasetServiceService = new ECMDatasetServiceService();
private DatasetService service = ecmDatasetServiceService.getDatasetServicePort();
//Inicia execução da classe
public static void main(String[] args) {
ECMDatasetServiceClient client = new ECMDatasetServiceClient();
//Configura acesso ao WebServices.
BindingProvider bp = (BindingProvider) client.service;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://localhost:8080/webdesk/ECMDatasetService");
try {
client.getDataset();
} catch (Exception e) {
e.printStackTrace();
}
}
public void getDataset() throws Exception {
//Cria os parâmetros utilizados na chamada
int companyId = 1;
String username = "adm";
String password = "adm";
String name = "colleague";
StringArray fields = new StringArray();
SearchConstraintDtoArray constraints = new SearchConstraintDtoArray();
StringArray order = new StringArray();
//Invoca o serviço de dataset
DatasetDto result = service.getDataset(
companyId, username, password, name, fields, constraints, order);
//Apresenta o cabeçalho
for (String columnName : result.getColumns()) {
System.out.print(columnName + "\t");
}
System.out.println();
//Apresenta as linhas do dataset
for (ValuesDto row : result.getValues()) {
for (Object value : row.getValue()) {
System.out.print(value + "\t");
}
System.out.println();
}
}
} |
Nota | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Ao utilizar os WebServices via Java™, deve-se atentar para o tipo de cada atributo e para o tipo de retorno do WebService. Por exemplo, para valores do tipo data deve ser utilizado a classe XMLGregorianCalendar:
|
Via Progress® 4GL
Assim como nos exemplos anteriores, o primeiro passo para consumir um Webservice em Progress® é utilizar um utilitário que irá ler o endereço WSDL e gerar as informações necessárias para acessá-lo. Diferente do Java™ e Flex®, o Progress® não gera objetos de stub, mas apenas uma documentação sobre como consumir os serviços descritos no arquivo WSDL. Embora em algumas situações seja possível utilizar os tipos nativos do Progress® como parâmetros, dependendo do tipo de dado utilizado é preciso manipular o XML SOAP para extrair ou enviar uma informação.
Para gerar a documentação de um serviço, deve-se utilizar o utilitário bprowsdldoc como no exemplo abaixo:
Sem Formato |
---|
bprowsdldoc <URL_TO_WSDL> |
Com a execução deste utilitário, serão gerados alguns arquivos HTML com as informações sobre como consumir o serviço. Esta documentação apresenta informações e exemplos de como realizar a conexão com o serviçoe e a utilizar as métodos e datatypes do serviço.
O código abaixo apresenta um exemplo de como consumir o serviço:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
/* 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",
| ||||||||||
HTML | ||||||||||
<div id="main-content" class="wiki-content group"> <h1 id="IntegraçãoComAplicativosExternos-Índice">Índice</h1> <p> </p> <p> <style type='text/css'>/*<![CDATA[*/ div.rbtoc1412695546456 { padding: 0px; } div.rbtoc1412695546456 ul { list-style: none; margin-left: 0px; } div.rbtoc1412695546456 li { margin-left: 0px; padding-left: 0px; } /*]]>*/ </style> <div class='toc-macro rbtoc1412695546456'> <ul class='toc-indentation'> <li><span class='TOCOutline'>1</span> <a href='#IntegraçãoComAplicativosExternos-ConsideraçõesGerais'>Consideraciones Generales</a></li> <li><span class='TOCOutline'>2</span> <a href='#IntegraçãoComAplicativosExternos-VisãoGeral'>Visión General</a></li> <li><span class='TOCOutline'>3</span> <a href='#IntegraçãoComAplicativosExternos-WebServices'>WebServices</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.1</span> <a href='#IntegraçãoComAplicativosExternos-AcessandoosWebServicesdoFluig'>Acceso a WebServices de Fluig</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.1.1</span> <a href='#IntegraçãoComAplicativosExternos-ViaApacheFlex®'>Vía Apache Flex®</a></li> <li><span class='TOCOutline'>3.1.2</span> <a href='#IntegraçãoComAplicativosExternos-ViaJava™'>Vía Java™</a></li> <li><span class='TOCOutline'>3.1.3</span> <a href='#IntegraçãoComAplicativosExternos-ViaProgress®4GL'>Vía Progress® 4GL</a></li> </ul></li> <li><span class='TOCOutline'>3.2</span> <a href='#IntegraçãoComAplicativosExternos-AcessandoWebServicesapartirdoFluig'>Acceso a WebServices desde Fluig</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.2.1</span> <a href='#IntegraçãoComAplicativosExternos-WebServicescomAutenticaçãoBásica'>WebServices con Autenticación Básica</a></li> <li><span class='TOCOutline'>3.2.2</span> <a href='#IntegraçãoComAplicativosExternos-WebServicecomclientcustomizado'>WebService con cliente personalizado</a></li> </ul></li> <li><span class='TOCOutline'>3.3</span> <a href='#IntegraçãoComAplicativosExternos-CasodeUso'>Caso de Uso</a></li> <li><span class='TOCOutline'>3.4</span> <a href='#IntegraçãoComAplicativosExternos-ConfiguraçãodoAppServer'>Configuración de AppServer</a></li> <li><span class='TOCOutline'>3.5</span> <a href='#IntegraçãoComAplicativosExternos-Expondocódigos4GLcomProxyGen'>Exponiendo códigos 4GL con ProxyGen</a></li> <li><span class='TOCOutline'>3.6</span> <a href='#IntegraçãoComAplicativosExternos-ConfiguraçãodoServiçonoFluig'>Configuración del Servicio en Fluig</a></li> <li><span class='TOCOutline'>3.7</span> <a href='#IntegraçãoComAplicativosExternos-VisãoGeraldosObjetosEnvolvidos'>Visión general de los objetos involucrados</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.7.1</span> <a href='#IntegraçãoComAplicativosExternos-ProceduresPersistenteseNão-Persistentes'>Procedures Persistentes y No Persistentes</a></li> <li><span class='TOCOutline'>3.7.2</span> <a href='#IntegraçãoComAplicativosExternos-ParâmetrosdeEntradaeSaída'>Parámetros de Entrada y Salida</a></li> </ul></li> <li><span class='TOCOutline'>3.8</span> <a href='#IntegraçãoComAplicativosExternos-CriaçãodosDatasets'>Creación de los Datasets</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.8.1</span> <a href='#IntegraçãoComAplicativosExternos-TiposdeCentrodeCusto'>Tipos de Centro de Costo</a></li> <li><span class='TOCOutline'>3.8.2</span> <a href='#IntegraçãoComAplicativosExternos-NaturezadosCentrosdeCusto'>Naturaleza de los Centros de Costo</a></li> <li><span class='TOCOutline'>3.8.3</span> <a href='#IntegraçãoComAplicativosExternos-CentrosdeCusto'>Centros de Costo</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.8.3.1</span> <a href='#IntegraçãoComAplicativosExternos-CodificaçãoProgress®9'>Codificación Progress® 9</a></li> <li><span class='TOCOutline'>3.8.3.2</span> <a href='#IntegraçãoComAplicativosExternos-CodificaçãoOpenEdge®10'>Codificación OpenEdge® 10</a></li> </ul></li> <li><span class='TOCOutline'>3.8.4</span> <a href='#IntegraçãoComAplicativosExternos-UsuáriosemComum'>Usuarios en Común</a> <ul class='toc-indentation'> <li><span class='TOCOutline'>3.8.4.1</span> <a href='#IntegraçãoComAplicativosExternos-CodificaçãoProgress®9.1'>Codificación Progress® 9</a></li> <li><span class='TOCOutline'>3.8.4.2</span> <a href='#IntegraçãoComAplicativosExternos-CodificaçãoOpenEdge®10.1'>Codificación OpenEdge® 10</a></li> </ul></li> </ul></li> <li><span class='TOCOutline'>3.9</span> <a href='#IntegraçãoComAplicativosExternos-ServiceHelper'>Service Helper</a></li> </ul></li> <li><span class='TOCOutline'>4</span> <a href='#IntegraçãoComAplicativosExternos-ThirdPartyTrademarks'>Third Party Trademarks</a></li> </ul> </div> </p> <h1 id="IntegraçãoComAplicativosExternos-ConsideraçõesGerais">Consideraciones Generales</h1> <p>La información contenida en este documento tiene el objetivo de demostrar cómo realizar la integración entre Fluig y aplicaciones externas. Para una comprensión completa de esta información, algunos conocimientos se consideran requisitos previos, incluyendo entre ellos:</p> <ul> <li class="O1">Visión general del producto Fluig</li> <li class="O1">Visión general de la integración de sistemas</li> <li class="O1">JavaScript</li> <li class="O1">WebServices</li> <li class="O1">SOAP</li> <li class="O1"><p> <span style="font-size: 10.0pt; line-height: 13.0pt;">Progress® 4GL</span> </p></li> <li class="O1">Progress® Open App Server</li> <li class="O1">Progress® Open Client for <span style="font-size: 10.0pt; line-height: 13.0pt;">Java</span></li> <li class="O1">Datasets (Fluig)</li> <li class="O1">Java™</li> <li class="O1">Apache Flex®</li> </ul> <p>En varias partes de este documento se presentarán fragmentos de código en diferentes lenguajes de programación, con el fin de demostrar el uso de las capacidades de integración de Fluig. Sin embargo, este documento no pretende capacitar al lector en el uso de estas tecnologías más allá de los fines anteriormente descritos, siendo responsabilidad del lector buscar información en profundidad sobre estos lenguajes.</p> <p>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.</p> <h1 id="IntegraçãoComAplicativosExternos-VisãoGeral">Visión General</h1> <p>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).</p> <p>Con la llegada de las tecnologías de Sistema de Información, varios sistemas comenzaron a apoyar estos procesos de negocio, en especial aquellos considerados más críticos para la operación de la empresa. El mejor ejemplo de ello es la adopción de los sistemas ERP que ofrecen soporte a los procesos de varias áreas de la empresa.</p> <p>Fluig pretende ser una plataforma agnóstica de gestión de procesos, documentos e identidades a través de una interfaz de comunicación colaborativa. Esto se puede percibir en mayor o menor grado en cada una de sus funcionalidades, desde las más simples (como la colaboración) hasta las más complejas (como DM y BPM).</p> <p>No obstante, parte de estos procesos dependen en gran medida de los sistemas de información ya existentes en la empresa y por esta razón, la arquitectura de Fluig está diseñada para permitir la integración a estos sistemas, permitiendo que los procesos modelados tengan mayor valor agregado.</p> <p>Fluig permite tanto el acceso por el producto a los sistemas externos (para consultar o alimentar la información) como también posibilita que otros sistemas se conecten para consultar información o para ejecutar operaciones de transacción.</p> <p> </p> <p> <img class="confluence-embedded-image image-center" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-20%2015%3A33%3A42.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-20%2015%3A33%3A42.png?version=1&modificationDate=1377284793000&api=v2"> </p> <p> </p> <p>El principal canal de integración del producto es a través de WebServices, que se están convirtiendo en el estándar más común de integración con cualquier aplicación. A través de ellos, se puede tener acceso a las funcionalidades de Fluig y ofrecer acceso por medio del producto a aplicaciones externas. Este documento dedica una sección específica a la integración a través de WebServices.</p> <p>La otra forma de integración es a través de llamadas a Progress® Open AppServer, que se recomienda para usuarios que necesitan integrar Fluig con aplicaciones desarrolladas en esta plataforma.</p> <h1 id="IntegraçãoComAplicativosExternos-WebServices">WebServices</h1> <p>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.</p> <h3 id="IntegraçãoComAplicativosExternos-AcessandoosWebServicesdoFluig">Acceso a WebServices de Fluig</h3> <p> Fluig 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. <span style="font-size: 10.0pt; line-height: 13.0pt;">Para tener la lista de los WebServices disponibles, ingrese a: </span> </p> <div class="preformatted panel" style="border-width: 1px;"> <div class="preformattedContent panelContent"> <pre>http://<host>:<porta>/webdesk/services </pre> </div> </div> <p>Cada link que se muestra dirige el navegador a la URL de WSDL del servicio. WSDL (Web Servicio Description Language) tiene la descripción del servicio en formato XML y lo utilizan las herramientas de desarrollo para crear componentes que representarán este servicio.</p> <div class="aui-message warning shadowed information-macro"> <span class="aui-icon icon-warning">Icon</span> <div class="message-content"> <p>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:</p> <ul> <li>C#: <strong>dateTime</strong></li> <li>Java™: <strong>XMLGregorianCalendar</strong></li> <li>Progress®: <strong>DATETIME-TZ</strong></li> </ul> </div> </div> <p> </p> <h5 id="IntegraçãoComAplicativosExternos-ViaApacheFlex®">Vía Apache Flex®</h5> <p>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.</p> <p>Utilice el paso a paso para visualizar el proceso de creación de los stubs para un servicio ofrecido por Fluig:</p> <a name="composition-deck-stubFlex"></a> <div id="stubFlex" class="deck" history="false" loopcards="false" effecttype="" effectduration="1.0" nextafter="0.0"> <ul class="tab-navigation"></ul> <!-- // .tab-navigation --> <div class="deck-cards panel" style=""> <div id="1" class="deck-card active-pane" style="" cssclass="" accesskey="" label="1&ordm; Passo" title="" nextafter="0" effecttype="fade" effectduration="0.5"> <p>La creación de los stubs en Flex® se lleva a cabo a través del menú Data, opción Import WebService(WSDL), como muestra la siguiente imagen.</p> <p> <img class="confluence-embedded-image" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A30%3A3.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A30%3A3.png?version=1&modificationDate=1377284793000&api=v2"> </p> </div> <div id="2" class="deck-card " style="" cssclass="" accesskey="" label="2&ordm; Passo" title="" nextafter="0" effecttype="fade" effectduration="0.5"> <p>En la primera ventana, se solicita la carpeta dentro del proyecto actual donde deben generarse los stubs.</p> <p> <img class="confluence-embedded-image" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A34%3A29.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A34%3A29.png?version=1&modificationDate=1377284793000&api=v2"> </p> </div> <div id="3" class="deck-card " style="" cssclass="" accesskey="" label="3&ordm; Passo" title="" nextafter="0" effecttype="fade" effectduration="0.5"> <p>En la siguiente pantalla, se debe informar la dirección de WSDL donde se encuentra el servicio. También se puede definir si se accede desde la estación de cliente o desde el servidor LiveCycle Data Services.</p> <p> <img class="confluence-embedded-image" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A36%3A18.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A36%3A18.png?version=1&modificationDate=1377284793000&api=v2"> </p> </div> <div id="4" class="deck-card " style="" cssclass="" accesskey="" label="4&ordm; Passo" title="" nextafter="0" effecttype="fade" effectduration="0.5"> <p>En la última pantalla, se debe informar el package que se utilizará y cuál es el nombre de la clase principal (ya sugeridos por Flex™ Builder™).</p> <p> <img class="confluence-embedded-image" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A39%3A19.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A39%3A19.png?version=1&modificationDate=1377284793000&api=v2"> </p> </div> <div id="5" class="deck-card " style="" cssclass="" accesskey="" label="Resultado" title="" nextafter="0" effecttype="fade" effectduration="0.5"> <p>Una vez finalizado el proceso, Flex ™ Builder ™ agregará al proyecto un conjunto de clases que serán utilizadas por el programador para invocar los servicios, como se muestra a continuación:</p> <p> <img class="confluence-embedded-image" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A57%3A40.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-21%2010%3A57%3A40.png?version=1&modificationDate=1377284793000&api=v2"> </p> </div> </div> </div> <!-- // .deck --> <div class="aui-message hint shadowed information-macro"> <span class="aui-icon icon-hint">Icon</span> <div class="message-content"> <p> Para el ejemplo que se presenta a continuación, se utilizó IDE Adobe® Flex™ Builder™ 3.0 con Flex® SDK 3.2. Para otras versiones de IDE y/o SDK, el proceso de creación de los stubs puede sufrir algunas variaciones.<span style="font-size: 10.0pt; line-height: 13.0pt;"> </span> </p> </div> </div> <p>El siguiente fragmento de código presenta un ejemplo de invocación de WebService de acceso a los Datasets de Fluig:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>ECMDatasetServiceClient.mxml</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: actionscript3; gutter: true" style="font-size: 12px;"><?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="{this.start()}"> <mx:Script> <![CDATA[ import generated.webservices.ValuesDto; import generated.webservices.DatasetDto; import generated.webservices.GetDatasetResultEvent; import generated.webservices.SearchConstraintDtoArray; import generated.webservices.StringArray; import generated.webservices.ECMDatasetServiceService; import mx.rpc.events.FaultEvent; import mx.collections.ArrayCollection; //Crea una instancia de stub de acceso al servicio private var ds:ECMDatasetServiceService = new ECMDatasetServiceService(); public function start() : void { //Crea tipos auxiliares que se utilizarán en la llamada de servicio var fields:StringArray = new StringArray(); var constraints:SearchConstraintDtoArray = new SearchConstraintDtoArray(); var order:StringArray = new StringArray(); //Define las funciones para tratamiento de la devolución ds.addEventListener(GetDatasetResultEvent.GetDataset_RESULT, resultGetDataset); ds.addEventListener(FaultEvent.FAULT,faultGetDataset); //invoca el método getDataset del servicio ds.getDataset("adm", 1, "adm", constraints, order, fields, "colleague"); } //Tratamiento de los datos devueltos por el servicio invocado. public function resultGetDataset(ev:GetDatasetResultEvent) : void { //Recupera la devolución del servicio, en forma de un DatasetDto var dataset:DatasetDto = ev.result as DatasetDto; //Instala una string con todos los datos del dataset var line:String = ""; //Encabezado con el nombre de los campos var columnsArray:ArrayCollection = new ArrayCollection(dataset.columns); for (var j:int = 0; j < columnsArray.length; j++) { line += columnsArray.getItemAt(j) + "\t"; } //Línea de datos var valuesArray:ArrayCollection = new ArrayCollection(dataset.values); for (var j:int = 0; j < valuesArray.length; j++) { var row:ValuesDto = valuesArray.getItemAt(j) as ValuesDto; line += "\n" + j + ":"; for (var i:int = 0; i < row.length; i++) { line += row.getItemAt(i) + "\t"; } } //Muestra la string creada en un textarea en la pantalla this.sysout.text = line; } public function faultGetDataset(ev:FaultEvent) : void { this.sysout.text = ev.fault.faultString; } ]]> </mx:Script> <mx:TextArea id="sysout" name="sysout" width="100%" height="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5"/> </mx:Application></pre> </div> </div> <div class="aui-message warning shadowed information-macro"> <span class="aui-icon icon-warning">Icon</span> <div class="message-content"> <p>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).</p> <p>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:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: actionscript3; gutter: true" style="font-size: 12px;">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 }</pre> </div> </div> <p>Otros servicios que no trabajan con arrays multidimensionales no exigen cambios en el código generado.</p> </div> </div> <p> </p> <h5 id="IntegraçãoComAplicativosExternos-ViaJava™">Vía Java™</h5> <p>Existen muchas implementaciones de uso de WebServices en Java ™ y en este ejemplo vamos a utilizar las bibliotecas disponibles en Java ™ 7.</p> <p>Del mismo modo que en el ejemplo anterior, en Apache Flex®, el primer paso consiste en utilizar la dirección WSDL para generar los stubs en Java ™. El siguiente comando presenta un ejemplo de cómo generar estos stubs:</p> <div class="preformatted panel" style="border-width: 1px;"> <div class="preformattedContent panelContent"> <pre>wsimport -d <output_directory> <wsdl_url></pre> </div> </div> <p>A través de este comando se generan los stubs en el directorio de destino (output_directory), según la descripción del archivo wsdl (wsdl_url).</p> <p> <img class="confluence-embedded-image" src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-20%2016%3A0%3A2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/image2013-8-20%2016%3A0%3A2.png?version=1&modificationDate=1377284793000&api=v2"> </p> <p>A partir de los stubs generados, se puede consumir el WebService como se muestra en el siguiente ejemplo:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>ECMDatasetServiceClient.java</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: java; gutter: true" style="font-size: 12px;">package com.fluig.examples; import javax.xml.ws.BindingProvider; import net.java.dev.jaxb.array.StringArray; import com.totvs.technology.ecm.dataservice.ws.DatasetDto; import com.totvs.technology.ecm.dataservice.ws.DatasetService; import com.totvs.technology.ecm.dataservice.ws.ECMDatasetServiceService; import com.totvs.technology.ecm.dataservice.ws.SearchConstraintDtoArray; import com.totvs.technology.ecm.dataservice.ws.ValuesDto; /* * Clase para invocar servicio DatasetService */ public class ECMDatasetServiceClient { //Instancia DatasetServiceService. private ECMDatasetServiceService ecmDatasetServiceService = new ECMDatasetServiceService(); private DatasetService service = ecmDatasetServiceService.getDatasetServicePort(); //Inicia ejecución de la clase public static void main(String[] args) { ECMDatasetServiceClient client = new ECMDatasetServiceClient(); //Configura acceso a WebServices. BindingProvider bp = (BindingProvider) client.service; bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8080/webdesk/ECMDatasetService"); try { client.getDataset(); } catch (Exception e) { e.printStackTrace(); } } public void getDataset() throws Exception { //Crea los parámetros utilizados en la llamada int companyId = 1; String username = "adm"; String password = "adm"; String name = "colleague"; StringArray fields = new StringArray(); SearchConstraintDtoArray constraints = new SearchConstraintDtoArray(); StringArray order = new StringArray(); //Invoca el servicio de dataset DatasetDto result = service.getDataset( companyId, username, password, name, fields, constraints, order); //Presenta el encabezado for (String columnName : result.getColumns()) { System.out.print(columnName + "\t"); } System.out.println(); //Presenta las líneas del dataset for (ValuesDto row : result.getValues()) { for (Object value : row.getValue()) { System.out.print(value + "\t"); } System.out.println(); } } }</pre> </div> </div> <div class="aui-message warning shadowed information-macro"> <span class="aui-icon icon-warning">Icon</span> <div class="message-content"> <p> 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 tipo <strong>fecha </strong>se debe utilizar la clase <strong>XMLGregorianCalendar:</strong> </p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: java; gutter: true" style="font-size: 12px;">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);</pre> </div> </div> </div> </div> <p> </p> <h5 id="IntegraçãoComAplicativosExternos-ViaProgress®4GL">Vía Progress® 4GL</h5> <p>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.</p> <p> Para generar la documentación de un servicio, se debe utilizar la utilidad <strong>bprowsdldoc</strong> como en el siguiente ejemplo: </p> <div class="preformatted panel" style="border-width: 1px;"> <div class="preformattedContent panelContent"> <pre>bprowsdldoc <URL_TO_WSDL></pre> </div> </div> <p>Mediante la ejecución de esta utilidad se generarán algunos archivos HTML con la información sobre la forma de consumir el servicio. Esta documentación proporciona información y ejemplos de cómo llevar a cabo la conexión con el servicio y cómo utilizar los métodos y datatypes del servicio. </p> <p> <span style="font-size: 10.0pt; line-height: 13.0pt;">El siguiente código presenta un ejemplo de cómo consumir el servicio:</span> </p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>wsECMDatasetService.p</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javafx; gutter: true" style="font-size: 12px;">/* Parte I - Invocar el 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 ítem 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 ítem. 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 - Realiza el parser de XML y crear un archivo de texto separado por tabulación */ 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). /* Recorre las columnas <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. /* Recorre los registros <values> */ DO iCount = 1 TO hRoot:NUM-CHILDREN WITH 20 DOWN: hRoot:GET-CHILD(hValues, iCount). IF hValues:NAME <> "values" THEN NEXT. /* Recorre los 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.</pre> </div> </div> <h3 id="IntegraçãoComAplicativosExternos-AcessandoWebServicesapartirdoFluig">Acceso a WebServices desde Fluig</h3> <p>Fluig permite realizar llamadas a WebServices de terceros a través del registro de Servicios en la visualización de Servicios de Fluig Studio.</p> <p> Para agregar un nuevo WebService, es necesario ingresar a la opción <strong>Incluir Servicio, </strong>abriendo el asistente Nuevo Servicio, e informar al servidor de Fluig donde se agregará el servicio, <span style="font-size: 10.0pt; line-height: 13.0pt;">un código identificador para él, su descripción, la URL para WSDL y su tipo (en este caso WebService). </span><span style="font-size: 10.0pt; line-height: 13.0pt;">En el siguiente ejemplo, se utilizará un WebService público para consultar la tabla periódica, cuya dirección de WSDL es </span><span class="nolink" style="font-size: 10.0pt; line-height: 13.0pt;"><a href="http://www.webservicex.com/periodictable.asmx?wsdl" class="external-link" rel="nofollow">http://www.webservicex.com/periodictable.asmx?wsdl</a></span><span style="font-size: 10.0pt; line-height: 13.0pt;">.</span> </p> <p> <span style="font-size: 10.0pt; line-height: 13.0pt;"><img class="confluence-embedded-image image-center" src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-1.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-1.png?version=1&modificationDate=1377284793000&api=v2"></span> </p> <p>Basado en esta información, Fluig extraerá la información sobre el WebService informado y finalizará el registro de este servicio. </p> <p> <span style="font-size: 10.0pt; line-height: 13.0pt;">Una vez que el servicio está registrado, se pueden ver las clases y métodos disponibles en este servicio y que se utilizarán en los códigos JavaScript que lo usarán. La siguiente pantalla presenta un ejemplo de visualización de WebService.</span> </p> <p> <span style="font-size: 10.0pt; line-height: 13.0pt;"><img class="confluence-embedded-image image-center" src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-2.png?version=1&modificationDate=1377284793000&api=v2"></span> </p> <p> Los servicios agregados en Fluig se pueden instanciar y utilizar en los puntos donde el producto permite personalización utilizando JavaScript, como en scripts para eventos globales, eventos de procesos, eventos de definición de formulario o Datasets. <span style="font-size: 10.0pt; line-height: 13.0pt;">En el siguiente ejemplo se creará un Dataset que usará este servicio para traer los datos de la tabla periódica.</span> </p> <p>El siguiente código presenta una implementación de ejemplo del uso de un servicio en la construcción de un Dataset:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>periodicTable.js</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">function createDataset(fields, constraints, sortFields) { //Crea el dataset var dataset = DatasetBuilder.newDataset(); dataset.addColumn("elementName"); // Conecta el servicio y busca los libros var periodicService = ServiceManager.getService('PeriodicTable'); var serviceHelper = periodicService.getBean(); var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable'); var service = serviceLocator.getPeriodictableSoap(); //Invoca el servicio try { var result = service.getAtoms(); var NewDataSet = new XML(result); for each(element in NewDataSet.Table) { dataset.addRow(new Array(element.ElementName.toString())); } } catch(erro) { dataset.addRow(new Array(erro)); } return dataset; }</pre> </div> </div> <p> El primer paso para invocar el servicio es solicitar a Fluig que cargue el servicio, a partir del método <strong>ServiceManager.getService('PeriodicTable')</strong>. El valor informado como parámetro debe ser el código utilizado cuando se registró el servicio. </p> <p> Cuando el servicio se haya cargado, se utiliza el método <strong>getBean()</strong> para devolver una utilidad para acceder a las clases del servicio, a través del método <strong>instantiate</strong>. A través de esta utilidad, se pueden instanciar las clases disponibles, que se encuentran en el registro del Servicio (como se puede ver en la imagen anterior). </p> <p>Después de que se haya instanciado el objeto utilidad del servicio, las clases se deben instanciar y los métodos que se deben invocar depende de cada WebService utilizado y, deben recurrir a su documentación para obtener más información.</p> <p>Para el servicio de la tabla periódica es necesario realizar los siguientes pasos:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable'); var service = serviceLocator.getPeriodictableSoap(); var result = service.getAtoms();</pre> </div> </div> <p>Donde:</p> <ul> <li><p> <strong>Paso 1: </strong>Instanciar la clase <strong><span style="font-size: 10.0pt; line-height: 13.0pt;">net.webservicex.Periodictable</span></strong><span style="font-size: 10.0pt; line-height: 13.0pt;"> para tener acceso al localizador del servicio; </span> </p></li> <li><span style="font-size: 10.0pt; line-height: 13.0pt;"><strong>Paso 2:</strong> Invocar el método <strong>getPeriodictableSoap</strong> para instanciar el servicio;</span></li> <li><span style="font-size: 10.0pt; line-height: 13.0pt;"><strong>Paso 3:</strong> Invocar el método <strong>getAtoms</strong> para tener la lista de los elementos.</span><br /> <span style="font-size: 10.0pt; line-height: 13.0pt;"><br /></span></li> </ul> <p> En el caso de este servicio, el método <strong>getAtoms</strong> devuelve una string que contiene un XML con la lista de todos los elementos, como se muestra en el siguiente ejemplo: </p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: html/xml; gutter: true" style="font-size: 12px;"><NewDataSet> <Table> <ElementName>Actinium</ElementName> </Table> <Table> <ElementName>Aluminium</ElementName> </Table> ... </NewDataSet></pre> </div> </div> <p> Para recorrer el XML y extraer los datos disponibles, se utilizan las funcionalidades de tratamiento de XML de JavaScript que facilita la manipulación de datos de este tipo. Para más información sobre esta funcionalidad, ingrese a : <a href="http://www.ecma-international.org/publications/standards/Ecma-357.htm" style="font-size: 10.0pt; line-height: 13.0pt;" class="external-link" rel="nofollow">http://www.ecma-international.org/publications/standards/Ecma-357.htm</a><span style="font-size: 10.0pt; line-height: 13.0pt;"> o </span><a href="http://www.xml.com/pub/a/2007/11/28/introducing-e4x.html" style="font-size: 10.0pt; line-height: 13.0pt;" class="external-link" rel="nofollow">http://www.xml.com/pub/a/2007/11/28/introducing-e4x.html</a><span style="font-size: 10.0pt; line-height: 13.0pt;">.</span> </p> <p>El siguiente ejemplo presenta el código utilizado para recorrer el XML devuelto:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">var NewDataSet = new XML(result); for each(element in NewDataSet.Table) { dataset.addRow(new Array(element.ElementName.toString())); }</pre> </div> </div> <p>Una vez implementado el código del Dataset, es posible visualizarlo, como muestra la siguiente figura:</p> <p> <img class="confluence-embedded-image image-center" src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-3.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-3.png?version=1&modificationDate=1377284793000&api=v2"> </p> <p> </p> <h5 id="IntegraçãoComAplicativosExternos-WebServicescomAutenticaçãoBásica">WebServices con Autenticación Básica</h5> <p> Para consumir WebServices que utilizan la autenticación básica (<em>WSS</em> o <em>WS-Security</em>), es necesario utilizar el método <strong>getBasicAuthenticatedClient </strong>localizado en provider del servicio (el mismo que se obtiene vía <strong>ServiceManager). </strong>Este método proporciona un client autenticado. </p> <p> </p> <p>Los parámetros que se deben informar en el método siguen el siguiente orden:</p> <ol> <li>Instancia del servicio</li> <li>Nombre de la clase del servicio</li> <li>Usuario para la autenticación</li> <li>Contraseña para la autenticación</li> </ol> <p> Utilizando el ejemplo del servicio <strong>PeriodicTable </strong>presentado anteriormente, el código de la llamada tendría los siguientes cambios: </p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable'); var service = serviceLocator.getPeriodictableSoap(); var authenticatedService = serviceHelper.getBasicAuthenticatedClient(service, "net.webservicex.PeriodictableSoap", 'usuario', 'contraseña'); var result = authenticatedService.getAtoms();</pre> </div> </div> <h5 id="IntegraçãoComAplicativosExternos-WebServicecomclientcustomizado"> <span style="color: rgb(0, 0, 0); font-size: 1.8em; font-weight: bold; line-height: normal;"><br /></span>WebService con client personalizado </h5> <div class="aui-message warning shadowed information-macro"> <p class="title">Atención</p> <span class="aui-icon icon-warning">Icon</span> <div class="message-content"> <p>Esta técnica es válida para Fluig 1.3.7 o superior.</p> <p>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".</p> </div> </div> <p> Para personalizar el client que accede al servicio se debe utilizar el método <strong>getCustomClient</strong>, localizado en provider del servicio (el mesmo que se obtiene vía <strong>ServiceManager</strong>). Esta configuración exige la creación de un mapa de parámetros con sus respectivos valores para pasar al método, según el siguiente <em style="line-height: 1.4285715;">snippet</em>: </p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeContent panelContent pdl"> <pre class="theme: Eclipse; brush: js; gutter: false" style="font-size: 12px;"> var properties = {}; properties["basic.authorization"] = "true"; properties["basic.authorization.username"] = "username"; properties["basic.authorization.password"] = "password"; properties["disable.chunking"] = "true"; properties["log.soap.messages"] = "true"; var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable'); var service = serviceLocator.getPeriodictableSoap(); var customClient = serviceHelper.getCustomClient(service, "net.webservicex.PeriodictableSoap", properties); var result = customClient.getAtoms();</pre> </div> </div> <p> </p> <p>Los parámetros que se pueden configurar son los siguientes:</p> <div class="table-wrap"> <table class="confluenceTable"> <tbody> <tr> <th class="confluenceTh">Propriedad</th> <th class="confluenceTh">Función</th> </tr> <tr> <td class="confluenceTd"><pre>basic.authorization</pre></td> <td class="confluenceTd"><p> Cuando se define como "true", hace lo mismo que el método <strong>getBasicAuthenticatedClient</strong>, pero permite aplicar la configuración de autenticación junto con las demás personalizaciones que se detallan a continuación. Para configurar la autenticación<span style="line-height: 1.4285715;">, las siguientes propiedades con "username" y "password" también necesitan definirse.</span> </p></td> </tr> <tr> <td class="confluenceTd"><pre>basic.authorization.username</pre></td> <td class="confluenceTd">Usuario que se utilizará para autenticación básica.</td> </tr> <tr> <td class="confluenceTd"><pre>basic.authorization.password</pre></td> <td class="confluenceTd">Contraseña de usuario utilizado para autenticación básica.</td> </tr> <tr> <td class="confluenceTd"><pre>disable.chunking</pre></td> <td class="confluenceTd"><p>Cuando se define como "true", desactiva el envío de solicitudes grandes en "fragmentos" menores. Puede ser útil cuando el servicio llamado no admite este tipo de solicitud.</p></td> </tr> <tr> <td colspan="1" class="confluenceTd"><pre>log.soap.messages</pre></td> <td colspan="1" class="confluenceTd">Cuando se define como "true", permite que los mensajes SOAP utilizados en las solicitudes realizadas a los servicios se presenten en el log del servidor, lo que facilita la depuración en caso de fallas.</td> </tr> </tbody> </table> </div> <p> </p> <p> <span style="color: rgb(0, 0, 0); font-size: 1.8em; font-weight: bold; line-height: normal;">Progress® Open AppServer</span> </p> <p>Así como es posible invocar operaciones en WebServices, Fluig también permite realizar llamadas a programas en Progress® 4GL (o ABL) expuestos vía Progress® Open AppServer.</p> <p>En los siguientes ejemplos, se crearán Datasets que a través de la capa de servicio, tendrán acceso a las lógicas en 4GL que realizarán la extracción de datos. Aunque los códigos 4GL, en este ejemplo, sean muy simples, abarcan los casos más comunes requeridos en el día a día, ya que la complejidad de la integración se encuentra en las interfaces (parámetros de entrada y salida) de cada procedure expuesto y no en su lógica interna.</p> <p>Tenga en cuenta que los ejemplos que aquí se presentan pretenden demostrar la dinámica de la integración entre Progress® y Fluig sin entrar en detalles específicos de las tecnologías involucradas. La capa de servicios Progress® de Fluig 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®.</p> <h3 id="IntegraçãoComAplicativosExternos-CasodeUso">Caso de Uso</h3> <p> Los ejemplos que se muestran a continuación, tienen como objetivo crear cuatro Datasets <sup>1</sup> en Fluig: </p> <ol> <li><strong>Tipos de Centro de Costo, </strong>que deben devolver los tipos de centros de coste existente en la aplicación en Progress® (en este caso, EMS2).</li> <li><strong>Naturaleza de los Centros de Costo, </strong>que debe devolver los tipos posibles de naturaleza, según la aplicación en Progress® (en este caso, EMS2).</li> <li><strong>Centros de Costo, </strong>que debe devolver los registros en la tabla cuenta <sup>2</sup>.</li> <li><p> <strong>Usuarios Comunes, </strong>que debe generar una lista de usuarios comunes entre Fluig y la aplicación en Progress® (utilizando la tabla usuar_mestre). </p> <div class="aui-message warning shadowed information-macro"> <span class="aui-icon icon-warning">Icon</span> <div class="message-content"> <p> <span>1 - Los ejemplos utilizan una base de datos de EMS2 para consultar los centros de costo y los usuarios. No obstante, sólo dos tablas y seis campos se utilizan en total, lo que no debe perjudicar la comprensión de la lógica por parte del lector, ni impedir la creación de un esquema equivalente para pruebas, en caso de ser necesario.</span> </p> <p> <span>2 - El código presentado para extracción de los centros de costo tiene fines puramente educativos y no puede considerarse para el uso en producción. Para obtener más información acerca de cómo extraer los centros de costos de EMS2, consulte su documentación técnica.</span> </p> </div> </div></li> </ol> <p>Para los tres primeros casos, la lógica de extracción de la información deseada estará expuesta en un programa con varios procedures, uno para cada necesidad que aquí se presenta:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>CostCenterUtils.p</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javafx; gutter: true" style="font-size: 12px;">/************************************************************************** ** Utilidad que ofrece procedures para la extracción de información ** sobre centros de costo. **************************************************************************/ DEFINE TEMP-TABLE ttCC NO-UNDO FIELD cuenta LIKE cuenta.ct-codigo /* CHARACTER */ FIELD naturaleza LIKE cuenta.naturaleza /* INTEGER */ FIELD tipo LIKE cuenta.tipo /* INTEGER */ FIELD titulo LIKE cuenta.titulo. /* CHARACTER */   /*------------------------------------------------------------------- Procedure: readCostCenters Objetivo: Devuelve una temp-table con la lista de centros de costo. ----------------------------------------------------------------------*/ PROCEDURE readCostCenters: DEFINE OUTPUT PARAMETER TABLE FOR ttCC. FOR EACH cuenta: CREATE ttCC. ASSIGN ttCC.cuenta = cuenta.ct-codigo ttCC.naturaleza = cuenta.naturaleza ttCC.tipo = cuenta.tipo ttCC.titulo = cuenta.titulo. END. END. /*------------------------------------------------------------------- Procedure: readCostNatureTypes Objetivo: Devuelve una string con las naturalezas de los centros de costo, separadas por coma. ----------------------------------------------------------------------*/ PROCEDURE readCostNatureTypes: DEFINE OUTPUT PARAMETER cNatureList AS CHARACTER NO-UNDO. cNatureList = {adinc/i01ad047.i 03}. END. /*------------------------------------------------------------------- Procedure: readCostTypes Objetivo: Devuelve una string con los tipos de centro de costo, separados por coma. ----------------------------------------------------------------------*/ PROCEDURE readCostTypes: DEFINE OUTPUT PARAMETER cTypeList AS CHARACTER NO-UNDO. cTypeList = {adinc/i02ad047.i 3}. END.</pre> </div> </div> <p>En el caso de la extracción de usuarios comunes a los dos productos, se utilizará un único programa, según el siguiente código:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>verifyUsers.p</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javafx; gutter: true" style="font-size: 12px;">/************************************************************************** ** Utilidad que recibe una temp-table con una lista de usuarios y devuelve ** otra, sólo con los usuarios de la lista que existan en la base de datos. **************************************************************************/ DEFINE TEMP-TABLE ttUsers FIELD cod_usuar AS CHARACTER FIELD nom_usuario AS CHARACTER INDEX principal IS PRIMARY UNIQUE cod_usuar. DEFINE TEMP-TABLE ttOutUsers LIKE ttUsers. DEFINE INPUT PARAMETER TABLE FOR ttUsers. DEFINE OUTPUT PARAMETER TABLE FOR ttOutUsers. FOR EACH ttUsers: IF CAN-FIND(usuar_mestre WHERE usuar_mestre.cod_usuar = ttUsers.cod_usuar) THEN DO: CREATE ttOutUsers. BUFFER-COPY ttUsers TO ttOutUsers. END. END.</pre> </div> </div> <p>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.</p> <h3 id="IntegraçãoComAplicativosExternos-ConfiguraçãodoAppServer"> <a name="_Toc324776230" rel="nofollow"></a>Configuración de AppServer </h3> <p>Algunas informaciones importantes en la configuración del AppServer:</p> <ol> <li>AppServer debe cargarse en el modo Stateless;</li> <li><p>En la configuración del agente, en el campo Propath, se debe agregar el directorio donde están ubicados los archivos compilados (.r).</p> <div class="aui-message warning shadowed information-macro"> <span class="aui-icon icon-warning">Icon</span> <div class="message-content"> <p> <strong>Importante:</strong> 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. </p> </div> </div></li> </ol> <h3 id="IntegraçãoComAplicativosExternos-Expondocódigos4GLcomProxyGen">Exponiendo códigos 4GL con ProxyGen</h3> <p> <span style="font-size: 10.0pt; font-family: Arial, sans-serif;">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.</span> </p> <p>Utilice el paso a paso para visualizar el proceso de creación del proxy:</p> <a name="composition-deck-proxyGen"></a> <div id="proxyGen" class="deck" history="false" loopcards="false" effecttype="fade" effectduration="0.5" nextafter="0.0"> <ul class="tab-navigation"></ul> <!-- // .tab-navigation --> <div class="deck-cards panel" style=""> <div id="1" class="deck-card active-pane" style="" cssclass="" accesskey="" label="1&ordm; Passo" title="" nextafter="0" effecttype="default" effectduration="-1.0"> <p> <span style="font-size: 10.0pt; line-height: 13.0pt; text-align: justify;">En la primera pantalla del ProxyGen, el punto principal que se debe tener en cuenta es el nombre del Proyecto (en el ejemplo, EMSProxies). La información de este campo será utilizada por ProxyGen para nombrar la clase de acceso al servicio, y se utilizará en la configuración del servicio en Fluig. En esta pantalla también es necesario configurar PROPATH de manera correcta, para que se puedan encontrar los archivos compilados (.r).</span> </p> <p> <span style="font-size: 10.0pt; line-height: 13.0pt; text-align: justify;"><img class="confluence-embedded-image" src 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. |
Acessando WebServices a partir do Fluig
O Fluig permite fazer chamadas a WebServices de terceiros através do cadastro de Serviços na Visualização de Serviços do Fluig Studio.
Para adicionar um novo WebService, é preciso clicar na opção Incluir Serviço, abrindo o assistente Novo Serviço, e informar o servidor do Fluig onde será adicionado o serviço, um código identificador para ele, a sua descrição, a URL para o WSDL e o seu tipo (neste caso WebService). No exemplo abaixo, será utilizado um WebService público para consulta à tabela periódica, cujo endereço do WSDL é http://www.webservicex.com/periodictable.asmx?wsdl.
Integração Com Aplicativos Externos > acesso-ws-1.png" src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-1.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/acesso-ws-1.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406793" data-linked-resource-type="attachment" data-linked-resource-default-alias="acesso-ws-1.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > acesso-ws-1.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-1.png?version=1&modificationDate=1377284793000&api=v2">
Com base nestas informações, o Fluig irá extrair as informações sobre o WebService informado e finalizará o cadastro deste serviço.
Uma vez que o serviço esteja cadastrado, é possível visualizar as classes e métodos disponíveis neste serviço e que serão utilizados nos códigos JavaScript que farão uso do mesmo. A tela abaixo apresenta um exemplo de visualização de WebService.
Integração Com Aplicativos Externos > acesso-ws-2.png" src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/acesso-ws-2.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406792" data-linked-resource-type="attachment" data-linked-resource-default-alias="acesso-ws-2.png" data-base-url="http://tdn.totvs.com
...
" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > acesso-ws-2.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/
...
...
2.png?version=1&modificationDate=1377284793000&api=v2"
...
>
Os serviços adicionados no Fluig podem ser instanciados e utilizados nos pontos onde o produto permite personalização utilizando-se JavaScript, como nos scripts para eventos globais, eventos de processos, eventos de definição de formulário ou Datasets. No exemplo a seguir, será criado um Dataset que fará uso deste serviço para trazer os dados da tabela periódica.
O código abaixo apresenta uma implementação de exemplo do uso de um serviço na construção de um Dataset:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function createDataset(fields, constraints, sortFields) {
//Cria o dataset
var dataset = DatasetBuilder.newDataset();
dataset.addColumn("elementName");
// Conecta o servico e busca os livros
var periodicService = ServiceManager.getService('PeriodicTable');
var serviceHelper = periodicService.getBean();
var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable');
var service = serviceLocator.getPeriodictableSoap();
//Invoca o serviço
try {
var result = service.getAtoms();
var NewDataSet = new XML(result);
for each(element in NewDataSet.Table) {
dataset.addRow(new Array(element.ElementName.toString()));
}
} catch(erro) {
dataset.addRow(new Array(erro));
}
return dataset;
} |
O primeiro passo para invocar o serviço é solicitar ao Fluig que carregue o serviço, a partir do método ServiceManager.getService('PeriodicTable'). O valor passado como parâmetro, deve ser o código utilizado quando cadastrado o serviço.
Uma vez que o serviço tenha sido carregado, é utilizado o método getBean() para retornar um utilitário para acesso às classes do serviço, através do método instantiate. Através deste utilitário, é possível instanciar as classes disponíveis e que estão listadas no cadastro do Serviço (conforme imagem vista anteriormente).
Uma vez que se tenha instanciado o objeto utilitário do serviço, as classes que devem ser instanciadas e os métodos que devem ser invocados dependem de cada WebService utilizado, e deve-se recorrer à sua documentação para mais informações.
Para o serviço da tabela periódica é necessário realizar os seguintes passos:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable');
var service = serviceLocator.getPeriodictableSoap();
var result = service.getAtoms(); |
Onde:
Passo 1: Instanciar a classe net.webservicex.Periodictable para ter acesso ao localizador do serviço;
- Passo 2: Invocar o método getPeriodictableSoap para instanciar o serviço;
- Passo 3: Invocar o método getAtoms para ter a lista dos elementos.
No caso deste serviço, o método getAtoms retorna uma string contendo um XML com a lista de todos os elementos, conforme o exemplo abaixo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<NewDataSet>
<Table>
<ElementName>Actinium</ElementName>
</Table>
<Table>
<ElementName>Aluminium</ElementName>
</Table>
...
</NewDataSet> |
Para percorrer o XML e extrair o dados disponíveis, são utilizadas as funcionalidades de tratamento de XML do JavaScript que facilita a manipulação de dados deste tipo. Para mais informações sobre esta funcionalidade, acesse: http://www.ecma-international.org/publications/standards/Ecma-357.htm ou http://www.xml.com/pub/a/2007/11/28/introducing-e4x.html.
O exemplo abaixo apresenta o código utilizado para percorrer o XML retornado:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
var NewDataSet = new XML(result);
for each(element in NewDataSet.Table) {
dataset.addRow(new Array(element.ElementName.toString()));
} |
Uma vez implementado o código do Dataset, é possível visualizá-lo, conforme a figura abaixo:
Integração Com Aplicativos Externos > acesso-ws-3.png" src="http://tdn.totvs.com/download/attachments/73082260/
...
...
3.png?version=1&modificationDate=1377284793000&api=
...
v2" data-image-src="
...
/download/attachments/73082260/
...
acesso-ws-
...
3.png?version=1&modificationDate=1377284793000&api=v2"
...
data-linked-resource-id="
...
73406791" data-linked-resource-type="attachment" data-linked-resource-default-alias="acesso-ws-3.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > acesso-ws-3.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/acesso-ws-3.png?version=1&modificationDate=1377284793000&api=v2">
WebServices com Autenticação Básica
Para consumir WebServices que fazem uso de autenticação básica (WSS ou WS-Security), é necessário utilizar o método getBasicAuthenticatedClient localizado no provider do serviço (o mesmo que é obtido via ServiceManager). Este método disponibiliza um client autenticado.
Os parâmetros que devem ser informados no método seguem a ordem abaixo:
- Instância do serviço
- Nome da classe do serviço
- Usuário para a autenticação
- Senha para a autenticação
Utilizando o exemplo do serviço PeriodicTable apresentado anteriormente, o código da chamada teria as alterações abaixo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
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 com client personalizado
Nota | ||
---|---|---|
| ||
Esta técnica é válida para o Fluig 1.3.7 ou superior. Em integrações que utilizem serviços criados com o CXF com sistemas que não suportam o protocolo HTTP/1.1 (Protheus, por exemplo), é necessário utilizar este método configurando o parâmetro "disable.chunking" com o valor "true". |
Para personalizar o client que acessa os serviços, é necessário utilizar o método getCustomClient, localizado no provider do serviço (o mesmo que é obtido via ServiceManager). Esta configuração exige a criação de um mapa de parâmetros com seus respectivos valores para passar ao método, conforme snippet abaixo:
Bloco de código | ||||
---|---|---|---|---|
| ||||
var properties = {};
properties["basic.authorization"] = "true";
properties["basic.authorization.username"] = "username";
properties["basic.authorization.password"] = "password";
properties["disable.chunking"] = "true";
properties["log.soap.messages"] = "true";
var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable');
var service = serviceLocator.getPeriodictableSoap();
var customClient = serviceHelper.getCustomClient(service, "net.webservicex.PeriodictableSoap", properties);
var result = customClient.getAtoms(); |
Os parâmetros que podem ser definidos são os seguintes:
Propriedade | Função |
---|---|
basic.authorization | Quando definido como "true", faz o mesmo que o método getBasicAuthenticatedClient, porém permite aplicar as configurações de autenticação juntamente com as demais personalizações abaixo. Para configurar a autenticação, as propriedades com "username" e "password" abaixo também precisam ser definidas. |
basic.authorization.username | Usuário a ser utilizado para autenticação básica. |
basic.authorization.password | Senha do usuário utilizado para autenticação básica. |
disable.chunking | Quando definido como "true", desabilita o envio de requisições grandes em "pedaços" menores. Pode ser útil quando o serviço chamado não suporta este tipo de requisição. |
log.soap.messages | Quando definido como "true", permite que as mensagens SOAP utilizadas nas requisições feitas aos serviços sejam apresentadas no log do servidor, facilitando a depuração em caso de falhas. |
Resolvendo conflitos utilizando arquivos de bind JAXB
Nota | ||
---|---|---|
| ||
Esta técnica é válida apenas para serviços criados utilizando a API CXF. |
Ao criar serviços no Fluig podem ocorrer alguns conflitos impedindo a geração dos stubs. Normalmente isso ocorre quando temos um elemento do schema do WSDL com duas ou mais propriedades com o mesmo identificador ou nome, o que impede a criação da Classe Java desse elemento.
Para resolver esse conflitos podem ser utilizados arquivos de bind JAXB, conforme a figura abaixo:
Integração Com Aplicativos Externos > Binding.png" src="http://tdn.totvs.com/download/attachments/73082260/Binding.png?version=1&modificationDate=1422607474000&api=v2" data-image-src="/download/attachments/73082260/Binding.png?version=1&modificationDate=
...
1422607474000&api=v2
...
" data-linked-resource-id="184844668" data-linked-resource-type="attachment" data-linked-resource-default-alias="Binding.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > Binding.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/
...
Binding.png?version=1&modificationDate=
...
...
Esse arquivo tem o propósito de personalizar a geração dos stubs alterando o nome das propriedades conflitantes.
A seguir temos dois exemplos de utilização desses arquivos:
Exemplo 1 :
Durante a criação do serviço ocorreu o seguinte erro :
Sem Formato |
---|
Não foi possível salvar os stubs para acesso ao serviço:
http://localhost:8080/pcliente/CHAMTEC.apw?WSDL [2255,11]: Two declarations cause a collision in the ObjectFactory class.
http://localhost:8080/pcliente/CHAMTEC.apw?WSDL [2245,11]: (Related to above error) This is the other declaration. |
O que indica que temos duas declarações de propriedades conflitantes, conforme o fragmento do WSDL abaixo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<s:complexType name="STRUCT_SA1">
<s:sequence>
...
<s:element minOccurs="1" maxOccurs="1" name="_A1COD_MUN" type="s:string"/>
...
<s:element minOccurs="1" maxOccurs="1" name="_A1CODMUN" type="s:string"/>
...
</s:sequence>
</s:complexType> |
Os identificadores "_A1COD_MUN" e "_A1CODMUN" são considerados iguais pela API de geração dos stubs, e fazem parte do mesmo tipo complexo "STRUCT_SA1".
Para resolver esse conflito, pode ser utilizado o arquivo de bind abaixo :
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<?xml version="1.0" encoding="utf-8"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="http://localhost:8080/pcliente/CHAMTEC.apw?WSDL#types1" node="/xsd:schema">
<jxb:bindings node="//xsd:complexType[@name='STRUCT_SA1']//xsd:sequence//xsd:element[@name='_A1COD_MUN']">
<jxb:property name="_A1COD_MUN2"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings> |
Esse arquivo faz com que o elemento "_A1COD_MUN" contido no tipo complexo "STRUCT_SA1" assuma o nome "_A1COD_MUN2", resolvendo assim o conflito na geração dos stubs.
Exemplo 2 :
Durante a criação do serviço ocorreu o seguinte erro :
Sem Formato |
---|
Não foi possível salvar os stubs para acesso ao serviço:
http://localhost:8080/tbc/wsConsultaSQL.asmx?WSDL [49,19]: Property "Any" is already defined. Use <jaxb:property> to resolve this conflict.
http://localhost:8080/tbc/wsConsultaSQL.asmx?WSDL [50,19]: The following location is relevant to the above error
http://localhost:8080/tbc/wsConsultaSQL.asmx?WSDL [75,19]: Property "Any" is already defined. Use <jaxb:property> to resolve this conflict.
http://localhost:8080/tbc/wsConsultaSQL.asmx?WSDL [76,19]: The following location is relevant to the above error |
O que indica que temos duas propriedades com a identificação "any" no nosso elemento, conforme o fragmento do arquivo WSDL abaixo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<s:element name="RealizarConsultaSQLDataTableResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="RealizarConsultaSQLDataTableResult">
<s:complexType>
<s:sequence>
<s:any minOccurs="0" maxOccurs="unbounded" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" />
<s:any minOccurs="1" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
...
<s:element name="RealizarConsultaSQLDataTableAuthResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="RealizarConsultaSQLDataTableAuthResult">
<s:complexType>
<s:sequence>
<s:any minOccurs="0" maxOccurs="unbounded" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" />
<s:any minOccurs="1" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element> |
Essa situação ocorre em dois elementos do arquivo WSDL, o "RealizarConsultaSQLDataTableResponse" e o "RealizarConsultaSQLDataTableAuthResponse".
Para resolver esse conflito, pode ser utilizado o arquivo de bind abaixo :
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<?xml version="1.0" encoding="utf-8"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="http://localhost:8080/tbc/wsConsultaSQL.asmx?WSDL#types1" node="/xsd:schema">
<jxb:bindings node="//xsd:element[@name='RealizarConsultaSQLDataTableResponse']//xsd:sequence//xsd:any[position()=2]">
<jxb:property name="any2"/>
</jxb:bindings>
<jxb:bindings node="//xsd:element[@name='RealizarConsultaSQLDataTableAuthResponse']//xsd:sequence//xsd:any[position()=2]">
<jxb:property name="any2"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings> |
Esse arquivo faz com que a segunda propriedade "any" de cada um dos elementos assuma o nome "any2", resolvendo assim o conflito na geração dos stubs.
Maiores informações sobre personalizações via JAXB Bindings em http://docs.oracle.com/javase/tutorial/jaxb/intro/custom.html
Progress® Open AppServer
Assim como é possível invocar operações em WebServices, o Fluig também permite fazer chamadas a programas em Progress® 4GL (ou ABL) expostos via Progress® Open AppServer.
Nos exemplos a seguir, serão criados Datasets que, via camada de serviço, farão o acesso à lógicas em 4GL que farão a extração dos dados. Embora os códigos 4GL, neste exemplo, sejam muito simples, eles compreendem os casos mais comuns exigidos no dia-a-dia, uma vez que a complexidade da integração se encontra nas interfaces (parâmetros de entrada e saída) de cada procedure exposta, e não na sua lógica interna.
Observe que os exemplos aqui apresentados têm por objetivo demonstrar a dinâmica de integração entre Progress® e o Fluig sem entrar em detalhes específicos das tecnologias envolvidas. A camada de serviço Progress® do Fluig cria uma interface em JavaScript para a biblioteca Java Open AppServer Client, da Progress® e, por isso, para mais informações sobre como integrar aplicativos Java™ e Progress® consulte a documentação fornecida pela Progress®.
Caso de Uso
Os exemplos exibidos a seguir, têm por objetivo a criação de quatro Datasets 1 no Fluig:
- Tipos de Centro de Custo, que deve retornar os tipos de centro de custo existentes no aplicativo em Progress® (neste caso, o EMS2).
- Natureza dos Centros de Custo, que deve retornar os tipos possíveis de natureza, conforme o aplicativo em Progress® (neste caso, o EMS2).
- Centros de Custo, que deve retornar os registros na tabela conta 2.
Usuários Comuns, que deve gerar uma lista de usuários comuns entre o Fluig e o aplicativo em Progress® (utilizando a tabela usuar_mestre).
Nota 1 - Os exemplos utilizam uma base de dados do EMS2 para consulta de centros de custo e usuários. Entretanto, apenas duas tabelas e 6 campos são utilizados no total, o que não deve prejudicar o entendimento da lógica pelo leitor, nem impedir a criação de um esquema equivalente para testes, caso necessário.
2 - O código apresentado para extração dos centros de custo tem fins meramente didáticos e não pode ser considerado para uso em produção. Para ter mais informações sobre como extrair centros de custos do EMS2, consulte a documentação técnica do mesmo.
Para os três primeiros casos, a lógica de extração das informações desejadas será exposta em um programa com várias procedures, uma para cada necessidade aqui apresentada:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
/**************************************************************************
** Utilitário que disponibiliza procedures para a extração de informações
** sobre centros de custo.
**************************************************************************/
DEFINE TEMP-TABLE ttCC NO-UNDO
FIELD conta LIKE conta.ct-codigo /* CHARACTER */
FIELD natureza LIKE conta.natureza /* INTEGER */
FIELD tipo LIKE conta.tipo /* INTEGER */
FIELD titulo LIKE conta.titulo. /* CHARACTER */
/*-------------------------------------------------------------------
Procedure: readCostCenters
Objetivo: Retorna uma temp-table com a lista de centros de custo.
----------------------------------------------------------------------*/
PROCEDURE readCostCenters:
DEFINE OUTPUT PARAMETER TABLE FOR ttCC.
FOR EACH conta:
CREATE ttCC.
ASSIGN
ttCC.conta = conta.ct-codigo
ttCC.natureza = conta.natureza
ttCC.tipo = conta.tipo
ttCC.titulo = conta.titulo.
END.
END.
/*-------------------------------------------------------------------
Procedure: readCostNatureTypes
Objetivo: Retorna uma string com as naturezas dos centros de custo,
separadas por vírgula.
----------------------------------------------------------------------*/
PROCEDURE readCostNatureTypes:
DEFINE OUTPUT PARAMETER cNatureList AS CHARACTER NO-UNDO.
cNatureList = {adinc/i01ad047.i 03}.
END.
/*-------------------------------------------------------------------
Procedure: readCostTypes
Objetivo: Retorna uma string com os tipos de centro de custo,
separados por vírgula.
----------------------------------------------------------------------*/
PROCEDURE readCostTypes:
DEFINE OUTPUT PARAMETER cTypeList AS CHARACTER NO-UNDO.
cTypeList = {adinc/i02ad047.i 3}.
END. |
No caso da extração de usuários comuns aos dois produtos, será utilizado um programa único, conforme o código abaixo:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
/**************************************************************************
** Utilitário que recebe um temp-table com uma lista de usuários e retorna
** outra, apenas com os usuários da lista que existam na base de dados.
**************************************************************************/
DEFINE TEMP-TABLE ttUsers
FIELD cod_usuar AS CHARACTER
FIELD nom_usuario AS CHARACTER
INDEX principal IS PRIMARY UNIQUE cod_usuar.
DEFINE TEMP-TABLE ttOutUsers LIKE ttUsers.
DEFINE INPUT PARAMETER TABLE FOR ttUsers.
DEFINE OUTPUT PARAMETER TABLE FOR ttOutUsers.
FOR EACH ttUsers:
IF CAN-FIND(usuar_mestre WHERE usuar_mestre.cod_usuar = ttUsers.cod_usuar) THEN DO:
CREATE ttOutUsers.
BUFFER-COPY ttUsers TO ttOutUsers.
END.
END. |
Os dois códigos apresentados têm diferenças significativas na forma como são utilizados e na forma como serão expostos pelo Progress®. No primeiro, o programa é carregado de forma persistente e suas procedures podem ser executadas de forma independente. No segundo caso, o programa é executado de forma não-persistente e a lógica principal se encontra no main-block. As procedures internas, caso existam, têm por objetivo melhorar a organização do código e não podem ser utilizadas de forma isolada.
Configuração do AppServer
Algumas informações importantes na configuração do AppServer:
- O AppServer deve ser carregado no modo Stateless;
Na configuração do agente, no campo Propath, deve ser adicionado o diretório onde estão localizados os arquivos compilados (.r).
Nota Importante: Quando utilizado um caminho relativo (\\servidor\pasta), o serviço Windows® do Progress® (AdminService) deve ser iniciado com um usuário de rede que possua permissão de acesso ao diretório informado.
Expondo códigos 4GL com ProxyGen
O primeiro passo para que seja possível executar rotinas em Progress® 4GL é criar a biblioteca cliente, o que é feito com o uso do aplicativo ProxyGen, que acompanha a instalação do Progress®, conforme o exemplo abaixo.
Utilize o passo-a-passo para visualizar o processo de criação do proxy:
Deck of Cards | |||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||||||||||||||||||||
|
Informações |
---|
Dependendo da versão do Progress®, as telas podem sofrer alguma variação na quantidade e disposição dos campos. Consulte a documentação em caso de dúvida |
Configuração do Serviço no Fluig
O cadastro de um serviço é realizado através do Fluig Studio, na view Visualização de Serviços, pela opção Incluir Serviço. A tela abaixo apresenta o assistente de novo serviço e os campos utilizados para o cadastro do serviço Progress®:
Integração Com Aplicativos Externos > servico-process-1.png" src="http://tdn.totvs.com/download/attachments/73082260/servico-process-1.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/servico-process-1.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406786" data-linked-resource-type="attachment" data-linked-resource-default-alias="servico-process-1.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > servico-process-1.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/servico-process-1.png?version=1&modificationDate=1377284793000&api=v2">
Onde:
- Servidor: Servidor do Fluig onde será adicionado o serviço;
- Código: Código único que irá identificar o serviço no sistema. Este código será utilizado nos códigos JavaScript para ter acesso a este serviço;
- Descrição: Texto que descreve o serviço de dados;
- URL: Identifica a URL de acesso ao serviço AppServer, como por exemplo AppServer://<servidor>/<nome_serviço>;
No caso de não estar utilizando o NameServer padrão deve ser informada a porta de acesso ao NameServer. Ex.: AppServer://<servidor>:<porta_NameServer>/<nome_serviço>.
Observe que dependendo da configuração do serviço e/ou da forma de conexão, a URL pode sofrer alterações. Verifique a documentação do Open AppServer para mais informações. - Tipo: Identifica o tipo de serviço (Progress ou WebService). Deve ser selecionado Progress;
- Objeto Remoto: Identifica a classe de acesso do proxy. Esta classe normalmente é formada pelo nome do pacote utilizado para a geração das classes Proxy, mais o nome do projeto no ProxyGen.
Exemplo: Nas telas que apresentam o ProxyGen, foi utilizado o pacote com.fluig.samples.ems, e o nome dado ao projeto no ProxyGen foi EMSProxies. Neste caso, a classe do Objeto remoto será com.fluig.samples.ems.EMSProxies; - Usuário: Usuário utilizado na conexão ao serviço, conforme definido nas configurações no AppServer;
- Senha: Senha utilizada na conexão ao serviço, conforme definida nas configurações no AppServer;
- Parâmetros Extras: Parâmetros extras (e opcionais) utilizados para conexão ao AppServer. Verifique a documentação do Open AppServer para verificar as opções disponíveis em cada versão do Progress®;
- Diretório do arquivo de Proxy: Arquivo .JAR contendo as classes geradas pelo ProxyGen; Deve ser utilizado o botão Selecionar Arquivo para localizar o mesmo.
Uma vez que o serviço tenha sido adicionado, é possível visualizar as classes disponíveis e os métodos existentes em cada uma delas. Estas informações são importantes para guiar o desenvolvimento dos códigos personalizados que farão uso deste serviço. Para visualizar as classes e métodos do serviço, utilize a opção Consulta Serviço na Visualização de Serviços, conforme a tela abaixo:
Integração Com Aplicativos Externos > servico-process-2.png" src="http://tdn.totvs.com/download/attachments/73082260/servico-process-2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/servico-process-2.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406785" data-linked-resource-type="attachment" data-linked-resource-default-alias="servico-process-2.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > servico-process-2.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/servico-process-2.png?version=1&modificationDate=1377284793000&api=v2">
Visão Geral dos Objetos Envolvidos
O acesso às procedures expostas no AppServer envolve quatro elementos que interagem entre si, conforme o diagrama abaixo:
Integração Com Aplicativos Externos > diagrama objetos envolvidos.png" src="http://tdn.totvs.com/download/attachments/73082260/diagrama%20objetos%20envolvidos.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/diagrama%20objetos%20envolvidos.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406794" data-linked-resource-type="attachment" data-linked-resource-default-alias="diagrama objetos envolvidos.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > diagrama objetos envolvidos.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/
...
diagrama%20objetos%20envolvidos.png?version=1&modificationDate=1377284793000&api=v2">
Onde:
- Script Code: é o código em JavaScript que fará uso das procedures expostas no AppServer. Como mencionado anteriormente, este JavaScript pode ser de qualquer natureza, como a implementação de um Dataset ou a personalização de um evento de processo.
- Service Provider: Objeto recuperado através do método ServiceManager.getService e que fornece o acesso às funcionalidades do serviço. Este objeto é responsável por gerenciar a conexão e recursos alocados pelo serviço durante a execução do script.
- Service Helper: Objeto recuperado via método getBean no ServiceProvider e que disponibiliza um conjunto de métodos utilitários que permitem, entre outras coisas, criar objetos específicos do Progress® (StringHolder, ResultSetHolder, etc.), ter acesso ao objeto remoto do ProxyGen e instanciar classes. Para mais informações sobre o Service Helper consultar aqui.
- ProxyGen Classes: Classes geradas pelo ProxyGen e que serão utilizadas pelo desenvolvedor para execução das rotinas em Progress®. A lista das classes disponíveis, bem como os seus métodos, podem ser visualizados na Visualização de Serviços do Fluig Studio.
Procedures Persistentes e Não-Persistentes
Quando uma procedure é adicionada ao projeto do ProxyGen, ela deve ser configurada em duas listas: Procedures Persistentes ou Não-Persistentes. Esta decisão implica diretamente na forma como estes objetos são acessados pela biblioteca gerada e, consequentemente, na forma como o desenvolvedor irá acessá-las nos códigos JavaScript.
As procedures expostas de forma não-persistente dão origem à métodos na classe configurada como Objeto Remoto (ou Proxy) no Serviço, e a sua execução é feita chamando o método correspondente, por exemplo:
Sem Formato |
---|
serviceHelper.getProxy().verifyUsers(inputTT, holder). |
As procedures expostas de forma persistente dão origem à novas classes que podem ser instanciadas via chamadas a métodos no Objeto Remoto (através da Visualização de Serviços no Fluig Studio é possível verificar os métodos disponíveis na classe), ou via o método createManagedObject. A chamada via o método createManagedObject permite que o Fluig tenha controle sobre o ciclo de vida deste objeto, liberando-o automaticamente ao fim do método. Caso o objeto seja instanciado manualmente, o desenvolvedor deve codificar a liberação do objeto (método _release()), sob pena de bloquear um novo agente do AppServer a cada invocação do método.
Parâmetros de Entrada e Saída
Outro ponto importante na invocação das rotinas em 4GL é observar quais os tipos de parâmetros de entrada e saída de cada procedure ou programa. Dependendo do tipo de dado (CHARACTER, INTEGER, TEMP-TABLE, etc.), do tipo de parâmetro (INPUT, INPUT-OUTPUT, BUFFER, etc.) e da versão utilizada do Progress®, a forma de se manipular estes parâmetros pode variar.
Para os tipos mais simples, como strings, datas ou valores inteiros, o ProxyGen utiliza um mapeamento direto para os tipos ou classes padrões da linguagem Java™. Para tipos complexos, como temp-tables e buffers, o ProxyGen utiliza classes que fazem parte da biblioteca de runtime destes serviços.
Quando os parâmetros são de entrada e saída (INPUT-OUTPUT) ou de saída (OUTPUT), os tipos primitivos precisam ser substituídos por classes Holders, que conterão o valor retornado após a execução do método. Os exemplos mais comuns são StringHolder ou ResultSetHolder.
Os tipos de dados utilizados em cada método podem ser consultado através da Visualização de Serviços no Fluig Studio. Observe que dependendo da versão do Progress® pode haver variação nos tipos de parâmetros utilizados e na forma de utilizá-los. Em caso de dúvida, consulte a documentação fornecida pela Progress®.
Criação dos Datasets
Uma vez que o serviço Progress® tenha sido adicionado no Fluig, é possível utilizá-lo nos pontos onde o produto permite persoanlização utilizando-se JavaScript, como nos scripts para eventos globais, eventos de processos, eventos de definição de formulário ou Datasets.
A forma de se invocar as rotinas expostas pelo serviço é sempre a mesma, independente de qual ponto está sendo chamado. Entretanto, para facilitar o entendimento do uso dos serviços Progress® no Fluig e facilitar a reprodução dos exemplos apresentados no ambiente do leitor, todos os exemplos abaixo utilizarão Datasets como alvo.
Conforme visto anteriormente, os Datasets que serão apresentados aqui são Tipos de Centro de Custo, Natureza dos Centros de Custo, Centros de Custo e Usuários em Comum.
Tipos de Centro de Custo
O código abaixo apresenta a implementação do Dataset de Tipos de Centro de Custo. A explicação de cada passo da implementação será apresentada após o código:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function </p> <p> </p> <h5 id="IntegraçãoComAplicativosExternos-CentrosdeCusto">Centros de Costo</h5> <p>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.</p> <p>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.</p> <h6 id="IntegraçãoComAplicativosExternos-CodificaçãoProgress®9">Codificación Progress® 9</h6> <p>Las temp-table en Progress® 9 son manejadas por los objetos que implementan la interfaz java.sql.ResultSet:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>dsCentroCostoP9.js</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">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; }</pre> </div> </div> <h6 id="IntegraçãoComAplicativosExternos-CodificaçãoOpenEdge®10">Codificación OpenEdge® 10</h6> <p>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:</p> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>dsCentroCostoOE10.js</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">function createDataset(fields, constraints, sortFields) { //CreaPasso 1 la- estructuraCria delo Dataset dataset var dataset = DatasetBuilder.newDataset(); dataset.addColumn("cuentaid"); dataset.addColumn("titulodescricao"); dataset.addColumn("naturaleza"); dataset.addColumn("tipo"); //Recupera el servicio y carga el objeto remoto //Passo 2 - Invoca o serviço cadastrado no Fluig var servico = ServiceManager.getService("EMS2"); //Passo 3 - Carrega o objeto utilitário para integração com Progress var servicoserviceHelper = ServiceManagerservico.getServicegetBean("EMS2"); //Passo 4 - Carrega vara serviceHelperprocedure =persistente servico.getBean();CostCenterUtils.p var remoteObj = serviceHelper.createManagedObject("CostCenterUtils"); //Passo 5 - Invoca a procedure que retorna uma string com //Leeos lastipos cuentasde corrientesCC var holdertypes = serviceHelper.createProDataGraphHoldercreateStringHolder(); remoteObj.readCostCentersreadCostTypes(holdertypes); //Passo 6 - Quebra a //Recorre los registros, cargando el Dataset con los datosstring em um array com cada um dos tipos var ttCCtypeArray = holdertypes.getProDataGraphValuegetStringValue().getProDataObjectssplit("ttCC"); ,"); //Passo 7 - Adiciona cada tipo retornado for(var pos = 0; pos < typeArray.length; pos++) { for (var row_index = 0; row_index < ttCC.size(); row_index++) { dataset.addRow(new Array(pos + 1, typeArray[pos])); } var row = ttCC.get(row_index); dataset.addRow(new Array(row.get("cuenta"), row.get("titulo"), row.get("naturaleza"), row.get("tipo"))); } return dataset; }</pre> </div> </div> <p>Visualización del Dataset:</p> <p> <img class="confluence-embedded-image" return dataset; } |
Onde:
- Passo 1: Cria o dataset e adiciona os campos do mesmo;
- Passo 2: É feita a invocação do serviço cadastrado no Fluig, através do método ServiceManager.getService, e o valor passado como parâmetro deve ser o código do serviço. Note que neste ponto não é preciso informar qualquer parâmetro de conexão ao serviço, uma vez que isto já foi feito no seu cadastro;
- Passo 3: Utiliza o método getBean para retornar um objeto utilitário para serviços Progress®. Este utilitário disponibiliza uma série de métodos que facilitam a interação com o proxy gerado e seus métodos serão apresentados em mais detalhes adiante neste documento;
- Passo 4: Faz a carga do objeto CostCenterUtils de forma gerenciada, através do método createManagedObject do utilitário criado anteriormente;
- Passo 5: Invoca o método desejado, neste caso o readCostTypes, passando um StringHolder que irá receber o valor de saída;
- Passo 6: Transforma a String recebida por parâmetro em um array com as opções. O caractere , (vírgula) é utilizado para determinar os pontos de quebra da string;
- Passo 7: Percorre o array criado, adicionando uma linha no Dataset para cada item do array.
A tela abaixo apresenta a visualizaçào dos dados do Dataset criado:
Integração Com Aplicativos Externos > ems-dt1.png" src="http://tdn.totvs.com/download/attachments/73082260/ems-
...
dt1.png?version=1&modificationDate=1377284793000&api=v2"
...
data-image-src="/download/attachments/73082260/ems-dt1.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406784" data-linked-resource-type="attachment" data-linked-resource-default-alias="ems-dt1.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > ems-dt1.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/ems-
...
dt1.png?version=1&modificationDate=1377284793000&api=v2">
Natureza dos Centros de Custo
O Dataset de Natureza dos Centros de Custo é muito similar ao Dataset de tipo de centro de custo. Na prática, a única alteração é a procedure que é chamada:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function createDataset(fields, constraints, sortFields) {
var dataset = DatasetBuilder.newDataset();
dataset.addColumn("id");
dataset.addColumn("descricao");
var servico = ServiceManager.getService("EMS2");
var serviceHelper = servico.getBean();
var remoteObj = serviceHelper.createManagedObject("CostCenterUtils");
var types = serviceHelper.createStringHolder();
remoteObj.readCostNatureTypes(types);
var typeArray = types.getStringValue().split(",");
for(var pos = 0; pos < typeArray.length; pos++) {
dataset.addRow(new Array(pos + 1, typeArray[pos]));
}
return dataset;
} |
Após o cadastro do Dataset, é possível visualizar o seu conteúdo:
Integração Com Aplicativos Externos > ems-dt2.png" src="http://tdn.totvs.com/download/attachments/73082260/ems-dt2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/ems-dt2.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406783" data-linked-resource-type="attachment" data-linked-resource-default-alias="ems-dt2.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > ems-dt2.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/ems-dt2.png?version=1&modificationDate=1377284793000&api=v2">
Centros de Custo
O Dataset de Centros de Custo possui uma estrutura muito semelhante aos dois Datasets vistos anteriormente. A diferença principal é que, neste caso, a procedure retorna uma temp-table com os centros de custo, o que altera a forma como os dados são manipulados.
Dependendo da versão do Progress®, os objetos utilizados podem variar. A seguir, são apresentados exemplos da codificação para Progress® 9 e OpenEdge® 10, respectivamente. Em ambos os casos, o resultado apresentado pelo Dataset será o mesmo.
Codificação Progress® 9
As temp-table no Progress® 9 são tratadas através de objetos que implementam a interface java.sql.ResultSet:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function </p> <p> </p> <h5 id="IntegraçãoComAplicativosExternos-UsuáriosemComum">Usuarios en Común</h5> <p>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.</p> <p>La segunda diferencia es que el código 4GL se implementa en un programa no persistente, lo que cambia la forma como la lógica se invoca desde el código JavaScript.</p> <p>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).</p> <h6 id="IntegraçãoComAplicativosExternos-CodificaçãoProgress®9.1">Codificación Progress® 9</h6> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>dsUsuariosComunesP9.js</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;">function createDataset(fields, constraints, sortFields) { //CreaCria a elestrutura nuevodo Dataset var dataset = DatasetBuilder.newDataset(); dataset.addColumn("usuarioconta"); dataset.addColumn("nombretitulo"); //Recupera los usuarios de Fluig var campos = new Array("colleaguePK.colleagueId", "colleagueNamedataset.addColumn("natureza"); var colleaguesDataset = DatasetFactory.getDatasetdataset.addColumn("colleague", campos, null, nulltipo"); //Recupera o serviço e carrega //Instanciao elobjeto servicioremoto var servico = ServiceManager.getService("EMS2"); var serviceHelper = servico.getBean(); var remoteObj //Transforma el dataset en un ResultSet (v9) y crea holder de salida= serviceHelper.createManagedObject("CostCenterUtils"); var//Lê inputTTas = colleaguesDataset.toResultSet();contas correntes var holder = serviceHelper.createResultSetHolder(); //Invoca el procedure en el Progress serviceHelper.getProxy().verifyUsers(inputTT, holder); remoteObj.readCostCenters(holder); //Percorre os registros, carregando o Dataset com os dados var rs = holder.getResultSetValue(); while (rs.next()) { var conta = datasetrs.addRow(new Array(getObject("conta"); var natureza = rs.getObject("cod_usuar"),natureza"); var tipo = rs.getObject("nom_usuariotipo"))); } var titulo return dataset; }</pre> </div> </div> <h6 id="IntegraçãoComAplicativosExternos-CodificaçãoOpenEdge®10.1">Codificación OpenEdge® 10</h6> <div class="code panel pdl" style="border-width: 1px;"> <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>dsUsuariosComunesOE10.js</b> </div> <div class="codeContent panelContent pdl"> <pre class="first-line: 1; theme: Eclipse; brush: javascript; gutter: true" style="font-size: 12px;= rs.getObject("titulo"); dataset.addRow(new Array(conta, titulo, natureza, tipo)); } return dataset; } |
Codificação OpenEdge® 10
No OpenEdge® 10, as temp-tables retornadas são encapsuladas como objetos da classe ProDataGraph. Esta classe também é utilizada quando se utilizam parâmetros do tipo DATASET:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function">function createDataset(fields, constraints, sortFields) { //CreaCria a elestrutura nuevodo Dataset var dataset = DatasetBuilder.newDataset(); dataset.addColumn("usuarioconta"); dataset.addColumn("nombretitulo"); //Recupera los usuarios de Fluig var campos = new Array("colleaguePK.colleagueId", "colleagueName"dataset.addColumn("natureza"); var colleaguesDataset = DatasetFactory.getDatasetdataset.addColumn("colleague", campos, null, nulltipo"); //Recupera o serviço e carrega //Instanciao elobjeto servicioremoto var servico = ServiceManager.getService("EMS2"); var serviceHelper = servico.getBean(); //Transforma el dataset en un ProDataGraph (v10) y crea holder de salida var inputTTvar remoteObj = serviceHelper.toProDataGraph(colleaguesDataset); var holder = serviceHelper.createProDataGraphHolder(createManagedObject("CostCenterUtils"); //InvocaLê as elcontas procedurecorrentes en el Progress var holder = serviceHelper.getProxycreateProDataGraphHolder().verifyUsers(inputTT, ; remoteObj.readCostCenters(holder); //Percorre os registros, carregando o Dataset com os dados var ttCC = holder.getProDataGraphValue().getProDataObjects("ttOutUsersttCC"); 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("cod_usuarnatureza"), row.get("nom_usuariotipo"))); } return dataset; }</pre> </div> </div> <p>Visualización del Dataset:</p> <p> <img class="confluence-embedded-image" |
Visualização do Dataset:
Integração Com Aplicativos Externos > ems-dt3.png" src="http://tdn.totvs.com/download/attachments/73082260/ems-
...
dt3.png?version=1&modificationDate=1377284793000&api=v2"
...
data-image-src="
...
/
...
download/attachments/73082260/ems-
...
dt3.png?version=1&modificationDate=1377284793000&api=v2"
...
data-linked-resource-id="73406782" data-linked-resource-type="attachment" data-linked-resource-default-alias="ems-dt3.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > ems-dt3.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/ems-dt3.png?version=1&modificationDate=1377284793000&api=v2">
Usuários em Comum
A primeira diferença entre o Dataset de usuários comuns e os exemplos anteriores, é que neste caso é preciso passar uma temp-table como parâmetro para a procedure invocada.
A segunda diferença é que o código 4GL está implementado em um programa não-persistente, o que altera a forma como a lógica é invocada a partir do código JavaScript.
A terceira diferença que pode se observar neste caso é que é possível transformar um Dataset nos tipos de dados requeridos pelo Progress® (ResultSet ou ProDataGraph).
Codificação Progress® 9
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function createDataset(fields, constraints, sortFields) {
//Cria o novo Dataset
var dataset = DatasetBuilder.newDataset();
dataset.addColumn("usuario");
dataset.addColumn("nome");
//Recupera os usuários do Fluig
var campos = new Array("colleaguePK.colleagueId", "colleagueName");
var colleaguesDataset = DatasetFactory.getDataset("colleague", campos, null, null);
//Instancia o servico
var servico = ServiceManager.getService("EMS2");
var serviceHelper = servico.getBean();
//Transforma o dataset em um ResultSet (v9) e cria holder para saida
var inputTT = colleaguesDataset.toResultSet();
var holder = serviceHelper.createResultSetHolder();
//Invoca a procedure no 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;
} |
Codificação OpenEdge® 10
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function createDataset(fields, constraints, sortFields) {
//Cria o novo Dataset
var dataset = DatasetBuilder.newDataset();
dataset.addColumn("usuario");
dataset.addColumn("nome");
//Recupera os usuários do Fluig
var campos = new Array("colleaguePK.colleagueId", "colleagueName");
var colleaguesDataset = DatasetFactory.getDataset("colleague", campos, null, null);
//Instancia o servico
var servico = ServiceManager.getService("EMS2");
var serviceHelper = servico.getBean();
//Transforma o dataset em um ProDataGraph (v10) e cria holder para saida
var inputTT = serviceHelper.toProDataGraph(colleaguesDataset);
var holder = serviceHelper.createProDataGraphHolder();
//Invoca a procedure no 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;
} |
Visualização do Dataset:
Integração Com Aplicativos Externos > ems-dt4.png" src="http://tdn.totvs.com/download/attachments/73082260/ems-dt4.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/ems-dt4.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406781" data-linked-resource-type="attachment" data-linked-resource-default-alias="ems-dt4.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > ems-dt4.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/ems-dt4.png?version=1&modificationDate=1377284793000&api=v2">
Service Helper
A tabela abaixo apresenta a lista de métodos existentes na classe utilitária para serviços Progress®:
Retorno | Método e Descrição |
---|---|
java.lang.Object | createBigDecimalHolder() Cria um objeto Holder para o tipo DECIMAL |
java.lang.Object | createBooleanHolder() Cria um objeto Holder para o tipo LOGICAL |
java.lang.Object | createByteArrayHolder() Cria um objeto Holder para o tipo RAW |
java.lang.Object | createCOMHandleHolder() Cria um objeto Holder para o tipo COM-HANDLE |
java.lang.Object | createDateHolder() Cria um objeto Holder para o tipo DATE |
java.lang.Object | createHandleHolder() Cria um objeto Holder para o tipo WIDGET-HANDLE (Handle) |
java.lang.Object | createIntHolder() Cria um objeto Holder para o tipo INTEGER |
java.lang.Object | createLongHolder() Cria um objeto Holder para o tipo RECID |
java.lang.Object | createManagedObject(java.lang.String objName) Lê um arquivo .p ou .r que tenha sido exposto via AppServer de forma persistente. Através deste método o provedor do serviço pode gerenciar o ciclo de vida destes objetos, liberando-os ao final da execução do script. |
java.lang.Object | createMemptrHolder() Cria um objeto Holder para o tipo MEMPTR |
java.lang.Object | createProDataGraph(java.lang.Object metadata) Cria um objeto da classe ProDataGraph |
java.lang.Object | createProDataGraphHolder() Cria um objeto Holder para o tipo ProDataGraphHolder |
java.lang.Object | createProDataGraphMetaData(java.lang.String name) Cria um objeto da classe ProDataGraphMetadata |
java.lang.Object | createProDataObjectMetaData(java.lang.String tableName, int numFields, boolean bimageFlag, int numIndexes, java.lang.String multiIxCols, java.lang.String XMLNamespace, java.lang.String XMLPrefix) Cria um objeto da classe ProDataObjectMetadata. Cria um objeto para um dataset (Temp-table). |
java.lang.Object | createResultSetHolder() Cria um objeto Holder para o tipo TABLE |
java.lang.Object | createRowidHolder() Cria um objeto Holder para o tipo ROWID |
java.lang.Object | createStringHolder() Cria um objeto Holder para o tipo CHARACTER. |
java.lang.Object | getProxy() Retorna a instância do objeto de conexão ao AppServer, já conectado e disponível para uso. O objeto remoto é a principal classe gerada pelo ProxyGen. |
java.lang.Object | instantiate(java.lang.String className) Instancia um objeto de uma classe dentro da biblioteca do proxy. |
java.lang.Object | toProDataGraph(com.datasul.technology.webdesk.dataset. |
...
DefaultDataset d) Transforma um dataset em um ProDataGraph. |