Serviços da Web Java : Entendendo e Modelando o WSDL 1.1

Saiba como o WSDL 1.1 define serviços da Web e como os documentos WSDL podem ser modelados na linguagem Java para verificação e transformação

Vários anos depois da aprovação do Web Services Description Language (WSDL) 2.0 como padrão do World Wide Web Consortium (W3C), o WSDL 1.1 ainda é a forma mais usada de descrição de serviço da Web. Apesar da popularidade, o WSDL 1.1 tem alguns problemas, como a multiplicidade de esquemas em uso e variações na forma de processamento de documentos WSDL pelas pilhas de serviços da Web. Neste artigo, você verá como as descrições de serviço do WSDL 1.1 estão estruturadas. Verá também a estrutura básica de uma ferramenta Java™ para verificar documentos WSDL e transformá-los em uma forma de "boas práticas".

Dennis Sosnoski, Architecture Consultant and Trainer, Sosnoski Software Solutions, Inc.

Author photoDennis Sosnoski é um consultor e instrutor especializado em XML e serviços da Web baseados em Java. Sua experiência em desenvolvimento de software profissional se estende por mais de 30 anos, sendo que nos últimos 10 focou tecnologias XML e Java do lado do servidor. Dennis é o desenvolvedor líder da estrutura de software livre JiBX XML Data Binding e a estrutura de serviços da Web associada JiBX/WS, assim como um committer na estrutura de serviços da Web Apache Axis2. Também foi um dos membros do Grupo de Especialistas para as especificações JAX-WS 2.0 e JAXB 2.0. O material para a série Serviços da Web Java é baseado nas aulas de treinamento de Dennis.



01/Mar/2011

Sobre esta série

Os serviços da Web são uma parte crucial do papel da tecnologia Java™ na computação corporativa. Nesta série de artigos, o consultor em XML e serviços da Web Dennis Sosnoski abrange as principais estruturas e tecnologias que são importantes para os desenvolvedores Java que usam os serviços da Web. Acompanhe a série para manter-se informado sobre os desenvolvimentos mais recentes no campo e sobre como usá-los para auxiliar os seus projetos de programação.

Os serviços da Web para aplicativos corporativos dependem muito do uso de definições de serviço. As definições de serviço especificam um contrato básico entre o provedor de serviços e quaisquer possíveis clientes, detalhando os tipos de funções que são fornecidas pelo serviço e as mensagens trocadas como parte de cada função. Os provedores de serviços e consumidores são livres para implementar as suas extremidades da troca como quiserem, desde que as mensagens que eles enviam correspondam à definição de serviço. O uso de definições de serviço que especificam trocas de mensagem XML é o que diferencia os serviços da Web das tecnologias anteriores de programação distribuída.

Foram propostas várias técnicas para definir serviços da Web, mas a abordagem mais usada é o WSDL 1.1. O WSDL 1.1 tem algumas desvantagens — como uma estrutura complexa demais — que o tornam quase ilegível para os "não iniciados". Também não tem uma definição consagrada formal, e o resultado disso são sucessivos "acréscimos" para esclarecimento que preencheram algumas lacunas do documento de especificação original. Em resposta a isso, as pilhas de serviços da Web tendem a processar documentos WSDL 1.1 da forma mais flexível possível. Essa flexibilidade pode dificultar ainda mais o entendimento do WSDL 1.1, porque os desenvolvedores podem ver uma variedade ampla de estruturas WSDL, mas não têm uma orientação em relação à melhor abordagem.

Neste artigo, você aprenderá a entender os documentos WSDL 1.1 e verá as primeiras partes de um modelo Java para verificar documentos WSDL e convertê-los para um formato padrão.

Entendendo o WSDL 1.1

Uso de namespaces

Este artigo usa:

  • O prefixo wsdl para representar o namespace do WSDL 1.1 http://schemas.xmlsoap.org/wsdl/ .
  • O prefixo soap para o namespace http://schemas.xmlsoap.org/wsdl/soap/ usado pela extensão do SOAP 1.1 para o WSDL 1.1
  • O prefixo xs para o namespace http://www.w3.org/2001/XMLSchema usado para definições de esquema XML

