style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Servicios Web con Java SE 6 (Parte 4)

Creando un Cliente muy simple para un Servicio Web muy simple

Ahora crearemos (en un directorio/proyecto distinto) el cliente para nuestro Servicio Web el cual debe estar publicado y en ejecución.

Primero necesitamos generar los artefactos cliente. Para ello utilizaremos la herramienta wsimport incluida en Java SE 6.0, a la cual le pasamos como argumento la ubicación del contrato del servicio, es decir el WSDL:

>wsimport http://localhost:8080/hello?wsdl

Esto generará las clases que encapsulan las operaciones para la invocación de los métodos del Servicio Web. En nuestro caso se generarán seis clases dentro del paquete ‘hello’, entre ellas estan las clases hello.HelloService y hello.Hello que utilizaremos directamente en nuestro cliente.

Una vez generados los artefactos cliente solo resta crear el cliente en sí, una simple aplicación de consola:

Listado de Client.java

public class Client {
  public static void main(String[] args) {
    String arg = null;
    String result = null;
    if (args.length > 0) {
      arg = args[0];
    }
    else {
      arg = "Anonimo";
    }
    try {
      hello.HelloService service = new hello.HelloService();
      hello.Hello port = service.getHelloPort();
      result = port.sayHello(arg);
    }
    catch (Exception ex) {
      result = ex.toString();
    }
    finally{
      System.out.println(result);
    }
  }
}

Nótese que para invocar la operación del Servicio Web primero creamos el localizador del servicio (con HelloService) y mediante éste obtenemos un puerto (de tipo Hello) por medio del cual se invoca al método sayHello —tras del cual se invoca la operación del Servicio Web el cual a su vez invoca el método de la clase Hello implementada al inicio…

Solo resta compilar y ejecutar nuestro cliente con algún argumento, su nombre por ejemplo, si no especifica argumento alguno la salida será “Hola Anonimo”:

>javac Client.java
>java Client Yo
Hola Yo.

La misma salida se desplegará en la consola del servicio.

Epílogo

Con todo lo que hemos visto hasta el momento vemos lo fácil que es crear y publicar un Servicio Web así como su cliente con los paquetes y herramientas de JAX-WS incluidos en Java SE 6.0. No obstante para un despliegue en producción no podemos prescindir de los contenedores Java EE (Tomcat, Glassfish, JBoss etc…) pero para fines de desarrollo de prototipos —y proyectos escolares— es suficiente con lo incluido en Java SE 6.0.

Así pues ésto sólo fue el inicio, la finalidad fue dar una introducción en el desarrollo de Servicios Web utilizando JAX-WS esperando les motive a continuar para después "abordar el Metro". Quedan muchas cosas por ver, como la automatización de las tareas que realizamos, crear un servicio y cliente a partir de un WSDL, el despliegue en contenedores Java EE, utilizar contratos de datos y JAXB, utilización de JAXP, StAX y SAAJ, interoperabilidad y WS-* con WSIT, etc. Ya ni se diga de explorar otras opciones para el desarrollo de WS en Java como XMLBeans, AXIOM, etc...

Espero que sirva de algo y hasta la próxima
Willy Mejía.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

JAX-WS

Que tal Willy he visto los post que has puesto respecto a web services dado que es algo que desean implementar y realmente soy nuevo en ésta parte, te comento mi problema espero puedas echarme una idea por dónde empezar.
1 Tengo un web service creado con sybase que me regresa un xml con los datos de varios clientes
2 Se desea consumir ese web service mediante J2EE aqui es dónde me he puesto a investigar pero desgraciadamente no he podido encontrar información explícita acerca de manipular ese contenido sólo he visto ejemplos de como crear un web service pero no consumirlo.
3 Mencionas que no es necesario usar J2EE para consumir un web service, supongo que en ésta parte si tendría que usar contenedores para poder manipularlo o si estoy equivocado espero puedas orientarme en éste aspecto.

Te agradezco mucho y parece pintar para algo interesante ésta tecnología nueva para mi.
Saludos cordiales.

Mariots.

Imagen de ezamudio

Configuración

