Abstracción

September 17, 2011 Leave a comment

Hablar de abstracción, no es solamente un principio que aplica dentro del Paradigma Orientado a Objetos. Cualquier sistema de software se basa en alguna forma de representación de la realidad. Se abstraen conceptos, se abstraen funciones, se abstraen algoritmos.

Hablando ahora sí de Orientación a Objetos, las abstracciones suelen ser diferentes de acuerdo al dominio del problema. Una clase Persona no tendrá el mismo detalle para una aplicación de medicina que para una aplicación web de correo. Al final estas diferencias hacen complicada la reutilización de clases.

Sería interesante un paradigma que permitiera modificar o alterar la abstracción de una clase en función del dominio en que se esté aplicando.

Categories: Uncategorized

Modelo del dominio

September 17, 2011 Leave a comment

Dentro del paradigma orientado a objetos, el modelo del dominio, expresado en un modelo conceptual, intenta capturar y expresar mediante conceptos (que pueden ser entendidos como clases) el contexto del problema, es decir, todo los objetos y sus relaciones que interactuan dentro de él.

Categories: Uncategorized

Example of tag library using TLD Generator

June 8, 2011 Leave a comment

In this post, I show an example of a tag library where TLD Generator is used. The example library contains one tag and one function, both for generation of  a random int. NetBeans is used to create the project.

Project structure

The package myrandom contains the tag handler and the function. The TLD generator jar and the JSP API are added to the libraries of the project.

Implementation of the tag

Every time the tag is invoked a random int is generated and sent to the output of its jspContext. The tag has an attribute to indicate the bound (exclusive) of the random int.

package myrandom;

import java.io.IOException;
import java.util.Random;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import tldgen.Tag;
import tldgen.TagAttribute;

@Tag
public class RandomNumberTag extends SimpleTagSupport{
    private int bound;

    @TagAttribute(required=true, runtimeValueAllowed=true)
    public void setBound(int bound) {
        this.bound = bound;
    }
    
    @Override
    public void doTag() throws JspException, IOException {
        Random r=new Random();
        getJspContext().getOut().print(r.nextInt(bound));
    }
    
}

The tag handler has two important annotations:

  • @Tag in the tag handler class. Because the tag doesn’t have an explicit name, the name will be the decapitalized name of the class with the suffix “Tag” removed. So in this example, the name of the tag in the descriptor will be randomNumber.
  • @TagAttribute is present in the setter of the bound attribute. The values of the annotations define that this attribute is required and that its value can be determined from an expression.

Function Implementation

The function is implemented like this:

package myrandom;

import java.util.Random;
import tldgen.Function;

public class RandomFunction {
    
    @Function
    public static int getRandomInt(){
        return new Random().nextInt();
    }
    
}

The method is annotated with @Function. The method has to be public and static for being visible from JSP pages. The name of the function is the name of the method, but other could be defined in the annotation.

Definition of the library

At this moment, the content of the project looks like this:

In order to group the tags and functions, we need to define a tag library. This is accomplished in a package-level annotation defined in the package-info.java file in myrandom (I used New Empty File wizard in NetBeans because the Class wizard doesn’t allow package-info name for a class).

And here is the content of this file:

@TagLibrary("http://random.org")
package myrandom;

import tldgen.TagLibrary;

In the above declaration, we define an URI for the library. The descriptor file will be taglib.tld by default. This may be changed in the annotation.

Compiling the project and generating the descriptor

Now, let’s compile the project in order to generate the descriptor with the Clean and Build option of the project.

To see the generated file, go to the Files window in NetBeans and navigate to the build/classes directory of the project.  The tld file will be in the subdirectory META-INF from where it’s read by the Servlet container at deployment time.

The content of the descriptor is:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib version="2.1" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <tlib-version>1.0</tlib-version>
    <uri>http://random.org</uri>
    <tag>
        <name>randomNumber</name>
        <tag-class>myrandom.RandomNumberTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>bound</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.lang.Integer</type>
        </attribute>
    </tag>
    <function>
        <name>getRandomInt</name>
        <function-class>myrandom.RandomFunction</function-class>
        <function-signature>int getRandomInt()</function-signature>
    </function>
</taglib>

Conclusion

In this example, I showed how to use TLD generator to produce automatically a Tag Library Descriptor. Most of the times, the descriptor is manually build with information already contained in the classes. With TLD generator I don’t have to write redundant information (DRY principle).

Resources

RandomNumbers NetBeans project in zip file

Categories: Java, TLD Generator, web

TLD Generator is released

June 8, 2011 Leave a comment

My annotation-based tool for automatic generation of Tag Library Descriptor is now available. It’s based is the TLD schema in JSP 2.1. It supports tag handlers, tag files, functions, tag attributes with deferred values or methods.

For more information, please visit http://code.google.com/p/tld-generator/.

Categories: Uncategorized

Reduciendo el archivo TLD con un listener en JAXB

June 3, 2011 Leave a comment

Ahora con el soporte completo de la versión jsp 2.1 para archivos TLD, el descriptor generado puede ser bastante grande. Según la especificación del archivo TLD, si un elemento no se encuentra presente, toma un valor default. Tal es el caso de required para un atributo ya que por omisión es false.

