Java, Web e Netbeans, parte I: Webservices [Um Estudo de Projeto]

Olá, confesso que andei meio sumida. Mas há um motivo: estava bastante ocupada com um projeto que envolve Java para Web. O projeto está quase no fim e, olhando para trás, percebo que aprendi muitas coisas com esse projeto e, portanto, tenho muito para compartilhar com vocês. Por isso, hoje eu vou iniciar uma série de tutoriais voltados a diversos aspectos de desenvolvimento de software que eu utilizei nesse projeto. Tanto para ajudar outras pessoas que venham a desenvolver projetos de necessidades parecidas, quanto para que eu não me esqueça dessas coisas...

Ao invés de detalhar muito como foi o meu projeto, vou me focar nas necessidades do projeto e nas maneiras que eu encontrei de atender a essas necessidades, de maneira que seja simples para vocês relacionarem essa minha experiência com projetos que vocês tenham.

Para essa primeira parte, vamos dar uma olhada nos requisitos e, então, dar uma olhada em como desenvolver, implantar e testar um serviço web.

1. Uma Sopa de Requisitos

Se o projeto não tivesse tantos requisitos envolvendo tantas áreas diferentes de desenvolvimento, eu provavelmente não teria aprendido tanto. E não são requisitos "aliens", muitos deles já devem fazer parte do dia-a-dia de muitas empresas, tendo em vista as necessidades atuais dos clientes.  Vejam alguns desses requisitos:
  1. Uma série de informações deve ser armazenada em um banco de dados. São tabelas com relações 1-para-muitos e 1-para-1, que precisam ser acessadas e manipuladas pelas aplicações do projeto.
  2. Certas funcionalidades devem ser acessadas por clientes web, uma aplicação deve ter como acessar as operações de uma outra aplicação que pode não estar no mesmo servidor.
  3. Deve existir uma interface web que seja atualizada dinamicamente, conforme o usuário navega e interage com as opções da interface.
  4. Após a aplicação estar pronta, existem certos parâmetros e fluxos do programa que devem poder ser modificados sem que seja necessário mexer em todo o programa e de uma maneira mais visual e compreensível para pessoas que tenham um conhecimento mais administrativo do que programação.
  5. Uma das aplicações do projeto é um portlet, isto é, um pequeno "módulo" a ser encaixado em um portal que já existe e que conta com fóruns, chat, gerenciador de arquivos, calendário, flowchart, etc.

Só de ler esses requisitos você já pode ter imaginado algumas das tecnologias que foram usadas, mas, vamos olhar esses tópicos de novo, dessa vez olhando a tecnologia que foi escolhida:

  1. Persistência em Java? Nós temos algumas opções, como acessar diretamente o banco de dados ou usar uma framework como Hibernate/JPA. No caso, eu preferi usar Hibernate/JPA já que eu não tinha boas lembranças de acessar diretamente o banco de dados com JDBC.
  2. Webservices estão bastante famosos agora, com a necessidade de integrar serviços de diferentes tecnologias em diferentes localidades, e no caso foi escolhido desenvolver um webservice com JAX-WS.
  3. AJAX, essa outra buzzword, foi o escolhido - JavaScript é uma das maneiras mais simples e diretas de atualizar uma página web dinamicamente.
  4. Aqui foi escolhido algo que talvez não seja tão famoso entre desenvolvedores, mas que está ganhando muita atenção em conversas de desenvolvimento de software voltados a serviços: BPEL. Voltado justamente para que pessoas da área de negócios consigam mudar o fluxo de uma aplicação de uma maneira mais visual, que se assemelha a um fluxograma e que, portanto, é muito mais fácil de ser compreendida por alguém de áreas administrativas.
  5. O portal em questão é o Liferay, e um portlet foi modificado (o do fórum) e um foi desenvolvido, utilizando JSP.

Como vocês podem ver, acaba se mexendo com praticamente todas as áreas de Java para um projeto como esse. Hoje eu quero falar um pouco sobre o segundo tópico, webservices.

2. Webservices: Uma Maneira de Integrar Diferentes Serviços

