EJBs compartilhados

15 respostas
danieldestro

Caros,

Tenho uma aplicação (vulgo App1), que possui uns EJBs e umas interfaces Home e Remote.
Minha outra aplicação (App2 - outro EAR) tem um EJB que implementa as interfaces (home e remote) da App1.
Porém dá erro quando eu faço deploy da App2.
Há como fazer isso? Um EJB de um App2 usar as interfaces de outra App1?

Abraços


Redefinindo o problema:

Eu tenho uma aplicação chamada GPA, que possui alguns EJBs (Session e MDB) e uma aplicação WEB. Tudo empacotado em um EAR. A estrutura do EAR está mais ou menos assim:

EAR |-- gpa-ejb.jar (EJBs e interfaces) |-- gpa.war (JSPs) |-- lib | |-- outros arquivos JAR | |-- META-INF |-- application.xml |-- jboss-app.xml

No MANIFEST.MF do gpa-ejb.jar eu faço referência para uns JARs dependentes que estão no lib.

Tudo funciona bem.

Eu também tenho outra aplicação, chamada CGE. Esta aplicação CGE possui um EJB, onde as suas interfaces (home e remote) configuradas, são interfaces do projeto GPA (gpa-ejb.jar).

Porém, quando eu faço o deploy do CGE, ele reclama que não achou as interfaces deste EJB.

Como eu poderia indicar que ele usa as interfaces disponíveis no GPA? Qual a melhor estratégia?

Nota: O GPA vai invocar esse EJB do CGE. São aplicações que dependem dos EJBs umas das outras.

Estou usando JBoss 3.0.3.

Abraços

15 Respostas

louds

Qual AS? Qual estratégia de classloading?
São EARs diferentes ou módulos ejb diferentes?
Voce não tá apanhando o UCL do jboss, né?

danieldestro

Estou usando o JBoss.
A app GPA vai em um EAR e a app CGE vai em outro EAR.

louds

Qual esquema de classloaders vc tá usando? Nenhum? Ai vc tem o UCL maldito que coloca tudo no mesmo espaço de nomes…

danieldestro

Que eu saiba não to usando nada de Classloader, pelo menos não explicitamente.

Na App1 eu joguei todas as minhas classes num único JAR (inclusive o EJB) e joguei o JAR direto no EAR, e no application.xml eu defini ele como meu JAR de EJB.

Os JARs de terceiros que eu uso, eu coloquei no EAR, dentro da pasta lib e informei isso no application.xml também.

Na App2 está mais ou menos assim tbm.

louds

Com UCLl, o classloader padrão do jboss, você tem 1 espaço de nomes achatado, ou seja, todas aplicações compartilham todas suas classes.

Você pode simplesmente usar as classes que tão no App1 do App2; ou então configurar o esquema de classloading das tuas 2 aplicações para elas usarem espaços de nomes para classes diferentes, é importante que você faça isso nas 2, senão pode acabar com bugs que dependem da ordem de deployment.

danieldestro

Essa config de espaços de nomes é feito naquele arquivo jboss-app.xml que vai no EAR?

E outra. Se a App1 pode acessar as classes de App2, porque isso não ocorre?
Devo mencionar no Class-Path do MANIFEST.MF do jar dos EJBs da aplicação?

louds

Não lembro onde exatamente configura, mas nada que 2min de google não resolva.

Com UCL todos as classes ficam automáticamente visiveis, não precisa colocar no mafinest.mf nem nada.

Qual erro de deploy tá rolando?

danieldestro

Valeu Louds. Eu redefini o meu post inicial. Se quiser dar uma olhada.

Vou procurando no Google enquanto isso.

danieldestro

