Как установить время ожидания подключения при использовании клиента веб-служб JAXRPC-RI? - PullRequest
6 голосов
/ 30 апреля 2009

Я работаю с устаревшим компонентом, в котором мы взаимодействуем с веб-службой SOAP (технология, которую я абсолютно, безусловно, ненавижу), используя некоторый клиентский код, созданный с использованием библиотеки JAXRPC-RI (эталонная реализация). 1001 *

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

Я использую для работы с клиентами / заглушками, сгенерированными Apache Axis, в которых вы можете просто использовать org.apache.axis.client.Stub.setTimeout() для установки времени ожидания.

Я не могу понять, как установить тайм-аут при использовании заглушек, созданных с помощью JAXRPC-RI:

  • Класс порта, который я создаю, расширяет com.sun.xml.rpc.client.StubBase и реализует javax.xml.rpc.Stub и com.sun.xml.rpc.spi.runtime.StubBase.
  • В JavaDocs ни для одного из этих классов не указан какой-либо таймаут или метод для этого.
  • Попытка кода, подобного stub._setProperty("axis.connection.timeout", 1000);, приводит к исключению во время выполнения: javax.xml.rpc.JAXRPCException: Stub does not recognize property: axis.connection.timeout

Есть ли у кого-нибудь идеи о том, как установить / применить тайм-аут при использовании клиента JAXRPC-RI? Это вообще возможно?

Ответы [ 8 ]

4 голосов
/ 07 июня 2009

У вас могут быть такие параметры настройки удачи, как sun.net.client.defaultConnectTimeout или sun.net.client.defaultReadTimeout, хотя это приведет к общесистемному таймауту.

В коде значения свойств задаются с помощью строк:

System.setProperty("sun.net.client.defaultConnectTimeout", "1000");
System.setProperty("sun.net.client.defaultReadTimeout", "1000");

Для быстрого теста может быть проще установить переменную среды JAVA_OPTS или использовать командную строку:

java -Dsun.net.client.defaultConnectTimeout="1000" ...
2 голосов
/ 04 ноября 2010

Я не уверен, почему эта конкретная реализация JAXRPC делает все возможное, чтобы затруднить установку тайм-аута. Возможно, для этого есть веская причина. Другие реализации, такие как Axis и, я полагаю, JAX-WS, позволяют просто вызывать метод setTimeout () в Stub. После некоторых болей я смог придумать это решение. Надеюсь, это будет полезно. Вам нужно будет сделать следующее, чтобы установить время ожидания для основного URLConnection:

  1. Создать новый класс ClientTransport. Он должен расширить класс com.sun.xml.rpc.client.http.HttpClientTransport. Переопределите метод createHttpConnection (String, SOAPMessageContext). Вызовите super.createHttpConnection (), который вернет объект HttpURLConnection. В объекте HttpURLConnection вы можете вызвать setReadTimeout (), который принудительно установит тайм-аут на стороне клиента за X миллисекунд. Как только это будет сделано, верните измененный объект HttpURLConnection.
  2. Расширьте класс Stub на стороне клиента своим собственным. Переопределите метод _getTransport (), чтобы вернуть новый экземпляр класса ClientTransport, созданный на шаге (1).
  3. Расширьте класс _Impl на стороне клиента своим собственным. Переопределите метод get ... Port (), чтобы он использовал заглушку, созданную на шаге (2), вместо сгенерированной.
  4. Измените код клиента, который вы написали для вызова веб-службы, чтобы он использовал заглушку, созданную на шаге (2), и _Impl, созданный на шаге (3).

Примечание. Убедитесь, что все, что вы вызываете для создания заглушек с помощью wscompile (сценарий Ant?), Не перезаписывает 3 класса Java, которые вы только что создали / изменили. Вероятно, имеет смысл переместить их в другой пакет, чтобы они не перезаписывались.

1 голос
/ 25 ноября 2010

Ответ Евгения Трейвуса очень хороший, но в результате создается новый HTTPUrlConnection для каждого вызова SOAP. Во время тестирования его подхода я обнаружил, что можно установить ClientTransportFactory. Теперь я использую CustomClientTransportFactory и устанавливаю его на заглушку (приведение к StubBase). Тогда не нужно шагов 2 и 3.

