2009-04-30 10 views
5

Pracuję z odrobiną starszego komponentu, w którym wchodzimy w interakcję z usługą sieciową SOAP (technologia absolutnie, pozytywnie brzydząca) za pomocą kodu klienta zbudowanego przy użyciu biblioteki JAXRPC-RI (implementacja referencyjna).Jak ustawić limit czasu połączenia podczas korzystania z klienta usług WWW JAXRPC-RI?

Jestem zainteresowany ustawieniem limitu czasu za pomocą kodów pośredniczących, aby na wypadek, gdyby serwer usług internetowych nie odpowiedział w ciągu X sekund, aplikacja nie ustawi się tam na zawsze, czekając na odpowiedź.

Używam do pracy z klientami/stubami generowanymi przez Apache Axis, w których można po prostu użyć org.apache.axis.client.Stub.setTimeout(), aby ustawić limit czasu.

Dla życia mnie nie mogę dowiedzieć się, jak ustawić limit czasu podczas korzystania Stubs utworzone z JAXRPC-RI:

  • Klasa portu Mam instancji rozciąga com.sun.xml.rpc.client.StubBase i wdraża javax.xml.rpc.Stub i com.sun.xml.rpc.spi.runtime.StubBase.
  • Dokumentacja JavaDocs dla żadnej z tych klas nie wspomina o żadnym limicie czasu ani metodzie, aby to zrobić.
  • Próbując kod jak stub._setProperty("axis.connection.timeout", 1000); powoduje wyjątek w środowisku wykonawczym: javax.xml.rpc.JAXRPCException: Stub does not recognize property: axis.connection.timeout

Czy ktoś ma jakieś pomysły, w jaki sposób ustawić/wymusić limit czasu przy użyciu klienta JAXRPC-RI? Czy to możliwe?

Odpowiedz

0

Po prostu spróbuję zebrać nagrodę, więc nie strzelaj do mnie, jeśli jestem całkowicie na niewłaściwym torze :) Jeśli twoja aplikacja "ustawia tam na zawsze czeka na odpowiedź", niż mogłabyś zrobić Żądaj w osobnym wątku i po odradzaniu twojego requestThread możesz powiedzieć, że następne wywołanie sprawdzi, czy requestThread wciąż żyje, a jeśli to spróbuje, spróbuj go zabić.

aplikacja

Będziesz poruszać się po przekroczeniu limitu czasu i nie jest to najbardziej nieeleganckie rozwiązanie ...

+0

Jest to opcja, ale naprawdę chciałbym to zrobić w ramach kodu/klienta API usług internetowych, jeśli to możliwe. Dziękuję Ci. –

4

może mieć właściwości takie jak sun.net.client.defaultConnectTimeout lub sun.net.client.defaultReadTimeout ustawienia szczęścia, mimo że wtedy wprowadzić limit czasu dla całego systemu .

W kodzie właściwości wartości są ustawiane za pomocą ciągi:

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

Dla szybkiego testu, może łatwiej będzie ustawić zmienną środowiskową JAVA_OPTS lub użyj polecenia:

java -Dsun.net.client.defaultConnectTimeout="1000" ... 
+0

Jakiś pomysł, jeśli dotyczy to nie tylko połączeń wychodzących, ale również przychodzących? –

+0

Sądzę, że pierwsze może dotyczyć tylko zleceń wychodzących, chyba że uwzględnione zostaną również uściski dłoni. I biorąc pod uwagę nazwy "net.client" zakładam, że obie właściwości wpływają tylko na wychodzące, co dla drugiej właściwości jest obsługiwane przez jej definicję "[..] określa limit czasu (w milisekundach) podczas odczytu ze strumienia wejściowego, gdy połączenie jest ustanowione do zasób." Rzeczywiście, można się zastanawiać, czy istnieją podobne właściwości dla gniazd, które zaakceptowały połączenie przychodzące, ale nie mogę ich szybko znaleźć. – Arjan

+0

I, "Te właściwości określają domyślny limit czasu połączenia i odczytu (odpowiednio) dla procedury obsługi protokołu używanej przez java.net.URLConnection." Tak więc, wychodząc tylko na pewno. http://java.sun.com/javase/6/docs/technotes/guides/net/properties.html – Arjan

2

