Server Components: Enterprise JavaBeans
Introdução aos Server Components
- Client/Server is dead!
- "Business Logic" está sendo movida de volta para o servidor
- Motivos:
- Problemas de escalabilidade
- Não há recursos suficientes tais como conexões de bancos de dados para suportar
milhares de clientes
- Client/Server puro tem baixa gerenciabilidade (problemas
graves de suporte e atualização de software)
- Queremos Very Thin Clients e não apenas PCs poderosos como
clientes
- Very Thin Clients = "Dispositivos Internet-Enabled"
- Network Computer
- Personal Digital Assistants (PDAs)
- Telefones
- Smartcards
- Quiosques (em shopping centers, por exemplo)
- Um cenário possível de acesso a uma aplicação corporativa
- Money Makers, um grande corretor de ações tem uma aplicação corporativa para
gerenciar Fundos de Ações
- Eles querem prover aos clientes um sistema de auto-atendimento eletrônico de compra e
venda
- Eles querem dar suporte efetivo aos corretores e aos clientes usando Thin Clients,
incluindo:
- Aplicações Desktop nos PCs
- Browsers
- Telefones
- Quiosques
- SmartCards
- Outros dispositivos "Internet-Enabled"

- Mover o Business Logic de volta para o servidor requer uma nova
arquitetura, com a introdução de uma camada intermediária
- Middle Tier
- Arquitetura 3-Tier
- O User Services Tier trata da apresentação
- O Data Services Tier trata da persistência, concorrência, ...
- O Business Services Tier trata do Business Logic e de serviços de suporte (ver adiante)

- Podemos ir até uma arquitetura n-tier quando:
- O Middle Tier é distribuído em várias máquinas
- Exemplo: Tem um Web Server entre o cliente e o Application Server
- O Web Server pode executar um servlet, por exemplo
- Exemplo: Load Balancing devido a escalas só encontradas na Internet
- Exemplo: Replicação devido à natureza Missão-Crítica das aplicações
- O Data Services Tier também pode ser distribuído em várias fontes
- Exemplo: Integração de sistemas legados, Internet Data Feeds, etc.
- Quais são os Serviços de Suporte (ou Middleware) do Middle Tier?
- Servidor Web
- Para permitir um browser como cliente
- Persistência de componentes e acesso a dados
- Gerência de transações distribuídas
- Directory/Naming
- Para achar serviços, componentes, etc.
- Segurança
- Tolerância a falha com Failover
- Prover escalabilidade com truques para aumentar a performance
- Balanceamento de carga
- Resource pooling
- Exemplo: Conexões aos SGBDs
- Multithreading
- Monitoring, logging
- Mas todo isso tem que ser feito dentro de um paradigma de
componentes
- Para maximizar a reusabilidade
- (Ver todas as vantagens de componentes já vistas antes)
- O que são Server Components?
- Componentes já vistos são orientados a eventos, server components não o são
- Server Components nunca têm uma representação visual
- Os problemas básicos que precisamos resolver no uso de Server Components são aqueles
listados acima como Serviços de Suporte do Middle Tier
- Help! Programadores normais não sabem como resolver essas
questões (difíceis)
- E nem deveriam! Eu, como empresário, quero que meus programadores se concentrem no
Business Logic, não em acertar transações distribuídas!
- Server Component Model
- Precisamos de um modelo de componentes que simplifique o processo de mover Business
Logic para o servidor
- Para tanto, o modelo deve implementar um conjunto de serviços
automáticos para gerenciar os componentes
- Em outras palavras, queremos um framework que ofereça serviços automáticos e permitir
que o Business Logic seja plugado facilmente com componentes que obedeçam ao modelo
- Em termos concretos, o framework pode executar como parte de
- Um SGBD
- Um monitor de transações ou Transaction Processing Monitor (Tuxedo, MTS, ...)
- "Application Servers"
- Isso é coisa nova na fauna de Middleware
- etc. etc.
Overview de Enterprise JavaBeans (EJB)
- EJB não é um produto: é uma especificação
- Para ter suporte multi-fornecedor
- Sistemas Abertos continuam ...
- O objetivo maior é deixar o programador se concentrar no Business Logic
- Isso é feito de duas grandes formas:
- Programação Declarativa
- Serviços Automáticos
Programação Declarativa
- Cada Bean tem um Deployment Descriptor que permite
configurá-lo visualmente durante a implantação
- Sem ter código fonte e sem programar
Serviços Automáticos
- Implementados por um Container
- Lifecycle
- Bean não precisa se preocupar com criação de processos,
threads, ativação ou destruição de objetos
- Gerência de estado
- O estado conversacional de Beans (se houver) é gerênciado
(salvo/recuperado) automaticamente
- Segurança
- Beans não precisam autenticar os usuários ou verificar o nível
de autorização
- Transações
- Não precisa colocar código de demarcação de transações nos
Beans para que possam participar de transações distribuídas
- O Container automaticamente gerência o início, enrollment,
commitment e rollback de transações
- Persistência
- Beans não precisam se preocupar com sua persistência num Banco
de Dados
- Outros
- Outros serviços podem ser oferecidos dependendo do fornecedor
(Replicação, Load-Balancing, ...)
- A implementação dessas idéias depende de 3 coisas:
- Uma arquitetura
- Um novo processo de desenvolvimento
- Novos papeis para os desenvolvedores
Arquitetura
- A Arquitetura se baseia num EJB Container que roda num EJB Server e intercepta as
chamadas ao Bean feitas pelos clientes
- O cliente nunca acessa o Bean diretamente
- Vários "Wire Protocols" podem ser usados pelos clientes
- Default: Remote Method Invocation (RMI)
- O EJB Container implementa os Serviços Automáticos
- Em termos de Design Pattern, é uma combinação de:
- Proxy (controla o acesso a um Bean, ex. segurança)
- Decorador (adiciona funcionalidade a um Bean)
- O EJB Server permite que vários containers executem e
implementa outros serviços (não transparentes) tais como:
- Naming
- Security (Cadastro de usuários, grupos, etc.)
- Serviços de transação (chamados automaticamente pelo Container)
- etc.

