lunes, 24 de noviembre de 2008

Como hacer un demonio en Linux usando Java

En ocasiones es necesario, por la razón que sea, crear aplicaciones capaces de funcionar como demonios en linux (también conocidos como servicios en win2)...

El problema en java, para desarrollar un demonio, es el hecho de que la ejecución de los programas inicia siempre por el main, esto está bien para una aplicación cliente, donde una persona inicia y detiene la ejecución, pero ya que un demonio es manejado directamente por el sistema sin necesidad de intervención por parte del usuario esto se convierte en un problema, para solucionar esta situación existe una utilidad en linux llamada jsvc, más información.

Usando jsvc solamente hace falta crear una clase que implemente los métodos o funciones necesarios para responder a cuatro eventos importantes durante la vida de un demonio, los cuales son:

  1. init: inicializar todos los recursos. (en la documentación oficial dice que el método se llama load pero esto es incorrecto)
  2. start: inicia el proceso y espera por peticiones.
  3. stop: indica un cierre inminente al demonio para que pueda liberar recursos adquiridos durante el init por ejemplo cerrar sockets abiertos.
  4. destroy: elimina cualquier objeto creado durante el init.
Para ejecutar jsvc se necesitan privilegios de administrador, de cualquier forma la utilidad acepta una opción para especificar el usuario con el cual ejecutar el demonio después de terminado los pasos que requieren privilegios de root.

Bueno manos a la obra, para trabajar estoy usando Ubuntu 8.04 y Java 1.6.0_07:

Primero: hay que definir una clase en java que implemente apropiadamente las funciones antes descritas en nuestro editor de preferencia:
package daemon;

public class JavaDaemon
{

/**
* Here open the configuration files, create the trace file,
* create the ServerSockets, the Threads, etc.
* @param parameters
*/
public void init(String []parameters){
System.out.printf("Init params %s", parameters.toString());
}
/**
* Start the Thread, accept incoming connections.
*/
public void start(){
System.out.println("start server life...");
}
/**
* Inform the Thread to stop, close the ServerSockets.
*/
public void stop(){
System.out.println("stop signal recieved...");
}
/**
* Destroy any object created in init()
*/
public void destroy(){
System.out.println("destoying all objects...");
}
}

Segundo: instalar, sino lo está ya, la utilidad jsvc con el siguiente comando:
sudo aptitude install jsvc

Tercero: descargar la librería commons-daemon.jar desde la siguiente dirección: http://commons.apache.org/downloads/download_daemon.cgi descomprimimos el archivo descargado y copiamos la librería commons-daemon.jar en donde tenemos nuestra clase compilada. Opcionalmente pueden empaquetar su clase en un archivo jar ya sea a mano o usando alguna herramienta o IDE, yo he creado un jar y lo he nombrado myDameon.jar.


Para ejecutar el demonio en una consola escribimos el siguiente comando:
sudo jsvc -user @user -home /usr/lib/jvm/java-6-sun/jre -debug -pidfile /var/run/myDaemon.pid -cp commons-daemon.jar:myDaemon.jar daemon.JavaDaemon

Nota: reemplazar @user con algún usuario válido, por ejemplo el que estemos usando.

Y para detener el demonio podemos usar el siguiente comando:

sudo jsvc -stop -pidfile /var/run/myDaemon.pid -cp commons-daemon.jar:myDaemon.jar daemon.JavaDaemon

Con esto tenemos listo nuestro primer demonio implementado en java.
Saludos.

6 comentarios:

  1. Hola, esta bueno tu blog... No te interesa Que ponga tu blog en mi Blogroll y viceversa amigo??
    Cualquier cosa me comunicas por ferfactor@gmail.com

    ResponderEliminar
  2. Que tal man, pues fijate que tengo un problema con esto ya que siempre me tira el error que no encuentra la clase Test la cual la inserte en un .jar como dices en el post.

    Las variables de entorno las tengo bien configuradas, cuando corro la clase que pones como ejemplo me tira error que no encuentra el main, pero esta bien xq esa la implementa con commons-daemon.jar. Nose si haya que hacer algo de más x allí gracias x tu ayuda

    ResponderEliminar
  3. Hola c@rlos.

    Bueno para empezar ¿Estas usando algún IDE? de ser así ¿Al crear el proyecto lo definiste como una aplicación (hay una clase que tiene un main) o una librería (no existe una clase con un main)? lo correcto es crearlo como una librería.

    Por favor postea el error que recibes, así tendré una mejor idea de lo que pasa.

    Veras los jar tienen un archivo llamado MANIFEST.MF dentro de una carpeta llamada META-INF en donde es posible definir la clase "principal" es decir por donde se inicia/ejecuta la aplicación, para aquellos que son ejecutables (aplicaciones). Por lo que mencionas me parece que simplemente has borrado el main de la clase Test y ahora java no logra encontrar dicho método para iniciar el programa.

    Asegurate de crear un proyecto que no sea ejecutable (una librería) y de que estas colocando la ruta completa para que la herramienta jsvc pueda encontrar la clase que implementa los cuatro métodos necesarios: init, start, stop y destroy, por ejemplo:

    sudo jsvc -user @user -home /usr/lib/jvm/java-6-sun/jre -debug -pidfile /var/run/myDaemon.pid -cp commons-daemon.jar:test.jar package1.subpackage1.Test


    Un ejemplo del manifest de un jar ejecutable (creado automáticamente por el IDE que uso):

    Manifest-Version: 1.0

    Ant-Version: Apache Ant 1.7.0
    Created-By: 11.0-b15 (Sun Microsystems Inc.)
    Main-Class: test.Test
    Class-Path: lib/appframework-1.0.3.jar lib/swing-worker-1.1.jar
    X-COMMENT: Main-Class will be added automatically by build


    y un manifest de un jar no ejecutable:
    Manifest-Version: 1.0
    Ant-Version: Apache Ant 1.7.0
    Created-By: 11.0-b15 (Sun Microsystems Inc.)

    Hasta pronto y buena suerte.

    ResponderEliminar
  4. Tu guia esta muy buena amigo. Muchas gracias por el recurso que has publicado. Solo tengo uan pregunta. Una ves que has ejecutado el comando 'sudo jsvc -user @user -home .......' en la consola ¿ya queda registrado nuestro programa como servicio y cada ves que se reinicie por ejmplo la maquina nuestro demonio arrancara automaticamente?. No se si la preguta puede ser muy obvia pero no tengo la respuesta y te agradeceria si me la puedes responder. Hasta pronto.

    ResponderEliminar
  5. Diego, de verdad que no vi antes tu pregunta, pero por si acaso alguien más tiene esta duda la respuesta es NO, el comando inicia el servicio pero si apagas la máquina el servicio no volverá a iniciar automaticamente.

    Puedes consultar este otro post donde explico como registrar "archiva" como un demonio. La idea sería la misma y una vez que tengas un script capas de iniciar el servicio podrías usar el comando update-rc.d.

    ResponderEliminar
  6. Exelente tu articulo gracias por la info

    ResponderEliminar

Deja tu comentario :D