Árvore de páginas

Versões comparadas

Chave

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

 

Índice

 

Índice
outlinetrue
stylenone
exclude.*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.

 

Image Added

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:

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

 

Vía Apache Flex®

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

Utilice el paso a paso para visualizar el proceso de creación de los stubs para un servicio ofrecido por Fluig:

Deck of Cards
idstubFlex
historyfalse
Card
defaulttrue
effectDuration0.5
id1
label1º Passo
effectTypefade

A criação dos stubs no Flex® é feito através do menu Data, opção Import WebService(WSDL), conforme a imagem abaixo.

Image Added

Card
effectDuration0.5
id2
label2º Passo
effectTypefade

Na primeira janela, é solicitada a pasta dentro do projeto corrente onde devem ser gerados os stubs.

Image Added

Card
effectDuration0.5
id3
label3º Passo
effectTypefade

Na tela a seguir, deve ser informado o endereço do WSDL onde se encontra o serviço. Também é possível definir se ele será acessado da estação cliente ou do servidor LifeCycle Data Services.

Image Added

Card
effectDuration0.5
id4
label4º Passo
effectTypefade

Na última tela, deve-se informar o package que será utilizado e qual o nome da classe principal (já sugeridos pelo Flex™ Builder™).

Image Added

Card
effectDuration0.5
id5
labelResultado
effectTypefade

Uma vez finalizado o processo, o Flex™ Builder™ adicionará ao projeto um conjunto de classes que serão utilizadas pelo programador para invocar os serviços, conforme a figura abaixo:

Image Added

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
themeEclipse
languageactionscript3
titleECMDatasetServiceClient.mxml
firstline1
linenumberstrue
<?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:

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

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
themeEclipse
languagejava
titleECMDatasetServiceClient.java
firstline1
linenumberstrue
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:

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

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

document.setExpirationDate(date);

 

Via Progress® 4GL

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
themeEclipse
languagejavafx
titlewsECMDatasetService.p
firstline1
linenumberstrue
/* Parte I - Invocar o WebService */
DEFINE VARIABLE hWebService     AS HANDLE NO-UNDO.
DEFINE VARIABLE hDatasetService AS HANDLE NO-UNDO.

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

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

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

RUN getDataset IN hDatasetService(INPUT 1,
                                  INPUT "adm",
               
HTML
<div id="main-content" class="wiki-content group">
	<h1 id="IntegraçãoComAplicativosExternos-Índice">Índice</h1>
	<p>&#160;</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&#160;<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>&#160;</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>&#160;</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.&#160;<span
			style="font-size: 10.0pt; line-height: 13.0pt;">Para tener la
			lista de los WebServices disponibles, ingrese a:&#160;</span>
	</p>
	<div class="preformatted panel" style="border-width: 1px;">
		<div class="preformattedContent panelContent">
			<pre>http://&lt;host>:&lt;porta>/webdesk/services&#160;</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>&#160;</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&amp;ordm; Passo" title="" nextafter="0"
				effecttype="fade" effectduration="0.5">
				<p>La creación de los stubs en&#160;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&amp;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&amp;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&amp;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;">&#160;</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;">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="{this.start()}">
	&lt;mx:Script>
		&lt;![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 &lt; 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 &lt; valuesArray.length; j++) {
					var row:ValuesDto = valuesArray.getItemAt(j) as ValuesDto;
					line += "\n" + j + ":";
					
					for (var i:int = 0; i &lt; 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;
			}
		]]>
	&lt;/mx:Script>
	&lt;mx:TextArea id="sysout" name="sysout" width="100%" height="100%" 
		paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5"/>
&lt;/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>&#160;</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 &lt;output_directory> &lt;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>&#160;</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 &lt;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.&#160;</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.
&#160;
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 &lt;columns> */ 
DO iCount = 1 TO hRoot:NUM-CHILDREN WITH 20 DOWN:
    hRoot:GET-CHILD(hEntry, iCount).
    IF hEntry:NAME &lt;> "columns" THEN
        NEXT.
    hEntry:GET-CHILD(hText, 1).
    PUT UNFORMATTED hText:NODE-VALUE "~t".
    DOWN.
