martes, 20 de septiembre de 2011

GRAILS - Cliente de servicios web con WS-Client

Hoy le toca al turno al plugin WSClient para grails. Utilizando este plugin podremos crear un cliente de un servicio web fácil fácil.

Un ejemplo para ver como funciona.

Primer paso (como siempre), instalarlo

install-plugin ws-client
Ahora la parte interesante... Creamos un controlador y en el método index llamamos a un servicio web que nos devolverá un saludo.
import org.grails.plugins.wsclient.service.WebService

class ClienteController {
    WebService webService

    def index = {
        def wsdlUrl = "http://algundominio.com/services/pruebas?wsdl"
        def proxy = webService.getClient(wsdlUrl)

        String resul = proxy.saluda("Eylen")
        render result
    }
}
El ejemplo es bastante sencillo. En primer lugar definimos la url donde se encuentra el wsdl. A continuación creamos un proxy utilizando el plugin WSClient, al que únicamente necesitamos pasar la url del wsdl.

Una vez tenemos el proxy ya podemos realizar las llamadas a los distintos métodos.

Como apunte extra decir que wsclient y cxf no se llevan muy bien si se instalan en el mismo proyecto, pero según algunas pruebas que he hecho, si se instalan cxf y wsclient (en ese orden) y después se elimina el jar de cxf de WSClient todo parece funcionar bien.

Enjoy!

14 comentarios:

Tengo una dudilla... tengo un webservice en la misma maquina, que quiero consumir.
Si intento acceder al mismo me dice que el puerto ya esta ocupado (imagino que por el servicio)
Que puedo hacer? (ademas de poner el servicio en otra maquina)

Supongo que el problema te lo da al intentar arrancar la segunda aplicación. Yo lo que suelo hacer es arrancarla en otro puerto, puedes mirar aquí cómo se hace, pero abreviando, -Dserver.port=8081 run-app.
Espero que eso te ayude :)

Perfecto! Muchas gracias!

Ahora una nueva duda.
Los ejemplos sencillos funcionan, pero intento enviar un array de Longs (Ids de una base de datos) y me da este error constantemente:

Exception Message: class [Ljava.lang.String; nor any of its super class is known to this context.
Caused by: class [Ljava.lang.String; nor any of its super class is known to this context.

Esto seria la parte 'interesante' del wsdl:













Parece que es un problema de tipos, pero en principio envio un Array de Longs y espero recibir lo mismo...

Y me temo que voy a tener problemas similares cuando intente enviar objetos complejos... :S

Hola,

No veo la parte del wsdl, pero por el error que dices si suena a tipo de datos. ¿Qué le pasas un List, un long[] o qué? Menos problemas suele haber con los arrays normales, pero si necesitas una lista te recomiedo que utilices List no ArrayList ni ninguno de sus subtipos.

En cuanto a los objetos complejos... si te refieres a hashmaps por ejemplo, sí es bastante más complicado, pero si te refieres a pasar tus propios pogos o pojos es bastante simple, ya lo verás.

Un saludo.

Blogger me quita todo lo que este entre etiquetas, asi que te paso el wsdl sin algunos caracteres para que blogger no toque las narices:

xsd:element name="crear"
xsd:complexType
xsd:sequence
xsd:element maxOccurs="1" minOccurs="1" name="nombre" nillable="true" type="xsd:string"/
xsd:element maxOccurs="1" minOccurs="1" name="coches" nillable="true" type="tns:ArrayOfLong"/
/xsd:sequence
/xsd:complexType
/xsd:element


Y el codigo no puede ser mas simplon (tipico ejemplo de entidad "Persona" que tiene asignadas N entidades "Coche"):

def index = {
def wsdlURL = "http://localhost:8080/SimpleWS/services/persona?wsdl"
def proxy = webService.getClient(wsdlURL)

List coches = []
coches.add(1)
coches.add(2)
def result = proxy.crear("Guiller", coches)
result = "Resultado de la operacion: ${result}"
render result
}


El servicio me sigue diciendo que estoy enviando un "ArrayList". Cuando he intentado enviar un Long[] me dice:

Exception Message: class [Ljava.lang.Long; nor any of its super class is known to this context.

Empiezo a desesperar... no puedo creer que sea tan complicado enviar una lista de Longs...

He leido por ahi que se pueden instancias los argumentos (uno a uno) con:

def arg = proxy.create(?)

Evidentemente no entiendo bien que debo poner en ? pero parece que esto podría ser la solución a todos mis problemas.
Perdona si mis preguntas son demasiado básicas pero es que acabo de aterrizar en Grails (bueno, de hecho en Java/Groovy/Grails) desde .Net y ando como pollo sin cabeza...

No obstante, muchisimas gracias por la ayuda... :)

Hola,

Lo que has visto de def arg=proxy.create(?) si no me equivoco es sólo para la parte cliente, o al menos yo sólo lo he usado en la parte cliente. En la ? tendrías que poner el objeto a instanciar, por ejemplo, suponiendo que lo que devuelves es una clase Coche, para crear una instancia de coche podrías hacer proxy.create(namespace.Coche).

En cuanto a lo del array me extraña que te esté dando tanto problemas, mañana si puedo lo miro y te doy una solución.

Saludos

Perdona mi torpeza de nuevo... :S
Si, estoy intentando usar def arg=proxy.create(?) para instanciar en el CLIENTE una clase vacia del servicio (una clase que tengo que ENVIAR) y así garantizar que no tengo problemas con el envío de ningún tipo de datos. Si el plugin me permite conseguir una instancia del objeto que tengo que enviar al servicio no puede haber problemas de tipos... no?

Aun asi... SOY INCAPAZ!!! (AAAAARG!) (Notese mi desesperacion creciente...)

¿Me podrías explicar exactamente qué estás intentando hacer? Es que me estoy liando, no sé si tienes problemas al crear el servidor, si es al crear el cliente...

De todas formas en cuanto encuentre un hueco libre (que ando bastante liada) intento poner un ejemplo un poco más complejo.

Ok. Te explico:

Tengo un servicio Soap con 2 entidades:
- Coche: 2 campos string (modelo y color)
- Persona: Un campo string (nombre) y un array/lista de Longs (los ids de los coches a asignar)

El servidor esta bien. Ningun problema. Lo hago con XFire.

El cliente es es que es fastidioso.
Dar de alta 'coches' esta fácil. Son campos sencillos. Con este trozo de código funciona sin problemas:

import org.grails.plugins.wsclient.service.WebService

class CocheController {
WebService webService

def index = {
def wsdlURL = "http://localhost:8080/SimpleWS/services/coche?wsdl"
def proxy = webService.getClient(wsdlURL)

def result = proxy.crear("Mazda", "Morcado")
result = "Resultado de la operacion: ${result}"
render result
}
}


El problema viene cuando se trata de dar de alta 'Personas'. Haciendolo de un modo homologo al de coches me da problemas de tipos, He probado enviando List, Long[] ... todo lo que se me ha ocurrido... y no hay manera.

Creo que un ejemplo sencillo como este seria de mucha ayuda para mucha gente. La verdad es que no encuentro documentacion y ejemplos algo mas complejos.

Muchas gracias

He intentando hacer este ejemplo, pero me sale este error:
doesnt contain ObjectFactory.class or jaxb.index. Stacktrace follows:

Alguna sugerencia?

Hola,
No sé exactamente por qué te está dando el error, pero sí te voy a decir que el plugin y por tanto este post se han quedado un poco desactualizados. En su lugar te recomiendo que pruebes este otro (que aún no he tenido posibilidad de probar pero sí se de gente que lo ha usado)
http://grails.org/plugin/wslite

wow no esperaba q contestaras :), te comendo antes de pasar a lo q m dices:

Tengo 2 proyectos:

Uno de ellos hace simplemente esto(usa el plugin cfx) y esta arrancado en el puerto 8080
class MiServicioService {

static expose=['cxf']


String hola(String name){
return "Hola"+name
}
}

y el otro proyecto(usa el plugin ws client) y esta arrancado en el puerto 8090

class ClienteController {
def webService

def index() {
def wsdlUrl = "http://localhost:8080/pruebaWS/services/miServicio?wsdl"
def proxy = webService.getClient(wsdlUrl)

String result = proxy.hola("Paco")
render result
}

Pero me da el sgte error:

"pruebaws" doesnt contain ObjectFactory.class or jaxb.index. Stacktrace follows:

Sin embargo si lo llamo desde SOAPUI si que me funciona la llamada

Alguna sugerencia?

Saludos

Pues realmente no te sabría decir, ese mensaje cuando me sale no me ayuda mucho jeje.
Lo único que se me ocurre es que verifiques que estás apuntando a un JDK en lugar de un JRE, que ya me ha pasado alguna vez. Si no es esto, me temo que ahora mismo no puedo ayudarte más, ya lo siento.
Sé que un compañero tuvo problemas hace poco usando este plugin y me suena que le daba el mismo error. Y cambiando al otro que te he comentado pudo hacer las llamadas sin problemas.
Ya me dirás. Suerte!

Publicar un comentario

Twitter Delicious Facebook Digg Stumbleupon Favorites More