Novo Processo e Novos Papeis
- Há uma correspondência entre novas etapas do processo de desenvolvimento e os novos
papeis
- Discutiremos portanto os novos papeis

- EJB Server Provider
- Provê o Middleware contendo os serviços não automáticos (Naming usando JNDI,
Transações usando JTS, ...)
- O EJB Server deve ser capaz de aceitar vários EJB Containers
- EJB Servers podem ser construídos em cima de
- SGBDR
- SGBDOO
- Monitores de Transação
- Web Application Servers
- etc.
- Exemplos: IBM, Sun, BEA, Oracle
- Devem ser especialistas em Gerência de Transações Distribuídas, Objetos
Distribuídos, etc.
- EJB Container Provider
- Provê o software para receber Beans e fornecer os serviços automáticos
- Alguma ferramenta deve fornecer a geração automática dos Containers (que obedecem à
interface dos Beans, já que interceptam as chamadas)
- No final das contas, um Container é um monte de classes em Java geradas automaticamente
- Deve também se registrar junto ao serviço de Naming para que os clientes possam achar
objetos que obedeçam às interfaces desejadas
- O Container roda dentro do EJB Server
- Como não há (ainda) padronização de interface entre o EJB Server e o EJB Container,
quem é fornecedor de EJB Server também provê o Container
- Exemplos: IBM, Sun, BEA, Oracle
- EJB Developer
- Um programador que produz EJBs
- EJBs capturam o Business Logic reutilizável da empresa
- Sendo reutilizável, vale a pena colocar num Bean
- Pode ser um programador da empresa cliente ou de uma empresa especializada em construir
EJBs
- EJB Deployer
- Faz tudo que tem a ver com o ambiente run-time final
- Um técnico da empresa cliente final
- Vai instalar os Beans no EJB Server e configurá-los no ambiente run-time
- Através do Deployment Descriptor
- Usando Programação Declarativa
- Não precisa saber Java, nem o Business Logic
- Deve saber quais são os bancos de dados, os usuários, etc.
- O que é configurado:
- O nome dos Beans
- Os nomes das interfaces dos Beans
- Valores de timeout de sessão
- Lista de campos mantidos pelo container (persistência automática)
- Access Control List para segurança
- Controle de Transação (Not Supported, Supported, Required, Requires_New, Bean-Managed,
...)
- Transaction Isolation Level (Serializable, Read Uncommitted, Read Committed, Repeatable
Read)
- Application Developer
- Junta todos os tiers para criar a aplicação final
- Escreve a aplicação usando Componentes prontos
- A aplicação pode ser:
- Aplicação Java
- Applet
- Servlet
- Aplicação CORBA
- Controle ActiveX (usando o bridge COM-CORBA)
- O desenvolvedor se preocupa mais com a funcionalida de muito alto nível
- Tipicamente Apresentação de Dados
- System Administrator
- Gerencia o ambiente e faz o afinamento (fine tuning)
- Monitoração em tempo real de
- Servidores de aplicação
- Beans
- Containers
- Clientes
- Pode definir o número concorrente de usuários que executam um cliente ou Container ou
Bean específico
- Pode ter visão instantânea ou histórica de eventos, cargas, etc.
Detalhes sobre o modelo EJB
Localização, Factory e Interfaces

