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 Service
podklasa, 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 ?!
Odpowiedzi:
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.
źródło
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");
źródło
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."); } }
źródło
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.
źródło
Jeśli używasz JAX-WS na JDK6, użyj następujących właściwości:
źródło
com.sun.xml.internal.ws.connect.timeout
vscom.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.BindingProviderProperties
vscom.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.W przypadku, gdy twoim serwerem aplikacji jest WebLogic (dla mnie był to 10.3.6), to właściwości odpowiedzialne za timeouty to:
źródło
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.
źródło
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")
źródło