Comment définir le délai d'expiration d'un client de service Web JAX-WS?

93

J'ai utilisé JAXWS-RI 2.1 pour créer une interface pour mon service Web, basée sur un WSDL. Je peux interagir avec le service Web sans problème, mais je n'ai pas été en mesure de spécifier un délai d'expiration pour l'envoi des demandes au service Web. Si, pour une raison quelconque, il ne répond pas, le client semble juste faire tourner ses roues pour toujours.

La chasse a révélé que je devrais probablement essayer de faire quelque chose comme ceci:

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

J'ai également découvert que, selon la version de JAXWS-RI dont vous disposez, vous devrez peut-être définir ces propriétés à la place:

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

Le problème que j'ai est que, indépendamment de ce qui est correct, je ne sais pas je peux faire cela. Tout ce que j'ai, c'est une Servicesous-classe qui implémente l'interface générée automatiquement pour le service Web et au moment où cela est instancié, si le WSDL ne répond pas, il est déjà trop tard pour définir les propriétés:

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

Est-ce que quelqu'un peut-il me montrer la bonne direction?!

neuf côtés
la source
5
Je ne pense pas avoir de réponse pour vous, mais votre question m'a aidé à résoudre mon problème. Je connaissais la propriété com.sun.xml.ws.request.timeout mais pas celle com.sun.xml.internal.ws.request.timeout.
Ron Tuffin

Réponses:

90

Je sais que c'est vieux et que j'ai répondu ailleurs, mais j'espère que cela met fin à cela. Je ne sais pas pourquoi vous voudriez télécharger le WSDL dynamiquement mais les propriétés système:

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

devrait s'appliquer à toutes les lectures et connexions à l'aide de HttpURLConnection que JAX-WS utilise. Cela devrait résoudre votre problème si vous obtenez le WSDL à partir d'un emplacement distant - mais un fichier sur votre disque local est probablement meilleur!

Ensuite, si vous souhaitez définir des délais d'expiration pour des services spécifiques, une fois que vous avez créé votre proxy, vous devez le convertir en BindingProvider (que vous connaissez déjà), obtenir le contexte de la demande et définir vos propriétés. La documentation en ligne JAX-WS est fausse, ce sont les noms de propriété corrects (enfin, ils fonctionnent pour moi).

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);

Bien sûr, c'est une façon horrible de faire les choses, je créerais une belle usine pour produire ces fournisseurs de liaison qui peuvent être injectés avec les délais d'attente que vous souhaitez.

alpian
la source
10
Notez que les propriétés REQUEST_TIMEOUT / CONNECT_TIMEOUT sont en fait héritées de la classe interne SUN com.sun.xml.internal.ws.developer.JAXWSProperties et (au moins sur Linux 32 bits) javac 1.6.0_27 et javac 1.7.0_03 ne parviennent pas à compilez ce code (similaire à bugs.sun.com/view_bug.do?bug_id=6544224 ) ... vous devez passer -XDignore.symbol.file à javac pour que cela fonctionne.
JavaGuy
Qu'est-ce qui ne marche pas? Je viens de vérifier cela et cela fonctionne pour moi.
alpian
Je confirme simplement que je viens de l'utiliser avec JAX-WS RI 2.2.8 et JDK 1.7 et que cela a très bien fonctionné. Merci!
bconneen
Les classes et les paramètres qui ont «interne» dans leur nom complet ne doivent pas être utilisés, car ils dépendent du fournisseur et ne sont donc pas portables entre les différentes implémentations JDK. Dans le cas des paramètres jax-ws, par exemple, les propriétés non internes correspondantes existent dans la classe com.sun.xml.ws.client.BindingProviderProperties.
polaretto
1
@ Matt1776 oui bien sûr, il manque: alors que JAX-WS est une spécification d'API, vous avez besoin d'une implémentation de bibliothèque, dans ce cas jaxws-ri.jar ou jaxws-rt.jar, qui ne fait pas partie du JDK. Il vous suffit de le télécharger et de l'ajouter à votre projet et vous aurez ces propriétés disponibles.
polaretto
41

Les propriétés de la réponse acceptée n'ont pas fonctionné pour moi, peut-être parce que j'utilise l'implémentation JBoss de JAX-WS?