Muy interesante post. Decidí probarlo para invocar un web service que tengo que llamar desde una app de Java SE, en vez de usar Axis 2. Resulta más compacta y el classpath se simplifica bastante. Sin embargo, no encuentro que se pueda tener un control muy fino de las opciones del web service; por ejemplo, en Axis2 podía invocar en mi web service stub _getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED, false) para indicar que no quiero enviar la petición por partes sino que tiene que salir toda de golpe.
Ahora parece que el web service está escribiendo por partes sus datos, pero encuentro en dónde desactivar esta misma propiedad en el código generado por el wsimport de Java 6...

Imagen de ezamudio

Transfer-Encoding: chunked

Por default los web services de Axis y los generados ahora por este wsimport, usan el Transfer-Encoding: chunked. Y resulta que los web services hechos en .NET normalmente no soportan eso (o es el ISS, o alguna tarugada de Microsoft para variar). La cosa es que si quieren deshabilitar el chunked en Axis ya lo puse en mi respuesta anterior en este mismo post, pero para deshabilitarlo en web services generados por wsimport, es un poco más complicado.

Después de estar buscando durante horas, me encontré con que Apache tiene un proyecto llamado CXF, el cual interactua con JAX-WS y nos permite deshabilitar lo del chunked (y seguramente hacer otras cosas más) de la siguiente manera:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;

//Suponiendo que la variable "service" es el puerto del web service generado...
//siguiendo el ejemplo original de willyxoft seria la variable "port" de tipo hello.Hello
Client _client = ClientProxy.getClient(port);
HTTPConduit httpConduit = (HTTPConduit)_client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setAllowChunking(false);
httpConduit.setClient(httpClientPolicy);

Espero que esto le sirva a alguien para que no se tenga que estar quebrando la cabeza el dia que invoquen un web service de .NET y no se puedan comunicar por el maldito "chunked", esto les va a ahorrar horas de estar buscando la solución.

En la clase de Cliente me aparce un error

Hola que tal, espero que te encuentres bien.

Te comento segui al pie de la letra tu blog para web service y al final en la clase cliente cuando la ejecuto me aparece el siguiente error y no se a ¿que a se deba?

java.lang.IllegalArgumentException: paquete.Hola is not an interface

y en el navegador me aparece

Web Services
No JAX-WS context information available.

Imagen de ezamudio

Proxy dinámico

Lo de web services en Java 6 funciona gracias a los proxies dinámicos, pero efectivamente sólo se pueden usar para envolver objetos que implementan al menos una interfaz. Falta definir una interfaz que implemente los métodos de la clase Hello (que supongo hugo renombró a paquete.Hola).

Puede un web service en java retornar tipos complejos?

Saludos a todos,

Estoy haciendo mi primer web service en java, el entorno que utilizo es:

Netbeans 6.8.

Glassfish 3.0(viene instalado por defecto en el IDE).

JRE 1.6.

Pero se me ha presentado un problemón que no logro resolver, y es el siguiente:

Creo mi servicio web desde netbeans, luego creo en este un metodo que retorna tipos primitivos por ejemplo un Integer, le doy clic derecho y pruebo el web service y funcion a las mil maravillas.

Sin embargo genero un metodo que devuelve un listado de personas usando ArrayList o cualquier otro tipo de estructura Vector, List, etc. El caso es que cuando le doy clic derecho---> Test Web service me da el error siguiente:

Primero muestra un mensaje diciendo: Unable to Open web service tester Page y que verifique que el web service se desplego correctamente, verifico y si esta desplegado sin problemas.

