Desenvolvendo um aplicativo remoto de mashup de cliente e servidor com IBM Worklight

Este artigo ilustra o processo de desenvolvimento de um aplicativo remoto híbrido que combina dados, apresentação e funcionalidade de várias fontes, nos lados de cliente e de servidor. As principais características de um aplicativo de mashup assim são a combinação, visualização e agregação de diferentes fontes. São utilizados várias origens da web publicadas, bem como dados de um banco de dados relacional que pode ser hospedado por uma empresa. Você verá que o IBM® Worklight V5 é uma plataforma ideal para desenvolver esses aplicativos híbridos baseados em mashup, que podem ser utilizados em diversos dispositivos móveis. Este conteúdo é parte do IBM WebSphere Developer Technical Journal.

Walter M. Jenny, Executive Architect, IBM

Author photo of Walter JennyWalter Jenny é Executive Architect no Software Group da IBM. Ele tem mais de 20 anos de experiência no desenvolvimento de aplicativos e gerenciamento de processos de negócios. Walter tem mestrado em ciência da computação, mestrado e doutorado em administração de empresas.



08/Out/2012

Introdução

Obtenha já o Worklight

Faça o download do IBM Worklight Developer Edition 5.0 sem custo e sem data de expiração!

IBM Worklight V5 é uma plataforma de aplicativo remoto aberta, abrangente e avançada, que pode ajudar a desenvolver, executar e gerenciar aplicativos HTML5, híbridos e nativos.

Usando tecnologias e ferramentas baseadas em normas, middleware otimizado para dispositivos remotos, diversos mecanismos de segurança e recursos integrados de gerenciamento e analítica, o Worklight simplifica o ciclo de vida de desenvolvimento de aplicativos para várias plataformas remotas, incluindo iOS, Android, BlackBerry e Windows® Phone. Como um ambiente de desenvolvimento visual baseado em Eclipse, o Worklight ajuda a acelerar o desenvolvimento, teste e entrega de aplicativos remotos usando tecnologias abertas, como HTML5, Apache Cordova, JavaScript™ e estruturas populares de JavaScript, como Dojo, jQuery e Sencha Touch.

Para determinar quais tecnologias usar ao desenvolver um aplicativo remoto, é necessário entender a natureza das diferentes abordagens de desenvolvimento para aplicativos da web móvel, híbridos e nativos:

  • Aplicativos da web móvel podem ser executados em quase qualquer dispositivo, pois não se associam a recursos nativos do dispositivo (como armazenamento de arquivo local, notificações push etc). Esses aplicativos são geralmente baseados em HTML5, em conjunto com CSS e JavaScript. O uso dessas tecnologias já estabelecidas ajuda a reduzir o custo de desenvolvimento, pois elas permitem a reutilização das qualificações disponíveis e não exigem desenvolvedores da plataforma nativa. Um único ciclo de vida de implementação, manutenção e teste também é menos complexo. Além disso, não é necessário lançar o aplicativo em lojas de apps proprietárias, o que poderia reduzir a receita em potencial e tornar a manutenção mais complicada.
  • Aplicativos híbridos são formados por HTML5, CSS e JavaScript, com acesso aos recursos nativos do dispositivo móvel. Eles oferecem todas as vantagens dos aplicativos da web móvel, incluindo a capacidade do aplicativo de executar em várias plataformas, mas também podem utilizar os recursos nativos do dispositivo. Essa abordagem geralmente usa uma estrutura que "virtualiza" os recursos nativos do dispositivo. Essa abstração é realizada através de uma ponte JavaScript, como Apache Cordova (antiga estrutura PhoneGap). Essa combinação maximiza a experiência do usuário e oferece maior flexibilidade e escalabilidade para desenvolver aplicativos em vários dispositivos. Para lidar com fatores de forma e recursos de dispositivos diferentes, são usadas aparências.
  • Aplicativos nativos são úteis para utilizar todos os recursos nativos do dispositivo, incluindo a aparência. Essa abordagem é recomendada quando é necessário usar as funções complexas do dispositivo que exigem mais memória. No entanto, essa abordagem é geralmente mais cara e menos escalável, pois é necessário desenvolver, manter e testar o código nativo para diferentes dispositivos.

A abordagem de aplicativo híbrido usa a eficiência do Worklight para combinar o melhor dos dois mundos: ela oferece suporte a aplicativos escritos principalmente em HTML5, CSS e JavaScript, mas também permite acesso total aos recursos do dispositivo através do Cordova como parte de seu tempo de execução de cliente remoto. Cordova é uma estrutura remota que permite atingir de forma nativa todos os smartphones com uma única base de código para um WebView ou Webkit no dispositivo.

Neste artigo, você irá explorar alguns dos recursos do Worklight para criar um aplicativo híbrido que mistura dados, apresentação e funcionalidade de várias fontes nos lados do cliente e do servidor. É incluído código de amostra para que você teste em seu ambiente.


Arquitetura Worklight