O WSDL 1.1, publicado no início de 2001, foi substituído tecnicamente pela recomendação WSDL 2.0 do W3C publicado em 2007. O WSDL 2.0 oferece uma estrutura mais limpa que a do WSDL 1.1 e mais flexibilidade. Entretanto, o WSDL 2.0 vive o dilema do ovo e da galinha — o WSDL 2.0 não é amplamente utilizado porque não tem um suporte amplo e, como não é amplamente utilizado, os implementadores de pilhas de serviços da Web não sofrem pressão para oferecer suporte a ele. O WSDL 1.1, embora tenha falhas, é suficientemente bom para a maioria dos propósitos.

A especificação original WSDL 1.1 era imprecisa em relação à quantidade de recursos a ser usados. Como o foco do WSDL era o trabalho com definições de serviço de SOAP, ele também incluiu o suporte para alguns recursos de SOAP (como codificação rpc) que posteriormente foram considerados indesejáveis. O Web Services Interoperability Organization (WS-I) tratou desses problemas no Basic Profile (BP), que definiu boas práticas para serviços da Web usando SOAP e WSDL. O BP 1.0 foi aprovado em 2004 e atualizado como BP 1.1 em 2006. Neste artigo, abordarei o WSDL 1.1 com base nas diretrizes do WS-I BP, ignorando recursos efetivamente descontinuados como a codificação rpc para SOAP.

As definições do esquema XML têm a finalidade de definir a estrutura dos documentos XML. O WSDL 1.1 incluiu uma descrição de esquema na especificação original, mas esse esquema não correspondia às descrições de texto em vários aspectos. Isso foi corrigido em uma versão modificada do esquema posteriormente, mas o documento do WSDL 1.1 não foi atualizado para refletir a alteração. Em seguida, o grupo WS-I BP decidiu fazer ainda mais mudanças no esquema WSDL; portanto, criou aquilo que parece ser a versão das boas práticas desse esquema confuso. Os documentos escritos para uma versão do esquema geralmente não são compatíveis com outras versões (apesar de usar o mesmo namespace), mas, felizmente, a maioria das ferramentas de serviços da Web basicamente ignora o esquema e aceita qualquer coisa que pareça razoável. (Consulte a seção Recursos para ver links para os vários esquemas do WSDL.)

Nem mesmo a versão WS-I BP do esquema WSDL 1.1 ajuda muito a garantir que os documentos WSDL 1.1 sigam a especificação. O esquema não reflete todas as restrições do WS-I BP, particularmente no que diz respeito à ordem dos componentes. Além disso, o esquema XML não consegue manipular muitos tipos de restrições declaradas facilmente nos documentos (tais como atributos alternativos e elementos de extensão obrigatórios provenientes de esquemas separados). Portanto, o ato de certificar-se de que um documento WSDL 1.1 siga a especificação WSDL 1.1 (conforme as mudanças realizadas pelo WS-I BP) envolve muito mais do que a ativação da validação do esquema XML. Voltarei a esse tópico mais adiante neste artigo. Primeiro revisarei a estrutura das descrições de serviço do WSDL 1.1.

Componentes da descrição

Os documentos WSDL 1.1 usam um elemento-raiz fixo, chamado convenientemente de <wsdl:definitions>. Dentro desse elemento-raiz, um elemento filho "passivo" (que só faz referência a documentos WSDL 1.1) e cinco elementos filho "ativos" (os que realmente contribuem para a descrição do serviço) são definidos no namespace do WSDL 1.1:

  • <wsdl:import> faz referência a um documento WSDL 1.1 separado, com descrições a ser incorporadas a esse documento.
  • <wsdl:types> define tipos ou elementos XML usados para troca de mensagens.
  • <wsdl:message> define a mensagem em si, em termos de tipos ou elementos XML.
  • <wsdl:portType> define um conjunto abstrato de operações implementadas por um serviço.
  • <wsdl:binding> define a implementação real de um <wsdl:portType>, usando formatos e protocolos específicos.
  • <wsdl:service> define o serviço como um todo, geralmente incluindo um ou mais elementos <wsdl:port> com informações de acesso para elementos <wsdl:binding> .

Também há um elemento <wsdl:document> que pode ser usado para fins de documentação, como o primeiro filho do elemento <wsdl:definitions> e também como o primeiro filho de qualquer um dos elementos acima.

