PZR420 - Temat F - EJB

(!!! NIEDOKOŃCZONE !!!)

EJB = Enterprise Java Beans

EJB to obiekty/ komponenty rozproszone, podobne do obiektów Corby ...

Literatura na temat EJB:
  1. specyfikacja EJB 2.0, 2.1, 3.0 patrz tutaj
  2. rozdział w "Thinking in Enterprise Java" TIE, rozdz o EJB, omawia się tu EJB2.0 (!); poniższe przykłady są oparte na tym rozdziale
  3. "Mastering EJB 3.0" książka w internecie ?
Cechy EJB:
  1. serwer EJB jest zwany kontenerem EJB; przykład implementacji kontenera EJB: openejb.org
    (stąd można go łatwo ściągnąć: openejb.tar.gz)
  2. "Bean" (=obiekt EJB) to plik *.jar umieszczany w katalogu apps kontenera EJB;
    bean-y można bez problemu przenosić między różnymi kontenerami...
  3. w EJB używa się RMI-IIOP, zatem (teoretycznie?) mamy niezależność od języka programowania;
    tj można pisać klienty Corby dla używające EJB...
  4. każdy kontener EJB musi posiadać pewne standardowe serwisy:
    trwałość, transakcje, bezpieczeństwo, współbieżność, klastering
    (i to jest chyba główna różnica z Corbą!!!)
  5. można używać serwisów nie tylko poprzez API, ale także poprzez deklaracje
    (w tzw deployment deskryptorze lub przez annotacje w kodzie źródłowym)
Rodzaje bean-ów:
  1. entity bean
  2. session bean
  3. messaage-driven bean
Jakie kroki musi wykonać klient używający bean-ów? (patrz przykład 1)
  1. ???
Bean to plik *.jar zawierający następujące elementy:
  1. deskryptor; patrz 2
  2. interfejs EJBHome; patrz 3
  3. interfejs EJBObject; patrz 4
  4. klasa bean-a; EntityBean lub SessionBean lub ?; patrz 5
Wskazówki co do instalacji kontenera openejb:
- wymaga aby w nazwie hosta nie było znaku "_"; jeśli jest to można to zmienić na czas uruchamiania serwera

Przykład 1

// użycie EJB od strony klienta (tclBlend)

# JNDI
set p1 [java::new java.util.Properties]
$p1 put java.naming.factory.initial "org.openejb.client.RemoteInitialContextFactory"
$p1 put java.naming.provider.url "localhost"
set ctx1 [java::new javax.naming.InitialContext $p1]

set x1 [$ctx1 list "/"] 
[$x1 next] toString
  #% KeywordBean2RemoteHome: org.apache.openejb.core.ivm.naming.ObjectReference
  #% ...

proc narrow ob {java::cast [[$ob getClass] getName] $ob}
  # w stylu Corby...

set o2 [narrow [$ctx1 lookup "KeywordBean2RemoteHome"]]

# tworzenie entity beans ...
# + w metodzie create podaje sie: klucz name info
#   "name" i "info" to pola entiy-beana...
set x1 [$o2 create 1 "111" "111111111111"]
set x2 [$o2 create 2 "222" "222222222222"]

# znajdowanie entity beans na podstawie klucza ...
set y1 [$o2 findByPrimaryKey 1]
set y2 [$o2 findByPrimaryKey 2]

$y2 remove
  # usuwanie entity beanow

java::prop $y1 info "1111111111111111"
java::prop $y1 info
  #% 1111111111111111
  # modyfikujemy pola entity-beana

set d1 [narrow [$o2 findByName 111]]
  # finder, znajdujacy entity-beany na podstawie pola "name"

set c1 [$o2 findByName2 111]
  # inny finder, znajdujacy entity-beany na podstawie pola "name"
  # + tym razem zwraca kolekcje ejb (to na wypadek gdyby ich bylo >1)

Przykład 2

// deskryptor entity bean-a...

<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC
"-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"
"http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">

