Descripción

Como en casi todas las aplicaciones y herramientas de desarrollo, el mejor lugar para empezar es con un simple ejemplo de "Hello World!" La aplicación habitual de Java Hello World se ejecuta, imprime Hello World y se apaga. Tal vez esto no sea muy interesante para demostrar la capacidad de una herramienta para ejecutar y monitorear servicios. En el caso del Java Service Wrapper, se necesita un ejemplo que se puede instalar, configurarse como un Servicio de Windows o como Demonio UNIX y seguir ejecutandose.

Esta página describe nuestra aplicación de ejemplo Hello World Server, además de ayudarle en el proceso de construcción. La página "¿Cómo puedo ejecutar mi aplicación Java como un Servicio de Windows?" mostrará como usar la aplicación de ejemplo y enseñarle paso a paso la configuración e instalación rápida para poder ejecutarla como un Servicio de Windows haciendo uso del Java Service Wrapper.

Esta aplicación de ejemplo Hello World inicia un subproceso demonio, el cual recibe información del puerto 9000 para clientes basados en forma de texto, que se conectan vía telnet. Esto simplemente imitará cualquier tipo de entrada recibida hasta que se encuentre la entrada exit, en cuyo punto se cerrará la conexión específica.

Si bien esto es un poco más complicado que el ejemplo típico de Hello World, le permite ejecutar una aplicación de servidor fácil, pudiendo interactuar con un programa cliente, siguiendo el modelo de diseño de cliente de servidor fundamental.

Ejemplo del Código Fuente

Con el propósito de mantener nuestro ejemplo claro y dejarle trabajar con facilidad, por favor inicie con un directorio vacío en la ubicación que desee. En el ejemplo lo llamaremos %HELLO_HOME%. Por favor cree los subdirectorios lib\classes y src\java dentro de %HELLO_HOME%, como sigue:

Estructura de Directorio
%HELLO_HOME%\
  lib\
    classes\
  src\
    java\

El siguiente paso es crear un archivo en el directorio src\java llamado HelloWorldServer.java y abrirlo en un editor. Copie la siguiente fuente en dicho archivo y guárdelo.

HelloWorldServer.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class HelloWorldServer
    implements Runnable
{
    private final Socket m_socket;
    private final int m_num;

    HelloWorldServer( Socket socket, int num )
    {
        m_socket = socket;
        m_num = num;
        
        Thread handler = new Thread( this, "handler-" + m_num );
        handler.start();
    }
    
    public void run()
    {
        try
        {
            try
            {
                System.out.println( m_num + " Connected." );
                BufferedReader in = new BufferedReader( new InputStreamReader( m_socket.getInputStream() ) );
                OutputStreamWriter out = new OutputStreamWriter( m_socket.getOutputStream() );
                out.write( "Welcome connection #" + m_num + "\n\r" );
                out.flush();
                
                while ( true )
                {
                    String line = in.readLine();
                    if ( line == null )
                    {
                        System.out.println( m_num + " Closed." );
                        return;
                    }
                    else
                    {
                        System.out.println( m_num + " Read: " + line );
                        if ( line.equals( "exit" ) )
                        {
                            System.out.println( m_num + " Closing Connection." );
                            return;
                        }
                        //else if ( line.equals( "crash" ) )
                        //{
                        //    System.out.println( m_num + " Simulating a crash of the Server..." );
                        //    Runtime.getRuntime().halt(0);
                        //}
                        else
                        {
                            System.out.println( m_num + " Write: echo " + line );
                            out.write( "echo " + line + "\n\r" );
                            out.flush();
                        }
                    }
                }
            }
            finally
            {
                m_socket.close();
            }
        }
        catch ( IOException e )
        {
            System.out.println( m_num + " Error: " + e.toString() );
        }
    }
    
    public static void main( String[] args )
        throws Exception
    {
        int port = 9000;
        if ( args.length > 0 )
        {
            port = Integer.parseInt( args[0] );
        }
        System.out.println( "Accepting connections on port: " + port );
        int nextNum = 1;
        ServerSocket serverSocket = new ServerSocket( port );
        while ( true )
        {
            Socket socket = serverSocket.accept();
            HelloWorldServer hw = new HelloWorldServer( socket, nextNum++ );
        }
    }
}

La aplicación inicia y empieza a "escuchar" en el puerto 9000 para conexiones remotas desde cualquier fuente. Cada vez que se acepta una conexión nueva, se crea un subproceso controlador para encargarse de toda la comunicación relacionada con la conexión hasta que ésta se cierre.

