SemtexGirl

É uma garota dinâmica e de bom gosto, uma garota que explode, que não para e nem aceita um não como resposta.

Archive for the 'technical' Category

Minha primeira tentativa de artigo técnico

Há um bom tempo atrás comecei a escrever um post sobre JNI que acabou virando um esboço de um artigo que não saiu do 'papel', deixei ele perdido no meu computador e só agora quase 4 meses depois resolvi colocá-lo aqui mesmo no blog, o artigo é enorme então vou postar um pedacinho a cada dia, assim tenho tempo para revisá-lo e de bem, se alguem mais ler posso saber se consegui me fazer entender.

JNI - Rompendo as barreiras do acesso às aplicações nativas I

Há pouco tempo precisei desenvolver uma aplicação Java integrada com funções nativas e me vi perdida em meio de uma série de complicações na hora de utilizar JNI. Infelizmente, na época, não encontrei nenhuma documentação que se aprofundasse no assunto. Principalmente quando este era envio/manipulação de estrutura/objetos, conversei com outros desenvolvedores na empresa em que trabalhava e todos me aconselharam a fazer algum ‘ajuste técnico’ no lugar de trabalhar com o envio de objetos. Apesar de esta sugestão ser a saída mais fácil, não me pareceu nada elegante retornar um string concatenando todos os dados da estrutura, ou criar métodos auxiliares que me retornariam cada atributo da estrutura em C separadamente.
Depois de quebrar a cabeça para entender melhor o funcionamento do JNI finalmente consegui trabalhar com objetos Java dentro do C, e é isso que vou tentar explicar abaixo. Mas antes foi explicar um pouco sobre o que é e como funciona o JNI sem no entendo me estender muito, pois estas explicações se acham facilmente digitando JNI no Google, vou tentar explicar como enviar e trabalhar com os objetos Java em C.

Introdução

Em Java para nos comunicarmos com bibliotecas nativas utilizamos o JNI uma interface de comunicação desenvolvida pela Sun que permite de forma bidirecional que os códigos executados pela Java Virtual Machine (JVM) acessem aplicações e bibliotecas desenvolvidas em outras linguagens, como C, C++ e Delphi como se fossem métodos Java, facilitando, por exemplo, a integração de sistemas legados.

JNI 1

Figura1 : Representação das camadas de comunicação

Porem existe algumas premissas para a utilização de JNI são elas:

1. Implementação de funcionalidades que as API's Java não fornecem
2. Problemas de desempenho.
ex.
Um algoritmo que em Java fique muito lento pode ser implementado em C ou Assembly e acessado pelo Java.
3. Ou ainda, quando o código nativo deseja ter acesso à API Java.

O desenvolvimento de um programa Java que chama funções nativas pode ser dividido em seis passos:

1. O primeiro passo é escrever o código Java que execute três tarefas;

Declaração do método nativo que estaremos chamando;
Carga da biblioteca compartilhada que contém o código nativo;
E que execute uma chamada ao método nativo.

Como exemplo, criaremos uma aplicação Java que execute um método nativo que imprima a mensagem “Olá Mundo!”.

Listagem 1 : OlaMundo.java

Como podem notar na listagem 1, os métodos nativos carregam o modificador native, e sua função nativa correspondente será implementada na forma de uma biblioteca dinâmica conforme veremos em breve.

Notamos ainda a existência do método:

void <system>.loadLibrary(String libraryName)
 

Observe que ele recebe como parâmetro o nome da biblioteca dinâmica que iremos utilizar. A biblioteca deve ser carregada antes da chamada de qualquer método nativo.

2. Compilar o código Java;

javac OlaMundo.java

3. Criar o arquivo de header C/C++. O arquivo de header C/C++ declarará a assinatura da função nativa que queremos chamar. Este header será usado durante a implementação da função C/C++ (veja Passo 4) onde criaremos a nossa biblioteca dinâmica.

javah OlaMundo

Lembre-se que OlaMundo é o nome da sua classe Java já compilada a partir do qual geraremos o arquivo OlaMundo.h, como podem ver na listagem 2.

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class OlaMundo */
  4.  
  5. #ifndef _Included_OlaMundo
  6. #define _Included_OlaMundo
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. /*
  11.  * Class: OlaMundo
  12.  * Method: saudacoes
  13.  * Signature: ()V
  14.  */
  15. JNIEXPORT void JNICALL Java_OlaMundo_saudacoes
  16. (JNIEnv *, jobject);
  17.  
  18. #ifdef __cplusplus
  19. }
  20. #endif
  21. #endif
  22.  

