Introdução à pesquisa de EJB JNDI no servidor de aplicativos WildFly

Introdução à pesquisa de EJB JNDI no servidor de aplicativos WildFly

1. Visão geral

Enterprise Java Beans (EJB) são a parte principal doJava EE specification, que visa simplificar o desenvolvimento de aplicativos distribuídos de nível corporativo. O ciclo de vida dos EJBs é gerenciado por um servidor de aplicativos, comoJBoss WildFly ouOracle GlassFish.

Os EJBs fornecem um modelo de programação robusto que facilita a implementação de módulos de software em nível corporativo, pois cabe ao servidor de aplicativos lidar com problemas relacionados à lógica não comercial, como manipulação de transações, gerenciamento do ciclo de vida dos componentes ou injeção de dependência.

Além disso, já publicamos dois artigos cobrindo os conceitos básicos do EJB, então sinta-se à vontade para conferirhereehere.

Neste tutorial, mostraremos como implementar um módulo EJB básico no WildFly e chamar um EJB de um cliente remoto por meio de umJNDI.

2. Implementando o Módulo EJB

A lógica comercial é implementada por uma ou várias interfaces de negócios locais / remotas (também conhecidas como visualizações locais / remotas) ou diretamente por meio de classes que não implementam nenhuma interface (interfaces que não são de visualização).

É importante notar que as interfaces de negócios locais são usadas quando o bean vai ser acessado de clientes que residem no mesmo ambiente, ou seja, o mesmo arquivo EAR ou WAR, enquanto interfaces comerciais remotas são necessárias quando o bean será acessado de um ambiente diferente, ou seja, um JVM ou servidor de aplicativos diferente.

Vamos criar um módulo EJB básico, que será composto de apenas um bean. A lógica de negócios do bean será direta, limitada a converter um determinadoString em sua versão em maiúsculas.

2.1. Definindo uma interface remota de negócios

Vamos primeiro definir uma única interface remota de negócios, decorada com a anotação@Remote. Isso é obrigatório, de acordo com oEJB 3.x specification, pois o bean será acessado de um cliente remoto:

@Remote
public interface TextProcessorRemote {
    String processText(String text);
}

2.2. Definindo um bean sem estado

Em seguida, vamos entender a lógica comercial implementando a interface remota mencionada:

@Stateless
public class TextProcessorBean implements TextProcessorRemote {
    public String processText(String text) {
        return text.toUpperCase();
    }
}

A classeTextProcessorBean é uma classe Java simples, decorada com a anotação@Stateless.

Os beans sem estado, por definição, não mantêm nenhum estado de conversação com seus clientes, mesmo quando eles podem manter o estado da instância em diferentes solicitações. Sua contraparte, os beans com estado, preservam seu estado de conversação e, por exemplo, são mais caros de criar para o servidor de aplicativos.

Como neste caso a classe acima não tem nenhum estado de instância, ela pode se tornar sem estado. Caso tenha um estado, usá-lo em diferentes solicitações de clientes não faria sentido.

O comportamento do bean é determinístico, ou seja, não tem efeitos colaterais, como um bean bem projetado deveria ser: ele apenas pega uma entradaStringe retorna a versão em maiúsculas dele.

2.3. Dependências do Maven

Em seguida, precisamos adicionar o artefato Mavenjavaee-api ao módulo, que fornece todas as APIs de especificação Java EE 7, incluindo as necessárias para EJBs:


    javax
    javaee-api
    7.0
    provided

Neste ponto, conseguimos criar um módulo EJB básico, mas funcional. Para disponibilizá-lo a todos os clientes em potencial, precisamos adicionar o artefato ao repositório Maven local como um arquivo JAR.

2.4. Instalando o Módulo EJB no Repositório Local

Existem vários métodos para conseguir isso. O mais simples consiste em executar as fases de compilaçãoclean – install do ciclo de vida do Maven:

mvn clean install

Este comando instala o módulo EJB comoejbmodule-1.0.jar (ou qualquer id de artefato arbitrário especificado no arquivopom.xml), em nosso repositório local. Para obter mais informações sobre como instalar um JAR local com Maven, verifiquethis article.

Supondo que o módulo EJB tenha sido instalado corretamente em nosso repositório local, a próxima etapa é desenvolver um aplicativo cliente remoto que faz uso de nossa APITextProcessorBean.

3. Cliente EJB Remoto