O cenário descrito neste artigo usa vários componentes do Worklight (Figura 1):

  • IBM Worklight Studio é um IDE baseado em Eclipse que permite realizar todas as tarefas de codificação e integração necessárias para desenvolver um aplicativo completamente operacional.
  • IBM Worklight Server é um gateway, baseado em Java, entre os aplicativos, serviços externos e a infraestrutura de backend corporativa. Worklight Server contém recursos de segurança para permitir conectividade, extração e manipulação de dados de mais de uma origem, autenticação, atualização direta de aplicativos da web e híbridos e de analítica, e funções de gerenciamento operacional. Worklight Server pode ser executado como um aplicativo dedicado em um servidor de aplicativo Java EE, como o WebSphere Application Server. Para este artigo, usaremos o servidor leve Jetty HTTP incluído com o Worklight Studio.
  • IBM Worklight Device Runtime Components fornece o SDK e o tempo de execução do aplicativo remoto no lado do cliente para os ambientes genérico e de outros destinos. Também integra a parte do cliente da funcionalidade de integração do servidor.
  • IBM Worklight Console é uma UI baseada na web dedicada ao monitoramento e administração contínuos do Worklight Server e seus aplicativos implementados, adaptadores e notificações push.
Figura 1. Principais componentes do Worklight
Principais componentes do Worklight

Para este cenário, imagine que precisamos apresentar informações de várias origens, todas relacionadas a um local específico. Podem ser informações sobre vendas fornecidas por agentes de campo ou territórios geográficos, em diversos formatos. Por simplicidade, usaremos apenas origens públicas da Internet.

Todo o código (HTML, CSS e JavaScript) será desenvolvido no Worklight Studio e depois implementado no servidor Worklight. O Worklight fornece uma estrutura de integração de adaptadores que conecta-se a sistemas de backend, entrega dados a aplicativos remotos e realiza nos dados a lógica necessária no lado do servidor. O Worklight Console será útil para controlar o aplicativo e como um ponto de partida.

O fluxo de controle básico do aplicativo de amostra é mostrado na Figura 2.

Figura 2. Fluxo de controle
Fluxo de controle
  1. O aplicativo da web remoto é carregado a partir do Worklight Server.
  2. Como parte do arquivo HTML inicial, um widget customizado é criado para chamar a API do Google Maps para renderizar um mapa, inicialmente com a localização atual do usuário, através do recurso de localização geográfica do HTML5.
  3. O aplicativo chama o adaptador do lado do servidor para fornecer uma lista de locais.
  4. O LocationAdapter do lado do servidor recupera, via JDBC, um array de locais do banco de dados DB2® e o envia de volta para o cliente móvel.
  5. Quando o usuário seleciona um novo local, a posição no mapa é atualizada e informações relacionadas são recuperadas através de NewsAdapter.
  6. NewsAdaptor primeiro coleta dados do Google News Feed.
  7. Em seguida, ele usa encadeamento para chamar StockAdapter para recuperar números de ações do Yahoo! Finance e aumentar essas informações.

Vamos ver os dois principais componentes que devem ser desenvolvidos nesses aplicativos - a parte do cliente e a do servidor - e executá-los em um simulador remoto.


A parte do cliente

Vamos começar com a parte do cliente.

  1. No Worklight Studio, crie um projeto do Worklight selecionando File > New > Worklight Project ou clicando em Create Worklight Artifacts (Figura 3).
    Figura 3. Criar projeto do Worklight
    Criar projeto do Worklight
  2. Dê um nome ao Project Mashup, selecione um modelo de Hybrid Application e clique em Next (Figura 4).
    Figura 4. Selecione um aplicativo híbrido
    Selecione um aplicativo híbrido
  3. Dê ao aplicativo o nome de Mashup. Selecione Add Dojo Toolkit, que permite ao aplicativo usar os recursos da biblioteca Dojo JavaScript e clique em Finish (Figura 5).
    Figura 5. Criar aplicativo do Worklight
    Criar aplicativo do Worklight

Isso cria a estrutura básica do projeto do Worklight (Figura 6). (Consulte documentação do usuário do IBM Worklight e Trabalhando com o Worklight, Parte 1: Introdução ao Primeiro Lançamento do Aplicativo Worklight para detalhes sobre esses elementos principais.)

Figura 6. Estrutura básica de projeto do Worklight
Estrutura básica de projeto do Worklight

O próximo conjunto de etapas envolve a criação de lógica para renderizar um mapa enriquecido com informações de localização geográfica. Para fazer isso, é possível escrever o código JavaScript necessário em Mashup.js diretamente, usando o Dojo Toolkit incluído com a estrutura Dijit, um conjunto de widgets eficiente e abrangente. No entanto, caso queira desenvolver algo que possa ser reutilizado por outras pessoas da equipe de desenvolvimento, um widget customizado é uma boa abordagem.

Criar um widget customizado do Dijit

