Glassfish v2 en producción

07:41PM sep 27, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

La semana pasada salió la versión final de glassfish v2, y aprovechando la ocasión decidí instalarlo para un nuevo proyecto que he comenzado en NHT-Norwick y que cuenta con varios servicios Web.

La integración netbeans 6 / glassfish es perfecta (no podía ser de otra forma) y desarrollar servicios web con JavaEE5 es de lo más sencillo

El único problema que tuve fue con la instalación del enlace mod_jk para glassfish, que obliga a introducir commons-logging dentro de las librerías del servidor y esto produjo conflictos con el log4j de mi aplicación. La solución fue mover log4j a las librerías del servidor para que lo cargase el mismo ClassLoader que commons-logging. La verdad es que había olvidado este tipo de problemas con los ClassLoaders desde que abandonamos el desarrollo de aplicaciones con EJB1.x y 2.x sobre JBoss, esperemos que solo fuese un susto ;-)

Por lo demás, sigo notando un poco lenta la interfaz de administración, pero me encuentro bastante cómodo con la interfaz de comandos, asadmin, así que posiblemente solo la use puntualmente para visualizar las estadísticas de los servicios Web. 

Resumen pesca TV

03:48AM jun 15, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

Casí un mes como blogger oficial de Glassfish en Español, veremos si da algún fruto, aunque tal y como viene de semana, con el más que probable descenso de la Real Sociedad, lo veo difícil.

A principios de semana me comunicaron que el concurso solo aceptaba el ingles como lenguajes, así que me he pasado la semana jugando con los traductores y viendo que saben algo más de ingles que yo, pero creo que tampoco saben suficiente.

 En definitiva el resumen queda con:

 Muchos sitios se han hecho echo de mis post, destaco

Gracias a todos por los ánimos, a Sun Microsystem por la idea del premio y a los desarrolladores de glassfish por su gran trabajo.

 

Fish TV Summary  

 

Glassfish Clustering

02:55AM jun 15, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

Solo me queda por ver el soporte de clustering para glassfish, punto destacado de la versión V2, y que puede ser otra de las funcionalidades que ayude a que glassfish se introduzca en el mercado.

Del soporte de clustering, lo primero que destaco es, la sencillez de la administración y las excelentes referencias que he encontrado que han hecho cuestionarme si este post era necesario. En los dos puntos se nota que hay una gran empresa detrás de glassfish y que aunque glassfish es open source, no ha perdido estos detalles respecto a sus antecesores Sun App Servers.

Ya explique en el primer post de la serie que glassfish podía contar con múltiples configuraciones llamadas dominios. Además de los dominos glassfish se puede instalar con 3 perfiles distintos: developer, enterprise y cluster. Haciendo un breve resumen, la versión developer es una única instancia que contiene la consola de administración y nuestras aplicadiones. La versión enterprise, cuenta con una instancia de administración, llamada DAS (Domain Administration Server) que permite administrar el resto de instancias del dominio (parar, arrancar, desplegar aplicaciones, etc). Por ultimo la versión cluster permite crear cluster de glassfish.

Por defecto y en el bundle de Netbeans se instala la versión developer, así que el primer paso es cambiar añadir el soporte de cluster, podeis ver como se realiza esta operación en el siguiente screencast.

El siguiente paso será crear un cluster en glassfish, esto consiste en configurar varios nodos que alberguen nuestras aplicaciones. Se ve perfectamente en este screencast Estos nodos pueden estar en una misma máquina y distintos puertos o en distintas máquinas. En cualquier caso a través de la consola de administración administraremos el cluster como si de una única instancia se tratase, aquí se explica perfectamente .Como se ve al final del screencast, desplegar una aplicación es exactamente igual que hacerlo en una instancia única.

