Como defino o tempo limite para um cliente de serviço da web JAX-WS?

93

Usei JAXWS-RI 2.1 para criar uma interface para meu serviço da web, com base em um WSDL. Posso interagir com o serviço da web sem problemas, mas não consegui especificar um tempo limite para enviar solicitações ao serviço da web. Se por algum motivo ele não responder, o cliente parece apenas girar suas rodas para sempre.

Procurar por aí revelou que provavelmente eu deveria tentar fazer algo assim:

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

Também descobri que, dependendo de qual versão do JAXWS-RI você possui, pode ser necessário definir estas propriedades:

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

O problema que tenho é que, independentemente de qual das opções acima seja a correta, não sei onde posso fazer isso. Tudo o que tenho é uma Servicesubclasse que implementa a interface gerada automaticamente para o serviço da web e no ponto em que isso está sendo instanciado, se o WSDL não responder, então já é tarde demais para definir as propriedades:

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

Alguém pode me apontar na direção certa?!

nove lados
fonte
5
Acho que não tenho uma resposta para você, mas sua pergunta me ajudou a resolver meu problema. Eu sabia sobre a propriedade com.sun.xml.ws.request.timeout, mas não sobre a com.sun.xml.internal.ws.request.timeout.
Ron Tuffin de

Respostas:

89

Eu sei que isso é antigo e respondido em outro lugar, mas espero que isso encerre isso. Não sei por que você deseja baixar o WSDL dinamicamente, mas as propriedades do sistema:

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

deve se aplicar a todas as leituras e conexões usando HttpURLConnection que JAX-WS usa. Isso deve resolver seu problema se você estiver obtendo o WSDL de um local remoto - mas um arquivo em seu disco local provavelmente é melhor!

Em seguida, se você deseja definir tempos limite para serviços específicos, depois de criar seu proxy, você precisa convertê-lo em um BindingProvider (que você já conhece), obtenha o contexto da solicitação e defina suas propriedades. A documentação JAX-WS online está errada, esses são os nomes de propriedade corretos (bem, eles funcionam para mim).

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

Claro, essa é uma maneira horrível de fazer as coisas, eu criaria uma boa fábrica para produzir esses provedores de ligação que podem ser injetados com os tempos limite que você deseja.

alpino
fonte
10
Observe que as propriedades REQUEST_TIMEOUT / CONNECT_TIMEOUT são realmente herdadas da classe SUN interna com.sun.xml.internal.ws.developer.JAXWSProperties e (pelo menos no Linux de 32 bits) javac 1.6.0_27 e javac 1.7.0_03 falham em compilar este código (semelhante a bugs.sun.com/view_bug.do?bug_id=6544224 ) ... você precisa passar -XDignore.symbol.file para javac para fazê-lo funcionar.
JavaGuy,
O que não funciona? Acabei de verificar isso e está funcionando para mim.
alpino
Apenas confirmando que acabei de usar isso com JAX-WS RI 2.2.8 e JDK 1.7 e funcionou muito bem. Obrigado!
bconneen
Classes e parâmetros que possuem "interno" em seu nome totalmente qualificado não devem ser usados, uma vez que são dependentes do fornecedor e, portanto, não são portáveis ​​entre diferentes implementações JDK. No caso dos parâmetros jax-ws, por exemplo, as propriedades não internas correspondentes existem na classe com.sun.xml.ws.client.BindingProviderProperties.
polaretto
1
@ Matt1776 sim, claro que está faltando: embora JAX-WS seja uma especificação de API, você precisa de uma implementação de biblioteca, neste caso jaxws-ri.jar ou jaxws-rt.jar, que não faz parte do JDK. Você só precisa fazer o download e adicioná-lo ao seu ptoject e você terá essas propriedades disponíveis.
polaretto
40

As propriedades na resposta aceita não funcionaram para mim, possivelmente porque estou usando a implementação JBoss do JAX-WS?

Usar um conjunto diferente de propriedades (encontrado no Guia do Usuário JBoss JAX-WS ) fez com que funcionasse:

//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
fonte
2
Não estou usando o JBoss, mas apenas as propriedades neste comentário funcionaram para mim, nada mais funcionou.
PaulP
2
Os nomes das propriedades dependem da implementação JAX-WS. Uma lista pode ser encontrada aqui: java.net/jira/browse/JAX_WS-1166
fabstab
3
O link java.net está quebrado. github.com/javaee/metro-jax-ws/issues/1166
trunkc
12

Aqui está minha solução de trabalho:

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

    }
}
Vnoel
fonte
3
Essas configurações são equivalentes a "javax.xml.ws.client.connectionTimeout" e "javax.xml.ws.client.receiveTimeout" ??
Jose Tepedino
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);

Isso funcionou para mim.

Daniel Kaplan
fonte
Obrigado! Para mim também, é uma maneira muito fácil
Kosm
4
Isso usa classes Apache CXF, porém, pode ser melhor adicionar isso na resposta. Um link para o qual os frascos CXF os contêm também ajudaria muito.
JBert
@JBert eu concordo. Eu respondi isso anos atrás e não consigo me lembrar. Sinta-se à vontade para editar a resposta.
Daniel Kaplan
8

Se você estiver usando JAX-WS no JDK6, use as seguintes propriedades:

com.sun.xml.internal.ws.connect.timeout  
com.sun.xml.internal.ws.request.timeout
Domenico Briganti
fonte
System.setProperty ("com.sun.xml.internal.ws.connect.timeout", "300"); System.setProperty ("com.sun.xml.internal.ws.request.timeout", "300") funcionou para mim.
2787184
2
Em alguns contextos, você não sabe o tempo de programação qual versão do JAXWS (interna ou independente) será usada no tempo de execução. Os dois são bastante compatíveis, exceto por esse recurso de tempo limite. As chaves são diferentes ( com.sun.xml.internal.ws.connect.timeoutvs com.sun.xml.ws.connect.timeout) e também a classe (ou interface) que as define ( 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). Minha melhor ideia é definir ambos, usando valores literais como chaves.
Lorinczy Zsigmond
5

Caso o seu appserver seja WebLogic (para mim era 10.3.6), as propriedades responsáveis ​​pelos tempos limite são:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout
E.Egiazarov
fonte
3

Não tenho certeza se isso vai ajudar no seu contexto ...

O objeto de sabão pode ser lançado como um 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();

Por outro lado, se você deseja definir o tempo limite na inicialização do objeto MyWebService, isso não ajudará.

Isso funcionou para mim quando queria atingir o tempo limite das chamadas de WebService individuais.

Ron Tuffin
fonte
2

a maneira mais fácil de evitar a recuperação lenta do WSDL remoto ao instanciar seu SEI é não recuperar o WSDL do terminal de serviço remoto no tempo de execução.

isso significa que você deve atualizar sua cópia WSDL local sempre que o provedor de serviços fizer uma alteração impactante, mas também significa que você deve atualizar sua cópia local sempre que o provedor de serviços fizer uma mudança impactante.

Quando eu gero meus stubs de cliente, digo ao JAX-WS runtime para anotar o SEI de forma que ele leia o WSDL de um local pré-determinado no caminho de classe. por padrão, a localização é relativa à localização do pacote do SEI de serviço


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

o atributo wsldLocation informa ao SEI onde ele pode localizar o WSDL e a cópia garante que o wsdl (e o xsd de suporte .. etc.) esteja no local correto.

como o local é relativo ao local do pacote do SEI, criamos um novo subpacote (diretório) chamado wsdl e copiamos todos os artefatos wsdl nele.

tudo o que você precisa fazer neste ponto é certificar-se de incluir todos os * .wsdl, * .xsd além de todos os * .class ao criar seu arquivo jar de artefato stub do cliente.

(no caso de você estar curioso, a anotação @webserviceClient é onde este local wsdl é realmente definido no código java

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")
Helter Scelter
fonte