// 
//     Licensed to the Apache Software Foundation (ASF) under one
//     or more contributor license agreements.  See the NOTICE file
//     distributed with this work for additional information
//     regarding copyright ownership.  The ASF licenses this file
//     to you under the Apache License, Version 2.0 (the
//     "License"); you may not use this file except in compliance
//     with the License.  You may obtain a copy of the License at
// 
//       http://www.apache.org/licenses/LICENSE-2.0
// 
//     Unless required by applicable law or agreed to in writing,
//     software distributed under the License is distributed on an
//     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//     KIND, either express or implied.  See the License for the
//     specific language governing permissions and limitations
//     under the License.
//

= Desenvolvimento de Clientes de Web Service JAX-WS
:jbake-type: tutorial
:jbake-tags: tutorials 
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Desenvolvimento de Clientes de Web Service JAX-WS - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Desenvolvimento de Clientes de Web Service JAX-WS

Neste tutorial, você utilizará os recursos de Web service fornecidos pelo NetBeans IDE para analisar um Web Service de Corretor Ortográfico e depois criar um cliente Web que interaja com o serviço. O cliente usará uma classe de servlet e uma página Web. O usuário passará informações para o servlet a partir da página Web.


image::images/netbeans-stamp-80-74-73.png[title="O conteúdo desta página se aplica ao NetBeans IDE 7.2, 7.3, 7.4 e 8.0"]


*Para seguir este tutorial, são necessários os recursos e o software a seguir.*

|===
|Software ou Recurso |Versão Necessária 

|link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |Pacote de download do Java EE 

|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+JDK (Java Development Kit)+] |versão 7 ou versão 8 

|Servidor de aplicações ou Web compatível com Java EE |Servidor Web Tomcat 7.0 
GlassFish Server Open Source Edition
Oracle WebLogic Server 
|===

*Cuidado:*Se estiver utilizando o JDK 6, será necessário possuir o JDK 6 Atualização 7 ou posterior.

O Tomcat e o GlassFish Server podem ser instalados com a distribuição Web e Java EE do NetBeans IDE. Como alternativa, você pode visitar a link:https://glassfish.java.net/download.html[+página de downloads do GlassFish Server+] ou a link:http://tomcat.apache.org/download-60.cgi[+página de downloads do Apache Tomcat+].

*Importante: *os projetos Java EE requerem Tomcat 7.x, GlassFish Server ou Oracle WebLogic Server 12c.

Esta será a aparência do cliente, com todos os dados recebidos do Web service:

image::images/jaxwsc-spellchecker-report.png[title="Relatório de Corretor Ortográfico"]

No fim deste tutorial, você descobrirá que sua única contribuição com a aplicação consiste em fornecer o texto a ser verificado, chamar uma operação no Web service e renderizar o resultado. O IDE gera todo o código necessário para entrar em contato com o Web service e enviar o texto. O Web service de Corretor ortográfico cuida do restante. Ele identifica as palavras com erro ortográfico e fornece uma lista de alternativas sugeridas.

O Web service de corretor ortográfico usado neste tutorial é fornecido pela link:http://www.cdyne.com/account/home.aspx[+CDYNE Corporation.+] A CDYNE desenvolve, comercializa e oferece suporte a um conjunto abrangente de Web services para análise de dados, qualidade de dados e aprimoramento de dados e integração de inteligência comercial. O Web service de corretor ortográfico é um dos Web services fornecidos pela CDYNE. Observe que a capacidade de uma aplicação baseado em um ou mais Web services depende da disponibilidade e confiabilidade dos Web services. Entretanto, as link:http://www.cdyne.com/company/faqs.aspx[+Perguntas Frequentes+] da CDYNE apontam que ela tem "100% de disponibilidade" como objetivo e, no caso de um "desastre natural, ato terrorista ou outra catástrofe, o tráfego do Web service será transferido para o centro de dados secundário". A NetBeans agradece à CDYNE por permitir que este tutorial tenha sido escrito e por oferecer suporte ao seu desenvolvimento.


== Consumindo o Web Service de Corretor Ortográfico 

Para usar um Web service na rede, o que é denominado "consumo" de um Web service, é preciso criar um cliente de Web service. Para a criação de clientes de Web service, o NetBeans IDE fornece um recurso de criação de cliente, que é o assistente de Cliente de Web Service, que gera o código para pesquisar um Web service. Ele também fornece recursos para desenvolver o cliente de Web service criado, que é uma área de trabalho que consiste em nós na janela Projetos. Esses recursos fazem parte do pacote EE da instalação do NetBeans IDE. Eles são fornecidos e não é necessário nenhum plug-in.