Normalmente, uma descrição de serviço completa requer pelo menos um desses elementos, com exceção de <wsdl:import>, mas não é necessário que todos estejam no mesmo documento. É possível usar <wsdl:import> para montar uma descrição WSDL completa a partir de diversos documentos, oferecendo a você a flexibilidade de dividir descrições para que se adaptem à sua organização. Por exemplo, os três primeiros elementos da descrição (<wsdl:types>, <wsdl:message> e <wsdl:portType>) em conjunto fornecem uma descrição completa da interface de serviço (talvez definida por uma equipe de arquitetura) — portanto, talvez faça sentido mantê-los separados dos elementos voltados para a implementação <wsdl:binding> e <wsdl:service> . Todas as principais pilhas de serviços da Web suportam a divisão de descrições em diversos documentos WSDL.

A Listagem 1 e a Listagem 2 apresentam uma amostra de uma descrição do serviço WSDL dividida em dois documentos WSDL, com os componentes da descrição da interface no arquivo BookServerInterface.wsdl e os componentes de implementação em BookServerImpl.wsdl. A Listagem 1 mostra BookServerInterface.wsdl:

Listagem 1. BookServerInterface.wsdl
<wsdl:definitions ... xmlns:tns="http://sosnoski.com/ws/library/BookServerInterface"
    targetNamespace="http://sosnoski.com/ws/library/BookServerInterface">
  <wsdl:document>Book service interface definition.</wsdl:document>
  <wsdl:types>
    <xs:schema ...
        targetNamespace="http://sosnoski.com/ws/library/BookServerInterface">
      <xs:import namespace="http://sosnoski.com/ws/library/types"
          schemaLocation="book-types.xsd"/>
      ...
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="getBookMessage">
    <wsdl:part name="part" element="tns:getBook"/>
  </wsdl:message>
  <wsdl:message name="getBookResponseMessage">
    <wsdl:part name="part" element="tns:getBookResponse"/>
  </wsdl:message>
  ...
  <wsdl:message name="addBookMessage">
    <wsdl:part name="part" element="tns:addBook"/>
  </wsdl:message>
  <wsdl:message name="addBookResponseMessage">
    <wsdl:part name="part" element="tns:addBookResponse"/>
  </wsdl:message>
  <wsdl:message name="addDuplicateFault">
    <wsdl:part name="fault" element="tns:addDuplicate"/>
  </wsdl:message>
  <wsdl:portType name="BookServerPortType">
    <wsdl:documentation>
      Book service implementation. This creates an initial library of books when the
      class is loaded, then supports method calls to access the library information
      (including adding new books).
    </wsdl:documentation>
    <wsdl:operation name="getBook">
      <wsdl:documentation>
        Get the book with a particular ISBN.
      </wsdl:documentation>
      <wsdl:input message="tns:getBookMessage"/>
      <wsdl:output message="tns:getBookResponseMessage"/>
    </wsdl:operation>
    ...
    <wsdl:operation name="addBook">
      <wsdl:documentation>Add a new book.</wsdl:documentation>
      <wsdl:input message="tns:addBookMessage"/>
      <wsdl:output message="tns:addBookResponseMessage"/>
      <wsdl:fault message="tns:addDuplicateFault" name="addDuplicateFault"/>
    </wsdl:operation>
  </wsdl:portType>
</wsdl:definitions>

A Listagem 2 mostra BookServerImpl.wsdl. O elemento <wsdl:import> perto do começo importa a descrição da interface de BookServerInterface.wsdl.