<ejb-jar>
  <enterprise-beans>
    <entity>
      <ejb-name>KeywordBean2</ejb-name>
      <home>org.acme.keyword.KeywordHome2</home>
      <remote>org.acme.keyword.Keyword2</remote>
      <ejb-class>org.acme.keyword.KeywordBean2</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.Integer</prim-key-class>
      <reentrant>False</reentrant>
      <cmp-version>2.x</cmp-version>
      <cmp-field>
        <field-name>id</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>name</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>info</field-name>
      </cmp-field>
      <primkey-field>id</primkey-field>
      <resource-ref>
        <res-ref-name>jdbc/hsqldb</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
      </resource-ref>
      <abstract-schema-name>KeywordBean2</abstract-schema-name>
      <query>
        <query-method>
          <method-name>findByName</method-name>
          <method-params>
            <method-param>java.lang.String</method-param>
          </method-params>
        </query-method>
        <ejb-ql>
          SELECT OBJECT(m) FROM KeywordBean2 m WHERE m.name=?1
        </ejb-ql>
      </query>
      <query>
        <query-method>
          <method-name>findByName2</method-name>
          <method-params>
            <method-param>java.lang.String</method-param>
          </method-params>
        </query-method>
        <ejb-ql>
          SELECT OBJECT(m) FROM KeywordBean2 m WHERE m.name=?1
        </ejb-ql>
      </query>
    </entity>
  </enterprise-beans>

  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>KeywordBean2</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Supports</trans-attribute>
    </container-transaction>
  </assembly-descriptor>

</ejb-jar>

Przykład 3

// EJBHome (dla entity bean-a)

package org.acme.keyword;

import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.FinderException;
import java.rmi.RemoteException;

public interface KeywordHome2 extends EJBHome
{
    public Keyword2 create( Integer id, String name, String info )
        throws RemoteException, CreateException;
    
    public Keyword2 findByPrimaryKey( Integer id )
        throws RemoteException, FinderException;

    public Keyword2 findByName( String name )
        throws RemoteException, FinderException;

    public java.util.Collection findByName2( String name )
        throws RemoteException, FinderException;
}

Przykład 4

// EJBObject (dla entity bean-a)

package org.acme.keyword;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Keyword2 extends EJBObject
{
    public String name() throws RemoteException;
    public String info() throws RemoteException;

    public String getName() throws RemoteException;
    public String getInfo() throws RemoteException;
    public void setName(String name) throws RemoteException;
    public void setInfo(String info) throws RemoteException;
}

Przykład 5

// klasa bean-a czyli EntityBean

package org.acme.keyword;

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

abstract public class KeywordBean2 implements EntityBean
{
    public EntityContext context;

    //////////
    //////////

    public void setEntityContext( EntityContext context )
        throws EJBException, RemoteException
    {
        this.context = context;
    }

    public void unsetEntityContext()
        throws EJBException, RemoteException
    { }

    public void ejbActivate()
        throws EJBException, RemoteException
    { }

    public void ejbPassivate()
        throws EJBException, RemoteException
    { }

    public void ejbLoad()
        throws EJBException, RemoteException
    { }

    public void ejbStore()
        throws EJBException, RemoteException
    { }

    public void ejbRemove()
        throws RemoveException, EJBException, RemoteException
    { }

    public Integer ejbCreate( Integer id, String name, String info )
        throws CreateException
    {
	setId( id );
        setName( name );
        setInfo( info );
        return null;
    }

    public void ejbPostCreate( Integer id, String name, String info )
        throws CreateException
    { }

    //////////
    //////////

    public String name()
    {
        return getName();
    }
    public String info()
    {
        return getInfo();
    }
    
    abstract public String getName();
    abstract public void setName(String name);
    abstract public String getInfo();
    abstract public void setInfo(String info);
    abstract public Integer getId();
    abstract public void setId(Integer id);
}

Zadanie F.1 (najprostszy przykład użycia EJB)
Zainstaluj kontener EJB "openejb" (openejb.tar.gz);
zbuduj prostego entity-beana wg powyższych przykładów;
zbuduj klienta (w czystej javie) używającego tego beana...