Para esse cenário, é necessário um widget customizado que mostra dados em um mapa relacionados a um local específico. A primeira parte do desenvolvimento envolve mostrar o local atual e renderizá-lo em um mapa padrão do Google. Em seguida, será desenvolvido um widget customizado para encapsular esses elementos reutilizáveis da UI, junto com uma funcionalidade adicional específica. Essas etapas para criar o widget Dojo customizado incluem:

  1. Criar a estrutura de arquivo para o widget customizado

    Considera-se uma boa prática ter uma estrutura de arquivos apropriada para o trabalho customizado no Dijit, e o Worklight Studio tem suporte para essa abordagem. Você irá criar uma pasta chamada custom, que representará o namespace. (É possível usar qualquer nome que você queira, mas é melhor algo com significado, como o nome do aplicativo ou da organização.)

    Worklight Studio facilita muito essa etapa:

    1. Clique com o botão direito na pasta /Mashup/apps/Mashup/common na visualização Explorer e selecione New > Dojo Widget. O assistente New Dojo Widget aparece. Para Module Name, insira custom; para Widget Name, insira LocationViewer. O modelo HTML e folha de estilo dos caminhos do widget são preenchidos automaticamente (Figura 7).
      Figura 7. Assistente New Dojo Widget
      Assistente New Dojo Widget
    2. Clique em Finish. Três arquivos são criados na pasta common (Figura 8).
      Figura 8. Assistente New Dojo Widget
      Assistente New Dojo Widget
  2. Criar a classe de widget usando define

    O Worklight Studio abre automaticamente o arquivo de origem JavaScript de LocationViewer no editor, contendo a instrução Dojo gerada (Listagem 1, comentários removidos).

    Listagem 1. Criar o código JavaScript do widget customizado
    define("custom/LocationViewer", [ "dojo", "dijit", "dijit/_Widget",
    		"dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
    		"dojo/text!custom/templates/LocationViewer.html" ], function(dojo,
    		dijit, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin) {
    	return dojo.declare("custom.LocationViewer", [ dijit._Widget,
    			dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin ],
    {
    templateString : dojo.cache("custom",	"templates/LocationViewer.html"),
    constructor : function() {
    		},
    	postMixInProperties : function() {
    		},
    	postCreate : function() {
    		}
    	});
    });

    O formato do módulo AMD substitui dojo.provide e dojo.require por define ao criar os módulos customizados. Essas chamadas definem são idênticas às chamadas require, exceto pelo fato de que o retorno de chamada retorna um valor que é salvo e usado como o valor resolvido do módulo. O Worklight Studio declarou o widget customizado LocationViewer, usando dijit/_WidgetBase e dijit/_TemplatedMixin como base.

    Dica: caso queira criar o mesmo modelo sem usar o assistente (por exemplo, ao trabalhar com um arquivo JS existente), é possível usar o mecanismo de geração de código integrado. Para isso, digite decl e Ctrl+Space (Figura 9).

    Figura 9. Declarando um widget Dijit sem o assistente
    Declarando um widget Dijit sem o assistente

    Em seguida, é necessário definir algumas propriedades, para que o widget saiba quais tipos de propriedade ele receberá (Listagem 2).

    Listagem 2. Configurando as propriedades
    zoom			: 10,
    address		: "",
    // Define reasonable defaults for mobile devices
    containerWidth	: "320px",
    containerHeight	: "460px",

    A função postMixInProperties é chamada quando todas as variáveis herdadas de superclasses são "misturadas". Operações comuns para postMixInProperties são modificação ou designação de valores para variáveis de propriedade do widget definidas no arquivo HTML de modelo. Aqui basta chamar o método da superclasse (Listagem 3).

    Listagem 3. Configurando as propriedades "misturadas"
    postMixInProperties : function() {
    	this.inherited('postMixInProperties', arguments);
    },

    O método postCreate é chamado quando a estrutura DOM do widget estiver pronta, mas antes de ser inserida na página. Esse é geralmente o melhor ponto para colocar qualquer tipo de código de inicialização. Por ora, iremos chamar quem fará a maior parte do trabalho: a função refreshMap, que cria o mapa do Google com um endereço vazio e sem informações. Para manter a cadeia do construtor, chame o método de superclasse (Listagem 4).

    Listagem 4. Inicializar o widget customizado
    postCreate : function()
    {
    this.refreshMap(this.address, "");
    	this.inherited('postCreate', arguments);
    },

    A funcionalidade real é implementada na função refreshMap. Quando chamada com um endereço vazio e sem informações, usamos o recurso de localização geográfica do HTML5 para obter a posição atual. Do contrário, tentamos localizar o endereço dado no mapa usando o Geocoder do Google. O conteúdo de InfoWindow é passado como um argumento (Listagem 5).

    Listagem 5. Desenhando o mapa
    refreshMap : function(address, information)
    {
      var localZoom = this.zoom;
      var mapOptions = {
                zoom : localZoom,
                mapTypeId : google.maps.MapTypeId.ROADMAP
      };
      var map = new google.maps.Map(this.mapNode, mapOptions);
      if (address == null || address == "")
      {
        if(navigator.geolocation) // Try HTML5 geolocation
        {
          navigator.geolocation.getCurrentPosition(function(position)
          {
            var pos = new google.maps.LatLng(position.coords.latitude,
                                             position.coords.longitude);
            var infoWindow = new google.maps.InfoWindow({map : map,
                                             position :        pos,
                                             content : 'This your current location<br>' +
    		Found using <a href="http://dev.w3.org/geo/api/spec-source.html">HTML5 
    		Geolocation</a>'
          });
          map.setCenter(pos);
          infoWindow.open(map);
        }, function() {
          handleNoGeolocation(true);
          });
        }
        else // Browser doesn't support Geolocation
        {
          handleNoGeolocation(false);
        }
        return;
      }
      var geocoder = new google.maps.Geocoder();
      geocoder.geocode({'address' : address
      }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK)
        {
          map.setCenter(results[0].geometry.location);
          var infoWindow = new google.maps.InfoWindow({ content  : information,
    maxWidth : 230
          });
          var marker = new google.maps.Marker({ map      : map,
                                                position : results[0].geometry.location
          });
          infoWindow.open(map, marker);
          }
          else
          {
            alert("Error: " + status);
          }
        });
      },
      handleNoGeolocation : function (errorFlag)
      {
        …
      }

