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

PyActiveMQ + Mac OS X Snow Leopard

Só uma dica, para o tutorial de instalação/compilação do activemq no Leopard funcionar com o Snow Leopard, depois que executar o passo 2 faça o seguinte:

cd /System/Library/Frameworks/Python.framework/Versions/
mv 2.6 2.6Old
sudo ln -s /opt/local/Library/Frameworks/Python.framework/Versions/2.6 2.6

E depois executar os demais passos... a dica acima tambem serve para o python 2.5 rodando no Leopard ou Snow Leopard.

Twittar este post! No comments

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3

Problemas com unicode?

Vá no diretório <python_home>/lib/python2.6/site-packages/ e crie um novo arquivo com o nome sitecustomize.py com o conteúdo abaixo:

import sys
sys.setdefaultencoding('utf-8')

Prontinho problema resolvido!

Twittar este post! Comments are off for this post

Compilando o PyActiveMQ + ActiveMQ-CPP no Mac OS X Leopard

Finalmente consegui compilar o PyActiveMQ + ActiveMQ-CPP no meu Mac. Uma boa parte do trabalho eu fiz via Mac Port, vou colocar o passo-a-passo abaixo para caso alguem precise fazer o mesmo.

Pré-requistos:

  • X11
  • Apple's Xcode Developer Tools
  • MacPorts 1.710
  • apr-util 1.3.8

Para saber o que você ja tem instalado basta utilizar o comando abaixo:

sudo port installed

1) Atualizando o port:

sudo port -v selfupdate

2) Instalando o python 2.6

sudo port install python26
sudo port install python_select
sudo python_select python26

3) Instalando o Boost com suporte para o Python26

sudo port install boost +python26

Dica importante... este processo demora um bocado... portanto de um volta, tome um café, leia algum blog e por ai vai.

4) Compilando o ActiveMQ-CPP

svn co https://svn.apache.org/repos/asf/activemq/activemq-cpp/tags/activemq-cpp-2.2.6 activemq-cpp-2.2.6
cd activemq-cpp-2.2.6
./autogen.sh
./configure --prefix=/opt/activemq-cpp
make
sudo make install

5) Compilando o PyActiveMQ

svn co http://pyactivemq.googlecode.com/svn/tags/pyactivemq-0.1.0 pyactivemq-0.1.0
cd pyactivemq-0.1.0

Abra o arquivo setup.py e faça as seguintes alterações:
de:

libraries = [
'libactivemq-cpp',
'apr-1',
'aprutil-1',
'apriconv-1',
'uuid',
'ws2_32',
'rpcrt4',
'mswsock',
'advapi32',
'shell32'
]

para:

libraries = [
'libactivemq-cpp',
'apr-1',
'aprutil-1',
'apriconv-1',
#'uuid',
'ws2_32',
'rpcrt4',
'mswsock',
'advapi32',
'shell32'
]

de:

include_dirs = [
'/opt/activemq-cpp-2.2.1/include/activemq-cpp-2.2.1'
]
libraries = [
'activemq-cpp',
'uuid',
'boost_python'
]
extra_compile_args = []
extra_link_args = [
'-Wl,-rpath,/opt/activemq-cpp-2.2.1/lib'
]

para:

include_dirs = [
'/opt/activemq-cpp/include/activemq-cpp-2.2.6',
'/opt/local/include'
]
libraries = [
'activemq-cpp',
#'uuid',
'boost_python-mt'
]
library_dirs = [
'/opt/activemq-cpp/lib'
]
extra_compile_args = []
extra_link_args = [
'-Wl,-rpath,/opt/activemq-cpp/lib'
]

python setup.py build
sudo python setup.py install

Twittar este post! 2 comments

Desejar trabalhar de forma ágil? Venha para a Globo.com!

A Globo.com continua crescendo, inovando e se transformando!

Devido a isso, estamos procurando por um Desenvolvedor (experiente e versátil) com sólidos conhecimentos teóricos de computação e capacidade de adaptação para integrar um de nossos times no GloboEsporte.com. Procuramos pessoas com espírito inovador, curiosidade, paixão por tecnologia e talento, que se empolgam com construir grandes softwares com grandes pessoas. Que acredite que ajudar a criar e distribuir um produto é importante. Nós também procuramos pessoas que pensam sobre o que nossos clientes gostariam de ter, que focam no sucesso do produto e do negócio e não se deixam levar em guerras religiosas sobre processos de desenvolvimento.

Hoje grande parte de nossos aplicativos são desenvolvidos em Java e Python, mas encorajamos o contato de desenvolvedores que dominem outras tecnologias de desenvolvimento web, pois apreciamos visões diferentes e diversidade de conhecimento e acreditamos que um bom desenvolvedor poderá estudar as tecnologias que utilizamos e dominá-las rapidamente.

Prezamos a colaboração e a constante busca pelo aperfeiçoamento.

