4. O serviço web J2EE para marcação de consultas
Voltemos à arquitetura da aplicação a construir:
![]() |
Nesta secção, vamos centrar-nos na construção do serviço web J2EE [1] 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: número que identifica o médico — chave primária da tabela
- VERSION: 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.
- NOM: o apelido do médico
- PRENOM: o seu nome próprio
- TITRE: o seu título (Menina, Sra., Sr.)
4.1.2. A tabela [CLIENTS]
Os clientes dos diferentes médicos estão registados 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 sempre que é feita uma alteração na linha.
- NOM: o nome do cliente
- PRENOM: o seu nome próprio
- TITRE: o seu título (Menina, Sra., Sr.)
4.1.3. A tabela [CRENEAUX]
Esta tabela lista os intervalos horários em que os RV são possíveis:
![]() |
![]() |
- ID: número que identifica o intervalo horário — chave primária da tabela (linha 8)
- VERSION: 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.
- ID_MEDECIN: número que identifica o médico a quem pertence este intervalo horário – chave estrangeira na coluna MEDECINS (ID).
- HDEBUT: hora de início do horário
- MDEBUT: minutos de início do intervalo
- HFIN: hora de fim do intervalo
- MFIN: minutos de fim do intervalo
A segunda linha da tabela [CRENEAUX] (ver [1] acima) indica, por exemplo, que o intervalo n.º 2 começa às 8h20 e termina às 8h40 e pertence ao médico n.º 1 (Sra. Marie PELISSIER).
4.1.4. A tabela [RV]
Esta tabela lista os RV atribuídos a cada médico:
![]() |
- ID: número que identifica o RV de forma única – chave primária
- JOUR: dia do RV
- ID_CRENEAU: intervalo horário do RV – chave estrangeira no campo [ID] da tabela [CRENEAUX] – determina simultaneamente o intervalo horário e o médico em questão.
- ID_CLIENT: número do cliente para quem é feita a reserva – chave estrangeira no campo [ID] da tabela [CLIENTS]
Esta tabela possui uma restrição de unicidade na sobre os valores das colunas associadas (JOUR, ID_CRENEAU):
Se uma linha da tabela [RV] tiver o valor (JOUR1, ID_CRENEAU1) para as colunas (JOUR, ID_CRENEAU), esse valor não pode aparecer em mais nenhum outro local. Caso contrário, isso significaria que dois RV foram registados 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 um SQLException quando esta situação ocorre.
A linha de id igual a 3 (ver [1] acima) significa que um RV foi marcado para o horário n.º 20 e o cliente n.º 4 em 23/08/2006. A tabela [CRENEAUX] 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 Srta. Brigitte BISTROU.
4.2. Geração da base de dados
Crie a base de dados MySql [dbrdvmedecins] com a ferramenta da sua escolha. Para criar as tabelas e preenchê-las, pode utilizar o script [createbd.sql] que lhe será fornecido. O seu conteúdo é o seguinte:
4.3. Os elementos da arquitetura do lado do servidor
Voltemos à arquitetura da aplicação a construir:
![]() |
Do lado do servidor, a aplicação será composta por:
- por uma camada JPA que permite trabalhar com a BD por meio de objetos
- de um EJB encarregado de gerir as operações com a camada JPA
- de um serviço web encarregado de expor aos clientes remotos a interface do EJB sob a forma de um serviço web.
Os elementos (b) e (c) implementam a camada [dao] representada no esquema anterior. Sabe-se 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++, ... É isso que pretendemos demonstrar aqui, utilizando um cliente .NET.
Para uma breve introdução aos serviços web, pode consultar-se o curso [ref1], parágrafo 14, página 109.
Um serviço web pode ser implementado de duas formas:
- através de uma classe anotada com @WebService que é executada num contentor web
![]() |
- através de um EJB anotado com @WebService que é executado num contentor EJB
![]() |
![]() |
Vamos utilizar aqui a primeira solução:
No curso [ref1], parágrafo 14, página 109, encontra-se um exemplo que utiliza a segunda solução.
4.4. Configuração do servidor Glassfish para Hibernate
Dependendo da versão, o servidor Glassfish V2 fornecido com o NetBeans pode não incluir as bibliotecas Hibernate necessárias para a camada JPA/Hibernate. Se, ao longo do tutorial, verificar que o Glassfish não disponibiliza uma implementação JPA/Hibernate ou se, durante a implementação dos serviços, surgir uma exceção a indicar que as bibliotecas do Hibernate não foram encontradas, deverá adicionar as bibliotecas à pasta [<glassfish>/domains/domain1/lib/ext] e, em seguida, reiniciar o servidor Glassfish:
![]() |
|
As bibliotecas do Hibernate encontram-se no ficheiro zip que acompanha o tutorial.
4.5. As ferramentas de geração automática do NetBeans
Voltemos à arquitetura que temos de construir:
![]() |
Com o NetBeans, é possível gerar automaticamente a camada [JPA] e a camada [Ejb], que controla o acesso às entidades JPA geradas. É interessante conhecer estes métodos de geração automática, pois o código gerado fornece indicações valiosas sobre como escrever entidades JPA ou o código EJB que as utiliza.
Descrevemos agora algumas dessas ferramentas de geração automática. Para compreender o código gerado, é necessário ter bons conhecimentos sobre as entidades JPA, [ref1] e as EJB, [ref2].
Criação de uma ligação do NetBeans à base de dados
- Execute o SGBD e o MySQL 5 para que o BD fique disponível
- criar uma ligação do NetBeans à base de dados [dbrdvmedecins]
![]() |
- no separador [Files], no ramo [Databases] [1], selecionar o controlador JDBC MySQL [2]
- e, em seguida, selecione a opção [3] «Connect Using», que permite 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. Aqui podem ver-se as quatro tabelas da base de dados ligada.
Criação de um projeto EJB
![]() |
- em [1], criar uma nova aplicação, um módulo EJB
- em [2], selecione a categoria [Java EE] e, em [3], o tipo [EJB Module]
![]() |
- em [4], selecione uma pasta para o projeto e, em [5], atribua-lhe um nome — em seguida, 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 [Services], inicie o servidor Glassfish [2, 3]
- no separador [Projects], clique com o botão direito do rato no projeto EJB e, em [5], selecione a opção [New / Other] que permite adicionar um elemento ao projeto.

- em [6], selecione a categoria [Glassfish] e, em [7], indique que pretende criar um recurso JDBC, selecionando o tipo [JDBC Resource]
- em [8], indicar que este recurso JDBC irá utilizar o seu próprio conjunto de ligações
- em [9], atribuir um nome ao recurso JDBC
- em [10], passar à etapa seguinte
![]() |
- em [11], definem-se as características do conjunto de ligações do recurso JDBC
- em [12], atribuir um nome ao conjunto de ligações
- em [13], selecione a ligação 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 extraídas das propriedades da ligação do NetBeans [dbrdvmedecins] criada anteriormente
- em [16], avance para o passo seguinte
![]() |
- em [17], mantenha os valores predefinidos sugeridos
- em [18], conclua o assistente. Este cria o ficheiro [sun-resources.xml] [19], cujo conteúdo é o seguinte:
O ficheiro acima contém todas as informações introduzidas no assistente no formato XML. Será utilizado pelo IDE NetBeans para solicitar ao servidor GlassFish que crie 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: indica a implementação JPA utilizada (Toplink, Hibernate, ...) e configura-a.
![]() |
![]() |
- em [1], clique com o botão direito do rato no projeto EJB e selecione [New / Other] em [2]
- em [3], selecione a categoria [Persistence] 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], selecione [Hibernate] como implementação JPA
- em [7], selecionar o recurso Glassfish «jdbc/dbrdvmedecins» que acabou de ser criado
- em [8], indicar que não deve ser realizada nenhuma ação na base de dados durante a instanciação da camada JPA
- concluir o assistente
- no [9], o ficheiro [persistence.xml] criado pelo assistente
O seu conteúdo é o seguinte:
Mais uma vez, este ficheiro retoma, no formato XML, as informações fornecidas no assistente. Este ficheiro não é suficiente para trabalhar com a base de dados MySQL5 «dbrdvmedecins». Teríamos de indicar ao Hibernate o tipo de SGBD a gerir. Isso será feito posteriormente.
Criação das entidades JPA
![]() |
![]() |
![]() |
- em [1], clicar com o botão direito do rato no projeto e, em [2], selecionar a opção [New / Other]
- em [3], selecione a categoria [Persistence] 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], as quatro tabelas da base de dados associada
- em [7,8], inclua-as todas na geração de entidades JPA
- em [9], continuar com o assistente
![]() |
- em [10], as entidades JPA que vão ser geradas
- em [11], atribuir um nome ao pacote das entidades JPA
- em [12], escolher o tipo Java que irá encapsular as listas de objetos devolvidas pela camada JPA
- concluir o assistente
- em [13], as quatro entidades JPA geradas, uma para cada tabela da base de dados.
Eis, por exemplo, o código da entidade [Rv], que representa uma linha da tabela [rv] da base de dados [dbrdvmedecins].
Criação da camada EJB de acesso às entidades JPA
![]() |
![]() |
- em [1], clicar com o botão direito do rato no projeto e, em [2], selecionar a opção [New / Other]
- em [3], selecione a categoria [Persistence] e, em seguida, em [4], o tipo [Session Beans for Entity Classes]
![]() |
- em [5], as entidades JPA criadas anteriormente são apresentadas
- em [6], selecione-as todas
- em [7], foram selecionadas
- em [8], continue com o assistente
![]() |
- em [9], atribuir um nome ao pacote dos EJB que vão ser gerados
- em [10], indicar que os EJB devem implementar tanto uma interface local como uma interface remota
- Concluir o assistente
- em [11], os EJB gerados
Eis, por exemplo, o código do EJB que gere o acesso à entidade [Rv], ou seja, à tabela [rv] da base de dados [dbrdvmedecins]:
Como já foi referido, a geração automática de código pode ser muito útil para dar início a um projeto e familiarizar-se com as entidades JPA e EJB. A seguir, reescreveremos as camadas JPA e EJB com o nosso próprio código, mas o leitor encontrará nelas informações que acabámos de ver na geração automática das camadas.
4.6. O projeto NetBeans do módulo EJB
Criamos um novo módulo EJB em branco (ver parágrafo 4.5):
![]() |
- o pacote [rdvmedecins.entites] agrupa as entidades da camada JPA
- o pacote [rdvmedecins.dao] implementa o EJB da 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 descritos no parágrafo 4.5. Terá de repetir alguns deles.
4.6.1. Configuração da camada JPA
Recorde-se a arquitetura da nossa aplicação cliente/servidor:
![]() |
O projeto NetBeans:
![]() |
A camada [JPA] é configurada pelos ficheiros [persistence.xml] e [sun-resources.xml] acima referidos. Estes dois ficheiros são gerados por assistentes já abordados:
- a geração do ficheiro [sun-resources.xml] foi descrita no parágrafo 4.5.
- A geração do ficheiro [persistence.xml] foi descrita no parágrafo 4.5.
O ficheiro [persistence.xml] gerado deve ser alterado da seguinte forma:
- linha 3: o tipo de transações é 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 parágrafo 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 características JDBC da fonte de dados (URL da base de dados, nome e palavra-passe do utilizador). A base de dados MySQL dbrdvmedecins é a descrita no parágrafo 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
Recorde-se a arquitetura da nossa aplicação cliente/servidor:
![]() |
O projeto NetBeans:
![]() |
O pacote [rdvmedecins.entites] implementa a camada [Jpa].
Vimos no parágrafo 4.5 como gerar automaticamente as entidades JPA de uma aplicação. Aqui, não utilizaremos essa técnica, mas definiremos nós próprios as entidades. No entanto, estas irão retomar grande parte do código gerado no parágrafo 4.5. Neste caso, pretendemos que as entidades [Medecin] e [Client] sejam classes filhas de uma classe [Personne].
A classe Pessoa é utilizada para representar médicos e clientes:
- linha 3: note-se que a classe [Personne] não é, ela própria, uma entidade (@Entity). Será a classe pai de entidades. A anotação @MappedSuperClass indica esta situação.
A entidade [Client] encapsula as linhas da tabela [clients]. Ela deriva da classe anterior [Personne]:
- linha 3: a classe [Client] é uma entidade JPA
- linha 4: está associada à tabela [clients]
- linha 5: deriva da classe [Personne]
A entidade [Medecin], que encapsula as linhas da tabela [medecins], segue o mesmo modelo:
A entidade [Creneau] encapsula as linhas da tabela [creneaux]:
- as linhas 15-17 modelam a relação «um para vários» que existe entre a tabela [creneaux] e a tabela [medecins] da base de dados.
A entidade [Rv] encapsula as linhas da tabela [rv]:
- as linhas 15-17 modelam a relação «um para vários» que existe entre a tabela [rv] e a tabela [clients] da base de dados e as linhas 18-20 a relação «um para vários» que existe entre a tabela [rv] e a tabela [creneaux]
4.6.3. A classe de exceção
![]() |
A classe de exceção [RdvMedecinsException] da aplicação é a seguinte:
- linha 6: a classe deriva da classe [RuntimeException]. O compilador não obriga, portanto, a tratá-la com try/catch.
- linha 5: a anotação @ApplicationException faz com que a exceção não seja «engolida» por uma exceção do tipo [EjbException].
Para compreender a anotação @ApplicationException, voltemos à arquitetura utilizada no lado do servidor:
![]() |
A exceção do tipo [RdvMedecinsException] será lançada pelos métodos do EJB da camada [dao] no interior do contentor EJB3 e interceptada por este. Sem a anotação @ApplicationException, o contentor EJB3 encapsula a exceção ocorrida numa exceção do tipo [EjbException] e relança-a. Pode não se desejar este encapsulamento e permitir que uma exceção do tipo [RdvMedecinsException] saia do contentor Ejb3. É isso que permite a anotação @ApplicationException. Além disso, o atributo (rollback=true) desta anotação indica ao contentor EJB3 que, se a exceção do tipo [RdvMedecinsException] ocorrer no interior de um método executado no âmbito de uma transação com um SGBD, esta deve ser revertida. Em termos técnicos, isto denomina-se efetuar um rollback da transação.
4.6.4. O EJB da camada [dao]
![]() |
![]() |
A interface Java [IDao] da camada [dao] é a seguinte:
A interface local [IDaoLocal] do EJB limita-se a derivar da interface anterior [IDao]:
O mesmo se aplica à interface remota [IDaoRemote]:
O EJB [DaoJpa] implementa ambas as interfaces, a local e a remota:
- a linha 3 indica que o EJB remoto tem o nome «rdvmedecins.dao»
- a linha 4 indica que todos os métodos do EJB decorrem no âmbito de uma transação gerida pelo contentor EJB3.
- a linha 5 mostra que o EJB implementa as interfaces local e remota.
O código completo do EJB é 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. Aquando da instanciação da classe, este campo será inicializado pelo contentor EJB graças à anotação @PersistenceContext da linha 7.
- linha 15: consulta JPQL que devolve todas as linhas da tabela [clients] sob a forma de uma lista de objetos [Client].
- linha 22: consulta semelhante para os médicos
- linha 32: uma consulta JPQL que realiza uma junção entre as tabelas [creneaux] e [medecins]. É parametrizada pelo ID do médico.
- linha 43: uma consulta JPQL que realiza uma junção entre as tabelas [rv], [creneaux] e [medecins] e que tem dois parâmetros: o ID do médico e o dia da consulta.
- linhas 55-57: criação de uma consulta e, em seguida, o seu armazenamento na base de dados.
- linha 67: eliminação de uma consulta da base de dados.
- linha 76: executa uma consulta na base de dados para encontrar um determinado cliente
- linha 85: o mesmo para um médico
- linha 94: o mesmo para uma consulta
- linha 103: o mesmo para um intervalo horário
- Todas as operações com o contexto de persistência em da linha 9 podem encontrar um problema com a base de dados. Por isso, estão todas rodeadas por um try/catch. A eventual exceção é encapsulada na exceção «própria» RdvMedecinsException.
O módulo EJB, uma vez compilado, gera um ficheiro .jar com o :
![]() |
4.7. Implantação do EJB da camada [dao] com o NetBeans
O NetBeans permite implementar facilmente no servidor GlassFish o EJB criado anteriormente.
![]() |
- Nas propriedades do projeto EJB, verifique as opções de execução [1].
- em [2], o nome do servidor no qual o EJB será implementado
- no separador [Services] [3], executa-se o processo [4].
![]() |
- em [5], o servidor GlassFish, uma vez iniciado. Ainda não possui nenhum 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 do NetBeans criada no parágrafo 4.5.
- No separador [Projects] [6], é implementado o módulo EJB [7]: é necessário que o SGBD MySQL5 esteja em execução para que o recurso JDBC «jdbc/dbrdvmedecins», utilizado pelo EJB, esteja acessível.
- No [8], o EJB implementado aparece na árvore de diretórios do servidor GlassFish
![]() |
- Em [9], remove-se o EJB implementado
- em [10], o EJB já não aparece na árvore de diretórios do servidor GlassFish.
4.8. Implantação do EJB da camada [dao] com o GlassFish
Mostramos aqui 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 no parágrafo 4.5.
Recorde-se a configuração JPA do módulo EJB que vai ser implementado. Esta configuração é definida no ficheiro [persistence.xml]:
A linha 5 indica que a camada JPA utiliza uma fonte de dados JTA, c.a.d, gerida pelo contentor EJB3, denominada «jdbc/dbrdvmedecins».
Vimos no parágrafo 4.5 como criar esta recurso JDBC a partir do NetBeans. Mostramos aqui como fazê-lo diretamente com o GlassFish. Seguimos aqui um procedimento descrito no parágrafo 13.1.2, página 79 do [ref1].
Começamos por eliminar o recurso para o podermos recriar. Fazemo-lo a partir do NetBeans:
![]() |
- em [1], as recursos JDBC do servidor GlassFish
- para [2], o recurso «jdbc/dbrdvmedecins» do nosso EJB
- em [3], o conjunto de ligações deste recurso JDBC
![]() |
- em [4], elimina-se o conjunto de ligações. Isto terá como efeito a eliminação de todos os recursos JDBC que o utilizam, ou seja, o recurso «jdbc/dbrdvmedecins».
- em [5] e [6], a recurso JDBC e o pool de ligações foram eliminados.
Agora, utilizamos a consola de administração do servidor Glassfish para criar a recurso JDBC e implementar o EJB.
![]() |
- no separador [services] [1] do NetBeans, inicie o servidor GlassFish [2] e, em seguida, aceda à 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 ligações. Recorde-se que um conjunto de ligações é uma técnica para limitar o número de aberturas/encerramentos de ligações com um SGBD. Ao iniciar o servidor, N — um número definido na configuração — ligações são abertas com o SGBD. Estas ligações abertas são, em seguida, disponibilizadas aos EJBs que as solicitam para realizar uma operação com o SGBD. Assim que a operação estiver concluída, o EJB devolve a ligação ao conjunto. A ligação nunca é encerrada. É partilhada entre os diferentes 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 é, neste caso, o MySQl.
- em [10], avance para o passo seguinte
![]() |
- No [11], o atributo «Connection Validation Required» faz com que, antes de atribuir uma ligação, o conjunto verifique se esta está operacional. Se não for o caso, cria uma nova. Isto permite que uma aplicação continue a funcionar após uma interrupção momentânea com o SGBD. Durante a interrupção, nenhuma ligação está disponível e são comunicadas exceções ao cliente. Quando a interrupção termina, os clientes que continuam a solicitar ligações voltam a obtê-las: graças ao atributo «Connection Validation Required», todas as ligações do conjunto serão recriadas. Sem este atributo, o conjunto verificaria que as ligações iniciais foram interrompidas, mas não tentaria recriar novas ligações.
- Em [12], solicita-se o nível de isolamento «Read Committed» para as transações. Este nível garante que uma transação T2 não possa ler dados alterados por uma transação T1 enquanto esta última não estiver totalmente concluída.
- No [13], solicita-se que todas as transações utilizem o nível de isolamento especificado no [12]
![]() |
- em [14] e [15], especifique o URL de BD cujo pool gere as ligações
- no [16], o utilizador será o root
- no [17], adicione uma propriedade
- no [18], adicione a propriedade «Password» com o valor () no [19]. Embora a captura de ecrã [19] não o mostre, não se deve colocar a cadeia vazia, mas sim () (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.
- no [20], conclua o assistente de criação do conjunto de ligações para a base de dados MySQL [dbrdvmedecins].
![]() |
- em [21], o conjunto de ligações foi criado. Clique na respetiva ligação.
- em [22], o botão [Ping] permite criar uma ligação à 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 ligações, é possível criar um recurso JDBC:
![]() |
- em [1], seleciona-se o ramo [JDBC Resources] da árvore de objetos do servidor
- em [2], cria-se uma nova recurso JDBC
- em [3], atribui-se um nome à recurso JDBC. Este nome deve corresponder ao nome utilizado no ficheiro [persistence.xml]:
- no [4], especifica-se o conjunto de ligações que a nova recurso JDBC deve utilizar: aquele que acabou de ser criado
- No ficheiro [5], conclui-se o assistente de criação
![]() |
- em [6], a nova recurso JDBC
Agora que o recurso JDBC foi criado, podemos implementar o arquivo jar do EJB:
![]() |
- em [1], selecione o ramo [Enterprise Applications]
- em [2], com o botão [Deploy], indique que pretende implementar uma nova aplicação
- em [3], indique que a aplicação é um módulo EJB
- em [4], selecione o ficheiro JAR do EJB [serveur-ejb-dao-jpa-hibernate.jar] que lhe foi fornecido para o TP.
- em [5], pode alterar o nome do módulo EJB, se assim o desejar
- em [6], conclua o assistente de implementação do módulo EJB
![]() |
- No [7], o módulo EJB foi implementado. Já pode ser utilizado.
4.9. Testes do EJB da camada [dao]
Agora que o EJB da 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] são constituídas, por um lado:
- do ficheiro JAR do EJB da camada [dao] [3] (ver parágrafo 4.6.4).
- das bibliotecas GlassFish [4] necessárias aos clientes remotos dos EJB.
A classe de teste é a seguinte:
- linha 13: note-se a instanciação do proxy do EJB remoto. Utiliza-se o seu nome JNDI «rdvmedecins.dao».
- Os métodos de teste utilizam os métodos expostos pelo EJB (ver parágrafo 4.6.4).
Se tudo correr bem, os testes devem ser bem-sucedidos:
![]() |
Agora que o EJB da camada [dao] está operacional, podemos avançar para a sua exposição pública 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 o parágrafo 14, página 111 de [ref1].
Voltemos à arquitetura do servidor da nossa aplicação cliente/servidor:
![]() |
Estamos a analisar acima o serviço web da camada [dao]. A única função deste serviço é disponibilizar a interface do EJB da camada [dao] a clientes multiplataforma capazes de interagir com um serviço web.
Recorde-se que existem duas formas de implementar um serviço web:
- através de uma classe anotada com @WebService que é executada num contentor web
![]() |
- através de um EJB anotado com @WebService que é executado num contentor EJB
![]() |
Aqui, utilizamos a primeira solução. No NetBeans IDE, temos 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 a criar.
Vamos construir este projeto empresarial de duas formas.
4.10.1. Projeto NetBeans - Versão 1
Começamos por criar um projeto NetBeans do tipo «Aplicação Web»:
![]() |
- em [1], criamos um novo projeto na categoria «Java Web» [2] do tipo «Aplicação Web» [3].
![]() |
- em [4], atribui-se um nome ao projeto e, em [5], especifica-se a pasta na qual este deve ser gerado
- no [6], define-se o servidor de aplicações que irá executar a aplicação web
- em [7], define-se o contexto da aplicação
- em [8], valida-se 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 isso, precisa de referenciar o ficheiro .jar do módulo EJB [10].
- No [11], adicionamos um projeto NetBeans às bibliotecas do projeto web [12]
![]() |
- no [13], seleciona-se a pasta do módulo EJB no sistema de ficheiros e confirma-se.
![]() |
- 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]:
- Na linha 4, a classe [WsdaoJpa] implementa a interface [IDao]. Recorde-se que esta interface está definida no arquivo do EJB da camada [dao] da seguinte forma:
- linha 3: a anotação @WebService transforma a classe [WsDaoJpa] num serviço web.
- linhas 6-7: a referência do EJB da camada [dao] será injetada pelo servidor de aplicações no campo da linha 7. Recorde-se que é sempre a implementação local (IDaoLocal, neste caso) que é assim 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 os tornar 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 limita-se a chamar 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:
![]() |
Em [1], vemos o serviço web WsDaoJpa e, em [2], os métodos que este expõe aos clientes remotos.
Recorde-se 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 construir
- [2]: o módulo EJB que criámos numa etapa anterior e do qual o serviço web depende
Para os implementar em conjunto, é necessário reunir os dois módulos num projeto NetBeans denominado «empresarial»:
![]() |
No [1], criamos um novo projeto empresarial [2, 3].
![]() |
- No [4,5], atribui-se um nome ao projeto e define-se a pasta de criação
- em [6], seleciona-se 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, aplicação cliente. Aqui, o projeto é criado sem qualquer componente. Estes serão adicionados posteriormente.
![]() |
- em [8], a aplicação empresarial recém-criada.
![]() |
- em [9], clicar com o botão direito do rato em [Java EE Modules] e adicionar um novo módulo
- em [10], apenas os módulos NetBeans atualmente abertos no IDE são apresentados. Aqui, selecionamos o módulo web [serveur-webservice-1-ejb-dao-jpa-hibernate] e o módulo EJB [serveur-ejb-dao-jpa-hibernate] que criámos.
- No [11], os dois módulos adicionados ao projeto empresarial.
Resta-nos implementar esta aplicação empresarial no servidor Glassfish. Em seguida, o SGBD e o MySQL devem ser iniciados para que a fonte de dados JDBC «jdbc/dbrdvmedecins», utilizada pelo módulo EJB, fique acessível.
![]() |
- no [1], inicia-se o servidor Glassfish
- se o módulo EJB [serveur-ejb-dao-jpa-hibernate] estiver implementado, este é desativado [2]
- em [3], implementa-se a aplicação de e-business
![]() |
- em [4], a aplicação está implementada. Verifica-se que contém os dois módulos: Web e EJB.
4.10.2. Projeto NetBeans - versão 2
Mostramos agora 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 do serviço Web será o seguinte:
![]() |
Os elementos dignos de nota do projeto são os seguintes:
- [1]: o serviço web é implementado por um projeto NetBeans do tipo [Web Application].
- [2]: o serviço web é implementado pela classe [WsDaoJpa], já analisada
- [3]: o arquivo EJB da camada [dao], que permite à classe [WsDaoJpa] aceder às definições das diferentes classes, interfaces e entidades das camadas [dao] e [jpa].
Em seguida, criamos o projeto empresarial necessário para a implementação do serviço web:
![]() |
- [1], criamos uma aplicação empresarial [ea-rdvmedecins], inicialmente sem qualquer módulo.
- em [2], adicionamos o módulo web [serveur-webservice-ejb-dao-jpa-hibernate] anterior
- 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. É apresentado um erro. É, portanto, necessário implementar manualmente o arquivo EAR da aplicação [ea-rdvmedecins]:
![]() |
- o arquivo [ea-rdvmedecins.ear] encontra-se na pasta [dist] [2] do separador [Files] do NetBeans.
- Nesta pasta [3], encontram-se os dois elementos da aplicação empresarial:
- o arquivo do EJB [serveur-ejb-dao-jpa-hibernate]. Este arquivo está presente porque fazia parte das bibliotecas referenciadas pelo serviço web.
- o arquivo do serviço web [serveur-webservice- ejb-dao-jpa-hibernate].
- O arquivo [ea-rdvmedecins.ear] é constituído por um simples Build [4] da aplicação empresarial.
- No [5], a operação de implementação falha.
Para implementar o arquivo [ea-rdvmedecins.ear] da aplicação empresarial, procedemos tal como foi demonstrado durante a implementação do arquivo EJB [serveur-ejb-dao-jpa-hibernate.jar] no parágrafo 4.2. Utilizamos novamente o cliente web de administração do servidor GlassFish. Não repetimos os passos já descritos.
Em primeiro lugar, começaremos por «desinstalar» a aplicação empresarial implementada no parágrafo 4.10.1:
![]() |
- [1]: selecione o ramo [Enterprise Applications] 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 [Enterprise Applications] do servidor Glassfish
- em [2], implemente uma nova aplicação empresarial
- em [3], selecione o tipo [Enterprise Application]
- em [4], indique o ficheiro .ear do 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. Selecionamo-lo.
- em [8], temos várias informações sobre o serviço web. A informação mais interessante para um cliente é a [9]: o URI do serviço web.
- Em [10], é possível testar o serviço web
![]() |
- em [11], a URI do serviço web, à qual foi adicionado o parâmetro ?tester. Esta 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 solicita a lista de clientes.
![]() |
- No [14], apresentamos apenas uma visão parcial da página de resposta. No entanto, é possível verificar que o método getAllClients devolveu efetivamente a lista de clientes. A captura de ecrã mostra-nos que o serviço envia a sua resposta no formato XML.
Um serviço web é descrito na íntegra por um ficheiro XML denominado ficheiro WSDL:
![]() |
- em [1] na ferramenta de administração web do servidor Glassfish, selecione o serviço web [WsDaoJpa]
- em [2], siga a ligação [View WSDL]
![]() |
- em [3]: o URI do ficheiro WSDL. Esta é uma informação importante a ter em conta. É necessária para configurar os clientes deste 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 do serviço web
Criamos um projeto NetBeans para «executar» os testes já realizados com um cliente EJB, utilizando desta vez um cliente para o serviço web recentemente implementado. Seguimos aqui um procedimento semelhante ao descrito no parágrafo 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 do EJB para aceder às definições da interface da camada [dao] e das entidades JPA. Recorde-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 esquema acima, a camada [2] [C=Client] comunica com a camada [1] [S=Serveur]. Para comunicar com a camada [S], o cliente [C] tem de estabelecer uma ligação de rede com a camada [S] e comunicar com ela de acordo com um protocolo específico. As ligações de rede são do tipo TCP e o protocolo de transporte é o HTTP. A camada [S], que representa o serviço web, é implementada por um servlet Java executado pelo servidor Glassfish. Não fomos nós que escrevemos esta servlet. A sua geração é automatizada pelo Glassfish a partir das anotações @Webservice e @WebMethod da classe [WsDaoJpa] que escrevemos. Da mesma forma, vamos automatizar a geração da camada [C] do cliente. A camada [C] é por vezes designada como uma camada proxy do serviço web remoto, sendo que o termo proxy designa um elemento intermediário numa cadeia de software. Neste caso, o proxy C é o intermediário entre o cliente que iremos escrever e o serviço web que implementámos.
Com o NetBeans 6.5, o proxy C pode ser gerado da seguinte forma (para prosseguir, é necessário que o serviço web esteja ativo no servidor GlassFish):
![]() |
- em [1], adicionar um novo elemento ao projeto Java
- em [2], selecione o ramo [Web services]
- em [3], selecione [Web Service Client]
![]() |
- em [4], forneça o URI do ficheiro WSDL do serviço web. Este URI foi apresentado no parágrafo 4.10.2.
- em [5], mantenha o valor predefinido [JAX-WS]. O outro valor possível é [JAX-RPC]
- Após ter validado o assistente de criação do proxy do serviço web, o projeto NetBeans foi enriquecido com um ramo [Web Service References] [6]. Este ramo mostra os métodos expostos pelo serviço web remoto.
![]() |
- No separador [Files] [7], foram adicionados códigos-fonte Java [8]. Estes correspondem ao proxy C gerado.
- Em [9], o código de uma das classes. Pode-se ver em [10] que estas 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 serve de 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, essas chamadas locais são traduzidas em chamadas remotas.
Resta-nos 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 no teste do EJB da camada [dao]:
- na linha [13], o teste test1 é mantido na íntegra.
- na linha [9], o conteúdo do método [init] foi eliminado.
Nesta fase, o projeto apresenta erros porque o método de teste [test1] utiliza as entidades [Client], [Medecin], [Creneau], [Rv], que já não se encontram nos mesmos pacotes que anteriormente. Estão agora no pacote do proxy C gerado. Eliminam-se as instruções import em questão e regeneram-se através da operação «Fix Imports».
![]() |
Voltemos ao código da classe de teste [MainTestsDaoRemote]:
O método [init] da linha 10 deve inicializar a referência da camada [dao] da linha 7. Precisamos de saber como utilizar o proxy C gerado no nosso código. O NetBeans ajuda-nos neste processo.
![]() |
- Selecione, em [1], o método [getAllClients] do serviço web com o rato e, em seguida, arraste esse método para o colocar dentro do método [init] da classe de teste.
O resultado obtido é [2]. Este esboço de código mostra-nos como utilizar o proxy C gerado:
- A linha [5] mostra-nos que o método [getAllClients] é um método do objeto do tipo [WsDaoJpa] definido na linha 3. O tipo [WsDaoJpa] é uma interface que apresenta os mesmos métodos que os expostos pelo serviço web remoto.
- Na linha [3], o objeto [WsDaoJpa port] é 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 código está envolto num bloco try/catch.
- Os objetos do proxy C encontram-se no pacote [rdvmedecins.ws]
Depois de compreender este código, percebe-se que a referência local do serviço web remoto pode ser obtida através do código:
O código da classe de teste JUnit passa então a ser o seguinte:
Estamos agora prontos para os testes:
![]() |
No [1], o teste JUnit é executado. No [2], o teste é bem-sucedido. Se observarmos as mensagens na consola do NetBeans, encontramos 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 apresenta os diferentes campos de um objeto do tipo [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 dos respetivos métodos get/set. Assim, o método toString não foi gerado na entidade [Client] do proxy C. O que explica a exibição anterior. Isto não prejudica o teste JUnit: este foi bem-sucedido. Consideraremos, a partir de agora, que temos um serviço web operacional.






























































