El subproceso controlador leerá e imitará (repetirá) cualquier línea de texto como respuesta al cliente. Si una línea de texto conteniendo solo la palabra exites recibida, la conexión del cliente se terminará.

Generando el Ejemplo

Generar el ejemplo es muy simple. Comience abriendo el Símbolo del Sistema (o Shell en UNIX), acceda al directorio >%HELLO_HOME% que previamente se creó usando el comando cd.

El ejemplo ahora se puede compilar usando el siguiente comando:

Compilando el Ejemplo:
javac -d lib\classes src\java\HelloWorldServer.java

Si recibe un error de que el comando javac no fue encontrado, asegúrese de tener instalado un Java SDK en su sistema. Si todo ha ido bien, entonces debe obtener el símbolo del sistema de nuevo sin ninguna salida adicional después de que se complete la compilación.

Verifique para asegurarse de que el archivo de clase se creó ejecutando:

Comprobar el Archivo de Clase:
dir lib\classes

Felicidades, ha construido exitosamente el ejemplo de HelloWorldServer.

Ejecutar el Ejemplo

La ejecución de la aplicación puede hacerse usando el siguiente comando desde el directorio %HELLO_HOME%.

Ejecutar el Ejemplo:
java -classpath lib\classes HelloWorldServer

Si todo está en orden, verá algo como lo siguiente:

Ejemplo de Salida de Datos:
Accepting connections on port: 9000

Conectar como un Cliente

Ahora trataremos de conectar un cliente a nuestro servidor y veremos que resultados obtenemos. Inicie abriendo una segunda ventana del Símbolo del Sistema y conéctese usando Telnet:

Connecting with Telnet:
telnet localhost 9000

Una vez conectado, deberá recibir una respuesta mostrando su número de conexión. Luego, cualquier texto que escriba seguido de la tecla "Enter" generará el mismo contenido.

Ejemplo de Sesión Telnet:
Welcome connection #1
Test
echo Test
Hello there world!
echo Hello there world!

Cuando termine la conversación con el servidor, puede cerrar la conexión al escribir exit en su propia línea.

Nuestro servidor de ejemplo también tiene la capacidad de aceptar conexiones telnet desde cualquier computadora que pueda ver el servidor. Sin embargo, si tiene algún problema para conectarse, primero asegúrese de que no haya ningún cortafuegos en el camino.

Bloqueo de Servidor

El ejemplo anterior es excelente como un servidor Java independiente simple. Sin embargo, nos gustaría mostrarle como el Java Service Wrapper puede ayudar a mantener nuestro servidor de ejemplo mucho más estable, para que su organización pueda empezar a confiar en el Wrapper para sus sistemas de misión crítica.

Para iniciar, necesitamos agregar un comando crash (bloqueo) nuevo, el cual hará posible que un cliente conectado bloquee la JVM. Mientras es posible crear un bloqueo real usando una serie de "bugs" conocidos en la JVM, muchos de ellos solo funcionan en ciertas plataformas o versiones de Java específicas. Para este ejemplo simularemos un bloqueo al llamar Runtime.getRuntime().halt(0) para que la JVM salga instantáneamente sin cerrarse limpiamente.

Abra la fuente del archivo HelloWorldServer.java en un editor y actualice el código como a continuación:

HelloWorldServer.java (Cambiar)
    ...
    System.out.println( m_num + " Read: " + line );
    if ( line.equals( "exit" ) )
    {
        System.out.println( m_num + " Closing Connection." );
        return;
    }
    else if ( line.equals( "crash" ) )
    {
        System.out.println( m_num + " Simulating a crash of the Server..." );
        Runtime.getRuntime().halt(0);
    }
    else
    {
        System.out.println( m_num + " Write: echo " + line );
        out.write( "echo " + line + "\n\r" );
        out.flush();
    }
    ...

Ahora se puede volver a compilar el ejemplo y ejecutarlo con los mismos comandos que antes.

Ahora trate de conectarse al servidor y enviar el comando: crash. Nuestro servidor de ejemplo se apagará y ya no podrá conectarse o hacer uso del servidor de telnet. Obviamente, si se tratara de un servidor de misión crítica, el administrador del sistema recibiría una llamada telefónica tan pronto como uno de los usuarios tuviera inconvenientes.

Para resolver este tipo de problema, por favor visite la página "¿Cómo puedo ejecutar mi aplicación Java como un Servicio de Windows?" para instrucciones sobre como configurar el servidor como un Servicio de Windows o Demonio en UNIX, que podrá recuperarse automáticamente de nuestro bloqueo de ejemplo, así como un número de problemas inesperados.