Listagem 2. BookServerImpl.wsdl
<wsdl:definitions ... xmlns:ins="http://sosnoski.com/ws/library/BookServerInterface"
    xmlns:tns="http://sosnoski.com/ws/library/BookServer"
    targetNamespace="http://sosnoski.com/ws/library/BookServer">
  <wsdl:document>
    Definition of actual book service implementation.
  </wsdl:document>
  <wsdl:import namespace="http://sosnoski.com/ws/library/BookServerInterface"
      location="BookServerInterface.wsdl"/>
  <wsdl:binding name="BookServerBinding" type="ins:BookServerPortType">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="getBook">
      <soap:operation soapAction="urn:getBook"/>
      <wsdl:input>
        <soap:body/>
      </wsdl:input>
      <wsdl:output>
        <soap:body/>
      </wsdl:output>
    </wsdl:operation>
    ...
    <wsdl:operation name="addBook">
      <soap:operation soapAction="urn:addBook"/>
      <wsdl:input>
        <soap:body/>
      </wsdl:input>
      <wsdl:output>
        <soap:body/>
      </wsdl:output>
      <wsdl:fault name="addDuplicateFault">
        <soap:fault name="addDuplicateFault"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="BookServer">
    <wsdl:port name="BookServerPort" binding="tns:BookServerBinding">
      <soap:address location="http://localhost:8080/cxf/BookServer"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Além das definições de elementos (e atributos) no namespace do WSDL 1.1, o WSDL 1.1 também define elementos de extensão. Esses elementos de extensão devem se encaixar em locais específicos das descrições de serviço do WSDL 1.1 para fornecer informações adicionais necessárias para um tipo de serviço específico. Os únicos elementos de extensão do WSDL 1.1 que ainda são amplamente usados são os que estão relacionados a ligações de SOAP 1.1 (vistos na Listagem 2, dentro dos elementos <wsdl:binding> e <wsdl:service> ), que foram definidas pela especificação WSDL 1.1 original, e a ligações do SOAP 1.2, definidas por uma especificação separada em 2006.

Detalhes dos componentes

O elemento <wsdl:types> quebra todas as definições XML usadas para mensagens, na forma de um ou mais elementos <xs:schema> . (O WSDL permite alternativas ao esquema XML para essas definições, mas a maioria das pilhas só suporta o esquema XML.) Os elementos <xs:schema> podem usar <xs:import> e/ou <xs:include> para incorporar outros esquemas externos ao WSDL, se você desejar (e podem fazer referência a esquemas separados contidos no mesmo WSDL).

Já que um único elemento <wsdl:types> pode conter qualquer quantidade de definições de esquema, nunca há um motivo para usar mais de um elemento <wsdl:types> em um documento WSDL. Na Listagem 1, o elemento <wsdl:types> está perto da parte superior de BookServerInterface.wsdl.

Com exceção de <wsdl:import> e <wsdl:types>, todos os outros componentes de nível superior de um documento WSDL são nomeados individualmente pelo uso de um atributo name obrigatório. Se você usa um atributo targetNamespace no elemento de raiz do documento <wsdl:definitions> (algo que, de modo geral, você deve fazer, por ser uma boa prática), os nomes desses componentes são definidos no namespace de destino. Isso significa que, ao definir o nome, você só dá a parte simples ou "local" do nome, mas as referências a esse componente devem qualificar o nome com um prefixo de namespace ou namespace padrão. A Figura 1 shows mostra as ligações mais importantes entre os componentes do WSDL. As linhas contínuas representam referências qualificadas aos nomes e as linhas pontilhadas representam nomes para identificação sem a qualificação do namespace:

Figura 1. Ligações entre componentes do WSDL
Linkages between WSDL components

As mensagens, representadas por elementos <wsdl:message> estão no "coração" das descrições do serviço WSDL. Os elementos <wsdl:message> são as descrições dos dados XML trocados entre o cliente e o provedor de serviços. Cada <wsdl:message> contém zero ou mais (normalmente um) elementos filho <wsdl:part> . Cada elemento part requer o seu próprio atributo name (exclusivo dentro de <wsdl:message>) e um atributo element ou type que faz referência à definição de esquema dos dados XML. Vários elementos <wsdl:message> são mostrados na Listagem 1, depois do elemento <wsdl:types> em BookServerInterface.wsdl.

Os elementos <wsdl:portType> definem a interface abstrata para um serviço, em termos de mensagens enviadas do/para o serviço. Os elementos <wsdl:portType> contém qualquer quantidade de elementos filho <wsdl:operation> . Cada elemento filho <wsdl:operation> precisa do seu próprio atributo name (que o WS-I BP exige que seja exclusivo dentro de <wsdl:portType>) e contém um elemento filho ou mais que descrevem as mensagens usadas pela operação. Os elementos filho têm três tipos, representando tipos de uso diferentes:

  • <wsdl:input> : dado enviados do cliente para o provedor de serviços como entrada para a operação
  • <wsdl:output> : dados retornados para o cliente pelo provedor de serviços como resultado da operação
  • <wsdl:fault> : dados retornados para o cliente pelo provedor de serviços quando há um erro no processamento

