Custom Tags - Hola Mundo TLD

En esta ocasión crearemos una librería de etiquetas personalizadas o custom tags. Todo ello como continuación de la anterior entrada, en la que abordábamos cómo enviar un correo desde java o desde un jsp.
La solución desarrollada la semana pasada funcionaba pero tenía dos "peros" importantes: no me gustan los scriplets y no me gusta la ejecucción en primer plano si ésta empeora la experiencia de usuario. Para eliminar los scriplets vamos a crear unas librerias de etiquetas. Esto es, yo lo que buscamos en encapsular el código java y llamar a una "custom tag" que me meta el código html y además me ejecute código java. La idea es poder dejar el código de los jsp limpio.
 El entorno habítual de trabajo: jdk 1.6, eclipse Indigo (¿Para qué actualizar?) y el tomcat para desplegar es un 6y el siempre presente maven.
Lo que quiero construir es una libreria que me meta un textarea para enviar desde una página web el contenido a una dirección de correo, una vez enviado me devuelva un texto de envío correcto. Para el usuario del hipotético portal quedará oculto las direcciones de correo. Él sólo necesita un sitio donde meter el texto y un botón de enviar.
He reutilizado el proyecto anterior con algunos mínimos cambios. A saber, necesitamos un clase que implemente javax.servlet.jsp.tagext.Tag o que extienda directamente de javax.servlet.jsp.tagext.TagSupport y un archivo tld con el descriptor de las etiquetas. En mi caso utilizaré la implementación pues parece más cómodo.
La clase que envía el correo puedes verla aquí y apenas incorpora novedades. Cambia que toma el valor de la dirección de destino también desde el archivo xml de configuración.
En el pom vamos a añadir las librerias necesarias para acceder a las customTag
        <dependency>
            <groupId>javaee</groupId>
            <artifactId>javaee-api</artifactId>
            <version>5</version>
            <scope>provided</scope>
        </dependency>
No tiene ningún interés añadir dicha libreria ya que el contenedor web nos debería proporcionar la implementación apropiada.
La clase que ya incorpora la lógica de la las etiquetas personalizadas es MailerTag:
package es.sinjava.labs;
import javax.servlet.http.HttpServletRequest;
.....
public class MailerTag extends TagSupport {

    private static final String CONTENT_MAILER = "contentMailer";
    private String styleClass;
    private String messageClass;
    private String cols;
    private String rows;

    public String getCols() {
        return cols;
    }

    public void setCols(String cols) {
        this.cols = cols;
    }

    @Override
    public int doStartTag() throws JspException {
        HttpServletRequest request = (HttpServletRequest) pageContext
                .getRequest();
        StringBuffer sb = null;
        String texto = request.getParameter(CONTENT_MAILER);
        if (texto != null) {

            // Creamos el correo
            MailSender mailSender = new MailSender();
            mailSender.setText(texto);

            // lo lanzamos en segundo plano
            Thread segundoPlano = new Thread(mailSender);
            segundoPlano.start();

            // Escribimos la salida
            sb = new StringBuffer("<span ");
            prepareAttribute(sb, "class", getMessageClass());
            sb.append(" > Su Solicitud ha sido registrada ");
            sb.append(" </span>");
        } else {
            sb = new StringBuffer("<textarea ");
            // HttpServletResponse resp = (HttpServletResponse) pageContext
            // .getResponse();
            prepareAttribute(sb, "id", getId());
            prepareAttribute(sb, "name", CONTENT_MAILER);
            prepareAttribute(sb, "class", getStyleClass());
            prepareAttribute(sb, "cols", getCols());
            prepareAttribute(sb, "rows", getRows());
            sb.append(" > default value");
            sb.append(" </textarea>");
        }
        JspWriter out = pageContext.getOut();
        try {
            out.print(sb.toString());
        } catch (java.io.IOException e) {
            throw new JspException("IOException while writing to client: " + e);
        }
        return SKIP_BODY;
    }
 El método doStartTag() es el principal. Queremos poner una etiqueta que según venga de la carga inicial o destino muestre un texarea o un span informativo, eso lo obtenemos consultando un parámetro sobre la request. La clase completa en pastebin.
Reseñar que creo una clase privada de utilidad para lanzar en segundo plano el envío del correo.
Veamos el segundo archivo importante en las librerias de etiquetas personalizadas, el archivo TLD que hay que situar en resources/META-INF.  En este caso el nombre elegido es mailertag:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>mailertag</short-name>
    <uri>http://sinjava.blogspot.com.es</uri>   
    <tag>
        <name>mailerguay</name>
        <tag-class>es.sinjava.labs.MailerTag</tag-class>
        <body-content>JSP</body-content>
        <attribute>
            <name>styleClass</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>cols</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>rows</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>messageClass</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
</taglib>
El TLD es un xml sin mucha historia. Definición de nombres, versiones, etc y de la etiqueta con los nombre de los atributos que admite como parámetro la clase que lo va a gestionar. En nuestro caso "es.sinjava.labs.MailerTag"
En cualquiera de los casos, el proyecto completo para ver lo que me haya podido olvidar lo tienes para descarga.
Para poder añadirlo a otro proyecto web lo más sencillo es hacer un maven install (mvn install).
La razón última de utilizar las etiquetas personalizadas era eliminar completamente java de los jsp. Lo hemos logrado, ahora las jsp de nuestra aplicación de testeo quedan como sigue:
index.jsp:
<%@ taglib prefix="hp" uri="http://sinjava.blogspot.com.es" %>
<html>
<head>
<title>Enviador de correo</title>
</head>
<body>
    <h2>Introduce los datos</h2>
    <form name="frmMail" action="send.jsp">
        <hp:mailerguay cols="50" rows="5" styleClass="none" />
        <input type="submit">
    </form>
</body>
</html>
Y el de salida, send.jsp:
<%@ taglib prefix="hp" uri="http://sinjava.blogspot.com.es"%>
<html>
<head>
<title>Enviador de correo</title>
</head>
<body>
    <h1>Correo enviado</h1>
    <hp:mailerguay />
</body>
</html>
Breves, concisos y sin un resto de java y con el código altamente reutilizable. Proyecto web completo aquí.
El código en ambos casos es utilizar la directiva taglib, indicarle un prefijo y el "uri" que hemos puesto en el tld de la librería.
Por supuesto para que funcione deberemos añadir en el pom la librería creada por nosotros y de las que dependen. Sin olvidarnos del archivo de configuración de la cuenta de correo.
Dependencias del pom:
    <dependencies>
        <dependency>
            <groupId>es.sinjava.labs</groupId>
            <artifactId>mailTag</artifactId>
            <version>1.0.1</version>
        </dependency>   
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.5</version>
        </dependency>
    </dependencies>
Creo que metiendo un logger y mejorando un poco el control de excepciones ya empezaría a parecerse a algo interesante.