=== Criando o Cliente 

Nesta seção, você utilizará um assistente para gerar objetos Java a partir do arquivo WSDL do Web service.

1. Selecione Arquivo > Novo Projeto (Ctrl-Shift-N no Linux e Windows, ⌘-Shift-N no MacOS). Em Categorias, selecione Java Web. Em Projetos, selecione Aplicação Web. Clique em Próximo. Defina o nome do projeto como  ``SpellCheckService``  e especifique um servidor apropriado como o servidor de destino. (Consulte a seção "Introdução" para ver os detalhes). Aceite as outras opções default e clique em Finalizar.
2. Na janela Projetos, clique com o botão direito no nó do projeto  ``SpellCheckService``  e escolha Novo > Outros e selecione Cliente de Web Service na categoria Web Services do assistente Novo Arquivo. Clique em Próximo.
3. Selecione o URL de WSDL e especifique o seguinte URL para o web service:

link:http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl[+http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl+]

Se você estiver protegido por firewall, talvez seja necessário especificar um servidor proxy, do contrário, o arquivo WSDL não poderá ser baixado. Para especificar o servidor proxy, clique em Definir Proxy no assistente. A janela Opções do IDE será aberta, onde você poderá definir o proxy de forma universal para o IDE.


[start=4]
. Deixe o nome do pacote em branco. Por default, o nome do pacote de classe do cliente é baseado no WSDL. Nesse caso, é  ``com.cdyne.ws`` . Clique em Finalizar.

[start=5]
. Na janela Projetos, no nó Referências de Web Service, você verá o seguinte:
image::images/ws-refs.png[title="Janela Projetos mostrando as referências de Web services"]

A janela Projetos mostra que um Web service chamado 'check' tornou disponível uma quantidade de operações 'CheckTextBody' e 'CheckTextBodyV2' para sua aplicação. Estas operações verificam se há erros de ortografia em uma sequência de caracteres e retorna os dados para serem processados pelo cliente. A versão V2 do serviço não requer autenticação. Você utilizará a operação  ``checkSoap.CheckTextBodyV2``  neste tutorial.

No nó  ``Códigos-Fonte Gerados `` , você verá os stubs cliente que foram gerados pelo assistente de Cliente de Web Service JAX-WS.

image::images/gen-files.png[title="Exibição de Arquivos mostrando a estrutura do nó Construir do pacote"]

Expanda o nó WEB-INF e o subnó wsdl. Você encontrará uma cópia local do arquivo WSDL, denominada  ``check.asmx.wsdl`` .

image::images/web-inf.png[]

O URL do WSDL que você usou para criar o cliente é mapeado para a cópia local do WSDL no  ``jax-ws-catalog.xml`` . O mapeamento para a cópia local tem diversas vantagens. A cópia remota do WSDL não precisa estar disponível para que o cliente seja executado. O cliente é mais rápido porque não precisa fazer parsing de um arquivo WSDL remoto. Por fim, a portabilidade é mais fácil.

image::images/jax-ws-catalog.png[]


=== Desenvolvendo o Cliente 

Há muitas maneiras de implementar um cliente de Web service. O arquivo WSDL do Web service restringe o tipo de informações que você pode enviar para o Web service e restringe o tipo de informações que você recebe de volta. Entretanto, o arquivo WSDL não faz restrições sobre _como_ você passa as informações necessárias nem sobre o _que_ consiste a interface do usuário. A implementação do cliente que você construirá a seguir consiste em uma página Web que permite que o usuário insira o texto a ser verificado e um servlet que passará o texto para o Web service e depois gerará um relatório contendo o resultado.


==== Codificando a Página Web 

A página Web consistirá de uma área de texto, onde o usuário inserirá um texto e um botão para enviar o texto para o Web service. Dependendo da versão do servidor escolhida como servidor de destino, o IDE gerou  ``index.html``  ou  ``index.jsp``  como a página do índice da aplicação.

1. Na janela Projetos, expanda o nó Páginas Web do projeto  ``SpellCheckService``  e clique duas vezes na página do índice ( ``index.html``  ou  ``index.jsp`` ) para abrir o arquivo no Editor de Código-fonte.
2. Copie o seguinte código e cole-o sobre as tags  ``<body>``  na página do índice:

[source,html]
----

<body>
  <form name="Test" method="post" action="SpellCheckServlet">
     <p>Enter the text you want to check:</p>
     <p>
     <p><textarea rows="7" name="TextArea1" cols="40" ID="Textarea1"></textarea></p>
     <p>
     <input type="submit" value="Spell Check" name="spellcheckbutton">
  </form>
</body>
----

O código acima listado especifica que, ao clicar no botão Submeter, o conteúdo de  ``textarea``  é postado em um servlet chamado  ``SpellCheckServlet`` .


==== Criando e Codificando o Servlet 

Nesta seção, você criará um servlet que irá interagir com o Web service. Entretanto, o código que realiza a interação será fornecido pelo IDE. Como resultado, você só precisa lidar com a lógica de negócios, ou seja, a preparação do texto a ser enviada e o processamento do resultado.

1. Clique com o botão direito do mouse no nó do projeto  ``SpellCheckService ``  na janela Projetos, selecione Novo > Outro e, em seguida, selecione Web > Servlet. Clique em Próximo para abrir o assistente Novo Servlet.
2. Defina o nome do servlet como  ``SpellCheckServlet``  e digite  ``clientservlet``  na lista drop-down Pacote. Clique em Próximo.
image::images/name-servlet.png[]

[start=3]
. No painel Configurar Implantação do Servlet, observe que o mapeamento do URL deste servlet é  ``/SpellCheckServlet`` . Aceite os defaults e clique em Finalizar. O servlet será aberto no Editor de Código-Fonte.
image::images/jaxwsc-servlet.png[]

[start=4]
. Coloque o cursor no Editor de Código-Fonte, dentro do corpo do método  ``processRequest``  de  ``SpellCheckServlet.java``  e adicione algumas linhas novas logo acima do método.

[start=5]
. Clique com o botão direito do mouse no espaço criado na etapa anterior e selecione Inserir Código > Chamar Operação de Web Service. Clique na operação  ``checkSoap.CheckTextBodyV2``  na caixa de diálogo "Selecionar Operação a Ser Chamada", conforme mostrado a seguir:
image::images/insert-ws-ops.png[title="Janela Projetos mostrando as referências de Web services"]

Clique em OK.

*Observação:* você também pode arrastar e soltar o nó da operação diretamente da janela Projetos no editor, em vez de chamar a caixa de diálogo mostrada anteriormente.

No final da classe  ``SpellCheckServlet`` , você verá um método privado para chamar o serviço SpellCheckerV2 e para retornar um objeto  ``com.cdyne.ws.DocumentSummary`` .


[source,java]
----

private DocumentSummary checkTextBodyV2(java.lang.String bodyText) {com.cdyne.ws.CheckSoap port = service.getCheckSoap();return port.checkTextBodyV2(bodyText);}
----

Somente este método é necessário para chamar a operação no Web service. Além disso, as linhas de código a seguir (em negrito) são declaradas na parte superior da classe:


[source,java]
----