Para que el cluster tenga sentido debemos poner delante de el un balanceador de carga, que puede ser hardware (muy caro) o un servidor web Apache o Sun. Daros cuenta que las funcionalidades de un cluster consisten en replicar la sesión de un nodo a otro de tal forma que si el balanceador de carga me redirigía al nodo A o B, tengo que encontrar mis datos de la sesión en los dos nodos y mejor aún, si el nodo A falla, el balanceador me redirigira al nodo B donde estarán mis datos replicados. Podemos ver un pequeño auto cuestionario / FAQ que Nazrul a preparado para ver las dudas de otros administradores

Aunque bajo un ejemplo sencillo todo es ideal, crear un cluster es añadir un nivel de estabilidad, rendimiento y complejidad, por lo que es necesarío valorar pros y contras.
 


Glassfish debug con IntelliJ Idea

02:09AM jun 12, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

El año pasado me hicieron un regalo de lo más interesante, el Russian Development Pack compuesto de:

El Idea me impresiono, ya tenia muy buenas referencias por parte de Roberto, pero ver lo tremendamente eficaz que es, sobre todo si ya llevas algunos años programando en Java, solo se puede explicar se lo utilizas durante un mes.

He utilizado Netbeans desde antes de que lo comprará Sun y lo llamase Forte for Java , los avances han sido increíbles, sobre todo los últimos años, pero sinceramente, aun le queda camino para tener la estabilidad del Idea, tanto camino como los 150€ que cuesta (promoción con javahispano finales de 2006). Y ciertamente, son 150€, pero creo también que deberíamos de ser los informáticos los primeros en reconocer y apreciar cuanto esfuerzo y calidad hay detrás de esa "ridícula" cifra.

Para mi el debugger del Idea vale el doble de esa cantidad porque sencillamente funciona, y como no podía ser de otra forma, con Glassfish también funciona, aunque en este caso, solo lo hace conectandose en remoto. Esto supone la pega de tener que arrancar el servidor a través de sus scripts de forma externa al IDE.

El primer paso es configurar Glassfish para que arranque en modo debug, para ello con Glassfish arrancado y desde la consola de administración, marcamos la opción debug en las opciones del la JVM

Activar debug mode en Glassfish

Al hacer este cambio el servidor nos pide reiniciar por lo que ejecutamos:

asadmin stop-domain domain1
asadmin start-domain domain1 

Al iniciarse Glassfish debemos ver en la consola el siguiente mensajes

Listening for transport dt_socket at address: 9009
Application server is listening at address 9009 for debugger
to attach using transport dt_socket 

A partir de este instante podemos conectarnos remotamente con un Debugger JPDA, en nuestro caso el del Idea. No voy a entrar en detalles de como crear un proyecto web en el entorno, pero si como ejecutar el proyecto en glassfish. Para ello, en la configuración de ejecución del proyecto añadimos una nueva configuración de servidor Glassfish Remoto

Añadir configuración glassfish remoto en Idea

El siguiente paso es configurar el servidor Glassfish, para lo cual debemos seleccionar el directorio de instalación y añadir los .jar  que tengan las clases que vayamos a utilizar. Una vez hecho esto podemos dar un nombre al servidor y rellenar los datos de configuración del mismo (Puertos y claves de acceso)

Configuración glassfish en Idea Configuración glassfish en Idea, asignación de nombre, puertos y claves

Por utlimo configuramos el puerto de debug al que se conectará el idea, en nuestro caso el 9009

Configuración en Idea del puerto de debug de glassfish remoto

Con estos pasos bastan para tracear las aplicaciones desplegadas en Glassfish y como podeis ver hacer uso de toda la potencia del debugger del Idea.

Idea Debugger en glassfish

Virtual Servers with Glassfish and/or Apache 

Comet en Glassfish/Grizzly con Ajax o iframe

04:40AM jun 11, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

La verdad es que el ejemplo de Jean-Francois me parecía demasiado complejo y me quede algo extrañado por el uso de un iframe como cliente del Comet... con todo lo que se habla de AJAX y las posibilidades de Comet, me parecía raro que "volvieramos" a usarlo.

La verdad, es que se nota bastante que esto del Comet es muy nuevo y no hay mucha información en internet, pero he podido encontrar cosas interesantes y razones por las cuales usar iframes o AJAX como cliente de Comet. Tengo que advertir, que si por algo no me destaco es por mis capacidades con javascript, pero conozco un poco y me han hablado bien siempre de Prototype, así que el objetivo era que el cliente AJAX fuera realizado con este framework. Empezemos:

Ya vimos lo sencilla que era la implementación de Comet en Grizzly, pero repito explicación sobre mi ejemplo que tiene menos funcionalidades.

1.- Registramos el comet bajo un nombre. Puede coincidir con una URL para dar sentido a las operaciones pero no es algo obligatorio. Esta operación se debe realizar antes que ninguna otra, por lo que su ubicación natural es el método init de un Servlet. Si además configurames el servlet para que se inicie al arrancar nuestra aplicación con la etiqueta <load-on-startup>0</load-on-startup> nos evitaremos problemas.

public void init (ServletConfig config) throws ServletException
{
super.init(config);
//comet = servlet context path pero no es obligatorio
contextPath = config.getServletContext()
.getContextPath() + "/subscription";
CometEngine cometEngine = CometEngine.getEngine();
context = cometEngine.register(contextPath);
context.setExpirationDelay(40 * 1000); //segundos de delay
}

2.-El Servlet solo va a realizar dos operaciones registrar al cliente en el Comet y enviar notificaciones a todos los clientes conectado. Para enviar la notificación se debe enviar el parametro notificar al Servlet. Para garantizar que un cliente no intenta conectarse dos veces, se crea una variable de sesión, conectado, que se comprueba que no exista antes de conectarse.

