viernes, 6 de septiembre de 2013

Como crear servicios web con Tapestry5 y JAXB


En las anteriores entradas del blog que hablábamos de JAXB hemos mostrado como realizar las operaciones de marshalling y unmarshalling, es decir como obtener archivos XML a partir de una serie de objetos y como obtener una colección de objetos a partir de ficheros XML. Podéis encontrar el primer post de la serie (aquí)
Ahora vamos a implementar un servicioWeb en Tapestry usando JAXB y las clases que nos creamos en los post anteriores. Primero vamos a crear un servicio web que nos devuelva todas las direcciones que tenemos almacenadas en la base de datos. Para ello vamos a usar las clases Direccion.java y DireccionResponse.java. Si recordamos, Direccion.java mapeaba mediante Hibernate la tabla direccion de PostgreSQL mientras que DireccionResponse.java nos permitía crearnos un único objeto que contenía una lista de objetos Direccion de modo que al marshall de JAXB solamente le pasábamos un objeto. Estas dos clases las tenemos en la carpeta entities de nuestro proyecto y su contenido es el siguiente. Primero Direccion.java:


import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@SequenceGenerator(
    name="direccion_seq",
    sequenceName="direccion_seq",
    initialValue=1,
    allocationSize=1
)

@XmlRootElement
@Table(name = "direccion")
public class Direccion {
   
    private static final long serialVersionUID = 1L;
   
    protected long id;
    protected String calle;
    protected String codPostal;
    protected String localidad;
    protected String pais;
    protected String telf1;
    protected String telf2;
    protected String email1;
    protected String email2;
    protected String fax;
    protected Cliente cliente;

    public Direccion() {
        super();
    }
   
    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="direccion_seq")
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
   
    public String getCalle() {
        return calle;
    }

    public void setCalle(String direccion) {
        this.calle = direccion;
    }

    public String getCodPostal() {
        return codPostal;
    }

    public void setCodPostal(String codPostal) {
        this.codPostal = codPostal;
    }

    public String getLocalidad() {
        return localidad;
    }

    public void setLocalidad(String localidad) {
        this.localidad = localidad;
    }

    public String getPais() {
        return pais;
    }

    public void setPais(String pais) {
        this.pais = pais;
    }

    public String getTelf1() {
        return telf1;
    }

    public void setTelf1(String telf1) {
        this.telf1 = telf1;
    }

    public String getTelf2() {
        return telf2;
    }

    public void setTelf2(String telf2) {
        this.telf2 = telf2;
    }

    public String getEmail1() {
        return email1;
    }

    public void setEmail1(String email1) {
        this.email1 = email1;
    }

    public String getEmail2() {
        return email2;
    }

    public void setEmail2(String email2) {
        this.email2 = email2;
    }

    public String getFax() {
        return fax;
    }

    public void setFax(String fax) {
        this.fax = fax;
    }   
   
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cliente_id")
    public Cliente getCliente() {
        return cliente;
    }
    public void setCliente(Cliente cliente) {
        this.cliente = cliente;
    }
}
Ahora la clase DireccionResponse.java:

import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class DireccionResponse {

    private List<Direccion> direcciones;
   
    public void setList(List<Direccion> direcciones){
        this.direcciones = direcciones;
    }
   
    public List<Direccion> getList(){
        return direcciones;
    }
   
    public void add(Direccion direccion) {
        direcciones.add(direccion);
    }
}
Para la creación del servicio web en Tapestry5 vamos a crearnos una clase que se llama DireccionesFind.java en la carpeta pages de nuestro proyecto. De esta forma en la ruta http://localhost:8080/proyecto/direccionesfind tendremos montado un servicio web que nos devolverá todas las direcciones que tenemos almacenadas en XML. La clase DireccionesFind devolverá en el onActivate un objeto que será del tipo StreamResponse. Para ello tenemos que implementar un método llamado prepareResponse que será donde se implemente la funcionalidad que estamos buscando. El código que tenemos que crear será el siguiente:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

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

import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Response;

import org.hibernate.Criteria;
import org.hibernate.Session;

import com.ctnaval.noise.entities.Direccion;
import com.ctnaval.noise.entities.DireccionResponse;

public class DireccionesFind {
   
@Inject
private Session session;
   
Object onActivate() {
   
return new StreamResponse() {
     private InputStream inputStream;
       
public void prepareResponse(Response response) {
               
Criteria crit = session.createCriteria(Direccion.class);
               
Iterator it = crit.list().iterator();
List<Direccion> direccionesList = new ArrayList<Direccion>();
               
while (it.hasNext()){
     direccionesList.add((Direccion) it.next());
}
               
DireccionResponse dr = new DireccionResponse();
dr.setList(direccionesList);
              
try {
JAXBContext context = JAXBContext.newInstance(DireccionResponse.class);
Marshaller marshaller = context.createMarshaller();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(dr, outputStream);
inputStream = new ByteArrayInputStream(outputStream.toByteArray());

// Set content length to prevent chunking - see
// http://tapestry-users.832.n2.nabble.com/Disable-Transfer-Encoding-chunked-from-StreamResponse-td5269662.html#a5269662
response.setHeader("Content-Length", "" + outputStream.size());
}
catch (JAXBException e) {
    throw new IllegalStateException(e);
}
}
           
public String getContentType() {
     return "text/xml";
}

public InputStream getStream() throws IOException {
   return inputStream;
}   
};
}
}
Podemos observar como tenemos una primera parte similar a la empleada en este post (aquí) para traernos todas las direcciones mediante un Criteria de la tabla direccion y como mediante una lista nos creamos un objeto DireccionResponse.  Después la salida del marshall la enviamos a través de un ByteArrayOutputStream y de esta forma ya tenemos nuestro servicio web publicado. Ahora si cargamos la url http://localhost:8080/proyecto/direccionesfind podemos ver algo como mostramos a continuación:


En el siguiente post explicaremos como consumir este servicio web empleando también Tapestry.

No hay comentarios :

Publicar un comentario