O que é AMD?

O formato Asynchronous Module Definition (AMD) é o novo formato de módulo do Dojo 1.7 e posteriores, substituindo dojo.provide, dojo.require, dojo.requireIf, dojo.requireAfterIf, dojo.platformRequire e dojo.requireLocalization. Ele tem muitas melhorias em relação ao estilo de módulo legado do Dojo, incluindo operação totalmente assíncrona, portabilidade real de pacotes, melhor gerenciamento de dependências e melhor suporte a depuração. AMD também é um padrão motivado pela comunidade, o que significa que módulos escritos na especificação AMD podem ser usados com qualquer carregador ou biblioteca que siga o padrão. Consulte Defining Modules para mais informações.

  1. Criar o código HTML do widget customizado

    Os modelos devem sempre ter um elemento-pai de agrupamento que contenha todos os demais elementos. Pode ser qualquer elemento que você queira, mas é importante que tenha apenas um elemento-raiz. Para nosso widget básico, basta usar div como o elemento de agrupamento.

    Na visualização Explorer, clique duas vezes em templates/LocationViewer.html para abrir o modelo HTML do widget e concluir o código, como mostra a Listagem 6.

    Listagem 6. Código HTML do widget customizado
    <div>
    	<div dojoAttachPoint="mapNode"
                 style="width:${containerWidth}; height:${containerHeight}">
    	</div>
    </div>

    Usando dijit/_TemplatedMixin, é possível usar a sintaxe ${attribute} para inserir diretamente alguns valores, como containerWidth. Os nós devem receber um ponto de conexão, ou seja, um nome que possa ser usado no código do widget para fazer uma referência direta ao nó. Isso é semelhante a chamar getElementById. As referências são configuradas antecipadamente.

  2. Crie o estilo apropriado

    Caso você precise de instruções CSS especiais, pode customizar themes/LocationViewer.css.

  3. Use o widget customizado no seu aplicativo

    O widget customizado está agora disponível na seção Other Dojo Widgets da paleta do Worklight Studio (Figura 10). O Rich Page Editor do Worklight Studio oferece suporte para que você use esse widget em seu projeto.

    Figura 10. Widget customizado no modelo do Worklight Studio
    Widget customizado no modelo do Worklight Studio

    Na visualização Explorer, clique duas vezes em js/Mashup.html para abrir o modelo HTML. Remova o texto "Mashup". Arraste um dojox.mobile.View da paleta "Dojo Mobile Widgets" para Mashup.html e solte-o próximo do comentário <!-- application UI goes here -->. Arraste o ícone locationViewer para Mashup.html e solte-o dentro do div de dojox.mobile.View. Inclua a referência à API do mapa do Google (linha em negrito na Listagem 7) e inclua um ID para LocationViewer, no código ou através da guia Properties.

    Dependendo da sua preferência, é possível escrever esse código manualmente ou aproveitar o Design Mode do Rich Page Editor para orientá-lo sobre o posicionamento do código ao soltar um widget em um contêiner de widget. Dicas visuais indicam os possíveis locais de descarte, e dicas pop-up indicam as funções de edição disponíveis para o widget selecionado. Por exemplo, ao arrastar o LocationViewer da paleta para View, uma dica visual do posicionamento é exibida. O Rich Page Editor usa navegadores integrados para produzir uma representação visual de uma página da web na visualização Design. (Consulte Module 03.5 - Rich Page Editor para obter mais detalhes.)

    Figura 11. Modo Design do Rich Page Editor
    Modo Design do Rich Page Editor

    O Worklight Studio irá inserir todo o restante do código necessário (Listagem 7).

    Listagem 7. Widget customizado no arquivo HTML principal
    <!DOCTYPE html>		
    <html>
    	<head>
    		<meta charset="utf-8" />
    <meta name="viewport"
    	content="width=device-width, initial-scale=1, maximum-scale=1, 
    	user-scalable=no" />
    <title>Mashup</title>
    		<link rel="shortcut icon" href="images/favicon.png" />
    		<link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
    		<link rel="stylesheet" href="css/reset.css" />
    		<link rel="stylesheet" href="css/Mashup.css" />
    <script type="text/javascript"
    	data-dojo-config="isDebug: false, async: true, parseOnLoad: true"
    	src="dojo/dojo.js"></script>
    <script type="text/javascript" src="dojo/core-web-layer.js"></script>
    <script type="text/javascript" src="dojo/mobile-ui-layer.js"></script>
    <script type="text/javascript" src="dojo/mobile-compat-layer.js"></script>
    <!--  add this line -->
    <script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript">
    require(
    // Set of module identifiers
    [ "dojo", "dojox/mobile/parser", "dojox/mobile/View", "dojox/mobile", 
    	"dojox/mobile/compat", "dojox/mobile/deviceTheme", "custom/LocationViewer" ],
    // Callback function, invoked on dependencies evaluation results
    function(dojo) {
    	dojo.ready(function() {
    
    	});
    });
    </script>
    <meta name="apple-mobile-web-app-capable" content="yes">
    </head>
    	<body onload="WL.Client.init({})" id="content" style="display: none">
    	<div data-dojo-type="dojox.mobile.View" id="view0"
    		data-dojo-props="selected:true">
    		<div data-dojo-type="custom.LocationViewer" id="locationViewer"></div>
    	</div>
    
    	<script src="js/Mashup.js"></script>
    		<script src="js/messages.js"></script>
    		<script src="js/auth.js"></script>
    	</body>
    </html>