Manteremos a lógica de negócios do cliente EJB remoto extremamente simples: primeiro, ele executa uma pesquisa JNDI para obter um proxyTextProcessorBean. Depois disso, ele invoca o métodoprocessText() do proxy.

3.1. Dependências do Maven

Precisamos incluir os seguintes artefatos do Maven para que o cliente EJB funcione conforme o esperado:


    javax
    javaee-api
    7.0
    provided


    org.wildfly
    wildfly-ejb-client-bom
    10.1.0.Final


    com.beldung.ejbmodule
    ejbmodule
    1.0

Embora seja bastante óbvio porque incluímos o artefatojavaee-api, a inclusão dewildfly-ejb-client-bom não é. The artifact is required for performing remote EJB invocations on WildFly.

Por último, mas não menos importante, precisamos disponibilizar o módulo EJB anterior para o cliente, por isso adicionamos a dependênciaejbmodule também.

3.2. Classe de cliente EJB

Considerando que o cliente EJB chama um proxy deTextProcessorBean, seremos muito pragmáticos e nomearemos a classe do clienteTextApplication:

public class TextApplication {

    public static void main(String[] args) throws NamingException {
        TextProcessorRemote textProcessor = EJBFactory
          .createTextProcessorBeanFromJNDI("ejb:");
        System.out.print(textProcessor.processText("sample text"));
    }

    private static class EJBFactory {

        private static TextProcessorRemote createTextProcessorBeanFromJNDI
          (String namespace) throws NamingException {
            return lookupTextProcessorBean(namespace);
        }

        private static TextProcessorRemote lookupTextProcessorBean
          (String namespace) throws NamingException {
            Context ctx = createInitialContext();
            String appName = "";
            String moduleName = "EJBModule";
            String distinctName = "";
            String beanName = TextProcessorBean.class.getSimpleName();
            String viewClassName = TextProcessorRemote.class.getName();
            return (TextProcessorRemote) ctx.lookup(namespace
              + appName + "/" + moduleName
              + "/" + distinctName + "/" + beanName + "!" + viewClassName);
        }

        private static Context createInitialContext() throws NamingException {
            Properties jndiProperties = new Properties();
            jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
              "org.jboss.naming.remote.client.InitialContextFactory");
            jndiProperties.put(Context.URL_PKG_PREFIXES,
              "org.jboss.ejb.client.naming");
            jndiProperties.put(Context.PROVIDER_URL,
               "http-remoting://localhost:8080");
            jndiProperties.put("jboss.naming.client.ejb.context", true);
            return new InitialContext(jndiProperties);
        }
    }
}

Simplificando, tudo o que a classeTextApplication __ faz é recuperar o proxy do bean e chamar seu métodoprocessText() com uma string de amostra.

A pesquisa real é executada pela classe aninhadaEJBFactory, que primeiro cria uma instância JNDIInitialContext, em seguida, passa os parâmetros JNDI necessários para o construtor e, finalmente, os usa para pesquisar o proxy do bean.

Observe que a pesquisa é realizada usando o espaço de nome "ejb:" proprietário do WildFly. Isso otimiza o processo de pesquisa, pois o cliente adia a conexão com o servidor até que o proxy seja explicitamente chamado.

É importante notar também que é possível pesquisar o proxy do bean sem recorrer ao namespace "ejb". No entanto,we’d be missing all the additional benefits of lazy network connections, thus making the client a lot less performant.

3.3. Configurando o Contexto EJB

O cliente deve saber com qual host e porta estabelecer uma conexão para executar a pesquisa de bean. Nesse sentido,the client requires setting up the proprietary WildFly EJB context, which is defined with the jboss-ejb-client.properties file colocado em seu caminho de classe, geralmente na pastasrc/main/resources:

endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options
  .SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=myusername
remote.connection.default.password=mypassword

O arquivo é bastante autoexplicativo, pois fornece todos os parâmetros necessários para estabelecer uma conexão com o WildFly, incluindo o número padrão de conexões remotas, o host e a porta padrão e as credenciais do usuário. Nesse caso, a conexão não é criptografada, mas pode ser quando o SSL está ativado.

A última coisa a levar em consideração é queif the connection requires authentication, it’s necessary to add a user to WildFly via the https://docs.jboss.org/author/display/WFLY8/add-user+utility?sscc=t[_add-user.sh/add-user.bat utility].

4. Conclusão

A realização de pesquisas EJB no WildFly é simples, desde que sigamos rigorosamente o processo descrito.

Como de costume, todos os exemplos incluídos neste artigo estão disponíveis no GitHubhereehere.