Nossos Desenvolvedores devem ser capazes de:

  • Trabalhar em equipe e ouvir a equipe;
  • Colocar suas idéias e valores de maneira clara e objetiva;
  • Expor suas opniões com segurança e baseadas em fundamentos;
  • Desenvolver módulos para integração com serviços web;
  • Projetar e programar a aplicação em camadas visando modularização;
  • Elaborar as melhores estratégias de implementação para reduzir o custo de manutenção do produto;
  • Aprimorar o ambiente de desenvolvimento automatizando processos repetitivos;
  • Estimar o tempo de desenvolvimento das atividades;
  • Dividir as atividades (Visões do Cliente) em tarefas;
  • Escolher as tarefas para desenvolvimento;
  • Atualizar o status de suas atividades diariamente;
  • Participar das reuniões de planejamento de iteração e release, reviews e retrospectivas com os demais integrantes do time, clientes e usuários;
  • Desenvolver os produtos de software;
  • Elaborar a arquitetura e esquema lógico dos dados quando necessário;
  • Implementar testes de unidade, aceitação, integração;
  • Trabalhar com ferramentas para Gerência de Configuração de Software (ex.: SVN, GIT e várias outras SCM suites);
  • Refatorar constantemente para manter o código limpo;
  • Integrar freqüentemente com o repositório porém sem descuidar de requisitos mínimos como executar os testes;
  • Revisar o código:
    • Trabalhar em par;
    • Outro desenvolvedor faz uma revisão antes da integração.

É necessário ter experiência comprovada em:

  • Desenvolvimento multi-camadas usando tecnologias tais como EJB ou Hibernate;
  • Desenvolvimento de aplicações Java™ J2EE no ambiente da Web;
  • Implementação de testes unitários em JUnit e DBUnit;
  • Processos e Threads;
  • Redes;
  • Linguagens XML e SQL;
  • Ter sólidos conhecimentos de Engenharia de Software;
  • OO, MVC, Design Patterns;
  • Métodos e estratégias de depuração;
  • Um ou mais servidores de aplicação Java™: Tomcat, JBoss, Bea Weblogic e Jetty;
  • Bancos de dados: Oracle 9i/10g e MySQL.

É importante saber do que se trata e como funciona:

  • Subversion;
  • Git;
  • Test Driven Development (TDD);
  • SOA;
  • Web Services (SOAP, XML-RPC, REST);
  • Javascript, JQuery, Ajax, Template Engines;
  • CSS2, CSS3, HTML, DHTML e XSLT;
  • Scrum.

É desejável conhecer:

  • Linguagens de script (Shell Script, Perl...);
  • Linguagens dinâmicas, preferencialmente Python.

Nós da Globo.com, buscamos criar o melhor ambiente possível, pois acreditamos que o segredo do sucesso de um time está nas pessoas e não nas ferramentas. Por isso, adotamos o Manifesto Ágil e quaisquer idéias que promovam a melhoria dos processos para o desenvolvimento de software. Oferecemos contratação apenas no regime CLT, com salário de mercado e um bom plano de benefícios. Nosso escritório fica localizado na Barra da Tijuca na cidade do Rio de Janeiro e damos suporte a pessoas de outros estados que queiram se mudar. Se você se sente capaz de encarar este desafio, envie seu currículo para andreia at corp dot globo dot com, com o valor pretendido e uma breve descrição do seu interesse pela oportunidade e sua aptidão.

Twittar este post! Comments are off for this post

Software Development Best Practices 2008

O SD Best Practices é uma conferência onde os principais players da comunidade de desenvolvimento de software se reúnem para aprender sobre as últimas tecnologias, e se encontram com os principais vendedores da indústria. A conferência é um treinamento centrado em fornecer as ferramentas necessárias para adoação com êxito em seus projetos das melhores práticas de design, qualidade e técnicas de gerenciamento de projeto.

Com uma programação com 142 sessões apresentadas em 6 formatos (Birds-of-a-Feather Gathering, Estudo de Caso, Classe, Experimental, Mesa Redonda, Tutorial) separados em 10 tracks( Algoritmos Avançados & Conceitos, Processo Ágil & Metodologia, C++, Design & Arquitetura, Linguagem & Implementação, Pessoas, Projetos & Times, Requisitos & Analise, Secure Design, Teste & Qualidade, Web Services/SOA) o SD Best Practices é uma maratona de 5 dias que começa na próxima segunda-feira, 27 de outubro e termina na sexta-feira dia 30 de outubro das 8:30 as 17:00

Solicitação aprovada, passagens compradas, hotel reservado, visto aprovado, agora é fato, Boston aqui vou eu!

Twittar este post! Comments are off for this post

Sobre gerenciamento de projetos

Empresas americanas gastam mais de US$275 bilhões a cada ano em projetos de desenvolvimento de software aplicativo. Muitos desses projetos falharão, mas não por falta de dinheiro ou tecnologia; a maioria falhará por falta de um gerenciamento de projetos habilidoso.

Twittar este post! Comments are off for this post

Aumentando o desempenho ao acessar arrays e os membros de um objeto

Ao desenvolvermos uma aplicação em JNI o acesso aos membros de uma classe é normalmente realizado através das próprias funções JNI, em vez de permitir acesso direto aos membros nativos. Este procedimento tem uma vantagem e um inconveniente:

• Vantagem: Os objetos apontados por referencias são visto de forma simples pelo programador.
• Inconveniente: Impacto no desempenho

Este impacto no desempenho se vê atenuado com a utilização de métodos nativos apenas para realizar funções não triviais, é por este motivo que não costumamos usa-los para realizar operações triviais, exceto é claro em exemplos como neste artigo.

Desempenho acessando arrays

Quando trabalhamos com arrays múltiplos não é viável o uso de função para acessarmos cada elemento de um array, no intuito de resolver este problema foi desenvolvida uma solução chamada ‘pinning’, que consiste em um método nativo que pede a maquina virtual que não remova da memória o conteúdo de um array, desta forma o método nativo pode obter o ponteiro que aponta diretamente para o conteúdo de um array. Esta solução, entretanto, tem duas implicações:

• O garbage coletor deve suportar ‘pinning’. Em muitas implementações é inviável utilizar ‘pinning’ pois complica o garbage coletor e induz � fragmentação da memória.
• A máquina virtual deve posicionar as primitivas contiguamente na memória. Embora esta seja a disposição natural para array de tipos primitivos, os arrays booleanos podem ser implementados como empacotados e desempacotados. Uma disposição booleana empacotado usa um bit para cada elemento, visto que desempacotado usa tipicamente um byte para cada elemento. Conseqüentemente, o código nativo que confia na disposição exata dos arrays booleanos perdera sua portabilidade.

E através das funções do tipo GetArrayElements() podemos apenas obter ponteiros de tipo primitivos de dados, os arrays de objetos devem ser acessados individualmente usando GetObjectArrayElement().

Ainda assim GetArrayElements() não nos garante a obtenção do ponteiro do array original uma vez que ele cria uma cópia em outra área de memória, em resumo esta decisão depende de:

Que o garbage colector suporte “pinning”, no qual implica que o objeto não pode ser liberado ainda que não seja uma referência Java e para que o JNI o libere é preciso executar a função ReleaseArrayElements().

A distribuição dos elementos de um array na memória, assim como o seu tamanho sejam os mesmos do C.

De outra forma o array será copiado para outra área de memória e será formatado convenientemente.

Atento ao fato de que só quando chamamos a função ReleaseArrayElements() que a máquina virtual finaliza o pinning, deixando livre uma cópia do array.

Outra solução que foi incorporada ao JSDK 1.2 as funções GetPrimitiveArrayCritical() e ReleasePrimitiveArrayCritical(), ao uso destas funções são recomendadas sempre que uma thread não:

• Possuir um processo de tempo indefinido
• Chamar outras funções JNI
• Realizar uma operação “thread sleep” (suspensão da execução da thread por um tempo determinado)

Cumprindo estas condições a máquina virtual pode desativar temporariamente o garbage colector enquanto o método nativo acessa diretamente o array, sem que a máquina virtual use pinning. Isto aumenta a possibilidade da máquina virtual retornar o array original em vez de uma cópia.

  1. /* parametros.java */
  2.  
  3. public class Parametros {
  4.  
  5. private native int soma(int a, int b);
  6. private native String texto(String prompt);
  7. private native int[] somaArrays(int[] A, int[] B);
  8.  
  9. public static void main(String[] args) {
  10. Parametros parametros = new Parametros();
  11. System.out.println("4+6=" + parametros.soma(4, 6));
  12. String string = parametros.texto("Digite algum texto");
  13. System.out.println("O texto digitado foi:" + string);
  14. int[] A = { 1, 2, 3 };
  15. int[] B = { 4, 5, 6 };
  16. int[] C = parametros.somaArrays(A, B);
  17. if (C == null) {
  18. System.out.println("Não foi possível realizar a soma.");
  19. } else {
  20. System.out.println("O resultado da soma dos arrays é:");
  21. for (int i = 0; i < C.length; i++) {
  22. System.out.println(C[i] + " ");
  23. }
  24. System.out.println();
  25. }
  26. }
  27.  
  28. static {
  29. System.loadLibrary("parametros");
  30. }
  31. }
  32.  

Listagem 13: Código da classe Parametros.java

Implementação em C.

  1. /* parametros.cpp */
  2.  
  3. JNIEXPORT jintArray JNICALL Java_Parametros_somaArrays(JNIEnv* env,
  4. jobject obj, jintArray arrayA, jintArray arrayB){
  5.  
  6. jintArray arrayC;
  7. jint* A;
  8. jint* B;
  9. jint* C;
  10. jsize i;
  11. //Pegamos o tamanho de um dos arrays e comparamos
  12. jsize tamanho = (*env)->GetArrayLength(env,ArrayA);
  13. if(tamanho!=(*env)->GetArrayLength(env,arrayB))
  14. return NULL; //tamanho dos arrays são diferentes.
  15.  
  16. //criação do array de retorno
  17. arrayC = (*env)->NewIntArray(env, tamanho);
  18.  
  19. A = (jint*)(*env)->GetPrimitiveArrayCritical(env, arrayA, NULL);
  20. B = (jint*)(*env)->GetPrimitiveArrayCritical(env, arrayB, NULL);
  21. A = (jint*)(*env)->GetPrimitiveArrayCritical(env, arrayC, NULL);
  22.  
  23. for (i=0; i < tamanho; i++)
  24. C[i] = A[i]+B[i];
  25.  
  26. (*env)->ReleasePrimitiveArrayCritical(env, ArrayA,A, JNI_ABORT);
  27. (*env)->ReleasePrimitiveArrayCritical(env, ArrayB,B, JNI_ABORT);
  28. (*env)->ReleasePrimitiveArrayCritical(env, ArrayA,A, 0);
  29.  
  30. return C;
  31. }
  32.  

Listagem 14: Código nativo parametros.cpp

Por ultimo devo dizer que JNI garante o acesso concorrente ao array por várias threads, uma vez que o JNI mantém um controlador de pinnings, para que uma thread não finalize o pinning de um array que outra thread esta usando.

Desempenho ao acessar os membros de um objeto