END.
PUT UNFORMATTED SKIP.
/* Recorre los registros &lt;values> */
DO iCount = 1 TO hRoot:NUM-CHILDREN WITH 20 DOWN:
    hRoot:GET-CHILD(hValues, iCount).
    IF hValues:NAME &lt;> "values" THEN
        NEXT.
    /* Recorre los campos &lt;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&#160;Studio.</p>
	<p>
		Para agregar un nuevo WebService, es necesario ingresar a la opción <strong>Incluir
			Servicio,&#160;</strong>abriendo el asistente Nuevo Servicio, e informar al
		servidor de Fluig donde se agregará el servicio,&#160;<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).&#160;</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&#160;</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.&#160;</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.&#160;<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:&#160;</strong>Instanciar la clase&#160;<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;">&#160;para
					tener acceso al localizador del servicio;&#160;</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;">&lt;NewDataSet>
	&lt;Table>
		&lt;ElementName>Actinium&lt;/ElementName>
	&lt;/Table>
	&lt;Table>
		&lt;ElementName>Aluminium&lt;/ElementName>
	&lt;/Table>
	...
&lt;/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 :&#160;<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>&#160;</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&#160;<strong>getBasicAuthenticatedClient&#160;</strong>localizado
		en provider del servicio (el mismo que se obtiene vía <strong>ServiceManager).&#160;</strong>Este
		método proporciona un client autenticado.
	</p>
	<p>&#160;</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&#160;<strong>PeriodicTable&#160;</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>,&#160;localizado en provider
		del servicio (el mesmo que se obtiene vía&#160;<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>&#160;</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&#160;<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>&#160;</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&#160;<sup>1</sup> en Fluig:
	</p>
	<ol>
		<li><strong>Tipos de Centro de Costo,&#160;</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,&#160;</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,&#160;</strong>que debe devolver los
			registros en la tabla cuenta&#160;<sup>2</sup>.</li>
		<li><p>
				<strong>Usuarios Comunes,&#160;</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 */
