Configuración y uso de Apache JServ
|
Ari Halberstadt, 1999 (ari@shore.net) Apache JServ es un módulo para el popular servidor web Apache que implementa la API de servlets de Java de Sun para ejecutar codigo del lado del servidor. Puede que esté interesado en este artículo si esta desarrollando software Java para ejecutarlo en un web site y se usa el servidor Apache. Actualmente el servidor Apache es el más popular y utilizado en Internet. Tanto el servidor Apache como el módulo Apache JServ son libres e incluyen su código fuente completo. Este artículo proporciona información sobre cómo usar Apache JServ para desarrollar servlets de Java, incluyendo tanto la instalación básica como configuración y gestión interemedia y avanzada. Este artículo (o una versión muy parecida) aparece en el libro Professional Java Server Programming, publicado por Wrox Press. Un artículo relacionado, centrado en la configuración de Apache Jserv desde la perspectiva de un administrador de Apache aparece en el libro Professional Apache de Peter Wainwright, también publicado por Wrox Press. Nota: Los ejemplos de este artículo han sido probados con Apache JServ 1.0b5, que fue la última release beta antes de la versión final 1.0 del 14 de Junio de 1999.
Contenido
ArquitecturaLos Java servlets deben ser ejecutados desde una máquina virtual Java (JVM de ahora en adelante), y por lo tanto cualquier entorno de ejecución de servlets debe incluir una. Añadir una JVM al servidor Apache no es una opción viable, la complejidad y sobrecarga asociadas a una JVM son prohibitivas, y degradarían la arquitectura del servidor. La solución adoptada con Apache JServ ha sido separar la JVM del servidor Apache. Esta separación proporciona, además, diversas ventajas. Permite el uso de cualquier JVM compatible proporcionada por cualquier proveedor. No se tiene que hacer ninguna modificación al servidor web cuando se hace un cambio en la JVM, como actualizarla a una versión mejorada. También proporciona mayor estabilidad el separar los procesos, permitiendo así protecciones de proceso y nivel por el sistema operativo. Si la JVM cae o se desconfigura, el servidor web seguira funcionando normalmente. También proporciona funcionalidades avanzadas, como arranque automático versus arranque manual, diferentes JVMs para diferentes configuraciones y la habilidad de soportar balance de carga en sites con un alto tráfico. El servidor Apache incorpora una arquitectura modular, mediante la que se le pueden añadir funcionalidades. Los módulos pueden ser enlazados con el servidor estáticamente o bien puden ser cargados de forma dinámica usando DSO (objectos dinámicos compartidos, Dinamic Shared Object) en Unix o DLL (Dynamically Linked Libraries) en Windows. La API para estos componentes modulares está basada en el lenguaje C. Apache JServ está implementado como dos componentes separados, uno escrito en C y el otro en Java, llamado Protocolo Apache Jserv (Apache JServ Protocol-AJP). La versión actual de este protocolo es la 1.1., por lo que le denomina ajpv11. El lado C de Apache JServ, llamado mod_jserv, proporciona una interficie entre el servidor web Apache y el lado Java. El módulo pasa peticiones e información entre el servidor web y el lado Java, y puede ser usado para arrancar y parar automáticamente la JVM en que el se ejecuta dicho lado Java. El lado Java de Apache JServ, llamado el Motor de Servets (Servlet Engine), implementa la API servlet, y es donde está la mayoría de las funcionalidades del Apache JServ. El lado Java está, de hecho, completamente separado del lado C, y el único enlace entre ellos es el AJP. Así, se puede atacar el lado Java desde cualquier servidor web siempre que se tenga un módulo apropiado de comunicación usando AJP para ese servidor web. El lado C, o mod_jserv,se puede entender como un cliente del lado Java del Apache JServ. Del mismo modo, el lado Java se puede entender como un servidor que acepta peticiones desde el cliente. Éste es, esencialmente, un modelo de tres capas, en el que el navegador actúa como front end, el servidor web es la capa media y el lado C del Apache JServ es el back end. Este modelo de tres capas se puede extender a uno de N capas si se accede a servicios adicionales como bases de datos o servidores de aplicaciones a través de Apache JServ. En este modelo, la capa comprendida por servidor web Apache y mod_jserve puede ser reemplazada con cualquier programa que use el protocolo AJP para comunicarse con Apache JServ. Apache JServ introduce también los conceptos de almacenes (repositories) y de zonas de servlets (servlet zones). Los almacenes de servlets son lugares desde donde son llamados los ficheros de clases de Java, incluyendo ficheros JAR (Java ARchives) y directorios que contengan jerarquias de clases de Java. Las zonas de servlets (servlet zones) son análogas a hosts virtuales en un servidor web. Cada zona puede tener su propio conjunto de servlets, e incluso usar una JVM dedicada. Secciones posteriores detallarán más cómo usar zonas de servlets y almacenes.
Instalación básicaEsta sección proporciona una introducción rápida para tener funcionando en una máquina una instalación de Apache y Apache JServ. Se pueden explorar opciones de configuración más avanzadas una vez se haya completado con éxito la instalación básica. Ésta consiste en dos pasos principales: instalación del servidor web Apache, y seguidamente la instalación del motor de servlets Apache Jserv. También se puede añadir Apache JServ a un servidor Apache ya existente saltando la instalación del servidor, haciendo sólo la instalación del Apache JServ. El ejemplo de instalación proporciona un punto de partida básico para explorar servlets Java usando Apache JServ, pero hay unos cuantos aspectos de una configuración completa que se pueden continuar explorando. Para trabajar con Apache JServ sacándole partido se deberían entender conceptos básicos, que incluyen los diferentes tipos de ficheros de configuración, las zonas de servlets, los almacenes (repositories) de clases, la rellamada automática de clases y cómo añadir servlets. Puede que también quieras explorar temas más avanzados, como mapeo de URLs a servlets, configuración de hosts virtuales, uso de múltiples JVMs, mejora del rendimiento, consideraciones sobre seguridad y funcionalidades añadidas.
RequerimientosSe necesita un sistema con JDK 1.1 o 1.2. También se necesita bajar e instalar el Java Servlet Development Kit (JSDK), versión 2.0, desde el website de Sun: http://java.sun.com/products/servlet/index.html. La versión 1.0 de Apache JServ es comptabile sólo con la versión 2.0 del JSDK, y no funcionará con ninguna otra versión de JSDK. Para la instalación en un sistema Unix también se necesita un compilador C y la utilidad make, como por ejemplo gcc y gmake del proyecto GNU, disponibles en el web site de Free Software Foundation www.fsf.org. Casi todos los sistems Unix incluyen versiones apropiadas o equivalentes a estos programas en su instalación estándar. Para la instalacion en Windows NT, corriendo sobre un i386 o compatible, no se necesita un compilador de C, ya que estan disponibles directamente los programas de instalación conteniendo los binarios compilados de Apache y Apache Jserv. Los requerimientos de disco son mínimos, una instalación completa de Apache y Apache JServ en mi sistema Linux (sobre Intel Pentium) ocupa alrededor de 3 MB, y necesita unos 10 MB adicionales para compilar y construir ambos programas. Los requerimientos de memoria dependen, en gran manera, del sistema operativo que se tenga y de la JVM. Como la JVM utilitza la parte del león de los recursos de memoria, se debe consultar la documentación de la JVM propia, aunque una buena aproximación es tener, al menos, 32 o 64 MB disponibles. Antes de instalar Apache JServ se debería verificar que se tiene una instalación de Java operativa. El intérprete debe ser compatible con JDK 1.1, lo que se puede comprobar con el comando java -version java version "1.1.7" Se puede comprobar si se puede compilar código Java simplemente compilando un programa de prueba. Per ejemplo, guardando el siguiento código en un fichero llamado HolaMundo.java: public class HolaMundo {
public static void main(String argv[])
{
System.out.println("Hola, mundo!");
}
}
y despues compilando y ejecutando el programa: javac HolaMundo.java java HolaMundo Hola, mundo! Si no se puede compilar y ejecutar este pograma, deberían consultarse las instrucciones de instalación del JDK. Para simplificar el desarrollo de servlets, se puede añadir el path del JSDK al classpath, lo que permite que scripts de ejemplo que vienen con Apache JServ puedan localizar automáticamente el JSDK, si no, se tendrá que especificar el path del JSDK cada vez un servlet se compile. Por ejemplo, en Unix, añadiendo las líneas CLASSPATH=$CLASSPATH:/usr/local/java/jsdk/lib/jsdk.jar export CLASSPATH al fichero .profile, en el que /usr/local/java/jsdk es el sitio donde se ha instalado el paquete JSDK de Sun. UnixHay que bajarse, descomprimir, configurar, compilar e instalar el servidor Apache y el motor de servlets Apache JServ. Cada producto incluye suficientes directivas/instrucciones para configurarlo, compilarlo e instalarlo en sus respectivos documentos INSTALL. La principal decisión a tomar es compilar Apache con DSO o bien enlazar (linkar) Apache JServ estáticamente con el servidor. El soporte DSO permite a Apache llamar módulos en tiempo de ejecución, reduciendo así el volumen del ejecutable y añadiendo y eliminando los modulos más convenientes, pero no todos los sistemas proveen soporte DSO, por lo que, en ese caso, se tiene que usar una compilación estática. Para tener una referencia, he incluido las instrucciones que usé para hacer una instalación limpia de Apache v1.3.6 y Apache JServ 1.0b5 en mi sistema Red Hat Linux v5.1. He incluido dos versiones de dos grupos de instrucciones: uno compilando Apache con soporte DSO, y otro enlazando las librerías estáticamente. Para otros sistemas, se necesita adaptar estos comandos, y también se debe instalar las versiones más recientes de Apache y Apache JServ. En estos ejemplos, yo he utilizado la utilidad wget (del proyecto GNU) para bajarme las aplicaciones, pero si no está en el sistema propio, se puede utilizar cualquier navegador para bajártelas. Necesitarás hacer la instalación como un usuario con suficientes privilegios como para escribir en los diferentes directorios, un usuario como por ejemplo root. Sin embargo, puedes instalar los programas en cualquier sitio de tu disco, incluso en tu directorio personal (home), ya que el directorio de instalación se indica usando la directiva --prefijo en el script de configuración de Apache, y con las directivas --with-apache-install o --with-apache-src en el caso del script de Apache JServ. ApacheScript de ejemplo para instalar el servidor web Apache con soporte DSO: % cd /usr/local/src % wget http://www.apache.org/dist/apache_1.3.9.tar.gz % gunzip -c apache_1.3.9.tar.gz | tar x % cd apache_1.3.9 % ./configure --prefix=/usr/local/apache --enable-module=most --enable-shared=max % make % make install Script de ejemplo para instalar el servidor web Apache sin soporte DSO: % cd /usr/local/src % wget http://www.apache.org/dist/apache_1.3.9.tar.gz % gunzip -c apache_1.3.9.tar.gz | tar x % cd apache_1.3.9 % ./configure --prefix=/usr/local/apache % make % make install Llegados aquí, y suponiendo que no ha habido errores durante la instalación, deberías poder arrancar Apache y confirmar que está trabajando accediento la página por defecto del mismo: % /usr/local/apache/bin/apachectl start % lynx http://localhost Si no puedes acceder a la página por defecto del servidor, entonces deberías mirar en el web site de Apache, http://www.apache.org, y en la documentación on-line para más asistencia. El procedimiento superior provee una instalación bastante rudimentaria, por lo que deberías refererirte a la documentación on-line de Apache, accesible a través de la página por defecto (http://localhost), para más instrucciones de configuración e instalación (por ejemplo, podrías activar el arranque automático de Apache después de cada rearranque del sistema). Apache JServScript de ejemplo para instalar Apache JServ con soporte DSO: % cd /usr/local/src % wget http://java.apache.org/jserv/dist/Apache_JServ_1.0.tar.gz % gunzip -c Apache_JServ_1.0.tar.gz | tar x % cd ApacheJServ_1.0 % ./configure --with-apache-install=/usr/local/apache % make % make install
Script de ejemplo para instalar Apache JServ como un módulo estáticamente enlazado (este script construye y reinstala Apache despue de construir e instalar Apache JServ): % cd /usr/local/src % wget http://java.apache.org/jserv/dist/Apache-JServ-1.0b5.tar.gz % gunzip -c Apache-JServ-1.0b5.tar.gz | tar x % cd ApacheJServ-1.0b5 % ./configure --with-apache-src=/usr/local/src/apache_1.3.9 --enable-apache-conf % make % make install % /usr/local/apache/bin/apachectl stop % cd /usr/local/src/apache_1.3.9 % make % make install Una vez instalado Apache JServ aún hay que configurar Apache para que se comunique con Apache JServ, lo que se puede hacer añadiendo la siguiente línea al final del fichero httpd.conf file (en /usr/local/apache/conf/httpd.conf): Include /usr/local/src/ApacheJServ-1.0b5/example/jserv.conf Asumiendo que la instalación haya procedido sin errores, deberías poder rearrancar Apache y acceder al servlet de ejemplo Hello, para confirmar que tu instalación haya sido correcta. /usr/local/apache/bin/apachectl restart (espera unos segundos para darle tiempo a Apache a rearrancar) lynx http://localhost/example/Hello Si no puedes acceder al servlet, entonces mira en la sección de solución de problemas. Prueba a acceder la URL unas cuantas veces, ya que puede ser que Apache JServ tarde algunos segundos en cargarse y empezar a aceptar peticiones. WindowsInstalar Apache consiste en bajarse y ejecutar el programa instalador y luego arrancar Apache. Se puede bajar el instalador para Windows desde http://www.apache.org/dist (para Apache 1.3.6 els instalador está en el fichero apache_1_3_6_win32.exe). Después de bajarte el fichero, ejecuta el instalador (haz doble click sobre el fichero .exe). Después de la instalación, arranca Apache desde el grupo de opciones de menú Apache Web Server, bajo el menú de Inicio desde el prompt de sistema (línea de comandos). Hecho esto, usa tu navegador para acceder a la home page por defecto en http://localhost. Si eso no funciona, consulta la documentación de Apache y el web site de Apache. Instalar Apache JServ consiste en bajarse y ejecutar el instalador, y luego rearrancar Apache. El instalador para Windows de Apache JServ está en http://java.apache.org/jserv/dist/. Para Apache JServ 1.0b5 el instalador está en el fichero Apache-JServ-1.0b5.exe. Después de bajarte el fichero, ejecuta el instalador (haz doble click sobre el fichero .exe), seleccionando la instalación integrada, de manera que Apache JServ será arrancado y parado automáticamente por el servidor web. Después de la instalación rearranca el servidor web (o sea, para y arranca el servidor). Para probar la instalación, accede a la URL http://localhost/servlets/IsItWorking, que debería ejecutar el servlet de ejemplo y mostrar una página simple. Si no puedes acceder al servlet, mira en la sección solución de problemas. Prueba a acceder la URL unas cuantas veces, ya que puede ser que Apache JServ tarde algunos segundos en cargarse y empezar a aceptar peticiones.
Ficheros de configuración y directivasApache y Apache JServ utilizan diversos ficheros de configuración. Respecto a Apache, el fichero más interesante es httpd.conf, donde estan (entre otras cosas) las directivas para la carga de módulos y la configuración del módulo mod_jserv. El fichero de configuración principal para el motor de servlets es el fichero de propiedades del motor, y suele ser jserv.properties. Contiene las propiedades pasadas a la JVM, opciones diversas y preferencias de seguridad, y una lista de todas las zonas de servlets y sus ficheros de propiedades respectivos. Cada zona de servlets usa también su propio fichero de propiedades, el fichero de propiedades de zona. Éste contiene propiedades que especifican almacenes (repositories) desde los que los servlets son llamados en la zona, si las clases son cargadas automaticamente cuando se cambian, y otros puntos especificos de cada zona de servlets Directivas de ApacheSi has instalado la configuración de Apache JServ, entonces habrás añadido una directiva Include en httpd.conf para añadir el fichero de configuración de ejemplo (estas directivas se usan para configurar mod_jserv de manera que se pueda comunicar con el motor de servlets). También puedes configurar mod_jserv añadiendo las directivas apropiadas en httpd.conf. Si estás usando Apache JServ como un módulo DSO, entonces deberías incluir una directiva LoadModule en httpd.conf para cargar mod_jserv. En Unix, esto se hace más o menos como sigue: LoadModule jserv_module libexec/mod_jserv.so En Windows, esto sería: LoadModule jserv_module modules/ApacheModuleJServ.dll La directiva LoadModule es parte de mod_so, y no deberías utilitzarla si has enlazado mod_jserv estaticament a Apache. Las directivas que son especificas de mod_jserv estan mejor puestas dentro de una directiva IfModule, de manera que el servidor web pueda arrancar incluso si mod_jserv se elimina de manera temporal. Por ejemplo, una instalación básica podría incluir las siguientes directivas en httpd.conf: <IfModule mod_jserv.c> ApJServProperties /usr/local/apache/conf/jserv.properties ApJServLogFile /usr/local/apache/logs/mod_jserv.log ApJServSecretKey DISABLED ApJServMount /servlets /servlets <Location /status/jserv/> SetHandler jserv-status order deny,allow deny from all allow from localhost </Location> </IfModule> Los comentarios en el fichero de configuración de ejemplo incluido en Apache JServ (bajo el directorio examples/jserv.conf) incluyen una descripción de todas las directivas de configuración disponibles. Actualmente este fichero se incluye en httpd.conf (a través de la directiva Include de Apache), después de una correcta instalación de Apache JServ. El fichero httpd.conf se carga sólo cuando el servidor web arranca, de manera que tendrás que rearrancar el servidor después de cualquier modificación. Propiedades del motorEl fichero de propiedades del motor es leído tanto por mod_jserv como por el propio motor de servlets. Este fichero contiene pares de propiedades nombre/valor. Un fichero de ejemplo, que contiene comentarios explicando cada propiedad, se incluye con la distribución de código de Apache JServ en examples/jserv.properties. Hay un fichero de propiedades distinto para cada JVM usada por Apache JServ. Este fichero contiene propiedades que se necesitan para lanzar la JVM, questiones de de seguridad y comunicación para comunicación con el servidor web Apache, y propiedades para activar rastreo (logging). Este fichero se llama sólo una vez en el arranque, por lo que cualquier cambio sólo será efectivo a partir de la reinicialización del servidor web y la JVM. A continuación hay un ejemplo de un fichero de configuración mínimo de un motor: wrapper.bin=/usr/local/java/jdk/bin/java wrapper.class=org.apache.jserv.JServ wrapper.classpath=/usr/local/jserv/lib/ApacheJServ.jar wrapper.classpath=/usr/local/java/jsdk/lib/jsdk.jar port=8007 security.allowedAddresses=127.0.0.1 security.authentication=false zones=servlets servlets.properties=/usr/local/apache/conf/servlets.properties En este ejemplo, las propiedades wrapper son usadas por mod_jserv para arrancar automáticamente el motor de servlets. La propiedad port indica qué puerto debe usar el motor para comunicarse con mod_jserv, y la propiedad zones lista las zonas de servlets a las que se puede acceder. La propiedad que empieza conel nombre de una zona de servlets, seguida por el texto ".properties" (en el ejemplo, servlets.properties) especifica la localización del fichero de propiedades de zona para cada zona de servlets. Propiedades de zonaCada zona de servlets usa un fichero de propiedades de zona. Este fichero contiene una lista de almacenes (repositories) que contienen ficheros de clase y servlets Java. También contiene alias y arguments de inicialización para los servlets de cada zona. A continuación hay un ejemplo de un fichero de configuración mínimo de propiedades de una zona. repositories=/usr/local/apache/servlets Este fichero de propiedades sólo indica un directorio que puede contener servlets.
Añadir y ejecutar ServletsLos servlets se añaden a una zona de servlets poniendo los ficheros compilados de la clase (.class) en uno de los almacenes de la zona. Por ejemplo, se puede añadir un serlvet a la zona de ejemplo de servlets que viene con la instalacin de Apache JServ poniendo el servlet compilado (.class) en el directorio de ejemplo, que esta en la carpeta exampe en la distribución fuente (p.e., /usr/local/src/ApacheJServ-1.0b5/example). Un buen servlet de ejemplo es SnoopServlet, que se incluye con el JSDK de Sun. Este servlet imprime la mayoría de la información que el motor de servlets le pasa al servlet. Puedes compilar SnoopServlet, lo que da una fichero llamado SnoopServlet.class, que luego tendrá que copiar al almacen de tu zona de servlets. Si estas usando la zona de servlets de ejemplo, deberías copiar el fichero de la clase compilada a /usr/local/src/ApacheJServ-1.0b5/example. Para ejecutar SnoopServlet, entra su URL en tu navegador: http://dominio:puerto/example/SnoopServlet Donde dominio es el nombre de tu dominio y puerto es el puerto por el que se accede a tu servidor web (usualmente es el 80). La forma general de acceder a un servlet es protocolo://host:puerto/zona/nombre Donde protocolo es usualmente http, host es la dirección IP o el nombre de tu servidor, puerto es el puerto para conectar al servidor, zona es el punto de montaje de una zona de servlets, y nombre es el nombre completo del servlet o un alias en la zona especificada. Un error común entre los que empiezan es intentar acceder a un servlet a través del AJP. AJP es sólo para comunicación interna entre el servidor web y Apache JServ, nunca se usa para acceder al servidor web. Así, no pruebes un URL como ajpv11://tudominio:8007/example/SnoopServlet, ya que no funcionará. Accede siempre a tus servlets usando un protocolo estándar como HTTP. Los servlets cuyas clases estan en un package se acceden a través de su nombre completo de clase. Por ejemplo, si añades un servlet llamado FooServlet en el paquete com.dominio.foo a una zona de servlets cuyo punto de montaje es /servlets, entonces deberías acceder a ese servlet mediante la URL http://dominio.com/servlets/com.dominio.foo.FooServlet Puedes ocultar el nombre del servlet y el paquete en la URL definiendo un alias para tu servlet. Esta definición del alias dentro de un almacén de servlets se hace mediante la propiedad servlet.name.code, donde name es el alias que quieres assiganr a tu servlet. Por ejemplo, para definir un alias foo para la clase com.dominio.foo.FooServlet, tienes que añadir la siguiente propiedad al fichero de propiedades de la zona: servlet.foo.code=com.dominio.foo.FooServlet Y para acceder al servlet hay que usar el URL http://dominio.com/servlets/foo Algunos servlets pueden necesitar información adicional, que se les pasa en el momento del arranque. Se puede pasar cualquier numero de argumentos a un servlet usando las propiedades initArgs en el fichero de propiedades de la zona, y se puede acceder a los argumentos usando el método getInitParameter de javax.servlet.ServletConfig. Por ejemplo, para pasar argumentos de inicialización a FooServlet, servlet.foo.initArgs=name=This is foo servlet servlet.foo.initArgs=purpose=Nothing in particular El formato de esta directiva es servlet.nombre.initArgs, donde nombre puede ser o bien un alias de un servlet o bien el nombre completo de la clase del servlet. Si tienes demasiados argumentos de inicialización para un servlet, quizás querrás guardarlos en un fichero separado. Esto puedes hacerlo omitiendo cualquier directiva initArgs en el fichero de propiedades de la zona y proporcionando, en cambio, un fichero <nombre>.initArgs en el mismo directorio que contiene la clase del servlet. La propiedad especial servlets.default.initArgs permite definir argumentos de inicialización que se pasan a todos los servlets. Por ejemplo, le puedes pasar la dirección e-mail de tu webmaster a todos tus servlets, de manera que incluyan la dirección en los mensajes de error generados por ellos. Normalmente, los serlvets son cargados en la memoria la primera vez que son llamados, de manera que si nadie llama nunca (accede) a un servlet, éste nunca será cargado en la memoria. Sin embargo, podrías querer que determinados servlets se ejecutaran cuando el servidor web (o la JVM) se arrancara. Para esto se usa la directiva servlets.startup, a la que se le proporciona una lista de servlets que seran ejecutados cuando la JVM se arranque. Se pueden añadir servlets a la lista s tienes servlets que hagan procesos en backgroundm, o servlets que tardan algunos segundos en arrancar y no quieres que tus usuarios tengan que esperar un retraso mínimamente notable.
Rutas (path) y rellamada de clasesLa ruta de clases es donde la JVM busca las definiciones de clases. La ruta de clases en Apache JServ se divide en una ruta de clases de sistema y en un conjunto de rutas de clases de zonas de servlets. La ruta de clases de sistema está compartida entre todos los servlets, mientras que la ruta de clases de las zonas de servlets es accesible sólo desde cada zona. La ruta de clases de sistema se define de dos maneras: de modo automática, usando la directiva wrapper.classpath en el fichero de propiedades del motor, o de modo manual, donde es cualquier cosa que se le pase al runtime de Java mediante la variable de entorno CLASSPATH o la opcion -classpath. Cada zona de servlets tiene asignado su propio cargador de clases. Éste es responsable de cargar las definiciones de clase desde los almacenes a la JVM y de detectar modificaciones en los almacenes de clases. Así, si tenemos dos zonas, A y B, y cada una de ellas usa la clase C del almacén R, entonces tendremos dos copias de la clase C, cada una de las cuales es inaccesible a la otra. De la misma manera, cualquier objeto que sea una instancia de la clase C será inaccesible a otras zonas. No importa que el almacén sea el mismo fichero o el mismo directorio, ya que cada uno tiene se cargador separado. Una característica útil para desarrollar servlets es la habilidad para rellamar clases automáticamente cuando se modifican. Apache JServ recargará las clases si un almacen que contiene una de ellas ha sido modificado, y una zona de servlets también será recargada si su fichero de propiedades se modifica; esto permite instalar y probar nuevas versiones de servlets sin tener que rearrancar el servidor. Las clases de la lista de una zona de servlets sólo son accesibles a esa zona. Además, sólo las clases cargadas desde un almacén de zona están sujetas a recarga automática si el almacén de zona o el fichero de propiedades cambian. Esto permite poner las clases más usadas y/o las más estables en la ruta de clase del sistema, dando así acceso a clases compartidas y mejorando el rendimiento en general. Por ejemplo, las clases del JDK y del JSDK deberían ponerse en la ruta de clase del sistema (CLASSPATH,-classpath). Así, una libreria estable y comunmente usada, como un driver JDBC, podría ponerse en la ruta de clases del sistema. La rellamada automática de clases reduce el rendimiento porque se debe comprobar cada almacén en cada una de las ejecuciones de un servlet. La rellamada está activada por defecto, pero se puede desactivar para una zona particular poniendo la propiedad autoreload en el fichero de propiedades de la zona como falsa (false). Esto puede conducir a una mejora significativa del rendimiento, a costa de un ciclo de desarrollo más pesado, ya que se requeriría entonces rearrancar el servidor cada vez que se modifica una classe. Otro problema de rendimiento de la rellamada de clases es que incluso un pequeño cambio en una clase forzará a una recarga de toda la zona. Esto no suele ser un problema si solo hay unas pocas clases, pero puede ser un problema de rendimiento significativo si hay varios almacenes grandes. Esto se puede esquivar moviendo los almacenes grandes a la ruta de clases del sistema; aunque se perderán los beneficios de la rellamada automática de clases para estos almacenes, se ganará la ventaja un cicle de actualización y pruebas más rápido en las clases con las que se trabaja. Cuando una zona de servlets se recarga, todos los objetos creados en la zona son destruidos. Con la recarga automàtica activada, incluso el más pequeño cambio en el fichero de propiedades de zona o de uno de los almacenes en una zona causarán la recarga de esa zona, lo que puede ser un problema si se mantienen los estados entre las ejecuciones de un servlet. Por ejemplo, si se mantiene una sesión de un usuario en memoria, se perderá cuando la zona sea recargada. En este caso, la recarga automática no es más que un caso especial del problema, más general, de mantener un estado persistente en un servlet. La mejor solución para mentener los datos de una sesión es proporcionar un mecanismo persistente: antes que Apache JServ destruya una zona de servlets, llama al método destroy() de cada servlet. Los servlets pueden, entonces, guardar los datos en un almacén persistente, como un fichero o una base de datos. Cuando los servlets son rellamados, sus métodos init() pueden leer la información guardada de la sesión. También se pueden guardar las sesiones siempre que se actualizen, previniendo así pérdidas de datos debidas a errores inesperados (e imprevisibiles, muchas veces: Caída de la JVM, fallos de tensión, etc.) El acceso a métodos implementados via Java Native Interface (JNI) debe ser provisto por las clases a través del cargador de clases de sistema en la ruta de clases de sistema. Esto es una limitación impuesta por la manera en que los cargadores de clases de Java están implementados, que sólo permiten al llamador de clases del sistema cargar métodos JNI. Dicho de otra manera, no se puede acceder a métodos JNI en clases llamadas a través de la ruta de clases de una zona de servlets, pero se pueden listar esas clases en la ruta de clase del sistema...
Añadir zonas de servletsApache JServ ejecuta todos los servlets en zonas de servlets, y puede ser configrado con una o más zonas de servlets. A cada zona se le asigna un único punto de montaje y un nombre. El punto de montaje corresponde a una prefijo URL único, de manera que todos los URL que empiezen por ese prefijo (por ese punto de montaje) serán manejados por un servlet de la zona especificada. Por ejemplo, la instalación por defecto incluye una sola zona llamada example, los URL cuyo path empiece con /example seran manejados por el servlet de la zona example. El disponer de múltiples zonas de servlets proporciona diversas ventajas: las zonas permitan separar servlets por criteros de seguridad, para ejecutar múltiples JVMs, para soporte de de múltiples hosts virtuales, etc. Cada zona de servlets requiere una directiva ApJServMount en el fichero httpd.conf de Apache, una entrada en el fichero de propiedades del motor (compartido) y un fichero de propiedades propio de la zona. La directiva ApJServMount indica a mod_jserv cómo mapear URLs a zonas de servlets. La sintaxis de la directiva es ApJServMount ruta protocolo://host:puerto/zona Donde ruta es la parte principal del URL que se mapea a la zona, protocolo el protocolo de comunicación interno AJP, host es la direción IP o el nombre del host en el que se ejecuta la JVM, puerto es el puerto por el que se comunicará internamente con Apache JServ, y zona es el nombre de una zona de servlets. Ruta y zona són obligatorios. Si se omite protocolo, se entenderá por defecto el valor de la directiva ApJServDefaultProtocol o ajpv11 en Apache JServv1.0. Si se omite host, se entenderá por defecto el valor de la directiva ApJServDefaultHost o el localhost de defecto. Y si se omite puerto, se entenderá por defecto el valor de la directiva ApJServDefaultPort o bien 8007. Por ejemplo, para mapear peticiones de la ruta /dev/servlets a la zona devservlets en la máquina local, se podría usar la directiva ApJServMount /dev/servlets /devservlets Las peticiones a cualquier URL que empieze por /dev/servlets serán manejadas por los servlets de la zona devservlets. En el fichero de propiedades del motor, habrá que añadir una entrada para la zona listandola en la propiedad zones y proporcionando la ruta al fichero de propiedades de la zona. Por ejemplo, zones=devservlets devservlets.properties=/usr/local/apache/conf/devservlets.pro perties El fichero de propiedades para la zona devservlets debe contener como mínimo una entrada repositories especificando un almacén del cual se llamarán los servlets, por ejemplo: repositories=/usr/local/apache/devservlets En este ejemplo, el almacén es un directorio en el cual se pueden poner servlets. Por supesto, hay que crear el diretorio: mkdir /usr/local/apache/devservlets Una vez se haya finalizado la configuración de la zona, hay que rearrancar el servidor web. Para el ejemplo superior, se puede usar una URL como http://tudominio/dev/servlets/MiServlet?address=foo@bar.com que ejecutará el servlet MiServlet en la zona devservlets.
Mapeo de URLsHay un par de maneras de mapear URLs, además de las zonas de servlets y los alias. El módulo mod_jserv puede mapear ficheros que acaben en un sufijo particular a un servlet de manera que, cuando el servlet se ejecuta, la ruta al fichero se pasa como información extra al servlet. La otra manera us usar el muy flexible módulo mod_rewrite, que se proporciona con Apache. La directiva ApJServAction el servlet que se ejecutará para ficheros que acaben en un sufijo determinado. La ruta al fichero solicitado se pasa al servlet, y éste puede acceder a ella mediante los métodos getPathInfo o getPathTranslated de javax.servlet.HttpServletRequest. Por ejemplo, el proyecto Java Apache proporciona el servlet Apache JSSI, que incluye la salida de otro servlet en un fichero HTML. Para mapear ficheros acabados en el sufijo .jhtml al servlet Apache JSSI, hay que añadir una línea como la siguiente en el fichero httpd.conf: ApJServAction .jhtml /servlets/org.apache.servlet.ssi.SSI Después de un rearranque del servidor, y asumiendo que el servlet Apache JSSI está instalado, cualquier fichero acabado en .jhtml será analizado por dicho servlet. Hay veces en que no se quiere que los usuarios vean una ruta como /dev/servlets/MiServlet al acceder al sitio. Alternativamente, también podría interesar 'envolver' ficheros existentes en un servlet para proporcionar autenticación o contenido dinámico. Apache incluye un módulo muy flexible, llamado mod_rewrite, que se puede usar para modificar URL de casi cualquier manera que pueda ocurrirse. Usar mod_rewrite con mod_jserv es como usar mod_rewrite con cualquier otor módulo o URL. Para los detalles, se debería consultar documentación y ejemplos proporcionados por el autor del módulo, Ralf S. Engelschall, que están incluidos en la distribución de Apache. Lo único importante que hay que recorder es que la directiva AddModule de mod_jserv debe estar antes de la directiva AddModule de mod_rewrite. Por ejemplo, en httpd.conf, ClearModuleList ... AddModule mod_jserv.c AddModule mod_rewrite.c Esto es así porque los módulos se ejecutan en la dirección inversa en que se especifican con la directiva AddModule, y mod_rewrite debe ejecutarse antes de mod_jserv. El resto de esta sección incluye algunos consejos simples para usar mod_rewrite con mod_jserv. El ejemplo siguiente reescribe cualquier URL que empiece por /auth con /servlets/AuthServlet. La opción [PT] indica a mod_rewrite que debe pasar la URL reescrite para procesos posteriores en Apache. <IfModule mod_rewrite.c> RewriteEngine on RewriteRule ^/auth(.*) /servlets/AuthServlet$1 [PT] </IfModule> Se puede decidir añadir contenido dinámico a una páginas estáticas añadiendo, por ejemplo, el servlet Apache JSSI, que proporciona funcionalidades de server-side include a los servlets Java. Asumiremos que se a añadido previamente una directiva ApJServAction de manera que los ficheros cuyo sufijo sea .jhtml iran a través del servlet Apache JSSI. Si se quiere obtener algún beneficio de esta nueva funcionalidad en los ficheros existentes, pero éstos no se pueden renombrar sin romper URLs ya existentes, y no se quiere mantener una lista de todos los mapeos de ficheros .html existentes a .jhtml, se puede usar la directiva RewriteMap de mod_rewrite y un pequeño programa en Perl para solucionar el problema: <IfModule mod_rewrite.c>
RewriteEngine on
RewriteMap suffixmap prg:/usr/local/apache/conf/suffixmap
RewriteRule ^(.*)\\.html% $1.${suffixmap:$1|html}
</IfModule>
Este ejemplo pasa cualquier URL acabado en .html al programa /usr/local/bin/suffixmap. El programa de mapeo de sufijos devuelve un nuevo sufjio o bien un string NULL para usar el sufijo por defecto. El código fuente del programa de mapeo de sufijos es: #!/usr/bin/perl
# Usado para el mapeo de urls con mod_rewrite
$| = 1;
$root = "/usr/local/apache/htdocs";
@suffixes = ("jhtml");
MATCH:
while (<>) {
chop;
$file = $root . $_;
foreach $suffix (@suffixes) {
if (-f "$file.$suffix") {
print "$suffix\\n";
next MATCH;
}
}
print "NULL\\n";
}
Este script concatena el directorio raiz de documentos del servidor con la URL proporcionada, y luego comprueba la existencia de un fichero con uno de los sufijos buscados (se pueden añadir fácilmente sufijos adicionales). Si se encuentra una coincidencia, el script devuelve el sufijo de la coincidencia a mod_rewrite escribiendo en la salida estandar, y si no escribe NULL para indicar ue el sufijo por defecto es el que debe usarse. Esta solución no es la aproximación más eficiente, dado que requiere una búsqueda en todos y cada uno de los URLS que acaben en .html. Sería mejor generar manual o automáticamente un texto o un fichero DBM que mapeara URL específicos. Sin embargo, el script anterior es conveniente para usarlo durante el desarrollo y demuestra algunas de las capacidades y flexibilidad de mod_rewrite.
Hosts virtualesLos hosts virtuales son una acertada manera de hacer que un sólo servidor web pueda manejar peticiones para múltiples dominios. Cada host virtual puede tener configuraciones separadas de Apache JServ, mientras diferentes directivas compartidas pueden situarse fuera de la configuración de cualquier host virtual. Las directivas compartidas incluyen las directivas para las propiedades y los ficheros de log (registro) y la URL de estado. Otras directivas, como los puntos de montaje de los servlets y las zonas, se pueden especificar separadamente para cada host virtual. El ejemplo siguiente muestra una configuración de muestra para dos hosts virtuales, llamados vhost1 and vhost2. # directivas compartidas LoadModule jserv_module libexec/mod_jserv.so <IfModule mod_jserv.c> ApJServProperties /usr/local/apache/conf/jserv.properties ApJServLogFile /usr/local/apache/logs/mod_jserv_log ApJServSecretKey DISABLED <Location /status/jserv/> SetHandler jserv-status order deny,allow deny from all allow from localhost </Location> </IfModule> NameVirtualHost 192.168.1.1 # directivas para vhost1 <VirtualHost 192.168.1.1> ServerName vhost1.com DocumentRoot /usr/local/hosts/vhost1/htdocs <Directory /usr/local/hosts/vhost1/htdocs> order allow,deny allow from all </Directory> <IfModule mod_jserv.c> ApJServDefaultHost vhost1.com ApJServMount /servlets ajpv11://vhost1.com/vhost1 </IfModule> </VirtualHost> # directivas para vhost2 <VirtualHost 192.168.1.1> ServerName vhost2.com DocumentRoot /usr/local/hosts/vhost2/htdocs <Directory /usr/local/hosts/vhost2/htdocs> order allow,deny allow from all </Directory> <IfModule mod_jserv.c> ApJServDefaultHost vhost2.com ApJServMount /servlets ajpv11://vhost2.com/vhost2 </IfModule> </VirtualHost> Para este ejempo se ha usado una dirección IP sin sentido en la red. La directiva ApJServDefaultHost se necesita porque ambos hosts virtuales comparten la misma direccion IP, y permita a Apache JServ dirigir cada petición a la zona de servlets correcta. Se necesitará crear los directorios htdocs para cada host virtual, y también los directorios donde almacenar los servlets: mkdir -p /usr/local/hosts/vhost1/htdocs mkdir -p /usr/local/hosts/vhost2/htdocs mkdir -p /usr/local/hosts/vhost1/servlets mkdir -p /usr/local/hosts/vhost2/servlets El fichero de propiedades del motor debería contener propiedades tanto para vhost1 como para vhost2 y permitir el acceso desde la dirección IP del host virtual: wrapper.bin=/usr/local/java/jdk/bin/java wrapper.class=org.apache.jserv.JServ wrapper.classpath=/usr/local/jserv/lib/ApacheJServ.jar wrapper.classpath=/usr/local/java/jsdk/lib/jsdk.jar port=8007 security.allowedAddresses=192.168.1.1 security.authentication=false zones=vhost1,vhost2 vhost1.properties=/usr/local/apache/conf/vhost1.properties vhost2.properties=/usr/local/apache/conf/vhost2.properties Cada zona necesita también el correspondiente fichero de propiedades de la zona, vhost1.properties and vhost2.properties, que son como cualquier otro fichero de propiedades de zona. El fichero vhost1.properties podria ser como lo que sigue: repositories=/usr/local/hosts/vhost1/servlets Se pueden añadir almacenes e indicaciones como para cualquier otra zona de servlets. Y se tiene que crear un fichero similar para vhost2. A partir de la configuración anterior, peticiones de URLs como http://vhost1.com/servlets/... serán manejadas por la zona de servlets vhost1, mientras peticiones de URLs como http://vhost2.com/servlets/... lo serán por la zona de servlets vhost2. Con la directiva ApJServMountCopy se pueden hacer zonas de servlets compartidas, accesibles por cada host virtual. Se puede usar esta directiva para proporcionar un conjunto común de servlets básicos para cada host virtual. Permitiendo la copia del montaje, las zonas definidas fuera de cualquier sección del host virtual son automáticamente accesibles para cada host virtual. Si las siguientes directivas se añaden a la parte compartida de la configuración de ejemplo del host virtual, entonces tanto vhost1 como vhost2 tendrán acceso a la zona /share. ApJServMountCopy on ApJServMount /share/servlets /share También se necesitará añadir un fichero de propiedades de zona y una entrada en el fichero de propiedades del motor para la zona de servlets compartida (sólo hay que seguir el mismo procedimiento que para cualquier otra zona de servlets). Así, dado un servlet MailServlet en la zona share, URLs como http://vhost1.com/share/servlets/MailServlet y http://vhost2.com/share/servlets/MailServlet ejecutarían la misma instancia de MailServlet.
Ejecutar Apache JServApache JServ se puede usar de dos modos, automático y manual. El modo automático es el mas conveniente para ejecutarlo, ya que maneja el arranque y parada de la JVM. El modo automático es apropiado para instalaciones básicas que utilizan una única JVM. En el modo manual, se debe lanzar la JVM usando un programa externo, como un shell script o un fichero batch. El modo manual da un trabajo extra de configuración, pero permite utilizar cualquier número de JVMs para, por ejemplo, proporcionar aislamiento entre cliente o para dar equilibrar el balance de la carga o la tolerancia a errores. En el modo automático, el módulo mod_jserv lanza automáticamente la JVM. El módulo tambien monitoriza la JVM y la relanza si ésta finaliza inesperadamente. Cuando el servidor Apache se rearranca o se para, el módulo rearranca o para la JVM. Todo lo que se necesita para configurar el modo automática es usar el valor "off" en la directiva ApJServManual en httpd.conf y configurar adecuadamente las propiedades wrapper en el fichero de propiedades del motor. El modo manual se requiere, en cambio, si se quiere hacer uso de más de una JVM, por ejemplo, un ISP que proporciona hosting virtual a sus clientes querrá proporcionar a cada cliente una JVM propia para asegurarse que los datos y ejecutables de cada uno de ellos se separan de los del resto. En sitios con alto tráfico también se pueden usar las características de balance de carga añadidads en Apache JServ 1.0b5. En el modo manual hay que lanzar la JVM. Esto se puede hacer directamente desde la línea de comandos, usando un shell script o un batch script, desde un script ejecutado en el arranque del servidor, etc. A continuación hay un ejemplo de un shell script de Unix que se puede usar para lanzar Apache JServ en modo manual (antes de usar el script, habrá que ajustar las rutas (paths) para las localizaciones de los ficheros en el propio sistema). Shell script de Unix para lanzar Apache JServ en modo manual #!/bin/sh properties=/usr/local/apache/conf/jserv.properties log=/usr/local/apache/logs/jserv_manual.log CLASSPATH=$CLASSPATH:/usr/local/jsdk/lib/jsdk.jar CLASSPATH=$CLASSPATH:/usr/local/jserv/lib/ApacheJServ.jar java org.apache.jserv.JServ $properties $1 2>> $log Cuando se ejecuta en modo manual, el error estándar y la salida estándar de la JVM (System.err and System.out) van, por defecto, al dispositivo de salida regular, normalmente la ventana de terminal local. Se puede redireccionar la salida (ambas) a un fichero de log, de manera que el terminal no se llene de los datos de salida y además se podrá guardar para futuras referencias. Uno de los defectos del modo manual es que no hay una monitorización de la JVM establecida. Si la JVM falla, hay que rearrancarla manualmente. Un paquete de monitorización externo, como mon http://www.kernel.org/software/mon/, es entonces una necesidad para cualquier site que use modo manual Otro de los defectos del modo manual es que no se notifica a la JVM el rearranaque o parada del servidor web. Como regla, nunca se debería terminar un proceso Apache JServ usando el comano kill de Unix o el gestor de tareas de Windows NT. Cerrar una JVM de esta manera no permita una destrucción limpia de todos los servlets, para rearrancar o terminar limpiamente Apache JServ se debe usar la opción apropiada para Apache JServ, o sea: -v print server version -V print server version and details -r restart server -s stop server Por ejempo, si el shell script de Unix anterior se grabara en un fichero llamado jserv, entonces se podría rearrancar el servidor usando el comando jserv -r
Múltiples JVMsApache JServ permite tener cualquier número de JVMs. Esto puede usarse para dar soporte a seguridad mejorada, balance de carga, y tolerancia a los errores. La parte negativa es que cada JVM puede requerir recursos de memoria y procesdor significativos, lo que puede ser un factor a tener en cuenta a la hora de decidir cuantas JVMs permitir o qué hardware comprar. El lado Java de Apache JServ escucha en un puerto específico las peticiones del servidor web. Si se ejecutan diversas copias (instancias) de Apache JServ en el mismo host virtual hay que asignar a cada instancia un número de puerto diferente. El puerto se especifica en el fichero de propiedades del motor, de manera que cada instancia requiere también un fichero de propiedades del motor separado. Estos ficheros pueden ser idénticos entre ellos, excepto en el número de puerto, o bien pueden ser completamente diferentes, ya que cada JVM es independiente de las otras. Para ejecutar múltiples JVMs se neceista ejecutar Apache JServ en modo manual. La sección previa explica las diferencias entre el modo manual y el automático y muestra cómo lanzar una JVM en modo manual. La configuración de ejemplo siguiente muestra cómo configurar Apache JServ para usar diferentes JVMs para cada zona de servlets. <IfModule mod_jserv.c> ApJServManual on ApJServMount /servlets1 ajpv11://localhost:9001/jvm1 ApJServMount /servlets2 ajpv11://localhost:9002/jvm2 ApJServLogFile /usr/local/apache/logs/mod_jserv.log <Location /status/jserv/> SetHandler jserv-status order d |