Server Components: Enterprise JavaBeans

Introdução aos Server Components

wpe8.jpg (19309 bytes)

n-tier.gif (23321 bytes)

Overview de Enterprise JavaBeans (EJB)

Programação Declarativa

Serviços Automáticos

Arquitetura

ejb1.gif (6079 bytes)

Novo Processo e Novos Papeis

ejb2.gif (10735 bytes)

Detalhes sobre o modelo EJB

Localização, Factory e Interfaces

ejb3.gif (13287 bytes)

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
  • No início de uma sessã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
  • Transacional
Exemplo
  • Shopping Cart
  • Um item de um catálogo de produtos

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
  • Mais pesado
  • Extremamente lightweight
Exemplo
  • Shopping Cart
  • Verificação de crédito
    (Todo o trabalho pode ser feito numa única chamada de método)

Detalhes sobre os serviços automáticos

ejb4.gif (22270 bytes)

Detalhes adicionais sobre o Container

Um exemplo de aplicação com EJB

ecommerce1.gif (11857 bytes)

Desenvolvimentos dos Entity Beans

CREATE TABLE BOOKS
    CODE Number
    TITLE Text
    AUTHORS Text
    PRICE Currency
    DISCOUNT Number
        *primary key (CODE)
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;
}
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;
}
package com.gopalan.Shop.Books;

public class BooksPK implements java.io.Serializable {
    public int isbn;

    public BooksPK() {
    }

    public BooksPK(int isbn) { 
        this.isbn = isbn; 
    }
}
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
<!------------------------------------------>
<!------- 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>
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
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...");
    }
}

Desenvolvimentos do Session Bean

package com.gopalan.Shop.Cart;

import javax.ejb.*;
import java.rmi.*;

interface CartHome extends EJBHome { 
    Cart create() throws RemoteException, CreateException;
}
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;
}
// 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
<!------------------------------------------>
<!------- 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>
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

Comparação de JavaBeans e EJB

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

comp-4 programa anterior próxima