Bagaimana cara mengatur waktu tunggu untuk klien layanan web JAX-WS?

93

Saya telah menggunakan JAXWS-RI 2.1 untuk membuat antarmuka untuk layanan web saya, berdasarkan WSDL. Saya dapat berinteraksi dengan layanan web tanpa masalah, tetapi belum dapat menentukan waktu tunggu untuk mengirim permintaan ke layanan web. Jika karena alasan tertentu tidak merespons, klien sepertinya memutar rodanya selamanya.

Berburu di sekitar telah mengungkapkan bahwa saya mungkin harus mencoba melakukan sesuatu seperti ini:

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

Saya juga menemukan bahwa, bergantung pada versi JAXWS-RI yang Anda miliki, Anda mungkin perlu menyetel properti ini sebagai gantinya:

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

Masalah yang saya miliki adalah, terlepas dari yang mana di atas yang benar, saya tidak tahu di mana saya bisa melakukan ini. Yang saya dapatkan hanyalah Servicesubclass yang mengimplementasikan antarmuka yang dihasilkan secara otomatis ke webservice dan pada titik ini semakin instan, jika WSDL tidak responsif maka sudah terlambat untuk mengatur properti:

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

Adakah yang bisa mengarahkan saya ke arah yang benar ?!

bersisi sembilan
sumber
5
Saya tidak berpikir saya punya jawaban untuk Anda, tetapi pertanyaan Anda membantu saya memecahkan masalah saya. Saya tahu tentang properti com.sun.xml.ws.request.timeout tetapi tidak tentang properti com.sun.xml.internal.ws.request.timeout.
Ron Tuffin

Jawaban:

90

Saya tahu ini sudah tua dan dijawab di tempat lain tetapi mudah-mudahan ini menutupnya. Saya tidak yakin mengapa Anda ingin mengunduh WSDL secara dinamis tetapi properti sistem:

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

harus berlaku untuk semua pembacaan dan koneksi menggunakan HttpURLConnection yang digunakan JAX-WS. Ini seharusnya menyelesaikan masalah Anda jika Anda mendapatkan WSDL dari lokasi jarak jauh - tetapi file di disk lokal Anda mungkin lebih baik!

Selanjutnya, jika Anda ingin menyetel waktu tunggu untuk layanan tertentu, setelah Anda membuat proxy, Anda perlu mentransmisikannya ke BindingProvider (yang sudah Anda ketahui), dapatkan konteks permintaan dan setel properti Anda. Dokumentasi JAX-WS online salah, ini adalah nama properti yang benar (yah, itu berfungsi untuk saya).

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

Tentu saja, ini adalah cara yang mengerikan untuk melakukan sesuatu, saya akan membuat pabrik yang bagus untuk memproduksi penyedia penjilidan ini yang dapat diinjeksi dengan batas waktu yang Anda inginkan.

alpian
sumber
10
Perhatikan bahwa properti REQUEST_TIMEOUT / CONNECT_TIMEOUT sebenarnya diwarisi dari kelas internal SUN com.sun.xml.internal.ws.developer.JAXWSProperties dan (setidaknya pada Linux 32-bit) javac 1.6.0_27 dan javac 1.7.0_03 gagal kompilasi kode ini (mirip dengan bugs.sun.com/view_bug.do?bug_id=6544224 ) ... Anda harus meneruskan -XDignore.symbol.file ke javac agar bisa berfungsi.
JavaGuy
Apa yang tidak berhasil? Saya baru saja memeriksa ulang ini dan berhasil untuk saya.
alpian
Hanya mengonfirmasi bahwa saya baru saja menggunakan ini dengan JAX-WS RI 2.2.8 dan JDK 1.7 dan berfungsi dengan baik. Terima kasih!
bconneen
Kelas dan parameter yang memiliki "internal" dalam nama yang sepenuhnya memenuhi syarat, tidak boleh digunakan, karena bergantung pada vendor dan karenanya tidak portabel di antara implementasi JDK yang berbeda. Dalam kasus parameter jax-ws, misalnya, properti non-internal terkait ada di kelas com.sun.xml.ws.client.BindingProviderProperties.
polaretto
1
@ Matt1776 ya tentu saja tidak ada: meskipun JAX-WS adalah spesifikasi API, Anda memerlukan implementasi perpustakaan, dalam hal ini jaxws-ri.jar atau jaxws-rt.jar, yang bukan merupakan bagian dari JDK. Anda hanya perlu mengunduh dan menambahkannya ke ptoject Anda dan properti tersebut akan tersedia.
polaretto
41