Este es un fragmento para la descripción de un atributo:

       <attribute>
            <name>url</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <type>java.lang.String</type>
            <fragment>false</fragment>
        </attribute>       

Si se omitieran los elementos con un valor default, el xml podría quedar así:

        <attribute>
            <name>url</name>
            <type>java.lang.String</type>
        </attribute>

JAXB realiza el mapeo de todos los atributos cuyo valor sea diferente de null. Dentro del proyecto, los valores de estos atributos son copiados automaticamente de los valores de las anotaciones o en otros casos derivado del elemento que contiene la anotación. Debido a esta copia automática y que no creo que sea conveniente incluir condicionales para manejar valores default dentro del procesador, busqué y afortunadamente encontré una forma de limpiar estos atributos antes de ser transformados a XML.

Lo que hice fue utilizar un listener para el marshaller y antes de que el objeto sea convertido, explorar sus atributos y aquellos que tengan un valor que sea igual al default establecerlos en null.

Este es el código del listener:

package tldgen.processor;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;

/**
 *
 * @author Victor
 */
public class DefaultValueCleaner extends Marshaller.Listener{

    @Override
    public void beforeMarshal(Object source) {
        try {
            PropertyDescriptor[] descriptors = Introspector
                 .getBeanInfo(source.getClass()).getPropertyDescriptors();
            for(PropertyDescriptor descriptor:descriptors){
                if(descriptor.getReadMethod() != null){
                    Object currentValue=descriptor
                          .getReadMethod().invoke(source);
                    XmlElement xmlElement = descriptor
                          .getReadMethod().getAnnotation(XmlElement.class);
                    String defaultValue=null;
                    if(xmlElement != null){
                        defaultValue=xmlElement.defaultValue();
                    }
                    if(currentValue != null 
                        && currentValue.toString().equals(defaultValue) 
                        && descriptor.getWriteMethod() != null){
                            descriptor.getWriteMethod().invoke(source, new Object[]{null});
                    }
                }
            }
        } catch (IntrospectionException ex) {
            throw new RuntimeException(ex);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            throw new RuntimeException(ex);
        }
    }
    
}

Y así se establece en el marshaller:

   marshaller.setListener(new DefaultValueCleaner());

Sé que es ineficiente establecer el valor de un atributo para posteriormente quitarlo pero opté por esta opción por las siguientes razones:

  • Para que al procesador de anotaciones le sea transparente el uso o no de valores default.
  • Porque el proceso de generación del archivo se realiza solamente una vez durante la compilación y esto no afectará el performance de una aplicación en producción.
Categories: Java, JAXB, TLD Generator, web

Generador de Tag Library Descriptor usando JAXB y Procesador de anotaciones

June 2, 2011 Leave a comment

Estoy realizando modificaciones a mi proyecto de generación de archivos TLD (archivo XML para la definición de etiquetas para JSP).

Anteriormente el archivo TLD se generaba con Stax pero consideré que era prudente reducir el código para hacer más fácil las actividades de mantenimiento. El proyecto ya contenia clases bean cuyas propiedades eran directamente escritas a elementos o atributos XML con Stax. No había utilizado antes JAXB pero sabía que es un API para la traducción de XML/ Java (en forma bidireccional) por lo que realizé algunas pruebas preliminares y funcionaba de forma muy cercana a lo que yo esperaba.

Éste es un ejemplo de una clase en mi proyecto que contiene anotaciones de JAXB para poder ser traducida a XML.


package tldgen.processor;

import java.util.LinkedList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name="taglib")
@XmlType(propOrder={"description", "displayName", "icon", "libraryVersion", "shortName", "uri", "validator", "webListeners", "tagFiles", "tagHandlers", "functions"})
public class TagLibraryInfo {
    private String uri;
    private String description;
    private String displayName;
    private String icon;
    private String libraryVersion;
    private String jspVersion;
    private String shortName;
    private List<TagInfo> tagHandlers=new LinkedList<TagInfo>();
    private List<FunctionInfo> functions=new LinkedList<FunctionInfo>();
    private ValidatorInfo validator;
    private List<WebListenerInfo> webListeners=new LinkedList<WebListenerInfo>();
    private List<TagFileInfo> tagFiles=new LinkedList<TagFileInfo>();

    protected TagLibraryInfo() {
    }
    
    public TagLibraryInfo(String uri) {
        this.uri = uri;
    }

    @XmlElement
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @XmlElement(name="display-name")
    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    @XmlElement
    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    @XmlElement(name="short-name")
    public String getShortName() {
        return shortName;
    }

    public void setShortName(String shortName) {
        this.shortName = shortName;
    }

    @XmlElement
    public String getUri() {
        return uri;
    }

    @XmlElement(name="tlib-version")
    public String getLibraryVersion() {
        return libraryVersion;
    }

    public void setLibraryVersion(String version) {
        this.libraryVersion = version;
    }

    @XmlAttribute(name="version")
    public String getJspVersion() {
        return jspVersion;
    }

