20 de junho de 2006 Resumo Este artigo traz uma introduc ao de como distribuir servicos Web im- plementados em Java no Apache Axis. O Apache Axis traz ferramentas que auxiliam no processo da implementa c ao e disponibilizac ao do servico. O presente documento explica tanto como disponibilizar um servico ma- nualmente, como usando as ferramentas disponveis. 1 Introducao O Apache Axis e uma ferramenta que auxilia tanto o desenvolvimento como a disponibilizacao de Servicos Web. Existem implementa coes para as linguagens C++ e Java. Aqui sera abordada apenas a implementa cao para Java. Na etapa de criacao do servico, o Axis dispoe de uma ferramenta para gerar um arquivo WSDL a partir de uma interface Java (Java2WSDL), e uma ferramenta para geracao de codigo a partir de um arquivo WSDL (WSDL2Java). Para a etapa de disponibilizacao do servico, o Axis traz uma aplicacao Web (que pode ser usada em qualquer Web Containter, como o Tomcat) que, por sua vez, e um container para servicos Web. Toda o esforco de serializacao e deseria- lizacao das mensagens, invocacao dos metodos, e tratada automaticamente pela aplicacao. Alem disso, a engine Axis usa o conceito de interceptadores (han- dlers). Os handlers podem ser denidos para interceptar as mensagens SOAP nos pontos de entrada e sada, na aplicacao cliente e no servidor. Este acesso `as mensagens permite que varias caractersticas sejam implementadas de forma transparente ao servico. Ha duas formas de distribuir servicos no Axis: a distribuicao instantanea e a distribuicao personalizada. A distribuicao instantanea a rapida e simples, porem nao permite que o usuario altere nenhuma opcao da distribuicao. Para isso deve-se usar a distribuicao personalizada. Nesta ultima, o usuario modica as opcoes de distribuicao atraves de um arquivo de descricao de distribuicao de servico Web (Web Service Depolyment Descriptor - WSDD). Ao longo do artigo, um servico exemplo sera implementado, distribudo e testado usando as funcionalidades da ferramenta Axis. 2 Distribuicao instantanea
E a forma mais simples de distribuir servicos Web no Axis. Para realizar a
distribuicao instantanea, basta copiar o arquivo fonte da classe Java que imple- menta o servico para o diretorio raiz da aplicacao do Axis, trocando a extensao 1 package exemplo; public class ServicoExemplo { public int dobro(int x) { return 2 * x; } public int triplo(int x) { return 3 * x; } public int quadruplo(int x) { return 4 * x; } } Figura 1: Codigo fonte da classe Java de exemplo do arquivo de .java para .jws. E pronto. Basta iniciar o servidor de aplicacao e o servico ja estara disponvel. Para ilustrar, suponha que se quer distribuir um servico que calcule o dobro, o triplo ou o quadruplo de um n umero. O codigo fonte da classe Java que implementa o servico esta listado na gura 1. Apos escrever o fonte, basta salvar o arquivo, com extensao .jws, no diretorio raiz da aplicacao do Axis ($CATALINA_HOME/webapps/axis/, no Tomcat, onde a variavel CATALINA_HOME e o diretorio raiz do Tomcat), como descrito. A partir deste momento, tudo e feito pelo Axis: O arquivo fonte e localizado, compilado, o arquivo WSDL e gerado, e as mensagens SOAP sao devidamente transformadas em invocacoes dos metodos da classe implementada. Todos os metodos p ublicos da classe sao adicionados `a interface do servico. Para testar o servico, abra um browser e digite o seguinte endereco: http://localhost:8080/axis/ServicoExemplo.jws. Deve aparecer a men- sagem There is a Web Service here, e um link para o WSDL do servico. Clique no link para ver o arquivo de descricao do servico (WSDL) que e gerado automaticamente pelo axis por meio da classe. Uma forma de testar a chamada dos metodos da classe distribuda e passando variaveis para a chamada na barra de enderecos do browser. Se, alem da URL do servico, for digitado ?method=dobro, signica que o metodo dobro() da classe sera invocado. Podem ser necessaria, ainda, outras variaveis, que representam os argumentos da chamada, caso ela use algum. No exemplo, e necessario dizer o n umero do qual se deseja calcular o dobro. Para isso, pode-se acrescentar o texto ¶m=N, onde N e o n umero passado como parametro. Como resposta para essa chamada, deve aparecer no browser a mensagem SOAP retornada pelo servico. Outra forma de testar uma chamada de metodo de um servico e por meio de um programa cliente. Essa forma sere descrita na secao 4. Apesar de simples e rapida, a distribuicao instantanea nao permite nenhuma 2 <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="ServicoExemplo" provider="java:RPC"> <parameter name="className" value="exemplo.ServicoExemplo"/> <parameter name="allowedMethods" value="*"/> <parameter name="scope" value="Aplication"/> </service> </deployment> Figura 2: Arquivo WSDD distribuindo o servico exemplo. conguracao na forma como distribumos o servico. Nao podemos, por exem- plo, especicar quais metodos da classe serao distribudos, adicionar handlers, entre outros. Para congurar essas opcoes, e necessario fazer a distribuicao personalizada. 3 Distribuicao personalizada
E atraves desta forma de distribuicao que todas funcionalidades do Axis podem
ser exploradas. Para realizar a distribuicao personalizada utiliza-se um arquivo WSDD. Um arquivo WSDD descreve como um servico (ou um handler) deve ser disponibilizado. Varios parametros podem ser especicados em um arquivo de descricao, am de personalizar a distribuicao do servico.
E no WSDD tambem, que se pode denir quais handlers devem interceptar as mensagens de entrada e sada do servico. Para o servico exemplo, um arquivo de descricao simples esta listado na gura 2. O elemento <deployment> informa para o Axis que se trata de um ar- quivo WSDD, e os lhos deste elemento devem ser adicionados `a aplicacao. O elemento <service> indica que se deseja distribuir um servico Web. O parametro name deste elemento corresponde ao nome do servico que se esta distribuindo, e o parametro provider indica que o servico segue as convencoes SOAP-RPC para invocar os metodos da classe. Os elementos <parameter> especicam as conguracoes da distribuicao do servico. Para o exemplo, a classe (exemplo.ServicoExemplo) e os metodos acessveis (* signica todos os metodos p ublicos da classe). Com o arquivo WSDD em maos, pode-se distribuir o servico. Para isso, deve- se executar o AdminClient, que vem com o Axis, passando o arquivo WSDD como parametro. Antes, porem, e necessario colocar as classes compiladas em um local onde o Axis possa encontra-las, no diretorio WEB-INF/classes, dentro da aplicacao do Axis. Esse e o diretorio raiz de onde as denicoes de classe dos servicos sao carregadas pelo Axis para poderem ser instanciadas (tambem pode- se empacotar as classes do servico em um arquivo .jar, ou similar, como .war, e colocar na pasta WEB-INF/lib). Assim, o parametro className tem como diretorio base WEB-INF/classes. Para rodar o AdminClient deve-se executar a classe org.apache.axis.client.AdminClient, passsando como parametro o arquivo WSDD: > java org.apache.axis.client.AdminClient deploy.wsdd 3 <undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="ServicoExemplo"/> </undeployment> Figura 3: Arquivo WSDD para remover o servico exemplo do Axis. package exemplo; public interface ServicoExemplo extends java.rmi.Remote { public int dobro(int x) throws java.rmi.RemoteException; public int triplo(int x) throws java.rmi.RemoteException; public int quadruplo(int x) throws java.rmi.RemoteException; } Figura 4: Interface para automatizar a distribuicao personalizada (supondo que o arquivo de descricao seja mesmo deploy.wsdd, e que as biblio- tecas do Axis estejam no classpath). Para remover um servico do Axis, basta executar o AdminClient passando um arquivo WSDD, onde a tag externa e <undepolyment>, como na gura 3. Este elemento indica que seus lhos devem ser retirados a aplicacao do Axis. Na distribuicao descrita acima, o servico exemplo e disponibilizado justa- mente como na distribuicao instantanea. No entanto, para servicos mais com- plexos, sera necessario especicar mais caractersticas no arquivo WSDD e es- creve-lo manualmente se torna uma tarefa difcil e cansativa. Existem, para isso, ferramentas no Axis que automatizam todo o processo. Essas ferramentas sao Java2WSDL e WSDL2Java. Java2WSDL gera um arquivo WSDL a partir de uma interface java. WSDL2Java gera o arquivo WSDD, e o codigo basico para a implementa cao do servico e do cliente. Para automatizar todo o processo de distribuicao persona- lizada, devemos prosseguir da seguinte forma: 1. Escrever e compilar uma interface com os metodos que devem estar acessveis no servico. A interface deve extender java.rmi.Remote e todos os metodos devem lancar a excecao java.rmi.RemoteException. Para o servico exemplo, a interface ca como na gura 4. 2. Executar o Java2WSDL para gerar um arquivo WSDL a partir da inter- face. > java org.apache.axis.wsdl.Java2WSDL -o ServicoExemplo.wsdl -l"http://localhost:8080/axis/services/ServicoExemplo" -n "urn:ServicoExemplo" -p"exemplo" "urn:ServicoExemplo" exemplo.ServicoExemplo onde: -o indica o nome do arquivo WSDL gerado; -l indica a localizacao (URL) do servico; -n indica o namespace do WSDL gerado; 4 -p indica um mapeamento do pacote Java para o namespace; a classe passada como parametro e a interface do servico, mostrada na gura 4. 3. Executar o WSDL2Java para gerar o arquivo WSDD, o stub e outras classes para facilitar a criacao do servico e do programa cliente. > java org.apache.axis.wsdl.WSDL2Java -o -d Application -s -S true -N "urn:ServicoExemplo" "exemplo" ServicoExemplo.wsdl onde: -o indica o diretorio onde os arquivos gerados serao colocados; -d indica o escopo do servico; -s indica que se quer gerar as classes do lado do servidor; -S indica que se quer gerar o skeleton para o servico; -N indica um mapeamento do namespace do servico para o pacote Java; o arquivo WSDL especicado e o mesmo gerado no passo 2. Para o comando acima, serao gerados os seguintes arquivos: deploy.wsdd - arquivo de descricao de distribuicao para distribuir o ser- vico; undeploy.wsdd - arquivo de descricao de distribuicao para remover o servico; ServicoExemploSoapBindingImpl.java - classe que implementa o servi- co; ServicoExemploSoapBindingSkeleton.java - skeleton do servico, im- plementa a interface do servico; ServicoExemplo.java - interface do servico; ServicoExemploSoapBindingStub.java - stub do cliente, implementa a interface do servico; ServicoExemploService.java - interface que representa o servico; ServicoExemploServiceLocator.java - classe responsavel por prover instancias de stubs, usada pela aplicacao cliente. 4. implementar a classe *SoapBindingImpl.java ( ServicoExemploSoapBindingImpl.java no exemplo) com o codigo do servico. 5. compilar as classes geradas no passo 3 e separar as classes do servico (*SoapBindingSkeleton e *SoapBindingImpl) das classes do cliente. 5 6. Juntar as outras classes do servico (caso haja alguma) com as classes geradas automaticamente que nao fazem parte do cliente. 7. Por ultimo, deve-se mover as classes do servico para o diretorio WEB-INF/classes e executar o AdminClient passando o arquivo WSDD gerado no passo 3. Para servicos onde dados de tipos complexos sao enviados nas mensagens SOAP, o passo 3 acima gerara classes serializaveis que representam esses tipos. Essas classes implementam XML beans que o Axis usa para enviar objetos estruturados nas mensagens SOAP. Essas classes de objetos serializaveis sao geradas a partir de denicoes Schema presentes no WSDL do servico. No lado do servico, os mapeamentos de tipos sao denidos no arquivo WSDD. No lado do cliente, os mapeamentos sao denidos na classe stub. Vale a pena mencionar que os passos acima podem ser executados por um script. O Axis traz, para isso, denicoes de tarefas Ant. Na documentacao do Axis ha um tutorial que ensina a usar essas tasks. 4 Criando um programa cliente Se for feita a distribuicao instantanea, ou nao forem usadas as ferramentas Java2WSDL e WSDL2Java, dever-se-a escrever um cliente manualmente. Um cliente deve instanciar a classe org.apache.axis.client.Service e, a par- tir dessa instancia, invocar o metodo createCall(), que instancia um objeto do tipo org.apache.axis.client.Call. Deve-se entao invocar os metodos setTargetEndpointAddress() passando a URL do servico como parametro, e depois setOperationName passando um objeto javax.xml.namespace.QName representando o nome da operacao. Depois disso, basta chamar o metodo invoke(), passando um array do tipo java.lang.Object[], contendo os pa- rametros para a chamada remota. Para o servico exemplo, um cliente simples que invoca o metodo dobro passando 12345 e mostra o resultado, esta listado na gura 5. Caso sejam usadas as ferramentas Java2WSDL e WSDL2Java, basta usar a classe *ServiceLocator e invocar o metodo get*(), onde * e o nome do servico. Este metodo retornara um stub para o servico, que implementa a interface do servico e cuida da invocacao remota dos metodos. Assim nao e necessario se preocupar com os detalhes da chamada. Para o servico exemplo, um cliente que usa as classes geradas automaticamente esta listado na gura 6. 6 public class Client { public static void main(String[] args) { try { String endPoint = "http://localhost:8080/axis/services/ServicoExemplo"; org.apache.axis.client.Service service = new org.apache.axis.client.Service(); org.apache.axis.client.Call call; call = (org.apache.axis.client.Call) service.createCall(); call.setTargetEndpointAddress(endPoint); call.setOperationName( new javax.xml.namespace.QName("dobro")); System.out.println( call.invoke(new Object[] { 12345 })); } catch (javax.xml.rpc.ServiceException e) { e.printStackTrace(); } catch (java.rmi.RemoteException e) { e.printStackTrace(); } } } Figura 5: Cliente para o ServicoExemplo que imprime na tela o dobro de 12345 7 public class Client { public static void main(String[] args) { try { ServicoExemploServiceLocator locator = new ServicoExemploServiceLocator(); ServicoExemplo servico = locator.getServicoExemplo(); System.out.println(servico.dobro(12345)); } catch (javax.xml.rpc.ServiceException e) { e.printStackTrace(); } catch (java.rmi.RemoteException e) { e.printStackTrace(); } } } Figura 6: Cliente para o ServicoExemplo que imprime na tela o dobro de 12345, usando as classes geradas pela ferramente WSDL2Java 8