Escolar Documentos
Profissional Documentos
Cultura Documentos
Ejb 3 Tutorial
Ejb 3 Tutorial
0 Tutorial
Por Fabricio Braga
contato@fabriciobraga.com.br
http://www.fabriciobraga.com.br
O objetivo deste tutorial é mostrar de forma essencialmente prática, a configuração do ambiente, a
criação dos componentes EJB e os testes, usando JUnit.
A maioria dos tutoriais hoje descrevem as novas features da especificação EJB 3.0 focando na parte
das annotations e das inúmeras facilidades que o uso do Hibernate trouxe para o tratamento da
camada de persistência.
Eu senti alguma dificuldade quando comecei a desenvolver os componentes usando a especificação
EJB 3.0 na hora de configurar o ambiente. Como fazer a minha IDE processar corretamente as
annotations? Como fazer o deploy? Quais os melhores padrões para utilizar esta nova especificação?
Aqui veremos passoapasso, sem nenhum “salto lógico”, como fazer isso funcionar.
Espero, de verdade, que este tutorial ajude as pessoas e solucione facilmente para desenvolvedor
iniciante nessa nova especificação, as dúvidas que eu tive.
Fabricio Braga
http://www.fabriciobraga.com.br
Parte 1
Configurando o ambiente
Primeiro precisamos ter todas a ferramentas necessárias. Então vamos lá…
Lembrese de que para desenvolver EJB 3.0 será preciso utilizar o JDK 1.5 ou superior, por causa
das “annotations”. Caso você ainda não o tenha, baixe o JDK 1.5 aqui:
Baixe a última versão estável do Eclipse, aqui.
Baixe a versão do JBoss com a implementação da especificação EJB 3.0. Note que até a data em
que escrevi esse artigo, ainda havia sido lançado o release final da especificação 3.0, então o JBoss
implementa uma versão beta desta especificação. Baixe o JBoss Application Server aqui.
1 Instale o JDK 1.5
2 Descompacte o Eclipse em um diretório de sua preferência
3 Execute a instalação do JBoss, provelmente o pacote que você baixou é um “.jar”, então talvez
um simples duplo clique faça a instalação começar. Se não funcionar vá na linha de comando de
execute o comando:
$java jar nomedopacotejbossquevocebaixou
Será aberto um Wizzard, onde o JBoss pergunta qual o diretório de instalação e depois pergunta
quais a features que você quer instalar, selecione a opção “ejb3″(conforme a figura abaixo). O
wizzard vai descompactar o JBoss, com as features do EJB 3.0 para o diretório selecionado por
você.
http://www.fabriciobraga.com.br
http://www.fabriciobraga.com.br
Parte 2
Agora é hora de começar a desenvolver!
Abra o Eclipse e crie um projeto Java, simples, vazio. Você pode fazer isso no menu:
“File” > “New Project…” e selecionando a opção “Java Project”.
Escolha um nome para o seu projeto e clique em “finish”, não precisa setar mais nada, por
enquanto.
Um projeto novo apereceu agora, na aba “Package Explorer”, do lado esquerdo do seu Eclipse.
Agora precisamos configurar os diretórios de fonte e de output do seu projeto. Clique com o botão
direito em cima dele e selecione “Properties”.
Uma janela se abrirá, no menu do lado esquerdo selecione a opção “Java build path”, algumas
opções aparecerão do lado direito, certo? Selecione a aba “source”. Nela você escolhe os diretórios
de fonte e de output do seu projeto.
Para este tutorial, criaremos um diretório chamado “src”, clique em “add folder…” do lado direito, e
na caixa de diálogo que se abre entre com o nome dele, “src”. Provavelmente após fazer isso, a
“Default output folder”, ali embaixo, foi automaticamente configurada para “SeuProjeto/bin”. Se
sim, feche a janela, clicando em “ok”.
Caso não seja esta a pasta, clique em “Browse” e crie uma pasta chamada “bin”, imediatamente
abaixo da pasta do projeto.
Criando nosso primeiro Session…
Chega de enrolação agora, vamos escrever código! Crie um pacote para seus Sessions, clicando com
o botão direito em cime do diretorio “src”, que é o nosso diretório de fontes, e selecione “new” >
“package”.
Crie um pacote com o nome “com.model.ejb.session”
Crie uma classe nesse pacote, chamada “UsuarioServiceBean”:
http://www.fabriciobraga.com.br
package com.model.ejb.session;
@Stateless
public class UsuarioServiceBean {
...
}
Aquela “annotation” em cima do nome da classe indica que tratase de um SessionBean do tipo
Stateless. Inicialmente o Eclipse não vai reconhecela, e vai indicar um erro ali, resolveremos isso
adicionando ao path do seu projeto o “jar” com essa classe.
Crie um diretório chamado “lib” imediatamente abaixo do diretório do seu projeto. Copie para
dentro deles o jar “ejb3x.jar” que fica dentro diretório de instalação do JBoss:
jboss/server/default/deploy/ejb3.deployer
Note que a rigor não é necessário copiar esse jar para cá, como alternativa você poderia
simplesmente adicionar um jar externo ao seu java build path. Mas eu pessolamente prefiro assim,
porque facilitará muito quando formos empacotar nossa aplicação com ajuda do ant, e evita
problemas com path se por acaso você levar seu projeto para outra máquina, onde o diretório do
JBoss pode ser diferente.
Agora faça o seguinte, clique com botão direito em cima do seu projeto, e depois em “properties”,
no menu ” Java build path”, selecione a aba “Libraries”, nela você vai adicionar o jar utilizando
“add jars” e selecionando o nosso “ejb3x.jar”.
Volte à nossa classe “UsuarioServiceBean”, que estava com erro, e use o recurso “organize imports”
do Eclipse, pode ser pelas teclas de atalho “Ctrl+Shift+O”. Nossa classe agora ficará assim:
package com.model.ejb.session;
import javax.ejb.Stateless;
@Stateless
public class UsuarioServiceBean {
E não devem haver mais erros.
Ok, agora deixeme dar uma breve explicação de um tópico muito importante, que são as interfaces
locais e remotas do seu EJB. Todo EJB pode ter interfaces do tipo “Local” ou “Remote”, e é por
estas interfaces que o cliente acessa os métodos do seu componente.
É considerado “local” tudo o que estiver na mesma VM (Virtual Machine). Então suponha, por
exemplo que você tenha um Tomcat, com alguns Servlets rodando em uma aplicação na sua
máquina e um JBoss, na mesma máquina, com seus componentes EJB.
http://www.fabriciobraga.com.br
A pergunta é: o meu Servlet que está lá dentro do Tomcat vai acessar os meus componentes EJB de
maneira local ou remota?
Provavelmente remota.
O que ocorre é que muito provavelmente estes dois containers, por estarem separados, foram
startados por VMs diferentes. O que não ocorre por exemplo se os seus Servlets estiverem dentro do
JBoss (O JBoss possui um módulo do Tomcat dentro dele), quando então ambos estarão na mesma
VM.
E porque você precisa de uma interface para os seus componentes?
Bem, uma das vantagens de usar componentes remotos é que você pode disponibilizalos para seus
clientes sem que eles tenham acesso a implementação dos métodos e às suas regras de negócio.
Então certamente você não vai enviar para o seu cliente um pacote com seus Session Beans, certo?
Na prática o que você fará é disponibilizar um pacote para o cliente com suas interfaces remotas,
para que ele acesse seus métodos de negócio, apenas.
Detalhes da implementação são problema seu, não dele.
Então vamos agora escrever uma interface remota, com os métodos de negócio para que nossos
clientes possam acessar nosso SessionBean. Crie um pacote chamado “com.service”, e crie uma
interface chamada “UsuarioService”:
package com.service;
import javax.ejb.Remote;
@Remote
public interface UsuarioService {
}
A anotation “@Remote” indica que tratase de uma interface do tipo “Remote” para a classe que a
implementa. Vamos também adicionar um método a ela:
package com.service;
import java.rmi.RemoteException;
import javax.ejb.Remote;
@Remote
public interface UsuarioService {
public String getMessage() throws RemoteException;
}
http://www.fabriciobraga.com.br
Agora, o nosso UsuarioServiceBean deve implementar a interface, vamos fazer mais algums
modificações nele:
package com.model.ejb.session;
import java.rmi.RemoteException;
import javax.ejb.Stateless;
import com.service.UsuarioService;
@Stateless
public class UsuarioServiceBean implements UsuarioService{
public String getMessage() throws RemoteException {
return “don’t worry buddy it is just a test…”;
}
}
Repare que agora ele implementa a interface, e adicionamos um código bem simples ao método de
negócio.
O próximo passo é configurar o ant para automatizarmos o processo de compilação, teste e deploy
da nossa aplicação. Crie um arquivo chamado “build.xml” no diretório principal do nosso projeto,
esse será o aqruivo de build do ant.
Vamos editar o arquivo da seguinte forma:
<?xml version="1.0"?>
<project name="EJBTutorial" basedir="." default="init">
<target name="init">
<echo>Iniciando build do EJB tutorial</echo>
</target>
</project>
Iniciando build do EJB tutorial
É muito importante que não haja nenhum espaço ou tabulação antes da primeira linha “” porque
isso gera um erro no processamento do arquivo pelo ant. A partir disso, espaços ou tabulações serão
ignoradas, apenas nessa primeira linha temos esta restrição.
O atributo “basedir”:
basedir=”.”
indica que estamos no diretŕoio raiz do projeto, algumas pessoas (inclusive eu) preferem colocar o
arquivo build do ant em um diretório separado, chamado normalmente de “METAINF”. Mas tenho
como objetivo neste tutorial simplificar o máximo possível, então vamos deixar ele aqui mesmo.
http://www.fabriciobraga.com.br
Temos agora um arquivo de build do Ant bastante básico, que na verdade não faz muita coisa,
apenas imprime na tela a mensagem “Iniciando build do EJB tutorial”. entretanto o Ant é uma
bastante poderosa, e vamos utilizar um pouco mais de recursos dele, vamos setar algumas
propriedades dele começando pelos diretórios de fonte, output e lib da nossa aplicação e também
algumas “targets”:
<?xml version="1.0"?>
<project name="EJBTutorial" basedir="." default="init">
<property name="src" value="src"/>
<property name="bin" value="bin" />
<property name="lib" value="lib" />
<path id="classpath.base">
<fileset dir="${lib}">
<include name="*.jar" />
</fileset>
</path>
<target name="init">
<echo>Iniciando build do EJB tutorial</echo>
</target>
<target name="clean" depends="init">
<delete dir="${bin}">
</delete>
</target>
<target name="prepare" depends="init">
<mkdir dir="${bin}" />
</target>
<target name="compile" depends="init, clean, prepare">
<javac srcdir="${src}" destdir="${bin}" verbose="false">
<classpath refid="classpath.base" />
</javac>
</target>
</project>
Agora nosso arquivo ganhou alguma utilidade, de fato. Adicionamos “targets” a ele que fazem
algum trabalho para nós, como limpar o diretório de output e compilar nossas classes.
Vamos fazer uma análise rápida delas:
http://www.fabriciobraga.com.br
<property name="src" value="src"/>
<property name="bin" value="bin" />
<property name="lib" value="lib" />
Aqui o que fizemos foi setar algumas propriedades do Ant, que facilitarão nossa vida porque
substituem os nomes de diretórios por variáveis, que podem ser referenciadas. Nesse caso, não
percebemos muita vantagem porque os diretórios são simples, e estão dentro do nosso projeto, só
que mais adiante vamos adicionar mais variáveis e você perceberá de forma mais clara a verdadeira
vantagem de usarmos estas propriedades.
<path id="classpath.base">
<fileset dir="${lib}">
<include name="*.jar" />
</fileset>
</path>
Aqui setamos o classpath para a compilação, com o nosso diretório “lib” e todos os jars que
estiverem dentro dele. Perceba que aqui já fazemos uso da variável que setamos anteriormente.
<target name="clean" depends="init">
<delete dir="${bin}">
</delete>
</target>
Esta target existe apenas para garantir que antes de iniciar o processo de compilação estaremos
limpando tudo o que existe no diretório de output.
<target name="compile" depends="init, clean, prepare">
<javac srcdir="${src}" destdir="${bin}" verbose="false">
<classpath refid="classpath.base" />
</javac>
</target>
Aqui a mais importante delas, a compilação das nossas classes. Note que fazemos referência ao
classpath que setamos antes, para que o compilador utilize as classes do nosso diretório “lib”.
Agora, no Eclipse, clique com o botão direito no arquivo “build.xml”, e depois no menu “Run
As…” > “Ant Build”
Na janela de opções que se abre, selecione apenas a target “compile”, desmarque todas as outras, e
clique em “run”.
Você verá o Ant sendo executado, e algumas informações sobre o processamento deverão aparecer,
ao final a mais importante é:
“BUILD SUCCESSFUL”
http://www.fabriciobraga.com.br
Parte 3
Agora que já temos nossa interface remota e nosso UsuarioServiceBean prontos, e compilando,
podemos passar para a parte da implementação deles.
Crie um diretório chamado “jar” imediatamente abaixo do diretório do seu projeto. Nesse diretório
vamos colocar o pacote com os nossos EJBs.
Por definição, o pacote com os SessionBean tem a extensão “*.ejb3″, é por nele que o JBoss vai
procurar seus Sessions, então para facilitar nossa vida vamos criar mais um propriedade no nosso
build.xml do Ant, e também mais uma importante target, que vai empacotar nossos Sessions nosso
arquivo agora ficará assim:
<?xml version="1.0"?>
<project name="EJBTutorial" basedir="." default="init">
<property name="src" value="src"/>
<property name="bin" value="bin" />
<property name="lib" value="lib" />
<property name="session.jar.file" value="jar/business.ejb3"/>
<path id="classpath.base">
<fileset dir="${lib}">
<include name="*.jar" />
</fileset>
</path>
<target name="init">
<echo>Iniciando build do EJB tutorial</echo>
</target>
<target name="clean" depends="init">
<delete dir="${bin}">
</delete>
</target>
<target name="prepare" depends="init">
<mkdir dir="${bin}" />
</target>
<target name="compile" depends="init, clean, prepare">
<javac srcdir="${src}" destdir="${bin}" verbose="false">
<classpath refid="classpath.base" />
</javac>
</target>
http://www.fabriciobraga.com.br
<! Empacota os SessionBeans >
<target name="packageejbsession" depends="compile">
<jar jarfile="${session.jar.file}">
<fileset dir="${bin}">
<include name="com/**"/>
</fileset>
</jar>
</target>
</project>
Perceba que agora nós temos uma nova propriedade, onde setamos o nome do nosso arquivo que vai
conter os Sessions e as interfaces, e o diretório onde ele vai ficar. Não é muito difícil de entender.
O atributo:
name=”com/**”
Diz para o Ant que ele deve incluir todos os subdiretórios e arquivos abaixo do pacote “com” no
nosso pacote.
Execute novamente o build do Ant, mas desta vez marque apenas a target “packageejbsession”, e
desmarque todas as outras. Ao final, se tudo correr bem ele terá gerado um arquivo chamado
“business.ejb3″ dentro do diretório “jar”.
Para fazer o deploy, basta copiar esse arquivo para o diretório “deploy” da sua aplicação no JBoss,
ele é provavelmente esse:
jboss/server/default/deploy
Você pode copialo para lá mesmo com JBoss já rodando, não precisa reiniciar o JBoss só para fazer
isso. Em geral para fazer simples deploys de seus pacotes de EJB ou WARs no JBoss você não
precisa reinicialo, isso é necessário apenas quando alterar arquivos de configuração, como
datasources por exemplo.
Mas eu como sou extremamente preguiçoso, prefiro deixar o Ant fazer até mesmo esse deploy para
mim, então acrescento duas coisas muito simples ao meu “build.xml”. Primeiro uma propriedade,
com o diretŕoio de deploy da minha aplicação:
<property name="deploy.home" value="/home/fabricio/jboss
4.0.3SP1/server/ejbtutorial/deploy"/>
Atenção:
O caminho do diretório é o da minha máquina, você deve substituilo pelo seu diretório no seu
JBoss. O diretório “ejbtutorial” que vem entre “server” e “deploy” é o diretório da configuração
para esta minha aplicação. Talvez na sua máquina seja “default” ou outro que você possa ter
escolhido durante o wizard de instalação do Jboss.
Agora adicionamos a target que vai copiar o arquivo para lá:
<target name="deployejb" depends="packageejbsession">
http://www.fabriciobraga.com.br
<copy file="${session.jar.file}" todir="${deploy.home}" />
</target>
Pronto, agora ao executarmos o Ant, marcamos apenas a target “deployejb”, e o Ant fará tudo.
Bem facil, não?
Apenas para recaptular, no final nosso arquivo do Ant ficou assim:
<?xml version="1.0"?>
<project name="EJBTutorial" basedir="." default="init">
<property name="src" value="src"/>
<property name="bin" value="bin" />
<property name="lib" value="lib" />
<property name="session.jar.file" value="jar/business.ejb3"/>
<property name="deploy.home" value="/home/fabricio/jboss4.0.3SP1/server/dmgestao/deploy"/>
<path id="classpath.base">
<fileset dir="${lib}">
<include name="*.jar" />
</fileset>
</path>
<target name="init">
<echo>Iniciando build do EJB tutorial</echo>
</target>
<target name="clean" depends="init">
<delete dir="${bin}">
</delete>
</target>
<target name="prepare" depends="init">
<mkdir dir="${bin}" />
</target>
<target name="compile" depends="init, clean, prepare">
<javac srcdir="${src}" destdir="${bin}" verbose="false">
<classpath refid="classpath.base" />
</javac>
</target>
<! Empacota os SessionBeans >
<target name="packageejbsession" depends="compile">
<jar jarfile="${session.jar.file}">
<fileset dir="${bin}">
http://www.fabriciobraga.com.br
<include name="com/**"/>
<exclude name="com/dmgestao/testes/**"/>
<exclude name="com/dmgestao/model/ejb/entity/**"/>
</fileset>
</jar>
</target>
<target name="deployejb" depends="packageejbsession">
<copy file="${session.jar.file}" todir="${deploy.home}" />
</target>
</project>
Execute o build.xml, apenas com a target “deployejb” marcada, e observe o console do JBoss, você
deverá ver algo assim:
17:55:43,118 INFO [JaccHelper] Initialising JACC Context for deployment: business.ejb3
17:55:43,165 INFO [Ejb3AnnotationHandler] found EJB3:
ejbName=com.model.ejb.session.UsuarioServiceBean,
class=com.model.ejb.session.UsuarioServiceBean, type=STATELESS
17:55:43,225 INFO [JaccHelper] com.model.ejb.session.UsuarioServiceBean has no
@SecurityDomain skipping JACC configuration
17:55:43,226 INFO [JaccHelper] JACC Policy Configuration for deployment has been put in
service
17:55:43,226 INFO [Ejb3Deployment] EJB3 deployment time took: 108
17:55:43,235 INFO [ProxyDeployer] no declared remote bindings for :
com.model.ejb.session.UsuarioServiceBean
17:55:43,236 INFO [ProxyDeployer] there is remote interfaces for
com.model.ejb.session.UsuarioServiceBean
17:55:43,236 INFO [ProxyDeployer] default remote binding has jndiName of
com.service.UsuarioService
17:55:43,344 INFO [EJB3Deployer] Deployed: file:/home/fabricio/jboss
4.0.3SP1/server/ejbtutorial/deploy/business.ejb3
Isso significa que o deploy ocorreu sem problemas.
http://www.fabriciobraga.com.br
Criando um Client para o nosso Stateless
SessionBean
Agora, com o nosso componente rodando no servidor, precisamos testalo e acessalo. Vamos agora
escrever um cliente que possa acessar o componente e seus métodos de negócio. O nosso cliente
precisará conectarse ao serviço de nomes (JNDI) e encontrar o nosso componente.
Para usarmos uma abordagem mais de acordo com o que acontece no mundo real durante o
desenvolviemnto de um sistema, vamos criar um “ServiceLocator”.
ServiceLocator é uma pattern que nos poupa o trabalho de pegar o InitialContext toda vez que
quisermos uma interface para um objeto de negócio. Imagine que toda vez que você for acessar um
componente EJB você faça assim:
try {
Hashtable t = new Hashtable();
t.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
t.put(Context.PROVIDER_URL, "localhost");
t.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
initialContext = new InitialContext(t);
UsuarioService usuarioService = (UsuarioService)
initialContext.lookup(UsuarioService.class.getName());
} catch (Exception exc) {
exc.printStackTrace();
}
}
É evidente que isso faria o nosso código ficar demasiadamente grande. Por isso concentramos o
processo de “procurar” o objeto no serviço de nomes em um Singleton, que fará esse trabalho para
nós.
Crie uma classe chamada “ServiceLocator, dentro do pacote “com.service”. Aqui o nosso
ServiceLocator:
package com.service;
import java.util.HashMap;
import java.util.Hashtable;
import javax.ejb.EJBHome;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
http://www.fabriciobraga.com.br
public class ServiceLocator {
private HashMap homes = new HashMap();
private static ServiceLocator locator;
private InitialContext initialContext;
private ServiceLocator() {
try {
Hashtable t = new Hashtable();
t.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
t.put(Context.PROVIDER_URL, "localhost");
t.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
initialContext = new InitialContext(t);
} catch (Exception exc) {
exc.printStackTrace();
}
}
public static ServiceLocator getInstance() {
if (locator == null) {
locator = new ServiceLocator();
}
return locator;
}
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException(
"Nao e possivel clonar o ServiceLocator!");
}
public Object get(String jndiName) throws Exception {
try {
Object result = null;
result = initialContext.lookup(jndiName);
if(result==null) {
if (result==null) {
throw new NamingException();
}
}
return result;
} catch (NamingException e) {
e.printStackTrace();
}
return null;
}
}
http://www.fabriciobraga.com.br
Agora vamos criar uma classe teste, pa
ra acessar o nosso objeto, crie um pacote chamado “com.testes” e nele uma classe chamada
“TestUsuario”:
package com.testes;
import com.service.ServiceLocator;
import com.service.UsuarioService;
public class TestUsuario {
public static void main (String...args){
try{
UsuarioService usuario =
(UsuarioService)ServiceLocator.getInstance().get(UsuarioService.class.getName());
System.out.println(usuario.getMessage());
}
catch (Exception e){
e.printStackTrace();
}
}
}
Vamos precisar adicionar ao build path do nosso projeto 2 arquivos jars, localizados no diretorio de
instalação do JBoss:
jboss/client/jbossallclient.jar
jboss/server/default/deploy/jbossaop.deployer/jbossaspectlibraryjdk50.jar
Feito isso, podemos executar nossa classe de teste e veremos a mensagem contida na implementação
do método do nosso componente.
Fabricio Braga
http://www.fabriciobraga.com.br