sexta-feira, 25 de janeiro de 2008

Java Gateway no Ensemble e alternativas via Web Services

Já mencionei num post anterior sobre Criptografia em Caché/Ensemble, que precisei usar criptografia. Como a API do Caché/Ensemble não contemplava nem de longe o que eu precisava (e mesmo a versão mais nova - que eu não uso - contempla, apesar de ter melhorado), fui em busca de outras soluções.

Como já havia trabalhado com Java, e sabia que tinha uma boa e vasta API, pensei porque não usá-la? Vasculhando na documentação, achei o recurso do Java Gateway, do Ensemble, que nas próprias palavras da Intersystems é:

"... um jeito fácil do Ensemble interoperar com componentes Java. O Java Gateway pode instanciar objetos java externos e manipulá-los como se fossem objetos nativos do Ensemble."

Como isso acontece? Bem, o Ensemble gera alguns "proxies" para as classes Java que você quer manipular. Estes proxies são classes dentro do Ensemble, em Caché Object Script (COS), que fazem chamadas ao Java Gateway. O Java Gateway nada mais é que um conjunto de classes/objetos que fazem a comunicação entre uma JVM (máquina virtual Java) e as classes do Ensemble. Dê uma olhada na figura abaixo, que mostra como é a arquitetura dessa solução:



Se você já estudou Sistemas Distribuídos, ou tem uma noção de como EJBs trabalham, deve reconhecer o design desta solução. O que o Java Gateway faz é nada menos que um pequeno "framework" (Middleware, na realidade) de chamadas remotas. Neste caso, o cliente é dentro do Ensemble e o objeto remoto, dentro da JVM. Simplificadamente, o processo é o seguinte:

- No Ensemble, você efetua uma chamada a um método da classe proxy.
- A classe proxy serializa/transforma os parâmetros para serem enviados via TCP/IP para a instância do Java Gateway que deve estar rodando em uma JVM (não necessariamente na mesma máquina).
- As classes do Java Gateway dentro da JVM recebem uma conexão TCP/IP, identificam que é uma chamada de um método, e reconstroem os parâmetros para serem reconhecidos em Java.
- Através de reflection, fazem a chamada ao objeto Java.
- O objeto Java retorna do método, possivelmente com algum valor.
- Esse valor passa pelo processo de serialização/transformação, e é enviado via TCP/IP para o Ensemble.
- A classe proxy recebe o valor pela conexão TCP/IP, transforma o(s) valor(es) para o formato usado no Caché e retorna para quem efetuou a chamada.

Nota: o processo de formatar/transformar/serializar os dados para serem enviados via rede, e o seu inverso, na literatura de Sistemas Distribuídos é geralmente chamado de marshaling/unmarshaling.

Pois bem, a descrição de todo o processo é muito legal, muito bonita, mas a implementação de qualquer middleware não é trivial, mesmo num ambiente restrito, como é o Java Gateway (só um tipo de cliente, um tipo de objeto servidor, e outros). Por isso, a ocorrência de bugs não é de todo inesperada.

E é exatamente isso o que aconteceu: bugs, bugs e mais bugs. Utilizando o Java Gateway na mesma máquina que rodava o Ensemble (não testei com uma JVM remota), a maioria das vezes, travava tudo. Depois de uma ou duas chamadas, a máquina parava de responder. Algumas vezes, só o Ensemble, mas em outras, congelava todo o computador, de maneira que só reiniciando no dedão.

Conclusão: desisti de usar o Java Gateway. Depois de dois dias investigando sem sucesso, e sem pista do que poderia estar acontecendo, desisti (note que a classe em Java era bem simples, servindo de proxy para umas funções de criptografia, e funcionava perfeitamente bem numa JVM stand-alone). No meu caso particular, achei melhor implementar o algoritmo de criptografia nativamente em Caché Object Script.

Mas nem sempre isso é possível, ou mesmo vantajoso. Imagine implementar em COS tudo o que já foi implementado em Java ou PHP, por exemplo, em termos de bibliotecas. Impraticável.

Eis que uns tempos atrás, na lista de discussão de Caché, o Rob Tweed compartilhou uma idéia que ele teve, e que está na thread Extending Cache using PHP.

O que ele fez? Simplesmente montou uma página em PHP simples, que retornava algo do tipo:

retorno=valor

Usando a classe %Net.HttpRequest, ele estabeleceu uma conexão para a página PHP, obteve o retorno, e simplesmente fez um parsing simples de "retorno=valor" usando a função $PIECE. Um esquema bem simples.

Se você anda por dentro das últimas notícias, deve ter notado que esse esquema é bem parecido (na verdade, praticamente uma simplificação) de arquiteturas Web Services utilizando chamadas estilo REST. Implementando-se um padrão para a troca de valores (em vez de uma String customizada, um XML ou JSON), você estaria construindo a sua primeira arquitetura Web Service REST =P.

Veja que esta abordagem não se limita a utilizar PHP, podendo implementar a página web com qualquer linguagem/plataforma, passando por Java e Ruby.

E apesar de haver algumas implicações não mostradas, por exemplo, falhas na conexão, re-tentativas de acesso, segurança, etc., pelo menos você tem liberdade para cobrir quais casos se aplicam ao seu ambiente. Por exemplo, se o servidor que roda o PHP estiver na mesma máquina que o Caché/Ensemble, não precisará lidar com falhas de conexão. No caso de uso do Java Gateway, você provavelmente também lidará com essas implicações, a diferença é o nível de controle que você terá, bem menor. E claro, estará sujeito a bugs que você provavelmente não terá como de lidar/corrigir.

