Empece este blog para guardar los descubrimientos en programacion que hago cuando tengo un error y por mas que busco en san Google, no encuentro nada hasta despues de horas de andar buscando y horas de prueba y error. Si a alguien algun dia le sirve, que bueno. En general es para mi porque se me olvidan muchos de estos descubrimientos.

Monday, January 30, 2012

Web Service clients desde command line

Webservices, webservices, porque me dificultas tanto la vida? Esta bien, son un reto, son algo nuevo para mi y mantienen las cosas interesantes. Aunque me estoy quejando de webservices y realmente son los clients los que han sido dolores de cabeza. En el pasado escribi un post de como generar clientes en ADB y en xmlBeans con el Axis2 Code Generator Eclipse plugin. Al tener otro problema con estos clientes, tuve que irme por la solucion de clientes generados por linea de comando.

En general es muy sencillo. Estoy segura que hay mas informacion al respecto pero he aqui lo esencial.

Descargar las librerias de Axis2. Trata siempre de estar actualizando ya que Axis pasa corrigiendo bugs conocidos que probablemente sean los que te estan dando problemas.

Abres una consola DOS y navegas hasta llegar al directory donde tienes tus librerias Axis2. Navega hasta la carpeta bin. escribe el siguiente comando:
WSLD2JAVA -uri http://EndpointDelWebService?wsdl

Hay mas comandos que puedes agregar a esta sentencia para especificar databinding (ADB es el default en esta generacion tambien), ruta en donde poner las clases generadas, etc. Para mas informacion puedes buscar aqui: http://axis.apache.org/axis2/java/core/docs/reference.html

Navega en la carpeta bin y copia las tareas generadas (clases JAVA). Copia las clases en algun proyecto donde desees el webclient (En este caso no tenemos problemas poniendolo en un Java Project que te permite usar este .jar para cualquier proyecto que requiera usar ese cliente).

Siempre requeriras crear clases para consumir las clases generadas. En mi caso siempre necesito un ConectionStud manager y un PasswordCallbackHandler. Las clases son un poco bruscas a mi parecer ya que generan casi todo el codigo en una sola clase, pero si necesitas entrar al codigo para hacer cambios, el codigo generado es un poco mas facil de seguir y cambiar que las clases generadas por los Eclipse code generator plugins.

En una nota aparte, tambien tuvimos problemas con el policy del webservice. Por lo general, el policy va dentro del request cuando envias el user y password. En este caso tuvimos problemas porque el webservice nos retornaba que no encontraba el policy. Se tuvo que crear .xml que llevara el policy con el username de nuestro cliente para poder solucionar este problema. Ejemplo de Policy:


<?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy wsu:Id="wss_username_token_service_policy"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken>TuUserName</sp:WssUsernameToken>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SupportingTokens>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>TuUserName</ramp:user>
<ramp:passwordCallbackClass>package.claseDeTuCallBackHandler</ramp:passwordCallbackClass>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>


Como puedes ver en el ejemplo, se utiliza ramparta para el manejo de autenticacion por lo que necesitaras el modulo rampart (yo utilizo el 1.4 aunque no es el ultimo) y agregar las librerias de rampart.

Para el uso de este, debes configurar apache.axis2.client.options en el ConectionStud Manager.
Aqui un pequeño ejemplo:


 ClientGeneradoStub result = new  ClientGeneradoStub  ();
 ServiceClient sc = result.getServiceClient();
 Options options = new Options();
 options.setUserName("TuUserName");
 options.setTo(new EndpointReference(endPoint));
 options.setProperty(RampartMessageData.KEY_RAMPART_POLICY,  loadPolicy(repositoryPath + "policy/policy.xml"));
 sc.setOptions(options);
 sc.engageModule("rampart");


  private static Policy loadPolicy(String xmlPath) throws Exception {
StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
 return PolicyEngine.getPolicy(builder.getDocumentElement());
 }

Ahora, en el llamado al loadPolicy mandas el directorio en donde se encuentras tu archivo policy.xml (o como tu lo nombraste). Yo agregaba esto al directorio: "policy\\policy.xml" y funcionaba perfectamente. Sin embargo, una vez en produccion, el cliente se volvio a quejar que no encontraba el policy. Crei que el problema era de permisos de carpeta y no lei el policy porque no podia. El problema era de sintaxis. Un amable compañero descubrio que la sintaxis correcta era:   "policy/policy.xml". Mi sintaxis corria perfectamente en windows, pero la sintaxis del compañero corria en windows y linux y voila!

Bueno, ahi sigo con los exploits en el mundo de webservices. Espero esto te ayude!

2 comments:

  1. Hola, no sabes lo útil que me está siendo tu blog. Pero tengo una duda, igual me la sabes responder...
    Resulta que quiero acceder a un web service a través de wdsl. Lo estoy programando en java embebido en Matlab. El caso es que conecta bien y manda el mensaje de petición, pero a la hora de recibir el mensaje, salta el siguiente error: "SOAP Fault: org.apache.axis2.databinding.ADBException: Unexpected subelement
    HistoricRequest"
    ¿Sabes si puede ser que tengo mal instaladas las librerías de axis2? ¿Qué otra cosa puede ser?
    Mil gracias de antemano.
    Saludos!

    María

    ReplyDelete
  2. Hola Maria, no me he encontrado con ese error, lo siento.

    ReplyDelete