Java Web Services Cookbook
Transcrição
Java Web Services Cookbook
Departamento de Engenharia Informática Sistemas Distribuídos Java Web Services Cookbook 12 de Maio de 2009 Java Web Services Cookbook Índice Nota prévia ................................................................................................................ 3 Criar um Web Service ............................................................................................... 4 Estratégia............................................................................................................... 4 Passos básicos ....................................................................................................... 4 Variantes ............................................................................................................... 8 Diagnóstico de erros ...................................................................................... 8 Usar Eclipse ................................................................................................... 8 Activar um JAX-WS Handler no servidor .....................................................10 Registar o Web Service no UDDI .................................................................10 Criar um servidor com dois endpoints ...........................................................12 Criar um cliente de Web Service ..............................................................................15 Estratégia..............................................................................................................15 Passos básicos ......................................................................................................15 Variantes ..............................................................................................................17 Diagnóstico de erros .....................................................................................17 Usar Eclipse ..................................................................................................17 Activar um JAX-WS Handler no cliente .......................................................18 Obter a localização do Web Service a partir do UDDI ...................................19 Criar um cliente de dois Web Services ..........................................................21 2 Java Web Services Cookbook Nota prévia Este livro de "receitas" descreve procedimentos para o desenvolvimento de Web Services. Não explica nem pretende explicar todos os conceitos envolvidos, que deverão ser estudados e compreendidos em pormenor antes da utilização deste guia. A infra-estrutura de software que se assume é: Java 5, JWSDP 2.0+, Ant 1.7.0+ e ImportAnt 5.5.1+. São também apresentadas variantes que usam o Eclipse Java Enterprise Europa+. A estrutura base de directorias dos projectos (ImportAnt) é a seguinte: project build.xml Project Ant build file: - import modules - define properties - define classpaths - define build targets build.properties Property overrides config configuration files lib src library (jar) files source code java Java classes web Web resources (JSP, HTML, ...) xml WSDL, XSD and other XML sources etc additional files build temporary build directory dist temporary application or library distribution directory 3 Java Web Services Cookbook Criar um Web Service Estratégia Um Web Service é uma aplicação servidora que responde a pedidos de clientes formatados em XML e transportados em mensagens SOAP. O procedimento consiste em criar uma estrutura de directórios e ficheiros para o projecto, definir o Web Service através de WSDL e XSD, gerar código Java para tratamento da comunicação e da conversão de dados e, finalmente, escrever o restante código. Aqui o Web Service é genericamente designado como MyWS. Este e outros nomes relacionados deverão ser ajustados caso a caso, de acordo com o pretendido. Passos básicos 1. Criar projecto Ant a. Criar estrutura de directorias e ficheiros para o projecto. import-ant my-ws config resources jax-ws-server web.xml sun-jaxws.xml server-custom-binding.xml src java xml web.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app> <display-name>JAX-WS @ant.project.name@</display-name> <description>JAX-WS application: @ant.project.name@</description> <listener> <listenerclass>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listenerclass> </listener> <servlet> <servlet-name>jax-ws-servlet</servlet-name> <display-name>JAX-WS servlet</display-name> <description>JAX-WS endpoint</description> <servletclass>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jax-ws-servlet</servlet-name> <url-pattern>/endpoint</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> 4 Java Web Services Cookbook </session-config> </web-app> sun-jaxws.xml <?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="endpoint" interface="@jax-ws-server.ties.interface.name@" implementation="@jax-ws-server.impl.class.name@" wsdl="WEB-INF/wsdl/@jax-ws-server.wsdl.file-name@" service="{@jax-ws-server.wsdl.namespace@}@jax-wsserver.wsdl.service-name@" port="{@jax-ws-server.wsdl.namespace@}@jax-wsserver.wsdl.port-name@" url-pattern="/endpoint" /> </endpoints> server-custom-binding.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="@jax-ws-server.wsdl.file-name@" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> @jax-ws-server.handler-chains@ </bindings> </bindings> Todos estes ficheiros contêm itens de substituição (@...@) que serão substituídos pelo ImportAnt durante o processo de construção. Deste modo, estes ficheiros permanecem sempre iguais e o que muda é o build.xml. b. Criar ficheiro de construção build.xml: <project name="MyWS" default="build" basedir="."> <property name="import-ant" value="../import-ant" /> <!-- IMPORTS --> <import file="${import-ant}/core.xml" /> <import file="${import-ant}/tomcat.xml" /> <import file="${import-ant}/jwsdp.xml" /> <import file="${import-ant}/jax-ws-server.xml" /> <!-- Web Service definitions --> <property name="jax-ws-server.wsdl.file-name" value="" /> <property name="jax-ws-server.wsdl.namespace" value="" /> <property name="jax-ws-server.wsdl.service-name" value="" /> <property name="jax-ws-server.wsdl.port-name" value="" /> <property name="jax-ws-server.ties.package" value="" /> <property name="jax-ws-server.ties.interface.simple-name" value="" /> <property name="jax-ws-server.impl.package" value="" /> <property name="jax-ws-server.impl.class.simple-name" value="" /> <!-- CLASSPATHS --> <path id="compile.classpath"> <pathelement location="${build.classes.rel-dir}" /> <path refid="project.lib.path" /> <path refid="jwsdp.jars.path" /> </path> 5 Java Web Services Cookbook <!-- TARGETS --> <target name="build" depends="config,build-jax-ws-server" description="Builds the project"> </target> </project> c. Criar directorias temporárias build e dist e confirmar que sintaxe do build.xml está correcta: $ ant init 2. Definir contrato do serviço a. Criar ficheiro MyWS.wsdl em src/xml que especifica as operações do Web Service com o vocabulário WSDL. Os tipos de dados são definidos com o vocabulário XSD. <?xml version="1.0" encoding="UTF-8"?> <definitions name="MyWS" targetNamespace="http://myWS" xmlns:tns="http://my-ws" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <types> <xsd:schema elementFormDefault="qualified" targetNamespace="http://my-ws"> <xsd:complexType name="MyOperationType"> <xsd:sequence> <xsd:element name="i" type="xsd:int" /> <xsd:element name="z" type="xsd:string" /> </xsd:sequence> </xsd:complexType> <xsd:element name="myOperation" type="tns:MyOperationType" /> <xsd:complexType name="MyOperationResponseType"> <xsd:sequence> </xsd:sequence> </xsd:complexType> <xsd:element name="myOperationResponse" type="tns:MyOperationResponseType" /> <message name="myOperation"> <part name="parameters" element="tns:myOperation" /> </message> <message name="myOperationResponse"> <part name="result" element="tns:myOperationResponse" /> </message> <portType name="MyPortType"> <operation name="myOperation"> <input message="tns:myOperation" name="myOperation"/> <output message="tns:myOperationResponse" name="myOperationResponse"/> </operation> </portType> <binding name="MyBinding" type="tns:MyPortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="myOperation"> <soap:operation soapAction="" /> <input> 6 Java Web Services Cookbook <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </operation> </binding> <service name="MyService"> <port name="MyPort" binding="tns:MyBinding"> <soap:address location="REPLACE_WITH_ACTUAL_URL" /> </port> </service> </definitions> b. Definir nomes seguindo a convenção dos sufixos: ...Service, ...Port, ...PortType, ...Binding, ... 3. Criar serviço a. Gerar ties i. Definir valores de propriedades de Web Service no build.xml de acordo com os valores definidos no WSDL <!-- Web Service definitions --> <property name="jax-ws-server.wsdl.file-name" value="MyWS.wsdl" /> <property name="jax-ws-server.wsdl.namespace" value="http://my-ws" /> <property name="jax-ws-server.wsdl.service-name" value="MyService" /> <property name="jax-ws-server.wsdl.port-name" value="MyPort" /> <property name="jax-ws-server.ties.package" value="my.ws.ties" /> <property name="jax-ws-server.ties.interface.simple-name" value="MyPortType" /> <property name="jax-ws-server.impl.package" value="my.ws" /> <property name="jax-ws-server.impl.class.simple-name" value="MyServiceImpl" /> ii. Executar wsimport $ ant build-jax-ws-server iii. Consultar ties gerados pelo wsimport em build/jax-wsserver/wsimport, em particular MyService.java e MyPortType.java 7 Java Web Services Cookbook b. Criar implementação do serviço i. Criar classe em src/java/my/ws, implementando todos os métodos definidos em MyPortType package my.ws; import my.ws.ties.*; @javax.jws.WebService (endpointInterface="my.ws.ties.MyPortType") public class MyServiceImpl implements MyPortType { public void myOperation(int i, String s) { return; } } c. Construir Web Service e instalar $ catalina start $ ant deploy d. Confirmar instalação correcta http://localhost:8080/MyWS/endpoint http://localhost:8080/MyWS/endpoint?wsdl Variantes Diagnóstico de erros Consultar ficheiro de log: %CATALINA_HOME%\logs\launcher.server.log $ ant rebuild $ ant quick-redeploy O ficheiro de log pode ser consultado continuamente com o comando tail: $ tail -f %CATALINA_HOME%\logs\launcher.server.log Usar Eclipse (Antes do passo 2) Iniciar o Eclipse e criar novo projecto File, New, Project, Java Project, Project name: MyWS Create project from existing source, Next Source, Source folder, src/java, Default output folder: build/eclipse Libraries, Add library, User library: jwsdp-essd-2008, Finish Add class folder: build/classes, Finish O conjunto de bibliotecas (user library) jwsdp-essd-2008 pode ser importado a partir do ficheiro contido na directoria %JWSDP_HOME%\eclipse. 8 Java Web Services Cookbook Configurar Ant Windows, Show View, Ant View build.xml ~drag-and-drop~> Ant View Hide internal targets (Apoio ao passo 2, a) Criar WSDL New, Other..., XML, WSDL Next Parent folder: src/xml File name: MyWS.wsdl, Next Target namespace: http://my-ws Namespace prefix: tns Create WSDL Skeleton Protocol: SOAP SOAP Binding options: document literal Finish Indentar XML WSDL, View Source Select All Text Source, Format, Document (Depois do passo 3, a, ii) Refrescar Eclipse Project, Refresh (Apoio ao passo 3, b, i) Criar classe File, New, Class package: my.ws name: MyServiceImpl superclass: java.lang.Object interfaces: my.ws.ties.MyPortType inherit abstract methods generate comments Anotar classe @javax.jws.WebService (endpointInterface="my.ws.ties.MyPortType") Escrever código Java dos métodos. 9 Java Web Services Cookbook Activar um JAX-WS Handler no servidor Acrescentar o seguinte target ao build.xml. <target name="-replace-jax-ws-server-custom-tokens(dir)"> <replace dir="${dir}" token="@jax-ws-server.handler-chains@"> <replacevalue><![CDATA[ <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <jws:handler-chain> <jws:handler> <jws:handlerclass>my.ws.handler.MyHandler</jws:handler-class> </jws:handler> </jws:handler-chain> </jws:handler-chains> ]]></replacevalue> </replace> </target> A classe my.ws.handler.MyHandler deverá existir e ser um JAX-WS Handler. Registar o Web Service no UDDI Obter uma biblioteca com as classes step.framework.ws.registry.* e colocar numa das directorias lib do projecto: lib my-ws lib Criar e preencher ficheiros de configuração de registo Registry.properties (dados do servidor UDDI) e Registration.properties (dados de registo). my-ws config ws-registry Registry.properties Registration.properties Registry.properties # # Registry # [email protected]@ [email protected]@ [email protected]@ #locale= optionOutputMessages=true #optionValidateURI=false #optionWarnAboutLocale=true Registration.properties # # Registration # organizationName=My Organization serviceName=My Service serviceBindingAccessURI=http://myserver:8080/MyWS/endpoint classificationScheme=unspsc-org:unspsc:3-1 10 Java Web Services Cookbook classificationName=Research and Science Based Services classificationValue=81000000 Criar ou editar ficheiro build.properties para acrescentar: ws-registry.username=testuser ws-registry.password=testuser Modificar build.xml, acrescentando a importação de um novo módulo: <import file="${import-ant}/ws-registry.xml" /> As propriedades relacionadas com o registo UDDI: <property name="ws-registry.url" value="http://localhost:8080/RegistryServer/" /> <property name="ws-registry.main-class" value="step.framework.ws.registry.Main" /> <property name="dir" value="${build.config.ws-registry.rel-dir}" /> <property name="ws-registry.publish.args" value="${dir}/Registry.properties publish ${dir}/Registration.properties ${dir}/RegistrationKey.properties" /> <property name="ws-registry.delete.args" value="${dir}/Registry.properties delete key ${dir}/RegistrationKey.properties" /> <property name="ws-registry.query.args" value="${dir}/Registry.properties query classification ${dir}/Registration.properties" /> Uma nova dependência no build.xml: <target name="build" depends="config,build-ws-registry,build-jax-ws-server" description="Builds the project"> </target> Efectuar o registo: $ ant build-ws-registry ws-publish Consultar o registo: $ ant build-ws-registry ws-query Apagar o registo: $ ant build-ws-registry ws-delete 11 Java Web Services Cookbook Criar um servidor com dois endpoints É possível que o mesmo servidor disponibilize dois endpoints, neste caso, Hello e Calc. No entanto, os itens de substituição (@...@) do ImportAnt já não funcionam correctamente e é necessário efectuar a configuração directamente nos ficheiros. Criar dois ficheiros de custom bindings: my-ws config resources jax-ws-server web.xml sun-jaxws.xml server-custom-binding_hello.xml server-custom-binding_calc.xml web.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app> <display-name>JAX-WS Application</display-name> <description>JAX-WS Application</description> <listener> <listenerclass>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listenerclass> </listener> <servlet> <servlet-name>JAX-WS Servlet</servlet-name> <display-name>JAX-WS Servlet</display-name> <description>JAX-WS endpoint</description> <servletclass>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>JAX-WS Servlet</servlet-name> <url-pattern>/endpoint_hello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>JAX-WS Servlet</servlet-name> <url-pattern>/endpoint_calc</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app> sun-jaxws.xml <?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="endpoint_hello" interface="hello.ties.HelloPortType" implementation="hello.HelloServiceImpl" wsdl="WEB-INF/wsdl/Hello.wsdl" service="{http://hello}HelloService" port="{http://hello}HelloPort" url-pattern="/endpoint_hello" /> <endpoint name="endpoint_calc" interface="calc.ties.CalcPortType" implementation="calc.CalcServiceImpl" 12 Java Web Services Cookbook wsdl="WEB-INF/wsdl/Calc.wsdl" service="{http://calc}CalcService" port="{http://calc}CalcPort" url-pattern="/endpoint_calc" /> </endpoints> server-custom-binding_hello.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="Hello.wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <jws:handler-chain> <jws:handler> <jws:handler-class>util.HelloLoggingHandler</jws:handlerclass> </jws:handler> </jws:handler-chain> </jws:handler-chains> </bindings> </bindings> server-custom-binding_calc.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="Calc.wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <jws:handler-chain> <jws:handler> <jws:handler-class>util.CalcLoggingHandler</jws:handlerclass> </jws:handler> </jws:handler-chain> </jws:handler-chains> </bindings> </bindings> 13 Java Web Services Cookbook O build.xml deverá ter agora os seguintes targets: <target name="build" depends="config,build-jax-ws-server-ties_hello,build-jax-wsserver-ties_calc,compile,create-jax-ws-server-war" description="Builds the project"> </target> <target name="build-jax-ws-server-ties_hello"> <echo level="info" message="Creating Hello ties..." /> <antcall target="build-jax-ws-server-ties" inheritAll="false"> <param name="jax-ws-server.wsdl.file-name" value="Hello.wsdl" /> <param name="jax-ws-server.wsimport.bindings.file-pattern" value="*binding*hello.xml" /> <param name="jax-ws-server.ties.package" value="hello.ties" /> </antcall> </target> <target name="build-jax-ws-server-ties_calc"> <echo level="info" message="Creating Calc ties..." /> <antcall target="build-jax-ws-server-ties" inheritAll="false"> <param name="jax-ws-server.wsdl.file-name" value="Calc.wsdl" /> <param name="jax-ws-server.wsimport.bindings.file-pattern" value="*binding*calc.xml" /> <param name="jax-ws-server.ties.package" value="calc.ties" /> </antcall> </target> As propriedades relativas a Web Services (jax-ws-server.wsdl.file-name, jaxws-server.wsdl.namespace, etc.) devem desaparecer, porque as definições são agora feitas directamente nos ficheiros de configuração e não através do mecanismo de substituição (@...@). 14 Java Web Services Cookbook Criar um cliente de Web Service Estratégia Um cliente de Web Service é uma aplicação que invoca um Web Service. Nesta receita cria-se um cliente que se executa a partir da linha de comando, no entanto, o procedimento é idêntico para aplicações Web ou de outro tipo. O procedimento consiste em criar uma estrutura de directórios e ficheiros para o projecto, gerar código Java de invocação e de conversão de dados e, finalmente, escrever o restante código. Aqui o cliente de Web Service é genericamente designado como MyWSCli. Este e outros nomes relacionados deverão ser ajustados caso a caso, de acordo com o pretendido. Passos básicos 1. Criar projecto Ant a. Criar estrutura de directorias e ficheiros para o projecto. import-ant my-ws config resources jax-ws-client client-custom-binding.xml src java client-custom-binding.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="@jax-ws-client.wsdl.url@" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> @jax-ws-client.handler-chains@ </bindings> </bindings> Este ficheiro contêm itens de substituição (@...@) que serão substituídos pelo ImportAnt durante o processo de construção. Deste modo, o ficheiro permanece sempre igual e o que muda é o build.xml. b. Criar ficheiro de construção build.xml: <project name="MyWSCli" default="build" basedir="."> <property name="import-ant" value="../import-ant" /> <!-- IMPORTS --> 15 Java Web Services Cookbook <import <import <import <import file="${import-ant}/core.xml" /> file="${import-ant}/console-app.xml" /> file="${import-ant}/jwsdp.xml" /> file="${import-ant}/jax-ws-client.xml" /> <!-- Console application --> <property name="run.main-class" value="my.MyClient" /> <property name="run.args" value="http://localhost:8080/MyWS/endpoint" /> <!-- Web Service client --> <property name="jax-ws-client.wsdl.url" value="http://localhost:8080/MyWS/endpoint?wsdl" /> <property name="jax-ws-client.stubs.package" value="my.ws.stubs" /> <!-- CLASSPATHS --> <path id="compile.classpath"> <pathelement location="${build.classes.rel-dir}" /> <path refid="project.lib.path" /> <path refid="jwsdp.jars.path" /> </path> <path id="run.classpath"> <path refid="compile.classpath" /> </path> <target name="build" depends="config,build-jax-ws-client,compile" description="Build the project"> </target> </project> c. Criar directorias temporárias build e dist e confirmar que sintaxe do build.xml está correcta: $ ant init 2. Criar cliente a. Gerar stubs i. Executar wsimport $ ant build-jax-ws-client ii. Consultar stubs gerados pelo wsimport em build/jax-wsclient/wsimport, em particular MyService.java e MyPortType.java b. Criar classe do cliente em src/java/my package my; import javax.xml.ws.BindingProvider; import javax.xml.ws.WebServiceException; import my.ws.stubs.*; public class MyServiceClient { public static void main(String[] args) { try { System.out.println("begin"); 16 Java Web Services Cookbook // web service endpoint address String endpointURL = args[0]; System.out.println("Web Service endpoint URL: " + endpointURL); // // create Web Service stub // MyService service = new MyService(); MyPortType port = service.getMyPort(); BindingProvider bindingProvider = (BindingProvider) port; // set endpoint address bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_AD DRESS_PROPERTY, endpointURL); // // invoke Web Service operation // port.myOperation(123, "abc"); } catch(WebServiceException e) { // handle Web Service exception System.out.println("Caught web service exception: "); System.out.println(e.getClass().toString()); System.out.println(e.getMessage()); } catch(Exception e) { // handle general exception System.out.println("Caught exception: "); System.out.println(e.getClass().toString()); System.out.println(e.getMessage()); } finally { System.out.println("end"); } } } c. Construir cliente e executar $ ant run Variantes Diagnóstico de erros Consultar tipo e mensagem da excepção produzida. Usar Eclipse (Antes do passo 2) Iniciar o Eclipse e criar novo projecto File, New, Project, Java Project, Project name: MyWSCli Create project from existing source, Next Source, Source folder, src/java, Default output folder: build/eclipse Libraries, Add library, User library: jwsdp-essd-2008, Finish Add class folder: build/classes, Finish 17 Java Web Services Cookbook O conjunto de bibliotecas (user library) jwsdp-essd-2008 pode ser importado a partir do ficheiro contido na directoria %JWSDP_HOME%\eclipse. Configurar Ant Windows, Show View, Ant View build.xml ~drag-and-drop~> Ant View Hide internal targets (Depois do passo 2, a, i) Refrescar Eclipse Project, Refresh (Apoio ao passo 2, b) Criar classe File, New, Class package: my name: MyServiceClient superclass: java.lang.Object inherit abstract methods public static void main(String[] args) generate comments Activar um JAX-WS Handler no cliente Acrescentar o seguinte target ao build.xml. <target name="-replace-jax-ws-client-custom-tokens(dir)"> <replace dir="${dir}" token="@jax-ws-client.handler-chains@"> <replacevalue><![CDATA[ <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <jws:handler-chain> <jws:handler> <jws:handlerclass>my.handler.MyClientHandler</jws:handler-class> </jws:handler> </jws:handler-chain> </jws:handler-chains> ]]></replacevalue> </replace> </target> A classe my.handler.MyClientHandler deverá existir e ser um JAX-WS Handler. 18 Java Web Services Cookbook Obter a localização do Web Service a partir do UDDI Obter uma biblioteca com as classes step.framework.ws.registry.* e colocar numa das directorias lib do projecto: lib my-ws lib Criar e preencher ficheiros de configuração de registo Registry.properties (dados do servidor UDDI), ClassificationQuery.properties (dados de pesquisa por classificação) ou NamePatternQuery.properties (dados de pesquisa por nome). my-ws config ws-registry Registry.properties ClassificationQuery.properties NamePatternQuery.properties Registry.properties # # Registry # [email protected]@ [email protected]@ [email protected]@ #locale= optionOutputMessages=true #optionValidateURI=false #optionWarnAboutLocale=true ClassificationQuery.properties # # Classification Query # queryClassificationScheme=unspsc-org:unspsc:3-1 queryClassificationName=Research and Science Based Services queryClassificationValue=81000000 NamePatternQuery.properties # # Name Pattern Query # queryNamePattern=%Organization% Criar ou editar ficheiro build.properties para acrescentar: ws-registry.username=testuser ws-registry.password=testuser Modificar build.xml, acrescentando a importação de um novo módulo: <import file="${import-ant}/ws-registry.xml" /> As propriedades relacionadas com a pesquisa UDDI: <property name="ws-registry.url" value="http://localhost:8080/RegistryServer/" /> <property name="ws-registry.main-class" value="step.framework.ws.registry.Main" /> 19 Java Web Services Cookbook <property name="dir" value="${build.config.ws-registry.rel-dir}" /> <property name="ws-registry.query.args" value="${dir}/Registry.properties query classification ${dir}/ClassificationQuery.properties" /> Uma nova dependência no build.xml: <target name="build" depends="config,build-ws-registry,build-jax-ws-client" description="Builds the project"> </target> Testar a pesquisa em tempo de compilação: $ ant build-ws-registry ws-query Efectuar a pesquisa no código do cliente: package my; import import import import javax.xml.ws.BindingProvider; javax.xml.ws.WebServiceException; step.framework.ws.registry.*; my.ws.stubs.*; public class MyServiceClient { public static void main(String[] args) { try { System.out.println("begin"); // // query web services registry // Registry registry = null; ClassificationQuery query = null; Registration[] registrationArray = null; try { registry = new Registry("/Registry.properties"); query = new ClassificationQuery("/ClassificationQuery.properties"); registry.setOptionOutputMessages(false); // no output registry.connect(false); // no authentication is required for querying registrationArray = registry.query(query); if(registrationArray == null) { System.out.println("No web service registrations found in registry server " + registry.getURL()); return; } else { System.out.println("Found " + registrationArray.length + " web service registrations in registry server " + registry.getURL()); } } finally { if(registry != null) registry.disconnect(); } // // create Web Service stub // MyService service = new MyService(); MyPortType port = service.getMyPort(); BindingProvider bindingProvider = (BindingProvider) port; // // for each web service, invoke Web Service operation // System.out.println("Invoking operation on all found web service 20 Java Web Services Cookbook registrations"); for(int i=0; i < registrationArray.length; i++) { try { String endpointURL = registrationArray[i].getServiceBindingAccessURI(); // set endpoint address System.out.println("Web Service endpoint URL: " + endpointURL); bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL); port.myOperation(123, "abc"); } catch(WebServiceException e) { // handle Web Service exception System.out.println("Caught web service exception: "); System.out.println(e.getClass().toString()); System.out.println(e.getMessage()); System.out.println("Proceed to next endpoint"); } } } catch(Exception e) { // handle general exception System.out.println("Caught exception: "); System.out.println(e.getClass().toString()); System.out.println(e.getMessage()); } finally { System.out.println("end"); } } } Criar um cliente de dois Web Services Para invocar dois Web Services a partir do mesmo cliente, suponhamos Hello e Calc, é necessário criar duas directorias de configuração: my-ws-cli config jax-ws-client_hello client-custom-binding.xml jax-ws-client_hello client-custom-binding.xml E modificar o build.xml: <target name="build" depends="config,build-jax-ws-client-stubs_hello,build-jax-ws-clientstubs_calc,compile" description="Build the project"> </target> <target name="build-jax-ws-client-stubs_hello"> <echo level="info" message="Creating Hello stubs..." /> <antcall target="build-jax-ws-client-stubs" inheritAll="false"> <param name="jax-ws-client.dir-name" value="jax-ws-client_hello" /> <param name="jax-ws-client.wsdl.url" value="http://localhost:8080/ExemploHelloWS/endpoint?wsdl" /> <param name="jax-ws-client.stubs.package" value="hello.ws.stubs" /> <param name="jax-ws-client.custom-tokens.target-name" value="replace-jax-ws-client-custom-tokens(dir)_hello" /> </antcall> </target> <target name="-replace-jax-ws-client-custom-tokens(dir)_hello"> <replace dir="${dir}" token="@jax-ws-client.handler-chains@"> 21 Java Web Services Cookbook <replacevalue><![CDATA[ <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <jws:handler-chain> <jws:handler> <jws:handlerclass>step.framework.ws.handler.LoggingHandler</jws:handler-class> </jws:handler> </jws:handler-chain> </jws:handler-chains> ]]></replacevalue> </replace> </target> <target name="build-jax-ws-client-stubs_calc"> <echo level="info" message="Creating Calc stubs..." /> <antcall target="build-jax-ws-client-stubs" inheritAll="false"> <param name="jax-ws-client.dir-name" value="jax-ws-client_calc" /> <param name="jax-ws-client.wsdl.url" value="http://localhost:8080/ExemploCalcWS/endpoint?wsdl" /> <param name="jax-ws-client.stubs.package" value="calc.ws.stubs" /> <param name="jax-ws-client.custom-tokens.target-name" value="replace-jax-ws-client-custom-tokens(dir)_calc" /> </antcall> </target> <target name="-replace-jax-ws-client-custom-tokens(dir)_calc"> <replace dir="${dir}" token="@jax-ws-client.handler-chains@"> <replacevalue><![CDATA[ <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <jws:handler-chain> <jws:handler> <jws:handlerclass>step.framework.ws.handler.LoggingHandler</jws:handler-class> </jws:handler> </jws:handler-chain> </jws:handler-chains> ]]></replacevalue> </replace> </target> Os targets -replace-jax-ws-client-custom-tokens(dir)_hello e -replace-jax-wsclient-custom-tokens(dir)_calc são definidos para permitir uma configuração individual de JAX-WS Handlers. O código do cliente deve importar e usar os stubs dos dois Web Services: import hello.ws.stubs.*; import calc.ws.stubs.*; ... 22