jcompany Service Capítulo Introdução aos RESTful Services via JAX-RS - Um breve histórico sobre REST - O padrão JAX-RS e o jcompany Service - PDF
Download "jcompany Service Capítulo Introdução aos RESTful Services via JAX-RS - Um breve histórico sobre REST - O padrão JAX-RS e o jcompany Service"
Raquel Laranjeira Valverde
1 A1RESTful com JAX-RS e jcompany Service Capítulo 23 Introdução aos RESTful Services via JAX-RS - Um breve histórico sobre REST Os RESTful Services, de certa maneira, foram a resposta dos programadores mais pragmáticos ao crescimento da indústria de WebServices em torno de complexidades questionáveis. O aumento da complexidade a partir da exigência de um envelope SOAP adicional ao HTTP, servidores UDDI para busca de serviço, contratos WSDL, padrões para segurança (WS-Security), dentre outros, levantaram uma questão fundamental: precisamos mesmo de tudo isso para acessar serviços programaticamente via Web? Não seria possível obter os mesmos benefícios, somente a partir do bom uso das práticas HTTP já disponíveis? A esta simplificação, alguns autores inclusive denominaram de arquitetura ROA (RESTful Oriented Architecture) em contraposição ao SOA, bastante associado tecnicamente aos "grandes Web-Services". E este questionamento recebeu bastante receptividade no mercado: uso do SSL simplesmente para criptografia de senhas; uso dos motores de busca (Google, Yahoo!, MSN) para buscar serviços REST em lugar do UDDI; uso mais diligente de métodos (POST, GET, PUT, etc.) e códigos de resposta do HTTP em lugar de extensões SOAP; dentre outros, se mostraram estratégias eficazes para a grande maioria das situações, ao ponto de hoje a maior parte dos sites que disponibilizam serviço fazê-lo nas duas modalidades: em "Web-Services" e "RESTful Services". - REST A Transferência de Estado Representacional (Representational State Transfer) ou somente (REST) são serviços sem estado (stateless) e arquiteturas que fazem uso da semântica e do conteúdo de uma URL ou URI, para identificar um determinado recurso da aplicação. Em sistemas REST, os recursos são manipulados através da troca de representações do recurso. Ex.: " Neste exemplo, através desta URL estamos definindo padrões que serão utilizados para mapear nossas ações e recursos a serem obtidos. É fácil entender como ela funciona: identificamos nossa chave primária (object-id) com o texto entre parênteses "(1)" ao final da URI e o nome da colaboração como "funcionariomdt". Poderíamos alterar a chamada para um serviço que retorne uma coleção de objetos definidos em "funcionariomdt" simplesmente com a omissão da chave primária. Mais adiante neste capítulo utilizaremos o jcompany Service para demonstrar todas as principais operações possíveis. A URI é uma maneira uniforme de identificar recursos e o HTTP é o meio utilizado para manipular estes recursos. Como as URIs são únicas, ganhamos uma busca otimizada que, de forma simples, nos permite recuperar diversas representações de dados (advindos de agregações de entidades ou JPA-QL sobre elas), em diversos formatos (XML, JSON, etc) parametrizáveis. Grande parte deste mecanismo é suportado pelo padrão Java EE 6 JAX-RS, utilizado pelo jcompany. - O padrão JAX-RS e o jcompany Service O jcompany Developer Suite implementa o padrão JAX-RS reutilizando sua implementação de referência, o jboss RESTEasy. Mas vai além desta especificação ao prover uma API simples para utilização de serviços REST integrados aos seus padrões de caso de uso, que proveem operações de CRUD de forma simples, mesmo para agregações complexas de entidades. Ou seja, além de simplesmente permitir a utilização de um serviço REST através da implementação de referência jboss RESTEasy, o jcompany generaliza diversos serviços ao ponto de dispensar programação do serviço em si para diversos casos em que informações de metadados já definidas em casos de uso padrões existentes são reutilizadas.
2 RESTful com JAX-RS e jcompany Service Para estas generalizações, as diferentes operações de CRUD são ativadas em conformidade com comandos do protocolo HTTP, conforme a Figura G23.1 abaixo: Figura G23.1. Métodos HTTP. Serviços adicionais específicos podem também ser criados de forma altamente produtiva e evoluída, através de recomendações de arquitetura pré-implementadas no jcompany Service. * - Configurando o suporte a REST com JAX-RS no jcompany Para começarmos a utilizar o padrão JAX-RS, devemos realizar algumas poucas configurações no arquivo "web.xml", muitas inclusive geradas automaticamente por constarem em templates INI do jcompany. O padrão é para prover a funcionalidade REST em resposta às URLs que tenham o trecho /soa/*. Estas configurações estão detalhadas na Figura G23.2 e na Figura G23.3. Figura G23.2. Conf igurações para o f uncionamento do REST. #1. Configuração necessária para que um Servlet específico nomeado como "Resteasy" intercepte URLs com token "/soa/" presente e as delega para serem atendidas por classes genéricas de controle do jcompany. Figura G23.3. Parâmetros para o f uncionamento de RESTServices no web.xml do projeto "rhtutorial". #1. Parâmetro que, ao assumir o valor "true", ativa a funcionalidade de busca automatizada por classes anotadas para atender a serviços RESTFul, estejam elas no projeto ou no jcompany em si (genéricas). #2. Parâmetro que permite a execução de rotinas de segurança na trâmite das informações. #3. Parâmetro que define o prefixo da url de acesso ao serviço RESTFul, por padrão será usado "/soa". * O Java pos sui uma JSR que define a A P I para c omunicação de aplicações Web através de RE ST Web Services. E ssa API é des crita n a JSR (JAX-RS p.org/en/js r/detail?id=3 11) e o jc ompany utiliza a implementação RE STEasy da jbos s ( s.org/resteasy) para implementá-la.
3 Capítulo 23 Por fim, para induzir o jcompany a empacotar os frameworks de base que implementam os serviços RESTFul, deve-se configurar o arquivo pom.xml do projeto incluindo a dependência do componente (artifactid) "jcompany_service". A Figura G23.4 mostra a dependência inserida no arquivo. Figura G23.4. Tags com as dependências do "jcompany_service" no arquivo "pom.xml" da aplicação. #1. Declaração de "dependency" do Maven, do projeto "rhtutorial" para o framework "jcompany_service", instalado no repositório Maven abaixo de "powerlogic.jcompany". Visão Geral do jcompany Service - Entendendo a demanda de negócio Vamos supor que nossa aplicação "rhtutorial" comece a ser demandada para possibilitar acesso por diversos dispositivos móveis que não necessariamente operam com Browser. E também para que outros sistemas agora possam realizar operações completas de "inclusão, alteração, exclusão e consulta" de funcionários (em uma arquitetura conhecida como B2B), tal como já fazemos em um Browser (arquitetura B2C). Uma alternativa seria expandir o nosso "WebService" do capítulo anterior para possibilitar não somente a consulta de algumas informações, mas também a inclusão, alteração e exclusão de todos os funcionários, seus endereços, históricos profissionais e dependentes. Mas isso seria bem mais trabalhoso que a abordagem que iremos utilizar via JAX-RS no jcompany Service. - Entendendo a arquitetura do jcompany Service Para executar as funções CRUD já citadas, necessitamos de uma classe de "Controle" e uma de "Conversor", respectivamente objetos que interceptam/controlam a execução dos métodos recebidos através do REST e formatam os dados para devolvê-los ao requerente (Browser ou Aplicação). Para identificar as classes de Controle e Conversor de uma aplicação, O jcompany Service faz uso do padrão CDI *, tornando a criação dos mesmos mais fácil e padronizada - sem necessitar de nenhuma configuração de XML e fazendo uso de técnicas de "Convenção sobre a Configuração". - Entendendo a implementação de Controle no jcompany Service Consegue-se uma implementação de Controle apenas estendendo a classe base "PlcBaseControle.java" e/ou implementando diretamente a interface "IPlcController.java". A Figura G23.5 mostra a interface "IPlcController.java". Figura G23.5. Interf ace "IPlcController.java". * C ontexts and Dependency I njection, JSR-299.
4 RESTful com JAX-RS e jcompany Service #1. HTTP GET - utiliza-se /soa/service/[controle](identificador) - dispara o método "public void recupera (I identificadorentidade);" e é utilizado para recuperar uma informação de acordo com a URI e o identificador. #2. HTTP POST - utiliza-se /soa/service/[controle] - invoca o método "public void inclui();" e é utilizado para adicionar uma informação. #3. HTTP PUT - utiliza-se /soa/service/[controle](identificador) - invoca o método "public void put();" e é utilizado para alterar uma informação. #4. HTTP DELETE - utiliza-se /soa/service/[controle](identificador) - invoca o método "public void exclui();" e é utilizado para remover logicamente uma entidade. #5. HTTP GET - utiliza-se /soa/service/[controle] - dispara o método "public void recuperacolecao();" e é utilizado para recuperar a coleção de acordo com a URI. A classe de implementação deve possuir a que a qualifica para o CDI como um controlador de serviços REST. Outra anotação associa este controle com a URL que ele atenderá. Ela é informada através da que pode ser vista na Figura G23.6: Figura G23.6. Exemplo da anotação Se nenhum nome for informado, o nome do controle passa a ser o mesmo da classe, sem o prefixo Controle conforme pode ser vista na Figura G23.7: Figura G23.7. Exemplo de classe sem a anotação Para dar mais flexibilidade e possibilitar agrupar controles em um mesmo grupo, existe ainda uma que possibilita a adição de um qualificador ou extensão à URI. Este qualificador pode ser genérico ou específico. A Figura G23.8 mostra a anotação na classe "FuncionarioGridController.java".
5 Capítulo 23 Figura G23.8. Exemplo de classe com a anotação ier ". É possível definir um qualificador genérico para todas as requisições, informando uma classe que atenda a todas as requisições, apenas adicionando um qualificador com caractere coringa * conforme mostra a Figura G23.9. Figura G23.9. Exemplo de classe com qualif icador genérico "*".
6 RESTful com JAX-RS e jcompany Service - Entendendo o Conversor de dados no jcompany Service Após a execução da classe de Controle, o resultado deve ser enviado para a requisição em um formato específico, e este formato é determinado pela própria requisição. O protocolo HTTP define um cabeçalho ACCEPT, para informar qual o retorno esperado da requisição, o que permite que um mesmo controle retorne o resultado em formatos distintos, XML, JSON, ou outro qualquer esperado pelo usuário. A implementação de um conversor pode ser feita através de uma classe simples que estende a classe de base "PlcBaseConversor.java" e/ou que implementa diretamente a interface "IPlcConversor.java". Tal como no caso da classe de Controle, esta classe também deve possuir a que determina o estereótipo de Conversor, de modo que o jcompany possa identificar e disponibilizar essas classes para agir junto às de controle para finalizar a requisição. A Figura G23.10 mostra a interface "IPlcConversor.java". Figura G Interf ace "IPlcConversor.java". Para especificar o formato de dados que o conversor consome e produz na requisição, deve-se definir na classe a Se não for definida nenhuma anotação, o jcompany assumirá o valor padrão */*, que torna o Conversor em questão genérico para toda requisição com formato não especificado. A Figura G23.11 mostra esta anotação, especificando o consumo de dados genéricos. Figura G Exemplo de especif icação de dados consumidos pelo conversor genéricos (*/*). Como funciona a localização de um conversor para atender a uma requisição REST? Para a identificação de um conversor, o jcompany inspeciona a hierarquia de herança do conversor em busca de uma declaração de Generics que determine a quais tipos de Controle o Conversor se aplica. A classe da Figura
7 Capítulo 23 G23.12, por exemplo, mostra um Conversor que responde a requisições para o controlador GridControle, onde para qualquer tipo de retorno */* será gerado um JSON de resposta. A Figura G23.12 mostra a anotação especificando o consumo de dados JSON. Figura G Exemplo de especif icação de dados com retorno em JSON. Serviço CRUD/REST genérico com jcompany Service - Entendendo as classes de controle genéricas do jcompany Service O jcompany já disponibiliza classes de Controle genéricas que implementam um serviço REST com todas as operações de CRUD já prontas para uso. Esta classe é parcialmente ilustrada na Figura G23.13, e utiliza conversores que utilizam o formato XML Atom para a transferência de dados. Figura G Implementação de controle genérica disponível para uso no jcompany Service. - Entendendo o protocolo Atom Publishing O protocolo Atom e sua extensão conhecida como Atom Publishing definem um formato bastante popular na Web, utilizado por grandes provedores como Google e Amazon para trabalhar com dados complexos. Ele é assim definido por seus criadores: "O Atom Publishing Protocol é um protocolo de nível de aplicativo para publicar e editar recursos da Web usando HTTP [RFC2616] e XML 1.0 [W3C.REC-xml ]. O protocolo suporta a criação de quaisquer recursos web oferecendo facilidades especialmente refinadas para: * Coleções: conjuntos de recursos que podem ser recuperados no todo ou em parte. * Introspecção: Descobrir e descrever coleções. * Edição: criar, atualizar e excluir recursos."
8 RESTful com JAX-RS e jcompany Service O jcompany também utiliza este formato para trafegar com informações obtidas de Agregações de Entidades, que podem inclusive possuir organizações Mestre-Detalhe como as que vimos neste livro, para Funcionários, Dependentes e Histórico Funcional. No jcompany, os dados das entidades em si são fornecidos como um entry do Atom/Publishing e os demais campos padrões são utilizados conforme requerido pelo protocolo, que não difere de outras Markup Languages tradicionais, contendo cabeçalhos, títulos e corpo. - Configurando o acesso via RESTClient Agora que o projeto rhtutorial está configurado para aceitar RESTful Services, já podemos experimentar a disponibilidade de nossos serviços REST genéricos. Vamos acessar a agregação definida no caso de uso "Manter Funcionário" que construímos em capítulos anteriores. Para tanto, basta dispararmos uma URL com o seguinte padrão: ' do projeto]/soa/service/[nome do caso de uso]'. Para melhorar nosso entendimento das mensagens REST enviadas - principalmente do formato dos dados enviados e recebidos - precisaremos utilizar alguma ferramenta de "cliente" que nos permita realizar simulações de acesso dinamicamente, em mais baixo nível que no Browser. Este tipo de ferramenta conhecido como RESTClient exibe a anatomia completa de mensagens do protocolo Atom, possibilitando ainda fazermos a edição manual de novas mensagens e submissões de PUT, DELETE ou POST que realizam alterações na camada modelo. Note que não conseguiríamos fazer testes no Browser destas operações, sem termos que programar um aplicativo. Portanto usaremos um RESTClient que é um complemento do Firefox, ferramenta que tem alguns destaques com relação a outras disponíveis *. Para obter acesso a esta ferramenta entre na página de complementos do Mozilla e a instale ( A Figura G23.14 nos mostra a ferramenta RESTClient, bem como uma noção de sua usabilidade. Figura G Console do RESTClient #1. O método "HTTP" que será usado. #2. URL de acesso ao serviço. #3. Cabeçalho da requisição. * P ara us uários que não utilizam o brows er Firefox é rec omendado o us o da ferramenta RE STclient desktop que é enc ontrada na ins talação do jc ompany. E s ta ferramenta pode obtida em: "[diretorio_base]\ferramentas \res tc lient\restclient.bat"
9 Capítulo 23 #4. Área de input de XML de acordo com o método estabelecido. #5. Área que mostra ao desenvolvedor os dados do serviço estabelecido. #6. Área que retorna o XML requisitado. #7. Área que retorna o XML requisitado, usando a tecnologia Syntax Highlight. Essa tecnologia mostra códigos fontes em cores e fontes diferentes, sendo organizada de acordo com a categoria de cada termo. - Testando os RESTful Services genéricos para CRUD - seleção e edição de funcionários Agora vamos testar o uso de RESTful Services para o caso de uso "Funcionario", utilizando as quatro operações básicas de aplicações Data-Centric (CRUD), com seus comandos HTTP correspondentes: operações de recuperação ou pesquisa/edição (HTTP GET), alteração (HTTP PUT), inclusão (HTTP POST) e exclusão (HTTP DELETE). Vamos começar obtendo uma lista de entidades "Funcionario" do projeto rhtutorial, em XML Atom/Publishing. Para obter uma primeira relação padrão destas entidades, o principal segredo é montar corretamente a URL, no padrão REST e com o identificador da colaboração "funcionariomdt". Esta única informação ao final é suficiente para possibilitar ao jcompany obter as demais informações dos metadados (anotações) deste Caso de Uso Padrão e conceber todo o resto. A URL para a aplicação "rhtutorial" rodando localmente fica assim: ' Após montada devemos digitá-la no RESTClient escolhendo o método GET e submetendo para o servidor. No caso do RESTClient do Firefox, clique no botão "Send". A Figura G23.15 mostra a lista de entidades "Funcionario" em formato XML Atom/Publishing, retornada da submissão. Figura G Retorno das entidades em XML Atom/Publishing através de um método HTTP GET. Obs.: O XML resultante não vem formatado nesta ferramenta de RESTClient. É aconselhável que o desenvolvedor iniciante em Atom/Publishing o edite no Eclipse e utilize "Ctrl+I" para endentar o arquivo e melhor compreendê-lo. Note que, como trabalhamos com reuso de configurações de metadados para caso de uso padrão ("Funcionario"), não tivemos que desenvolver mais nenhuma classe, seja de controle, modelo, persistência (DAO) ou entidades, para obter um resultado de pesquisa REST! Isso porque o jcompany Service é inteligente o suficiente para reutilizar estas configurações e classes para produzir um resultado inicial válido. Caso acessemos o console do Eclipse poderemos notar que o serviço estabelecido acima utiliza a namedquery "querysel" do JPA e/ou Hibernate para estabelecer a recuperação dos dados, sem passar
10 RESTful com JAX-RS e jcompany Service nenhum argumento (pois nenhum foi informado na URL). A Figura G23.16 mostra o SQL resultante da requisição acima. Figura G Query obtida através do método GET. Importante: Note que o jcompany Service reconhece padrões fortes do jcompany como o de "exclusão lógica" implementado pela propriedade "sithistoricoplc". Portanto, o HQL somente traz "funcionários ativos", desprezando os excluídos logicamente (como desejável na maior parte dos casos). Agora que já temos uma relação, vamos recuperar uma entidade específica Fulano de Tal, que aparece em nossa listagem anterior (simulando uma "seleção para edição" de uma ficha de funcionário). Para tanto siga os mesmos passos descritos para o comando anterior, somente acrescentando ao final da URL o Object-Id (valor numérico do "id") da entidade, entre parênteses. A Figura G23.17 mostra o retorno em XML Atom/Publishing, de todos os dados entidade especificamente informada. Figura G Retorno de uma entidade especif ica de "Funcionario". O serviço estabelecido acima utilizou a namedquery "queryman" do JPA/Hibernate. Esta Query, além de recuperar os dados do funcionário em si, recupera todos os demais de sua agregação, como os dados dos componentes (Endereco) e de composições (detalhes) que não estejam marcados como "por demanda" na configuração do caso de uso. A Figura G23.18 mostra parte do SQL produzido pela requisição acima.
11 Capítulo 23 Figura G SQL produzido pela edição de uma instância especif ica da entidade "Funcionario". - Testando os RESTful Services genéricos para CRUD - inclusão de funcionários Até agora trabalhamos com consultas. O próximo grande passo será a utilização do RESTful Services para incluir um novo registro de "Funcionario" com o nome Adolfo. Para tal monte no campo Request Body do RestClient o XML Atom/Publishing contendo os dados da entidade. O XML retornado na edição ajuda nesta operação. Copie um funcionário aleatório e somen te troque seu nome e retire o "id". Abaixo um exemplo do XML no formato Atom, utilizado pelo jcompany_service, na manutenção. O formato do XML segue o padrão Atom, onde o conteúdo do "Entry" é formado pelos dados da entidade. Ele pode ser visto no trecho de Código G23.1: <?xml vers ion="1.0" encoding="utf-8" s tandalone="yes"?> <entry xmlns =" 0 05/Atom"xmlns:plcAtom=" <c ontent type="application/xml"> <c om.empres a.rhtutorial.entidade.funcionario.funcionarioentity xmlns:ns3=" /Atom"> <vers ao>1 </versao>... <unidadeo rganizacional> <id>8 </id> </unidadeo rganizacional>... </c om.empres a.rhtutorial.entidade.funcionario.funcionarioentity> </c ontent> </entry> Código G23.1. Formato do XML Atom para envio de dados. Com o XML corretamente montado, selecione o método POST e clique em Send para disparar a requisição de inclusão. A Figura G23.19 mostra o resultado retornado de uma inclusão feita com sucesso.
12 RESTful com JAX-RS e jcompany Service Figura G Inclusão com sucesso de um registro de "Funcionario". Agora vamos acessar o console do Eclipse novamente para verificar o SQL de atualização. Os comandos SQL gerados pelo JPA/Hibernate realizam a verificação de dependências (integridade referencial) e do negócio (integridade de identidade, definida em namedqueries "naodeveexistir) e, por fim, a inclusão de dados da agregação de funcionário. Conforme o SGBD-R em uso podem também surgir comandos SQL voltados para a obtenção automática do Object-Id (chave primária definida na propriedade "id"). Tudo isso é ilustrado na Figura G Figura G SQL produzidos para inclusão de um "Funcionario". - Testando os RESTful Services genéricos para CRUD - alteração de funcionários Prosseguindo com nossas operações CRUD, iremos agora atualizar o registro inserido acima. Defina no campo "Request Body" o XML Atom/Publishing contendo os dados para atualização, de forma análoga caso de inclusão, porém agora com o cuidado de utilizar o Object-Id (tag "<id>") e também a última versão da entidade (tag "<versao>"), já que o jcompany utiliza o controle de "concorrência otimista" utilizando este atributo, conforme recomendado pelo JPA/Hibernate. A Figura G23.21 mostra o retorno de uma atualização bem sucedida:
13 Capítulo 23 Figura G Resultado da atualização bem-sucedida de um "Funcionario". O comando SQL gerado para atualização de funcionário pode ser vista na Figura G Obs.: Note que, tal como em todos os demais casos, os comandos utilizam "Prepared Statements" devidamente, evitando misturar argumentos (representados por "?") com comandos SQL. Além disso, todas as atualizações e exclusões são também acompanhadas de um teste de versão, para garantir que o registro não tenha sido alterado por outra pessoa, entre o momento que foi recuperado e o que está sendo atualizado. Estas são algumas das boas práticas de JPA/Hibernate, genericamente estimuladas pelo jcompany. Figura G SQL de atualização de "Funcionario", com teste de identif icação e versão (concorrência). - Testando os RESTful Services genéricos para CRUD - exclusão de funcionários O processo de exclusão de entidades é semelhante ao de alteração, porém utilizando o comando DELETE do HTTP. Após montar no Request Body do RESTClient o XML Atom/Publishing contendo Object-Id e versão da entidade na URL, selecione o método DELETE e clique em Send para enviar a requisição de exclusão. A Figura G23.23 mostra um exemplo de Delete.
14 RESTful com JAX-RS e jcompany Service Figura G Remoção de um "Funcionario" via jcompany Service. A console do Tomcat no Eclipse vai nos mostrar agora os SQLs utilizados para exclusão, que englobam também os SQLs de verificação (de toda a agregação). A Figura G23.24 mostra o console. Figura G Query de remoção de um "Funcionario". Importante: note que, muito embora os metadados do caso de uso padrão Funcionário definam o uso de "exclusão lógica" (ou seja, alterar sithistoricoplc para "A", em lugar de excluir fisicamente cada registro), nossa operação REST realizou uma exclusão física. Este comportamento dá mais controle à aplicação de cliente (que neste caso é agnóstica), para que realize exclusões lógicas (com comandos de alteração) e físicas se for preciso.
15 Capítulo 23 Padrões de Programação do jcompany Service - Programações de negócio em serviço REST. Em aplicações reais, apenas as operações de cadastro básico não seriam suficientes para se disponibilizar serviços úteis para os usuários. Felizmente, as regras de negócio programadas nas camadas de modelo para a agregação de funcionário, normalmente codificadas em "FuncionarioRepository" e/ou 'FuncionarioEntity", bem como serviços de DAO complementares em "FuncionarioDAO", serão todas executadas normalmente, tal como ocorrem nas manutenções Web padrões. Alguma variação de comportamento das regras de negócio, portanto, que deva atender somente a serviços REST, deve receber informações adicionais a partir da interceptação da camada de controle, esta sim diferente para cada caso. - Programações de controle e validação variante em serviço REST. A camada controle para serviços REST, como vimos, é inteiramente distinta da camada controle "convencional" do jcompany, baseada em classes de MB e padrão JSF. Não há acoplamento de tecnologia JSF nos controles JAX-RS, o que exatamente lhes tornam flexíveis para funcionar com qualquer cliente desejado. Felizmente, como vimos na introdução (e tal como ocorre no restante do jcompany FS Framework), a arquitetura concebida para o Controle REST permite o reuso total de generalizações mas também permite sua especialização "por exceção", com total flexibilidade para o desenvolvedor. Neste tópico, vamos realizar uma validação variante fictícia apenas para testar o mecanismo de tratamento de exceções via JAX-RS e Atom Publishing. Vamos também incluir algumas mensagens de logging em pontos chave de extensão, para ilustrar outras formas de especializações típicas. Importante: As validações invariantes (definidas nas Entidades, em nível de domínio) são disparadas genericamente pelo jcompany na camada modelo, independentemente da origem da requisição (se for "Web convencional" ou "REST") - e serão melhor discutidas mais abaixo. Nesta seção, vamos ilustrar uma validação "variante", supondo que seja necessária somente nas requisições REST, em um exemplo um tanto forçado mas útil para nosso propósito: "Não é permitido incluir funcionário com curso superior em operações B2B". Para estas validações ou quaisquer outras variações de comportamento específicas para requisições REST, devemos criar uma classe de Controle específica. Em nosso caso, ela deve ser chamada "FuncionarioController" (pode ter qualquer nome, mas as convenções facilitam a manutenção). Conforme explicamos no início do capítulo, deve ainda estender a classe "PlcBaseController" se for preciso implementar apenas códigos complementares. Codifique a regra acima nesta classe, conforme ilustra a Figura G Figura G Classe de controle que implementa a validação descrita acima. As estruturas principais desta classe já foram explicadas no início deste capítulo. Outro ponto de novidade é a obtenção da agregação a partir de sua entidade Raiz, via "getentity()" - Verificando exceções do jcompany Service no RESTClient Sejam exceções disparadas por validações invariantes, sejam programadas como na seção anterior, requisições com método "PUT" ou "POST" no RESTClient serão retornadas de modo homogêneo.
16 RESTful com JAX-RS e jcompany Service Teste o retorno provocando a exceção acima, com a inserção de valores de CPF ou inválidos (invariantes definidas por anotação na entidade Funcionario) ou mesmo burlando uma integridade de dados anotada com namedquery "naodeveexistircpfduplicado". Em quaisquer dos casos, a exceção será retornada de modo similar como apresentado na Figura G23.26, para uma validação de CPF duplicado. Figura G Exceção controlada, provocada por validação a partir de método "POST". Com este padrão homogêneo, uma aplicação de cliente genérica (Swing, Flex,.NET, Mobile, etc.) tem como receber e tratar exceções como desejar, enviando uma mensagem para o usuário ou realizando algum outro procedimento desejado. - Utilizando formato JSON e outros pontos de especialização do jcompany Service Vimos que o jcompany Service preserva as funcionalidades de negócio e validações invariantes e permite programação de regras de validação invariantes. Porém, outras regras de controle são possíveis para cenários diversos. Vamos exemplificá-las simulando a implementação de um serviço REST para funcionamento com um componente de "Grid". Este componente é disponibilizado em Javascript e funciona no padrão RIA, comunicando via REST com o servidor. Ele pode enviar argumentos para filtrar a recuperação da lista de entidades a serem exibidos na tabela do Grid, o que pode exigir outras lógicas de programação complementares de nossa parte, em casos mais complexos. Além disso, este componente envia e recebe dados em formato JSON, e não mais em XML Atom/Publishing, o que exigirá também algumas outras configurações de nossa parte. Para este exemplo, reutilizaremos a mesma classe de controle "FuncionarioController", mas seria possível fazê-lo em outra classe à parte, bastando que anotássemos o qualificador apropriadamente. Implemente os demais códigos conforme a Figura G23.27.
17 Capítulo 23 Figura G Classe "FuncionarioController.java" #1. Anotação de estereótipo informando que a classe é um controle. #2. Anotação de qualificador informando que no nome do controle é "funcionariomdt". #3. A classe criada deve estender "PlcBaseDynamicController". #4. Note que foi utilizado um ponto de especialização padrão que contém a validação de "Não é possível incluir funcionário com curso superior". Com esta demanda implantada já temos um serviços REST servindo JSON, formato que atende aos componentes de Grid' típicos encontrados no mercado, conforme vemos na Figura G23.28: Figura G Retorno de serviço REST em f ormato JSON. #1. Nome do controle é "funcionariomdt" que corresponde à manutenção de funcionário. #2. Tipo do conversor de dados utilizado pelo controle. #3. A requisição retorna todos os dados das entidades em JSON, formato tipicamente utilizados por componentes de Grid como o "jqgrid" homologado no jcompany. A geração da coleção de entidades no formato JSON para ser consumido pelo componente "Grid", pode ser feita apenas criando um conversor que herda da classe do JCompany que já da suporte a este tipo de geração. A Figura G23.29 mostra a classe "FuncionarioGridConversor" citada acima:
18 RESTful com JAX-RS e jcompany Service Figura G Retorno de serviço REST em f ormato JSON. Aplicações Cliente para Consumo de Serviços REST - Portando o Web-Services do capítulo anterior para REST Agora que já vimos como é altamente produtivo disponibilizar serviços completos de CRUDS (incluindo Search) no jcompany Service para grafos de entidades padrões, vejamos qual é o esforço para consumirmos estes serviços. Para melhorar nosso entendimento de RESTful Services em comparação com Web Services SOAP, vamos reimplementar exatamente o mesmo serviço do capítulo anterior, para que possa ser servido alternativamente via REST (aliás, prover acesso via ambos os padrões é uma prática muito comum nos provedores atuais). - Testando o novo serviço Note que já inserimos, no exemplo anterior, dois métodos na classe "FuncionarioController" para validar e permitir o uso do campo "CPF" como parâmetro de pesquisa, antecipando a nossa demanda para este tópico. Portanto, para simular a pesquisa basta digitar o CPF na URL, utilizando o RESTClient. A Figura G23.30 mostra a URL e o retorno da pesquisa em formato JSON. Figura G Retorno das entidades através do uso do parâmetro "CPF". #1. URL de requisição "normal". #2. Foi adicionado o parâmetro "?cpf= " para fazer a requisição conforme planejado em nosso serviço.
19 Capítulo 23 #3. A requisição do serviço prestado é retornada em JSON. - Criando a aplicação de consumo Com o serviço devidamente testado, vamos agora à criação em si da aplicação de consumo deste serviço. Note que nada impede que a aplicação cliente seja outra aplicação Java EE, consumindo o serviço em uma anatomia "server-to-server" ou "business-to-business" (B2B). Mas uma das vantagens dos RESTFul Services é a facilidade para se consumir estes serviços diretamente de "clientes finais ou Browsers", via rotinas Javascript bastante simples, como será nosso exemplo. 1. Crie um item de chamada de menu no arquivo "geralmenu.xhtml" e o arquivo XHTML para conter o formulário, com nome "buscafuncionario.xhtml". Obs.: Estes arquivos seguem as práticas semelhantes às que usamos no caso de uso "funcionário" e que, portanto não serão detalhadas nesta documentação. A Figura G23.31 mostra o arquivo "geralmenu.xhtml" enquanto a Figura G23.32 mostra o código do formulário e suas chamadas Javascript/Ajax, no arquivo "buscafuncionario.xhtml". Figura G Arquivo "geralmenu.xht ml" com as conf igurações de "Busca Funcionário". Figura G Arquivo "buscafuncionario.xhtml". #1. Criação do botão que aciona a busca através do serviço REST. #2. Elemento HTML utilizado para mostrar a resposta do serviço REST. #3. Criação da função JavaScript "buscarcpf". Essa função é disparada ao clicar no botão com o ID "Buscar CPF" #4. Recuperando o valor do campo "CPF" informando o atribuindo a uma variável local. #5. Verificação simples de uma validação de "CPF". #6. Trecho de código responsável por mostrar os dados do "Funcionario" retornado pela chamada Ajax ao serviço REST. #7. Trecho que limpa as mensagens da tela. #8. Caso não tenha encontrado resultado, mostra a seguinte mensagem: "CPF não encontrado".
20 RESTful com JAX-RS e jcompany Service #9. Especifica que a função que trata o retorno do Ajax espera um resultado no formato JSON. 2. Faça uma liberação, entre na aplicação e acesse via menu o caso de uso. A Figura G23.33 mostra o resultado obtido enquanto a Figura G23.34 e a Figura G23.35 mostram o resultado das validações criadas. Figura G Uso do RESTf ul para retornar um "Funcionario". Figura G Validação de "CPF não encontrado". Figura G Validação de "CPF inválido", disparada quando o campo "CPF" est á vazio.
21 Capítulo 23 Sumário Neste capítulo discutimos os RESTful Services e o padrão JAX-RS, alternativas aos Web-Services SOAP e ao padrão JAX-WS para programação de demandas por prover serviços distribuídos na Web. Conhecemos a arquitetura do jcompany Service e suas generalizações que nos possibilitam disponibilizar serviços REST completos para todas as transações de CRUD e Search (CRUDS), mesmo quando envolvendo estruturas de agregações com composições (tipo Mestre-Detalhe) em quantos níveis existirem. Disponibilizarmos serviços de CRUD e Search para funcionários mostrando regras de validação ativas, portando o Web-Service SOAP do capítulo anterior para um serviço padrão REST. Com isso, constatamos como é simples disponibilizar os serviços do jcompany para outras aplicações (B2B), interfaces proprietárias de dispositivos móveis (com acesso a Web), como ObjectiveC para iphone/ipad - ou mesmo a partir de tecnologias como Flex ou Java-FX, dentre outros.