Executando o aplicativo

Para executar e testar essa primeira versão do aplicativo, é necessário publicá-la em um servidor Worklight local. O Worklight Studio V5 contém um servidor local integrado que pode ser usado para testar o código criado acima. Clique com o botão direito do mouse em apps/Mashup e selecione Run as > Build All and Deploy. Isso irá iniciar o servidor local na porta 8080, ativar o projeto e implementar o aplicativo para que você teste em um navegador.

Figura 12. Aplicativo implementado no Worklight Console
Aplicativo implementado no Worklight Console

Para abrir o aplicativo no navegador, clique no ícone ou no link Preview as Common Resources. Como esperado, o local atual é exibido (Figura 13).

Figura 13. Visualização do aplicativo
Visualização do aplicativo

A parte do servidor

A próxima etapa é incluir o acesso aos recursos de backend. A ferramenta escolhida são os adaptadores do Worklight, que conectam a sistemas de backend, entregam dados de aplicativos remotos e realizam nos dados a lógica necessária no lado do servidor. A estrutura do adaptador oferece:

  • JavaScript flexível e eficiente, no lado do servidor, que produz código sucinto e legível para integração com aplicativos de backend e processamento. Também é possível usar XSL para transformar dados de backend hierárquicos em JSON.
  • Suporte a modos de acesso somente leitura e transacional aos sistemas de backend.
  • Recursos flexíveis de autenticação para criar conexões com sistemas de backend. Adaptadores oferece controle sobre a identidade do usuário com quem a conexão é feita.
  • Os dados recuperados dos aplicativos de backend são expostos de forma consistente, de modo que é possível acessar os dados de maneira uniforme, independente da origem, formato ou protocolo.

Criar LocationAdapter

O Worklight oferece estes adaptadores:

  • Adaptador de SQL
  • Adaptador de HTTP (suporte para REST e SOAP)
  • Adaptador de Cast Iron

Usaremos o adaptador de SQL para acessar informações contidas em um banco de dados relacional.

Os procedimentos de adaptadores são declarados usando XML e são, geralmente, implementados em JavaScript. Mas, como um adaptador é uma entidade do lado do servidor, é possível usar fragmentos Java no código do adaptador. Um procedimento pode processar os dados antes ou depois de chamar o serviço.

LocationAdapter é um adaptador muito básico que consulta um banco de dados DB2 com a tabela mostrada na Listagem 8.

Listagem 8. Código SQL para criar o banco de dados DB2
CREATE SCHEMA TRAVEL;
SET SCHEMA = TRAVEL;
	
DROP TABLE travel.locations;
CREATE TABLE travel.locations
	(
	city varchar(10),
	country varchar(20),
	stock varchar(10)
	);

DELETE FROM travel.locations;
INSERT INTO travel.locations values ( 'Paris', 'France', 'FCHI');
INSERT INTO travel.locations values ( 'London', 'UK', 'FTSE');
INSERT INTO travel.locations values ( 'New York', 'US', 'DJI');
INSERT INTO travel.locations values ( 'Frankfurt', 'Germany', 'GDAXI');
INSERT INTO travel.locations values ( 'Tokyo', 'Japan', 'N225');
INSERT INTO travel.locations values ( 'Madrid', 'Spain', 'IBEX');

Esse código SQL pode ser executado na perspectiva Database do Worklight Studio, ou em qualquer ferramenta semelhante. Para criar LocationAdapter, clique com o botão direito na pasta apps/Mashup na visualização Explorer e selecione New > Worklight Adapter. O assistente New Worklight Adapter é exibido (Figura 14).

Figura 14. Assistente New Worklight Adapter
Assistente New Worklight Adapter

Em Adapter type, selecione SQL Adapter e, em Adapter name, insira LocationAdapter. Isso cria a estrutura de arquivo do projeto mostrada na Figura 15.

Figura 15. Estrutura de arquivo do adaptador
Estrutura de arquivo do adaptador

É necessário atualizar LocationAdapter.xml para usar a conectividade correta do banco de dados. Nesse caso, configure a origem de dados para um banco de dados DB2 e altere o nome do procedimento padrão para getLocations (Listagem9).

Listagem 9. Conectividade de LocationAdapter
<displayName>LocationAdapter</displayName>
<description>LocationAdapter</description>
<connectivity>
	<connectionPolicy xsi:type="sql:SQLConnectionPolicy">
		<dataSourceDefinition>
			<driverClass>com.ibm.db2.jcc.DB2Driver</driverClass>
			<url>jdbc:db2://localhost:50001/TRAVELDB</url>
		<user>user</user>
		<password>password</password> 
		</dataSourceDefinition>
</connectionPolicy>
<loadConstraints maxConcurrentConnectionsPerNode="5" />
</connectivity>
<procedure name="getLocations"/>