I nie jestem pewien, dlaczego ta konkretna implementacja JAXRPC wychodzi mu z drogi, aby utrudnić ustawienie limitu czasu. Być może istnieje ku temu dobry powód. Inne implementacje, takie jak Axis i, jak sądzę, JAX-WS, pozwalają po prostu wywołać metodę setTimeout() na Stub. Po kilku trudach udało mi się wymyślić to rozwiązanie. Mamy nadzieję, że będzie to pomocne. Trzeba będzie wykonać następujące czynności, aby ustawić limit czasu na podstawowej URLConnection:

  1. utworzyć nową klasę ClientTransport. Powinno to rozszerzyć klasę com.sun.xml.rpc.client.http.HttpClientTransport. Zastąp metodę createHttpConnection (String, SOAPMessageContext). Wywołaj super.createHttpConnection(), który zwróci obiekt HttpURLConnection. Na obiekcie HttpURLConnection można wywołać funkcję setReadTimeout(), która wymusi timeout po stronie klienta w X liczbie milisekund.Gdy to zrobisz, zwróć zmodyfikowany obiekt HttpURLConnection.
  2. Rozszerz klasę klientów po stronie klienta. Zastąp metodę _getTransport() w celu zwrócenia nowej instancji klasy ClientTransport utworzonej w kroku (1).
  3. Rozszerz klasę _Impl po stronie klienta. Zastąp metodę get ... Port() tak, aby używała Stubu utworzonego w kroku (2) zamiast wygenerowanego.
  4. Zmodyfikuj kod klienta, który napisałeś, aby zadzwonić do usługi sieci Web, aby używał kodu pośredniczącego utworzonego w kroku (2) i znaku _Impl utworzonego w kroku (3).

Uwaga: Upewnij się, że cokolwiek wywołuje generowanie skrótów przez wscompile (skrypt Ant?), Nie zastępuje 3 klas Java, które właśnie utworzyłeś/zmodyfikowałeś. Prawdopodobnie ma sens przeniesienie ich do innej paczki, aby nie zostały nadpisane.

1

Odpowiedź Yevgeniya Treyvusa jest bardzo dobra, ale powoduje powstanie nowego połączenia HTTPUrlConnection dla każdego połączenia SOAP. Dowiedziałem się podczas testowania jego podejścia, że ​​można ustawić ClientTransportFactory. Używam teraz CustomClientTransportFactory i ustawię go na Stub (przerzucając go na StubBase). Wtedy nie trzeba krok 2 i 3.

w kroku 4 jeden ustawia swój nowy ClientTransportFactory tak: ((StubBase) myPort) ._ setTransportFactory (nowa CustomClientTransportFactory());

0

Ray,

Dzięki za twój wkład. Wygląda na to, że twoje podejście jest lepsze, ponieważ pozwoli uniknąć kilku nieistotnych kroków. Będę musiał rzucić okiem. Jednak chyba brakuje mi czegoś nie wierzę dodatkowy httpconnection jest tworzony jako YourClientTransport.createHttpConnection (String s, SOAPMessageContext CTX) powinny przesłonić 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

wiem, że używasz Axis ale Próbowałem znaleźć tę samą odpowiedź na Weblogic, a ponieważ tytuł pytania i tagi są ogólne, oto moje rozwiązanie.

W mojej klasie klienta, która implementuje wygenerowany interfejs MyObject, dostosowałem metodę getServicePort() w następujący sposób (proszę zauważyć, że mam tu także zabezpieczenia).

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

Dokumentacja Oracle jest tutaj: http://docs.oracle.com/cd/E12840_01/wls/docs103/webserv_rpc/client.html#wp241849 ale błędnie twierdzi, że limit czasu w sekundach. W rzeczywistości jest w milisekundach!

-1

Należy użyć:

import javax.xml.rpc.Stub; 

... 


int timeout = <number of milliseconds>; 

((Stub) port)._setProperty(
       "axis.connection.timeout", 
       timeout); 
0

Może trochę późno na to pytanie, ale doszedłem do tego problemu dzisiaj. oparciu o rozwiązania zaproponowanego przez Jewgienija Treyvus (! Podziękować za nią) wpadłem na następujący:

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

To jest w zasadzie taka sama jak Jewgienij zaproponował ale z nieco mniej nadrzędnego (za pomocą połączenia fabryka).

Powiązane problemy