    public void setJspVersion(String jspVersion) {
        this.jspVersion = jspVersion;
    }

    public ValidatorInfo getValidator() {
        return validator;
    }

    @XmlElement
    public void setValidator(ValidatorInfo validator) {
        this.validator = validator;
    }
    
    @XmlElement(name="tag")
    List<TagInfo> getTagHandlers() {
        return tagHandlers;
    }

    @XmlElement(name="function")
    List<FunctionInfo> getFunctions() {
        return functions;
    }

    @XmlElement(name="tag-file")
    List<TagFileInfo> getTagFiles() {
        return tagFiles;
    }

    @XmlElement(name="listener")
    List<WebListenerInfo> getWebListeners() {
        return webListeners;
    }
    
}

Para definir el namespace del archivo TLD, incluí el archivo package-info.java  (ver anotaciones en paquetes) con el siguiente contenido:

@XmlSchema(
namespace = "http://java.sun.com/xml/ns/javaee",
elementFormDefault = XmlNsForm.QUALIFIED)

package tldgen.processor;

import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

Aquí hay un ejemplo de una clase que invoca JAXB para realizar la conversión:


package tldgen.processor;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import tldgen.BodyContentType;

public class Main {
    
    public static void main(String[] args) throws JAXBException {
        TagLibraryInfo info=new TagLibraryInfo("http://simplehtml.net");
        info.setJspVersion("2.1");
        info.setLibraryVersion("1.0");
        info.setDescription("Tags for common HTML elements");
        info.getFunctions().add(
             new FunctionInfo("sum", "functions.Sum", "int sum(int a, int b)"));
        info.getFunctions().add(
             new FunctionInfo("sum2", "functions.Sum", "int sum(int a, int b)"));
        TagInfo tagInfo = new TagInfo("img", "my.ImageTag", BodyContentType.TAG_DEPENDENT);
        AttributeInfo attributeInfo = new AttributeInfo("src");
        attributeInfo.setType("java.lang.String");
        tagInfo.getAttributes().add(attributeInfo);
        info.getTagHandlers().add(tagInfo);
        JAXBContext context=JAXBContext.newInstance(TagLibraryInfo.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, 
          "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd");
        m.marshal(info, System.out);
    }
    
}

Y este es el XML generado:


run:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
    <description>Tags for common HTML elements</description>
    <tlib-version>1.0</tlib-version>
    <uri>http://simplehtml.net</uri>
    <tag>
        <name>img</name>
        <tag-class>my.ImageTag</tag-class>
        <body-content>tagdependent</body-content>
        <attribute>
            <name>src</name>
            <type>java.lang.String</type>
        </attribute>
    </tag>
    <function>
        <name>sum</name>
        <function-class>functions.Sum</function-class>
        <function-signature>int sum(int a, int b)</function-signature>
    </function>
    <function>
        <name>sum2</name>
        <function-class>functions.Sum</function-class>
        <function-signature>int sum(int a, int b)</function-signature>
    </function>
</taglib>


Ahora que estoy utilizando JAXB en el proyecto, creo que dispondré de tiempo que ocuparé en otros módulos del generador (como el procesador de anotaciones) o en otros proyectos.

El tutorial que utilice se encuentra en este enlace http://jaxb.java.net/tutorial/.

Categories: Java, TLD Generator, web

Hello World with Carmesi

May 16, 2011 Leave a comment

In this post, I’ll show an example of a very minimal web application using Carmesi. It’s just a variation of “Hello, world!” that receives a parameter to concatenate in a greeting message that is displayed in a different page.

First, there have to be a HTML page to capture the parameter. This page contains a form that allows the user to capture his or her name.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <form method="GET" action="greetings">
            <p>
                <label for="name">Please, introduce your name</label>
                <input type="text" name="name"/>
            </p>
            <button>Get greeting message</button>
        </form>
    </body>
</html>

The next step (and here is where Carmesi is used), a class to put the logic of the application (as this example is very very basic, the logic is captured in the controller but not to be done in an application with a more complex logic).

We have to specify a few things in the controller:

  • The url to invoke it. The form in the first step uses this url to send the parameter. This information is specified with URL annotation.
  • That the request parameter called name will be injected into a parameter of the method (RequestParameter annotation).
  • That the result will be stored in a request attribute to be displayed by the result page. This information is implicit in the declaration of the controller because the name of the method is prefixed with get (the name of the attribute is got by removing this prefix from the name of the method).  The annotation RequestAttribute could be added to the method to make it explicit.
  • The result page of this controller. This is specified using ForwardTo because we need to access to the request scope (in other cases RedirectTo could be used).
import carmesi.URL;
import carmesi.ForwardTo;
import carmesi.RequestParameter;

@URL("/greetings")
@ForwardTo("result.jsp")
public class GreetingsController {

    public String getGreetingMessage(@RequestParameter("name") String name){
        return "Hello, "+name+"!";
    }

}

And finally, the application needs a result page to display the message. The value is in the request attribute greetingMessage.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>${greetingMessage}</h1>
    </body>
</html>

Here is an screenshot of the execution of this example:

Categories: Uncategorized
Follow

Get every new post delivered to your Inbox.