Um procedimento alternativo é clicar com o botão direito em LocationAdapter.xml e selecionar Open With > Adaptor Editor para inserir as configurações (Figura 16).

Figura 16. Adapter Editor
Adapter Editor

A lógica do adaptador é implementada em adapters/LocationAdapter/LocationAdapter-impl.js. Um procedimento declarado no arquivo XML do adaptador deve ser implementado no arquivo JavaScript correspondente. Para essa instrução SQL básica, há dois métodos fornecidos pela estrutura do adaptador Worklight que podem ser aplicados:

  • WL.Server.createSQLStatement() cria uma instrução SQL preparada, a ser chamada posteriormente com WL.Server.invokeSQLStatement. O método pode ser usado apenas dentro de um procedimento declarado dentro de um adaptador SQL. Deve ser usado fora do escopo de uma função JavaScript. O método aceita qualquer instrução SQL válida que inclua pontos de interrogação ("?") como marcadores de parâmetro e retorna um objeto que representa a instrução preparada.
  • WL.Server.invokeSQLStatement() toma estes parâmetros:
    • preparedStatement, retornado pelo método acima
    • um array de parâmetros opcionais para a instrução preparada
    • transformation, uma transformação XSL opcional para a resposta

    O método retorna o conjunto de resultados da instrução preparada, após o processamento opcional. (Consulte o IBM Worklight V5.0 Developer Reference Guide para obter mais detalhes.)

Use esses dois métodos na implementação mostrada na Listagem 10.

