Translate

domingo, 14 de novembro de 2010

Java no Auto-atendimento

Olá leitores,

Vou falar hoje um pouco sobre o uso cada vez mais crescente de aplicações front-end escritas em Java para os terminais de auto-atendimento em geral. Farei também um paralelo sobre as especificações bancárias (WS/XFS e J/XFS), e também de um recurso bastante útil chamado JNI, disponibilizado pela plataforma Java. Por fim, falarei como lidar com código nativo quando a necessidade é uma solução multi-plataforma. Este artigo, como sempre, é bem superficial pois é o que permite o espaço de um blog. Mas, para quem nunca ouviu falar dessas coisas, e nem sabia que era possível, serve de introdução. Vamos lá :)

Contextualizando
Há algum tempo atrás, dificilmente se encontrava alguma aplicação de auto-atendimento baseada em uma plataforma de desenvolvimento que não fosse o Microsoft Visual Basic ou alguma outra usando a linguagem C/C++, como o Microsoft Visual C++ e o Borland Visual C++ Builder. Isso era natural, até porque nessa época a maioria dos terminais de auto-atendimento executavam sistemas operacionais como o Windows NT, e o que se tinha disponível nas especificações bancárias era o antigo Wosa (hoje WS/XFS), dependente do sistema operacional da Microsoft.

Esse panorama mudou com o advento do Linux, e seu fenômeno de escala mundial. O fato é que o Linux passou a ser visto de uma maneira mais séria por empresas, instituições e até governos. Muitos governos no mundo todo iniciaram projetos baseados em software livre, tendo o Linux como plataforma base, com uma forte substituição de sistemas Windows por sistemas Linux. Bem, isso também ocorreu no Brasil no início do atual governo. Instituições governamentais foram orientadas pelo governo a darem preferência para a plataforma de software livre, e isso alavancou o uso do Linux em bancos como Caixa Econômica Federal, Banco do Brasil, Banrisul e outros.

Foi mais ou menos nessa mesma época que o Java já tinha ocupado uma posição de destaque entre as principais plataformas de desenvolvimento de software, e também foi mais ou menos nessa época que a especificação J/XFS foi lançada. Como o Java sempre teve a proposta de geração de soluções de software multi-plataforma, o trio J/XFS+Java+Linux, passou a ser uma ótima opção estratégica para os bancos e demais empresas, no momento de compor suas soluções de auto-atendimento.

Agora, será que realmente representa vantagem a substituição de sistemas operacionais da Microsoft, por sistemas Linux? Bom, os gerentes de negocio na Microsoft certamente devem ter inúmeros argumentos, mas o fato é que qualquer grande banco possui uma base de ATMs e outros terminais de auto-atendimento, na ordem numérica dos 20 mil terminais. Imagine, seriam 20 mil licenças para uso do Windows Vista, por exemplo. E alguns bancos brasileiros têm quase o dobro desse número em quantidade de terminais de auto-atendimento, e isso realmente representa um enorme argumento financeiro (além de outros tantos argumentos de ordem técnica). A verdade é que, embora o Linux talvez jamais consiga superar seus concorrentes junto aos computadores pessoais em geral, é certo que ele é uma ótima escolha para aplicações específicas, como servidores, celulares, consoles de games, e também, terminais de auto-atendimento.


No Brasil hoje, todos os principais bancos já tem, em execução ou em fase adiantada de desenvolvimento, sistemas front-end baseado na plataforma Java para seu canal de auto-atendimento nos terminais bancários. Caixa Econômica Federal e outros importantes bancos brasileiros, apostaram na estratégia de ter uma aplicação que possa executar em qualquer plataforma de sistema operacional, mesmo que alguns desses bancos não tenham optado ainda por substituir o sistema operacional da Microsoft. Na verdade, é a liberdade de escolha da plataforma de sistema operacional que faz a estratégia de uso do Java ser tão atraente para o contexto do auto-atendimento.

Sistemas multi-plataforma: desafios e soluções
De fato, nem tudo é azul quando tratamos de auto-atendimento. Se você pegar um case conceitual, você encontrará a solução de auto-atendimento escrita inteiramente em Java, executando em um ambiente Linux, "embarcado" em um ATM dotado de infra-estrutura J/XFS. É perfeito, pois nesse caso a aplicação de auto-atendimento codificada em Java, executará sem necessidades de alterações, mesmo se instalada em um sistema Windows no mesmo ATM (lembrando que a infra-estrutura J/XFS, deve funcionar sem problemas tanto no Windows quanto no Linux). Ocorre porém, que nem tudo funciona conforme o conceito escrito.

