Una de las ventajas de Java es ser multiplataforma que le permite trasladar su código entre plataformas gracias a la máquina virtual (JVM).
Pero hay veces que necesitamos hacer cosas sobre el sistema operativo anfitrión, en esos casos se complica la cosa... se puede solucionar de varias formas como: haciendo que lance un script, creando un socket que se conecte a otro lenguaje de programación que actúe en local, etc. pero casi todas esas opciones implican lentitud u otros problemas o efectos laterales.
Java dispone de una tecnología que nos ayuda en estos casos: JNI (Java Native Interface) que nos permite utilizar códigos C ejecutándolos en Java, lo cual puede hacer que sea incluso más rápido que la ejecución a través de la JVM.
Como punto de partida necesitamos un código Java (luego necesitaremos otro en C, pero vayamos por partes):
De este código destacan 2 cosas:
- Una función no tiene cuerpo y tiene la palabra reservada native en su declaración, con esto se indica que es una función llamada a través de JNI. Es parecido a decir que es abstracta y que su cuerpo está en otro lugar (pero no es lo mismo abstracta que nativa).
- Hay un trozo estático de carga de una librería, con ello le decimos que librería debe cargar para utilizar esa función nativa.
Los 2 archivos (el .java y el .c) puede descargarse desde un proyecto hecho en github.
El siguiente paso es compilar este código, con el comando:
javac JavaJni.java
Una vez que lo tenemos compilado, generamos la cabecera C de esta clase, con el comando:
javah -jni JavaJni
El resultado de este comando es:
Si analizamos esa captura veremos que aparece una declaración de una función Java_JavaJni_getTexto y sus parámetros son: el enviroment (entorno), el objeto y los parámetros de la función, en este caso un entero.
Ahora nos toca implementar el código C que utilice esta cabecera (como se ve en los includes):
Ahora vamos a compilar ese código pero poniendo dentro de los directorios a incluir el directorio de includes de java (para que no de error cuando busque la librería jni.h), en mi caso ejecuto el siguiente comando:
gcc -I/usr/lib/jvm/default-java/include -g -c -Wall -fPIC JavaJni.c -o JavaJni.o
Ahora nos queda hacer que se incluya nuestro archivo en las librerías y evitar que nos muestre el típico error: no JavaJni in java.library.path Para ello vamos a crear una librería que aglutine a todos los archivos (en nuestro ejemplo es sólo uno), esta librería va a llevar el prefijo lib y el sufijo .so que es como se llaman las librerías en Linux, lo haremos con el comando:
sudo ld -G *.o -o libJni.so
Ahora, al ejecutar el código hay que indicarle donde está la librería, este paso es un generador de dolores de cabeza, así que os pondré las 3 formas que he conseguido echarlo a andar:
1. La básica: decirle al comando de ejecución java que mire busque la librería en el mismo directorio:
java -Djava.library.path=. JavaJni
export LD_LIBRARY_PATH=.
java JavaJni
3. La profesional: y más recomendada... crear un enlace simbólico desde el directorio donde deben estar las librerías (/usr/lib) al directorio donde estamos trabajando y ejecutarlo:
sudo ln -s /home/pi/jni/libJni.so /usr/lib/libJni.so
java JavaJni
Os pongo una captura del final con el ejemplo ejecutado:
Con esto ya podemos realizar aplicaciones utilizando librerías del sistema operativo.
Este pequeño manual ha sido basado en otro muy bueno (enlace). Habiendo superado esta parte, si queréis seguir ampliando os recomiendo que miréis 2 sitios webs: El oficial de Oracle para JNI (enlace) y uno de la Universidad de Sevilla (enlace).
A modo de recordatorio, los 2 archivos utilizados (el .java y el .c) pueden descargarse desde un proyecto hecho en github.
Como siempre para acabar, dejo un enlace al post inicial desde el cual se puede acceder a los demás post creados... bye!
No hay comentarios:
Publicar un comentario