Neste artigo vou mostrar como criar um projeto EJB 3 bem simples usando
Maven 2. Vamos fazer o deploy no JBoss 5.o.1.GA através do plugin do
maven do cargo. Além disso vamos criar um projeto cliente que acessa o
EJB criado através de JNDI.
Meu objetivo é mostrar, de uma
maneira simples e que funciona, como usar maven 2 com projetos ejb3,
de barbada vamos fazer o deploy no JBoss 5.0.1.GA. No final do texto você
irá encontrar os códigos fontes e bem como as dependências (jars) da
aplicação cliente.
Criar uma aplicação Java com Maven é
realmente muito mais fácil quando falamos de fazer um deploy no
servidor com o cargo, usando o plugin do maven as coisas não são tão
simples, porque a documentação do Cargo não é 100% intuitiva e faltam
exemplos práticos de como usar as configurações. Além disso o JBoss 5
ainda não está 100% com o maven 2, mais para frente do post vocês irão
entender o porquê disso.
Cuidado com o JDK
Recomendo que você use um JDK acima do JDKu10, eu estou usando no momento o JDKu13.
Caso você use um inferior ao JDKu10 você terá sérios problemas para
subir o comtainer do JBoss 5. Existem diversos posts em blogs e
tutoriais na web que recomendam você colocar os jars do jaxb e jaxws no
diretório endorsed da jvm, para mim isso não funcionou. A melhor saída
é usar um JDK mais novo.
Nota: Até por que o JDK tem uma performance melhor do que as dos anteriores e recursos bem interessantes em termos de ferramentas.
O Projeto EJB 3
Nesse
projeto vamos criar uma interface de negócio chamada de DateService.
Essa interface é simples e seu objetivo é representar o contrato de um
serviço de datas, que informa através de uma String a data atual do
container. Vamos ao código da interface:
package com.blogspot.diegopacheco.services;
/**
* Interface de Servico de Data
*
* @author Diego Pacheco
* @version 1.0
* @since 03/05/2009
*
*/
public interface DateService {
public String getDateTime();
}
Agora vamos à implementação do EJB 3. Vou usar os novos recursos do EJB 3 em termos de anotações. Vamos ver o código então:
package com.blogspot.diegopacheco.services;
import java.util.Date;
import javax.ejb.Remote;
import javax.ejb.Stateless;
/**
* Stateless Session Bean que eh uma implementacao do Servico de Data
*
* @author Diego Pacheco
* @version 1.0
* @since 03/05/2009
*
*/
@Stateless
@Remote(DateService.class)
public class DateServiceBean implements DateService{
public String getDateTime() {
return new Date().toString();
}
}
Como podem ver a implementação é simples, porque o meu objetivo é mostrar como integrar e usar essas tecnologias. Muito bem, agora vamos ao pom do maven desse projeto:
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.blogspot.diegopacheco</groupid>
<artifactid>mvn2-jboss5-ejb3</artifactid>
<version>1.0-SNAPSHOT</version>
<packaging>ejb</packaging>
<name>Maven 2 + EJB 3.0 + Jboss 5</name>
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<inherited>true</inherited>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-source-plugin</artifactid>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-ejb-plugin</artifactid>
<configuration>
<ejbversion>3.0</ejbversion>
</configuration>
</plugin>
<plugin>
<groupid>org.codehaus.cargo</groupid>
<artifactid>cargo-maven2-plugin</artifactid>
<version>0.3-SNAPSHOT</version>
<configuration>
<wait>false</wait>
<container>
<containerid>jboss4x</containerid>
<type>remote</type>
</container>
<type>runtime</type>
<home>D:/Diego/Java/bin/jboss-5.0.1.GA/server/default</home>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupid>javax.ejb</groupid>
<artifactid>ejb-api</artifactid>
<version>3.0</version>
</dependency>
</dependencies>
</project>
Vocês podem ver que
estou usando o plugin de ejb do maven e bem como o plugin do cargo. Não
repare ao onde diz ‘jboss4x’ pois isso funciona no JBoss 5. Na
propriedade ‘home’ você tem que apontar para a sua intalação do JBoss 5.
Agora suba o JBoss 5.0 pelo console e após o JBoss ter subido execute os seguintes goals do maven:
mvn clean install cargo:deploy
Com
o ‘cargo:deploy’ você irá fazer o deploy do seu ejb no JBoss 5 através
do plugin do cargo do maven. Agora verifique no console do JBoss5, ele
deve ter mostrado algo parecido com isso:
20:26:11,545 INFO [MainDeployer] deploy, url=file:/D:/Diego/workspace-gps/mvn2-jboss5-ejb3/target/mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar
20:26:11,717 INFO [Ejb3DependenciesDeployer] Encountered deployment AbstractVFSDeploymentContext@19623251{vfszip:/D:/Diego/workspace-gps/mvn2-jboss5-ejb3/target/mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar/}
20:26:11,718 INFO [Ejb3DependenciesDeployer] Encountered deployment AbstractVFSDeploymentContext@19623251{vfszip:/D:/Diego/workspace-gps/mvn2-jboss5-ejb3/target/mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar/}
20:26:14,862 INFO [JBossASKernel] Created KernelDeployment for: mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar
20:26:14,871 INFO [JBossASKernel] installing bean: jboss.j2ee:jar=mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar,name=DateServiceBean,service=EJB3
20:26:14,871 INFO [JBossASKernel] with dependencies:
20:26:14,871 INFO [JBossASKernel] and demands:
20:26:14,872 INFO [JBossASKernel] jboss.ejb:service=EJBTimerService
20:26:14,872 INFO [JBossASKernel] and supplies:
20:26:14,872 INFO [JBossASKernel] jndi:DateServiceBean/remote-com.blogspot.diegopacheco.services.DateService
20:26:14,872 INFO [JBossASKernel] jndi:DateServiceBean/remote
20:26:14,872 INFO [JBossASKernel] Class:com.blogspot.diegopacheco.services.DateService
20:26:14,872 INFO [JBossASKernel] Added bean(jboss.j2ee:jar=mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar,name=DateServiceBean,service=EJB3) to KernelDeployment of: mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar
20:26:15,068 INFO [SessionSpecContainer] Starting jboss.j2ee:jar=mvn2-jboss5-ejb3-1.0-SNAPSHOT.jar,name=DateServiceBean,service=EJB3
20:26:15,086 INFO [EJBContainer] STARTED EJB: com.blogspot.diegopacheco.services.DateServiceBean ejbName: DateServiceBean
20:26:15,169 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
DateServiceBean/remote - EJB3.x Default Remote Business Interface
DateServiceBean/remote-com.blogspot.diegopacheco.services.DateService - EJB3.x Remote Business Interface
Agora
podemos ir para o projeto ejb-client. Nesse projeto vamos usar maven,
mas será necessário o uso de bibliotecas fora as do maven.
Por que não usar Maven no Ejb3-Client?
Porque ao utilizar os repositórios do maven do JBoss que são:
- http://repository.jboss.org/maven2/
- http://repository.jboss.com/maven2/
Até
existem os jars necessários para o uso da aplicação de ejb cliente com
JBoss 5.0.1.GA. Porém os jars estão em versões mais antigas do que as
bibliotecas que existem no JBoss 5.0.1.GA, você pode conferir isso, vá
nesses diretórios:
- $JBOSS_HOME/lib
- $JBOSS_HOME/common/lib
Atualmente as dependências dos repositórios do jboss acima não são compatíveis,
são de versões mais antigas, mas não são todas as bibliotecas, são
algumas. Para não ficar com o projeto capenga resolvi usar essas
dependências da maneira tradicional criando uma pasta lib e a
adicionando ao classpath no eclipse.
A Classe de testes do
projeto cliente chama o ejb através e um lookup JNDI feito por uma
classe helper chamada de ServiceLocator que, por sinal, é um padrão de
design da sun.
package com.blogspot.diegopacheco.services;
import org.junit.Test;
import com.blogspot.diegopacheco.services.DateService;
/**
* Classe de testes unitarios que usa o ejb 3.
*
* @author Diego Pacheco
* @version 1.0
* @since 03/05/2009
*
*/
public class ClientEjb3Test {
@Test
public void testDateServiceAsGetDate(){
try{
System.out.println("Inicio dos testes.");
DateService ds = ServiceLocator.getServiceRemote(DateService.class);
System.out.println("A Data retornada do EJB eh:" + ds.getDateTime());
System.out.println("Fim dos testes.");
}catch(Throwable t){
t.printStackTrace();
}
}
}
Vamos à classe de
ServiceLocator. Essa classe é genérica e melhora a qualidade do código,
mas para isso você deve criar as suas implementações de ejb com o sufixo
Bean.
package com.blogspot.diegopacheco.services;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* Classe utitilária para recuperação de EJBs.
*
* @author Diego Pacheco
* @version 1.0
* @since 03/05/2009
*
*/
public class ServiceLocator {
public static final String RemoteJNDIName = "Bean/remote";
private static String BASE;
private static FileInputStream PATH_SIMPLE;
private static String BASE_PATH;
private static Context context;
static{
try {
BASE = new File(".").getCanonicalPath();
BASE_PATH = BASE + "/src/main/resources/jndi.properties";
PATH_SIMPLE = new FileInputStream(new File(BASE_PATH));
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
static{
try
{
Properties properties = new Properties();
try {
properties.load(PATH_SIMPLE);
properties.list(System.out);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
context = new InitialContext(properties);
} catch (NamingException e){
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static <t> T getServiceRemote(Class clazz) throws NamingException{
T temp = (T)context.lookup( clazz.getSimpleName() + RemoteJNDIName );
return temp;
}
}
As configurações de JNDI estão em um arquivo properties. São as configurações default para o JBoss.
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
E, por fim, vamos ver o pom desse projeto. Perceba que as dependências não estão aqui:
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.blogspot.diegopacheco</groupid>
<artifactid>mvn2-jboss5-ejb3-client</artifactid>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Maven 3 + EJB3 + Jboss 5 Client</name>
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<inherited>true</inherited>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-source-plugin</artifactid>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.3</version>
</dependency>
<!-- Dependencia ao projeto EJB3 por conta das interfaces. -->
<dependency>
<groupid>com.blogspot.diegopacheco</groupid>
<artifactid>mvn2-jboss5-ejb3</artifactid>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Os Jars necessários ao projeto cliente são:
- concurrent.jar
- jboss-aop.jar
- jboss-common-core.jar
- jboss-ejb3-common.jar
- jboss-ejb3-core.jar
- jboss-ejb3-proxy.jar
- jboss-ejb3-security.jar
- jboss-integration.jar
- jboss-javaee.jar
- jboss-logging-spi.jar
- jboss-remoting.jar
- jboss-remoting-aspects.jar
- jboss-security-spi.jar
- jbosssx.jar
- jboss-transaction-aspects.jar
- jnpserver.jar
Como eu já disse antes você acha esses jars aqui: $JBOSS_HOME/lib e e $JBOSS_HOME/common/lib.
Ok,
podemos rodar a classe client, perceba que ela é uma classe de testes
do Junit. Vamos rodar o teste, o resultado deve ser algo como esse:
Inicio dos testes.
-- listing properties --
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
A Data retornada do EJB eh:Sun May 03 20:50:37 BRT 2009
Fim dos testes.
Você pode pegar os fontes completos no meu repositório do Subersion. São esses urls:
- http://diegopacheco.svn.beanstalkapp.com/sandbox/trunk/mvn2-jboss5-ejb3
- http://diegopacheco.svn.beanstalkapp.com/sandbox/trunk/mvn2-jboss5-ejb3-client
Espero que tenham gostado. A idéia é, na sequência, adaptar esse projeto para funcionar no Websphere e no ORACLE weblogic.
Abraços e até a próxima.