На шаге 4 каждый устанавливает свой новый ClientTransportFactory следующим образом: ((StubBase) myPort) ._ setTransportFactory (new CustomClientTransportFactory ());

0 голосов
/ 22 сентября 2015

Может быть, немного опоздал на этот вопрос, но я пришел к этой проблеме сегодня. На основе решения, предложенного Евгением Трейвусом (спасибо за это!), Я придумал следующее:

((com.sun.xml.rpc.client.StubBase)myRemoteStub)._setTransportFactory(new ClientTransportFactory() {
    @Override
    public ClientTransport create() {
        return new HttpClientTransport() {
            @Override
            protected HttpURLConnection createHttpConnection(String endpoint, SOAPMessageContext context) throws IOException {
                HttpURLConnection conn = super.createHttpConnection(endpoint, context);
                conn.setConnectTimeout(2000);
                conn.setReadTimeout(2000);
                return conn;
            }
        };
    }
});

Это в основном то же, что предложил Евгений, но с чуть меньшим переопределением (с помощью фабрики соединений).

0 голосов
/ 26 августа 2013

Вы должны использовать:

import javax.xml.rpc.Stub;

...


int timeout = <number of milliseconds>;

((Stub) port)._setProperty(
                "axis.connection.timeout",
                timeout);
0 голосов
/ 31 июля 2012

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

В моем клиентском классе, который реализует сгенерированный интерфейс MyObject, я адаптировал getServicePort () следующим образом (обратите внимание, что у меня также есть защита здесь).

protected MyObject getServicePort() throws java.rmi.RemoteException {
    if (port == null) {
        synchronized(this) {
            if (port == null) {
                try {
                    final MyObject_Impl service = new MyObject_Impl(wsdlURL);

                    // using a local variable until the object is completelly initialized
                    final MyObject localPort = service.getMyObjectPort();

                    // if username and password are provided: building a client which will include the 
                    // username and token
                    if (username != null && pwd != null) {
                        Stub localStub = ((Stub) localPort);

                        // We have UsernameToken Authentication too
                        localStub._setProperty(
                                WSSecurityContext.CREDENTIAL_PROVIDER_LIST, 
                                Collections.singletonList(
                                        new ClientUNTCredentialProvider(username.getBytes(), pwd.getBytes())));

                        if (timeout != null) {
                               log.debug("Setting timeout to " + timeout + " milliseconds");
                            localStub._setProperty("weblogic.wsee.transport.read.timeout", timeout);
                            localStub._setProperty("weblogic.wsee.transport.connection.timeout", timeout);
                        }
                    }

                    port = localPort;

                } catch (ServiceException e) {
                    throw new RemoteException("Could not initialize client to MyObject service", e);
                }
            }
        }
    }
    return port;
}

Документация Oracle находится здесь: http://docs.oracle.com/cd/E12840_01/wls/docs103/webserv_rpc/client.html#wp241849, но в ней неправильно указано, что время ожидания указано в секундах. Это на самом деле в миллисекундах!

0 голосов
/ 07 декабря 2010

Ray

Спасибо за ваш вклад. Похоже, ваш подход лучше, так как он позволит избежать пары посторонних шагов. Я должен буду посмотреть. Однако, если я что-то упускаю, я не верю, что создается дополнительное HttpConnection, поскольку YourClientTransport.createHttpConnection (String s, SOAPMessageContext ctx) должен переопределить HttpClientTransport one:

public class YourClientTransport extends HttpClientTransport {
   @Override
   protected HttpUrlConnection createHttpConnection(String s, SOAPMessageContext ctx) throws IOException {
      HttpURLConnection httpURLConnection = super.createHttpConnection(s, ctx);
      httpURLConnection.setReadTimeout(1000);
      httpURLConnection.setConnectTimeout(1000);
      return httpURLConnection;
   }
}
0 голосов
/ 02 июня 2009

Я просто попытаюсь пожать награду, так что не стреляйте в меня, если я полностью на неправильном пути :) Если ваше приложение «находится там всегда и ждет ответа», чем вы могли бы сделать запрос в отдельном потоке и после появления вашего requestThread вы можете просто сказать requestThread.join(max_time_to_wait);, что следующий вызов проверит, если requestThread еще жив, и если это так, то попытайтесь его убить.

Ваше приложение будет работать после истечения времени ожидания, и это не самое неэффективное решение ...

...