Jak ustawić limit czasu dla klienta usługi WWW JAX-WS?

93

Użyłem JAXWS-RI 2.1 do stworzenia interfejsu dla mojej usługi internetowej, opartego na WSDL. Nie mogę współdziałać z usługą sieciową bez problemów, ale nie udało mi się określić limitu czasu na wysyłanie żądań do usługi sieciowej. Jeśli z jakiegoś powodu nie reaguje, klient po prostu wydaje się kręcić kołami na zawsze.

Polowanie ujawniło, że prawdopodobnie powinienem spróbować zrobić coś takiego:

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

Odkryłem również, że w zależności od posiadanej wersji JAXWS-RI może być konieczne ustawienie tych właściwości:

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

Problem polega na tym, że niezależnie od tego, które z powyższych jest poprawne, nie wiem, gdzie mogę to zrobić. Wszystko, co mam, to Servicepodklasa, która implementuje automatycznie generowany interfejs do usługi sieciowej, a w momencie, gdy jest to uruchamiane, jeśli WSDL nie reaguje, jest już za późno na ustawienie właściwości:

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

Czy ktoś może wskazać mi właściwy kierunek ?!

dziewięciostronny
źródło
5
Chyba nie mam dla ciebie odpowiedzi, ale twoje pytanie pomogło mi rozwiązać mój problem. Wiedziałem o właściwości com.sun.xml.ws.request.timeout, ale nie o właściwości com.sun.xml.internal.ws.request.timeout.
Ron Tuffin,

Odpowiedzi:

91

Wiem, że to jest stare i odpowiedziałem gdzie indziej, ale mam nadzieję, że to zamyka sprawę. Nie jestem pewien, dlaczego chcesz pobierać WSDL dynamicznie, ale właściwości systemu:

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

powinno dotyczyć wszystkich odczytów i połączeń przy użyciu HttpURLConnection, z którego korzysta JAX-WS. Powinno to rozwiązać problem, jeśli pobierasz WSDL ze zdalnej lokalizacji - ale plik na dysku lokalnym jest prawdopodobnie lepszy!

Następnie, jeśli chcesz ustawić limity czasu dla określonych usług, po utworzeniu serwera proxy musisz rzucić go na BindingProvider (który już znasz), pobrać kontekst żądania i ustawić właściwości. Dokumentacja online JAX-WS jest błędna, to są poprawne nazwy właściwości (cóż, działają dla mnie).

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

Oczywiście jest to okropny sposób robienia rzeczy, stworzyłbym fajną fabrykę do produkcji tych dostawców wiązań, które można wstrzyknąć z żądanymi limitami czasu.

alpejski
źródło
10
Należy zauważyć, że właściwości REQUEST_TIMEOUT / CONNECT_TIMEOUT są w rzeczywistości dziedziczone z wewnętrznej klasy SUN com.sun.xml.internal.ws.developer.JAXWSProperties i (przynajmniej w 32-bitowym systemie Linux) javac 1.6.0_27 i javac 1.7.0_03 nie działają skompiluj ten kod (podobnie jak bugs.sun.com/view_bug.do?bug_id=6544224 ) ... musisz przekazać -XDignore.symbol.file do javac, aby działał.
JavaGuy
Co nie działa? Właśnie to dwukrotnie sprawdziłem i działa dla mnie.
alpian
Potwierdzam tylko, że właśnie użyłem tego z JAX-WS RI 2.2.8 i JDK 1.7 i działało dobrze. Dziękuję Ci!
bconneen
Klasy i parametry, które mają w pełni kwalifikowaną nazwę „wewnętrzne”, nie powinny być używane, ponieważ są zależne od dostawcy i dlatego nie można ich przenosić między różnymi implementacjami JDK. Na przykład w przypadku parametrów jax-ws odpowiednie właściwości nie wewnętrzne istnieją w klasie com.sun.xml.ws.client.BindingProviderProperties.
polaretto
1
@ Matt1776 tak, oczywiście, że go brakuje: podczas gdy JAX-WS jest specyfikacją API, potrzebujesz implementacji biblioteki, w tym przypadku jaxws-ri.jar lub jaxws-rt.jar, która nie jest częścią JDK. Wystarczy pobrać i dodać go do swojego ptojektu, a te właściwości będą dostępne.
polaretto
42

Właściwości w zaakceptowanej odpowiedzi nie działają dla mnie, prawdopodobnie dlatego, że używam implementacji JBoss JAX-WS?