Listagem 10. Implementação de LocationAdapter
var procedure1Statement = WL.Server.createSQLStatement("select * from travel.locations 
	order by city");
function getLocations() {
	return WL.Server.invokeSQLStatement({
		preparedStatement : procedure1Statement,
		parameters : []
	});
}

Observe a simplicidade e elegância do código. Um adaptador como esse pode ser chamado em qualquer aplicativo Worklight, no lado do cliente ou do servidor. Ele permite que o responsável pela chamada comunique-se com qualquer origem de dados sem estar sujeito a restrições da mesma origem.

Também é necessário um driver JDBC. Se você implementou o console do Worklight em um WebSphere Application Server pré-configurado, talvez o driver JDBC do DB2 já esteja no caminho de classe. Nesse exemplo, usaremos o mecanismo HTTP Jetty integrado, para o qual é necessário fornecer o driver JDBC (db2jcc4.jar, caso use o driver tipo 4) da instalação do DB2. Copie esse arquivo para a pasta server/lib ou inclua sua localização no caminho de classe do Jetty.

Para executar um teste rápido da configuração e código do adaptador, clique com o botão direito em adapters/LocationAdapter e selecione Run As > Invoke Worklight Procedure.

Figura 17. Chamando LocationAdapter
Chamando LocationAdapter

No assistente Edit Configuration, selecione getLocations como Procedure name e clique em Run. Isso chama o adaptador de destino de dentro do navegador (Figura 18.

Figura 18. Resultado da chamada
Resultado da chamada

Agora você está pronto para implementar o adaptador. Para isso, clique com o botão direito em Adapter e selecione Run As > Deploy Worklight Adapter (Figura 19).

Figura 19. Implementando LocationAdapter
Implementando LocationAdapter

O Worklight Studio arquiva o código do adaptador e implementa no Worklight Server. O adaptador implementado aparece no Worklight Console, junto com o aplicativo de mashup inicial (Figura 20).

Figura 20. LocationAdapter implementado
LocationAdapter implementado

Encadeamento de adaptador

De maneira semelhante, criamos os dois outros adaptadores como instâncias do HTTPAdapter. Lembre-se que, como mostrou a Figura 2, a parte do cliente chama NewsAdapter quando precisa de informações relacionadas para um local específico. Essa informação de local é passada para o lado do servidor e os dados relacionados são agregados a partir de duas fontes - Google News Feed e Yahoo! Finance – em efeito um mashup do lado do servidor a partir de diferentes fontes. Essa agregação também é chamada de encadeamento de adaptador (Figura 21).

Figura 21. Cadeia de adaptadores
Cadeia de adaptadores

o encadeamento de adaptadores permite que todo o processamento do lado do servidor seja executado em uma única chamada de cliente. Essas interações de "granularidade bruta" são consideradas boa prática. A maneira como se usa esse padrão depende dos requisitos concretos. Por exemplo, qual o volume de dados que precisa ser recuperado, qual é o custo da lógica de processamento no lado do servidor, se é possível armazenar em cache no lado do cliente e trabalhar com dados fixos, e assim por diante. Obviamente, essas considerações de arquitetura não são novas nem limitadas aos dispositivos móveis, mas são decisões importantes a serem tomadas em qualquer arquitetura multicamada.

Criar os adaptadores restantes

Primeiro é preciso implementar o último link na cadeira, StockAdaptor. É uma simples chamada para o serviço Yahoo! Finance. A conectividade é configurada como mostrado na Listagem 11.

Listagem 11. Conectividade de StockAdapter
>displayName>StockAdapter>/displayName>
>description>StockAdapter>/description>
>connectivity>
	>connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
			>protocol>http>/protocol>
			>domain>finance.yahoo.com>/domain>
			>port>80>/port>			
	>/connectionPolicy>
	>loadConstraints maxConcurrentConnectionsPerNode="2" />
>/connectivity>
>procedure name="getStock"/>

A chamada para o serviço Yahoo! Finance precisa de um símbolo de ação específico (o índice de ação do país, como DJI ou FTSE, é usado aqui como exemplo), bem como detalhes dos números exatos que são necessários. O serviço retorna um fluxo de dados em comma separated values (CSV). Por isso, configure returnedContentType para csv (Listagem12). Esse é outro bom recurso trazido pela estrutura de adaptador.

Listagem 12. Implementação de StockAdapter
function getStock(stock) {
	var input = {
	    method : "get",
	    returnedContentType : "csv",
	    path : "d/quotes.csv",
		parameters : {
			"s" : "^" + stock,
			"f" : "sl1c1c"
		}
	};
	return WL.Server.invokeHttp(input);
}

Para chamar o serviço Google News, é necessário configurar a conectividade mostrada na Listagem 13.

Listagem 13. Conectividade de NewsAdapter
>displayName<NewsAdapter>/displayName<
>description<NewsAdapter>/description<
>connectivity<
	>connectionPolicy xsi:type="http:HTTPConnectionPolicyType"<
		>protocol<http>/protocol<
		>domain<news.google.com>/domain<
		>port<80>/port<			
	>/connectionPolicy<
	>loadConstraints maxConcurrentConnectionsPerNode="2" /<
>/connectivity<
>procedure name="getNews"/<

Passamos as informações de local e obtemos o canal RSS de notícias para esse interesse específico. O canal RSS contém um array de itens. Para manter os dados breves, capturamos apenas o primeiro item no array. Também poderíamos usar o XSL para filtrar o conteúdo que é realmente necessário.

O próximo link na cadeia de adaptadores, StockAdapter, é chamado como parte do pós-processamento. A maneira como a chamada é realizada é discutida a seguir. Ambos os itens de dados são agregados no objeto newsData (Listagem 14).

Listagem 14. Implementação de NewsAdapter
function getNews(interest, stock)
{
	var input =
	{
		method : "get",
		returnedContentType : "html",
		path : "news",
		parameters :
		{
			"q" : interest,
			"output" : "rss"
		}
	};
	var newsData = WL.Server.invokeHttp(input).rss.channel.item[0];
	var stockData = WL.Server.invokeProcedure(
	{
		adapter : 'StockAdapter',
		procedure : 'getStock',
		parameters : [ stock ]
	});
	newsData["stock"] = stockData.text;
	return newsData;
}

Em resumo, NewsAdapter retorna um mashup dos dois recursos, que será processado e exibido no cliente.

Chamando os adaptadores

Você concluiu a implementação dos adaptadores no lado do servidor. Agora, é preciso chamá-los no cliente. Primeiro, é necessário um elemento de UI para armazenar os dados de local recuperados. Insira um ComboBox básico no arquivo Mashup.html (Listagem 15).

Listagem 15. Inclua um ComboBox para os locais
>body onload="WL.Client.init({})" id="content" style="display: none"<
>div data-dojo-type="dojox.mobile.View" id="view0"
	data-dojo-props="selected:true"<
	Available Locations >select id="availableLocations"
		onchange="javascript:changeLocation();"<
		>option value="" disabled="disabled"<Select a location>/option<
	>/select<
	>div data-dojo-type="custom.LocationViewer" id="locationViewer"<>/div<
>/div<

A implementação efetiva, que chama os adaptadores, é colocada em js/Mashup.js. Esse arquivo, gerado automaticamente, é o arquivo JavaScript principal do aplicativo. Contém a função wlCommonInit(), que será chamada durante a inicialização do aplicativo, quando a inicialização da estrutura Worklight for concluída. É o melhor lugar para colocar o código de inicialização do aplicativo. A função também é usada em arquivos JavaScript de ambientes específicos, para ter um ponto de partida comum para a inicialização.

Listagem 16. Código de inicialização
var busyIndicator = null;
var adapterData = new Array();

function wlCommonInit()
{
	busyIndicator = new WL.BusyIndicator("view0");
	getLocations();
}

Crie um busyIndicator que comunique ao usuário que está em andamento uma operação possivelmente longa. O método getLocations() é a primeira chamada de adaptador a preencher o ComboBox com os locais disponíveis (Listagem 17).

Listagem 17. Chamando LocationAdapter
function getLocations()
{
  busyIndicator.show();
  var invocationData =
  {
    adapter    : "LocationAdapter",
    procedure  : "getLocations",
    parameters : []
  };
  WL.Client.invokeProcedure(invocationData,
  {
    onSuccess : function(response)
    {
      busyIndicator.hide();
      if (response.invocationResult.resultSet.length != 0)
      {
        var locationList = response.invocationResult.resultSet;
        var availableLocations = document.getElementById("availableLocations");
        availableLocations.length[1] = null;
        for ( var i = 0; i < locationList.length; i++)
        {
          newLocation = new Option(locationList[i].CITY, locationList[i].CITY + ", "
 + locationList[i].COUNTRY + ":" +
                                  locationList[i].STOCK, false, true);
          availableLocations[i + 1] = newLocation;
        }
        availableLocations[0].selected = "selected";
      }
      else
      {
        WL.SimpleDialog.show("Mashup", "Adapter can't load locations. Check your 
database connection", [
        {
          text : "Reload app (via WL.Client.reloadApp)",
          handler : WL.Client.reloadApp
        } ]);
      }
    },
    onFailure : function()
    {
      busyIndicator.hide();
      WL.SimpleDialog.show("Mashup", "Adapter can't load locations. Check your 
database connection", [
      {
        text    : "Reload app (via WL.Client.reloadApp)",
        handler : WL.Client.reloadApp
      } ]);
    }
  });
}