Para obtermos o fieldID ou o methodID realizamos uma busca simbólica em uma base de nomes dos membros, o que é relativamente custoso. Uma forma de diminuir este custo quando houver necessidade de se busca-los mais de uma vez é cachear-los.

Para cachear podemos usar duas técnicas:

1.Cachear em variáveis estáticas de uma função nativa, como por exemplo a função abaixo:

  1. JNIEXPORT void JNICALL Java_MyClass_accessField(JNIEnv *env, jobject obj){
  2.  
  3. static jfieldID fid_s = NULL; /* cacheando field ID para s */
  4. jclass cls = (*env)->GetObjectClass(env, obj);
  5. jstring jstr;
  6. const char *str;
  7. if (fid_s == NULL) {
  8. fid_s = (*env)->GetFieldID(env, cls, "s","Ljava/lang/String;");
  9. if (fid_s == NULL) {
  10. return;
  11. }
  12. }
  13. printf("Aplicação em C:\n");
  14. jstr = (*env)->GetObjectField(env, obj, fid_s);
  15. str = (*env)->GetStringUTFChars(env, jstr, NULL);
  16. if (str == NULL) {
  17. return;
  18. }
  19. printf(" c.s = \"%s\"\n", str);
  20. (*env)->ReleaseStringUTFChars(env, jstr, str);
  21. jstr = (*env)->NewStringUTF(env, "123");
  22. if (jstr == NULL) {
  23. return;
  24. }
  25. (*env)->SetObjectField(env, obj, fid_s, jstr);
  26. }

Listagem 15: Código nativo para cache em variáveis estáticas

2.Cachear ao inicializar uma classe, isso quer dizer que em um bloco estático podemos chamar uma função que inicializa todos os atributos e métodos que vamos precisar.

  1. public class MyClass {
  2.  
  3. private static native void initIDs();
  4. private native void nativeMethod();
  5.  
  6. private void callback(){
  7. System.out.println("Aplicação Java");
  8. }
  9.  
  10. public static void main(String[] args) {
  11. MyClass call = new MyClass();
  12. call.nativeMethod();
  13. }
  14.  
  15. static{
  16. System.loadLibrary("myclass");
  17. initIDs();
  18. }
  19. }
  20.  

Listagem 16: Código da classe MyClass, cache ao inicializar a classe.

Implementação em C.

  1. jmethodID MID_MyClass_callback;
  2.  
  3. JNIEXPORT void JNICALL Java_MyClass_initIDs(JNIEnv *env, jclass cls){
  4. MID_ MyClass_callback = (*env)->GetMethodID(env, cls, "callback", "()V");
  5. }
  6.  
  7. JNIEXPORT void JNICALL Java_ MyClass_nativeMethod(JNIEnv *env, jobject obj){
  8. printf("Aplicação C\n");
  9. (*env)->CallVoidMethod(env, obj,MID_MyClass_callback);
  10. }
  11.  

Listagem 17: Código nativo que implementa o cache na inicialização da classe

E logo initIDs() guarda os IDs em variáveis globais.
Das duas técnicas a mais recomendada é a segunda por varias razões:

1.Os IDs se tornam inválidos logo que a classe é descarregada. Conforme o class loader descarrega a classe e ao se carregar a classe não se atualizam os IDs, na primeira solução porem o mesmo não acontece.

2.É relativamente mais rápido uma vez que carregados os IDs não teremos que voltar a comprovar o valor do ID com:

if (fid_s == NULL) {}

Diferenças de custo entre os objetos nativos e os métodos Java

Neste tópico vamos comentar rapidamente qual o custo de se realizar uma chamada Java-nativo, nativo-Java (chamada callback), comparado com uma chamada java-java.

Uma chamada Java-nativo é mais lenta que uma chamada java-java porque:

1.A máquina virtual tem que liberar as referências locais pra depois chamar o método nativo.
2.A máquina virtual tem que buscar uma função dinâmica em sua biblioteca.
3.A máquina virtual muitas vezes pode chamar in-line quando um método Java chama outro método Java.

Estima-se que o custo é de duas a três vezes superior ao de uma chamada java-java.
Estima-se também que o custo de uma chamada nativo-Java (callback) é duas ou três vezes superior a uma chamada Java-Java. O principal custo agregado esta em:

1.Obtenção do fieldID e do methodID
2.E no acesso aos atributos através de funções, enquanto que a virtual machine pode acessá-los diretamente.

Para Saber Mais
Indicado pela Sun como fonte definitiva de informações sobre JNI.
LIANG, Sheng. The Java Native Interface - Programmers Guide and Specification.
Massachusetts: ADDISON-WESLEY, 1999. ISBN 0-201-32577-2.
Pode ser baixado em:

http://java.sun.com/docs/books/jni/download/jni.pdf

Considerações Finais

Neste artigo apresentamos uma visão geral de como se escrever aplicações híbridas envolvendo Java, JNI e bibliotecas dinâmicas nativas criadas a partir de código C. Abordamos algumas técnicas que podem ser utilizadas para facilitar a integração de sistemas legados. E, ainda uma breve visão de custo e melhoria de desempenho.

Como podemos perceber o JNI é uma ferramenta poderosa, contudo, é preciso estar ciente que uma aplicação Java chamando código nativo compromete a portabilidade e a segurança da aplicação. Pois, embora o bytecode Java compilado permaneça altamente portável, o código nativo deve ser recompilado para cada plataforma na qual se pretenda executar a aplicação.

Referencias