Ainda no espírito de Web Services, o Caché provê algum suporte ao que se convencionou chamar de estilo ou stack WS-*, que utiliza padrões mais robustos, e consequentemente mais complexos (WSDL, UDDI, WS-Security, entre outros). Para problemas simples, talvez seja pedir demais, mas a idéia permanece a mesma: extender as capacidades do Caché/Ensemble usando invocações de provedores externos.

Conclusão: para extender as capacidades do Ensemble, prefira outras alternativas, como a utilização de Web Services, do que o uso do Java Gateway. Como o Java Gateway também cria um processo separado para a execução da JVM, não existem ganhos significativos em relação ao uso de um outro servidor leve, como por exemplo, um Tomcat. Em suma, talvez o Java Gateway tenha servido há algum tempo atrás, mas hoje em dia, deve ser usado somente em caso de código legado que faça uso deste.

Em tempo: a versão nova do Ensemble parece não ter novidades em relação ao Java Gateway, pelo menos não encontrei nada olhando a documentação da nova versão.

quinta-feira, 10 de janeiro de 2008

SQL Adapter no Ensemble - probleminha

Faz tempo que não posto nada, mas hoje vi algo que me fez postar.

Até agora, usando o Ensemble da Intersystems, não havia ainda precisado usar um adaptador de entrada SQL (ou no original em inglês, um SQL Inbound Adapter). OK, estou indo muito rápido no assunto. Se você já conhece a estrutura do Ensemble, pule os dois parágrafos abaixo.

O Ensemble é uma ferramenta que serve como várias coisas, entre elas Enterprise Service Bus (ESB) (assim ele é vendido pelo pessoal de marketing, mas você deve conhecer o pessoal de marketing...), mas é mais tipicamente um Enterprise Application Integration (EAI) (uma abordagem mais realista do produto). O que ele basicamente faz é servir de "ponte" para que dois ou mais sistemas possam se comunicar. E eles podem se comunicar de diferentes maneiras, desde troca de arquivos e tabelas de banco de dados, até interfaces mais "modernas", como mensagens SOAP (com Web Services), etc... Como cada sistema tem uma interface de comunicação, o Ensemble provê adaptadores (ou Adapters no original), que são interfaces entre os diferentes tipo de protocolos/estilos de comunicação e o ambiente interno do Ensemble.

Por exemplo, você pode ter uma aplicação legada que produza somente arquivos texto como saída, e quer fazer uma espécie de "mashup" desses arquivos com dados de outro sistema, que persiste as suas informações num banco de dados, e exibir a saída dessa "mistura" num XML via Web Service. Neste caso, pode-se usar o Ensemble com um Adapter de arquivo, para conversar com a aplicação legada, um Adapter SQL para conversar com o banco de dados, e um Adapter SOAP para exibir o resultado em XML.

Voltando ao assunto principal do post...

O Adapter SQL permite que se coloque uma consulta SQL, que executa de tempos em tempos, e ele "aciona" outro componente do Ensemble (um Business Service), enviando cada linha da consulta retornada.

É uma boa idéia, mas como de costume, alguns problemas apareceram...

Pra começar, vamos ver uma parte da classe do Adapter SQL:

Class EnsLib.SQL.InboundAdapter 
Extends (Ens.InboundAdapter, EnsLib.SQL.Common)
[ ClassType = "", ProcedureBlock ]
{

/// The Base query string that will
/// be repeatedly executed to look for new rows
Property Query As %String [ Required ];

...


A propriedade Query, um %String, guarda a consulta SQL que será executada. Entretanto, não é qualquer consulta que pode ser realizada. Veja a consulta abaixo:

SELECT id_tabela, campo1, campo2 FROM grande_tabela WHERE algum_campo <= 10

Supondo que a tabela mencionada exista, bem como os campos, essa consulta deveria funcionar. Entretanto, observe o que acontece quando se tenta colocar a consulta na configuração do Adapter:


Depois de pesquisar um pouco, vi que o problema estava na classe do Adapter SQL. Note que a propriedade Query foi definida como %String. Entretanto, o que pode não ser tão visível é a restrição que isso impõe. Ao se definir uma propriedade como %String, automaticamente é estipulado também um tamanho máximo que aquela String poderá conter. Caso você não defina manualmente, o Caché/Ensemble usa um valor padrão, no caso, 50. Como a consulta acima tem mais de 50 caracteres, acontece o erro mostrado na figura.

Para reparar esse "erro", abri a classe, alterei o código fonte (só acrescentei um parâmetro na propriedade, mostrado abaixo) e recompilei. E pronto!

Class EnsLib.SQL.InboundAdapter 
Extends (Ens.InboundAdapter, EnsLib.SQL.Common)
[ ClassType = "", ProcedureBlock ]
{

/// The Base query string that will
/// be repeatedly executed to look for new rows
Property Query As %String(MAXLEN = 500) [ Required ];

...


UPDATE1: Esqueci de mencionar que isso foi feito na versão 4 do Ensemble, a que utiliza o Caché 5.2. Não tenho, nem testei a versão mais nova (2007.1) pra ver como se comporta.

UPDATE2: Aqui vai o link para um pdf sobre SQL Adapters. Apesar de ser para a versão mais nova do Ensemble, muita coisa vale para a versão mais antiga: Using SQL Adapters with Ensemble - version 2007.1.2