O WSDL 1.1 define vários padrões de interação entre o cliente e o provedor de serviços, conforme o representado por sequências diferentes de elementos filho <wsdl:input> e <wsdl:output> , mas nem todos os padrões estão suficientemente bem definidos para ser implementados. O WS-I BP restringe os padrões a apenas dois: operações de solicitação-resposta, com um <wsdl:input> seguido por um <wsdl:output>, e operações unidirecionais, com apenas um <wsdl:input>. No caso de operações de solicitação-resposta (o tipo que é, de longe, o mais comum), os elementos <wsdl:input> e <wsdl:output> podem ser seguidos por qualquer quantidade de elementos <wsdl:fault> .

Cada elemento <wsdl:input>, <wsdl:output>ou<wsdl:fault> faz referência a uma descrição de mensagem por meio do atributo obrigatóriomessage . Essa referência é qualificada pelo namespace — portanto, geralmente precisa incluir um prefixo. É possível ver exemplos disso na Listagem 1, por exemplo, com o elemento <wsdl:input message="tns:getBookMessage"/> usado na descrição da operação getBook . (O prefixo tns é definido no elemento de raiz <wsdl:definitions> com o mesmo URI do namespace que o atributo targetNamespace .)

É possível considerar <wsdl:portType> como equivalente lógico de uma interface Java na maioria dos aspectos, com os elementos <wsdl:operation> equivalentes aos métodos, os elementos <wsdl:input> como parâmetros de método, os elementos <wsdl:output> como retornos de método e os elementos <wsdl:fault> como exceções verificadas. A geração de código Java a partir do WSDL usa essas correspondências, da mesma forma que a maioria das ferramentas que gera WSDL a partir do código Java já existente.

SOAP 1.1 x 1.2

O SOAP 1.1 tem sido usado amplamente para serviços da Web desde que a especificação foi publicada em 2000. O SOAP 1.2 foi desenvolvido com um suporte mais amplo do segmento de mercado por meio do W3C e publicado como padrão oficial do W3C em 2007. O SOAP 1.2 é mais bem documentado e mais limpo que o SOAP 1.1 — alguns dos aspectos mais feios do 1.1 foram removidos cirurgicamente. Apesar da estrutura mais limpa, para a maioria dos serviços da Web, na prática há pouca diferença entre os dois. Provavelmente, o recurso mais significativo do SOAP 1.2 é o fato de ser a única forma suportada oficialmente de usar o suporte melhorado para anexos de SOAP fornecido pelo XML-binary Optimized Packaging (XOP) e pelo Message Transmission Optimization Mechanism (MTOM) de SOAP. Eu venho usando o SOAP 1.1 na série Serviços da Web Java até hoje, porque algumas pilhas mais antigas não suportam o SOAP 1.2, mas o 1.2 provavelmente é uma opção melhor para o desenvolvimento de novos serviços da Web. Os elementos

<wsdl:binding> representam uma instância da interface abstrata definida por um <wsdl:portType>, visto na Listagem 2 no início de BookServerImpl.wsdl. O atributo type dá o nome qualificado do tipo de porta implementado pela ligação.

Os elementos filho de <wsdl:binding> dão os detalhes da implementação do tipo de porta. Os elementos filho do namespace do WSDL correspondem aos de <wsdl:portType> e devem usar os mesmos valores de referências de name não — referências qualificadas pelo namespace, como acontece com a referência de <wsdl:portType> . A Figura 1 mostra essa conexão no nível de <wsdl:operation> com linhas pontilhadas. A mesma conexão por nome se aplica aos elementos filho <wsdl:input>/<wsdl:output>/<wsdl:fault> dos elementos <wsdl:operation> . Apesar dessa reutilização dos nomes de elemento, o conteúdo desses elementos é muito diferente quando eles são filhos de <wsdl:binding> em vez do elemento <wsdl:portType> .