Nem sempre os fornecedores dispõe de infra-estrutura J/XFS para todos os dispositivos do ATM. É muito comum que algum dispositivo mais específico não tenham um driver J/XFS, ou por falta de suporte da própria especificação J/XFS, ou porque o fornecedor simplesmente não dispõe ainda de um driver para aquele dispositivo, e o que ele fornece nesses casos é apenas a sua solução de driver proprietário escrito em código nativo (normalmente está escrito em C/C++). Esses são os casos típicos dos dispositivos: Leitor Biométrico - PalmView e também das Impressoras de Cheque. No caso desses dois dispositivos o mais comum é encontrar drivers proprietários.

Além desse infortúnio aí descrito, existe também outros da mesma natureza, mas associados ao código legado dos bancos. É muito comum que os bancos tenham alguns componentes especializados para execução de tarefas bem específicas como a geração de dados cifrados e etc. E às vezes os bancos consideram muito importante manter o uso desses componentes sem portá-los para o Java. Isso pode até ser estratégico, já que nem todos os bancos desenvolvem diretamente suas aplicações de auto-atendimento, e nesse caso transferir para terceiros um componente sensível para a segurança do banco, realmente pode não ser uma alternativa.

A primeira vista, essas situações configuram um enorme problema. Afinal, o objetivo era um sistema multi-plataforma. Como se consegue isso se existem drivers e demais componentes em código nativo envolvidos? Bem, o problema é sério e não possui solução "elegante". O fato é que para casos assim, terá que se conviver realmente com um código nativo junto ao seu sistema multi-plataforma. Será necessário fazer uso do JNI para acessar de dentro do Java, aos comportamentos servidos pelos componentes nativos.

JNI: Java Native Interface
O JNI é um poderoso recurso do Java que permite que você acesse comportamentos exportados em componentes nativos, como .dll (para Windows, significa Dynamic Link Library) e .so (para Linux, significa Shared Object), diretamente a partir da aplicação escrita em Java. Esse recurso permite uma sobre-vida maior para componentes nativos sensíveis como os que eu citei anteriormente, mas exige uma atenção maior na arquitetura da solução, para que não se tenha mais problemas do que o necessário durante a manutenção do sistema.


Para acessar ao componente nativo, você precisará construir um driver JNI. Esse driver é construído em duas camadas, com uma parte definida em uma classe Java e a outra definida em uma .dll ou .so escrito em C/C++.  A parte escrita em Java, será integrada a sua aplicação, e a parte escrita em C/C++, fará acesso ao componente nativo. Segue abaixo um exemplo de driver JNI para uma impressora térmica, rodando em um sistema Windows. A imagem mostra os binários gerados:


Veja a seguir como ficaria a definição da classe CommJNI.java. Note que a classe é singleton, pois não faria sentido existir mais de uma instância dessa classe JNI  no sistema. Note também que o método print está sincronizado, para impedir que duas threads acionem o processo de impressão ao mesmo tempo (nem sempre há um controle de fila nesses dispositivos):


E a seguir, a definição do código JNIThermicPrinter.c. O header printer_CommJNI.h pode ser gerado automaticamente com a ferramenta javah presente na plataforma Java. É necessário apenas uma classe compilada, e esse header foi gerado a partir da classe CommJNI mostrada anteriormente. O código C segue abaixo:


Em termos de arquitetura é muito bom que se trate a classe JNI como um componente externo ao sistema. Uma boa estratégia é definir em arquivos .jar (Java ARchive) as classes JNI e qualquer outro recurso necessário a sua execução (exceto a parte relativa a .dll ou .so). É fácil perceber que o sistema poderá ficar amarrado a uma solução bastante específica. Assim, o melhor que é se defina uma interface genérica para acesso ao componente nativo, de modo que chamadas específicas do componente sejam mapeadas para métodos genéricos, o que permitirá mudar o componente mais tarde, sem afetar a aplicação.

Existem outros desafios envolvidos, como por exemplo, tentar criar algum mecanismo de "convivência" com o código nativo, utilizando bibliotecas cross-compiler. No entanto, esse é um assunto para um próximo post ;)

Até mais.


Um comentário:

Anônimo disse...

Olá Fagner,

Estou precisando fazer a impressão de boletos em um terminal onde tem um impressora laser instalada, sendo que esta impressora não tem driver proprietário.

Qual seria a solução para que eu pudesse verificar na minha aplicação as informações tipo: status da impressora, verificar se impressora está ligada, se o papel acabou, etc. Pois atualmente eu realizo a impressão, mas mesmo que dê algum erro, o sistema sempre informa que a impressão foi realizada com sucesso.

Desde já agradeço.

Roberto