L'utilisation d'un ensemble de propriétés différent (trouvé dans le Guide de l'utilisateur JBoss JAX-WS ) a permis de le faire fonctionner:

//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
la source
2
Je n'utilise pas JBoss, mais seules les propriétés de ce commentaire ont fonctionné pour moi, rien d'autre n'a fonctionné.
PaulP
2
Les noms de propriété dépendent de l'implémentation JAX-WS. Une liste peut être trouvée ici: java.net/jira/browse/JAX_WS-1166
fabstab
3
Le lien java.net est rompu. github.com/javaee/metro-jax-ws/issues/1166
trunkc
12

Voici ma solution de travail:

// --------------------------
// 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
la source
3
Ces configurations sont-elles équivalentes à "javax.xml.ws.client.connectionTimeout" et "javax.xml.ws.client.receiveTimeout"?
Jose 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);

Cela a fonctionné pour moi.

Daniel Kaplan
la source
Merci! Pour moi aussi, c'est un moyen vraiment facile
kosm
4
Cela utilise les classes Apache CXF, il serait peut-être préférable de l'ajouter dans la réponse. Un lien vers lequel les jars CXF les contiennent aiderait également beaucoup.
JBert
@JBert Je suis d'accord. J'ai répondu il y a des années et je ne m'en souviens plus. N'hésitez pas à modifier la réponse.
Daniel Kaplan
8

Si vous utilisez JAX-WS sur JDK6, utilisez les propriétés suivantes:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout
Domenico Briganti
la source
System.setProperty ("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty ("com.sun.xml.internal.ws.request.timeout", "300") a fonctionné pour moi.
2787184
2
Dans certains contextes, vous ne savez pas au moment de la programmation quelle version de JAXWS (interne ou autonome) sera utilisée au moment de l'exécution. Les deux sont tout à fait compatibles, à l'exception de cette fonction de temporisation. Les clés sont différentes ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout) également la classe (ou l'interface) qui les définissent ( 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). Ma meilleure idée est de définir les deux, en utilisant des valeurs littérales comme clés.
Lorinczy Zsigmond
5

Si votre serveur d'applications est WebLogic (pour moi, c'était 10.3.6), les propriétés responsables des délais d'expiration sont:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout
E. Egiazarov
la source
3

Je ne sais pas si cela vous aidera dans votre contexte ...

L'objet soap peut-il être converti en 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();

D'un autre côté, si vous souhaitez définir le délai d'expiration de l'initialisation de l'objet MyWebService, cela ne vous aidera pas.

Cela a fonctionné pour moi lorsque je voulais expirer les appels individuels de WebService.

Ron Tuffin
la source
2

le moyen le plus simple d'éviter une récupération lente du WSDL distant lorsque vous instanciez votre SEI est de ne pas récupérer le WSDL à partir du point de terminaison de service distant au moment de l'exécution.

cela signifie que vous devez mettre à jour votre copie WSDL locale chaque fois que le fournisseur de services effectue une modification ayant un impact, mais cela signifie également que vous devez mettre à jour votre copie locale chaque fois que le fournisseur de services effectue une modification ayant un impact.

Lorsque je génère mes stubs client, je dis au runtime JAX-WS d'annoter le SEI de manière à ce qu'il lise le WSDL à partir d'un emplacement prédéterminé sur le chemin de classe. par défaut, l'emplacement est relatif à l'emplacement du package du Service 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>

l'attribut wsldLocation indique au SEI où il peut trouver le WSDL, et la copie s'assure que le wsdl (et le support xsd .. etc.) est au bon emplacement.

puisque l'emplacement est relatif à l'emplacement du package du SEI, nous créons un nouveau sous-package (répertoire) appelé wsdl, et y copions tous les artefacts wsdl.

tout ce que vous avez à faire à ce stade est de vous assurer d'inclure tous les fichiers * .wsdl, * .xsd en plus de tous les * .class lorsque vous créez votre fichier jar d'artefact de stub client.

(au cas où vous êtes curieux, l'annotation @webserviceClient est l'endroit où cet emplacement wsdl est réellement défini dans le code java

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