&#160;
/*-------------------------------------------------------------------
  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&amp;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/

...

acesso-ws-

...

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
themeEclipse
languagejavascript
titleperiodicTable.js
firstline1
linenumberstrue
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
themeEclipse
languagejavascript
firstline1
linenumberstrue
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
themeEclipse
languagehtml/xml
firstline1
linenumberstrue
<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
themeEclipse
languagejavascript
firstline1
linenumberstrue
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/

...

acesso-ws-

...

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:

  1. Instância do serviço
  2. Nome da classe do serviço
  3. Usuário para a autenticação
  4. 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
themeEclipse
languagejavascript
firstline1
linenumberstrue
var serviceLocator = serviceHelper.instantiate('net.webservicex.Periodictable');
var service = serviceLocator.getPeriodictableSoap();
var authenticatedService = serviceHelper.getBasicAuthenticatedClient(service, "net.webservicex.PeriodictableSoap", 'usuario', 'senha');
var result = authenticatedService.getAtoms();

WebService com client personalizado
Nota
titleAtenção

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
themeEclipse
languagejs
		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:

PropriedadeFunçã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
titleAtenção

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=

...

1422607474000&api=v2">

...

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
themeEclipse
languagehtml/xml
firstline1
linenumberstrue
<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
themeEclipse
languagehtml/xml
firstline1
linenumberstrue
<?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 &lt;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 &lt;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
themeEclipse
languagehtml/xml
firstline1
linenumberstrue
<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
themeEclipse
languagehtml/xml
firstline1
linenumberstrue
<?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:

  1. Tipos de Centro de Custo, que deve retornar os tipos de centro de custo existentes no aplicativo em Progress® (neste caso, o EMS2).
  2. Natureza dos Centros de Custo, que deve retornar os tipos possíveis de natureza, conforme o aplicativo em Progress® (neste caso, o EMS2).
  3. Centros de Custo, que deve retornar os registros na tabela conta 2.
  4. 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
themeEclipse
languagejavafx
titleCostCenterUtils.p
firstline1
linenumberstrue
/**************************************************************************
** 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
themeEclipse
languagejavafx
titleverifyUsers.p
firstline1
linenumberstrue
/**************************************************************************
** 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:

  1. O AppServer deve ser carregado no modo Stateless;
  2. 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
startHiddenfalse
effectDuration0.5
idproxyGen
historyfalse
effectTypefade
Card
defaulttrue
id1
label1º Passo

 

  • Na primeira tela do ProxyGen, o principal ponto que deve ser observado é o nome do Projeto (no exemplo, EMSProxies). A informação deste campo será utilizada pelo ProxyGen para nomear a classe de acesso ao serviço, e que será utilizada na configuração do serviço no Fluig. Nesta tela também é preciso configurar o PROPATH corretamente, para que seja possível encontrar os arquivos compilados (.r).

Integração Com Aplicativos Externos > proxygen-1.png" src="http://tdn.totvs.com/download/attachments/73082260/proxygen-1.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/proxygen-1.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406790" data-linked-resource-type="attachment" data-linked-resource-default-alias="proxygen-1.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > proxygen-1.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/proxygen-1.png?version=1&modificationDate=1377284793000&api=v2">

 

Card
id2
label2º Passo

 

  • O segundo passo consiste em inserir quais procedures serão expostas de forma persistente ou não-persistente. A escolha de qual opção utilizar depende da forma como cada objeto exposto foi construído. Após inseridas as procedures, clicar na opção Generate.

Integração Com Aplicativos Externos > proxygen-2.png" src="http://tdn.totvs.com/download/attachments/73082260/proxygen-2.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/proxygen-2.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406789" data-linked-resource-type="attachment" data-linked-resource-default-alias="proxygen-2.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > proxygen-2.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/proxygen-2.png?version=1&modificationDate=1377284793000&api=v2">

 

Card
id3
label3º Passo

 

  • Durante o processo de geração do proxy, na aba General, assinalar a opção Java em Client Proxy e informar o diretório onde o proxy será gerado em Output Dir. Observe também o campo AppService, este deve ser o nome do serviço publicado no AppServer, caso contrário não será possível conectar ao servidor.

Integração Com Aplicativos Externos > proxygen-3.png" src="http://tdn.totvs.com/download/attachments/73082260/proxygen-3.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/proxygen-3.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406788" data-linked-resource-type="attachment" data-linked-resource-default-alias="proxygen-3.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > proxygen-3.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/proxygen-3.png?version=1&modificationDate=1377284793000&api=v2">

 

Card
id4
label4º Passo

 

  • A última informação relevante para a geração do proxy é o nome do pacote (package) onde as classes serão criadas. Esta informação é utilizada durante a configuração do serviço Progress® no Fluig. Para finalizar clicar no botão OK.

  Integração Com Aplicativos Externos > proxygen-4.png" src="http://tdn.totvs.com/download/attachments/73082260/proxygen-4.png?version=1&modificationDate=1377284793000&api=v2" data-image-src="/download/attachments/73082260/proxygen-4.png?version=1&modificationDate=1377284793000&api=v2" data-linked-resource-id="73406787" data-linked-resource-type="attachment" data-linked-resource-default-alias="proxygen-4.png" data-base-url="http://tdn.totvs.com" data-linked-resource-container-id="73082260" data-location="Fluig > Integração Com Aplicativos Externos > proxygen-4.png" data-mce-src="http://tdn.totvs.com/download/attachments/73082260/proxygen-4.png?version=1&modificationDate=1377284793000&api=v2">

 

Card
id5
labelÚltimo Passo

 

  • Uma vez criadas as classes, é preciso empacotá-las em um arquivo .JAR. Isto pode ser feito via linha de comando, utilizando-se o comando abaixo:

Sem Formato
jar -cvf <jar_file_name> <diretorio>

 

Observe apenas que no arquivo gerado, é preciso que as classes estejam nos diretórios corretos. No exemplo apresentado, o diretório com deve ser incluído e estar no raiz do arquivo JAR. Por ser compatível com o formato ZIP, uma outra opção é gerar um arquivo com as classes geradas (respeitando-se os diretórios) e renomeá-lo para a extensão .JAR.

 

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:

  • ServidorServidor 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 CustoNatureza dos Centros de CustoCentros 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
themeEclipse
languagejavascript
titledsTipoCentroCusto.js
firstline1
linenumberstrue
function
	</p>
	<p>&#160;</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 &lt; 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
themeEclipse
languagejavascript
titledsNaturezaCentroCusto.js
firstline1
linenumberstrue
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
themeEclipse
languagejavascript
titledsCentroCustoP9.js
firstline1
linenumberstrue
function
	</p>
	<p>&#160;</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
themeEclipse
languagejavascript
titledsCentroCustoOE10.js
firstline1
linenumberstrue
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 &lt;< 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
themeEclipse
languagejavascript
titledsUsuariosComunsP9.js
firstline1
linenumberstrue
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
themeEclipse
languagejavascript
titledsUsuariosComunsOE10.js
firstline1
linenumberstrue
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®:

RetornoMétodo e Descrição
java.lang.ObjectcreateBigDecimalHolder()
Cria um objeto Holder para o tipo DECIMAL
java.lang.ObjectcreateBooleanHolder()
Cria um objeto Holder para o tipo LOGICAL
java.lang.ObjectcreateByteArrayHolder()
Cria um objeto Holder para o tipo RAW
java.lang.ObjectcreateCOMHandleHolder()
Cria um objeto Holder para o tipo COM-HANDLE
java.lang.ObjectcreateDateHolder()
Cria um objeto Holder para o tipo DATE
java.lang.ObjectcreateHandleHolder()
Cria um objeto Holder para o tipo WIDGET-HANDLE (Handle)
java.lang.ObjectcreateIntHolder()
Cria um objeto Holder para o tipo INTEGER
java.lang.ObjectcreateLongHolder()
Cria um objeto Holder para o tipo RECID
java.lang.ObjectcreateManagedObject(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.ObjectcreateMemptrHolder()
Cria um objeto Holder para o tipo MEMPTR
java.lang.ObjectcreateProDataGraph(java.lang.Object metadata)
Cria um objeto da classe ProDataGraph
java.lang.ObjectcreateProDataGraphHolder()
Cria um objeto Holder para o tipo ProDataGraphHolder
java.lang.ObjectcreateProDataGraphMetaData(java.lang.String name)
Cria um objeto da classe ProDataGraphMetadata
java.lang.ObjectcreateProDataObjectMetaData(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.ObjectcreateResultSetHolder()
Cria um objeto Holder para o tipo TABLE
java.lang.ObjectcreateRowidHolder()
Cria um objeto Holder para o tipo ROWID
java.lang.ObjectcreateStringHolder()
Cria um objeto Holder para o tipo CHARACTER.
java.lang.ObjectgetProxy()
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.Objectinstantiate(java.lang.String className)
Instancia um objeto de uma classe dentro da biblioteca do proxy.
java.lang.ObjecttoProDataGraph(com.datasul.technology.webdesk.dataset.

...

DefaultDataset d)
Transforma um dataset em um ProDataGraph.