LIANG, Sheng. The Java Native Interface - Programmers Guide and Specification.
Massachusetts: ADDISON-WESLEY, 1999. ISBN 0-201-32577-2.

LINDHOLM, Tim;YELLIN, Frank. Java The JavaTM Virtual Machine Specification.
1999. Ultimo acesso em 17 de Julho de 2006. Disponível em:
< http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html>

MEAD, Matthew. Programmming in C/C++ with the Java Native Interface.
1998. Ultimo acesso em 17 de Julho de 2006. Disponível em:
< http://www.pacifier.com/~mmead/jni/cs510jip/index.html >.

SUN MICROSYSTEMS. Java Native Interface Specification.
2003. Ultimo acesso em 17 de Julho de 2006. Disponível em:

SUN MICROSYSTEMS. javap - The Java Class File Disassembler.
2002. Ultimo acesso em 17 de Julho de 2006. Disponível em:
< http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javap.html>

SUN MICROSYSTEMS. javah - C Header and Stub File Generator.
2002. Ultimo acesso em 17 de Julho de 2006. Disponível em:
< http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javah.html>

Twittar este post! 1 comment

Acessando os métodos de um objeto

Com JNI alem de podermos acessar os atributos de um objeto Java podemos também acessar seus métodos, este acesso é conhecido como callback, pois o Java executa um método nativo e em seguida o método nativo executa um método Java.

Figura 2: Estrutura de Callback

Existem três tipos de métodos Java:
• Métodos de instancia
• Métodos de classe
• Construtores

Vamos abordar o procedimento a ser realizado em cada caso.

Acessando métodos de instancia

O acesso aos métodos de uma classe é extremamente parecido com o acesso aos atributos e para acessá-los também é preciso seguir dois passos:

1.O primeiro passo é obter o methodID do método usando a função:

GetStaticMethodID
Protótipo

  1. jmethodID GetStaticMethodID(JNIEnv *env,jclass clazz, const char *name,
  2. const char *sig);

2.E em seguida usamos as funções:

CallMethod
Protótipo:

<tipoNativo> Call<tipo>Method(JNIEnv *env,jobject obj,
jmethodID methodID, ...);
Call<Tipo>Method <TipoNativo>
CallVoidMethodV void
CallObjectMethodV Jobject
CallBooleanMethodV Jboolean
CallByteMethodV Jbyte
CallCharMethodV Jchar
CallShortMethodV Jshort
CallIntMethodV Jint
CallLongMethodV Jlong
CallFloatMethodV Jfloat
CallDoubleMethodV Jdouble

Devemos usar a função de acordo com o tipo retornado. Os parâmetros são passados por uma lista de parâmetros variáveis que esta no final da função (...)

CallObjectMethod() é usado tanto para métodos que retornam objetos como para métodos que retornam arrays, para os métodos que retornam tipos primitivos devemos usar a função correspondente de acordo com a tabela acima.
Como exemplo, na listagem 7, faremos um método nativo chamado somaC() que chama um método Java chamado somaJava(), conforme listagem 6.

  1.  
  2. public class Contador {
  3. private int atributo = 0;
  4. private native void incrementa();
  5. private int somaJava(int a, int b){
  6. return a + b;
  7. }
  8. private native void somaC();
  9. public static void main(String[] args) {
  10. Contador contador = new Contador();
  11. System.out.println("Antes de chamar o método incrementa()
  12. o atributo vale:"+contador.atributo);
  13. contador.incrementa();
  14. System.out.println("Depois de chamar o método incrementa()
  15. o atributo vale:"+contador.atributo);
  16. contador.somaC();
  17. }
  18. static {
  19. System.loadLibrary("contador");
  20. }
  21. }
  22.  

Listagem 6: Contador.java, implementação do método somaJava()

E a implementação da função nativa correspondente:

  1.  
  2. /* contador.cpp */
  3. (...)
  4. JNIEXPORT void JNICALL Java_Contador_somaC(JNIEnv *env, jobject obj){
  5. int a=5,b=4,c;
  6. //Obter o methodID
  7. jclass class = (*env)->FindClass(env,"Contador");
  8. jmethodID methodID = (*env)->GetMethodID(env, class, "somaJava", "(II)I");
  9. //Executando o metodo
  10. c=(*env)->CallIntMethod(env, obj, methodID, a,b);
  11. }
  12. }

Listagem 7: Contador.cpp, implementação da função somaC()

Acessando métodos de classe

O processo é similar ao de execução de método de instancia, só que agora usamos outras funções.

1.Para obter o methodID usamos:
GetStaticMethodID
Protótipo:

jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name,
const char *sig);

2.Para executar os métodos usamos:
CallStaticMethodV
Protótipo:

<tipoNativo> CallStatic<tipo>MethodV(JNIEnv *env, jclass clazz,
jmethodID methodID, va_list args);
 
CallStatic<Tipo>Method <TipoNativo>
CallStaticVoidMethodV void
CallStaticObjectMethodV Jobject
CallStaticBooleanMethodV Jboolean
CallStaticByteMethodV Jbyte
CallStaticCharMethodV Jchar
CallStaticShortMethodV Jshort
CallStaticIntMethodV Jint
CallStaticLongMethodV Jlong
CallStaticFloatMethodV Jfloat
CallStaticDoubleMethodV Jdouble

Que são idênticas as executadas pelos métodos de instância, porem recebem como parâmetro um jclass em vez de um jobject.

Acessando métodos de instancia de uma superclasse

Em JNI podemos obter a classe base de uma classe usando:

Jclass GetSuperClass(HNIEnv* env, jclass class);

Esta função retorna uma classe ou NULL se a classe for um java.lang.Object ou uma interface.

Se executarmos um método que foi redefinido sobre uma referencia do tipo base usando as funções CallMethod() estaremos na verdade executando o método derivado, já que o Java usa ligação dinâmica.

Para executar um método de base teremos que usar as funções:

CallNonvirtualMethodV

Protótipo:

<nativeType> CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass clazz,
jmethodID methodID, va_list args);
CallNonvirtual<Tipo>Method <TipoNativo>
CallNonvirtualVoidMethodV void
CallNonvirtualObjectMethodV Jobject
CallNonvirtualBooleanMethodV Jboolean
CallNonvirtualByteMethodV Jbyte
CallNonvirtualCharMethodV Jchar
CallNonvirtualShortMethodV Jshort
CallNonvirtualIntMethodV Jint
CallNonvirtualLongMethodV Jlong
CallNonvirtualFloatMethodV Jfloat
CallNonvirtualDoubleMethodV Jdouble

Observe o exemplo das classes Java das listagens 8 e 9 e a implementação das funções nativas na listagem 10.

  1. /* Base.java */
  2.  
  3. public class Base {
  4. public String metodoJava() {
  5. return "Base";
  6. }
  7. public native void metodoC();
  8. public static void main(String[] args) {
  9. Base base = new Derivada();
  10. base.metodoC();
  11. }
  12. static{
  13. System.loadLibrary("Base");
  14. }
  15. }

Listagem 8: Código da classe Base

  1. /* Derivada.java */
  2. public class Derivada extends Base{
  3. public String metodoJava(){
  4. return "Derivada";
  5. }
  6. }

Listagem 9: Código da classe Derivada

Observe que metodoJava() foi redefinido. Vamos provar chamando o objeto do tipo Derivada, usando a função CallObjectMethod() e CallNonvirtualObjectMethod().

  1.  
  2. /* base.cpp */
  3.  
  4. (...)
  5. JNIEXPORT void JNICALL Java_Base_metodoC(JNIEnv* env, jobject object){
  6.  
  7. //Primeiro passo obter o methodID da classe Base
  8. jclass class = (*env)->FindClass(env,"Base");
  9. jmethodID methodID = (env*)->GetMethodID(env, class, "metodoJava","()Ljava/lang/String;");
  10. //Agora executamos o metodo sobre o object que é uma referencia do tipo Base
  11. //que aponta para um objeto Derivada e executa o metodo Derivada
  12. jstring mensagem=(jstring)(*env)->CallObjectMethod(env, object, methodID);
  13. const jbyte* mensagem_c = (*env)->GetStringUTFChars(env, mensagem, NULL);
  14. printf("A mensagem do metodoJava() é :%s", mensagem_c);
  15. (*env)->ReleaseStringUTFChars(env,mensagem, mensagem_c);
  16.  
  17. //Agora vamos executar o método da Base
  18. mensagem = (jstring)(*env)->CallNonvirtualObjectMethod(env, object,class, methodID);
  19. mensagem_c = (*env)->GetStringUTFChars(env, mensagem, NULL);
  20. printf("A mensagem do metodoJava() é :%s", mensagem_c);
  21. (*env)->ReleaseStringUTFChars(env,mensagem, mensagem_c);
  22. }

Listagem 10: Implementação da função nativa, que executa o método da classe Base

Obteremos como saída

A mensagem do metodoJava() é: Derivada
A mensagem do metodoJava() é: Base

Observe que é similar ao uso de super em Java, porem não é igual, pois em Java o super permite chamar os métodos de uma classe imediatamente da base, enquanto que com CallNonvirtualMethod() podemos executar os métodos de qualquer base.

Ex.: se temos:


Figura 3: Exemplo de hierarquia de classe

Tanto em JNI como em Java podemos chamar a partir de B os métodos de A, porem a partir de C não podemos executar os métodos de A usando super porem, podemos fazê-lo usando JNI.

Outra diferença é que podemos executar os métodos da classe base fora do objeto, coisa que não é possível fazer em Java usando super.

Resumindo em Java não podemos fazer:

  1. A a = new B();
  2. a.super.metodo();
  3.  

Acessando um construtor

Acessar um construtor em JNI é igual ao acesso a qualquer outro método de instância a única diferença é que para acessarmos o construtor usamos “” como sendo o nome do método.
E uma vez que tenhamos o methodID do construtor podemos passa-lo para a função:
NewObject
Protótipo:

jobject NewObject(JNIEnv *env, jclass clazz,jmethodID methodID, ...);

Que instância o objeto e executa o construtor especificado.

Existe outra forma de criar objetos Java, que consiste em usar a seguinte função:

AllocObject
Protótipo:

jobject AllocObject(JNIEnv *env, jclass clazz);

Esta função cria um objeto sem iniciá-lo e em seguida usa-se uma função CallNovirtualMethod() para executar o construtor do objeto desejado.

Esta é uma forma menos elegante, pois obteríamos o objeto sem iniciá-lo e não poderíamos esquecer de chamar CallNovirtualMethod() e depois cria-lo com AllocObject().