Listagem 2: OlaMundo.h

4. Escrever o código nativo. Este passo consiste em implementar a função desejada em C/C++, notem que no código da listagem 3 incluímos o arquivo de header OlaMundo.h criado no passo anterior.

  1. /*OlaMundo.c*/
  2.  
  3. #include <jni.h>
  4. #include
  5. <olaMundo.h>
  6.  
  7. JNIEXPORT void JNICALL Java_OlaMundo_saudacoes
  8. (JNIEnv *, jobject){
  9. printf("Olá Mundo!\n");
  10. return;
  11. }
  12.  

Listagem 3 : OlaMundo.c

5. Criar o arquivo de biblioteca dinâmica.

Agora que todo o código necessário foi escrito, podemos compilar a biblioteca nativa. Ela será invocada dinamicamente quando a classe OlaMundo tiver o método saudacoes() invocado. Para efetuar a compilação devemos considerar o sistema operacional e o compilador utililizado.

Se estivermos utilizando o Windows e o Microsoft Visual Studio, utilizaremos o comando abaixo:

cl -Ic:\jdk1.5.0_07\include -Ic:\jdk1.5.0_07\include\win32 -MD -LD OlaMundo.c OlaMundo.dll

Já em Solaris poderíamos utilizar:

cc -G -I/java/include -I/java/include/solaris OlaMundo.c -o libOlaMundo.so

E em Linux o comando correspondente seria:

gcc -o libOlaMundo.so -shared -Wl,-soname, libOlaMundo.so -I/export/home/java/include -I/export/home/java/include/linux OlaMundo.c -static –lc

Concluído o passo 5 teremos uma aplicação JNI pronta esperando para ser executada.

6. Executar o programa.

Neste ponto, têm-se dois componentes prontos para serem executados. O arquivo “.class” (OlaMundo.class) chama o método nativo e a biblioteca nativa (olamundo.dll ou libOlaMundo.so) implementa o método nativo. Como a classe OlaMundo contém sua própria função main, ela pode ser executada da seguinte maneira:

> java OlaMundo

Durante a execução do programa podemos obter algumas mensagens de erro, sendo que as três mais comuns são:

1. Uma ligação dinâmica (dynamic link) não pode ser encontrada. Isto resulta na mensagem de erro: java.lang.UnsatisfiedLinkError. Normalmente, esta mensagem significa que ou o arquivo de biblioteca dinâmica, ou um método nativo específico dentro da biblioteca dinâmica não pode ser encontrado.

2. O arquivo de biblioteca dinâmica não pode ser encontrado. Isso acontece quando a JVM não consegue localizar o arquivo de biblioteca indicado no loadLibrary(), caso isto ocorra devemos verificar se o nome do arquivo esta escrito corretamente e que não se tenha especificado a extensão. Devemos, também, verificar se o arquivo de biblioteca encontra-se acessível à JVM. Caso desejemos utilizar outros caminhos, que não os padrões, existem duas técnicas. A primeira consiste em setar a variável de ambiente PATH, no Windows, ou LD_LIBRARY_PATH, para Linux e Solaris, com o caminho desejado. E a outra é setar este caminho através de um parâmetro, durante a chamada do programa java:

java -Djava.library.path=. OlaMundo

Ola mundo!

No caso o parâmetro –D informa à máquina virtual que existe uma variável de ambiente do Java chamada java.library.path e ela será analisada pela máquina virtual como outro caminho alternativo aonde ir buscar as bibliotecas dinâmicas e até mesmo outras classes utilizadas no projeto.

No exemplo acima estamos informando que o arquivo de biblioteca dinâmica encontra-se no diretório atual.

3. Um método com a assinatura especificada não pode ser encontrado. A implementação da função C/C++ deve possuir uma assinatura idêntica à assinatura da função no arquivo de header. Se quiser saber um pouco mais sobre assinatura/descritor de argumento é só ler o próximo capítulo e este não for o seu caso vá direto para o capitulo “Acessando os atributos de um objeto”.

Agora que já relembramos os passos para a criação de uma aplicação JNI, podemos nos aprofundar um pouco mais sobre seu funcionamento.

O próximo post será sobre assinatura ou descritores de argumento.

6 comments

Configurando multiplas instancias do JBOSS em uma única máquina

Alguns devem se perguntar qual a necessidade de ter mais de uma instância do JBOSS na mesma máquina? Pois bem, a minha necessidade é ter duas instâncias com JDKs distintos, ou seja, uma versão com o Java 1.4 e a outra com o Java 5. Esta necessidade se fez presente durante um periodo de migração do Java em nosso ambiente de desenvolvimento e homologação e ainda o desenvolvimento de uma nova aplicação já usando o Java 5.