Użycie innego zestawu właściwości (które można znaleźć w podręczniku użytkownika JBoss JAX-WS ) sprawiło, że to zadziałało:

//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
źródło
2
Nie używam JBoss, ale działały tylko właściwości w tym komentarzu, nic innego nie działało.
PaulP,
2
Nazwy właściwości zależą od implementacji JAX-WS. Listę można znaleźć tutaj: java.net/jira/browse/JAX_WS-1166
fabstab
3
Link do java.net jest uszkodzony. github.com/javaee/metro-jax-ws/issues/1166
trunkc
12

Oto moje rozwiązanie robocze:

// --------------------------
// 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
źródło
3
Czy te konfiguracje są równoważne z „javax.xml.ws.client.connectionTimeout” i „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);

To zadziałało dla mnie.

Daniel Kaplan
źródło
Dzięki! Dla mnie też jest to naprawdę łatwy sposób
kosmos
4
Używa to jednak klas Apache CXF, najlepiej byłoby dodać to w odpowiedzi. Bardzo pomogłoby też łącze, do którego słoiki CXF je zawierają.
JBert,
@JBert Zgadzam się. Odpowiedziałem to lata temu i nie pamiętam. Zapraszam do edycji odpowiedzi.
Daniel Kaplan,
8

Jeśli używasz JAX-WS na JDK6, użyj następujących właściwości:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout
Domenico Briganti
źródło
System.setProperty ("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty ("com.sun.xml.internal.ws.request.timeout", "300") działał dla mnie.
2787184
2
W niektórych kontekstach nie wiadomo w czasie programowania, która wersja JAXWS (wewnętrzna lub autonomiczna) będzie używana w czasie wykonywania. Oba są całkiem kompatybilne, z wyjątkiem tej funkcji limitu czasu. Klucze są różne ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout) także klasa (lub interfejs), która je definiuje ( 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). Moim najlepszym pomysłem jest ustawienie obu, używając wartości dosłownych jako kluczy.
Lorinczy Zsigmond
5

W przypadku, gdy twoim serwerem aplikacji jest WebLogic (dla mnie był to 10.3.6), to właściwości odpowiedzialne za timeouty to:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout
E.Egiazarov
źródło
3

Nie jestem pewien, czy to pomoże w twoim kontekście ...

Czy obiekt mydła może zostać rzucony jako 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();

Z drugiej strony, jeśli chcesz ustawić limit czasu na inicjalizację obiektu MyWebService, to nie pomoże.

To działało dla mnie, gdy chciałem przekroczyć limit czasu poszczególnych wywołań WebService.

Ron Tuffin
źródło
2

najłatwiejszym sposobem uniknięcia powolnego pobierania zdalnego WSDL podczas tworzenia instancji SEI jest nie pobieranie WSDL ze zdalnego punktu końcowego usługi w czasie wykonywania.

Oznacza to, że musisz aktualizować lokalną kopię WSDL za każdym razem, gdy dostawca usług dokona zmiany, która ma wpływ, ale oznacza to również, że musisz zaktualizować swoją lokalną kopię za każdym razem, gdy dostawca usług dokona zmiany.

Kiedy generuję kody pośredniczące klienta, mówię środowisku wykonawczemu JAX-WS o dodaniu adnotacji do SEI w taki sposób, aby odczytywał WSDL z wcześniej określonej lokalizacji w ścieżce klas. Domyślnie lokalizacja jest określona względem lokalizacji pakietu usługi 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>

atrybut wsldLocation informuje SEI, gdzie może znaleźć WSDL, a kopia upewnia się, że wsdl (i obsługujące xsd .. itd.) znajduje się we właściwej lokalizacji.

Ponieważ lokalizacja jest zależna od lokalizacji pakietu SEI, tworzymy nowy pakiet podrzędny (katalog) o nazwie wsdl i kopiujemy tam wszystkie artefakty wsdl.

jedyne, co musisz zrobić w tym momencie, to upewnić się, że podczas tworzenia pliku jar artefaktów kodu klienta dołączono wszystkie pliki * .wsdl, * .xsd oprócz wszystkich * .class.

(jeśli jesteś ciekawy, adnotacja @webserviceClient jest miejscem, w którym ta lokalizacja wsdl jest faktycznie ustawiona w kodzie java

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")
Helter Scelter
źródło