Para chamar um procedimento de adaptador, é necessário um objeto invocationData, para o qual serão passados o nome do adaptador, o procedimento a ser chamado e um array de parâmetros opcionais. Quando a chamada assíncrona é concluída com sucesso, a função onSuccess é chamada como um retorno de chamada com um objeto de resposta. A função onFailure é chamada se a chamada ao adaptador falhar. Se tudo tiver sido configurado corretamente, esse código de inicialização preenche o ComboBox (Figura 22).

Figura 22. Locais disponíveis através de adaptador
Locais disponíveis através de adaptador

Quando o usuário seleciona um local, a função changeLocation() é chamada. Aqui mantemos um cache local dos dados de adaptador. Se o programa ainda não capturou as informações relacionadas ao local, ele chama getNews() para recuperá-las. Do contrário, mostra os dados em cache em um local apropriado no mapa (Listagem 18).

Listagem 18. Alterando um local
function changeLocation()
{
	var value = document.getElementById("availableLocations").value;
	var newLocation = value.split(":")[0];
	var newStock = value.split(":")[1];
	// Lazily load the Stock and News information
	if (adapterData[newLocation] == undefined)
	{
		busyIndicator.show();
		WL.Logger.debug("Load adapterData for " + newLocation);
		getNews(newLocation, newStock);
	}
	else
	{
		dijit.byId("locationViewer").refreshMap(newLocation,
				adapterData[newLocation]);
		busyIndicator.hide();
	}
}

Essa função chama o procedimento getNews a partir de NewsAdapter, se necessário, e mostra seu valor de retorno no mapa, usando o mesmo padrão de chamada discutido acima (Listagem 19).

Listagem 19. Chamando NewsAdapter
function getNews(location, stock)
{
  var invocationData =
  {
    adapter    : 'NewsAdapter',
    procedure  : 'getNews',
    parameters : [ location, stock ]
  };
  WL.Client.invokeProcedure(invocationData,
  {
    onSuccess : function(response)
    {
      var stockData = response.invocationResult.stock.split(',');
      var news = ">b>" + location + ":>/b>>br>" +
          stockData[0].substring(2, stockData[0].length - 1) + ": " +
         stockData[1] + ">/b>" + ">font color=" +
         (stockData[2] > 0 ? "green>" : "red>" ) + " (Change: " +
         stockData[3].substring(2, stockData[3].length - 1) + ")>br>>a href=" +
         response.invocationResult.link + ">" +
         response.invocationResult.title + ">/a>";
      adapterData[location] = news;
      dijit.byId("locationViewer").refreshMap(location, news);
      busyIndicator.hide();
    },
    onFailure : function()
    {
      busyIndicator.hide();
      WL.SimpleDialog.show("Mashup",
                           "NewsAdapter can't load content for location " + location,
                 [{
                     text : "OK"
                 }]);
    }
  });
}

A Figura 23 mostra o que acontece quando experimentamos alguns locais.

Figura 23. Locais disponíveis através de adaptador
Locais disponíveis através de adaptador

Incluindo um ambiente do Worklight

Como discutimos na Introdução, o Worklight oferece um ambiente de desenvolvimento e tempo de execução para suporte ao desenvolvimento de aplicativos para destinos específicos, usando um conceito chamado ambientes. Semelhante a um aplicativo da web remoto, o Worklight Studio cria artefatos para destinos específicos quando incluímos um dos ambientes suportados.

Por exemplo, para incluir um ambiente de iPhone, clique com o botão direito em apps/Mashup e selecione New > Worklight Environment. No assistente New Worklight Environment, selecione iPhone (Figura 24).

Figura 24. Incluindo um ambiente do Worklight
Incluindo um ambiente do Worklight

O Worklight Studio agora cria todos os artefatos necessários para executar o aplicativo recém-criado no dispositivo iPhone. Uma nova pasta chamada iphone é incluída automaticamente no projeto e aparece após o aplicativo ser desenvolvimento e implementado no Worklight Server.

Desenvolva e implemente o aplicativo e atualize o Worklight Console para ver um novo ícone para iniciar o aplicativo no simulador de navegador remoto, onde você seleciona iPhone 4 da Apple e Galaxy Ace da Samsung (Figura 25):

Figura 25. Iniciando o aplicativo no simulador de navegador remoto
Iniciando o aplicativo no simulador de navegador remoto

Conclusão

Este artigo descreveu como desenvolver remoto um aplicativo híbrido que usa tecnologias de mashup nos lados do cliente e do servidor. Você criou um widget Dijit customizado e usou-o como uma parte integral do aplicativo. Você também desenvolveu e encadeou vários adaptadores para recuperar dados de backend de várias origens.


Download

DescriçãoNomeTamanho
Code sampleMashup-160812.zip6.8 MB

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=WebSphere
ArticleID=839286
ArticleTitle=Desenvolvendo um aplicativo remoto de mashup de cliente e servidor com IBM Worklight
publish-date=10082012