Properti dalam jawaban yang diterima tidak berfungsi untuk saya, mungkin karena saya menggunakan implementasi JBoss dari JAX-WS?

Menggunakan sekumpulan properti yang berbeda (ditemukan di Panduan Pengguna JBoss JAX-WS ) membuatnya berfungsi:

//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.dll
sumber
2
Saya tidak menggunakan JBoss, tetapi hanya properti dalam komentar ini yang berfungsi untuk saya, tidak ada yang lain.
PaulP
2
Nama properti bergantung pada implementasi JAX-WS. Daftar dapat ditemukan di sini: java.net/jira/browse/JAX_WS-1166
fabstab
3
Tautan java.net rusak. github.com/javaee/metro-jax-ws/issues/1166
trunkc
12

Inilah solusi kerja saya:

// --------------------------
// 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
sumber
3
Apakah konfigurasi ini setara dengan "javax.xml.ws.client.connectionTimeout" dan "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);

Ini berhasil untuk saya.

Daniel Kaplan
sumber
Terima kasih! Bagi saya juga, ini cara yang sangat mudah
kosm
4
Ini menggunakan kelas Apache CXF, mungkin yang terbaik adalah menambahkan ini di jawabannya. Tautan yang berisi stoples CXF juga akan banyak membantu.
JBert
@JBert Saya setuju. Saya menjawab ini bertahun-tahun yang lalu dan tidak dapat mengingat. Jangan ragu untuk mengedit jawabannya.
Daniel Kaplan
8

Jika Anda menggunakan JAX-WS di JDK6, gunakan properti berikut ini:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout
Domenico Briganti
sumber
System.setProperty ("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty ("com.sun.xml.internal.ws.request.timeout", "300") berhasil untuk saya.
2787184
2
Dalam beberapa konteks, Anda tidak tahu waktu pemrograman versi JAXWS mana (internal atau mandiri) yang akan digunakan waktu proses. Keduanya cukup kompatibel, kecuali untuk fitur batas waktu ini. Kunci berbeda ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout) juga kelas (atau antarmuka) yang menentukannya ( 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). Ide terbaik saya adalah mengatur keduanya, menggunakan nilai literal sebagai kunci.
Lorinczy Zsigmond
5

Jika server aplikasi Anda adalah WebLogic (bagi saya itu 10.3.6) maka properti yang bertanggung jawab atas waktu tunggu adalah:

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

Tidak yakin apakah ini akan membantu dalam konteks Anda ...

Bisakah objek sabun dilemparkan sebagai 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();

Di sisi lain, jika Anda ingin mengatur waktu tunggu pada inisialisasi objek MyWebService, ini tidak akan membantu.

Ini berhasil untuk saya ketika ingin timeout panggilan WebService individu.

Ron Tuffin
sumber
2

cara termudah untuk menghindari pengambilan WSDL jarak jauh yang lambat saat Anda membuat instance SEI adalah dengan tidak mengambil WSDL dari titik akhir layanan jarak jauh saat runtime.

ini berarti Anda harus memperbarui salinan WSDL lokal Anda setiap kali penyedia layanan membuat perubahan yang berdampak, tetapi itu juga berarti Anda harus memperbarui salinan lokal Anda setiap kali penyedia layanan membuat perubahan yang berdampak.

Ketika saya membuat stub klien saya, saya memberi tahu runtime JAX-WS untuk memberi anotasi pada SEI sedemikian rupa sehingga ia akan membaca WSDL dari lokasi yang ditentukan sebelumnya di classpath. secara default lokasinya relatif terhadap lokasi paket 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>

atribut wsldLocation memberitahu SEI di mana dapat menemukan WSDL, dan salinan memastikan bahwa wsdl (dan mendukung xsd .. dll ..) berada di lokasi yang benar.

karena lokasinya relatif terhadap lokasi paket SEI, kami membuat sub-paket baru (direktori) bernama wsdl, dan menyalin semua artefak wsdl di sana.

yang harus Anda lakukan pada tahap ini adalah memastikan Anda menyertakan semua * .wsdl, * .xsd selain semua * .class saat Anda membuat file jar artefak klien-stub.

(jika Anda penasaran, anotasi @webserviceClient adalah tempat lokasi wsdl ini sebenarnya disetel dalam kode java

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