¿Cómo configuro el tiempo de espera para un cliente de servicio web JAX-WS?

93

He usado JAXWS-RI 2.1 para crear una interfaz para mi servicio web, basada en un WSDL. Puedo interactuar con el servicio web sin problemas, pero no he podido especificar un tiempo de espera para enviar solicitudes al servicio web. Si por alguna razón no responde, el cliente parece girar sus ruedas para siempre.

La búsqueda ha revelado que probablemente debería intentar hacer algo como esto:

((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.ws.request.timeout", 10000);
((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.ws.connect.timeout", 10000);

También descubrí que, según la versión de JAXWS-RI que tenga, es posible que deba establecer estas propiedades en su lugar:

((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 10000);
((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", 10000);

El problema que tengo es que, independientemente de cuál de las anteriores sea correcta, no sé dónde puedo hacer esto. Todo lo que tengo es una Servicesubclase que implementa la interfaz generada automáticamente para el servicio web y en el punto en que esto se está instanciando, si el WSDL no responde, entonces ya es demasiado tarde para establecer las propiedades:

MyWebServiceSoap soap;
MyWebService service = new MyWebService("http://www.google.com");
soap = service.getMyWebServiceSoap();
soap.sendRequestToMyWebService();

¿Alguien puede señalarme en la dirección correcta?

de nueve lados
fuente
5
No creo que tenga una respuesta para usted, pero su pregunta me ayudó a resolver mi problema. Sabía sobre la propiedad com.sun.xml.ws.request.timeout pero no sobre la propiedad com.sun.xml.internal.ws.request.timeout.
Ron Tuffin

Respuestas:

90

Sé que esto es antiguo y se ha respondido en otro lugar, pero espero que esto lo cierre. No estoy seguro de por qué querría descargar el WSDL dinámicamente, pero las propiedades del sistema:

sun.net.client.defaultConnectTimeout (default: -1 (forever))
sun.net.client.defaultReadTimeout (default: -1 (forever))

debería aplicarse a todas las lecturas y conexiones mediante HttpURLConnection que utiliza JAX-WS. Esto debería resolver su problema si obtiene el WSDL desde una ubicación remota, ¡pero un archivo en su disco local probablemente sea mejor!

A continuación, si desea establecer tiempos de espera para servicios específicos, una vez que haya creado su proxy, debe enviarlo a un BindingProvider (que ya conoce), obtener el contexto de la solicitud y establecer sus propiedades. La documentación de JAX-WS en línea es incorrecta, estos son los nombres de propiedad correctos (bueno, funcionan para mí).

MyInterface myInterface = new MyInterfaceService().getMyInterfaceSOAP();
Map<String, Object> requestContext = ((BindingProvider)myInterface).getRequestContext();
requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 3000); // Timeout in millis
requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 1000); // Timeout in millis
myInterface.callMyRemoteMethodWith(myParameter);

Por supuesto, esta es una forma horrible de hacer las cosas, crearía una buena fábrica para producir estos proveedores de enlace que se pueden inyectar con los tiempos de espera que desee.

alpian
fuente
10
Tenga en cuenta que las propiedades REQUEST_TIMEOUT / CONNECT_TIMEOUT en realidad se heredan de la clase interna de SUN com.sun.xml.internal.ws.developer.JAXWSProperties y (al menos en Linux de 32 bits) javac 1.6.0_27 y javac 1.7.0_03 fallan al compile este código (similar a bugs.sun.com/view_bug.do?bug_id=6544224 ) ... necesita pasar -XDignore.symbol.file a javac para que funcione.
JavaGuy
¿Qué no funciona? Acabo de verificar esto y me está funcionando.
alpian
Solo confirmo que acabo de usar esto con JAX-WS RI 2.2.8 y JDK 1.7 y funcionó bien. ¡Gracias!
bconneen
Las clases y parámetros que tienen "interno" en su nombre completo, no deben usarse, ya que dependen del proveedor y, por lo tanto, no son portables entre diferentes implementaciones de JDK. En el caso de los parámetros jax-ws, por ejemplo, las propiedades no internas correspondientes existen en la clase com.sun.xml.ws.client.BindingProviderProperties.
Polaretto
1
@ Matt1776 sí, por supuesto que falta: si bien JAX-WS es una especificación de API, necesita una implementación de biblioteca, en este caso jaxws-ri.jar o jaxws-rt.jar, que no es parte del JDK. Solo necesita descargarlo y agregarlo a su ptoject y tendrá esas propiedades disponibles.
polaretto
41

Las propiedades en la respuesta aceptada no me funcionaron, posiblemente porque estoy usando la implementación JBoss de JAX-WS.

El uso de un conjunto diferente de propiedades (que se encuentran en la Guía del usuario de JBoss JAX-WS ) lo hizo funcionar:

//Set timeout until a connection is established
((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", "6000");

//Set timeout until the response is received
((BindingProvider) port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", "1000");
jwaddell
fuente
2
No estoy usando JBoss, pero solo las propiedades en este comentario funcionaron para mí, nada más funcionó.
PaulP
2
Los nombres de las propiedades dependen de la implementación de JAX-WS. Puede encontrar una lista aquí: java.net/jira/browse/JAX_WS-1166
fabstab
3
El enlace de java.net está roto. github.com/javaee/metro-jax-ws/issues/1166
trunkc
12

Aquí está mi solución de trabajo:

// --------------------------
// SOAP Message creation
// --------------------------
SOAPMessage sm = MessageFactory.newInstance().createMessage();
sm.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
sm.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");

SOAPPart sp = sm.getSOAPPart();
SOAPEnvelope se = sp.getEnvelope();
se.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
se.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");

SOAPBody sb = sm.getSOAPBody();
// 
// Add all input fields here ...
// 

SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
// -----------------------------------
// URL creation with TimeOut connexion
// -----------------------------------
URL endpoint = new URL(null,
                      "http://myDomain/myWebService.php",
                    new URLStreamHandler() { // Anonymous (inline) class
                    @Override
                    protected URLConnection openConnection(URL url) throws IOException {
                    URL clone_url = new URL(url.toString());
                    HttpURLConnection clone_urlconnection = (HttpURLConnection) clone_url.openConnection();
                    // TimeOut settings
                    clone_urlconnection.setConnectTimeout(10000);
                    clone_urlconnection.setReadTimeout(10000);
                    return(clone_urlconnection);
                    }
                });


try {
    // -----------------
    // Send SOAP message
    // -----------------
    SOAPMessage retour = connection.call(sm, endpoint);
}
catch(Exception e) {
    if ((e instanceof com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl) && (e.getCause()!=null) && (e.getCause().getCause()!=null) && (e.getCause().getCause().getCause()!=null)) {
        System.err.println("[" + e + "] Error sending SOAP message. Initial error cause = " + e.getCause().getCause().getCause());
    }
    else {
        System.err.println("[" + e + "] Error sending SOAP message.");

    }
}
vnoel
fuente
3
¿Son estas configuraciones equivalentes a "javax.xml.ws.client.connectionTimeout" y "javax.xml.ws.client.receiveTimeout"?
José Tepedino
11
ProxyWs proxy = (ProxyWs) factory.create();
Client client = ClientProxy.getClient(proxy);
HTTPConduit http = (HTTPConduit) client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
http.setClient(httpClientPolicy);

Esto funcionó para mí.

Daniel Kaplan
fuente
¡Gracias! Para mí también, es una manera muy fácil
kosm
4
Sin embargo, esto usa clases de Apache CXF, podría ser mejor agregar esto en la respuesta. Un enlace en el que los frascos CXF los contengan también ayudaría mucho.
JBert
@JBert Estoy de acuerdo. Respondí esto hace años y no puedo recordar. Siéntase libre de editar la respuesta.
Daniel Kaplan
8

Si está utilizando JAX-WS en JDK6, utilice las siguientes propiedades:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout
Domenico Briganti
fuente
System.setProperty ("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty ("com.sun.xml.internal.ws.request.timeout", "300") funcionó para mí.
2787184
2
En algunos contextos, no sabe en tiempo de programación qué versión de JAXWS (interna o independiente) se utilizará en tiempo de ejecución. Los dos son bastante compatibles, excepto por esta función de tiempo de espera. Las claves son diferentes ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout) también la clase (o interfaz) que las define ( com.sun.xml.internal.ws.developer.JAXWSProperties/ com.sun.xml.internal.ws.client.BindingProviderPropertiesvs com.sun.xml.ws.developer.JAXWSProperties/ com.sun.xml.ws.client.BindingProviderProperties). Mi mejor idea es configurar ambos, usando valores literales como claves.
Lorinczy Zsigmond
5

En caso de que su servidor de aplicaciones sea WebLogic (para mí fue 10.3.6), las propiedades responsables de los tiempos de espera son:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout
E.Egiazarov
fuente
3

No estoy seguro de si esto ayudará en su contexto ...

¿Se puede convertir el objeto soap como BindingProvider?

MyWebServiceSoap soap;
MyWebService service = new MyWebService("http://www.google.com");
soap = service.getMyWebServiceSoap();
// set timeouts here
((BindingProvider)soap).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 10000);
    soap.sendRequestToMyWebService();

Por otro lado, si desea establecer el tiempo de espera en la inicialización del objeto MyWebService, esto no ayudará.

Esto funcionó para mí cuando quería agotar el tiempo de espera de las llamadas individuales de WebService.

Ron Tuffin
fuente
2

La forma más fácil de evitar la recuperación lenta del WSDL remoto cuando crea una instancia de su SEI es no recuperar el WSDL del punto final del servicio remoto en tiempo de ejecución.

esto significa que debe actualizar su copia WSDL local cada vez que el proveedor de servicios realiza un cambio impactante, pero también significa que debe actualizar su copia local cada vez que el proveedor de servicios realiza un cambio impactante.

Cuando genero mis stubs de cliente, le digo al tiempo de ejecución de JAX-WS que anote el SEI de tal manera que lea el WSDL desde una ubicación predeterminada en la ruta de clases. por defecto, la ubicación es relativa a la ubicación del paquete del Servicio SEI


<wsimport
    sourcedestdir="${dao.helter.dir}/build/generated"
    destdir="${dao.helter.dir}/build/bin/generated"
    wsdl="${dao.helter.dir}/src/resources/schema/helter/helterHttpServices.wsdl"
    wsdlLocation="./wsdl/helterHttpServices.wsdl"
    package="com.helter.esp.dao.helter.jaxws"
    >
    <binding dir="${dao.helter.dir}/src/resources/schema/helter" includes="*.xsd"/>
</wsimport>
<copy todir="${dao.helter.dir}/build/bin/generated/com/helter/esp/dao/helter/jaxws/wsdl">
    <fileset dir="${dao.helter.dir}/src/resources/schema/helter" includes="*" />
</copy>

el atributo wsldLocation le dice al SEI dónde se puede encontrar el WSDL, y la copia se asegura de que el wsdl (y el xsd de soporte, etc.) esté en la ubicación correcta.

dado que la ubicación es relativa a la ubicación del paquete de SEI, creamos un nuevo subpaquete (directorio) llamado wsdl, y copiamos todos los artefactos wsdl allí.

todo lo que tiene que hacer en este punto es asegurarse de incluir todos los * .wsdl, * .xsd además de todos los * .class cuando cree su archivo jar de artefactos de resguardo de cliente.

(en caso de que tenga curiosidad, la anotación @webserviceClient es donde esta ubicación wsdl se establece realmente en el código java

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")
Helter Scelter
fuente