Francisco Javier Martínez Páez

Consultor tecnológico de desarrollo de proyectos informáticos.

 Ingeniero Técnico en Telecomunicaciones

Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación

Somos expertos en Java/J2EE

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2008-01-18

Tutorial visitado 29.650 veces Descargar en PDF
"Icefaces, JBoss, Maven2 y EJB3

Icefaces, JBoss, Maven2 y EJB3: Parte 3.

Bueno, creo que en esta tercera parte es ya hora de comenzar a desarrollar nuestro negocio. Para el tutorial, he pensado en una pequeña biblioteca con libros, socios, autores etc...

  1. Modelo de negocio.

    Lo primero que voy a hacer es mostraros un pequeño diagrama de clases UML que representa las entidades del dominio del problema (de la Biblioteca). Como todo diagrama UML, es discutible y mejorable, pero creo que es suficiente para el tutorial:




De manera textual, lo que quiero representar es lo siguiente:

  • Un libro puede tener uno o varios autores, y un autor puede serlo de al menos un libro.

  • Un libro pertenece a una categoría (podría pertenecer a varias, pero no voy a complicar más el tema), y una categoría puede estar asociada a varios libros. También podría haber hecho que la categoría tuviese una relación consigo misma pudiéndose crear un árbol de categorías, pero no lo he hecho por la misma razón de antes

  • Un socio puede disponer de todos los libros que quiera y un libro puede o no estar prestado. Podría haber modelado esta asociación como una clase de la relación (clase Préstamo con una fecha de caducidad del préstamos etc...) pero no lo he hecho por el mismo motivo de antes.

  • Un socio tiene una información de contacto. Esta relación 'uno a uno' que la he modelado como una composición podría haberla evitado, es decir, podría haber modelado esta información dentro de la clase Socio, pero lo he forzado así para tener una relación 'uno a uno'. Es más, incluso así, si llevásemos este modelo a su implementación en la base de datos, podríamos mantener esta información en la tabla 'Socio' haciendo que la clase InformacionContacto fuese 'Embeddable' dentro de la clase Socio.

  1. Modelo de datos.

    Vamos ahora a crear las tablas en la base de datos MySQL. Me he creado un esquema llamado 'biblioteca' y le he dado todos los permisos al usuario 'paco' sobre el esquema. A continuación os dejo el script de creación de las tablas para nuestro modelo 'BibliotecaDDL.sql:

    CREATE TABLE IF NOT EXISTS `Socio` (

    `id` int NOT NULL auto_increment,

    `nombre` varchar(100),

    `apellidos` varchar(200),

    `dni` varchar(9),

    PRIMARY KEY (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;


    CREATE TABLE IF NOT EXISTS `InformacionContacto` (

    `id` int NOT NULL auto_increment,

    `socioId` int NOT NULL,

    `email` varchar(200),

    `movil` varchar(15),

    `fijo` varchar(15),

    PRIMARY KEY (`id`),

    index `ndx_infoContacto_socio` (`socioId`),

    CONSTRAINT `fk_infoContacto_socio` FOREIGN KEY (`socioId`) REFERENCES `Socio` (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;


    CREATE TABLE IF NOT EXISTS `Categoria` (

    `id` int NOT NULL auto_increment,

    `nombre` varchar(100),

    `descripcion` varchar(1024),

    PRIMARY KEY (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;


    CREATE TABLE IF NOT EXISTS `Libro` (

    `id` int NOT NULL auto_increment,

    `socioId` int,

    `categoriaId` int NOT NULL,

    `titulo` varchar(100),

    `isbn` varchar(15),

    PRIMARY KEY (`id`),

    index `ndx_libro_socio` (`socioId`),

    index `ndx_libro_categoria` (`categoriaId`),

    CONSTRAINT `fk_libro_socio` FOREIGN KEY (`socioId`) REFERENCES `Socio` (`id`),

    CONSTRAINT `fk_libro_categoria` FOREIGN KEY (`categoriaId`) REFERENCES `Categoria` (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;


    CREATE TABLE IF NOT EXISTS `Autor` (

    `id` int NOT NULL auto_increment,

    `nombre` varchar(100),

    `apellidos` varchar(200),

    PRIMARY KEY (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;


    CREATE TABLE IF NOT EXISTS `Libro_Autor` (

    `libro` int NOT NULL,

    `autor` int NOT NULL,

    PRIMARY KEY (`libro`,`autor`),

    index `ndx_libro` (`libro`),

    index `ndx_autor` (`autor`),

    CONSTRAINT `fk_libroAutor_libro` FOREIGN KEY (`libro`) REFERENCES `Libro` (`id`),

    CONSTRAINT `fk_libroAutor_autor` FOREIGN KEY (`autor`) REFERENCES `Autor` (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

    Os regalo también un script para rellenar datos: 'BibliotecaDML.sql'

    insert into Categoria (`id`, `nombre`, `descripcion`)

    values( '1', 'Filosofía', 'Libros de filosofía');

    insert into Categoria (`id`, `nombre`, `descripcion`)

    values( '2', 'Narrativa', 'Libros de Narrativa, novelas y varios.');

    insert into Categoria (`id`, `nombre`, `descripcion`)

    values('3', 'Historia', 'Libros de Historia');


    insert into Autor (`id`, `nombre`, `apellidos`)

    values( '1', 'Miguel', 'de Cervantes Saavedra');

    insert into Autor (`id`, `nombre`, `apellidos`)

    values( '2', 'John', 'Elliot');

    insert into Autor (`id`, `nombre`, `apellidos`)

    values( '3', 'René', 'Descartes');


    insert into Libro (`id`, `categoriaId`, `titulo`, `isbn`)

    values( '1', '2', 'El Quijote', 'A123456789');

    insert into Libro (`id`, `categoriaId`, `titulo`, `isbn`)

    values( '2', '1', 'El discurso del método', 'A987654321');

    insert into Libro (`id`, `categoriaId`, `titulo`, `isbn`)

    values( '3', '3', 'El conde duque de Olivares', 'A987654321');


    insert into Libro_Autor (`libro`,`autor`)

    values( '1', '1');

    insert into Libro_Autor (`libro`,`autor`)

    values( '2', '3');

    insert into Libro_Autor (`libro`,`autor`)

    values( '3', '2');


    insert into Socio (`id`,`nombre`,`apellidos`,`dni`)

    values ('1','Francisco Javier','Martínez Páez','12653786A');

    insert into Socio (`id`,`nombre`,`apellidos`,`dni`)

    values ('2','Germán','Jiménez Centeno','37265738J');

    insert into Socio (`id`,`nombre`,`apellidos`,`dni`)

    values ('3','Daniel','Hernández del Peso','376298795L');


    insert into InformacionContacto (`socioId`,`email`,`movil`,`fijo`)

    values ('1','paco@biblioteca.com','00346753322','0034912993387');

    insert into InformacionContacto (`socioId`,`email`,`movil`,`fijo`)

    values ('2','german@biblioteca.com','00346753323','0034912993388');

    insert into InformacionContacto (`socioId`,`email`,`movil`,`fijo`)

    values ('3','dani@biblioteca.com','00346753324','0034912993389');

  2. Creando las entidades con anotaciones.

    Ahora, vamos a crear nuestras clases de entidad. En un principio lo vamos a hacer con anotaciones. En el siguiente tutorial de la saga usaremos el descriptor 'orm.xml' para mostrar como se haría y las implicaciones de que ambas formas convivan.

En el paquete: com.autentia.tutoriales.modelo.entidades

  • Clase TransferObject. Clase abstracta padre de las demás que agrupará las características comunes:

    package com.autentia.tutoriales.modelo.entidades;


    import java.io.Serializable;


    public abstract class TransferObject implements Serializable {

    protected Integer id;


    /**

    * This method must be implemented by all the subclasses

    * of the superclass 'TransferObject' because EJB3 requires that every

    * class define its own getId() method with its annotations.

    */

    public abstract Integer getId();


    public void setId(Integer id) {

    this.id = id;

    }

    @Override

    public int hashCode() {

    final int prime = 31;

    int result = 1;

    result = prime * result + ((id == null) ? 0 : id.hashCode());

    return result;

    }

    @Override

    public boolean equals(Object obj) {

    if (this == obj) return true;

    if (obj == null) return false;

    if (getClass() != obj.getClass()) return false;

    final TransferObject other = (TransferObject)obj;

    if (id == null) {

    if (other.id != null) return false;

    } else if (!id.equals(other.id)) return false;

    return true;

    }


    public abstract String toString();

    }

  • Clase Categoria:

    package com.autentia.tutoriales.modelo.entidades;


    import javax.persistence.GeneratedValue;

    import javax.persistence.GenerationType;

    import javax.persistence.Id;

    import javax.persistence.Entity;


    @Entity

    public class Categoria extends TransferObject {

    private String nombre;

    private String descripcion;

    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    public Integer getId() {

    return id;

    }


    public String getNombre() {

    return nombre;

    }


    public void setNombre(String nombre) {

    this.nombre = nombre;

    }


    public String getDescripcion() {

    return descripcion;

    }


    public void setDescripcion(String descripcion) {

    this.descripcion = descripcion;

    }

    public String toString() {

    return "id="+id +" "+",nombre="+ this.nombre+",descripcion="+ this.descripcion;

    }


    }

  • Clase Autor:

    package com.autentia.tutoriales.modelo.entidades;


    import java.util.Set;

    import javax.persistence.Entity;

    import javax.persistence.GeneratedValue;

    import javax.persistence.GenerationType;

    import javax.persistence.Id;

    import javax.persistence.ManyToMany;


    @Entity

    public class Autor extends TransferObject {


    private String nombre;

    private String apellidos;

    private Set<Libro> libros;

    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    public Integer getId() {

    return id;

    }

    public String getNombre() {

    return nombre;

    }


    public void setNombre(String nombre) {

    this.nombre = nombre;

    }


    public String getApellidos() {

    return apellidos;

    }


    public void setApellidos(String apellidos) {

    this.apellidos = apellidos;

    }


    @ManyToMany(mappedBy="autores")

    public Set<Libro> getLibros() {

    return libros;

    }


    public void setLibros(Set<Libro> libros) {

    this.libros = libros;

    }


    public String toString() {

    return "id="+id +" "+",nombre="+ this.nombre+",apellidos="+ this.apellidos;

    }


    }

  • Clase Libro:

    package com.autentia.tutoriales.modelo.entidades;


    import java.util.Set;

    import javax.persistence.Entity;

    import javax.persistence.GeneratedValue;

    import javax.persistence.GenerationType;

    import javax.persistence.Id;

    import javax.persistence.JoinColumn;

    import javax.persistence.JoinTable;

    import javax.persistence.ManyToMany;

    import javax.persistence.ManyToOne;



    @Entity

    public class Libro extends TransferObject {

    private String titulo;

    private String isbn;

    private Set<Autor> autores;

    private Categoria categoria;

    private Socio socio;

    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    public Integer getId() {

    return id;

    }


    public String getTitulo() {

    return titulo;

    }


    public void setTitulo(String titulo) {

    this.titulo = titulo;

    }


    public String getIsbn() {

    return isbn;

    }


    public void setIsbn(String isbn) {

    this.isbn = isbn;

    }


    @ManyToMany

    @JoinTable(name="Libro_Autor",

    joinColumns=

    @JoinColumn(name="libro",referencedColumnName="id"),

    inverseJoinColumns=

    @JoinColumn(name="autor",referencedColumnName="id")

    )

    public Set<Autor> getAutores() {

    return autores;

    }


    public void setAutores(Set<Autor> autores) {

    this.autores = autores;

    }

    @ManyToOne

    @JoinColumn(name = "categoriaId",referencedColumnName="id")

    public Categoria getCategoria() {

    return categoria;

    }


    public void setCategoria(Categoria categoria) {

    this.categoria = categoria;

    }

    @ManyToOne

    @JoinColumn(name="socioId",referencedColumnName="id")

    public Socio getSocio() {

    return socio;

    }


    public void setSocio(Socio socio) {

    this.socio = socio;

    }


    public String toString() {

    return "id="+id+",titulo="+this.titulo+",isbn="+this.isbn+",categoria="+this.getCategoria().getNombre();

    }

    }

  • Clase Socio:

    package com.autentia.tutoriales.modelo.entidades;


    import java.util.Set;

    import javax.persistence.GeneratedValue;

    import javax.persistence.GenerationType;

    import javax.persistence.Id;

    import javax.persistence.OneToMany;

    import javax.persistence.OneToOne;

    import javax.persistence.PrimaryKeyJoinColumn;

    import javax.persistence.Entity;


    @Entity

    public class Socio extends TransferObject {


    private String nombre;

    private String apellidos;

    private Set<Libro> libros;

    private InformacionContacto informacionContacto;

    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    public Integer getId() {

    return id;

    }

    public String getNombre() {

    return nombre;

    }


    public void setNombre(String nombre) {

    this.nombre = nombre;

    }


    public String getApellidos() {

    return apellidos;

    }


    public void setApellidos(String apellidos) {

    this.apellidos = apellidos;

    }


    @OneToMany(mappedBy="socio")

    public Set<Libro> getLibros() {

    return libros;

    }


    public void setLibros(Set<Libro> libros) {

    this.libros = libros;

    }


    @OneToOne

    @PrimaryKeyJoinColumn(name="id",referencedColumnName="socioId")

    public InformacionContacto getInformacionContacto() {

    return informacionContacto;

    }


    public void setInformacionContacto(InformacionContacto informacionContacto) {

    this.informacionContacto = informacionContacto;

    }


    public String toString() {

    return "id="+id +" "+",nombre="+ this.nombre+",apellidos="+

    this.apellidos+",contacto="+this.getInformacionContacto();

    }


    }

  • Clase InformacionContacto:

    package com.autentia.tutoriales.modelo.entidades;


    import javax.persistence.GeneratedValue;

    import javax.persistence.GenerationType;

    import javax.persistence.Id;

    import javax.persistence.Entity;


    @Entity

    public class InformacionContacto extends TransferObject {

    private String email;

    private String movil;

    private String fijo;

    @Id

    @GeneratedValue(strategy = GenerationType.AUTO)

    public Integer getId() {

    return id;

    }

    public String getEmail() {

    return email;

    }


    public void setEmail(String email) {

    this.email = email;

    }


    public String getMovil() {

    return movil;

    }


    public void setMovil(String movil) {

    this.movil = movil;

    }


    public String getFijo() {

    return fijo;

    }


    public void setFijo(String fijo) {

    this.fijo = fijo;

    }

    @Override

    public String toString() {

    return "id="+id +" "+",email="+ this.email+",movil="+ this.movil +",fijo="+ this.fijo;

    }


    }

  1. Creamos el DAO.

    Primero creamos el Interfaz (únicamente local) en el paquete:com.autentia.tutoriales.modelo.services

    package com.autentia.tutoriales.modelo.services;


    import java.util.List;

    import java.util.Map;

    import javax.ejb.Local;

    import com.autentia.tutoriales.modelo.entidades.TransferObject;



    @Local

    public interface Dao {


    /**

    * Recover all the entries from a single table

    */

    public <T extends TransferObject> List<T> findAll(Class<T> transferObjectClass, String sortColumn, boolean ascending);


    /**

    * Recover a single entries from a table

    */

    public <T extends TransferObject> T find(Class<T> transferObjectClass, Integer id);


    /**

    * Recover a list of objects using a query and a map with the name of the parameters and his values

    */

    public <T extends TransferObject> List<T> findAllByQuery(String query, Map<String, Object> params);

    /**

    * Recover a single entry from a table using a query and a map with the name of the parameters and his values

    */

    public <T extends TransferObject> T findSingleByQuery(String query, Map<String, Object> params);

    /**

    * Recover all the entries from a single table and with filter

    */

    public <T extends TransferObject> List<T> findAllAndFilterLike(Class<T> transferObjectClass, Map<String, Object> params, String sortColumn, boolean ascending);

    }

    Solamente he incluido algunos métodos selectores.

    Ahora la implementación:

    package com.autentia.tutoriales.modelo.services;


    import java.util.Hashtable;

    import java.util.Iterator;

    import java.util.List;

    import java.util.Map;

    import javax.ejb.Stateless;

    import javax.persistence.EntityManager;

    import javax.persistence.NoResultException;

    import javax.persistence.PersistenceContext;

    import javax.persistence.Query;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import com.autentia.tutoriales.modelo.entidades.TransferObject;


    @Stateless

    public class DaoImpl implements Dao {


    private static final Log log = LogFactory.getLog(DaoImpl.class);

    @PersistenceContext

    protected EntityManager em;

    @SuppressWarnings("unchecked")

    public <T extends TransferObject> List<T> findAll(Class<T> transferObjectClass, String sortColumn, boolean ascending) {

    log.debug("GenericDao:findAll");

    final String entityName = transferObjectClass.getSimpleName();

    final Query query;


    if (ascending) {

    query = em.createQuery("from " + entityName + " e order by e." + sortColumn + " asc");

    } else {

    query = em.createQuery("from " + entityName + " e order by e." + sortColumn + " desc");

    }


    final List<T> resultList = query.getResultList();

    if (log.isTraceEnabled()) {

    log.trace(resultList.size() + " " + entityName + " recovered from database.");

    }

    return resultList;

    }


    public <T extends TransferObject> T find(Class<T> transferObjectClass, Integer id) {

    return em.find(transferObjectClass, id);

    }

    private Query createQuery(String query, Map<String, Object> params) {

    Query qQuery = em.createQuery(query);

    if (params != null) {

    Iterator<String> it = params.keySet().iterator();

    while (it.hasNext()) {

    String key = it.next();

    Object value = params.get(key);

    qQuery.setParameter(key, value);

    }

    }

    return qQuery;

    }

    @SuppressWarnings("unchecked")

    public <T extends TransferObject> List<T> findAllByQuery(String query, Map<String, Object> params) {

    Query qQuery = createQuery(query, params);

    log.debug("CONSULTA:" + qQuery.toString());

    return qQuery.getResultList();

    }

    @SuppressWarnings("unchecked")

    public <T extends TransferObject> T findSingleByQuery(String query, Map<String, Object> params) {

    Query qQuery = createQuery(query, params);

    log.debug("CONSULTA:" + qQuery.toString());

    Object obj = null;

    try {

    obj = qQuery.getSingleResult();

    } catch (NoResultException e) {

    log.debug("NO se han encontrado resultados", e);

    }

    return (T)obj;

    }

    public <T extends TransferObject> List<T> findAllAndFilterLike(

    Class<T> transferObjectClass, Map<String, Object> params,

    String sortColumn, boolean ascending) {

    log.debug("GenericDao:findAllAndFilterLike");

    final String entityName = transferObjectClass.getSimpleName();

    StringBuffer sbQuery = new StringBuffer("from ").append(entityName).append(" e");

    final Query query;

    Map<String, Object> params2 = new Hashtable<String, Object>();

    boolean first=true;

    if(params!=null && params.size()>0) {

    Iterator<String> it = params.keySet().iterator();

    while(it.hasNext()) {

    String key = it.next();

    if(first)

    sbQuery.append(" where e.").append(key).append(" like :").append(key);

    else

    sbQuery.append(" and e.").append(key).append(" like :").append(key);

    first=false;

    params2.put(key, params.get(key)+"%");

    }

    }

    if (ascending)

    sbQuery.append(" order by e." + sortColumn + " asc");

    else

    sbQuery.append(" order by e." + sortColumn + " desc");

    query = createQuery(sbQuery.toString(), params2);

    final List<T> resultList = query.getResultList();

    if (log.isTraceEnabled()) {

    log.trace(resultList.size() + " " + entityName + " recovered from database.");

    }

    return resultList;

    }

    }

  2. Creamos el datasource en Jboss:

    Como ya sabréis, para definir un datasource en Jboss nos creamos un fichero descriptor: biblioteca-ds.xml

<?xml version="1.0" encoding="UTF-8"?>

<datasources>

<local-tx-datasource>

<jndi-name>bibliotecaDS</jndi-name>

<connection-url>jdbc:mysql://localhost:3306/biblioteca</connection-url>

<driver-class>com.mysql.jdbc.Driver</driver-class>

<user-name>paco</user-name>

<password>paco</password>

</local-tx-datasource>

</datasources>

Lo desplegamos en el servidor en /<Jboss>/server/default/deploy

Nos creamos el descriptor de persistencia para nuestro Modelo en /src/main/java/META-INF : persistence.xml

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">


<persistence-unit name="biblioteca" transaction-type="JTA">


<!-- Defines the JPA provider. For JBoss you should use Hibernate. -->

<provider>org.hibernate.ejb.HibernatePersistence</provider>


<!-- Defines the datasource to be used by the persistente unit -->

<jta-data-source>java:/bibliotecaDS</jta-data-source>


<!-- As Hibernte is your JPA provider, you can set some Hibernate properties -->

<properties>

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />

</properties>

</persistence-unit>

</persistence>



  1. Vamos a probar esto.

    Ciertamente habría que probar esto bien, con pruebas unitarias, embedded Jboss y todo eso, pero para eso podéis intentarlo vosotros siguiendo el tutorial: http://www.adictosaltrabajo.com/tutoriales/tutorial.php?pagina=ejb3JUnitWithJBoss

    Yo, por motivos de tiempo, voy a preparar una prueba algo más 'cutre':

    Modificamos el código del método test() de la clase TestImpl:

package com.autentia.tutoriales.modelo.services;

import java.util.List;

import javax.ejb.EJB;

import javax.ejb.Stateless;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import com.autentia.tutoriales.modelo.entidades.Autor;

import com.autentia.tutoriales.modelo.entidades.Libro;

import com.autentia.tutoriales.modelo.entidades.Socio;


@Stateless

public class TestServiceImpl implements TestService {

private static Log log = LogFactory.getLog(TestServiceImpl.class);

@EJB

Dao dao;

public String test() {

log.info("Me llaman");

List<Socio> socios = dao.findAll(Socio.class, "nombre", true);

for(Socio socio:socios) {

log.info(socio);

}

List<Libro> libros = dao.findAll(Libro.class, "titulo", true);

for(Libro libro:libros) {

log.info(" ------- " + libro + " ----------- ");

log.info(" AUTORES: ");

for(Autor autor:libro.getAutores()) {

log.info(autor);

}

log.info(" --------------------------------- ");

}

return "Y este es el valor";

}


}



    Mostramos el resultado de la consola al invocar a la página inicial: http://localhost:8080/Web/


    Bueno, en el próximo tutorial de la saga continuaremos tratando de mapear las entidades a la base de datos usando el descriptor 'orm.xml'.

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL: