4. O Serviço Web J2EE para Agendamentos
Voltemos à arquitetura da aplicação a ser desenvolvida:
![]() |
Nesta secção, vamos concentrar-nos na criação do serviço web J2EE [1] a ser executado num servidor Sun/Glassfish.
4.1. A base de dados
A base de dados, a que chamaremos [ dbrdvmedecins], é uma base de dados MySQL5 com quatro tabelas:

4.1.1. A tabela [MEDECINS]
Contém informações sobre os médicos geridos pela aplicação [RdvMedecins].
![]() | ![]() |
- ID: o número de identificação do médico — a chave primária da tabela
- VERSÃO: um número que identifica a versão da linha na tabela. Este número é incrementado em 1 sempre que é feita uma alteração na linha.
- LAST_NAME: o apelido do médico
- FIRST_NAME: o nome próprio do médico
- TITLE: o seu título (Sra., Sra., Sr.)
4.1.2. A tabela [CLIENTS]
Os clientes dos vários médicos estão armazenados na tabela [CLIENTS]:
![]() | ![]() |
- ID: número de identificação do cliente - chave primária da tabela
- VERSION: número que identifica a versão da linha na tabela. Este número é incrementado em 1 cada vez que é feita uma alteração na linha.
- APELIDO: o apelido do cliente
- NOME: o nome do cliente
- TÍTULO: o seu título (Sra., Sra., Sr.)
4.1.3. A tabela [SLOTS]
Apresenta os horários disponíveis para marcação de consultas:
![]() |
![]() |
- ID: Número de identificação do intervalo de tempo - chave primária da tabela (linha 8)
- VERSION: Um número que identifica a versão da linha na tabela. Este número é incrementado em 1 cada vez que é feita uma alteração na linha.
- DOC_ID: Número de identificação que identifica o médico a quem este intervalo de tempo pertence – chave estrangeira na coluna DOCTORS(ID).
- START_TIME: Hora de início do intervalo de tempo
- MSTART: Minutos de início do intervalo de tempo
- HFIN: hora de fim do intervalo
- MFIN: Minutos de fim do intervalo
A segunda linha da tabela [SLOTS] (ver [1] acima) indica, por exemplo, que o intervalo n.º 2 começa às 8h20 e termina às 8h40 e pertence à médica n.º 1 (Sra. Marie PELISSIER).
4.1.4. A tabela [RV]
Apresenta a lista de consultas marcadas para cada médico:
![]() |
- ID: identificador único da consulta – chave primária
- DAY: dia da consulta
- SLOT_ID: intervalo horário da consulta – chave estrangeira no campo [ID] da tabela [SLOTS] – determina tanto o intervalo horário como o médico envolvido.
- CLIENT_ID: ID do cliente para quem a reserva é feita – chave estrangeira no campo [ID] da tabela [CLIENTS]
Esta tabela tem uma restrição de unicidade nos valores das colunas associadas (DAY, SLOT_ID):
Se uma linha na tabela [RV] tiver o valor (DAY1, SLOT_ID1) para as colunas (DAY, SLOT_ID), este valor não pode aparecer em mais nenhum outro local. Caso contrário, isso significaria que foram marcadas duas consultas ao mesmo tempo para o mesmo médico. Do ponto de vista da programação Java, o controlador JDBC da base de dados lança uma SQLException quando isto ocorre.
A linha com ID igual a 3 (ver [1] acima) significa que foi marcada uma consulta para o horário n.º 20 e o cliente n.º 4 em 23/08/2006. A tabela [SLOTS] indica-nos que o horário n.º 20 corresponde ao intervalo horário das 16h20 às 16h40 e pertence à médica n.º 1 (Sra. Marie PELISSIER). A tabela [CLIENTS] indica-nos que o cliente n.º 4 é a Sra. Brigitte BISTROU.
4.2. Criação da base de dados
Crie a base de dados MySQL [dbrdvmedecins] utilizando a ferramenta da sua escolha. Para criar as tabelas e preenchê-las, pode utilizar o script [createbd.sql] fornecido. O seu conteúdo é o seguinte:
4.3. Componentes da arquitetura do lado do servidor
Voltemos à arquitetura da aplicação a ser construída:
![]() |
No lado do servidor, a aplicação será composta por:
- uma camada JPA que permite a interação com a base de dados utilizando objetos
- um EJB responsável por gerir as operações com a camada JPA
- um serviço web responsável por expor a interface EJB a clientes remotos sob a forma de um serviço web.
Os elementos (b) e (c) implementam a camada [DAO] apresentada no diagrama anterior. Sabemos que uma aplicação pode aceder a um EJB remoto através dos protocolos RMI e JNDI. Na prática, isto limita os clientes a clientes Java. Um serviço web utiliza um protocolo de comunicação padronizado que várias linguagens implementam: .NET, PHP, C++, ... É isto que pretendemos demonstrar aqui utilizando um cliente .NET.
Para uma breve introdução aos serviços web, consulte o curso [ref1], parágrafo 14, página 109.
Um serviço web pode ser implementado de duas formas:
- por uma classe anotada com @WebService que é executada num contentor web
![]() |
- por um EJB anotado com @WebService que é executado num contentor EJB
![]() |
![]() |
Vamos utilizar a primeira solução aqui:
No curso [ref1], parágrafo 14, página 109, encontrará um exemplo que utiliza a segunda solução.
4.4. , e a configuração do Hibernate para o servidor GlassFish
Dependendo da versão, o servidor GlassFish V2 incluído no NetBeans pode não ter as bibliotecas Hibernate necessárias para a camada JPA/Hibernate. Se, ao prosseguir com o tutorial, verificar que o GlassFish não fornece uma implementação JPA/Hibernate, ou se ocorrer uma exceção durante a implementação do serviço indicando que as bibliotecas Hibernate não foram encontradas, deve adicionar as bibliotecas à pasta [<glassfish>/domains/domain1/lib/ext] e, em seguida, reiniciar o servidor GlassFish:
![]() |
|
As bibliotecas Hibernate estão incluídas no ficheiro ZIP que acompanha o tutorial.
4.5. Ferramentas de geração automática do NetBeans
Voltemos à arquitetura que precisamos de construir:
![]() |
Com o NetBeans, é possível gerar automaticamente a camada [JPA] e a camada [EJB] que controla o acesso às entidades JPA geradas. É útil familiarizar-se com estes métodos de geração automática, pois o código gerado fornece informações valiosas sobre como escrever entidades JPA ou o código EJB que as utiliza.
Vamos agora descrever algumas destas ferramentas de geração automática. Para compreender o código gerado, é necessário ter um conhecimento sólido das entidades JPA [ref1] e dos EJBs [ref2].
Criar uma ligação do NetBeans à base de dados
- Inicie o SGBD MySQL 5 para que a base de dados fique disponível
- Crie uma ligação do NetBeans à base de dados [dbrdvmedecins]
![]() |
- No separador [Ficheiros], na secção [Bases de dados] [1], selecione o controlador JDBC do MySQL [2]
- Em seguida, selecione a opção [3] «Ligar utilizando» para criar uma ligação a uma base de dados MySQL
- Em [4], introduza as informações solicitadas
- e, em seguida, confirme em [5]
![]() |
- Em [6], a ligação é criada. Pode ver as quatro tabelas na base de dados ligada.
![]() |
- Em [1], crie uma nova aplicação, um módulo EJB
- Em [2], selecione a categoria [Java EE] e, em [3], selecione o tipo [Módulo EJB]
![]() |
- Em [4], escolha uma pasta para o projeto e, em [5], atribua-lhe um nome — depois conclua o assistente
- Em [6], o projeto gerado
Adicionar um recurso JDBC ao servidor GlassFish
Vamos adicionar um recurso JDBC ao servidor GlassFish.
![]() |
![]() |
- No separador [Serviços], inicie o servidor GlassFish [2, 3]
- No separador [Projectos], clique com o botão direito do rato no projecto EJB e, em [5], selecione a opção [Novo / Outro] para adicionar um elemento ao projecto.

- Em [6], selecione a categoria [GlassFish] e, em [7], especifique que pretende criar um recurso JDBC selecionando o tipo [Recurso JDBC]
- Em [8], especifique que este recurso JDBC utilizará o seu próprio conjunto de ligações
- Em [9], atribua um nome ao recurso JDBC
- Em [10], avance para o passo seguinte
![]() |
- Em [11], defina as características do conjunto de ligações do recurso JDBC
- Em [12], atribua um nome ao conjunto de conexões
- Em [13], selecione a ligação do NetBeans [dbrdvmedecins] criada anteriormente
- em [14], avance para o passo seguinte
- Em [15], normalmente não há nada a alterar nesta página. As propriedades da ligação à base de dados MySQL [dbrdvmedecins] foram obtidas a partir das propriedades da ligação do NetBeans [dbrdvmedecins] criada anteriormente
- Em [16], avance para o passo seguinte
![]() |
- em [17], mantenha os valores predefinidos fornecidos
- em [18] e conclua o assistente. Isto cria o ficheiro [sun-resources.xml] [19] com o seguinte conteúdo:
O ficheiro acima contém todas as informações introduzidas no assistente em formato XML. Será utilizado pelo IDE NetBeans para instruir o servidor GlassFish a criar o recurso «jdbc/dbrdvmedecins» definido na linha 4.
Criação de uma unidade de persistência
A unidade de persistência [persistence.xml] configura a camada JPA: especifica a implementação JPA utilizada (TopLink, Hibernate, etc.) e configura-a.
![]() |
![]() |
- Em [1], clique com o botão direito do rato no projeto EJB e selecione [Novo / Outro] em [2]
- Em [3], selecione a categoria [Persistência] e, em seguida, em [4], indique que pretende criar uma unidade de persistência JPA
![]() |
- Em [5], atribua um nome à unidade de persistência criada
- Em [6], escolha [Hibernate] como implementação JPA
- Em [7], selecione o recurso GlassFish «jdbc/dbrdvmedecins» que acabou de ser criado
- em [8], especifique que nenhuma ação deve ser realizada na base de dados ao instanciar a camada JPA
- Conclua o assistente
- Em [9], o ficheiro [persistence.xml] criado pelo assistente
O seu conteúdo é o seguinte:
Mais uma vez, converte as informações fornecidas no assistente para o formato XML. Este ficheiro não é suficiente para trabalhar com a base de dados MySQL5 «dbrdvmedecins». Teríamos de especificar o tipo de SGBD a ser gerido pelo Hibernate. Isto será feito mais tarde.
![]() |
![]() |
![]() |
- Em [1], clique com o botão direito do rato no projeto e, em [2], selecione a opção [Novo / Outro]
- Em [3], selecione a categoria [Persistência] e, em seguida, em [4], indique que pretende criar entidades JPA a partir de uma base de dados existente.
![]() |
- Em [5], selecione a fonte JDBC «jdbc/dbrdvmedecins» que criámos
- Em [6], selecione as quatro tabelas da base de dados associada
- Em [7,8], inclua-as todas na geração de entidades JPA
- Em [9], continue com o assistente
![]() |
- Em [10], as entidades JPA que serão geradas
- em [11], nomeie o pacote das entidades JPA
- em [12], escolha o tipo Java que irá encapsular as listas de objetos devolvidas pela camada JPA
- Conclua o assistente
- em [13], as quatro entidades JPA geradas, uma para cada tabela da base de dados.
Aqui está, por exemplo, o código para a entidade [Rv], que representa uma linha na tabela [rv] da base de dados [dbrdvmedecins].
Criação da camada EJB para aceder a entidades JPA
![]() |
![]() |
- Em [1], clique com o botão direito do rato no projeto e, em [2], selecione a opção [Novo / Outros]
- em [3], selecione a categoria [Persistência] e, em seguida, em [4], selecione o tipo [Session Beans para classes de entidade]
![]() |
- em [5], são apresentadas as entidades JPA criadas anteriormente
- Em [6], selecione todas
- Em [7], elas foram selecionadas
- Em [8], continue com o assistente
![]() |
- Em [9], atribua um nome ao pacote para os EJBs que serão gerados
- Em [10], especifique que os EJBs devem implementar tanto uma interface local como uma interface remota
- Conclua o assistente
- em [11], os EJBs gerados
Aqui, por exemplo, está o código EJB que gere o acesso à entidade [Rv] e, consequentemente, à tabela [rv] na base de dados [dbrdvmedecins]:
Como mencionado, a geração automática de código pode ser muito útil para dar início a um projeto e aprender sobre entidades JPA e EJBs. Nas secções seguintes, reescreveremos as camadas JPA e EJB com o nosso próprio código, mas o leitor reconhecerá as informações que acabámos de abordar na geração automática das camadas.
4.6. O projeto NetBeans para o módulo EJB
Criamos um novo módulo EJB vazio (ver secção 4.5):
![]() |
- O pacote [rdvmedecins.entites] contém as entidades da camada JPA
- o pacote [rdvmedecins.dao] implementa o EJB para a camada [dao]
- o pacote [rdvmedecins.exceptions] implementa uma classe de exceção específica da aplicação
A seguir, partimos do princípio de que o leitor seguiu todos os passos da secção 4.5. Será necessário repetir alguns deles.
4.6.1. Configurar a camada JPA
Vamos rever a arquitetura da nossa aplicação cliente/servidor:
![]() |
O projeto NetBeans:
![]() |
A camada [JPA] é configurada pelos ficheiros [persistence.xml] e [sun-resources.xml] acima. Estes dois ficheiros são gerados pelos assistentes que já conhecemos:
- A geração do ficheiro [sun-resources.xml] foi descrita na Secção 4.5.
- A geração do ficheiro [persistence.xml] foi descrita na secção 4.5.
O ficheiro [persistence.xml] gerado deve ser modificado da seguinte forma:
- Linha 3: O tipo de transação é JTA: as transações serão geridas pelo contentor EJB3 do GlassFish
- linha 4: É utilizada uma implementação JPA/Hibernate. Para tal, a biblioteca Hibernate foi adicionada ao servidor GlassFish (ver secção 4.4).
- linha 5: a fonte de dados JTA utilizada pela camada JPA tem o nome JNDI «jdbc/dbrdvmedecins».
- Linha 8: Esta linha não é gerada automaticamente. Deve ser adicionada manualmente. Indica ao Hibernate que o SGBD utilizado é o MySQL5.
A fonte de dados «jdbc/dbrdvmedecins» está configurada no seguinte ficheiro [sun-resources.xml]:
- Linhas 8–10: As propriedades JDBC da fonte de dados (URL da base de dados, nome de utilizador e palavra-passe). A base de dados MySQL `dbrdvmedecins` é a descrita na Secção 4.1.
- Linha 7: As características do conjunto de ligações associado a esta fonte de dados
4.6.2. As entidades da camada JPA
Vamos rever a arquitetura da nossa aplicação cliente/servidor:
![]() |
O projeto NetBeans:
![]() |
O pacote [rdvmedecins.entites] implementa a camada [Jpa].
Na Secção 4.5, vimos como gerar automaticamente entidades JPA para uma aplicação. Não utilizaremos esta técnica aqui, mas definiremos as entidades nós próprios. No entanto, estas irão incorporar grande parte do código gerado na Secção 4.5. Aqui, queremos que as entidades [Medecin] e [Client] sejam classes filhas de uma classe [Personne].
A classe Person é utilizada para representar médicos e clientes:
- Linha 3: Note que a classe [Person] não é, por si só, uma entidade (@Entity). Será a classe pai das entidades. A anotação @MappedSuperClass indica esta situação.
A entidade [Client] encapsula as linhas da tabela [clients]. Ela deriva da classe [Person] anterior:
- Linha 3: A classe [Client] é uma entidade JPA
- linha 4: está associada à tabela [clients]
- linha 5: deriva da classe [Person]
A entidade [Doctor], que encapsula as linhas da tabela [doctors], segue o mesmo padrão:
A entidade [Creneau] encapsula as linhas da tabela [creneaux]:
- As linhas 15–17 modelam a relação «um-para-muitos» entre a tabela [slots] e a tabela [doctors] na base de dados.
A entidade [Rv] encapsula as linhas da tabela [rv]:
- As linhas 15–17 modelam a relação «um-para-muitos» entre a tabela [rv] e a tabela [clients] na base de dados, e as linhas 18–20 modelam a relação «um-para-muitos» entre a tabela [rv] e a tabela [slots]
4.6.3. A classe de exceção
![]() |
A classe de exceção da aplicação [ RdvMedecinsException] é a seguinte:
- Linha 6: A classe estende a classe [RuntimeException]. Por isso, o compilador não exige que seja tratada com blocos try/catch.
- Linha 5: a anotação @ApplicationException garante que a exceção não será «engolida» por uma [EjbException].
Para compreender a anotação @ApplicationException, vamos rever a arquitetura do lado do servidor:
![]() |
A exceção [RdvMedecinsException] será lançada pelos métodos EJB na camada [dao] dentro do contentor EJB3 e interceptada por este. Sem a anotação @ApplicationException, o contentor EJB3 encapsula a exceção que ocorreu dentro de uma [EjbException] e relança-a. Pode não querer esta encapsulação e preferir deixar que uma exceção do tipo [RdvMedecinsException] escape do contentor EJB3. É isso que a anotação @ApplicationException permite. Além disso, o atributo (rollback=true) desta anotação instrui o contentor EJB3 para que, se ocorrer uma exceção do tipo [RdvMedecinsException] dentro de um método executado como parte de uma transação com um SGBD, a transação seja revertida. Em termos técnicos, isto é chamado de reversão da transação.
4.6.4. O EJB da camada [dao]
![]() |
![]() |
A interface Java [ IDao] da camada [dao] é a seguinte:
A interface local do EJB [IDaoLocal] simplesmente estende a interface anterior [IDao]:
O mesmo se aplica à interface remota [IDaoRemote]:
O EJB [DaoJpa] implementa tanto a interface local como a remota:
- A linha 3 indica que o EJB remoto se chama "rdvmedecins.dao"
- A linha 4 indica que todos os métodos do EJB são executados dentro de uma transação gerida pelo contentor EJB3.
- A linha 5 mostra que o EJB implementa as interfaces local e remota.
O código EJB completo é o seguinte:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
- Linha 8: o objeto EntityManager que gere o acesso ao contexto de persistência. Quando a classe for instanciada, este campo será inicializado pelo contentor EJB utilizando a anotação @PersistenceContext na linha 7.
- linha 15: consulta JPQL que devolve todas as linhas da tabela [clients] como uma lista de objetos [Client].
- linha 22: uma consulta semelhante para médicos
- Linha 32: Uma consulta JPQL que realiza uma junção entre as tabelas [slots] e [doctors]. É parametrizada pelo ID do médico.
- Linha 43: Uma consulta JPQL que realiza uma junção entre as tabelas [appointments], [slots] e [doctors] e que tem dois parâmetros: o ID do médico e a data da consulta.
- Linhas 55–57: criação de uma consulta e a sua subsequente persistência na base de dados.
- Linha 67: Elimina uma consulta da base de dados.
- Linha 76: executa uma consulta SELECT na base de dados para encontrar um cliente específico
- Linha 85: O mesmo para um médico
- Linha 94: o mesmo para uma consulta
- Linha 103: o mesmo para um intervalo de tempo
- Todas as operações que envolvem o contexto de persistência da linha 9 são suscetíveis de encontrar um problema com a base de dados. Por isso, estão todas incluídas num bloco try/catch. Qualquer exceção é encapsulada na exceção personalizada RdvMedecinsException.
Depois de compilado, o módulo EJB gera um ficheiro .jar com o nome « »:
![]() |
4.7. Implementação do EJB da camada [DAO] com o NetBeans
O NetBeans permite-lhe implementar facilmente o EJB criado anteriormente no servidor GlassFish.
![]() |
- Nas propriedades do projeto EJB, verifique as opções de tempo de execução [1].
- Em [2], o nome do servidor no qual o EJB será implementado
- No separador [Serviços] [3], inicie-o [4].
![]() |
- Em [5], o servidor GlassFish após ter sido iniciado. Ainda não possui um módulo EJB.
- Inicie o servidor MySQL e certifique-se de que a base de dados [dbrdvmedecins] está online. Para tal, pode utilizar a ligação NetBeans criada na secção 4.5.
- No separador [Projects] [6], implemente o módulo EJB [7]: o SGBD MySQL5 deve estar em execução para que o recurso JDBC «jdbc/dbrdvmedecins», utilizado pelo EJB, esteja acessível.
- Em [8], o EJB implementado aparece na árvore do servidor GlassFish
![]() |
- Em [9], remova o EJB implementado
- Em [10], o EJB já não aparece na árvore do servidor GlassFish.
4.8. Implantar o EJB a partir da camada [DAO] com o GlassFish
Aqui mostramos como implementar um EJB no servidor GlassFish a partir do seu arquivo .jar.
- Inicie o servidor MySQL e certifique-se de que a base de dados [dbrdvmedecins] está online. Para tal, pode utilizar a ligação do NetBeans criada na Secção 4.5.
Vamos rever a configuração JPA do módulo EJB a ser implementado. Esta configuração está definida no ficheiro [persistence.xml]:
A linha 5 indica que a camada JPA utiliza uma fonte de dados JTA, ou seja, uma fonte gerida pelo contentor EJB3, denominada «jdbc/dbrdvmedecins».
Vimos na Secção 4.5 como criar este recurso JDBC utilizando o NetBeans. Aqui, mostramos como fazê-lo diretamente com o GlassFish. Seguimos o procedimento descrito na Secção 13.1.2, página 79 de [ref1].
Começamos por eliminar o recurso para que possamos recriá-lo. Fazemos isto a partir do NetBeans:
![]() |
- em [1], os recursos JDBC do servidor GlassFish
- em [2], o recurso «jdbc/dbrdvmedecins» do nosso EJB
- em [3], o conjunto de ligações para este recurso JDBC
![]() |
- em [4], eliminamos o conjunto de ligações. Isto terá como efeito a eliminação de todos os recursos JDBC que o utilizam, incluindo o recurso «jdbc/dbrdvmedecins».
- em [5] e [6], o recurso JDBC e o conjunto de ligações foram destruídos.
Agora, utilizamos a consola de administração do servidor GlassFish para criar o recurso JDBC e implementar o EJB.
![]() |
- No separador [Serviços] [1] do NetBeans, inicie o servidor GlassFish [2] e, em seguida, aceda [3] à sua consola de administração
- Em [4], inicie sessão como administrador (palavra-passe: adminadmin, caso não a tenha alterado durante a instalação ou posteriormente).
![]() |
- Em [5], selecione o ramo [Connection Pools] dos recursos do GlassFish
- Em [6], crie um novo conjunto de conexões. Note que um conjunto de conexões é uma técnica para limitar o número de conexões abertas e fechadas com um SGBD. Quando o servidor é iniciado, N conexões — um número definido pela configuração — são abertas para o SGBD. Estas conexões abertas são então disponibilizadas aos EJBs que as solicitam para realizar uma operação com o SGBD. Assim que a operação é concluída, o EJB devolve a conexão ao conjunto. A ligação nunca é encerrada; é partilhada entre os vários threads que acedem ao SGBD
- em [7], atribua um nome ao pool
- em [8], a classe que modela a fonte de dados é a classe [javax.sql.DataSource]
- em [9], o SGBD que contém a fonte de dados é o MySQL neste caso.
- em [10], avance para o passo seguinte
![]() |
- em [11], o atributo «Validação de ligação necessária» garante que, antes de conceder uma ligação, o conjunto verifique se esta está operacional. Caso contrário, cria uma nova. Isto permite que uma aplicação continue a funcionar após uma interrupção temporária do SGBD. Durante a interrupção, nenhuma ligação está disponível e são lançadas exceções para o cliente. Quando a interrupção termina, os clientes que continuam a solicitar ligações obtêm-nas novamente: graças ao atributo «Validação de ligação necessária», todas as ligações no conjunto serão recriadas. Sem este atributo, o conjunto detetaria que as ligações iniciais foram perdidas, mas não tentaria recriar novas ligações.
- Em [12], o nível de isolamento «Read Committed» é especificado para transações. Este nível garante que uma transação T2 não pode ler dados modificados por uma transação T1 até que esta última esteja totalmente concluída.
- Em [13], especificamos que todas as transações devem utilizar o nível de isolamento especificado em [12]
![]() |
- Em [14] e [15], especifique o URL da base de dados cujas ligações são geridas pelo pool
- Em [16], o utilizador será o root
- Em [17], adicione uma propriedade
- Em [18], adicione a propriedade «Password» com o valor () em [19]. Embora a captura de ecrã [19] não o mostre, não introduza uma cadeia de caracteres vazia; em vez disso, introduza () (parêntese de abertura, parêntese de fecho) para indicar uma palavra-passe vazia. Se o utilizador root do seu SGBD MySQL tiver uma palavra-passe não vazia, introduza essa palavra-passe.
- Em [20], conclua o assistente de criação do conjunto de ligações para a base de dados MySQL [dbrdvmedecins].
![]() |
- Em [21], o conjunto foi criado. Clique no seu link.
- Em [22], o botão [Ping] permite estabelecer uma ligação com a base de dados [dbrdvmedecins]
- Em [23], se tudo correr bem, uma mensagem indica que a ligação foi bem-sucedida
Depois de criado o conjunto de conexões, pode criar um recurso JDBC:
![]() |
- Em [1], selecione o ramo [Recursos JDBC] na árvore de objetos do servidor
- Em [2], crie um novo recurso JDBC
- Em [3], atribua um nome ao recurso JDBC. Este deve corresponder ao nome utilizado no ficheiro [persistence.xml]:
- Em [4], especifique o conjunto de ligações que o novo recurso JDBC deve utilizar: aquele que acabou de criar
- Em [5], concluímos o assistente de criação
![]() |
- Em [6], o novo recurso JDBC
Agora que o recurso JDBC foi criado, pode implementar o ficheiro JAR do EJB:
![]() |
- Em [1], selecione o ramo [Aplicações Empresariais]
- Em [2], clique no botão [Implantar] para indicar que pretende implantar uma nova aplicação
- Em [3], especifique que a aplicação é um módulo EJB
- Em [4], selecione o ficheiro JAR EJB [serveur-ejb-dao-jpa-hibernate.jar] que lhe foi fornecido para o laboratório.
- Em [5], pode alterar o nome do módulo EJB, se desejar
- Em [6], conclua o assistente de implementação do módulo EJB
![]() |
- Em [7], o módulo EJB foi implementado. Agora já pode ser utilizado.
4.9. Testar o EJB da camada [DAO]
Agora que o EJB para a camada [DAO] da nossa aplicação foi implementado, podemos testá-lo. Faremos isso utilizando o seguinte cliente Java:
![]() |
A classe [MainTestsDaoRemote] [1] é uma classe de teste JUnit 4. As bibliotecas em [2] consistem em:
- o ficheiro JAR EJB da camada [DAO] [3] (ver secção 4.6.4).
- as bibliotecas GlassFish [4] necessárias para clientes EJB remotos.
A classe de teste é a seguinte:
- Linha 13: Observe a instanciação do proxy EJB remoto. Utilizamos o seu nome JNDI "rdvmedecins.dao".
- Os métodos de teste utilizam os métodos expostos pelo EJB (ver secção 4.6.4).
Se tudo correr bem, os testes devem ser aprovados:
![]() |
Agora que o EJB da camada [dao] está operacional, podemos prosseguir para o expor publicamente através de um serviço web.
4.10. O serviço web da camada [dao]
Para uma breve introdução ao conceito de serviço web, consulte a secção 14, página 111 de [ref1].
Voltemos à arquitetura do servidor da nossa aplicação cliente/servidor:
![]() |
Estamos a concentrar-nos aqui no serviço web da camada [DAO]. O único objetivo deste serviço é disponibilizar a interface EJB da camada [DAO] a clientes multiplataforma capazes de comunicar com um serviço web.
Lembre-se de que existem duas formas de implementar um serviço web:
- utilizando uma classe anotada com @WebService que é executada num contentor web
![]() |
- utilizando um EJB anotado com @WebService que é executado num contentor EJB
![]() |
Aqui, utilizamos a primeira solução. No IDE NetBeans, precisamos de criar um projeto empresarial com dois módulos:
- o módulo EJB que será executado no contentor EJB: o EJB da camada [DAO].
- o módulo web que será executado no contentor web: o serviço web que estamos atualmente a construir.
Vamos construir este projeto empresarial de duas maneiras.
4.10.1. Projeto NetBeans - Versão 1
Primeiro, criamos um projeto NetBeans do tipo «Aplicação Web»:
![]() |
- Em [1], crie um novo projeto na categoria «Java Web» [2] do tipo «Aplicação Web» [3].
![]() |
- Em [4], nomeamos o projeto e, em [5], especificamos a pasta onde ele deve ser gerado
- Em [6], especificamos o servidor de aplicações que irá executar a aplicação web
- Em [7], defina o contexto da aplicação
- Em [8], valide a configuração do projeto.
![]() |
- Em [9], o projeto gerado. O serviço web que estamos a construir irá utilizar o EJB do projeto anterior [10]. Por conseguinte, é necessário referenciar o ficheiro .jar do módulo EJB [10].
- Em [11], adicione um projeto NetBeans às bibliotecas do projeto web [12]
![]() |
- Em [13], selecione a pasta do módulo EJB no sistema de ficheiros e confirme.
![]() |
- Em [14], o módulo EJB foi adicionado às bibliotecas do projeto web.
Em [15], implementamos o serviço web com a seguinte classe [WsDaoJpa]:
- Linha 4: A classe [WsdaoJpa] implementa a interface [IDao]. Recorde-se que esta interface está definida no arquivo EJB da camada [dao] da seguinte forma:
- Linha 3: A anotação @WebService torna a classe [WsDaoJpa] um serviço web.
- Linhas 6–7: A referência ao EJB na camada [DAO] será injetada pelo servidor de aplicações no campo da linha 7. Note-se que é sempre a implementação local (IDaoLocal, neste caso) que é injetada. Esta injeção é possível porque o serviço web é executado na mesma JVM que o EJB.
- Todos os métodos do serviço web são marcados com a anotação @WebMethod para torná-los visíveis aos clientes remotos. Um método não marcado com a anotação @WebMethod seria interno ao serviço web e não visível aos clientes remotos. Cada método M do serviço web simplesmente chama o método M correspondente do EJB injetado na linha 7.
A criação deste serviço web é refletida por um novo ramo no projeto NetBeans:
![]() |
Vemos em [1] o serviço web WsDaoJpa e em [2] os métodos que este expõe aos clientes remotos.
Vamos rever a arquitetura do serviço web em desenvolvimento:
![]() |
Os componentes do serviço web que vamos implementar são:
- [1]: o módulo web que acabámos de criar
- [2]: o módulo EJB que criámos numa etapa anterior, do qual o serviço web depende
Para os implementar em conjunto, precisamos de combinar os dois módulos num projeto «enterprise» do NetBeans:
![]() |
Em [1], crie um novo projeto empresarial [2, 3].
![]() |
- Em [4,5], nomeamos o projeto e especificamos o diretório de criação
- Em [6], selecione o servidor de aplicações no qual a aplicação empresarial será implementada
- Em [7], um projeto empresarial pode ter três componentes: aplicação web, módulo EJB e aplicação cliente. Aqui, o projeto é criado sem quaisquer componentes. Estes serão adicionados posteriormente.
![]() |
- Em [8], a aplicação empresarial recém-criada.
![]() |
- Em [9], clique com o botão direito do rato em [Módulos Java EE] e adicione um novo módulo
- Em [10], são apresentados apenas os módulos do NetBeans atualmente abertos no IDE. Aqui, selecionamos o módulo web [web-service-server-1-ejb-dao-jpa-hibernate] e o módulo EJB [ejb-server-dao-jpa-hibernate] que criámos.
- Em [11], os dois módulos adicionados ao projeto empresarial.
Precisamos agora de implementar esta aplicação empresarial no servidor GlassFish. Em seguida, o SGBD MySQL deve ser iniciado para que a fonte de dados JDBC «jdbc/dbrdvmedecins» utilizada pelo módulo EJB fique acessível.
![]() |
- Em [1], iniciamos o servidor GlassFish
- Se o módulo EJB [ejb-server-dao-jpa-hibernate] estiver implementado, descarregamo-lo [2]
- Em [3], implemente a aplicação empresarial
![]() |
- Em [4], está implementado. Podemos ver que contém ambos os módulos: Web e EJB.
4.10.2. Projeto NetBeans - Versão 2
Vamos agora mostrar como implementar o serviço Web quando não se dispõe do código-fonte do módulo EJB, mas apenas do seu arquivo .jar.
O novo projeto NetBeans para o serviço web será o seguinte:
![]() |
Os elementos mais importantes do projeto são os seguintes:
- [1]: O serviço web é implementado por um projeto NetBeans do tipo [Aplicação Web].
- [2]: O serviço web é implementado pela classe [WsDaoJpa], que já estudámos
- [3]: o arquivo EJB para a camada [DAO], que permite à classe [WsDaoJpa] aceder às definições das várias classes, interfaces e entidades nas camadas [DAO] e [JPA].
Em seguida, criamos o projeto empresarial necessário para implementar o serviço web:
![]() |
- [1] Criamos uma aplicação empresarial [ea-rdvmedecins], inicialmente sem quaisquer módulos.
- Em [2], adicionamos o módulo web anterior [webservice-ejb-dao-jpa-hibernate]
- em [3], o resultado.
Tal como está, a aplicação empresarial [ea-rdvmedecins] não pode ser implementada no servidor GlassFish a partir do NetBeans. Ocorre um erro. Por conseguinte, deve implementar manualmente o arquivo EAR da aplicação [ea-rdvmedecins]:
![]() |
- O arquivo [ea-rdvmedecins.ear] está localizado na pasta [dist] [2] do separador [Arquivos] no NetBeans.
- Neste arquivo [3], encontrará os dois componentes da aplicação empresarial:
- o arquivo EJB [ejb-server-dao-jpa-hibernate]. Este arquivo está presente porque fazia parte das bibliotecas referenciadas pelo serviço web.
- o arquivo do serviço web [webservice-server-ejb-dao-jpa-hibernate].
- O arquivo [ea-rdvmedecins.ear] é criado por uma simples compilação [4] da aplicação empresarial.
- Em [5], a operação de implementação falha.
Para implementar o arquivo da aplicação empresarial [ea-rdvmedecins.ear], procedemos da mesma forma que na implementação do arquivo EJB [ejb-server-dao-jpa-hibernate.jar] na secção 4.2. Utilizamos novamente o cliente de administração web do servidor GlassFish. Não repetiremos os passos já descritos.
Primeiro, começaremos por «descarregar» a aplicação empresarial implementada na secção 4.10.1:
![]() |
- [1]: Selecione o ramo [Aplicações Empresariais] do servidor GlassFish
- em [2] selecione a aplicação empresarial a descarregar e, em seguida, em [3] descarregue-a
- em [4], a aplicação empresarial foi descarregada
![]() |
- Em [1], selecione o ramo [Aplicações Empresariais] do servidor GlassFish
- em [2], implemente uma nova aplicação empresarial
- Em [3], selecione o tipo [Aplicação Empresarial]
- Em [4], especifique o ficheiro .ear para o projeto NetBeans [ea-rdvmedecins]
- Em [5], implemente este arquivo
![]() |
- Em [6], a aplicação foi implementada
- em [7], o serviço web [WsDaoJpa] aparece no ramo [Web Services] do servidor GlassFish. Selecione-o.
- Em [8], tem vários detalhes sobre o serviço web. A informação mais relevante para um cliente é [9]: o URI do serviço web.
- Em [10], pode testar o serviço web
![]() |
- Em [11], o URI do serviço web ao qual foi adicionado o parâmetro ?test. Este URI apresenta uma página de teste. Todos os métodos (@WebMethod) expostos pelo serviço web são apresentados e podem ser testados. Aqui, testamos o método [13], que recupera a lista de clientes.
![]() |
- Em [14], mostramos apenas uma vista parcial da página de resposta. Mas podemos ver que o método getAllClients devolveu, de facto, a lista de clientes. A captura de ecrã mostra que envia a sua resposta em formato XML.
Um serviço web é descrito na íntegra por um ficheiro XML denominado ficheiro WSDL:
![]() |
- Em [1], na ferramenta web de administração do servidor GlassFish, selecione o serviço web [WsDaoJpa]
- Em [2], siga o link [Ver WSDL]
![]() |
- Em [3]: o URI do ficheiro WSDL. Esta é uma informação importante a saber. É necessária para configurar os clientes para este serviço web.
- Em [4], a descrição XML do serviço web. Não iremos comentar este conteúdo complexo.
4.10.3. Testes JUnit para o serviço web
Criamos um projeto NetBeans para «executar» os testes anteriormente realizados com um cliente EJB, desta vez utilizando um cliente para o serviço web recentemente implementado. Aqui, seguimos um procedimento semelhante ao descrito na secção 14.2.1, página 115 de [ref1].
![]() |
- em [1], um projeto Java clássico
- Em [2], a classe de teste
- em [3], o cliente utiliza o arquivo EJB para aceder às definições da interface da camada [DAO] e às entidades JPA. Note-se que este arquivo se encontra na subpasta [dist] da pasta do módulo EJB.
Para aceder ao serviço web remoto, é necessário gerar classes proxy:
![]() |
No diagrama acima, a camada [2] [C=Cliente] comunica com a camada [1] [S=Servidor]. Para interagir com a camada [S], o cliente [C] deve estabelecer uma ligação de rede com a camada [S] e comunicar com ela utilizando um protocolo específico. As ligações de rede são ligações TCP e o protocolo de transporte é HTTP. A camada [S], que representa o serviço web, é implementada por um servlet Java em execução no servidor GlassFish. Não escrevemos este servlet. A sua geração é automatizada pelo GlassFish com base nas anotações @WebService e @WebMethod na classe [WsDaoJpa] que escrevemos. Da mesma forma, iremos automatizar a geração da camada cliente [C]. A camada [C] é por vezes designada por camada proxy para o serviço web remoto, sendo que o termo «proxy» se refere a um elemento intermediário numa cadeia de software. Aqui, o proxy C atua como intermediário entre o cliente que estamos prestes a escrever e o serviço web que implementámos.
Com o NetBeans 6.5, o proxy C pode ser gerado da seguinte forma (para o resto do processo, o serviço web deve estar a ser executado no servidor GlassFish):
![]() |
- Em [1], adicione um novo elemento ao projeto Java
- em [2], selecione o ramo [Serviços Web]
- em [3], selecione [Cliente de Serviço Web]
![]() |
- em [4], forneça o URI do ficheiro WSDL do serviço Web. Este URI foi apresentado na secção 4.10.2.
- Em [5], mantenha o valor padrão [JAX-WS]. O outro valor possível é [JAX-RPC]
- Após confirmar o assistente de criação do proxy do serviço web, o projeto NetBeans foi expandido para incluir um ramo [Referências de Serviço Web] [6]. Este ramo exibe os métodos expostos pelo serviço web remoto.
![]() |
- No separador [Ficheiros] [7], foi adicionado código-fonte Java [8]. Este corresponde ao proxy C gerado.
- Em [9] encontra-se o código de uma das classes. Podemos ver [10] que foram colocadas num pacote [rdvmedecins.ws]. Não iremos comentar o código destas classes, que é, mais uma vez, bastante complexo.
Para o cliente Java que estamos a construir, o proxy C gerado atua como intermediário. Para aceder ao método M do serviço web remoto, o cliente Java chama o método M do proxy C. O cliente Java chama, assim, métodos locais (executados na mesma JVM) e, de forma transparente para ele, estas chamadas locais são traduzidas em chamadas remotas.
Ainda precisamos de saber como chamar os métodos M do proxy C. Voltemos à nossa classe de teste JUnit:
![]() |
Em [1], a classe de teste [MainTestsDaoRemote] é a mesma já utilizada ao testar o EJB da camada [dao]:
- linha [13], o teste test1 permanece inalterado.
- linha [9], o conteúdo do método [init] foi eliminado.
Nesta altura, o projeto contém erros porque o método de teste [test1] utiliza as entidades [Client], [Medecin], [Creneau] e [Rv], que já não se encontram nos mesmos pacotes que antes. Estão agora no pacote proxy C gerado. Removemos as instruções de importação relevantes e regeneramo-las utilizando a operação Fix Imports.
![]() |
Voltemos ao código da classe de teste [MainTestsDaoRemote]:
O método [init] na linha 10 deve inicializar a referência à camada [dao] na linha 7. Precisamos de saber como utilizar o proxy C gerado no nosso código. O NetBeans ajuda-nos neste processo.
![]() |
- Selecione o método [getAllClients] do serviço web em [1] com o rato, depois arraste esse método e solte-o no método [init] da classe de teste.
Obtemos o resultado [2]. Este esqueleto de código mostra-nos como utilizar o proxy C gerado:
- A linha [5] mostra que o método [getAllClients] é um método do objeto [WsDaoJpa] definido na linha 3. O tipo [WsDaoJpa] é uma interface que expõe os mesmos métodos que aqueles expostos pelo serviço web remoto.
- Na linha [3], o objeto [WsDaoJpaPort] é obtido a partir de outro objeto do tipo [WsDaoJpaService] definido na linha 2. O tipo [WsDaoJpaService] representa o proxy C gerado localmente.
- O acesso ao serviço web remoto pode falhar, pelo que todo o bloco de código está incluído num bloco try/catch.
- Os objetos proxy C encontram-se no pacote [rdvmedecins.ws]
Uma vez compreendido este código, vemos que a referência local ao serviço web remoto pode ser obtida utilizando o seguinte código:
O código para a classe de teste JUnit passa então a ser o seguinte:
Estamos agora prontos para o teste:
![]() |
Em [1], o teste JUnit é executado. Em [2], o teste é aprovado. Se observarmos a saída na consola do NetBeans, vemos linhas como as seguintes:
Liste des clients :
rdvmedecins.ws.Client@1982fc1
rdvmedecins.ws.Client@676437
rdvmedecins.ws.Client@1e4853f
rdvmedecins.ws.Client@1e808ca
No lado do servidor, a entidade [Client] possui um método toString que exibe os vários campos de um objeto [Client]. Durante a geração automática do proxy C, as entidades são criadas no proxy C, mas apenas com os campos privados acompanhados pelos seus métodos get/set. Assim, o método toString não foi gerado na entidade [Client] do proxy C. Isto explica a exibição anterior. Isto não prejudica o teste JUnit: este foi aprovado. Vamos agora considerar que temos um serviço web operacional.






























































