Como exemplo na listagem 11, vamos fazer um método nativo que cria um objeto Ponto e o retorna com os valores passados como parâmetros ao método nativo.

  1. /* Ponto.java */
  2.  
  3. public class Ponto {
  4. private int x;
  5. private int y;
  6. public Ponto(int x, int y) {
  7. this.x = x;
  8. this.y = y;
  9. }
  10. @Override
  11. public String toString() {
  12. return "["+x+","+y+"]";
  13. }
  14. public static native Ponto criaPonto1(int x, int y);
  15. public static native Ponto criaPonto2(int x, int y);
  16. public static void main(String[] args) {
  17. System.out.println(criaPonto1(2, 3));
  18. System.out.println(criaPonto2(1, 3));
  19. }
  20. static{
  21. System.loadLibrary("ponto");
  22. }
  23. }
  24.  

Listagem 11: Código da classe Ponto.java

Agora, na listagem 12, vamos implementá-lo com NewObject() e também com AllocObject().

  1. /* ponto.cpp */
  2.  
  3. JNIEXPORT void JNICALL Java_PontocriaPonto1(JNIEnv* env, jclass class, jint x, jint y){
  4.  
  5. jmethodID methodID = (env*)->GetMethodID(env, class,"<init>","(II)V");
  6. if(jmethodID==NULL)
  7. return NULL;
  8. return (*env)->NewObject(env,class,"<init>","(II)V");
  9.  
  10. }
  11.  
  12. JNIEXPORT void JNICALL Java_PontocriaPonto2(JNIEnv* env, jclass class, jint x, jint y){
  13. jobject obj;
  14.  
  15. jmethodID methodID = (env*)->GetMethodID(env, class,"<init>","(II)V");
  16.  
  17. if(jmethodID==NULL)
  18. return NULL;
  19. obj = (*en)->AllocObject(env,class);
  20. (*env)->CallNonvirtualVoidMethod(env,obj,class, methodID,x,y);
  21.  
  22. return obj;
  23. }
  24.  

Listagem 12: Código nativo ponto.cpp

Twittar este post! 1 comment

Acessando os atributos de um objeto

O Java suporta dois tipos de atributos:

• Atributos de instância, no qual existe um para cada objeto que instanciamos;
• Atributos de classe, cada classe possui uma única cópia do atributo, independente do número de objetos instanciados a partir da classe. Podemos distingui-los pelo modificador static.

Acessando atributos de instância
O acesso a atributos de instancia é muito simples porem é preciso seguir a risca dois passos:

1. O primeiro é obter o fieldID do atributo que queremos acessar, o fieldID é uma variável do tipo jfieldID usada pelo JNI para referenciar um atributo de um objeto. Para consegui-lo usamos a função:

GetFieldID
Protótipo:

jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name,
const char *sig);

2. Em seguida usamos uma função que nos permite pegar (get) o modificador do atributo a partir do seu jobject e seu fieldID.

GetField
Protótipo:

 GetField(JNIEnv *env,jobject obj,
jfieldID fieldID);

Como podem ver na tabela abaixo existe uma função GetField para cada tipo de dado.

Get<Tipo>Field <TipoNativo>
GetObjectField Jobject
GetBooleanField Jboolean
GetByteField Jbyte
GetCharField Jchar
GetShortField Jshort
GetIntField Jint
GetLongField Jlong
GetFloatField Jfloat
GetDoubleField Jdouble

Sendo que a primeira função da lista é para ler os atributos de objetos.
Existem também funções correspondentes para atribuirmos dados aos atributos (set):

SetField
Protótipo:

void Set<tipo>Field(JNIEnv *env, jobject obj, jfieldID fieldID,
<tipoNativo> value);
Set<Tipo>Field <TipoNativo>
SetObjectField Jobject
SetBooleanField Jboolean
SetByteField Jbyte
SetCharField Jchar
SetShortField Jshort
SetIntField Jint
SetLongField Jlong
SetFloatField Jfloat
SetDoubleField Jdouble