<wsdl:binding> é onde as extensões definidas pelo WSDL entram em cena. O elemento filho <soap:binding> é usado na definição de um serviço SOAP (o único tipo de serviço permitido pelo WS-I BP, embora o WSDL 1.1 também permita ligações HTTP). Esse elemento <soap:binding> usa o atributo obrigatório transport para definir o tipo de transporte usado pela ligação. (HTTP, como mostra o valor http://schemas.xmlsoap.org/soap/http na Listagem 2, é a única opção permitida pelo WS-I BP.) O atributo opcional style permite escolher entre rpc e estilos de documento para a representação de dados XML (cujo padrão mais comum é document , que corresponde às mensagens que usam definições de elemento de esquema, e não definições de tipo).

Dentro de cada filho de <wsdl:operation> de <wsdl:binding>, um elemento <soap:operation> pode ser usado para especificar um valor de SOAPAction para identificar solicitações que chamam essa operação (e talvez também substituir a opção de rpc ou estilo de documento determinada pelo elemento <soap:binding> , embora o WS-I BP proíba esse uso). Cada elemento filho <wsdl:input>/<wsdl:output>/<wsdl:fault> contém outro elemento de extensão que, no caso da Listagem 2 é sempre <soap:body> (que indica que os dados da mensagem são enviados no corpo da mensagem SOAP — também é possível enviar dados e até mesmo falhas nos cabeçalhos SOAP, embora eu considere essa prática inadequada) para um <wsdl:input> ou <wsdl:output> ou o equivalente <soap:fault> usado com um <wsdl:fault>.

O componente final de uma descrição do serviço de WSDL é o elemento <wsdl:service> , que é formada por um agrupamento de elementos <wsdl:port> . Cada elemento <wsdl:port> associa um endereço de acesso com um <wsdl:binding>. O endereço de acesso é fornecido pelo elemento de extensão aninhado <soap:address> .


Trabalhando com o WSDL

Com todas as variações de esquemas e regras referentes a documentos do WSDL 1.1, não é de se estranhar que muitos documentos não correspondam à forma de boas práticas definidas pelo WS-I BP. O suporte de todas as pilhas de serviços da Web para muitas variações das formas de boas práticas ajudou a perpetuar o uso de construções desatualizadas ou incorretas, o que leva à disseminação de más práticas em todo o segmento de mercado. E eu certamente não estou imune a esse contágio — ao revisar os documentos WSDL que forneci como código de amostra para esta série, eu me surpreendi ao constatar que nenhum estava totalmente correto.

Portanto, quando eu me propus a escrever este artigo, pensei que seria bom incluir uma ferramenta que as pessoas pudessem usar para verificar documentos WSDL com relação às regras de boas práticas. Partindo daí, a transformação dos documentos WSDL na forma de boas práticas pareceu um passo pequeno a ser dado, desde que o WSDL não tenha erros. Isso acabou dando muito mais trabalho do que eu havia planejado originalmente, e os detalhes completos do modelo serão desenvolvidos nos dois artigos seguintes desta série.

Foram desenvolvidos diversos modelos diferentes para trabalhar com documentos WSDL na linguagem Java, inclusive o amplamente usado Web Services Description Language for Java Toolkit (WSDL4J), a implementação de referência do JSR 110 (consulte Recursos). Aparentemente nenhum desses modelos servia para o que eu queria fazer, por causa dos objetivos duplos de primeiramente ler documentos WSDL em qualquer forma razoável e reportar tanto erros quanto variações de boas práticas e, em segundo lugar, escrever documentos WSDL sem erros e reformatados de forma condizente com as boas práticas. O WSDL4J, por exemplo, não mantinha a ordem dos elementos a partir da entrada, para que eu pudesse relatar problemas de ordem e também não trata definições de esquema — portanto, não podia ser usado diretamente para verificar as referências a partir dos elementos <wsdl:part> . Portanto, eu pude escolher entre estabelecer objetivos de forma mais realista ou escrever o meu próprio modelo. Obviamente, optei por escrever meu próprio modelo.

Modelo de WSDL

Validação x verificação

Uso o termo verificação neste artigo para designar a verificação para ver se o documento WSDL está correto, porque o termo alternativo validação geralmente é usado, no contexto dos documentos XML, para designar a verificação de documentos com relação a uma definição de esquema.

Eu já tinha implementado um modelo de WSDL parcial para uso com a ligação de dados JiBX, como parte do projeto JiBX/WS. Esse modelo foi projetado somente para saída e envolve um número relativamente pequeno de classes que, em alguns casos, combinam dados de elementos aninhados da estrutura XML do WSDL (o <wsdl:message> combinado com um único filho de <wsdl:part> , o <wsdl:input>, <wsdl:output> e <wsdl:fault> dentro de um <wsdl:binding> combinado com um elemento <soap:body> ou <soap:fault> e assim por diante). Essa estrutura de classe compacta facilitou o desenvolvimento do subconjunto de documentos WSDL suportados pela estrutura, mas quando pensei, no início, em basear uma ferramenta de verificação e reestruturação naquele modelo, percebi que o suporte para entradas de um WSDL que poderia estar mal estruturado exigiria um modelo mais próximo da representação XML.

A geração de códigos a partir do esquema WS-I BP para WSDL 1.1 era outra opção. Quando examinei essa possibilidade, percebi que o ato de simplesmente usar as classes geradas diretamente seria uma bagunça, porque o esquema inclui tipos redundantes e algumas construções estranhas usadas para representar os diversos padrões de troca de mensagens (na época, alguns deles eram proibidos pelo texto do WS-I BP).

Então, acabei desenvolvendo as classes manualmente, embora fosse possível obter um resultado final praticamente igual se eu começasse com o código gerado a partir do esquema e eliminasse a duplicação e a complexidade desnecessária. A ligação de dados JiBX suporta diversas ligações para as mesmas classes — portanto, eu pude configurar a ligação de entradas para tratar toda a variedade de opções permitidas por qualquer versão do WSDL 1.1 e configurar a ligação de saídas para realizar a saída do WSDL somente de forma compatível com as boas práticas.

A Listagem 3 mostra parte da classe Definitions , que corresponde ao elemento-raiz <wsdl:definitions> :

Listagem 3. Classe Definitions (parcial)
public class Definitions extends ElementBase
{
    /** Enumeration of child elements, in expected order. */
    static enum AddState {
        invalid, imports, types, message, portType, binding, service };
    
    /** List of allowed attribute names. */
    public static final StringArray s_allowedAttributes =
        new StringArray(new String[] { "name", "targetNamespace" });
    
    /** Validation context in use. */
    private ValidationContext<ElementBase,Definitions> m_validationContext;
    
    /** Current state (used for checking order in which child elements are added). */
    private AddState m_state;
    
    /** Name for this definitions. */
    private String m_name;
    
    /** Target namespace for WSDL. */
    private String m_targetNamespace;
    
    /** List of all import child elements. */
    private List<Import> m_imports = new ArrayList<Import>();
    
    /** List of all types child elements. */
    private List<Types> m_types = new ArrayList<Types>();
    
    /** List of all message child elements. */
    private List<Message> m_messages = new ArrayList<Message>();
    
    /** List of all portType child elements. */
    private List<PortType> m_portTypes = new ArrayList<PortType>();
    
    /** List of all binding child elements. */
    private List<Binding> m_bindings = new ArrayList<Binding>();
    
    /** List of all services child elements. */
    private List<Service> m_services = new ArrayList<Service>();
    
    /** Map from qualified name to message in this definition. */
    private Map<QName,Message> m_nameMessageMap =
        new HashMap<QName,Message>();
    
    /** Map from qualified name to port type in this definition. */
    private Map<QName,PortType> m_namePortTypeMap =
        new HashMap<QName,PortType>();

    /** Map from qualified name to message in this definition. */
    private Map<QName,Binding> m_nameBindingMap =
        new HashMap<QName,Binding>();
    
    /** Map from qualified name to service in this definition. */
    private Map<QName,Service> m_nameServiceMap =
        new HashMap<QName,Service>();
    ...
    /**
     * Check state transitions between different types of child elements. 
     * If the elements are not in the expected order,
     * this flags the first out-of-order element for reporting.
     * @param state new add state
     * @param comp element component
     */
    private void checkAdd(AddState state, ElementBase comp) {
        if (m_state != state) {
            if (m_state == null || (m_state != AddState.invalid &&
                state.ordinal() > m_state.ordinal())) {
                
                // advanced on to another type of child element
                m_state = state;
                
            } else if (state.ordinal() < m_state.ordinal()) {
                
                // report child element out of order
                m_validationContext.addWarning
                    ("Child element of wsdl:definitions out of order", comp);
                m_state = AddState.invalid;
            }
        }
    }
    ...
    /**
     * Add an unmarshalled wsdl:message child element. This also indexes the message by
     * name for validation access.
     * 
     * @param child
     */
    public void addMessage(Message child) {
        checkAdd(AddState.message, child);
        m_messages.add(child);
        addName(child.getName(), child, m_nameMessageMap);
    }
    ...

A organização dos dados de elementos filho na Listagem 3 mostra como o modelo suporta entradas de forma geral e saídas de acordo com as boas práticas. Em vez de usar uma lista única de elementos filho de todos os tipos, ele usa listas separadas para cada tipo. A ligação JiBX de entrada trata os elementos filho como um conjunto não ordenado, chamando um método de configuração específico para o tipo de elemento sempre que um elemento filho é desserializado. O método de configuração inclui a instância em uma lista com tipos em vez de substituir os valores anteriores, como se pode ver no método de configuração addMessage() usado para os elementos filho <wsdl:message> . Cada método de configuração também executa uma verificação de estado para capturar casos em que os elementos não estão na ordem esperada.

Os atributos e elementos de extensão (basicamente, qualquer atributo ou elemento que não usa o namespace WSDL 1.1) são permitidos em qualquer um dos elementos de WSDL. As configurações WS-Policy integradas nos documentos WSDL dos artigos anteriores desta série são exemplos desses elementos de extensão, bem como as referências reais a políticas. A boa prática em relação a esses elementos de extensão é que eles precedam os elementos filho do namespace do WSDL 1.1, e essa é a forma como eles são tratados na ligação de saída. A ligação de entrada processa elementos de extensão e atributos usando o código proveniente de uma classe base das classes de elementos do WSDL, que não é mostrado na Listagem 3, e permite que os elementos estejam em qualquer ordem (e gera um aviso se eles seguem um elemento do namespace do WSDL 1.1).

O modelo trata elementos de extensão conhecidos usando ligações separadas para cada namespace de extensão, cada um com o seu próprio conjunto de classes. Abordarei a manipulação desses elementos de extensão mais detalhadamente na próxima parte de Serviços da Web Java , que também fornecerá mais detalhes do código de origem.

Verificando o modelo

Parte da verificação básica dos dados de WSDL é realizada à medida que objetos desserializados correspondentes a elementos são incluídos na estrutura em árvore do documento WSDL, como mostra o código de addMessage() no final da Listagem 3. Esse método usa o método checkAdd() para verificar a ordem dos elementos filho e o método addName() para se certificar de que um nome válido foi fornecido (o texto corresponde ao tipo de esquema deNCName e o valor é exclusivo dentro do tipo de elemento) e para correlacionar o nome ao objeto. No entanto, isso é só a verificação das informações mais básicas sobre o elemento de forma isolada; é necessário usar mais código de verificação para verificar outras propriedades de cada elemento e as inter-relações entre os elementos.

O JiBX permite chamar ganchos de extensão-usuário como parte dos processos de serialização e desserialização. O modelo do WSDL usa um gancho de extensão desse tipo, um método pós-configuração, para executar a lógica de verificação. O método pós-configuração é chamado depois que o processo de desserialização do objeto associado é concluído — portanto, frequentemente é uma boa forma de executar checagens de verificações de objetos. No caso da verificação do WSDL, a abordagem mais fácil é executar toda a verificação de objetos a partir de um único método pós-configuração, para o elemento-raiz <wsdl:definitions> . Essa abordagem evita problemas de referências antecipadas a componentes do documento WSDL quando os componentes não estão na ordem esperada.


Mais extensões

Neste artigo, você viu os fundamentos da estrutura e uso do WSDL, juntamente com a introdução a um modelo de dados Java para WSDL destinado a suportar a verificação de documentos WSDL e a conversão desses documentos para uma forma condizente com as boas práticas.

O próximo artigo da série aprofunda este tópico, examinando os problemas frequentes ao escrever asserções de política de WS e política de Segurança WS. Também tratará do processamento do modelo de WSDL e verificação com mais profundidade, incluindo a extensão do modelo para incluir asserções de política de WS e política de Segurança WS integradas ao WSDL.

Recursos

Aprender

Discutir

  • Participe da comunidade do developerWorks. Entre em contato com outros usuários do developerWorks e explore os blogs, fóruns, grupos e wikis voltados para desenvolvedores.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=630202
ArticleTitle=Serviços da Web Java : Entendendo e Modelando o WSDL 1.1
publish-date=03012011