public class SpellCheckServlet extends HttpServlet {
    *@WebServiceRef(wsdlLocation = "http://wsf.cdyne.com/SpellChecker/check.asmx?WSDL")
    private Check service;*
----

[start=6]
. Substitua o bloco  ``try``  do método  ``processRequest()``  pelo código a seguir. Os comentários alinhados no código a seguir explicam a finalidade de cada linha.

[source,html]
----

try (PrintWriter out = response.getWriter()) {
*    //Get the TextArea from the web page*String TextArea1 = request.getParameter("TextArea1");*//Initialize WS operation arguments*
    java.lang.String bodyText = TextArea1;

    *//Process result*
    com.cdyne.ws.DocumentSummary doc = checkTextBodyV2(bodyText);
    String allcontent = doc.getBody();

    *//From the retrieved document summary,
    //identify the number of wrongly spelled words:*
    int no_of_mistakes = doc.getMisspelledWordCount();

    *//From the retrieved document summary,
    //identify the array of wrongly spelled words:*
    List allwrongwords = doc.getMisspelledWord();

    out.println("<html>");
    out.println("<head>");

    *//Display the report's name as a title in the browser's titlebar:*
    out.println("<title>Spell Checker Report</title>");
    out.println("</head>");
    out.println("<body>");

    *//Display the report's name as a header within the body of the report:*
    out.println("<h2><font color='red'>Spell Checker Report</font></h2>");

    *//Display all the content (correct as well as incorrectly spelled) between quotation marks:*
    out.println("<hr><b>Your text:</b> \"" + allcontent + "\"" + "<p>");

    *//For every array of wrong words (one array per wrong word),
    //identify the wrong word, the number of suggestions, and
    //the array of suggestions. Then display the wrong word and the number of suggestions and
    //then, for the array of suggestions belonging to the current wrong word, display each
    //suggestion:*
    for (int i = 0; i < allwrongwords.size(); i++) {
        String onewrongword = ((Words) allwrongwords.get(i)).getWord();
        int onewordsuggestioncount = ((Words) allwrongwords.get(i)).getSuggestionCount();
        List allsuggestions = ((Words) allwrongwords.get(i)).getSuggestions();
        out.println("<hr><p><b>Wrong word:</b><font color='red'> " + onewrongword + "</font>");
        out.println("<p><b>" + onewordsuggestioncount + " suggestions:</b><br>");
        for (int k = 0; k < allsuggestions.size(); k++) {
            String onesuggestion = (String) allsuggestions.get(k);
            out.println(onesuggestion);
        }
    }

    *//Display a line after each array of wrong words:*
    out.println("<hr>");

    *//Summarize by providing the number of errors and display them:*
    out.println("<font color='red'><b>Summary:</b> " + no_of_mistakes + " mistakes (");
    for (int i = 0; i < allwrongwords.size(); i++) {
        String onewrongword = ((Words) allwrongwords.get(i)).getWord();
        out.println(onewrongword);
    }

    out.println(").");
    out.println("</font>");
    out.println("</body>");
    out.println("</html>");

} 

----

[start=7]
. Você verá diversas barras de erros e ícones de advertência indicando as classes não foram encontradas. Para corrigir as importações depois de colar o código, pressione Ctrl-Shift-I (⌘-Shift-I no Mac) ou clique com o botão direito do mouse em qualquer lugar, o que abrirá um menu de contexto. Lá, selecione Corrigir Importações. (Você poderá listar as classes para importação. Aceite o java.util.List default). Segue a lista das classes importadas:

[source,java]
----

import com.cdyne.ws.Check;
import com.cdyne.ws.Words;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.WebServiceRef;
----

*Observação: *Se forem exibidas advertências de que não foi possível encontrar as classes  ``com.cdyne.*`` , não se assuste. Este problema é resolvido quando você constrói o projeto, conforme o IDE faz parsing dos arquivos WSDL e encontra as classes.

Observe que não houve tratamento de erros no código acima listado. Consulte <<applyingwhatyouhavelearned,Aplicando o que Você Aprendeu>> para obter detalhes.


=== Implantando o Cliente 

O IDE utiliza um script de construção Ant para construir e executar sua aplicação. O IDE gera o script de construção com base nas opções inseridas ao criar o projeto. Você pode ajustar essas opções na caixa de diálogo Propriedades do Projeto do projeto (clique com o botão direito do mouse no nó do projeto na janela Projetos e selecione Propriedades).

1. Clique com o botão direito do mouse no nó do projeto e selecione Executar. Após um tempo, a aplicação é implantada e exibe a página Web codificada na seção anterior.
2. Insira um texto, verificando se parte dele está escrita incorretamente:
image::images/jaxwsc-spellchecker-form.png[title="Página JSP com texto para verificação"]

[start=3]
. Clique em Verificar Ortografia e veja o resultado:
image::images/jaxwsc-spellchecker-report.png[title="Relatório do Corretor Ortográfico mostrando erros"]


[[asynch]]
== Clientes Assíncronos de Web Service

Por default, os clientes JAX-WS criados pelo NetBeans IDE são assíncronos. Os clientes assíncronos chamam uma solicitação em um serviço e, a seguir, interrompem seus processamentos enquanto aguardam a resposta. No entanto, em alguns casos, você quer que o cliente continue com outros processamentos em vez de aguardar a resposta. Em alguns casos, por exemplo, o serviço poderá demorar um pouco para processar a solicitação. Os clientes de Web service que continuam processando sem aguardar a resposta do serviço são chamados de "assíncronos".

Os clientes assíncronos iniciam uma solicitação a um serviço e, em seguida, retomam seu processamento sem aguardar uma resposta. O serviço manipula a solicitação do cliente e devolve uma resposta algum tempo depois, em cujo momento o cliente recupera a resposta e continua com seu processamento.

Os clientes assíncronos consomem Web services por meio da abordagem "sondagem" ou "retorno de chamada". Na abordagem "sondagem", você chama um método de Web service e solicita repetidamente o resultado. A sondagem é uma operação de bloqueio porque bloqueia o thread que está realizando a chamada, motivo pelo qual você não quer usá-la em uma aplicação de GUI. Na abordagem "retorno de chamada", você passa por um handler de callback durante a chamada do método de Web service. O método  ``handleResponse()``  do handler é chamado quando o resultado fica disponível. Essa abordagem é apropriada para aplicações de GUI porque não é necessário aguardar a resposta. Por exemplo, você faz uma chamada de um handler de eventos de GUI e retorna o controle imediatamente, mantendo a interface de usuário receptiva. A desvantagem da abordagem de sondagem é que, mesmo que a resposta seja utilizada após ser obtida, é necessário verificar para saber se ela foi obtida.

No NetBeans IDE, você adiciona suporte para clientes assíncronos a uma aplicação cliente de Web service marcando uma caixa na GUI para Editar Atributos do Web Service nas referências do Web service. Todos os outros aspectos do desenvolvimento de clientes são iguais aos dos clientes síncronos, exceto pela presença dos métodos de sondagem do Web service ou de passagem pelo handler de callback e aguardar o resultado.

O restante desta seção explica como criar uma interface gráfica Swing e incorporar nela um cliente assíncrono JAX-WS.


[[asynch-swing]]
=== Criando o Form Swing

Nesta seção, você criará a aplicação Swing. Se não quiser criar a GUI Swing, você poderá link:https://netbeans.org/projects/www/downloads/download/webservices%252FAsynchSpellCheckForm.zip[+fazer o download de um JFrame predeterminado+] e ir à seção <<asynch-creatingtheclient,Criando o Cliente Assíncrono>>.

O cliente Swing pega o texto que você digitou, envia-o ao serviço e retorna o número de erros e uma lista de todas as palavras erradas. O cliente também mostra cada uma das palavras erradas e as sugestões para substituí-las, uma de cada vez.

image::images/asynch-swing-client.png[]

*Para criar o cliente Swing:*

1. Crie um novo projeto de Aplicação Java. Defina seu nome como  ``AsynchSpellCheckClient`` . NÃO crie uma classe  ``Main``  para o projeto.
2. Na view Projetos, clique com o botão direito do mouse no nó do projeto  ``AsynchSpellCheckClient``  e selecione Novo > Form JFrame...
3. Defina o nome do form como  ``MainForm``  e coloque-o no pacote  ``org.me.forms`` .
4. Após a criar o JFrame, abra as propriedades do projeto. Na categoria Executar, defina  ``MainForm``  como classe Principal.
image::images/asynch-main-class.png[]

[start=5]
. No Editor, abra a view Projeto de  ``MainForm.java`` . Da Paleta, arraste e solte três Painéis de Rolagem no  ``MainForm`` . Posicione e ajuste o tamanho dos painéis de rolagem. Eles conterão os campos de texto dos textos digitados para verificação, todas as palavras erradas e as sugestões para uma palavra errada.

[start=6]
. Arraste e solte cinco Campos de Texto no  ``MainForm`` . Arraste três deles para dentro dos painéis de rolagem. Modifique-os da seguinte forma:
|===

|Campos de Texto 

|Nome da Variável |No Painel de Rolagem? |Editável? 

|tfYourText |Y |Y 

|tfNumberMistakes |N |N 

|tfWrongWords |Y |N 

|tfWrongWord1 |N |N 

|tfSuggestions1 |Y |N 
|===

[start=7]
. Arraste e solte uma Barra de Andamento no  ``MainFrame`` . Chame a variável de  ``pbProgress`` .

[start=8]
. Arraste e solte dois Botões no  ``MainForm`` . Defina o nome do primeiro botão como  ``btCheck``  e altere seu texto para Verificar Texto ou Verificar Ortografia. Definia o nome do segundo botão como  ``btNextWrongWord`` , altere seu texto para Próxima Palavra Errada e desative-o.

[start=9]
. Arraste e solte alguns Labels no  ``MainForm``  para dar um título à aplicação e para descrever os campos de texto.

Arrume a aparência do JFrame de acordo com a sua preferência e salve-o. Depois, você adicionará a funcionalidade de cliente de Web service.


[[asynch-creatingtheclient]]
=== Ativando Clientes Assíncronos

Adicione as referências do Web service, conforme descrito em <<creatingtheclient,Criando o Cliente>>. Em seguida, edite os atributos do Web service para ativar clientes assíncronos.

1. Na janela Projetos, clique com o botão direito do mouse no nó  ``AsynchSpellCheckClient``  do projeto e selecione Novo > Outro. No assistente de Novo Arquivo, selecione Web Services > Cliente do Web Service. No assistente do Cliente de Web Service, especifique o URL para o Web service:

link:http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl[+http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl+]. Aceite todos os defaults e clique em Finalizar. Trata-se do mesmo procedimento da Etapa 2, descrito a seguir em <<creatingtheclient,Criando o Cliente>>.


[start=2]
. Expanda o nó Referências de Web Services e clique com o botão direito do mouse no serviço  ``check`` . O menu de contexto será aberto.
image::images/asynch-edit-ws-attrib.png[]

[start=3]
. No menu de contexto, selecione Editar Atributos do Web Service. A caixa de diálogo Atributos do Web service será aberta.

[start=4]
. Selecione a guia Personalização de WSDL.

[start=5]
. Expanda o nó Operações de Tipos de Porta. Expanda o *primeiro* nó  ``CheckTextBodyV2``  e selecione Ativar Cliente Assíncrono.
image::images/enable-async-client.png[]

[start=6]
. Clique em OK. A caixa de diálogo será fechada e será exibida uma advertência informando que a alteração dos atributos de Web service atualizarão o nó do cliente.
image::images/asynch-refresh-node-warning.png[]

[start=7]
. Clique em OK. A advertência será fechada e o nó do cliente, atualizado. Se expandir o nó  ``check``  em Referências de Web Service, você verá que agora possui as versões Sondagem e Retorno de Chamada da operação  ``CheckTextBody`` .
image::images/asynch-ws-refs.png[]

Os clientes assíncronos de Web service do serviço SpellCheck agora estão ativados para sua aplicação.


[[asynch-addcode]]
=== Adicionando o Código de Cliente Assíncrono

Agora que você possui operações assíncronas de Web service, adicione uma operação assíncrona ao  ``MainForm.java`` .

*Para adicionar o código de cliente assíncrono:*

1. No  ``MainForm`` , passe para a view de Código-Fonte e adicione o seguinte método antes da última chave de fechamento. 

[source,java]
----

public void callAsyncCallback(String text){
                 
}
----

[start=2]
. Na janela Projetos, expanda o nó Referências de Web Service do  ``AsynchSpellCheckService``  e localize a operação  ``checkSoap.CheckTextBodyV2 [Asynch Callback]`` .

[start=3]
. Arraste a operação  ``CheckTextBodyV2 [Asynch Callback]``  para o corpo do método  ``callAsynchCallback``  vazio. O IDE irá gerar o seguinte bloco  ``try`` . Compare este código gerado ao código gerado para o cliente síncrono.

[source,java]
----

try { // Call Web Service Operation(async. callback)
      com.cdyne.ws.Check service = new com.cdyne.ws.Check();
      com.cdyne.ws.CheckSoap port = service.getCheckSoap();
      // TODO initialize WS operation arguments here
      java.lang.String bodyText = "";
      javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = 
              new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
            public void handleResponse(javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
                  try {
                        // TODO process asynchronous response here
                        System.out.println("Result = "+ response.get());
                  } catch(Exception ex) {
                        // TODO handle exception
                  }
            }
      };
      java.util.concurrent.Future<? extends java.lang.Object> result = port.checkTextBodyV2Async(bodyText, asyncHandler);
      while(!result.isDone()) {
            // do something
            Thread.sleep(100);
      }
      } catch (Exception ex) {
      // TODO handle custom exceptions here
}
----