Para exemplificar, na listagem 4, faremos um método nativo em uma classe Java que incrementa o valor de um atributo da própria classe cada vez que o chamamos.

  1. /* Contador.java */
  2.  
  3. public class Contador {
  4. private int atributo = 0;
  5. private native void incrementa();
  6. public static void main(String[] args) {
  7. Contador contador = new Contador();
  8. System.out.println("Antes de chamar o método
  9. incrementa() o atributo vale:"+contador.atributo);
  10. contador.incrementa();
  11. System.out.println("Depois de chamar o método
  12. incrementa() o atributo vale:"+contador.atributo);
  13. }
  14.  
  15. static {
  16. System.loadLibrary("contador");
  17. }
  18. }
  19.  

Listagem 4: Contador.java

A implementação do método nativo correspondente pode ser visto na listagem 5:

  1.  
  2. /* contador.cpp */
  3.  
  4. #include <jni.h>
  5.  
  6. JNIEXPORT void JNICALL Java_Contador_incrementa(JNIEnv *env, jobject obj){
  7. jint valor;
  8. //Buscar a referencia de uma classe no objeto
  9. jclass class = (*env)->GetObjectClass(env,obj);
  10. jfieldID fieldID = (*env)->GetFieldID(env, class, "atributo","I");
  11. if(fieldID ==NULL)
  12. return;//gerar exception
  13. valor = (*env)->GetIntField(env, obj, fieldID);
  14. valor++;
  15. (*env)->SetIntField(env, obj, fieldID, valor);
  16. }
  17.  

Listagem 5: Contador.cpp

Observe que precisamos obter uma referência à classe do objeto, para tanto usamos a função:

GetObjectClass
Protótipo:

jclass GetObjectClass(JNIEnv *env, jobject obj);

Acessando atributos de classe

O acesso aos atributos de classe é parecido com o acesso aos atributos de instância porem para obtermos o fieldID usamos a função:

GetStaticFieldID
Protótipo:

jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name,
const char *sig);

Depois para acessarmos o seu valor usamos a função:

GetStaticField
Protótipo:

 GetStaticField(JNIEnv *env, jclass clazz,
jfieldID fieldID);

E assim como no acesso aos atributos de instância, o acesso a atributos de classe também possui uma função para cada tipo de dado.

GetStatic<Tipo>Field <TipoNativo>
GetStaticObjectField Jobject
GetStaticBooleanField Jboolean
GetStaticByteField Jbyte
GetStaticCharField Jchar
GetStaticShortField Jshort
GetStaticIntField Jint
GetStaticLongField Jlong
GetStaticFloatField Jfloat
GetStaticDoubleField Jdouble

Todavia ao invés de receber um jobject as funções GetStaticField recebem um jclass. E também possui suas respectivas funções de atribuições de dados:

SetStaticField
Protótipo:

void SetStatic<tipo>Field(JNIEnv *env,jclass clazz, jfieldID fieldID,
<nativeType> value);
SetStatic<Tipo>Field <TipoNativo>
SetStaticObjectField Jobject
SetStaticBooleanField Jboolean
SetStaticByteField Jbyte
SetStaticCharField Jchar
SetStaticShortField Jshort
SetStaticIntField Jint
SetStaticLongField Jlong
SetStaticFloatField Jfloat
SetStaticDoubleField Jdouble
Twittar este post! Comments are off for this post

Assinatura ou descritores de argumento

Para descrever os tipos de um atributo ou dos métodos de um objeto, a linguagem Java utiliza as assinaturas de argumento, também conhecida como descritores de membros (member descriptor).

Uma assinatura de argumento é uma string C que contem o tipo de um membro (atributos ou métodos) da uma classe.

ex.:
“Ljava/lang/String;” indica que é um atributo do tipo java.lang.String

Note que os tipos primitivos são representados apenas com letras. As assinaturas de argumento (ou descritores) são definidas a seguir:

Caractere
BaseType
Tipo Descrição
B byte byte assinalado
C char caractere Unicode
D double valor de ponto de flutuação de precisão dupla
F float valor de ponto de flutuação de precisão única
I int inteiro
J long inteiro longo
L; Reference uma instância da classe
S short short assinalado
Z boolean true ou false
[ Reference uma dimensão de matriz

Para saber mais detalhes, consulte o capítulo 4.3.2, Field Descriptors, na Especificação do Sun VM

Por exemplo, para representar o tipo int usamos “I” e para representar o tipo float “F”.

Porem para representar um array usamos um “[” ao lado do tipo.

ex.:
para representar um int[] usamos “[I” e
para representar um double[][] usamos “[[D”.

Por último para representarmos uma classe usamos o prefixo L seguido do nome completo da classe terminando com “;“.

ex.:
para representarmos uma classe java.util.Date usamos
“Ljava/util/Date;”

Note que substituíamos os . por /.

Assim como os atributos, os métodos também possuem uma assinatura de argumento e neste caso para representá-los colocamos primeiro os argumentos do método entre parênteses e depois o seu retorno.

ex.:
Para o método: public int getWidth();
Teremos como assinatura de argumento: “()I” e não “(V)I”.

Ou ainda para o método: public void getWidth(int w);

Teremos como assinatura “(I)V”, isso é para mostrarmos que na assinatura do retorno podemos colocar V.

Outro exemplo um pouco mais complexo:

public java.lang.String formatDate(java.util.Date)

Sua assinatura seria do tipo “(Ljava/util/Date;)Ljava/lang/String;”

Se um método receber vários parâmetros podemos colocá-los um seguido do outro sem nenhum separador:

ex.:
public int soma(int a, int b)
Sua assinatura seria “(II)I”

Agora vamos imaginar que tenhamos recebido uma classe Java, ou que não saibamos qual a assinatura para determinado método ou atributo, como podemos descobri-lo?

A melhor maneira de fazê-lo é utilizando o javap, um desassemblador de classes Java, o javap consegue abrir e ler uma classe Java e listar as assinaturas de argumento de seus atributos e métodos, entre outras coisas.

O javap fica na pasta bin do seu JDK e podemos utilizá-lo da seguinte forma:

javap[-opções] minhaClasse

Sendo que para listar as assinaturas de argumento usamos a opção –s, que informa ao javap que o mesmo deve mostrar as assinaturas no formato JNI e não as assinaturas no formato Java, e para incluímos as assinaturas dos métodos e atributos do tipo private usamos a opção –p.

Caso queria saber um pouco mais sobre o javap consulte sua documentação no site da SUN.

ex.:
Executando javap para a classe InstanceMethodCall:

% javap -s -p InstanceMethodCall

Teríamos como saída:

…
private callback ()V
public static main ([Ljava/lang/String;)V
private native nativeMethod ()V
…	

Uma vez que tenhamos a assinatura do argumento podemos passá-la para as funções como, por exemplo:

FindClass
Protótipo:

tipo_array = (*env)->FindClasse(env, “[I”);

Agora que já sabemos um pouco mais sobre as assinaturas de argumento vamos para o próximo passo "Acessando os atributos de um objeto".

Twittar este post! Comments are off for this post

Próxima Página »