Thursday, October 14, 2010

Envío de ficheros con WS usando jaxb

Siguiendo el tutorial anterior, vamos a comentar como se puede enviar un fichero. Filosóficamente, un Web service solamente debería se posible enviar datos en ascii, ya que cada uno bajo su plataforma implementa las funcionalidades de los WS sabiendo que son simplemente texto.

Para definir un Web service como comentaba en el anterior tutorial solamente definimos un pojo con la siguiente etiqueta
@WebService
public class SendFile{
}
después implementamos un método con los siguientes parámetros

public boolean send(
@WebParam(name="steamFile")
@XmlMimeType("application/octet-stream") DataHandler data,
@WebParam(name="nameFile") String  fileName,
@WebParam(name="extension")String  extension)
throws ReturnError {


try {
if(data.getInputStream().available()>0){
                            ///leer el fichero
                        }else{
                           throw new ReturnError ("fichero vacio");
                        }
} catch (IOException e) {

ReturnError err =new ReturnError ();
err.initCause(e);
throw err;
}
}


el objeto DataHandler  encapsula el tratamiento del fichero.

simplemente ahora generamos todo el código con wsgen, y generamos el cliente con wsimport.
lo desplegamos en nuestro servidor de aplicaciones favorito. y a jugar.




Wednesday, October 6, 2010

Creación de ws con JAXWS

Estoy maravillado por lo fácil que es crear un WS en java, nada de AXIS2 ni cosas por el estilo. Con JAXWS es casi trivial.

Te creas un interface, siempre viene bien definir un contrat, aunque no es necesario.

public interface ILeerSensor {
   public abstract int dameLaTemperatura(String nombreDelSensor) throws SensorError;

}

Implementas el servicio


import javax.jws.WebParam;
import javax.jws.WebService;



@WebService
public class LeerSensorImpl implements ILeerSensor {

    public int dameLaTemperatura(@WebParam(name="nombreDelSensor") String nombreDelSensor) throws SensorError{
      
       return Sensor.find(nombreDelSensor).getTemperatura();


    }
}


creamos el WS
ejecutas esta simple instrucción:
wsgen -cp src\main\java;target\classes  -d target/web-classes -verbose -r src\main\webapp\WEB-INF\wsdl -wsdl pais.compania.proyecto.server.ws.LeerSensorImpl

Con esto se genera la estructura para generar un WS. Luego hay que empaquetarlo en un war para publicarlo en el servidor Tomcat o JBoss.

creamos el cliente

wsimport -p pais.compania.proyecto.cliente.ws -s src\main\java -d target\classes http://ip:port/nombreDelWar/LeerSensorImpl?wsdl

Nos genera unas clases por cada servicio. Y solamente hay que usarlo.


Problemas que me he encontrado:

Problema:
Si generas varios WS con nombre de objetos reutilizados, estos objetos no son los mismos. Es decir, la clase SensorError, si se usa en varios WS, genera tantas clases como WS (no metodos) implementes. No se como usar solo uno, ya que uso distintos paquetes y da error de "cast". Además si quieres pasar como parámetro a un WS una clase que te ha devuelto otro WS tienes que convertir a mano estos objetos que a priori son iguales.

Solución: Hacer un Wrapper para cada tipo de objeto.


Problema:
Si al crear una interfaz pones como valor de retorno un objeto List,  y luego en la signatura de la implementación devuelves un ArrayList, que implementa un List, todo funciona menos al generarte el cliente que consume el servicio.

Solución:
Poner tal cual la implementacion del interfaz, es decir si decimos que devolvemos un List en la interfacedevolver un List en la signatura de la implementación.


Problema:
Al generar los WS y los clientes, se pierden los nombres de los parametros en los métodos del WS.
Solución
Hay que poner explicitamente  @WebParam(name="nombreDelSensor") si quieres que te salga en eclipse el nombre del parámetro.