Trabalhando com Session Beans Stateless e Stateful

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (4)  (0)

Veja neste artigo como desenvolver Session Beans, Stateless e Stateful, para acesso remoto com servidor de aplicações JBoss AS7. A seguir será implementada uma aplicação java para invocar os Sessions Beans criados.

Descrição: Veja neste artigo como desenvolver Session Beans, Stateless e Stateful, para acesso remoto com servidor de aplicações JBoss AS7. A seguir será implementado uma aplicação java para invocar os Sessions Beans criados.

Neste artigo serão desenvolvidos dois Sessions Beans, um do tipo Stateless e outro Stateful. O primeiro disponibilizará uma funcionalidade de conversão de câmbio, de dólar para real. O segundo possuirá serviços para realizar a compra da moeda americana.

Esses componentes de negócios serão utilizados por outro sistema, através de acesso remoto.

O IDE utilizado será o Eclipse em sua versão 4.2.2 Juno, com o plugin JBoss AS, para a configuração do servidor.

O primeiro passo é criar um EJB Project, para isso clique com o botão direito do mouse na área de Project Explorer, New -> EJB Project.

Criação do EJB Project no Eclipse

Figura 1: Criação do EJB Project no Eclipse

Após isso, um wizard será aberto, assim devemos configurar o nome do projeto e o target runtime que é o servidor de aplicações que iremos utilizar na nosso projeto. Para facilitar a configuração do servidor no Eclipse, foi instalado o plugin do JBoss AS.

Wizard Eclipse para criação do EJB project

Figura 2: Wizard Eclipse para criação do EJB project

Para a configuração do servidor no Eclipse utilizando o plugin, clique no botão “New Runtime...” e escolha dentro da pasta JBoss Comunity a opção JBoss 7.1 Runtime, após isso, clique em next. Na próxima etapa é preciso apontar para a pasta onde o JBoss está instalado.

Configuração do JBoss 7.1 no EJB project

Figura 3: Configuração do JBoss 7.1 no EJB project

O resultado final é apresentado na Figura 4, onde é possível ver o nome do projeto e a configuração final do servidor. Em seguida basta finalizar a criação.

Configuração final do EJB Project

Figura 4: Configuração final do EJB Project

Após a configuração do servidor, iremos criar os Sessions Beans. Criaremos primeiramente o componente que permite a conversão de câmbio, de dólar para real. Esse é um exemplo extremamente simples, pois o foco do artigo é explorar os conceitos dos tipos de EJBs (Stateless e Stateful) e JNDI, para acesso remoto entre aplicações Java. Conceitos importantes em aplicações distribuídas.

Para criar um Session Bean no Eclipse podemos utilizar um wizard. Ele facilita o processo de criação. Para acessá-lo clique com o botão direito do mouse na pasta ejb-module, que está dentro do projeto EJB e escolha a opção new -> Session Bean (EJB 3.x).

Criação de Stateless Session Beans

Figura 5: Criação de Stateless Session Beans

Neste wizard é possível configurar Stateless, Stateful e Singleton session beans para acesso Local e/ou Remoto.]

Wizard para criação de Session Bean

Figura 6: Wizard para criação de Session Bean

Criaremos agora um Stateless Session Bean com acesso Remoto. Para isso, é preciso configurar o pacote e no nome do EJB, na opção “State type”, escolha Stateless e marque o checkbox Remote, para a criação da interface do EJB com a anotação Remote.

Resultado da criação do Session Bean

Figura 7: Resultado da criação do Session Bean

O resultado da criação é apresentado na Figura 7, a classe CotacaoServices e a interface CotacaoServicesRemote foram criados corretamente.

Na interface CotacaoServicesRemote foi definido um único serviço, o calcular cotação da moeda real, passado um valor em dólar:

Listagem 1: Interface CotacaoServicesRemote

package devmedia.ejb;

import javax.ejb.Remote;

@Remote
public interface CotacaoServicesRemote {

	public double calcularCotacaoReal(double valor);
	
}

A interface está anotada com @Remote para possibilitar o acesso remoto ao EJB. Dessa forma, aplicações executadas em diferentes servidores de aplicações e/ou diferentes máquinas podem utilizar o nosso componente de negócios.

A classe deve implementar a interface e receber a anotação @Stateless, pois essa funcionalidade não precisa manter o estado. O serviço é atômico, ou seja, a conversão é executada para um cliente e logo após finalizada. Desta forma, ficará disponível para que outros clientes possam utilizar o serviço de conversão.

Listagem 2: Classe CotacaoServices

package devmedia.ejb;

import javax.ejb.Stateless;

/**
 * Session Bean implementation class CotacaoServices
 */
@Stateless
public class CotacaoServices implements CotacaoServicesRemote {

    private static final double COTACAO_DOLAR = 2.05;
    
	public CotacaoServices() {

    }

	@Override
	public double calcularCotacaoReal(double valor) {
		return valor*COTACAO_DOLAR;
	}

}

O próximo componente que iremos desenvolver neste artigo é um Session Bean Stateful para a compra de dólares. Ele armazena a quantidade de dólares que o usuário irá adquirir e calcular o valor total que o cliente deverá pagar em reais, para isso iremos utilizar o componente de conversão que desenvolvemos anteriormente.

O processo para a construção do EJB Stateful é o mesmo utilizado para o EJB Stateless, a diferença é que no momento da configuração, devemos escolher a opção Stateful ao invés de Stateless:

Criação de EJB Stateful

Figura 8: Criação de EJB Stateful

O Session Bean possui três funcionalidades: adiconar e remover dólares, e calcular o valor total em reais:

Listagem 3: Interface CompraDolarServiceRemote

package devmedia.ejb;

import javax.ejb.Remote;

@Remote
public interface CompraDolarServicesRemote {

	public void adicionarDolar(double valor);
	
	public void removerDolar(double valor);
	
	public double calcularValorTotal();
	
} 

A implementação da interface é uma classe EJB anotada com @Stateful, pois para esse serviço, a aplicação deve manter a quantidade de dólares que o usuário deseja comprar, pois cada instância do Session Bean deve atender a um cliente, mantendo a integridade das informações.

Listagem 4: Classe CompraDolarServices

package devmedia.ejb;

import javax.ejb.EJB;
import javax.ejb.Stateful;

/**
 * Session Bean implementation class CompraDolarServices
 */
@Stateful
public class CompraDolarServices implements CompraDolarServicesRemote {

    private double valor;
    
    @EJB
    private CotacaoServicesRemote cotacaoService;
	
    public CompraDolarServices() {
    }

	@Override
	public void adicionarDolar(double pValor) {
		valor += pValor;
	}

	@Override
	public void removerDolar(double pValor) {
		valor -= pValor;
	}

	@Override
	public double calcularValorTotal() {
		return cotacaoService.calcularCotacaoReal(valor);
	}

}
 

Esse EJB depende da funcionalidade do EJB de conversão, assim, foi criado um atributo que referencia a interface remota do EJB de conversão (CotacaoServicesRemote) e ela foi anotada com @EJB para utilizar a injeção de dependência, ou seja, para que o servidor de aplicações coloque uma instância do Session Bean de ConversaoServices neste atributo, depois que o componente de CompraDolarServices for criado.

Esta forma demonstra que a interface de Session Bean anotada com @Remote pode ser utilizada também de forma local, pois, os dois componentes (Conversão e Compra) estão sendo executados no mesmo servidor de aplicações. O contrário não pode ser realizado, pois a interface anotada como @Local não pode ser utilizada para chamadas remotas.

Os dois componentes estão prontos. Agora é necessário executar a aplicação no servidor JBoss AS 7.1. Para isso, iremos executar dentro do próprio Eclipse (é possível também gerar o arquivo .jar e realizar o deploy dentro do servidor). Para isso, clique com o botão direito do mouse no projeto e escolha “Run as” -> “Run on Server”.

Opção para executar o EJB project de dentro do eclipse no JBoss AS 7.1

Figura 9: Opção para executar o EJB project de dentro do eclipse no JBoss AS 7.1

Se a outra aplicação (Cliente) for acessar o servidor utilizando endereço de IP, é necessário realizar uma configuração no servidor de aplicações. Isso é necessário pois a configuração padrão permite o acesso somente com “localhost”.

Essa configuração é feita no arquivo standalone.xml e pode ser acessado de dentro do Eclipse na aba server -> Filesets -> Configuration File ->>standalone.xml. Este arquivo está presente dentro do jboss, no path JBOSS_HOME/standalone/configuration/.

Arquivo de configuração do JBoss AS7

Figura 10: Arquivo de configuração do JBoss AS7

Neste arquivo, altere a interface public de para :

Listagem 5: Trecho do arquivo standalone.xml

 
 <interfaces>
        <interface name="management">
            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
        </interface>
        <interface name="public">
            <any-address/>
        </interface>
        <interface name="unsecure">
            <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/>
        </interface>
</interfaces>

Vamos desenvolver uma outra aplicação para utilizar os EJBs de forma remota. Existem duas formas de fazer o acesso remoto, utilizando EJB Client API ou JNDI. Neste artigo vamos utilizar JNDI – Java Naming and Directory Interface para fazer o lookup do nossos Sessions Beans.

No Eclipse, crie um Java Project através do menu file -> new -> Project -> Java Project. Após isso, um wizard de configuração será aberto. Nele é necessário configurar o nome do projeto. O nosso será DevMedia_AcessoRemoto, as outras configurações podemos deixar o padrão.

Criação de um Java Project no Eclipse

Figura 11: Criação de um Java Project no Eclipse

O acesso remoto é feito sempre utilizando os contratos dos serviços, ou seja, através das interfaces dos EJBs. Dessa forma, é necessário copiar as interfaces “CompraDolarServicesRemote.java” e “CotacaoServicesRemote.java” para dentro do Java Project criado. É através das interfaces que podemos utilizar RMI (Remote Method Invocation) e invocar os métodos que estão “rodando” em outro servidor, em diferentes máquinas.

Copiando as interfaces dos EJBs

Figura 12: Copiando as interfaces dos EJBs

A Figura 12 mostra as interfaces copiadas do projeto EJB, elas apresentam erros, pois utilizam a annotation @Remote do javax.ejb.Remote e não estão presentes no projeto. Para os projetos clientes, podemos adicionar o “jboss-client.jar” no classpath da aplicação. Esse jar está no JBOSS_HOME/bin/client/ e contém todos os elementos que vamos precisar no desenvolvimento. Dessa forma os erros não haverá mais erros.

Para adicionar esse jar no buildpath do projeto, clique com o botão direito do mouse em cima do projeto e acesse o menu Build Path -> Configure Build Path, aa aba “Libraries”, clique em “add External JARs..” e procure pelo jboss-client.jar.

Adicionando o jboss-client.jar no buildpath do projeto

Figura 13: Adicionando o jboss-client.jar no buildpath do projeto

Vamos escrever a classe de teste. O primeiro passo é configurar as propriedades do contexto para fazer o lookup do EJB utilizando JNDI.

JNDI é a API padrão na plataforma Java EE para acesso uniforme a serviços de nomes e diretórios, desta forma é possível acessar diversos sistemas de catálogos, e no nosso caso, será utilizado para localizar os EJBs.

A aplicação cliente deve possuir um arquivo de configuração em seu classpath, chamado jboss-ejb-client.properties. Segue o conteúdo do arquivo para a nossa aplicação:

Listagem 6: Arquivo de configuração da aplicação

endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
 
remote.connections=default
 
remote.connection.default.host=10.2.22.10
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

remote.connection.default.username=thiagoyama
remote.connection.default.password=123456

A serguir vamos descrever algumas das propriedades:

  • endpoint.name: propriedade opcional, caso não seja definida, será utilizado o valor padrão: “config-based-ejb-client-endpoint”. Ela representa o nome do endpoint do lado da aplicação cliente;
  • remote.connections: nome da conexão, é utilizado para configurar as conexões. É possível definir várias conexões utilizando nomes diferentes para cada conexão. Ex. remote.connections= conexao1, conexao2;
  • remote.connection..host: host do servidor onde a aplicação EJB está executando;
  • remote.connection..port: porta para a conexão, por padrão o JBoss AS7 utiliza a 4447;
  • remote.connection..username, remote.connection..password: usuário e senha. Elas podem ser criadas através do comando JBOSS_HOME/bin/add-user.sh (ou .bat). Isso é necessário pois a configuração padrão de segurança sercurity-realm está ativada.
  • é o nome da conexão definido na propriedade remote.connection.

Vamos criar um usuário para a autenticação do acesso remoto. Acesse o add-user.sh (ou .bat), escolha a opção a, para criar um Management User, deixe em branco o Realm (ManagementRealm). Digite um username e password e finalize:

Criação de um usuário no JBoss AS7

Figura 14: Criação de um usuário no JBoss AS7

Com a configuração de contexto realizada, poderemos criar o contexto e utilizá-lo para fazer o lookup dos EJBs através do nome JNDI que eles foram publicados no servidor.

O nome de publicação para Stateless Session bean é composto por:

ejb:/// !

O Stateful Session bean segue o mesmo padrão, a diferença é a adição de ?Stateful no final do nome:

ejb:/// !?Stateful

Isso indica que estamos fazendo o lookup de um Stateful Session Bean, possibilitando a criação do bean correto, que deve manter sessão.

Vamos analizar cada parte do nome:

  • ejb: é uma constante (não muda), define que é um lookup de EJB;
  • app-name: o nome do .ear (sem o sufixo .ear) que contém os EJBs. Se a aplicação não for empacotada em um ear, então basta deixar o app-name vazio;
  • module-name: é o nome do .jar ou .war (sem o sufixo .jar ou .war) que contém os EJBs.
  • distinct-name: é um nome alternativo que podemos definir. Ela é opcional;
  • bean-name: o nome do session bean que queremos fazer o lookup;
  • fully-qualified-classname-of-the-remote-interface: o nome e pacote da interface remota que queremos fazer o lookup;

Abaixo está a classe de teste, ela cria o contexto, faz o lookup dos EJBs e invoca os métodos:

Listagm 7: Classe de teste

package devmedia.main;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

import devmedia.ejb.CompraDolarServicesRemote;
import devmedia.ejb.CotacaoServicesRemote;

public class ConsoleViewCotacao {

	public static void main(String[] args) throws Exception{
		
		Properties prop = new Properties();
		prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
		final Context context = new InitialContext(prop);
		
		//Lookup no serviço de cotação remota
		CotacaoServicesRemote cotacaoService = CotacaoServicesRemote) context.lookup(
"ejb:/DevMedia_EJB/CotacaoServices!devmedia.ejb.CotacaoServicesRemote");
		
		//Invocando a cotação remota
		System.out.println("Cotação: 20 dolares são " + cotacaoService.calcularCotacaoDolar(20) + " reais");
		
		//Lookup no serviço de compra de dolar remota
		CompraDolarServicesRemote dolarService =  (CompraDolarServicesRemote) context.lookup(
"ejb:/DevMedia_EJB/CompraDolarServices!devmedia.ejb.CompraDolarServicesRemote?stateful");
		
		//Adiciona 40 dolares
		dolarService.adicionarDolar(40);
		
		//Calcula o valor total a pagar em reais
		System.out.println("Total a pagar: " + dolarService.calcularValorTotal() + " reais");
		
		//Remove 20 dolares
		dolarService.removerDolar(20);
		
		//Calcula o valor total a pagar em reais
		System.out.println("Total a pagar: " + dolarService.calcularValorTotal() + " reais");
		
	}
}

A classe possui alguns comentários para facilitar o entendimento. Após o lookup, acionamos o método calculaCotacaoDolar() do CotacaoServicesRemote para converter 20 dólares em reais. Depois, utilizamos bean DolarServicesRemote para adicionar 40 dólares ao nosso “carrinho de compras” e calculamos o valor a pagar. Note que após isso, foi invocado o método para removerDolar, onde foram removidos 20 dólares dos 40 já armazenados. E por fim, calculamos novamente o valor total a pagar. Isso demonstra a diferença entre o Stateless e Stateful Session Bean, o primeiro pode ser acessado por vários clientes enquanto que no segundo, cada instância do Session Bean atende a um cliente e pode armazenar informações relativas a ele.

Neste artigo foram discutidos as diferenças entre Sessions Beans do tipo Stateless e Stateful, e o acesso remoto desses Sessions Beans utilizando JNDI. Estes conceitos podem ser bastante úteis no desenvolvimento de aplicações distribuídas, um cenário comum em grandes aplicações corporativas.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?