Imaginemos a situação: o seu negócio consiste em um módulo que auxilia empresas a encontrarem distribuidores dos produtos que precisam como matéria-prima - por exemplo, que ajude a encontrar a loja mais próxima com um produto, ou que tem o número de itens necessários, ou o melhor preço, etc. Você tem dois tipos de clientes: as empresas, e os distribuidores cadastrados.

Você poderia inicialmente pensar em dispor isso através de uma página web, que se conecta ao banco de dados com as devidas informações em um servidor. Isso resolve o problema, certo?

Mas e se a empresa tiver um módulo que auxilie essa análise? Digamos que a empresa tenha um módulo que automaticamente procura distribuidores caso o estoque de um determinado item esteja baixo. Não basta que você crie uma interface para as informações, a empresa precisa trabalhar com essas informações da sua maneira, ela deve conseguir obter uma lista de distribuidores de um determinado item sem que seja necessária interação humana.

É aí que surge o webservice, como uma "ponte" entre sistemas de diferentes linguagens, em diferentes servidores, com diferentes finalidades. O webservice serve para conectar dois programas, duas aplicaçõe diferentes.

Como ele faz isso? Mágica?

Bom, quase.

Um webservice é, basicamente, uma aplicação em um servidor que possui um descritor de suas operações em um arquivo WSDL. Esse arquivo WSDL consiste em um XML e contém as operações do serviço, e as entradas e saídas esperadas. Com isso, pouco importa em qual linguagem você irá desenvolver seu cliente, basta você ser capaz de preparar os envelopes para enviar para o serviço.

Vamos dar uma olhada em um WSDL de exemplo que pode ser encontrado aqui:

<?xml version="1.0"?>
<definitions name="StockQuote"
             targetNamespace="http://example.com/stockquote.wsdl"
             xmlns:tns="http://example.com/stockquote.wsdl"
             xmlns:xsd1="http://example.com/stockquote.xsd"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/">

  <types>
    <schema targetNamespace="http://example.com/stockquote.xsd"
            xmlns="http://www.w3.org/2000/10/XMLSchema">
      <element name="TradePriceRequest">
        <complexType>
          <all>
            <element name="tickerSymbol" type="string"/>
          </all>
        </complexType>
      </element>
      <element name="TradePrice">
         <complexType>
           <all>
             <element name="price" type="float"/>
           </all>
         </complexType>
      </element>
    </schema>
  </types>

  <message name="GetLastTradePriceInput">
    <part name="body" element="xsd1:TradePriceRequest"/>
  </message>

  <message name="GetLastTradePriceOutput">
    <part name="body" element="xsd1:TradePrice"/>
  </message>

  <portType name="StockQuotePortType">
    <operation name="GetLastTradePrice">
      <input message="tns:GetLastTradePriceInput"/>
      <output message="tns:GetLastTradePriceOutput"/>
    </operation>
  </portType>

  <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
    <soap:binding style="document" 
          transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="GetLastTradePrice">
      <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>

  <service name="StockQuoteService">
    <documentation>My first service</documentation>
    <port name="StockQuotePort" binding="tns:StockQuoteSoapBinding">
      <soap:address location="http://example.com/stockquote"/>
    </port>
  </service>

</definitions>





































































Parece uma confusão, não? Mas apenas à primeira vista - se você tiver paciência e olhar com calma cada parte do documento, você irá perceber que muitas coisas podem ser compreendidas com um pouco de intuição. Mas, claro, isso é um tutorial e não um exercício de intuição, vamos dar uma olhada em cada parte do documento.

<?xml version="1.0"?>


Isto é, meramente, para sabermos que versão das definições está sendo usada - neste caso, e na maioria deles, 1.0 Outro parâmetro que costuma aparecer aqui é o encoding, para sabermos o conjunto de caracteres que pode ser usado. O mais comum por aqui é UTF-8.

A próxima linha contém o início das definições:

<definitions name="StockQuote"
             targetNamespace="http://example.com/stockquote.wsdl"
             xmlns:tns="http://example.com/stockquote.wsdl"
             xmlns:xsd1="http://example.com/stockquote.xsd"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/">








O nome é o identificador das definições que você irá colocar abaixo, e xmlns:tns possui o namespace do seu wsdl. Esta parte é bastante padrão e geralmente gerada pelas ferramentas que você utilizar para gerar o serviço web. xmls:xsdl possui o namespace do xsd do seu documento.

