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

Я использовал 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();

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

Ответ 1

Я знаю, что это старо и отвечает в другом месте, но, надеюсь, это закрывает это. Я не уверен, почему вы хотите загрузить 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);

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

Ответ 2

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

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

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

Ответ 3

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

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

    }
}

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

Может ли объект мыла быть брошен как 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.

Ответ 7

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

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

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