A princípio fiquei meio perdida com as diversas informações que encontrei na internet sobre o assunto, mas no final deu tudo certo e a solução adotada por mim foi disponibilizada no próprio site do JBOSS, como poderão ver a solução é bastante simples, consiste em basicamente duplicar o server default com o nome desejado e descomentar a TAG

 
<mbean code=”org.jboss.services.binding.ServiceBindingManager”
name=”jboss.system:service=ServiceBindingManager”>
 

do arquivo <JBOSS>/server/java5/conf/jboss-service.xml para ler o arquivo <JBOSS>/docs/examples/binding-manager/sample-bindings.xml, este XML contêm a configuração das portas a serem utilizadas pelo seu server, afinal se simplesmente executarmos o script de inicialização indicando novo server este tentará utilizar as portas padrões, ocasionando erros. Deste modo para evitarmos este tipo de problema é preciso indicar ao server as portas que ele deve utilizar, eu fiz o jeito simples, editei o arquivo <JBOSS>/server/java5/conf/jboss-service.xml, retirando o comentário da TAG e alterei o ServerName para ports-02 conforme abaixo:

 
<mbean code=”org.jboss.services.binding.ServiceBindingManager”
name=”jboss.system:service=ServiceBindingManager”>
<attribute name=”ServerName”>ports-02</attribute>
<attribute name=”StoreURL”>${jboss.home.url}/bindings.xml</attribute>
<attribute name=”StoreFactoryClassName”>
org.jboss.services.binding.XMLServicesStoreFactory
</attribute> </mbean>
 

Isto faz com que o server no momento do start busque as portas na configuração definidas como ports-02 no arquivo jboss-service.xml.

E pronto! Tudo funcionando ;o) Como eu disse no inicio simples. Para rodar os servers com os JDKs distintos alterei o script de inicialização indicando qual o JDK que eu desejo usar e problema resolvido.

2 comments

JBOSS – Remote Debugging

O JBOSS é de longe o application server mais simples de usar mesmo assim as vezes me pego perdida na hora de ajustá-lo as minhas necessidades, uma delas foi acesso remoto, infelizmente no ambiente de desenvolvimento que trabalho nem sempre é possível debugar a aplicação localmente, então lá fui eu ver como isso funciona...

Passo 1:
Ajustar .bat/sh de start do JBOSS, eu uso a versão 4.0.5 e não sei se tem alguma diferença com as demais...

Localize a frase "JPDA options. Uncomment and modify as appropriate to enable remote debugging" é só descomentar a linha abaixo para habilitar debug remoto, no meu caso tive ainda que alterar a opção suspend=y para suspend=n, a opção address indica a porta pela qual você se conectara para debugar o projeto.

Feito isso é só dar um stop/start no JBOSS que ele esta prontinho.

Passo 2:
Vá até o eclipse, clique com o botão direito do mouse em cima do projeto que deseja debugar e vá até a opção Debug As -> Debug.

Debug As

Feito isso vai veremos a tela abaixo:

Remote

Agora é só colocar endereço que quer acessar e a porta que foi configurada para debug no JBOSS. Agora é só clicar de DEBUG e abrir um browser digitar a URL desejada e pronto ;o) a perspectiva de debug será ativada no primeiro break point.

Comments are off for this post

TWAIN

Até o inicio da década de 90 cada fabricante de scanner desenvolvia seus próprios drivers e programas de captura de imagens. E a falta de padronização impossibilitava o desenvolvimento de aplicações integradas com a captura de imagem já que cada hardware utilizava um 'dialeto' próprio para se comunicar.

Para resolver este problema os fabricantes de scanners decidiram em 1992 criar um comitê para desenvolver um protocolo de troca de dados entre scanners e aplicativos. O comitê queria algo pequeno porém eficiente, que representasse todos os aspectos da indústria. Este protocolo funcionaria como uma espécie de linguagem comum aos scanners facilitando o desenvolvimento de aplicações integradas com a captura de imagens como o Microsoft Photo Editor, o sofisticado Photoshop entre diversos outros. Este protocolo foi chamado de TWAIN.

A presença do TWAIN simplificou o processo de desenvolvimento e os softwares compatíveis com o TWAIN podem utilizar a interface de usuário do scanner sem precisar importar as imagens através de outros programas.

Curiosidade:

TWAIN - Technology Without An Interesting Name - Tecnologia Sem Nome Interessante

Comments are off for this post

« Página anterior