Luego si intento probarlo nuevamente me muestra este error en el navegador:
Exceptions details : nulljava.lang.NullPointerException at java.io.File.(File.java:222) at org.glassfish.webservices.monitoring.WebServiceTesterServlet .initializePort(WebServiceTesterServlet.java:505) at org.glassfish.webservices.monitoring.WebServiceTesterServlet .doGet(WebServiceTesterServlet.java:165) at org.glassfish.webservices.monitoring.WebServiceTesterServlet .invoke(WebServiceTesterServlet.java:100) at org.glassfish.webservices.JAXWSServlet.doGet(JAXWSServlet.ja va:193) at javax.servlet.http.HttpServlet.service(HttpServlet.java:734) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) at org.apache.catalina.core.StandardWrapper.service(StandardWra pper.java:1523) at org.apache.catalina.core.StandardWrapperValve.invoke(Standar dWrapperValve.java:279) at org.apache.catalina.core.StandardContextValve.invoke(Standar dContextValve.java:188) at org.apache.catalina.core.StandardPipeline.invoke(StandardPip eline.java:641) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:9 7) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invo ke(PESessionLockingStandardPipeline.java:85) at org.apache.catalina.core.StandardHostValve.invoke(StandardHo stValve.java:185) at org.apache.catalina.connector.CoyoteAdapter.doService(Coyote Adapter.java:332) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAd apter.java:233) at com.sun.enterprise.v3.services.impl.ContainerMapper.service( ContainerMapper.java:165) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTa sk.java:791) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.j ava:693) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.jav a:954) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultPr otocolFilter.java:170) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(D efaultProtocolChain.java:135) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocol Chain.java:102) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocol Chain.java:88) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolC hain.java:76) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChai nContextTask.java:53) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyCon textTask.java:57) at com.sun.grizzly.ContextTask.run(ContextTask.java:69) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(Abstra ctThreadPool.java:330) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractT hreadPool.java:309) at java.lang.Thread.run(Thread.java:619)

Error que no se que rayo es, solo me dice que hay un puntero NULL, pero les confieso que mi m'etodo lo unico que hace es lo siguiente:

@WebMethod(operationName = "getUsuario")
public Usuario getUsuario(@WebParam(name = "name")
String name) {

Usuario user = new Usuario("pepe", "perez");
return user;
}

Mi pregunta es que si se es posible retornar un arreglo de objetos o un objeto creado por mi, a traves de un web service. Aclaro que he buscado en internet muchos ejemplos, donde si los devuelven, pero nadie hace referencia a ese error que me da a mi. Ese error ocurre repito siempre que creo un metodo en el web service que retorna un objeto de una clase creada por mi. No se si es que debo hacer alg mas al desplegar el webservice, pero todos los ejemplos que encuentro he visto que devuelven objetos complejos creados por ellos mismos. Por favor denme una ayudita con este tema.

Si elimino ese metodo el web service funciona sin problemas.

Imagen de ezamudio

sí, sí puede

Yo he usado varios web services que retornan objetos que son contenedores de datos, algunos de los cuales incluso pueden ser más objetos que sean contenedores de datos.

Imagen de macaruchi

WebService

Probe todo el ejemplo y funciona perfecto. Pude publicar el WS con javaSE6.0 sin problemas y tambien consumirlo. Pero al tratar de consumirlo desde otra maquina usando http://ipserver:8080/wsdl? me refused la conexion.

Usando este metodo solo se pueden crear WS para ser consumidos localmente , es decir, http://localhost:8080/hello?wsdl??

equijada@utesa:~/wscliente$ wsimport <a href="http://10.0.0.46:8000/hello?wsdl
parsing"
title="http://10.0.0.46:8000/hello?wsdl
parsing"
>http://10.0.0.46:8000/hello?wsdl
parsing</a> WSDL...

[ERROR] Connection refused

Failed to read the WSDL document: <a href="http://10.0.0.46:8000/hello?wsdl" title="http://10.0.0.46:8000/hello?wsdl">http://10.0.0.46:8000/hello?wsdl</a>, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not <wsdl:definitions>.

[ERROR] failed.noservice=Could not find wsdl:service in the provided WSDL(s):

 At least one WSDL with at least one service definition needs to be provided.

        Failed to parse the WSDL.
equijada@utesa:~/wscliente$

EL 8000 es que cambie de puerto*

Como podria poner este ejemplo en Tomcat, para usarlo desde cualquier lugar ?

Gracias

Imagen de neko069

@macaruchi

De tu URL cambia "localhost" por la ip de la máquina donde levantas tu WebService, y todas las máquinas deben referirse a ésa URL para construir el cliente..

Imagen de ezamudio

firewall?

Tal vez tienes un firewall o alguna otra cosa. El web service debe poder ser consumido de manera remota (tan es así que ni siquiera lo definiste como 127.0.0.1:8000 sino con la IP local de tu maquina; en la práctica le pones ahí el dominio o IP pública desde donde va a estar accesible)

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">