Development

EJB remoto - JBoss 6 - Wildfly

Fizemos uma chamada remota EJB de forma isolada a partir do classloader do servidor do aplicativo para solucionar os problemas de comunicação do JBoss6/Wildfly9.

December 28 2015

Problema

Não é possível fazer uma chamada remota EJB em diferentes versões do JBoss/Wildfly AS.

Para realizar uma chamada remota EJB, você precisará da biblioteca de um cliente. A biblioteca do cliente contém classes que, normalmente, fazem parte do servidor de aplicativos. Se o cliente possui uma aplicação independente (Java SE), ele tem a solução. Mas, se o cliente tem outro servidor de aplicativos Java EE, não é possível realizar, já que muitas classes entram em conflito

A única exceção é quando os servidores dos aplicativos são exatamente da mesma versão, pois, assim, não é necessário ter a biblioteca do cliente.

Solução

Tente copiar o EJB independente do cliente como servidor alvo.

Faça a chamada remota EJB de forma isolada a partir do classloader do servidor do aplicativo e adicione somente as bibliotecas do cliente com base em outro servidor.

Caminho para a solução

Buscando uma solução, encontramos o Blog (http://wolf-71.blogspot.rs/2010/02/et-phone-home.html) do Carlo de Wolf (RedHat), que trata de um problema semelhante. A classe mais importante é a AluniteClassLoader, que não possui nenhum carregador principal de classe e direciona a determinados carregadores de classe, sucessivamente.

Também é muito importante incluir corretamente a nossa própria interface, para que ela seja acessível ao carregador de classe, evitando a temida ClassCastException.

Prova de conceito

O projeto de comunicação entre vários servidores (https://github.com/infobip/jboss-wildfly-remoting)

  • Módulo 1 JAR – entre vários servidores comuns, com um IConnector interface remoto e classe JndiHandler
  • Módulo 1 EJB - entre vários servidores ejb-jboss6, com uma implementação do IConnector, dirigida ao JBoss6
  • Módulo 1 EJB - entre vários servidores ejb-wildfly9, com uma implementação do IConnector, dirigida ao para Wildfly9
  • Módulo 1 EAR - Perfil construído com base:
    • Perfil wildfly9 construído em ear entre vários servidores comuns, e entre vários servidores ejb-wildfly9
    • Perfil jboss6 construído em ear entre vários servidores comuns, entre vários servidores ejb-jboss6, e excluindo o descritor de implementação jboss-deployment-structure.xml do ear

Blog Graphic

A interface IConnector tem dois métodos, Olá () e resposta (). E Olá () chamadas atendidas () e em outra instância do servidor.

A classe JndiHandler tem 3 métodos, um para pesquisa padrão JBoss6 e dois métodos para Wildfly9 - para pesquisas com base na API e EJB do cliente, e para pesquisas do tipo http-remoting com base em projetos de jboss-remote-naming:

  • lookupJboss6
Properties properties = new Properties(); 
properties.setProperty("java.naming.provider.url", host + ":" + port); 
properties.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); 
properties.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); 
InitialContext ctx = new InitialContext(properties); 
T service = (T) ctx.lookup(jndiName);
  • lookupWildfly9 (EJB client API)
Properties properties = new Properties(); 
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); 
InitialContext ctx = new InitialContext(properties); 
Context ejbRootNamingContext = (Context) ctx.lookup("ejb:");
T service = (T) ctx.lookup(ejb:" + jndiName);

Se optar por usar uma pesquisa a partir do EJB do cliente, o cliente deve ter jboss-ejb-client.properties no classpath.

  • lookupWildfly9HttpRemoting (jboss-remote-naming)
Properties properties = new Properties(); 
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); 
properties.put(Context.PROVIDER_URL, "http-remoting://" + host + ":" + port); 
properties.put("jboss.naming.client.ejb.context", true); 
InitialContext ctx = new InitialContext(properties); 
T service = (T) ctx.lookup(jndiName);

Cada servidor precisa ter as bibliotecas do cliente baseadas em outro servidor na máquina local, mas não implantadas no servidor de aplicativos.

Vamos começar com dois servidores de aplicativos.

Vamos começar com o JBoss6 AS na porta padrão 8080, e Wildfly com a port-offset 100.

Comunicação JBoss6-Wildfly9 no método Olá:

ClassLoader previous = Thread.currentThread().getContextClassLoader(); 
URLClassLoader urlCl = new URLClassLoader(new URL[]{ new URL(new File(jbossHome).toURI().toURL(), "client/jboss-client.jar") }, null); 
ClassLoader cl = new AluniteClassLoader(urlCl, previous);
Thread.currentThread().setContextClassLoader(cl);
String jndiname = "/cross-server-test/cross-server-ejb-wildfly9/ConnectorWildfly9Impl!com.infobip.crossserver.IConnector"; 
IConnector connector = (IConnector)JndiHandler.lookupWildfly9HttpRemoting(jndiname, new String[] {"localhost"}, 8180);
String answer = connector.answer(name);
logger.info("Wildfly is answering: " + answer);
// in the end, we return to previous classloader 
Thread.currentThread().setContextClassLoader(previous);

Comunicação Wildfly9-Jboss6 no método Olá:

ClassLoader previous = Thread.currentThread().getContextClassLoader(); 
URLClassLoader urlCl = new URLClassLoader(new URL[]{ new URL(new File(jbossHome).toURI().toURL(), "jbossall-client.jar") }, null); 
ClassLoader cl = new AluniteClassLoader(urlCl, previous);
Thread.currentThread().setContextClassLoader(cl);
String jndiname = "ConnectorJBoss6"; 
IConnector connector = (IConnector)JndiHandler.lookupJBoss6(jndiname, new String[] {"localhost"}, JndiHandler.LOCAL_JNDI_PORT);
String answer = connector.answer(name);
logger.info("JBoss6 is answering: " + answer);
// in the end, we return to previous classloader 
Thread.currentThread().setContextClassLoader(previous); 

E a mágica acontece...

Ao executar o teste Junit entre vários servidores wildfly9:

IConnector connector = (IConnector) lookup ("localhost", "8180"); connector.hello("Infobip");

Engineering

Engineering

E o semelhante teste Junit entre vários servidores jboss6:

IConnector connector = (IConnector) lookup("localhost", "8080"); connector.hello("Infobip");

Engineering

Engineering

(By Jelena Lazic, Software Engineer)