Come si imposta il timeout per un client del servizio web JAX-WS?


93

Ho usato JAXWS-RI 2.1 per creare un'interfaccia per il mio servizio web, basata su un WSDL. Riesco a interagire con il servizio web senza problemi, ma non sono stato in grado di specificare un timeout per l'invio delle richieste al servizio web. Se per qualche motivo non risponde, il cliente sembra semplicemente girare le ruote per sempre.

La caccia in giro ha rivelato che probabilmente dovrei provare a fare qualcosa del genere:

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

Ho anche scoperto che, a seconda della versione di JAXWS-RI che hai, potresti dover impostare queste proprietà invece:

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

Il problema che ho è che, indipendentemente da quale delle precedenti opzioni sia corretta, non so dove posso farlo. Tutto quello che ho è una Servicesottoclasse che implementa l'interfaccia generata automaticamente per il servizio web e al punto in cui questa viene istanziata, se il WSDL non risponde, è già troppo tardi per impostare le proprietà:

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

Qualcuno può indicarmi la giusta direzione ?!


5
Non credo di avere una risposta per te, ma la tua domanda mi ha aiutato a risolvere il mio problema. Conoscevo la proprietà com.sun.xml.ws.request.timeout ma non quella com.sun.xml.internal.ws.request.timeout.
Ron Tuffin

Risposte:


89

So che questo è vecchio e ha risposto altrove, ma si spera che questo lo chiuda. Non sono sicuro del motivo per cui vorresti scaricare il WSDL in modo dinamico, ma le proprietà di sistema:

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

dovrebbe applicarsi a tutte le letture e si connette utilizzando HttpURLConnection che utilizza JAX-WS. Questo dovrebbe risolvere il tuo problema se stai ottenendo il WSDL da una posizione remota, ma probabilmente un file sul tuo disco locale è meglio!

Successivamente, se vuoi impostare timeout per servizi specifici, una volta creato il tuo proxy devi trasmetterlo a un BindingProvider (che conosci già), ottenere il contesto della richiesta e impostare le tue proprietà. La documentazione JAX-WS in linea è sbagliata, questi sono i nomi di proprietà corretti (beh, per me funzionano).

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

Naturalmente, questo è un modo orribile di fare le cose, creerei una bella fabbrica per la produzione di questi provider di binding che possono essere iniettati con i timeout desiderati.


10
Si noti che le proprietà REQUEST_TIMEOUT / CONNECT_TIMEOUT sono effettivamente ereditate dalla classe SUN-internal com.sun.xml.internal.ws.developer.JAXWSProperties e (almeno su Linux a 32 bit) javac 1.6.0_27 e javac 1.7.0_03 non riescono a compila questo codice (simile a bugs.sun.com/view_bug.do?bug_id=6544224 ) ... devi passare -XDignore.symbol.file a javac per farlo funzionare.
JavaGuy

Cosa non funziona? Ho appena ricontrollato e sta funzionando per me.
alpian

Sto solo confermando che l'ho appena usato con JAX-WS RI 2.2.8 e JDK 1.7 e ha funzionato perfettamente. Grazie!
bconneen

Classi e parametri che hanno "interno" nel loro nome completo, non dovrebbero essere usati, poiché dipendono dal fornitore e quindi non possono essere trasferiti tra diverse implementazioni JDK. Nel caso dei parametri jax-ws, ad esempio, le proprietà non interne corrispondenti esistono nella classe com.sun.xml.ws.client.BindingProviderProperties.
polaretto

1
@ Matt1776 sì, ovviamente manca: mentre JAX-WS è una specifica API, è necessaria un'implementazione della libreria, in questo caso jaxws-ri.jar o jaxws-rt.jar, che non fa parte del JDK. Devi solo scaricarlo e aggiungerlo al tuo ptoject e avrai quelle proprietà disponibili.
polaretto

40

Le proprietà nella risposta accettata non hanno funzionato per me, forse perché sto utilizzando l'implementazione JBoss di JAX-WS?

L'utilizzo di un diverso insieme di proprietà (che si trova nella Guida per l'utente di JBoss JAX-WS ) ha funzionato:

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

2
Non sto usando JBoss, ma solo le proprietà in questo commento hanno funzionato per me, nient'altro.
PaulP

2
I nomi delle proprietà dipendono dall'implementazione JAX-WS. Un elenco può essere trovato qui: java.net/jira/browse/JAX_WS-1166
fabstab

3
Il collegamento java.net è interrotto. github.com/javaee/metro-jax-ws/issues/1166
trunkc

12

Ecco la mia soluzione di lavoro:

// --------------------------
// 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.");

    }
}

3
Queste configurazioni sono equivalenti a "javax.xml.ws.client.connectionTimeout" e "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);

Questo ha funzionato per me.


Grazie! Anche per me, è un modo davvero semplice
kosm

4
Tuttavia, questo utilizza le classi CXF di Apache, potrebbe essere meglio aggiungerlo nella risposta. Anche un collegamento a cui i jar CXF li contengono aiuterebbe molto.
JBert

@ JBert sono d'accordo. Ho risposto anni fa e non ricordo. Sentiti libero di modificare la risposta.
Daniel Kaplan

8

Se stai usando JAX-WS su JDK6, usa le seguenti proprietà:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout

System.setProperty ("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty ("com.sun.xml.internal.ws.request.timeout", "300") ha funzionato per me.
2787184

2
In alcuni contesti, non si conosce l'ora di programmazione quale versione di JAXWS (interna o autonoma) verrà utilizzata durante l'esecuzione. I due sono abbastanza compatibili, ad eccezione di questa funzione di timeout. I tasti sono diversi ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout) anche dalla classe (o interfaccia) che li definisce ( 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). La mia migliore idea è impostare entrambi, utilizzando valori letterali come chiavi.
Lorinczy Zsigmond

5

Nel caso in cui il tuo server app sia WebLogic (per me era 10.3.6), le proprietà responsabili dei timeout sono:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout

3

Non sono sicuro se questo aiuterà nel tuo contesto ...

L'oggetto soap può essere lanciato come 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'altra parte, se si desidera impostare il timeout sull'inizializzazione dell'oggetto MyWebService, questo non sarà di aiuto.

Questo ha funzionato per me quando volevo scadere le singole chiamate WebService.


2

il modo più semplice per evitare un lento recupero del WSDL remoto quando si crea un'istanza del SEI consiste nel non recuperare il WSDL dall'endpoint del servizio remoto in fase di esecuzione.

questo significa che devi aggiornare la tua copia WSDL locale ogni volta che il fornitore di servizi apporta una modifica significativa, ma significa anche che devi aggiornare la tua copia locale ogni volta che il fornitore di servizi apporta una modifica impattante.

Quando genero i miei stub client, dico al runtime JAX-WS di annotare il SEI in modo tale che leggerà il WSDL da una posizione predeterminata sul classpath. per impostazione predefinita, la posizione è relativa alla posizione del pacchetto del servizio 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'attributo wsldLocation indica a SEI dove è possibile trovare WSDL e la copia si assicura che wsdl (e che supporta xsd .. ecc ..) sia nella posizione corretta.

poiché la posizione è relativa alla posizione del pacchetto SEI, creiamo un nuovo sotto-pacchetto (directory) chiamato wsdl e copiamo tutti gli artefatti wsdl lì.

tutto quello che devi fare a questo punto è assicurarti di includere tutti * .wsdl, * .xsd oltre a tutti * .class quando crei il tuo file jar artefatto client-stub.

(nel caso in cui sei curioso, l'annotazione @webserviceClient è dove questa posizione wsdl è effettivamente impostata nel codice java

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.