Как установить тайм-аут для клиента веб-службы JAX-WS?

93

Я использовал JAXWS-RI 2.1 для создания интерфейса для моей веб-службы на основе WSDL. Я могу взаимодействовать с веб-службой без проблем, но не могу указать тайм-аут для отправки запросов к веб-службе. Если по какой-то причине он не отвечает, клиент просто крутит колеса вечно.

Поиски вокруг показали, что мне, вероятно, следует попробовать сделать что-то вроде этого:

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

Я также обнаружил, что в зависимости от того, какая у вас версия JAXWS-RI, вам может потребоваться вместо этого установить следующие свойства:

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

Проблема в том, что, независимо от того, что из вышеперечисленного является правильным, я не знаю, где я могу это сделать. Все, что у меня есть, - это Serviceподкласс, который реализует автоматически сгенерированный интерфейс для веб-сервиса, и в момент создания его экземпляра, если WSDL не отвечает, тогда уже слишком поздно устанавливать свойства:

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

Может кто-то указать мне верное направление?!

девяностый
источник
5
Не думаю, что у меня есть для вас ответ, но ваш вопрос помог мне решить мою проблему. Я знал о свойстве com.sun.xml.ws.request.timeout, но не о com.sun.xml.internal.ws.request.timeout.
Рон Таффин,

Ответы:

91

Я знаю, что это устарело и ответил в другом месте, но, надеюсь, это закрывает это. Я не уверен, почему вам нужно динамически загружать WSDL, но свойства системы:

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

должен применяться ко всем операциям чтения и подключения с использованием HttpURLConnection, который использует JAX-WS. Это должно решить вашу проблему, если вы получаете WSDL из удаленного места, но файл на локальном диске, вероятно, лучше!

Затем, если вы хотите установить тайм-ауты для определенных служб, после того, как вы создали свой прокси, вам нужно передать его BindingProvider (который вы уже знаете), получить контекст запроса и установить свои свойства. Онлайн-документация JAX-WS неверна, это правильные имена свойств (ну, у меня они работают).

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

Конечно, это ужасный способ делать что-то, я бы создал хорошую фабрику для создания этих поставщиков привязки, которые можно вводить с нужными вам таймаутами.

альпийский
источник
10
Обратите внимание, что свойства REQUEST_TIMEOUT / CONNECT_TIMEOUT фактически унаследованы от внутреннего класса SUN com.sun.xml.internal.ws.developer.JAXWSProperties и (по крайней мере, в 32-разрядном Linux) javac 1.6.0_27 и javac 1.7.0_03 не работают. скомпилируйте этот код (аналогично bugs.sun.com/view_bug.do?bug_id=6544224 ) ... вам нужно передать -XDignore.symbol.file в javac, чтобы он работал.
JavaGuy 09
Что не работает? Я просто дважды проверил это, и он работает для меня.
alpian
Просто подтверждаю, что я только что использовал это с JAX-WS RI 2.2.8 и JDK 1.7, и он работал нормально. Спасибо!
bconneen
Классы и параметры, у которых есть «внутренние» в своем полном имени, не должны использоваться, поскольку они зависят от производителя и, следовательно, не переносятся между различными реализациями JDK. В случае параметров jax-ws, например, соответствующие невнутренние свойства существуют в классе com.sun.xml.ws.client.BindingProviderProperties.
Polaretto
1
@ Matt1776 да, конечно, его нет: хотя JAX-WS является спецификацией API, вам нужна реализация библиотеки, в данном случае jaxws-ri.jar или jaxws-rt.jar, которая не является частью JDK. Вам просто нужно загрузить и добавить его в свой ptoject, и эти свойства будут доступны.
Polaretto
42

Свойства в принятом ответе у меня не сработали, возможно, потому, что я использую JBoss-реализацию JAX-WS?

Используя другой набор свойств (найденный в Руководстве пользователя JBoss JAX-WS ) заставило его работать:

//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
источник
2
Я не использую JBoss, но у меня работали только свойства в этом комментарии, больше ничего.
PaulP
2
Имена свойств зависят от реализации JAX-WS. Список можно найти здесь: java.net/jira/browse/JAX_WS-1166
fabstab
3
Ссылка java.net не работает. github.com/javaee/metro-jax-ws/issues/1166
trunkc 09
12

Вот мое рабочее решение:

// --------------------------
// 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
Эквивалентны ли эти конфигурации "javax.xml.ws.client.connectionTimeout" и "javax.xml.ws.client.receiveTimeout" ??
Хосе Тепедино
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);

Это сработало для меня.

Даниэль Каплан
источник
Благодарность! Для меня тоже это очень простой способ
косм 09
4
Однако здесь используются классы Apache CXF, возможно, лучше добавить это в ответ. Ссылка на то, какие банки CXF содержат их, также очень поможет.
JBert
@JBert Я согласен. Я ответил на это много лет назад и не могу вспомнить. Не стесняйтесь редактировать ответ.
Дэниел Каплан
8

Если вы используете JAX-WS на JDK6, используйте следующие свойства:

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") работал у меня.
2787184 03
2
В некоторых контекстах вы не знаете во время программирования, какая версия JAXWS (внутренняя или автономная) будет использоваться во время выполнения. Оба они вполне совместимы, за исключением тайм-аута. Ключи различны ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout), а также класс (или интерфейс), который их определяет ( 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). Моя лучшая идея - установить оба, используя буквальные значения в качестве ключей.
Lorinczy Zsigmond
5

Если ваш сервер приложений - это WebLogic (для меня это было 10.3.6), то свойства, отвечающие за тайм-ауты, следующие:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout
Е.Егиазаров
источник
3

Не уверен, поможет ли это в вашем контексте ...

Можно ли преобразовать объект soap как 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();

С другой стороны, если вы хотите установить тайм-аут при инициализации объекта MyWebService, это не поможет.

Это сработало для меня, когда я хотел отключить отдельные вызовы WebService.

Рон Таффин
источник
2

Самый простой способ избежать медленного извлечения удаленного WSDL при создании экземпляра SEI - не извлекать WSDL из конечной точки удаленной службы во время выполнения.

это означает, что вам нужно обновлять локальную копию WSDL каждый раз, когда поставщик услуг вносит влияющее изменение, но это также означает, что вам необходимо обновлять локальную копию каждый раз, когда поставщик услуг вносит влияющее изменение.

Когда я создаю свои клиентские заглушки, я приказываю среде выполнения JAX-WS аннотировать SEI таким образом, чтобы она считывала WSDL из заранее определенного места в пути к классам. по умолчанию расположение относительно расположения пакета 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>

атрибут wsldLocation сообщает SEI, где он может найти WSDL, а копия гарантирует, что wsdl (и поддерживающий xsd ... и т. д.) находится в правильном месте.

поскольку это расположение относительно расположения пакета SEI, мы создаем новый подпакет (каталог) с именем wsdl и копируем туда все артефакты wsdl.

все, что вам нужно сделать на этом этапе, это убедиться, что вы включили все * .wsdl, * .xsd в дополнение ко всем * .class, когда вы создаете файл jar артефакта клиент-заглушки.

(на случай, если вам интересно, аннотация @webserviceClient - это то место, где это местоположение wsdl фактически установлено в java-коде

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")
Хелтер Шелтер
источник