protected void doPost(HttpServletRequest request, 
HttpServletResponse response)
throws ServletException, IOException {
if (request.getParameter("notificar")==null
&& request.getSession().getAttribute("conectado")==null)
{//conecto el cliente al comet
response.setContentType("text/html");//muy importante
EjemploCometHandler handler = new EjemploCometHandler();
andler.attach(response.getWriter());
int handlerId = context.addCometHandler(handler);
request.getSession().setAttribute("conectado",
Integer.valueOf(handlerId));
response.getWriter().print("Conectado al Commet
");
response.getWriter().flush();
//no cerramos la conexion.. que de eso se trata
}else if (request.getParameter("notificar")!=null){
context.notify("Envio a todos los usuarios conectados al comet
");
}
return;
}

 

3.- El CometHandler implementado para el ejemplo se limita a enviar los mensajes de notificación y a informar de la desconexión

public class EjemploCometHandler implements CometHandler {

private PrintWriter printWriter=null;

public void attach(PrintWriter printWriter) {
this.printWriter = printWriter;
}

public void onEvent(CometEvent event) throws IOException {
printWriter.println(event.attachment());
printWriter.flush();
}

public void onInitialize(CometEvent event) throws IOException {
printWriter.println("onInitialize");
printWriter.flush();
}

public void onTerminate(CometEvent event) throws IOException {
printWriter.println("onTerminate");
printWriter.flush();
printWriter.close();
}

public void onInterrupt(CometEvent event) throws IOException {
printWriter.println("onInterrup");
printWriter.flush();
printWriter.close();
}
}

 

Con esto ya tenemos desarrollada la parte del servidor, ahora vamos al cliente. Como decía al principio hay dos posibilidades AJAX o iframe. Todo apunta a que la mejor opción es la del iFrame, por varias razones:

  1. Un navegador solo puede abrir dos conexiones HTTP desde una página/frame, por lo que si mantenemos una abierta para el Comet, solo nos queda una libre para realizar llamadas.
  2. El iframe funciona en todos los navegadores mientras que AJAX en InternetExplorer parece tener problemas con Comet, ya que en este navegador AJAX no es consciente de la información que va llegando hasta que se cierra la conexión :-(

Veamos el código del ejemplo del cliente con el iframe, por un lado tenemos el iframe que se conecta al comet. El boton realiza un llamada Ajax que actualiza el iframe de la misma página y la de todos los clientes conectados:

<html>
  <head><title>Ejemplo Comet iFrame</title>
      <script src="prototype.js" type="text/javascript"></script>
  </head>
  <body>
  <iframe src="subscription" name="comet" width="100%"></iframe>
  <script type="text/javascript" language="javascript">
    // <![CDATA[
    function notificarComet(){
        var url = 'subscription';
        new Ajax.Request( url, {
          method: 'get',
          parameters: 'notificar=true'
        });
    }
    // ]]>
  </script> 
  <input type="button" name="a" value="notificar"
onclick="notificarComet();"/>
  </body>
</html>

 

La única forma que he encontrado para hacer los mismo con Prototype y sabiendo que solo funciona en firefox es la siguente, tras hacer la petición y conectar al Comet, es necesario introducir el cliente en un bucle que vaya comprobando si se ha enviado información desde el Comet:

<html>
  <head><title>Ejemplo Comet Ajax</title>
  <script src="prototype.js" type="text/javascript"></script>
  <script type="text/javascript" language="javascript">
    // <![CDATA[
      function comet(){
        var url = 'subscription';
        var listener=null;
        new Ajax.Request(
          url,
          { onInteractive: function(xhr){
                if (!listener){
                  listener=new PeriodicalExecuter(
                    function(){
                       $('update').update(xhr.responseText);
                    },
                    1 /* check for changes every 1 second*/
                  );
                }
            }
          }
        );
      }

       function notificarComet(){
        var url = 'subscription';
        new Ajax.Request( url, {
          method: 'get',
          parameters: 'notificar=true&t='+new Date().getTime()
        });
        }
    // ]]>
  </script>
  </head>               
  <body onload="comet();">
  <div id="update"></div>
  <input type="button" name="a" value="notificar"
onclick="notificarComet();"/>
  </body>
</html>

No parece que Prototype se haya preparado para Comet. Sin embargo otro framework javascript muy conocido, Dojo, esta muy integrado con un servidor Comet, www.cometd.org, y con el no hay que recurrir a trucos como en Prototype, ya que cuenta con la operación dojo.io.bind() que me temo habrá que probar en próximos capítulos. Mientras os dejo el ejemplo para que lo probéis.

Comet in Glassfish/Grizzly with Ajax or iframe

Servidores Virtuales con Glassfish y/o Apache

03:09AM jun 08, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

Una de la razones por las que usuaria Glassfish en vez de Tomcat sería la posibilidad de eliminar Apache y conseguir que mis aplicaciones corran completamente sobre la plataforma Java. A día de hoy todas mis aplicaciones usan Apache por la mejora de rendimiento al servir contenido estático y por la configuración de los VirtualHost de cada una de las aplicaciones. Si con Grizzly parece que el rendimiento del servicio HTTP/S de Glassfish parece que no va a ser un problema, veamos si su soporte de Virtual Hosts es suficiente.

Ya veíamos en el ultimo post que a través de la consola de administración podíamos configurar el servicio HTTP. Esta configuración se base en tres apartados:

  1. El propio Servicio HTTP donde podemos configurar:
    • El sistema de logs de acceso a nuestras aplicaciones (rotado e información que se registra)
    • Configuración del tratamiento de peticiones HTTP entrantes (RequestProcessing)
    • Gestión de las conexiones "keep-alive" (configuración de timeouts, y limete de conexiones)
    • Configuración del Pool de conexiones HTTP que están a la espera de recibir peticiones
    • Definición de los valores por devolverá el servidor en las cabeceras HTTP
    • Configuración de la cache de contenido estático para mejorar el rendimiento
  2. Listeners HTTP son sockets (IP+Puerto) que estan a la escucha de peticiones HTTP. Además de esta configuración un listener puede estar asociado a un VirtualServer / VirtualHost por defecto y a varios nombres de máquina. Todos los listeners utilizan la configuración del Servicio HTTP de Glassfish.
  3. Por último los Virtual Servers (Me gusta más el nombre de VirtualHost) son la configuración del direccionamiento de un dominio/host a uno o varios listeners. De esta forma asignamos la dirección de acceso de nuestras aplicaciones a una instancia de Glassfish. Un Virtual Server se puede asociar a una aplicación en concreto, por lo que al escribir el dominio se direccionaría a dicha aplicación montada como ROOT. Es importante destacar que tras cambiar la configuración de un Virtual Server no es necesario reiniciar Glassfish.

Configuración Listener HTTP Glassfish Configuración Virtual Server Glassfish

La verdad es que se pueden realizar las configuraciones básicas, yo diría que esta al mismo nivel del Tomcat pero con una administración más sencilla, pero sigo echando en falta algunas cosas que suelo usar en el Apache como por ejemplo la posibilidad de hacer redirecciones. Para solventar esto en glassfish podemos utilizar URLRewriteFilter, que es muy completo y funciona a las mil maravillas.

En cualquier caso, si las funcionalidades de Glassfish como servidor Web no te parecen suficientes o si bien necesitas Apache por otras razones, Glassfish soporta el protocolo AJP, por lo que puedes configurar el Apache con mod_jk por delante de el.

Para ello debemos seguir los siguientes pasos:

1.- Añadir una propiedad al lanzar la JVM a través de la consola de administración,

Añadir Opción JVM de conector JK en Glassfish

o desde la consola

$GLASSFISH_HOME/bin/asadmin create-jvm-options 
-Dcom.sun.enterprise.web.connector.enableJK=8009

2.- Copiar desde Tomcat 5.5.x a %GLASSFISH%/lib las librerias

  • %TOMCAT%/server/lib/tomcat-ajp.jar
  • %TOMCAT%/server/lib/commons-modeler2.0.jar

3.- Copiar commons-logging.jar a %GLASSFISH%/lib

4.- Opcionalmente, configurar el conector AJP con un fichero de propiedades mediante la variable de la JVM

$GLASSFISH_HOME/bin/asadmin create-jvm-options 
-Dcom.sun.enterprise.web.connector.enableJK.propertyFile=
/path/glassfish/domains/domain1/config/glassfish-jk.properties 

La verdad es que esperaba un paso más por parte de Glassfish en este sentido. Siguen trabajando en ello y para la v2 se ha introducido el soporte de directorios virtuales, pero Apache sigue dando mucha más versatilidad. Veremos si Grizzly ahora independiente de Glassfish tiene también algo que decir.

Virtual Servers with Glassfish and/or Apache

Mi primera aplicacion Comet en Glassfish

01:43AM jun 07, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:

Grizzly es un framework de desarrollo de servidores Java. No vamos a desarrollar un servidor, ni mucho menos, pero vamos a intentar ver las posibilidades que nos ofrece Grizzly dentro de Glassfish.

Gracias a Grizzly nuevos proyectos nacidos recientemente como JRuby o Phobos cuentan con un rendimiento envidiable y una base solida y estable por su extenso uso en Glassfish como conector HTTP. Esta fue la idea inicial con la que nació, dar soporte HTTP al servidor de aplicaciones de Sun, por entonces el Sun Aplication Server 8.1, para que este pudiera funcionar de forma independiente sin servidor Web.

Grizzly, según sus autores, consigue excelentes rendimientos gracias a que usa la "nueva" librería de entrada/salida introducida en la JDK1.4: NIO. Esta librería además aportar facilidades para desarrollar servidores no bloqueantes (asincronos) lo cual puede resultar muy interesante como veremos a continuación.

Además de su rendimiento Grizzly es tremendamente "programable". En el Weblog de Jean-Francois Arcand podéis encontrar muchísima información pero de lo que yo he leído, destaco cosas tan sorprendentes como la capacidad de desarrollar un control de cuotas de ancho de banda o acceder a la capa de conexiones HTTP del servidor para poder realizar cosas tan novedosas como las aplicaciones Comet.

Estas aplicaciones consisten en enviar datos desde el servidor al navegador sin necesidad de que se realicen peticiones por parte del cliente. Para que este envió push sea posible, el servidor debe registrar y mantener una conexión abierta con los usuarios que se subscriben a la información que será enviada. El ejemplo más claro es el de un chat web como el de GMail, donde el envío de un usuario se ve reflejado en la pantalla de todos los usuarios conectados al chat.

El primer paso para realizar una aplicación comet es configurar el listener-http. En la instalación por defecto de Glassfish V2 existen dos listener el http y el https, para el ejemplo hay que añadir la propiedad cometSupport al http-listener-1 con valor true y eliminar la propiedad proxiedProtocols, que parece que no se lleva muy bien con el soporte de Comet. (Lo estoy consultando)

Configuración Listener HTTP ara aplicaciones Comet

Una vez nuestro servidor esta preparado vamos a utilizar un ejemplo de chat desarrollado por Jean-Francoise y comentado en su blog. El servlet de una aplicación comet como el del ejemplo, debe instanciarse y ejecutar su método init al arrancar la aplicación, por lo que debemos añadir a su configuración en el web.xml la etiqueta <load-on-startup>0</load-on-startup>. De esta forma obtenemos el contexto o ruta (CometContext) donde se van a esperar las conexiones antes de que la aplicación este funcionando. Podemos decir que el CometContext es el enlace del API de Comet con Grizzly.

super.init(config);
contextPath = config.getServletContext().getContextPath()+"/chat";
CometEngine cometEngine = CometEngine.getEngine();
CometContext context = cometEngine.register(contextPath);
context.setExpirationDelay(20 * 1000); 

Una vez el servlet se ha iniciado y por tanto tenemos el contexto comet, los usuarios pueden acceder al chat. Cuando esto ocurre el ejemplo registra el nombre del usuario en la sessión y redirecciona a la página chat.jsp, compuesta por dos iframes.

El primero de ellos es la pantalla donde se muestran los mensajes de los usuarios del chat. Se puede decir que este iframe es el que muestra el uso de la tecnología comet. Para ello llama al servlet del ejemplo enviando el parametro openchat. En el servlet al llegar esta petición se crea un CometHandler. Este interfaz que debemos implementar es el enlace entre nuestra aplicación y Grizzly. Se encarga de registrar el ciclo de vida y los eventos/notificaciones generados en el contexto. Además tiene la posibilidad de adjuntar recursos de la aplicación para hacer uso de ellos al producirse estos eventos. El caso más habitual es adjuntar los streams de salida (HTTPServletResponse ó PrintWriter) para enviar los datos al cliente.
Una vez hemos creado el handler, debemos añadirlo al contexto vinculando así al usuario. mas concretamente a su conexión HTTP.

CometRequestHandler handler = new CometRequestHandler();
handler.clientIP = request.getRemoteAddr();
handler.attach(response.getWriter());
cometContext.addCometHandler(handler); 

Todos los eventos que se produzcan en el contexto comet a partir de ahora mediante las llamadas a la operación CometContext.notify() serán enviados como eventos al handler del usuario (Típica implementación del patrón Observer). Estos eventos se generan desde el segundo iframe, que se encarga de enviar los mensajes del chat. El servlet en este caso, traduce el mensajes de los usuarios en un evento lanzado a todos los usuarios vinculados al contexto mediante la ya nombrada operación notify y por tanto generando una llamada a la operación onEvent del interfaz CometHandler.

cometContext.notify("[ " + username + " ]  " + message + " "); 

La operación onEvent del Handler recibe como parámetro el último interfaz de esta pequeña API, el CometEvent. Bajo este interfaz se almacena toda la información del CometContext y el objeto adjunto a la notificación, en el ejemplo, el mensaje enviado por algún usuario. Como el handler ya tiene los recursos necesarios para enviar los datos al usuarios, tan solo debe redireccionar la información adjunta al evento hasta el cliente.

printWriter.println(event.attachment());
printWriter.flush();

Y esto es todo, creo que merece la pena descargar el ejemplo y probarlo. Hace algunas cosas más de las que comento en el post, pero la basé es asi de simple: tres interfaces implementando un patron Observer. La verdad es que se me ocurren un par de ejemplos de donde usar esta técnologia... veremos si los pongo en práctica.

My first Comet Application in Glassfish