- A interface Home e o Home Object
- Interface de Factory para criar, localizar e remover instâncias
de Beans
- O desenvolvedor de Beans define esta interface
- O Home Object implementa a interface Home
- Implementa todos os serviços de lifecycle do Bean
- Lembra que os Beans não são acessados diretamente
- Apenas o container (Home Object e EJBObject) acessa os Beans
- O Home Object é automaticamente construído pelas ferramentas do Container Provider a
partir da interface especificada
- O Home Object deve ser localizado pelo cliente através do serviços de Naming (JNDI) do
EJB Server
- A interface Remote e o EJBObject
- Especifica os Business Methods do Bean
- O cliente acessa o EJBObject e este interpõe a funcionalidade desejada (persistência,
transação, segurança, gerência de estado), e acessa o Bean
- Quem realmente implementa a interface Remote é o EJBObject, não o Bean
- O EJBObject é gerado automaticamente pelas ferramentas do Container Provider a partir
da interface especificada
Tipos de Beans
Característica |
Session Bean |
Entity Bean |
O que o Bean representa |
- Uma conversação transiente com um cliente
- Pode ser considerado uma extensão do cliente que o criou
- Pode acessar um banco de dados usando JDBC ou acessando um Entity Bean
|
- Dão uma visão OO de um BD
- Representam dados num banco de dados e os métodos que agem sobre os dados
- Num SGBDR, cada Bean poderia representar um registro de uma tabela, por exemplo
|
Tempo de vida |
- Igual ao tempo de vida do cliente. Existe somente durante uma sessão cliente/servidor
(curto espaço de tempo)
|
- Persiste tanto quanto os dados do banco de dados (longo espaço de tempo)
|
Atributos |
- Representam o estado da conversação. Este estado é mantido entre chamadas a métodos
mas não depois que a sessão acaba
|
- Representam dados de um banco de dados (colunas de uma tabela, por exemplo)
|
Persistência
(além da sessão) |
- O Bean deve gerenciar sua própria persistência
|
- Gerenciada automaticamente pelo Container
|
Compartilhamento |
- Um único Bean por cliente (sem compartilhamento)
|
- Acesso compartilhado entre clientes
- Container gerencia a concorrência
|
Criação |
|
- Identificado usando uma chave primária
- A criação de um novo Bean insere dados num banco de dados
|
Durabilidade |
- Não sobrevive a um crash de servidor
|
- Sobrevive a um crash de servidor
|
Transação |
- Pode ser "transaction-aware", se assim for programado
|
|
Exemplo |
|
- Um item de um catálogo de produtos
|
- Diferenças entre dois tipos de Session Beans
- O tipo é definido no Deployment Descriptor
Característica |
Stateful Session Bean |
Stateless Session Bean |
Gerência de estado |
- Gerenciado automaticamente pelo Container
(Activation, Passivation)
|
- Não há estado a ser gerenciado
- Bean pode sair da memória sem salvar qualquer coisa (não há "Passivation")
- Beans são intercambiáveis e podem ser alocados de um "pool"
|
Responsabilidades |
- Estado conversacional pode ser mantido no Bean
|
- O cliente tem que manter qualquer estado
|
Performance |
|
|
Exemplo |
|
- Verificação de crédito
(Todo o trabalho pode ser feito numa única chamada de método)
|
- Regras para escolher o tipo de Bean
- Business Logic deve estar nos Session Beans
- Para escalabilidade, prefira Stateless Session Beans
- O uso de Stateful Beans deve ser minimizado
- Para acesso a BD, prefira Entity Beans para:
- Ter uma visão OO dos dados
- Não ter que tratar de aspectos transacionais, de persistência, de segurança, etc.
- Faça com que o cliente acesse apenas Session Beans
- Esconda os Entity Beans atrás de Session Beans
- Por quê?
- Para possibilitar armazenar estado transacional o que não deve ser feito em Entity
Beans
- Se houver aspectos transacionais não triviais a serem considerados, eles podem ser
tratados no Session Bean (escrito por um especialista) e o Application Developer não vai
ter que saber nada sobre transações
- Melhora a integridade dos Bancos de Dados, já que o Application Developer não vai
manipular o BD diretamente. Ele só usaria Session Beans
Detalhes sobre os serviços automáticos
- Gerência de estado
- Para gerenciar recursos limitados, o Container pode expulsar ("passivar") um
Bean (fazendo com que ele ocupe menos recursos temporariamente
- Não ocorre para Stateless Session Beans
- O Container decide como e quando fazer isso
- Tem hook methods ejbActivate() e ejbPassivate() que permitem colocar a lógica adicional
desejada para estes momentos
- Lembra que o container é um framework e oferece hook methods
- Normalmente, os hooks methods nada fazem por o framework já tratou de tudo
- Gerência de persistência
- Para Entity Beans
- Além de simplicidade, uma outra vantagem fundamental de usar persistência Bean-managed
é que posso mudar a fonte de dados subjacente no futuro e nada afetar no componente ou
nas aplicações que o usam
- Tem vários hook methods que podem ser utilizadas
- ejbCreate(), ejbRemove(), ejbLoad(), ejbStore(), ejbActivate(), ejbPAssivate()
- A persistência pode ser tratada pelo próprio Bean (Bean-managed persistence)
- Só se o que o container faria não for adequado
- Se apoia nos métodos ejbLoad() e ejbStore(), principalmente, usando chamadas JDBC, por
exemplo
- Pode ser Container-managed com várias alternativas de implementação em existência
- Serialização do componente
- Mapeamento de campos do Bean para colunas de uma única tabela de um SGBD Relacional
- O mapeamento é feito em tempo de deployment
- Se o Bean envolver várias tabelas, pode-se criar uma View e mapear os campos do Bean
para colunas da view
- Porém, lembre que vários BDs não permitem atualizar os dados de uma view
- Implementação de complex joins através de um mapeamento Object-Relational, com uma
ferramenta visual especial
- Ver figura abaixo que define o que fazer com um relacionamento (usando PowerTier da
Persistence)

- Gerência de transações
- Para Session Beans e Entity Beans
- Suporta transações distribuídas
- Envolvendo vários bancos de dados
- Demarcação de transação pode ser feita das seguintes formas:
- com código usando javax.jts.UserTransaction
- automaticamente feito pelo Container com instruções no Deployment Descriptor
- Demarcação: os atributos de demarcação podem se aplicar ao Bean todo ou a cada
método
- Tipos de atributos de transação:
- TX_NOT_SUPPORTED: chamada feita fora do contexto de qualquer transação
- TX_BEAN_MANAGED: O Bean se vira
- TX_REQUIRED: ao entrar no método, usa o contexto atual de transação se houver, caso
contrário, crie um novo contexto de transação
- TX_SUPPORTS: Se o método for chamado dentro de um contexto de transação, ok; caso
contrário, também ok.
- TX_REQUIRES_NEW: Um novo contexto de transação é sempre criado
- TX_MANDATORY: Se não houver contexto de transação, lança exceção
- Tratamento de concorrência:
- Vários níveis de isolamento de transação disponíveis (no deployment descriptor):
- TRANSACTION_READ_UNCOMMITTED
- TRANSACTION_READ_COMMITTED
- TRANSACTION_REPEATABLE_READ
- TRANSACTION_SERIALIZABLE
- Segurança
- Usa o modelo de segurança normal do Java (no JDK)
- Tudo é declarado no Deployment descriptor
- Resumo
- Pode estabelecer "roles"
- Pode associar usuários a roles
- Pode executar certos métodos com privilégios especiais
- Autorização com Access Control Lists
- Cada método pode ter uma lista de usuários que podem chamá-lo
Detalhes adicionais sobre o Container
- Agora que sabemos mais sobre EJB, podemos listar as coisas que o Container faz
- Swap de Beans de/para disco
- Gerência de persistência
- Disponibiliza um Home Object (o factory) para criar e localizar Beans
- Registra o Home Object no serviço de nomes (JNDI) para que o cliente possa achá-lo
- Cria, inicializa e remove Beans
- Se encarrega de executar os Business Methods no contexto apropriado de transação
- Implementa serviços básicos de segurança
- Resource pooling (ex.: conexões de bancos de dados)
- Outros serviços dependentes do fornecedor:
- Load Balancing
- Fail-over transparente
Um exemplo de aplicação com EJB
- Tirado daqui: http://www.execpc.com/~gopalan/java/ejb.html
- Algumas partes do exemplo se aplicam especificamente ao EJB Server chamado Homebase da
Iona (que faz o Orbix)
- Problema a resolver: Comércio eletrônico (compra on-line de livros e CDs)
- Arquitetura da solução segue abaixo

- Além disso, vamos desenvolver dois clientes para testar os Beans
- Um cliente para testar os Entity Beans
- Um cliente para testar o Session Bean
Desenvolvimentos dos Entity Beans
- Só mostraremos o desenvolvimento do Bean para livros (Book)
- Etapas:
- Acerte a fonte de dados
- Defina a Home Interface
- Defina a Remote Interface
- Defina a classe de Chave Primária (Primary Key)
- Implemente o Entity Bean
- Compile as classes EJB
- Declare o Deployment Descriptor
- Gere as classes do Container usando as ferramentas do fornecedor de EJB Server/Container
- Cadastre o factory (Home Object) junto ao serviço de nomes
- Escreva o código cliente de teste
- Compile o código cliente de teste
- Inicie o cliente
- Acerte a fonte de dados
- Usaremos uma tabela com a seguinte definição
CREATE TABLE BOOKS
CODE Number
TITLE Text
AUTHORS Text
PRICE Currency
DISCOUNT Number
*primary key (CODE)
- Defina a Home Interface
- Quem realmente vai implementar este método é o Home Object, criado automaticamente
- Quando o método create() do Home Object é chamado, este chama o método correspondente
ejbCreate() do Bean
- A primeira coisa que um cliente faz é localizar o Home Object de um Bean usando JNDI
package com.gopalan.Shop.Books;
import javax.ejb.*;
import java.rmi.*;
interface BooksHome extends EJBHome {
Books create(int isbn, String title,
String authors, double price,
int discount
throws CreateException, RemoteException;
Books findByPrimaryKey(BooksPK book)
throws FinderException, RemoteException;
}
- Defina a Remote Interface
- A interface externa (Business Methods) de BooksBean
- A interface será implementada por EJBObject, uma classe automaticamente criada
package com.gopalan.Shop.Books;
import javax.ejb.*;
import java.rmi.*;
interface Books extends EJBObject {
int getIsbn() throws RemoteException;
String getTitle() throws RemoteException;
String getAuthors() throws RemoteException;
double getPrice() throws RemoteException;
int getDiscount() throws RemoteException;
double getDiscountedPrice() throws RemoteException;
void setPrice(double cost) throws RemoteException;
void setDiscount(int disc) throws RemoteException;
}
- Defina a classe de Chave Primária (Primary Key)
- EJB exige que uma Entity Bean tenha uma classe <Nome>PK para representar uma chave
primária
- Os campos que representam a chave devem ser públicos
package com.gopalan.Shop.Books;
public class BooksPK implements java.io.Serializable {
public int isbn;
public BooksPK() {
}
public BooksPK(int isbn) {
this.isbn = isbn;
}
}
- Implemente o Entity Bean
- O Bean deve implementar a interface javax.ejb.EntityBean
- Observe que não tem JDBC neste código, já que o Container provê a
persistência
- Poderemos até mudar o BD no futuro e não afetar o Bean
package com.gopalan.Shop.Books;
import java.rmi.*;
import javax.ejb.*;
public class BooksBean implements EntityBean {
EntityContext entityContext;
public int code; // CODE
public String title; // TITLE
public String authors; // AUTHORS
public double price; // PRICE
public int discount; // DISCOUNT
// Implementação de todos os Business Methods
// da Remote Interface
public int getIsbn() throws RemoteException {
return code;
}
public String getTitle() throws RemoteException {
return title;
}
public String getAuthors() throws RemoteException {
return authors;
}
public double getPrice() throws RemoteException {
return price;
}
public int getDiscount() throws RemoteException {
return discount;
}
public double getDiscountedPrice() throws RemoteException {
double deduct = ( (double)discount)/100;
return price* (1-deduct);
}
public void setPrice(double cost) throws RemoteException {
price = cost;
}
public void setDiscount(int disc) throws RemoteException {
discount = disc;
}
// Implementação de todos os métodos para a Home Interface
public void ejbCreate(int isbn, String bookTitle,
String author, double cost,
int disc)
throws CreateException, RemoteException {
code = isbn;
title = bookTitle;
authors = author;
price = cost;
discount= disc;
}
public void ejbPostCreate(int isbn, String bookTitle,
String author, double cost,
int disc) {
}
// Implementação de outros métodos necessários com EJB
// ejbLoad() e ejbStore fazem nada porque estamos usando
// Container-managed persistence
public void ejbLoad() throws RemoteException {}
public void ejbStore() throws RemoteException {}
public void ejbActivate() throws RemoteException {}
public void ejbPassivate() throws RemoteException {}
public void ejbRemove()
throws RemoteException, RemoveException {}
public void setEntityContext(EntityContext context)
throws RemoteException {
entityContext = context;
}
public void unsetEntityContext() throws RemoteException {
entityContext = null;
}
}
javac *.java
- Declare o Deployment Descriptor
- O Deployment Descriptor é uma classe normal (javax.ejb.deployment.DeploymentDescriptor)
que deve ser criada, inicializada, serializada e incluída no packaging do componente (um
arquivo JAR)
- Em tempo de deployment, o Deployment Descriptor pode ser modificado usando ferramentas
que dependem do fornecedor
- No caso do HomeBase, edita-se um arquivo XML
- Observe a definição de campos persistentes
<!------------------------------------------>
<!------- Books Entity Bean ---------------->
<!------------------------------------------>
<ejbml>
<entity-bean
name="Books"
descriptor="Books/BooksDeployment"
package="com.gopalan.Shop.Books"
home="com.gopalan.Shop.Books.BooksHome"
remote="com.gopalan.Shop.Books.Books"
bean="com.gopalan.Shop.Books.BooksBean"
primary-key="com.gopalan.Shop.Books.BooksPK"
tx-attribute="TX_SUPPORTS"
>
<property
name="databasePassword"
value="mouse"
/>
<property
name="dataSourceName"
value="Shop"
/>
<property
name="databaseUser"
value="user"
/>
<property
name="databaseTable"
value="books"
/>
<container-managed
storage-helper=
"com.ejbhome.generator.helpers.RelationalPersistenceCodeHelper"
table="books"
data-source="Shop"
user="user"
password="mouse"
>
<field name="discount" />
<field name="price" />
<field name="authors" />
<field name="title" />
<field name="code" />
</container-managed>
</entity-bean>
</ejbml>
- Gere as classes do Container
- Usando a ferramenta do fornecedor
- Abaixo, incluímos a geração para os outros 2 Beans também
E:\>javac *.java
E:\>java com.ejbhome.Deployer .\conf\Shop.ejbml
EJBHome EJB Deployer version 0.5.1 (Scunthorpe)
(c) Copyright IONA Technologies PLC 1999. All Rights Reserved.
Windows NT x86 4.0
Deploying: Books...
Generating: IonaBooksHome...done.
Generating: IonaRemoteBooks...done.
Generating: IonaBooksBean...done.
Generating: IonaBooksContext...done.
Implementing Communications: Home Stubs & Skels...done.
Implementing Communications: Remote Stubs & Skels...done.
Compiling: IonaBooksHome.java...done.
Compiling: IonaRemoteBooks.java...done.
Compiling: IonaBooksBean.java...done.
Compiling: IonaBooksContext.java...done.
Compiling: IonaBooksHome_Stub.java...done.
Compiling: IonaBooksHome_Skel.java...done.
Compiling: IonaRemoteBooks_Stub.java...done.
Compiling: IonaRemoteBooks_Skel.java...done.
Deploying: Music...
Generating: IonaMusicHome...done.
Generating: IonaRemoteMusic...done.
Generating: IonaMusicBean...done.
Generating: IonaMusicContext...done.
Implementing Communications: Home Stubs & Skels...done.
Implementing Communications: Remote Stubs & Skels...done.
Compiling: IonaMusicHome.java...done.
Compiling: IonaRemoteMusic.java...done.
Compiling: IonaMusicBean.java...done.
Compiling: IonaMusicContext.java...done.
Compiling: IonaMusicHome_Stub.java...done.
Compiling: IonaMusicHome_Skel.java...done.
Compiling: IonaRemoteMusic_Stub.java...done.
Compiling: IonaRemoteMusic_Skel.java...done.
Deploying: Cart...
Generating: IonaCartHome...done.
Generating: IonaRemoteCart...done.
Generating: IonaCartBean...done.
Generating: IonaCartContext...done.
Implementing Communications: Home Stubs & Skels...done.
Implementing Communications: Remote Stubs & Skels...done.
Compiling: IonaCartHome.java...done.
Compiling: IonaRemoteCart.java...done.
Compiling: IonaCartBean.java...done.
Compiling: IonaCartContext.java...done.
Compiling: IonaCartHome_Stub.java...done.
Compiling: IonaCartHome_Skel.java...done.
Compiling: IonaRemoteCart_Stub.java...done.
Compiling: IonaRemoteCart_Skel.java...done.
E:\>
java com.ejbhome.Server
- Escreva o código cliente de testes
package com.gopalan.Shop.Books;
import java.rmi.*;
import java.util.*;
public class BooksTest {
static final int NUMBOOKS = 4;
public static void main(String[] args) throws Exception {
// Usa JNDI para achar o Home do Bean
BooksHome home = (BooksHome)Naming.lookup("Books");
System.out.println("Naming.lookup successful...");
if(home == null) {
System.out.println("null BooksHome returned...");
}
String title = "Book";
String author = "Author";
Vector v = new Vector();
for(int i = 0; i < BooksTest.NUMBOOKS; i++) {
System.out.println("ISBN = " + (i+1) +
" Book = " +title+ (i+1) +
" Author = " +author+ (i+1) +
" Creating home.create...");
v.add(home.create((i+1),title+(i+1),
author+(i+1),100.00,10));
}
for(int i = 0; i < BooksTest.NUMBOOKS; i++) {
Books books = (Books)(v.get(i));
books.setPrice(books.getPrice()+1);
System.out.println("Final Price of " +
books.getTitle() +
" is "+ books.getPrice());
}
System.out.println("Books.setBooksPrice successful...");
for(int i = 0; i < BooksTest.NUMBOOKS; i++) {
Books books = (Books)(home.findByPrimaryKey(
new BooksPK(i+1)));
books.setPrice(books.getPrice()+1);
System.out.println("Final Price of " +
books.getTitle() +
" is "+ books.getPrice());
}
System.out.println("Books.findByPrimaryKey successful...");
}
}
- Compile e execute o cliente
- Isto vai criar 4 registros no Banco de Dados
Desenvolvimentos do Session Bean
- Etapas:
- Defina a Home Interface
- Defina a Remote Interface
- Implemente o Session Bean
- Compile as classes EJB
- Declare o Deployment Descriptor
- Gere as classes do Container usando as ferramentas do fornecedor de EJB Server/Container
- Cadastre o factory (Home Object) junto ao serviço de nomes
- Escreva o código cliente de teste
- Compile o código cliente de teste
- Inicie o cliente
- Defina a Home Interface
package com.gopalan.Shop.Cart;
import javax.ejb.*;
import java.rmi.*;
interface CartHome extends EJBHome {
Cart create() throws RemoteException, CreateException;
}
- Defina a Remote Interface
- Adicionamos dois métodos para ajudar a criar Entity Beans
- createNewBook() e createNewAlbum()
- Temos também dois métodos para ajudar a recuperar informação
- Temos métodos para ajudar a encher o Shopping Cart
- addToBooksCart() e addToMusicCart()
- Temos métodos estatísticos para o usuário
- getNumberBooks(), getNumberAlbums(), getBooksTotal(), getAlbumsTotal(), getGrandTotal()
package com.gopalan.Shop.Cart;
import javax.ejb.*;
import java.rmi.*;
import java.util.*;
import com.gopalan.Shop.Books.*;
import com.gopalan.Shop.Music.*;
interface Cart extends EJBObject {
Books createNewBook(int isbn, String title, String authors,
double price, int discount)
throws RemoteException, CreateException;
Music createNewAlbum(int code, String album, String authors,
double price, int discount)
throws RemoteException, CreateException;
Books getBook(int isbn)
throws RemoteException, FinderException;
Music getAlbum(int code)
throws RemoteException, FinderException;
void addToBooksCart(int code) throws RemoteException;
void addToMusicCart(int code) throws RemoteException;
void flushBooksCart() throws RemoteException;
void flushMusicCart() throws RemoteException;
int getNumberBooks() throws RemoteException;
int getNumberAlbums() throws RemoteException;
double getBooksTotal() throws RemoteException;
double getAlbumsTotal() throws RemoteException;
double getGrandTotal() throws RemoteException;
// Não gostei de retornar vector aqui ...
// Cria um acoplamento desnecessário
// melhor seria usar Iterator
Vector getBooksList() throws RemoteException;
Vector getMusicList() throws RemoteException;
Vector getBooksCart() throws RemoteException;
Vector getMusicCart() throws RemoteException;
}
- Implemente o Session Bean
- Acessa a Home Interface dos dois Entity Beans
- Observe que o Session Bean faz cache de dados para obter melhor desempenho (evitar
acessos ao Banco de Dados)
// Estou estranhando a visibilidade de muitas coisas mas
// não que mexer até conhecer EJB melhor e testar tudo
package com.gopalan.Shop.Cart;
import java.rmi.*;
import javax.ejb.*;
import java.util.*;
import com.gopalan.Shop.Books.*;
import com.gopalan.Shop.Music.*;
import com.gopalan.Shop.Cart.ReturnSet;
public class CartBean implements SessionBean {
SessionContext sessionContext;
public BooksHome booksHome;
public MusicHome musicHome;
public Vector booksList = null, booksCart = null;
public Vector musicList = null, musicCart = null;
int totalBooks = 0, totalMusic = 0;
double booksCost = 0, musicCost = 0, grandTotal = 0;
void init() {
booksList = new Vector();
booksCart = new Vector();
musicList = new Vector();
musicCart = new Vector();
ReturnSet result = null;
for(int i=0; ;i++) {
try {
BooksPK key = new BooksPK(i+1);
Books found = booksHome.findByPrimaryKey(key);
if(null == found) {
break;
}
result = new ReturnSet(key.code, found.getTitle(),
found.getAuthors(),
found.getPrice(),
found.getDiscount(),
found.getDiscountedPrice());
System.out.println("isbn = "+ result.code +
" Title = "+result.title+
" Authors = "+result.authors+
" Price = " + result.price);
booksList.add(result);
} catch(Exception e) {
e.printStackTrace();
break;
}
}
for(int i=0; ;i++) {
try {
MusicPK key = new MusicPK(i+1);
Music found = musicHome.findByPrimaryKey(key);
if(found == null) {
break;
}
result = new ReturnSet(key.code, found.getAlbum(),
found.getComposers(),
found.getPrice(),
found.getDiscount(),
found.getDiscountedPrice());
System.out.println("code = "+ result.code +
" Album = "+result.title+
" Composers = "+result.authors+
" Price = " + result.price);
musicList.add(result);
} catch(Exception e) {
e.printStackTrace();
break;
}
}
}
// Implementação de todos os BUsiness Methods
// da interface Remote
public Books createNewBook(int isbn, String title,
String authors, double price,
int discount)
throws RemoteException, CreateException {
Books book = booksHome.create(isbn, title, authors,
price, discount);
if(null != book) {
booksList.add(new ReturnSet(isbn, title,
authors,
price, discount,
book.getDiscountedPrice()));
}
return book;
}
public Music createNewAlbum(int code, String album,
String authors,
double price, int discount)
throws RemoteException, CreateException {
Music music = musicHome.create(code, album, authors,
price, discount);
if(null != music) {
musicList.add(new ReturnSet(code, album, authors,
price, discount,
music.getDiscountedPrice()));
}
return music;
}
public void addToBooksCart(int isbn) throws RemoteException {
try {
Books book = getBook(isbn);
if(null != book) {
booksCart.add(new ReturnSet(isbn,
book.getTitle(),
book.getAuthors(),
book.getPrice(),
book.getDiscount(),
book.getDiscountedPrice()));
++totalBooks;
booksCost += book.getDiscountedPrice();
grandTotal+= book.getDiscountedPrice();
}
} catch(Exception e) {
e.printStackTrace();
}
}
public void flushBooksCart() throws RemoteException {
grandTotal -= booksCost;
totalBooks = 0;
booksCost = 0;
booksCart.removeAllElements();
}
public void flushMusicCart() throws RemoteException {
grandTotal -= musicCost;
totalMusic = 0;
musicCost = 0;
musicCart.removeAllElements();
}
public void addToMusicCart(int code) throws RemoteException {
try {
Music music = getAlbum(code);
if(null != music) {
musicCart.add(new ReturnSet(code, music.getAlbum(),
music.getComposers(),
music.getPrice(),
music.getDiscount(),
music.getDiscountedPrice()));
++totalMusic;
musicCost += music.getDiscountedPrice();
grandTotal+= music.getDiscountedPrice();
}
} catch(Exception e) {
e.printStackTrace();
}
}
public Books getBook(int isbn)
throws RemoteException, FinderException {
return booksHome.findByPrimaryKey(new BooksPK(isbn));
}
public Music getAlbum(int code)
throws RemoteException, FinderException {
return musicHome.findByPrimaryKey(new MusicPK(code));
}
public Vector getBooksList() throws RemoteException {
return booksList;
}
public Vector getMusicList() throws RemoteException {
return musicList;
}
public Vector getBooksCart() throws RemoteException {
return booksCart;
}
public Vector getMusicCart() throws RemoteException {
return musicCart;
}
public int getNumberBooks() throws RemoteException {
return totalBooks;
}
public int getNumberAlbums() throws RemoteException {
return totalMusic;
}
public double getBooksTotal() throws RemoteException {
return booksCost;
}
public double getAlbumsTotal() throws RemoteException {
return musicCost;
}
public double getGrandTotal() throws RemoteException {
return grandTotal;
}
// Implementação dos métodos da Home Interface
public void ejbCreate()
throws RemoteException, CreateException {
}
// Outros métodos exigidos pela especificação EJB
public void ejbActivate() throws RemoteException {}
public void ejbPassivate() throws RemoteException {}
public void ejbRemove() throws RemoteException {}
public void setSessionContext(SessionContext context)
throws RemoteException {
sessionContext = context;
try {
booksHome =(BooksHome)Naming.lookup("Books");
musicHome = (MusicHome)Naming.lookup("Music");
init();
} catch(Exception ex) {
throw new RemoteException("Shop not found", ex);
}
}
}
package com.gopalan.Shop.Cart;
public class ReturnSet implements java.io.Serializable {
// por que ele usou public?
public int code;
public String title;
public String authors;
public double price;
public int discount;
public double ourPrice;
public ReturnSet(int no, String name, String author,
double cost, int disc, double cp) {
code = no; title = name; authors = author;
price = cost; discount = disc; ourPrice = cp;
}
}
java *.java
- Declare o Deployment Descriptor
<!------------------------------------------>
<!------- Cart Session Bean ---------------->
<!------------------------------------------>
<ejbml>
<session-bean
name="cart"
descriptor="Cart/CartDeployment"
package="com.gopalan.Shop.Cart"
home="com.gopalan.Shop.Cart.CartHome"
remote="com.gopalan.Shop.Cart.Cart"
bean="com.gopalan.Shop.Cart.CartBean"
type="stateful"
timeout="3600"
tx-attribute="TX_SUPPORTS"
></session-bean>
</ejbml>
- Gere as classes do Container
- Escreva e compile o código cliente de teste
package com.gopalan.Shop.Cart;
import java.rmi.*;
import java.util.*;
public class CartTest {
static final int NUMITEMS = 2;
public static void main (String[] args) throws Exception {
CartHome home = (CartHome)Naming.lookup("Cart");
System.out.println("Naming.lookup successful...");
if(null == home) {
System.out.println ("null CartHome returned...");
}
Cart cart = home.create();
String title = "Title";
String author= "Author";
for(int i = 0; i < CartTest.NUMITEMS; i++) {
System.out.println("code = " +(i+1) +
" Title = " +title+(i+1) +
" Author = " +author+(i+1) +
" Creating cart.create...");
cart.createNewBook((i+1),title+(i+1),
author+(i+1),100.00,10);
cart.createNewAlbum((i+1),title+(i+1),
author+(i+1),20.00,5);
}
for(int i = 0; i < CartTest.NUMITEMS; i++) {
cart.addToBooksCart(i+1);
cart.addToMusicCart(i+1);
}
Vector bookList = cart.getBooksList();
System.out.println ("Book List of size "+
bookList.size()+" is...");
for(int i = 0; i < bookList.size(); i++) {
ReturnSet set = (ReturnSet)bookList.get(i);
System.out.println("code = " +set.code +
" Title = " +set.title +
" Author = " +set.authors);
}
Vector musicList= cart.getMusicList();
System.out.println ("Music List of size "+
musicList.size()+" is...");
for(int i = 0; i < musicList.size(); i++) {
ReturnSet set = (ReturnSet)musicList.get(i);
System.out.println("code = " +set.code +
" Title = " +set.title +
" Author = " +set.authors);
}
Vector bookCart = cart.getBooksCart();
System.out.println ("Book Cart of size "+
bookCart.size()+" is...");
for(int i = 0; i < bookCart.size(); i++) {
ReturnSet set = (ReturnSet)bookCart.get(i);
System.out.println("code = " +set.code +
" Title = " +set.title +
" Author = " +set.authors);
}
Vector musicCart = cart.getMusicCart();
System.out.println("Music Cart of size "+
musicCart.size ()+" is...");
for(int i = 0; i < musicCart.size(); i++) {
ReturnSet set = (ReturnSet)musicCart.get(i);
System.out.println("code = " +set.code +
" Title = " +set.title +
" Author = " +set.authors);
}
System.out.println("Total Books = " + cart.getNumberBooks() +
" Total Albums = " +cart.getNumberAlbums () +
" Book Cost = " +cart.getBooksTotal () +
" Album Cost = " +cart.getAlbumsTotal () +
" Grand Total =" + cart.getGrandTotal ());
}
}
Desenvolvimentos do Verdadeiro Cliente
- O servlet que realmente é usado como cliente pode ser visto aqui
Comparação de JavaBeans e EJB
- Agora que conhecemos EJB, podemos ver as diferenças com JavaBeans normais
JavaBeans |
Enterprise JavaBeans |
JavaBeans podem ser visíveis ou não em
tempo de execução |
Um EJB é um objeto remoto não visual |
JavaBeans rodam num único processo e foram feitos
basicamente para rodarem no cliente. É possível usar JavaBeans no servidor mas é
melhor usar EJB |
EJBs são componentes executáveis remotamente e só podem
executar no servidor |
Com JavaBeans, eventos são fundamentais:
são a base da interconexão de componentes |
Eventos não são importantes em EJB.
Outras propriedades (persistência, concorrência, segurança, etc.) são importantes Não
há relação entre os dois modelos de componentes |
JavaBeans têm uma interface externa (Properties) que permite que uma ferramenta interprete a
funcionalidade do Bean |
EJBs têm um Deployment Descriptor que descreve sua
funcionalidade, ou pelo menos que parametriza parte do comportamento desejado que o
Container tem que implementar |
JavaBeans podem ter classe BeanInfo, Property Editors, ou Customizers. |
EJBs não têm esses conceitos e só
possuem o Deployment Descriptor |
JavaBeans não são tipados |
Tem dois tipos de EJBs: Entity e Session |
Há um bridge disponível para implantar um
Bean como controle ActiveX |
Não se pode transformar um EJB num
controle ActiveX |
Para ser usado como server component, o programador teria que
escrever muita funcionalidade adicional |
O framework já foi escrito |
Produtos
- Vários tipos de produtos estão aparecendo como EJB Servers
- TP Monitors (CICS, IBM TX, Tuxedo)
- Transaction Servers (Sybase Jaguar CTS)
- Sistemas CORBA (IBM WebSphere)
- SGBDR (DB2, Oracle, Sybase, Informix)
- SGBDOO (GemStone/J)
- Sistemas Object/Relational (Persistence PowerTier, Secant Extreme)
- Servidores de aplicações Web (BEA Weblogic, Netscape Application Server, Oracle
Application Server)
- Dentro de pouco tempo, deve have apenas uns 3 ou 4 grandes fornecedores
- Servidores grátis
- Várias ferramentas permitem criar EJB com mais facilidade
comp-4 programa anterior próxima