sexta-feira, 16 de janeiro de 2009

JAX-WS no Rasea

JAX-WS é uma API que veio para substituir o antigo JAX-RPC (veja comparativo aqui). E para ficar dentro dos padrões e das especificações JEE, o Rasea Server usa como API de webservices o JAX-WS em sessions stateless EJB3.

Para o lado cliente, esta API fornece alguns modelos de consumo de serviços, sendo o consumo via proxy escolhido por nós do Rasea. Para consumir um serviço via classes proxy, é necessário executar o comando wsimport (via ant task ou linha de comando) para que sejam geradas as classes do serviço e os tipos usados.
wsimport http://localhost:8001/rasea-ws/AccessControl?wsdl
Excelente! Porém, o código da classe Service gerada instancía uma java.net.URL - num bloco static - para este caminho, além de estabelecer uma conexão a cada comunicação para o parse do WSDL em questão. Logo, podemos enumerar 2 problemas:
  1. Web service endpoint. Enpoint statico nas classes client;
  2. Wsdl location. Consumo de recursos - de rede - para fazer o parse do wsdl que se encontra no server.
Certamente o local do WSDL, bem como enpoint do serviço em uma companhia não coincidirão com os locais de WSDL e Web service enpoint de desenvolvimento do Rasea.

Como apresentado no post anterior, a companhia pode, e até recomenda-se, fazer uso de um barramento de serviços, logo é necessário que o usuário possa informar o endpoint correto. Por isso, o Rasea Client usa um arquivo de propriedades para configurar o servidor onde o serviço ficará de fato deployado.

Para o primeiro problema, decidimos embarcar o WSDL no próprio jar das classes client, o que evita o consumo de rede para alcancá-lo. Então foi necessário criar um xml de catalog JAX-WS que descreve um nome para o wsdl e um local alcançável a partir da pasta META-INF do jar.

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"
prefer="system">

<system systemId="http://rasea.org/wsdl/AccessControl"
uri="../AccessControl.wsdl"/>
</catalog>
<!-- https://glassfish.dev.java.net/public/CDDL+GPL.html -->
Note que o WSDL vai ficar na pasta raiz do jar. Mas para as classes client "entenderem" esta decisão nossa, precisamos de uns parâmetros a mais no wsimport.
wsimport -catalog ws/jax-ws-catalog.xml -wsdllocation
http://rasea.org/wsdl/AccessControl AccessControl.wsdl
É necessário informar o arquivo de catalog (que deve ser colocado na pasta META-INF do jar) e o local do wsdl (que será anotado na classe de serviço). Por último fornecemos o wsdl acessado localmente.

Como resultado temos:
@WebServiceClient(name = "AccessControlService", targetNamespace =
"http://rasea.org/ws/AccessControl", wsdlLocation = "http://rasea.org/wsdl/AccessControl")
public class AccessControlService
extends Service
{
...
}
Nos falta um meio de informar à esta classe, em tempo de execução, a localização correta do endpoint do serviço. A a interface javax.xml.ws.BindingProvider fornece um contexto de requisição através do método .getRequestContext() retornando um Map, eque é onde devemos informar o endpoint do seviço.
AccessControlService service = new AccessControlService();
AccessControl port = service.getAccessControlPort();
BindingProvider bindingProvider = (BindingProvider) port;

Map<String, Object> requestContext = bindingProvider.getRequestContext();

requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
http:
//myserver:7001/rasea-ws/AccessControl);

Este trecho substitui o endpoint original provindo do WSDL do serviço permitindo que o client se conecte ao endpoint correto.

Pronto! Agora você pode deployar seu jar com os clients em qualquer lugar sem a necessida de acessar a rede constatemente para obter o WSDL do serviço e sem usar estaticamente um endpoint para acessar o serviço. Você pode ver a aplicação completa destas duas dicas no código fonte do Rasea Client.

Outra informação é que ao utilizar @WebServiceRef num session EJB, alguns servidores (ex.: BEA Weblogic Server) não conseguem fazer o deploy da aplicação quando os WSDLs dos serviços não sejam alcançáveis durante o deploy. Ou seja, se seus provedores de serviço estiverem indisponíveis, sua aplicação pode não ser publicada até que estes serviços voltem a funcionar.

Daí a importância de adotar uma política adequada na localização do WSDL e definição do endpoint não estaticamente.

Até a próxima!

0 comentários:

Postar um comentário