Neste código, junto com a chamada do Web service, você observa que a resposta do serviço SpellCheck é manipulada por meio de um objeto  ``AsynchHandler`` . Enquanto isso, um objeto  ``Future``  verifica se foi retornado um resultado e inativa o thread até que o resultado seja concluído.


[start=4]
. Volte para a view do Projeto. Clique Duas Vezes no Botão Verificar Ortografia. O IDE adiciona automaticamente um ActionListener ao botão e alterna para a view Código-Fonte, com o cursor no método  ``btCheckActionPerformed``  vazio.

[start=5]
. Adicione o seguinte código ao corpo do método  ``btCheckActionPerformed`` . Este código toma o texto que você digitou no campo  ``tfYourText`` , exibe a mensagem "aguardando servidor" na barra de progresso, desativa o botão  ``btCheck``  e chama o método de retorno de chamada assíncrono.

[source,java]
----

private void btCheckActionPerformed(java.awt.event.ActionEvent evt) {                                        
    *String text = tfYourText.getText();
    pbProgress.setIndeterminate(true);
    pbProgress.setString("waiting for server");
    btCheck.setEnabled(false);
    callAsyncCallback(text);*
}
----

[start=6]
. No início da classe  ``MainForm`` , instancie um campo  ``ActionListener``  privado denominado  ``nextWord`` . Este  ``ActionListener``  é para que o botão Próxima Palavra Errada que passa para a palavra errada seguinte da lista de palavras erradas e exibe a palavra e as sugestões para corrigi-la. Você cria o campo privado aqui, assim você pode cancelar o registro de  ``ActionListener``  se ele já tiver sido definido. Do contrário, sempre que você verificar um novo texto, terá que adicionar um listener e o resultado será vários listeners chamando  ``actionPerformed()``  várias vezes. Nesse caso, a aplicação não terá o comportamento correto.

