Cómo modificar todos los componentes de Tapestry en bloque

Cómo modificar todos los componentes de Tapestry en bloque

A lo largo de su ciclo de vida, una aplicación web puede ir sufriendo diferentes modificaciones, ya sea por optimizaciones, nuevos requisitos, resolución de errores, etc.
Supongamos que aparece un nuevo requisito en nuestra aplicación web que implica modificar algún elemento concreto en todas las páginas en las que aparezca. Esto puede ser una tarea tediosa si nuestra aplicación es grande. Veamos qué opciones tenemos.

Caso de estudio

En esta ocasión, el ejemplo será sobre una aplicación web Java usando el framework Tapestry. Dicha aplicación tiene un nuevo requisito: es necesario deshabilitar todos los formularios bajo cierta condición en tiempo de ejecución. Se han escogido los formularios, pero podrían ser los enlaces, checkboxes, etc; es decir, cualquier componente de Tapestry.

Soluciones

La solución más básica, sería revisar todas las páginas de la aplicación e ir añadiendo la nueva condición. Esto es perfectamente válido, pero intentemos ser un poco más eficientes y aprovechar las funcionalidades de Tapestry.

Tapestry permite modificar el comportamiento de sus componentes mediante los Mixins. Su utilización es muy sencilla. El primer paso es crear una nueva clase en un paquete llamado “mixins” e implementar el comportamiento deseado. Por ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@MixinAfter
public class CustomCheckbox {
 
    void afterRender(MarkupWriter writer) {
 
        //Apply only under certain condition
        if (condition) {
            Element element = writer.getElement();
            if (element != null) {
                element.attribute("disabled", "true");
            }
        }
    }
}

A continuación, basta con añadirlo en el tml de la siguiente forma:

1
<t:checkbox t:id="elementId" t:mixins="CustomCheckbox" />

Esta solución es mejor que la anterior, ya que la nueva condición que debemos añadir, sólo hay que comprobarla en un único punto dentro del código. Por otro lado, seguimos teniendo el problema de que hay que recorrer y revisar todas las páginas de la aplicación para añadir el mixin al componente que deseemos modificar. Lo ideal sería aplicar un mixin de forma generalizada a todos los componentes.

La tercera y última solución que proponemos es utilizar otra característica de Tapestry: class transformations. En combinación con los mixins, podremos aplicarlos por componente, en lugar de por aparición, como en la solución anterior. Para esto, necesitamos crear una implementación de la interfaz ComponentClassTransformWorker si estamos usando Tapestry 5.2 o inferior, o de ComponentClassTransformWorker2 si estamos usando la versión 5.3 o superior.

El nuevo requisito, pedía deshabilitar todos los formularios bajo una condición, por lo tanto, el mixin que hemos creado lo tenemos que aplicar únicamente a los formularios. En concreto, basta con inyectar el mixin en el botón submit del formulario, que es un componente concreto de Tapestry.
Así, la implementación de nuestro “worker” quedará de la siguiente forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CustomSubmitWorker implements ComponentClassTransformWorker {
 
    private static final Logger logger = LoggerFactory.getLogger(CustomSubmitWorker.class);
 
    public void transform(ClassTransformation ct, MutableComponentModel mcm) {
 
        if (Submit.class.getName().equals(ct.getClassName())){
            if (!mcm.getMixinClassNames().contains(CustomSubmit.class.getName())){
                mcm.addMixinClassName(CustomSubmit.class.getName());
            }
        }
    }
}

Y para Tapestry 5.3+:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CustomSubmitWorker implements ComponentClassTransformWorker2 {
 
    private static final Logger logger = LoggerFactory.getLogger(CustomSubmitWorker.class);
 
    public void transform(final PlasticClass plasticClass, 
        TransformationSupport support, MutableComponentModel mcm) {
 
        if (Submit.class.getName().equals(plasticClass.getClassName())){
            if (!mcm.getMixinClassNames().contains(CustomSubmit.class.getName())){
                mcm.addMixinClassName(CustomSubmit.class.getName());
            }
        }
    }
}

Por último, es necesario decirle a Tapestry que no se olvide de aplicar nuestro worker. Esto se hace añadiendo a nuestra clase AppModule el siguiente método (recordando sustituir ComponentClassTransformWorker por ComponentClassTransformWorker2 dependiendo de nuestra versión de Tapestry):

1
2
3
4
@Contribute(ComponentClassTransformWorker.class)
    public static void provideWorkers(OrderedConfiguration workers) {
        workers.addInstance(CustomSubmitWorker.class.getSimpleName(), CustomSubmitWorker.class);
    }

Conclusión

Esta última solución nos ha permitido crear una condición en un único punto en el código y aplicarla al componente de Tapestry deseado de forma general, es decir, sin tener que revisar todas las páginas de la aplicación para añadir el nuevo comportamiento.

Referencias | TAWUS
Publicado en septiembre 17, 2014

,

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

« »