E o que é xsd, Cindy? Em termos práticos, é um arquivo que costuma conter as definições de tipos que serão usados nas mensagens - já que as mensagens podem conter tipos simples como inteiro, String, booleano, mas também podem conter tipos complexos, como um tipo Endereço que possui como partes o nome da rua, o nome do bairro, o CEP, a cidade, o estado e o país, por exemplo. Esse tipo Endereço pode ser tanto declarado no próprio documento wsdl, ou em um arquivo separado chamado xsd. E como declarar esse tipo complexo? É o que vemos nas linhas seguintes do documento de exemplo:

<types>
    <schema targetNamespace="http://example.com/stockquote.xsd"
            xmlns="http://www.w3.org/2000/10/XMLSchema">
      <element name="TradePriceRequest">
        <complexType>
          <all>
            <element name="tickerSymbol" type="string"/>
          </all>
        </complexType>
      </element>
      <element name="TradePrice">
         <complexType>
           <all>
             <element name="price" type="float"/>
           </all>
         </complexType>
      </element>
    </schema>
  </types>






















Nesse caso, TradePriceRequest é um tipo complexo, que possui como elemento tickerSymbol, do tipo String, e temos também TradePrice, que possui como elemento price do tipo float. Por que declarar isso ao invés de apenas usar um tipo String ou float na hora de declarar as partes da mensagem? Nesse caso realmente não faz muito sentido, mas poderíamos criar um tipo como Endereço, um tipo que fosse uma sequência de outros elementos, podendo conter múltiplas ocorrências de um desses elementos, por exemplo. 

E no caso de termos isso em um documento xsd? Aí nós teríamos algo assim (este retirado de um documento wsdl gerado pelo netbeans):

<types>
   <xsd:schema 
       targetNamespace="http://localhost/SynchronousSample/SynchronousSample">
       <xsd:import namespace="http://xml.netbeans.org/schema/SynchronousSample" 
                   schemaLocation="SynchronousSample.xsd"/>
   </xsd:schema>
</types>









A próxima parte consiste em definir quais serão as mensagens trocadas:

<message name="GetLastTradePriceInput">
    <part name="body" element="xsd1:TradePriceRequest"/>
</message>

<message name="GetLastTradePriceOutput">
    <part name="body" element="xsd1:TradePrice"/>
</message>









Como podemos ver, são duas mensagems, uma que será usada como parâmetro de entrada e outra como a resposta do serviço. Uma mensagem pode ter diversas partes mas como tipos mais complexos costumam ser definidos no schema, aqui é comum termos apenas uma parte, com um nome qualquer e cujo tipo é o tipo complexo definido anteriormente.

Agora que temos as mensagens bem definidas, o que resta é definirmos as operações a serem realizadas:

 <portType name="StockQuotePortType">
    <operation name="GetLastTradePrice">
      <input message="tns:GetLastTradePriceInput"/>
      <output message="tns:GetLastTradePriceOutput"/>
    </operation>
  </portType>









PortType consiste na definição da interface do serviço, com as operações que serão expostas, com suas respectivas mensagens. Ela pode ter várias operações, claro, mas aqui nós vemos uma única operação, que usa como mensagens de entrada e saída aquelas que já foram definidas nesse mesmo documento.

Agora, essas mensagens podem ser trocadas de diversas maneiras, através de diferentes protocolos. É aí que entra o binding:

<binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="GetLastTradePrice">
      <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>













Ele serve para dizer que essa mensagem pode ser trocada via SOAP, e que as mensagens são trocas usando "literal".

Por último, temos uma pequena definição com o nome do serviço, e talvez uma linha de documentação, além de descrever port e binding:

<service name="StockQuoteService">
    <documentation>My first service</documentation>
    <port name="StockQuotePort" binding="tns:StockQuoteSoapBinding">
      <soap:address location="http://example.com/stockquote"/>
    </port>
  </service>