[source,java]
----

public class MainForm extends javax.swing.JFrame {
    
    private ActionListener nextWord;
    ...
----

[start=7]
. Substitua todo o método  ``callAsynchCallback``  pelo código a seguir. Observe que o bloco  ``try``  mais externo foi removido. Isso é desnecessário, pois blocos  ``try``  mais específicos são adicionados ao método. Outras alterações no código são esclarecidas nos comentários do código.

[source,java]
----

public void callAsyncCallback(String text) {

        
    com.cdyne.ws.Check service = new com.cdyne.ws.Check();
    com.cdyne.ws.CheckSoap port = service.getCheckSoap();
    // initialize WS operation arguments here
    java.lang.String bodyText = text;

    javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {

        public void handleResponse(final javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
            SwingUtilities.invokeLater(new Runnable() {

                public void run() {

                    try {
                        // Create a DocumentSummary object containing the response.
                        // Note that getDocumentSummary() is called from the Response object
                        // unlike the synchronous client, where it is called directly from
                        // com.cdyne.ws.CheckTextBodycom.cdyne.ws.DocumentSummary doc = response.get().getDocumentSummary();
//From the retrieved DocumentSummary,
                        //identify and display the number of wrongly spelled words:
final int no_of_mistakes = doc.getMisspelledWordCount();
                        String number_of_mistakes = Integer.toString(no_of_mistakes);
                        tfNumberMistakes.setText(number_of_mistakes);
// Check to see if there are any mistakes
                        if (no_of_mistakes > 0) {
//From the retrieved document summary,
                            //identify the array of wrongly spelled words, if any:
final List<com.cdyne.ws.Words> allwrongwords = doc.getMisspelledWord();
//Get the first wrong word
                            String firstwrongword = allwrongwords.get(0).getWord();
//Build a string of all wrong words separated by commas, then display this in tfWrongWords
StringBuilder wrongwordsbuilder = new StringBuilder(firstwrongword);

                            for (int i = 1; i < allwrongwords.size(); i++) {
                                String onewrongword = allwrongwords.get(i).getWord();
                                wrongwordsbuilder.append(", ");
                                wrongwordsbuilder.append(onewrongword);
                            }
                            String wrongwords = wrongwordsbuilder.toString();
                            tfWrongWords.setText(wrongwords);
//Display the first wrong word
                            tfWrongWord1.setText(firstwrongword);
//See how many suggestions there are for the wrong word
                            int onewordsuggestioncount = allwrongwords.get(0).getSuggestionCount();
//Check to see if there are any suggestions.
                            if (onewordsuggestioncount > 0) {
//Make a list of all suggestions for correcting the first wrong word, and build them into a String.
                                //Display the string of concactenated suggestions in the tfSuggestions1 text field
List<String> allsuggestions = ((com.cdyne.ws.Words) allwrongwords.get(0)).getSuggestions();

                                String firstsuggestion = allsuggestions.get(0);
                                StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion);
                                for (int i = 1; i < onewordsuggestioncount; i++) {
                                    String onesuggestion = allsuggestions.get(i);
                                    suggestionbuilder.append(", ");
                                    suggestionbuilder.append(onesuggestion);
                                }
                                String onewordsuggestions = suggestionbuilder.toString();
                                tfSuggestions1.setText(onewordsuggestions);

                            } else {
                                // No suggestions for this mistake
                                tfSuggestions1.setText("No suggestions");
                            }
                            btNextWrongWord.setEnabled(true);
// See if the ActionListener for getting the next wrong word and suggestions
                            // has already been defined. Unregister it if it has, so only one action listener
                            // will be registered at one time.
if (nextWord != null) {
                                btNextWrongWord.removeActionListener(nextWord);
                            }
// Define the ActionListener (already instantiated as a private field)
                            nextWord = new ActionListener() {
//Initialize a variable to track the index of the allwrongwords list

                                int wordnumber = 1;

                                public void actionPerformed(ActionEvent e) {
                                    if (wordnumber < no_of_mistakes) {
// get wrong word in index position wordnumber in allwrongwords
                                        String onewrongword = allwrongwords.get(wordnumber).getWord();
//next part is same as code for first wrong word
tfWrongWord1.setText(onewrongword);
                                        int onewordsuggestioncount = allwrongwords.get(wordnumber).getSuggestionCount();
                                        if (onewordsuggestioncount > 0) {
                                            List<String> allsuggestions = allwrongwords.get(wordnumber).getSuggestions();
                                            String firstsuggestion = allsuggestions.get(0);
                                            StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion);
                                            for (int j = 1; j < onewordsuggestioncount; j++) {
                                                String onesuggestion = allsuggestions.get(j);
                                                suggestionbuilder.append(", ");
                                                suggestionbuilder.append(onesuggestion);
                                            }
                                            String onewordsuggestions = suggestionbuilder.toString();
                                            tfSuggestions1.setText(onewordsuggestions);
                                        } else {
                                            tfSuggestions1.setText("No suggestions");
                                        }
// increase i by 1
                                        wordnumber++;
} else {
                                        // No more wrong words! Disable next word button
                                        // Enable Check button
                                        btNextWrongWord.setEnabled(false);
                                        btCheck.setEnabled(true);
                                    }
                                }
                            };
// Register the ActionListener
                            btNextWrongWord.addActionListener(nextWord);
} else {
                            // The text has no mistakes
                            // Enable Check button
                            tfWrongWords.setText("No wrong words");
                            tfSuggestions1.setText("No suggestions");
                            tfWrongWord1.setText("--");
                            btCheck.setEnabled(true);

                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
// Clear the progress bar
                    pbProgress.setIndeterminate(false);
                    pbProgress.setString("");
                }
            });

        }
    };

    java.util.concurrent.Future result = port.checkTextBodyV2Async(bodyText, asyncHandler);
    while (!result.isDone()) {
        try {
//Display a message that the application is waiting for a response from the server
            tfWrongWords.setText("Waiting...");
            Thread.sleep(100);
        } catch (InterruptedException ex) {
            Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
----

[start=8]
. Pressione Ctrl-Shift-I (⌘-Shift-I no Mac) para corrigir importações. Isso adicionará as seguintes instruções de importação:

[source,java]
----

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
----

Agora, você pode construir e executar a aplicação! Infelizmente, você provavelmente não verá o que acontece quando há muita demora na resposta do servidor porque o serviço é bastante rápido.


== Praticando o que Você Aprendeu

Agora que você concluiu o seu primeiro cliente de Web service no IDE, é hora de aprimorar suas habilidades e melhorar a aplicação para tirar o melhor proveito dele. Veja a seguir duas tarefas sugeridas para começar.

* Adicione código de tratamento de erro ao servlet.
* Reescreva o cliente para que o usuário possa interagir com os dados retornados do Web service.


link:/about/contact_form.html?to=3&subject=Feedback:%20JAX-WS%20Clients%20in%20NetBeans%20IDE[+Enviar Feedback neste Tutorial+]



== Consulte Também

Para obter mais informações sobre o uso do NetBeans IDE para desenvolver aplicações Java EE, consulte os seguintes recursos:

* link:jax-ws.html[+Introdução aos Web Services JAX-WS+]
* link:rest.html[+Introdução ao RESTful Web Services+]
* link:wsit.html[+Interoperabilidade Avançada de Web Service+]
* link:../../trails/web.html[+Trilha do Aprendizado de Web services+]

Para enviar comentários e sugestões, obter suporte e se manter informado sobre os mais recentes desenvolvimentos das funcionalidades de desenvolvimento Java EE do NetBeans IDE, link:../../../community/lists/top.html[+inscreva-se na lista de correio nbj2ee@netbeans.org+].