Ví isso no site do JBoss ([url]http://www.jboss.org/wiki/Wiki.jsp?page=ClassLoadingConfiguration[/url]):

Accessing ejbs in isolated ears

If you want to make jndi lookups across ears that are isolated, you need to force marshalling of the lookup, e.g. if you have the following ejb-ref in your ejb-jar.xml that references an ejb in an isolated ear

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC 
"-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" 
"http://java.sun.com/dtd/ejb-jar_2_0.dtd"> 

<ejb-jar> 
<enterprise-beans> 
<session> 
<ejb-name>SessionA</ejb-name> 
<home>org.jboss.test.isolation.interfaces.a.SessionAHome</home> 
<remote>org.jboss.test.isolation.interfaces.a.SessionA</remote> 
<ejb-class>org.jboss.test.isolation.ejb.a.SessionAEJB</ejb-class> 
<session-type>Stateless</session-type> 
<transaction-type>Container</transaction-type> 
<ejb-ref> 
<ejb-ref-name>ejb/SessionB</ejb-ref-name> 
<ejb-ref-type>Session</ejb-ref-type> 
<home>org.jboss.test.isolation.interfaces.b.SessionBHome</home> 
<remote>org.jboss.test.isolation.interfaces.b.SessionB</remote> 
</ejb-ref> 
</session> 
</enterprise-beans> 
</ejb-jar>

in jboss.xml use the full scheme to define the lookup

<?xml version="1.0" encoding="UTF-8"?>

<jboss> 
<enterprise-beans> 
<session> 
<ejb-name>SessionA</ejb-name> 
<ejb-ref> 
<ejb-ref-name>ejb/SessionB</ejb-ref-name> 
<jndi-name>jnp://localhost:1099/SessionB</jndi-name> 
</ejb-ref> 
</session> 
</enterprise-beans> 
</jboss>

Mas acho que não serve para o meu caso.

danieldestro

Exceção:

14:07:14,312 INFO [EjbModule] Creating
14:07:14,392 INFO [EjbModule] Deploying GeraTxtHistoricoNormal
14:07:14,402 WARN [ServiceController] Problem creating service jboss.j2ee:jndiN
ame=ejb/GeraTxtHistoricoNormal,service=EJB
java.lang.ClassNotFoundException: dinap.gpa.interfaces.GPAProcessoAssincronoHome

at java.net.URLClassLoader$1.run(URLClassLoader.java:199)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
    at org.jboss.ejb.StatelessSessionContainer.create(StatelessSessionContai

ner.java:155)

danieldestro

Então,

Eu criei um jar novo com as interfaces home/remote e mais duas interfaces e uma exceção (todas do GPA) que o EJB do CGE usa.

O Deploy foi ok…

Mas na hora do EJB (do CGE) ser executado pelo GPA, ocorre ClassCastException nesta linha:

GPAProcessoAssincronoHome home = (GPAProcessoAssincronoHome) PortableRemoteObject.narrow(o, GPAProcessoAssincronoHome.class);

Ou seja, ele entende as Interfaces Home duplicadas como diferentes.

Cara. Isso é um saco grande!

Será que tem a ver com a isolação das classes dentro de cada EAR, que é feito no jboss-app.xml?

Valeu

Luca

Olá

Me desculpem se não li com atenção todas as mensagens. Mas vou tentar ajudar mesmo assim (?)

  1. Links diversos:
    :arrow: EAR file, how to JBOSS , Jar and war file packaged
    http://www.ideas2work.com/ear-file-deploy-jboss.html

:arrow: J2EE Enterprise Application Physical Construction
http://webdev.apl.jhu.edu/~jcs/corej2ee.fall02/deploy/doc/lectures/j2eeapp/public/building_j2ee_apps_lecture.pdf

:arrow: Component Development for the Java Platform by Stuart Dabbs Halloway Ler o capítulo 2
http://www.develop.com/us/technology/developmentorseriesdownload.aspx?id=11

:arrow: Find a way out of the ClassLoader maze

  1. Os arquivos ear permitem que classes com nomes absolutamente iguais sejam usadas em uma mesma aplicação justamente por seu mecanismo especial de classloader que carrega cada classe com um namespace diferente (isto não ocorre nos .jars). E cada application server tem sua própria política interna de classloader.

[]s
Luca

danieldestro

Você já passou por este problema, Luca? Adotou alguma estratégia específica?
Valeu!

Luca

Olá

Daniel, não passei por este problema. Mas quiz chamar a atenção para o fato de que com arquivos ear se pode usar a mesma classe sem problemas. Aliás, este é o único meio que conheço de colocar a mesma classe duas vezes na mesma aplicação sem dar pau. Acho que esta é uma das perguntas mais dificeis que se pode fazer a algum candidato a guru em Java:

[color=blue]É possível colocar a mesma classe mais de uma vez em uma aplicação Java? Se acha que sim diga como.[/color]

[color=green]Resposta: Sim, empacotando a aplicação em um arquivo ear e localizando as classes corretamente no arquivo manifest.[/color]

Resumo:
Carregar classes ou class loading é o processo de localizar os bytes de uma classe e converter em instâncias Java dentro da JVM. É um processo feito pela JVM desde a inicialização e depois por ClassLoaders subclasses de java.lang.ClassLoader. Isto permite carregar as classes independente de onde seus bytes estão armazenados tanto local como remotamente e ainda permitir gerar classes dinamicamente. Os ClassLoaders também carregam métodos nativos tais como arquivos .dll (ou .so).

Um classloader é uma subclasse de java.lang.ClassLoader que é responsável pelo carregamento das classes. Em uma aplicação Java pode haver diferentes classloaders usando mecanismos diferentes para carregar as classes. Os classloaders podem carregar as classes oriundas de diversas fontes tais como base de dados, servidor remoto, file system, fontes definidas em arquivo xml, código fonte a ser compilado, etc.

Cada classloader (uma instância de uma subclasse de ClassLoader) define um único e separado namespace. Em cada classloader somente uma classe com um determinado nome pode existir. Mas a mesma classe pode ser carregada por diferentes classloaders. Neste caso a JVM considerará cada classe como qualificada pela instância do ClassLoader que a carregou. Em outras palavras, o nome completo de uma classe consiste do seu nome mais seu classloader.

Porém carregar duas vezes a mesma classe pode ser fonte de bugs dificeis de serem descobertos.

“Daniel”:

O Deploy foi ok…

Mas na hora do EJB (do CGE) ser executado pelo GPA, ocorre ClassCastException nesta linha:

GPAProcessoAssincronoHome home = (GPAProcessoAssincronoHome) PortableRemoteObject.narrow(o, GPAProcessoAssincronoHome.class);

Ou seja, ele entende as Interfaces Home duplicadas como diferentes.

Toda tentativa de fazer cast de um objeto por outro (por exemplo durante a localização JNDI) resultará em ClassCastException.

Para entender melhor toda a questão dos classloaders normais é fundamental ler o capítulo 2 do livro do Stuart Haloway que indiquei antes. Mas para entender classloaders com J2EE há um excelente artigo que no caso do Daniel é de leitura obrigatória:

[color=red]Class Loading in J2EE and Oracle9iAS Environments (Bryan Atsatt e Debu Panda)[/color]
http://otn.oracle.com/oramag/oracle/02-sep/o52oc4j.html

Além do uso do parametro -verbose:class na linha de comando do Java, se pode debugar classloaders usando dicas do artigo do JavaWorld
Back to your Class roots, continued (Vladimir Roubtsov)

Um outro artigo sobre este assunto:
http://www.onjava.com/pub/a/onjava/2003/11/12/classloader.html

Espero ter ajudado (sem ter lido seu código)

[]s
Luca

danieldestro

Puta que o pariuuuu! :oops:
Conseguí!

Eu fiz o seguinte.

  1. Isolei as interfaces (home e remote) em um jar
  2. Joguei este jar no deploy do JBoss
  3. Empacotei o GPA num EAR, mas sem as interfaces
  4. Fiz depoy do GPA
  5. Empacotei o CGE num EAR, mas sem as interfaces
  6. Fiz depoy do CGE
  7. Funcionou!
Criado 9 de dezembro de 2004
Ultima resposta 14 de dez. de 2004
Respostas 15
Participantes 3