E, é isso. Embora você talvez não consiga escrever seu próprio WSDL após ler isso, você provavelmente vai ter condição de entender um documento quando ver um. Como você pode gerar WSDL com ferramentas como o Netbeans, você pode ir lentamente, aprendendo sobre os detalhes de WSDL aos poucos, conforme for necessitando de algo que não seja feito de imediato pela ferramenta, ou quando você precisar entender um documento alheio.

3. Colocando a Mão na Massa: Criando um Webservice com o Netbeans

Como já dito, webservices podem ser escritos em diversas linguagens, entre elas Java. O NetBeans possui diversas ferramentas que nos auxiliam a escrever, implantar e testar um serviço web, de uma maneira bastante simples.

Primeiro, crie um projeto de Java Web, indo no menu Arquivo -> Novo Projeto -> Java Web.

Um detalhe: configure-o para Java 5 para usar anotações, e selecione o servidor Glassfish v2. Embora outros servidores suportem serviços web, Glassfish v2 possui uma boa ferramenta para testes rápidos e que é facilmente acessada a partir do próprio Netbeans.

Não é necessário selecionar nenhuma das frameworks para desenvolvimento web, a menos que você vá utilizar para outra parte do seu projeto.

Então, com o projeto criado, clique com o botão direito sobre o projeto, vá em Novo -> Outro. Então, vá em Serviços Web e selecione Serviço Web como mostrado abaixo:



Dê um nome ao serviço, um pacote e selecione a opção para criar um serviço web do início. Você verá que ele cria um novo arquivo com algumas poucas linhas e algumas anotações, e uma mensagem de erro:

A mensagem de erro se deve ao fato de que nosso serviço ainda não possui nenhuma operação! Isso é facilmente corrigido clicando sobre a mensagem de operação e então selecionando "Adicionar operação". Dê um nome à operação, selecione a saída e os parâmetros de entrada. Para o nosso pequeno exemplo, vamos definir o serviço desta maneira:


E ele irá criar um método na sua classe:

    /\*\*
     \* Operação de serviço web
     \*/
    @WebMethod(operationName = "olaMundo")
    public String olaMundo(@WebParam(name = "nome")
    String nome) {
        //TODO grava o seu código de implementação aqui:
        return null;
    }

Podemos fazer um exemplo no qual o serviço recebe um texto com o nome do usuário, e então manda uma mensagem de volta cumprimentando-o. Incrivelmente complexo, claro. Essa seria a nossa clase, depois de completa:

package ws;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;


@WebService()
public class helloWorldWS {

    @WebMethod(operationName = "olaMundo")
    public String olaMundo(@WebParam(name = "nome")
    String nome) {
       return "Olá, "+nome;
    }


}

E agora, será que funciona? Para verificar, vamos implantar no servidor Glassfish v2. Feito isso, você deve ir na pasta Serviços Web do seu projeto, clicar com o botão direito sobre o helloWorldWS que você criou e então em testar serviço web. Irá abrir uma página no seu navegador web como essa:


Onde você pode informar os parâmetros e então clicar no botão para chamar a operação. No caso do nosso exemplo, isto é o que a nossa operação nos retorna:

Ele mostra quais foram os parâmetros de entrada, o que o método retornou, e ainda mostra os envelopes SOAP que foram trocados. É importante notar que envelopes SOAP sempre tem esse formado, de um envelope que possui um corpo e dentro dosse corpo está a mensagem a ser transmitida, como o nome da operação e os parâmetros. Ainda é possível notar que a resposta possui um "Response" anexado ao nome da operação.

Se você quiser ver o WSDL criado pelo Netbeans, basta trocar o ?tester da barra de endereços por ?wsdl, tendo o endereço local do seu serviço.

Bom, é isso. Espero que vocês tenham gostado dessa 'pequena' introdução do tutorial do projeto e, qualquer dúvida, não hesitem em comentar ;)

Comments:

Fiz Desta forma soque ao Baixar deu erro nas tag do xml do WSDL

tipo <any> nao declarado

Posted by guest on Março 30, 2011 at 03:31 PM GMT+03:00 #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Blog com tutoriais relacionados a desenvolvimento de software, especialmente Java, e que conta com as experiências de desenvolvimento de uma menina maluquinha, digo, eu.

Search

Archives
« Abril 2014
SegTerQuaQuiSexSábDom
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today