EJB komponenti

Dalīto aplikāciju dzīvotspēju nosaka to veidošanas ražīgums, mērogojamība, integrācija ar eksistējošām sistēmām, brīvība platformas izvēlē un drošības risinājumi. Šādu aplikāciju izstrādātājam jārēķinās ar daudziem apstākļiem:

  • Datubāzu un transakciju serveri prasa pavisam citu programmēšanas stilu nekā, teiksim, dinamiskais HTML (tehnoloģiju diverģence). Bet tie bieži jāintegrē vienā sistēmā.
  • "Enterprise" aplikācijai var būt jāatbalsta gan Web klienti, gan citi - specifiski klienti
  • Aplikācijai jātiek galā ar lielu skaitu vienlaicīgu klientu pieprasījumu
  • Aplikācijai jāvar izmantot eksistējošu sistēmu funkcionalitāte un pašai jābūt piemērotai dažādu piegādātāju videi un rīkiem.

J2EE platforma šos jautājumus risina, piedāvājot daudzslāņu izstrādes modeli (vienā no slāņiem ir EJB komponenti), kā arī karkasu (framework), kurš atbrīvo programmētāju no vistipiskāko uzdevumu veikšanas.

Pārzīmēts no [Sun2000]

Šajā kursā aplūkosim J2EE platformas centrālo sastāvdaļu - EJB, to izsaukšanu no Web un DOS aplikācijām, pašu EJB komponentu programmēšanu un EJB konteinera servisu mērķtiecīgu izmantošanu.

1. nodaļa: EJB komponentu ievads

Mērķi

  • Motivēt EJB nepieciešamību un saprast servisus, kurus šī vide nodrošina
  • Prast izvietot (deploy) gatavu EJB aplikāciju
  • Prast izsaukt EJB sesijas komponentus no klienta
  • Konfigurēt OC4J, lai darbinātu EJB, t.sk. konfigurēt DataSource

EJB vispārīgs raksturojums

EJB motivācija

  • Veicināt servera puses programmu atkalizmantojamību
  • Atkalizmantojamībai lietot aplikācijas sadalīšanu komponentos (moduļos ar precīzi definētiem interfeisiem)

Lielu dalītu sistēmu (distributed systems) veidošanā parasti rodas šādas problēmas:

attālinātie izsaukumi
klientam jāvar izsaukt servera komponentes, arī ja tās ir uz citas mašīnas
serveru klasteri un slodzes izlīdzināšana
pārāk noslogotie serveri pieprasījumus atdod citiem
datu slāņa integrācija
objektu saglabāšana relāciju datubāzēs, unificēta piekļuve senajām - legacy sistēmām
transakcijas
vienlaicīga piekļuve datiem, datubāzes atgriešanās konsistentā stāvoklī)
dinamiska programmatūras atjaunošana
t.i. dynamic redeployment - kodu maina, sistēmu neapturot
tīra serveru apturēšana
vienlaikus netraucēt klientu apkalpošanu, kuri lietoja šo serveri
notikumu reģistrācija un uzraudzība
t.i. logging and auditing - noskaidrot radušos kļūdu cēloņus
daudzpavedienu serveris
spēj apkalpot vienlaikus vairākus klientus
ziņojumorientēta starpprogrammatūra (middleware)
klienti un serveri var būt vāji sapāroti un apmainīties ar ziņojumiem
objektu dzīvescikli
servera objekti dzīvo savā redzamības apgabalā atbilstoši sistēmas slodzei
resursu baseini
klientu neizmantotie resursi atgriežas sistēmas kopīgo vajadzību apmierināšanai, piemēram, soketi (datubāzu konekcijas), atmiņas objekti
drošība
pārbauda lietotāju tiesības veikt darbību
kešošana
bieži lietotu datu glabāšana ātri pieejamā atmiņā)

EJB - komponentu arhitektūra

  • EJB standarts - vienošanās jeb interfeisu kopums, kas ļauj jebkuram aplikāciju serverim apkalpot jebkuru komponenti (specifikācija un interfeisi)
  • EJB komponentus sauc arī par enterprise beans

EJB alternatīvas:

  • MS .NET komponentes .NET platformā
  • Object Management Group (OMG) ieteiktā Common Objekct Request Broker Architecture (CORBA)

CORBA mēdz būt EJB sistēmu klients, t.i. var integrēt EJB arī ar citās valodās rakstītām programmām.

EJB un J2EE

EJB ir daļa no Sun piedāvātās J2EE (Java 2 Platform, Enterprise Edition). Vispār ir 3 javas platformas:

  • J2ME (Java 2, Micro Edition)
  • J2SE (Java 2, Standard Edition)
  • J2EE (Java 2, Enterprise Edition)

J2EE apvieno dažādas servera puses tehnoloģijas. Tas no Sun Microsystems viedokļa satur šāda veidu sastāvdaļas.

Specifikācijas
Katrai J2EE tehnoloģijai ir PDF specifikācija; šīs specifikācijas dažreiz numurējas atšķirīgi. Piemēram, tekošā J2EE versija ir 1.3.1, bet JSP versija ir 2.0, EJB versija ir 2.1, un JMS (Java Messaging Service) versija ir 1.1
Testu virkne
Sun var piešķirt J2EE atbalsta programmatūras izstrādātājam Sun sertifikātu (programmatūra var būt J2EE-certified jeb J2EE-compliant)
Paraugimplementācija
Sun'a bezmaksas implementācija, kura var būt nepiemērota komerciālai lietošanai

Arī Sun'a ieteikumi J2EE lietošanai, piemēram, http://java.sun.com/blueprints/enterprise/, utml.

J2EE tehnoloģiju pārskats

J2SE un J2EE satur atbalstu daudziem servera puses programmēšanas mehānismiem, kurus var lietot gan atsevišķi, gan kopā ar EJB. Šajā kursā atklāti izmantosim sekojošas "enterprise" Javas sastāvdaļas:

  • JNDI - piekļuve vārdu servisam
  • JDBC
  • JSP un Servletus
  • EJB

EJB vidē "aiz kulisēm" darbojas arī RMI-IIOP, transakcijas, u.c.

Uzskaitīsim visas būtiskākās J2EE tehnoloģijas:

EJB tehnoloģijas (Enterprise Java Beans (EJB))
Definē, kā rakstīt EJB komponentus, kā arī kontraktu starp komponentiem un aplikāciju serveri.
Attālinātie metožu izsaukumi RMI (Java Remote Method Invocation (RMI))
Attālinātie procedūru izsaukumi (RPC) starp Javu un Javu. RMI vēlāk paplašinājās par RMI-IIOP (Internet Inter-ORB Protocol), lai Java varētu piedalīties CORBA integrācijā ar citām tehnoloģijām.
Javas IDL valoda (Java IDL - Interface Definition Language)
Interfeisu apraksts integrācijai ar CORBA
Javas vārdu un direktoriju interfeiss JNDI (Java Naming and Directory Interface (JNDI))
JNDI definē Javas sadarbību ar vārdu un direktoriju servisiem; ar JNDI var piekonektēties, piemēram, EJB komponentēm. JNDI ļauj pieslēgties arī citiem vārdu servisiem, piemēram, Microsoft Exchange vai Lotus Notes.
Datubāzu interfeiss JDBC (Java DataBase Connectivity (JDBC))
"Standard Edititon" pakotnes java.sql un javax.sql, bet tās nepieciešamas arī "Enterprise" Javai.
Javas transakciju interfeiss JTA (Java Transaction API (JTA)), Javas transakciju serviss (Java Transaction Service (JTS))
Transakciju atbalsts komponentiem
Javas ziņu serviss (Java Messaging Service)
Ziņas ir alternatīva sadalītu aplikāciju saziņai, salīdzinot ar RMI
Servleti un JSP
Bieži kalpo par lietotāja interfeisa slāni EJB aplikācijām
Javas pasts (JavaMail)
Ļauj sūtīt pastu platformneatkarīgā veidā
"Enterprise" Javas konektoru arhitektūra (J2EE Connector Architecture)
Piekļuve "enterprise" sistēmu (IBM'a CICS, BEA's Tuxedo, utml.) resursiem vienotā veidā
Javas interfeiss XML parsēšanai (Java API form XML Parsing (JAXP))
Apstrādā XML datus, var veidot Web servisus
Javas autentikācijas/autorizācijas serviss (Java Authentication and Authorization Service (JAAS))
Sadarbība ar drošības sistēmām

Sadalītie objekti

Dalīts objekts (distributed object) ir tāds, kuru var izsaukt attālināti (remotely). Tas notiek sekojoši:

  1. Klients izsauc klienta starpnieku (stub, client-side proxy object). Starpnieks atbild par tīkla komunikāciju klienta pusē, piemēram izsaukuma parametru nosūtīšanu konkrētam TCP soketam.
  2. Klienta starpnieka izsaukums nonāk pie servera starpnieka (skeleton, server-side proxy). Tas saņem soketa izsaukumus un pārveido parametrus atpakaļ uz Javas mainīgo reprezentāciju.
  3. Servera starpnieks deleģē izsaukumu dalītajam objektam, kurš to apstrādā, un tāpat caur abiem starpniekiem rezultātu atgriež klientam.

Atklāta (explicit) starpprogrammatūras lietošana

Starpprogrammatūru, piemēram, transakcijām, drošībai, datubāzu piekļuvei var izmantot tieši - izsaucot dalītajā objektā atbilstošās programmatūras API. Tas notiek apmēram šādi:

transfer(Account account1, Account account2, long amount) {
  // 1. Izsauc drošības API, lai pārbaudītu tiesības
  // 2. Izsauc transakciju API, lai sāktu transakciju
  // 3. Izsauc DB API, lai ielādētu vajadzīgos ierakstus
  // 4. Atskaita "amount" no viena konta, pieskaita otram
  // 5. Izsauc DB API, lai noglabātu izmainītos ierakstus
  // 6. Izsauc transakciju API, lai beigtu transakciju
}

Pieejas īpatnības:

  • Var izmantot pēc vēlēšanās dažādus starpprogrammatūras risinājumus
  • Grūti rakstīt: Garš kods, un biznesa loģika sajaukta ar starpprogrammatūras izsaukumiem
  • Grūti uzturēt: Ja starpprogrammatūras piegādātāji mainās, kodu var nākties pārtaisīt

Slēpta (implicit) starpprogrammatūra

EJB, CORBA un MS .NET īpatnība ir iespēja izmantot starpprogrammatūru, to atklāti neizsaucot:

transfer(Account account1, Account account2, long amount) {
  // 1. Atskaita "amount" no viena konta, pieskaita otram
}

To sasniedz ar sekojošiem soļiem:

  • Deklarē starpprogrammatūras servisus, kurus mums vajag, atsevišķā deskriptorfailā
  • Iedarbina "pieprasījumu pārtvērēju", kurš saņem klienta pieprasījumus, nodrošina vajadzīgos starpprogrammatūras izsaukumus un pēc tam deleģē pieprasījumu tālāk dalītajam objektam

Dalītās skaitļošanas modelis (Distributed computing)

Aplikācijas kodu var sadalīt trīs vai vairāk daļās. Parasti izdala 3 slāņus:

Datu slānis Nodrošina pieeju datiem (relāciju vai objektu datubāzēm). JDBC
Biznesa loģikas slānis Satur aplikācijas biznesa loģiku. Enterprise JavaBeans
Klienta saskarnes slānis Nodrošina saskarni ar klientu. Servleti, JSP lapas

Kad lietot EJB komponentus:

  • Aplikācijai ir jābūt mērogojamai.
  • Ir nepieciešami servisi, kurus nodrošina EJB arhitektūra. Piemēram, lai nodrošinātu datu integritāti, ir jālieto transakcijas.
  • Aplikācijai ir jānodrošina dažādu tipu klienti, piemēram, WEB bāzēts un tradicionālais GUI.

EJB izmantošanas trūkumi:

  • Sarežģītāka aplikācijas izvietošana (deployment).
  • Grūtāka programmas skaņošana (debug).
  • Zemāka aplikācijas ātrdarbība.

Enterprise JavaBeans arhitektūras servisi un iespējas:

Serviss Apraksts
Vārdu un direktoriju serviss. Serviss ļauj tīklā atrast dažādus objektus, izmantojot standarta saskarni (Java Naming and Directory Interface - JNDI).
Datu uzturēšana (persistence). EJB konteiners var veikt EJB komponentu datu automātisku saglabāšanu datubāzē. Tam ir paredzēts atsevišķs komponentu tips - entītes komponents. Šis serviss ļauj izveidot DBVS neatkarīgas datu apstrādes sistēmas, kurām nav nepieciešams programmēt SQL pieprasījumus. EJB konteiners atbalsta arī JDBC standartu un datubāzes savienojumu pūlu.
Iebūvēts transakciju atbalsts. Šis serviss veic transakciju vadību. Rezultātā tiek nodrošināta datu integritāte un nav vajadzīgs programmēt ROLLBACK vai COMMIT tipa SQL izsaukumus. Lai izmantotu šo servisu, komponentu metodēm ir nepieciešams norādīt transakciju atribūtus.
Komponenta dzīves cikla kontrole. EJB komponentiem piemīt dzīves cikls, kuru automātiski kontrolē komponentu izpildes vide - EJB konteiners. Piemēram, retāk izmantotie komponenti var tiek serializēti un izdzēsti no operatīvās atmiņas. Vajadzības gadījumā tie tiek atjaunoti.
Drošības serviss (Java Authentication and Authorization Service - JAAS). Serviss veic lietotāju autentifikāciju - identitātes noskaidrošanu un autorizāciju - lietotāja tiesību kontroli. Komponentu metodēm ir iespējams norādīt lietotāju lomas, kuri drīkst šo metodi izsaukt. EJB konteiners automātiski veic pieejas kontroli.
Daudzlietotāju atbalsts (multithreading). EJB konteiners nodrošina daudzlietotāju atbalstu un pats uzņemas pavedienu vadību. Programmatoriska pavedienu izmantošana EJB komponentos nav nepieciešama un ir aizliegta.

EJB komponentu tipi:

EJB komponenta tips EJB komponenta mērķis
Sesijas Sesijas komponenti modelē biznesa procesus. Tie veic dažādas darbības, piemēram, saskaita skaitļus, pārbauda kredītkartes numuru, veic bankas pārskaitījumus vai izsauc citus EJB komponentus. Sesijas komponentu piemēri: bankas kasieris, kredītkartes validētājs.
Entītes Entītes komponenti modelē biznesa datus. Tie reprezentē biznesa entītes objektus, kuri eksistē patstāvīgajā datu glabātuvē (parasti relāciju datubāzē). Entītes komponenti var būt, piemēram, darbinieks, produkts, kredītkarte utml.
Ziņojumu Ziņojumu komponenti ir līdzīgi sesijas komponentiem, arī tie veic noteiktas darbības. Atšķirībā no sesijas komponentiem, ziņojumu komponentu var izsaukt tikai nosūtot tam ziņojumu. Komponents asinhronā režīmā saņem klientu sūtītos JMS (Java Messaging Service) ziņojoumus.

Enterprise JavaBean komponenta sastāvdaļas:

  • EJB komponenta klase.
  • Home saskarne un komponenta objekta saskarne. Šīs saskarnes var būt lokālas vai attālinātas.
  • EJB izvietošanas deskriptors. Tas apraksta komponenta konfigurāciju un tam nepieciešamos servisus, ko sniedz EJB konteiners.
  • Entītes komponenta primārās atslēgas klase.
  • Citas palīgklases.

EJB komponenta saskarnes:

Attālinātā saskarne Lokālā saskarne (EJB 2.0)
Home saskarne Remote home interface Local home interface
Komponenta saskarne Remote object interface Local object interface

Home saskarnei ir šādas īpašības:

  • Tā satur komponenta dzīves cikla metodes, piemēram, komponenta instances izveidošana, dzēšana, meklēšana.
  • Lai to izsauktu, komponenta instance nav nepieciešama.
Komponenta saskarnei ir sekojošas īpašības:
  • Tā satur komponenta biznesa metodes (ko komponents "dara").
  • Šī saskarne piemīt konkrētai komponenta instancei.

JNDI serviss

Ar JNDI var atrast tīklā dažādus objektus. JNDI ir Java standarta interfeiss ar kura palīdzību piekļūst vārdu un direktoriju servisiem. Vārdu serviss veic sekojošas funkcijas:
  • Objektiem piekārto vārdus. To sauc par binding.
  • Vārdi tiek sakārtoti kokveida struktūrās.
  • Nodrošina iespēju atrast objektus pēc vārda. To sauc par lookup.
  • Dod iespēju vārdiem piekārtot dažādus attribūtus. Šādus vārdus sauc par direktoriju objektiem.
Piemēri:
  • DNS (Domain Name System)
  • failu sistēma.
Direktoriju serviss ir vārdu serviss ar iespēju manipulēt ar direktoriju objektu atribūtiem. Piemēri:
  • LDAP (Lightweight Directory Access Protocol).
  • NDS (Network Directory System).
Direktoriju servisi ir līdzīgu datubāzēm, tie parasti tiek implementēti uz to pamata. EJB serveris parasti satur JNDI implementāciju, kas tiek izmantota sekojošiem mērķiem:
  • Komponentu attēlošana JNDI vārdu kokā, kas ļauj tos sameklēt tīklā.
  • Dažādu resursu, piemēram, datu avotu (DataSource) attēlošana JNDI kokā.

EJB komponentu piemērs

  • Entītes komponents CustomerEJBBean, kas apraksta bankas klientus.
  • Entītes komponents AccountEJBBean, kas apraksta kontus, kuri pieder kādam no bankas klientiem.
  • Sesijas komponents BankSessionEJB. Tas satur metodes, kas veic dažādas darbības, piemēram, atver jaunu kontu vai palielina konta naudas summu.

EJB komponenu klases:

EJB komponenti un to saskarnes:

Vērtības objektu klases:

Izņēmumi (exceptions):

Sesijas komponents BankSessionEJBBean :

// attālinātā home saskarne
public interface BankSessionEJBHome extends EJBHome {
  BankSessionEJB create() 
    throws RemoteException, CreateException;
}

// attālinātā komponenta saskarne
public interface BankSessionEJB extends EJBObject 
{
  CustomerVO[] readCustomers() throws RemoteException;

  void openNewAccount(String personasKods, String kontaNumurs) 
    throws RemoteException,
      DoesntExistException,
      AlreadyExistsException;
       
  void deposit(String kontaNumurs,BigDecimal amount) 
        throws RemoteException, DoesntExistException;
}

// komponenta klase
public class BankSessionEJBBean implements SessionBean {
  private SessionContext ctx;

  public void addCustomer(CustomerVO cust) 
      throws AlreadyExistsException {
    try {
      CustomerEJBLocalHome home 
          = this.getCustomerEJBLocalHome();
      CustomerEJBLocal customer 
          = home.create(cust.getPersonasKods());
      customer.setAdrese(cust.getAdrese());
      customer.setDzimsanasGads(cust.getDzimsanasDatums());
      customer.setUzvards(cust.getUzvards());
      customer.setVards(cust.getVards());
    }  
    catch (DuplicateKeyException ex) {
      throw new AlreadyExistsException("Customer already exists");
    } 
	catch (Exception ex) {
      throw new EJBException(ex);
    }
  }
}

Entītes komponents AccountEJBBean:

// lokālā home saskarne
public interface AccountEJBLocalHome extends EJBLocalHome {
  AccountEJBLocal create(String kontaNumurs) 
    throws CreateException;
  AccountEJBLocal findByPrimaryKey(String primaryKey) 
    throws FinderException;
  Collection findAll() throws FinderException;
}

// lokālā komponenta saskarne
public interface AccountEJBLocal extends EJBLocalObject {
  String getKontaNumurs();
  BigDecimal getSumma();
  void withdraw(BigDecimal amount) 
    throws InsufficientAmountException; 
  void deposit(BigDecimal amount);
} 

// komponenta klase

public abstract class AccountEJBBean implements EntityBean {
  private EntityContext context;

  public abstract String getKontaNumurs();
  public abstract void setKontaNumurs(String newKontaNumurs);

  public abstract BigDecimal getSumma();
  public abstract void setSumma(BigDecimal newSumma);

  public String ejbCreate(String kontaNumurs)
  {
    this.setKontaNumurs(kontaNumurs);
    this.setSumma(new BigDecimal("0.00"));
    return null;
  }
}

Sesijas komponenta atrašana tīklā un izsaukšana:

  1. Inicializē JNDI klasi javax.naming.InitialContext. Šī klase reprezentē savienojumu ar Java vārdu servisa JNDI serveri.
  2. Pēc norādītā vārda meklē sesijas komponenta home saskarni. Ja vārdu serveris atrod šādu saskarni, tad tā tiek atgriezta kā klases java.lang.Object instance.
  3. Atrasto objektu pārveido par nepieciešamo saskarni ar klases javax.rmi.PortableRemoteObject palīdzību.
  4. Izsauc home saskarnes metodi, kas izveido sesijas komponenta instanci. Šī metode atgriež komponenta saskarni.
  5. Komponenta saskarne izmantojama, lai izsauktu komponenta implementētās metodes.

Koda piemērs:

// 1
env.put(Context.INITIAL_CONTEXT_FACTORY, 
  "com.evermind.server.rmi.RMIInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL, "login");
env.put(Context.SECURITY_CREDENTIALS, "password");
env.put(Context.PROVIDER_URL, 
  "ormi://localhost/applicationName");
InitialContext ic =  new InitialContext(env);

// 2 
Object obj = ic.lookup("SessionBeanName");

// 3
SessionBeanHome home = 
  (SessionBeanHome)PortableRemoteObject.narrow(obj,
    SessionBeanHome.class);

// 4
SessionBean bean = home.create();

// 5
bean.doBusinessMethod(String arg1);

Data source konfigurēšana OC4J

Data source objekts ir datubāzes savienojumu fabrika. Tas parasti ir reģistrēts JNDI vārdu kokā. Datu avotus un to JNDI vārdus nepieciešams konfigurēt.
<data-source
  class="com.evermind.sql.DriverManagerDataSource"
  name="OracleDS"
  location="jdbc/OracleCoreDS"
  xa-location="jdbc/xa/OracleXADS"
  ejb-location="jdbc/OracleDS"
  connection-driver="oracle.jdbc.driver.OracleDriver"
  username="scott"
  password="tiger"
  url="jdbc:oracle:thin:@sidecar:1521:ora92"
  inactivity-timeout="30"
/>

2. nodaļa: Sesiju EJB komponenti

Mērķi

  • Saprast parametru nodošanas mehānismu RMI-IIOP gadījumā
  • Saprast JNDI mehānismu EJB komponenšu atrašanai

EJB klienta darbības apraksts

package ejbexample.client;

import java.util.*;
import java.math.*;
import javax.naming.*;			// pakotne, kas satur vārdu servisa klases

import javax.rmi.PortableRemoteObject;

import ejbexample.ejb.BankSessionEJB;		// komponenta saskarne		
import ejbexample.ejb.BankSessionEJBHome;	// home saskarne	
import ejbexample.valueobjects.*;		// vērtības objektu pakotne

public class BankSessionEJBClient 
{
  public static void main(String [] args)
  {
    try
    {
      Context context = new InitialContext();

      Object obj = context.lookup("BankSessionBean");	// meklē home saskarni
	
      BankSessionEJBHome bankSessionEJBHome = (BankSessionEJBHome) 
          PortableRemoteObject.narrow(obj, BankSessionEJBHome.class);

      BankSessionEJB bankSessionEJB;			// komponenta saskarne	

      bankSessionEJB = bankSessionEJBHome.create();	// izveido komponenta instanci	

      CustomerVO cust = new CustomerVO();    	// izviedo klienta aprakstu (value object)

      cust.setPersonasKods("101078-12334");
      cust.setAdrese("Ikskile, Lapu iela - 15");
      cust.setVards("Janis");
      cust.setUzvards("Berzs");
      cust.setDzimsanasDatums( (new GregorianCalendar(1978, 9, 10)).getTime());
				  
      bankSessionEJB.addCustomer( cust);	 // pievieno klienta datus datubāzei

      bankSessionEJB.openNewAccount("101078-12334","8875264445849"); // pievieno konta datus

      bankSessionEJB.deposit("8875264445849",new BigDecimal("124.00"));
	
      System.out.println("acounts...");		
      
      AccountVO[] konti = bankSessionEJB.readCustomersAccounts("101078-12334");

      for (int i =0; i<konti.length; i++)	  // izdrukā kontu sarakstu
      {
        System.out.println(konti[i].getKontaNumurs());
        System.out.println(konti[i].getSumma());
      }
    }
    catch(Throwable ex)
    {
      System.out.println("Error: "+ex.getMessage());
    }
  }
}
Fails jndi.properties Klase InitialConext veic sākotnējo savienojumu ar OC4J. Savienojuma parametrus var nodod šādos veidos:
  • InitialContext konstruktorā padod heštabulu..
  • Izveidot failu jndi.properties, kurā norādīt savienojuma parametrus. Šim failam ir jāatrodas CLASSPATH ceļā.
java.naming.factory.initial=com.evermind.server.rmi.RMIInitialContextFactory
java.naming.provider.url=ormi://localhost/ExampleBankApp
java.naming.security.principal=admin
java.naming.security.credentials=admin

Tipiskie EJB komponenta būvēšanas soļi

  1. Uzraksta java klases, no kurām sastāv EJB komponents: komponenta saskarne, home saskarne un komponenta implementācijas klase.
  2. Izveido izvietošanas (deployment) deskriptoru.
  3. Sakompilē java klases.
  4. Klases kopā ar izvietošanas deskriptoru arhivē jar failā.
  5. Jar failu izvieto EJB konteinerā (serverī).
  6. Var izveidot vienkāršu EJB klientu (izpildāmu java klasi), kas izsauc EJB komponenta metodes.

Piemērs:"Hello World" sesijas komponenta izstrāde.

Mērķis ir izveidot vienkāršu sesijas komponentu, kurš satur vienu metodi, kas atgriež "Hello World !" rindiņu. Šis komponents izmantos attālinātās saskarnes, lai to varētu izsaukt pa tīklu.

Komponenta saskarne.

Komponenta saskarnē norāda komponenta biznesa loģikas metodes. Tā ir attālināta saskarne, tās metodes izsauc pa tīklu. Saskarnei ir šādas īpašības.

  • Visas attālinātās komponenta saskarnes tiek atvasinātas no EJBObject saskarnes.
  • Visām metodēm ir jāmet RemoteException. Šis izņēmums tiek izsaukts tīkla komunikācijas vai servera problēmu gadījumā.
  • Komponenta klasē ir nepieciešams implementēt visas šīs metodes.

Mūsu piemērā nepieciešama tikai viena metode.

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

public interface HelloWorldSessionEJB extends EJBObject 
{
  String hello() throws RemoteException;	
}

Home saskarne

Šī saskarne satur ar komponenta dzīves ciklu saistītas metodes. Piemērā ir nepieciešama tikai viena metode, kas izveido sesijas komponenta instanci. Šī metode atgriež izveidotā komponenta saskarni.

package helloworldejb;
import javax.ejb.EJBHome;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import helloworldejb.HelloWorldSessionEJB;

public interface HelloWorldSessionEJBHome extends EJBHome 
{
  HelloWorldSessionEJB create() throws RemoteException, CreateException;
}

Izvietošanas deskriptors (deployment descriptor)

Izvietošanas deskriptors ejb-jar.xml apraksta komponenta tipu un tā sastāvdaļas.

<?xml version = '1.0' encoding = 'windows-1257'?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
  <enterprise-beans>
    <session>
      <description>Session Bean ( Stateless )</description>
      <display-name>HelloWorldSessionEJB</display-name>
      <ejb-name>HelloWorldSessionEJB</ejb-name>
      <home>helloworldejb.HelloWorldSessionEJBHome</home>
      <remote>helloworldejb.HelloWorldSessionEJB</remote>
      <ejb-class>helloworldejb.HelloWorldSessionEJBBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
</ejb-jar>

OC4J izvietošanas deskriptors

<?xml version = '1.0' encoding = 'windows-1257'?>
<!DOCTYPE orion-ejb-jar PUBLIC "-//Evermind//DTD Enterprise JavaBeans 1.1 runtime//EN" "http://xmlns.oracle.com/ias/dtds/orion-ejb-jar.dtd">
<orion-ejb-jar>
  <enterprise-beans>
    <session-deployment name="HelloWorldSessionEJB" location="HelloWorldBean"/>
  </enterprise-beans>
  <assembly-descriptor>
    <default-method-access>
      <security-role-mapping impliesAll="true" name="<default-ejb-caller-role>"/>
    </default-method-access>
  </assembly-descriptor>
</orion-ejb-jar>

Sesijas komponenta klients

package helloworldejb;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import helloworldejb.HelloWorldSessionEJB;
import helloworldejb.HelloWorldSessionEJBHome;
import javax.naming.NamingException;

public class HelloWorldSessionEJBClient 
{
  public static void main(String [] args)
  {
    try
    {
      Context context = new InitialContext();
	
      // atrod home saskarni
      Object obj = context.lookup("HelloWorldBean");	

      // atrasto objektu pârveido par home saskarni	
      HelloWorldSessionEJBHome helloWorldSessionEJBHome = 
          (HelloWorldSessionEJBHome)PortableRemoteObject.narrow(obj, HelloWorldSessionEJBHome.class);

      // izveido sesijas komponenta instanci
      HelloWorldSessionEJB helloWorldSessionEJB = helloWorldSessionEJBHome.create();

      // izsauc vienu no komponenta metodēm
      String greeting = helloWorldSessionEJB.hello();

      System.out.println(greeting);

      helloWorldSessionEJB.remove();	// izdzēš komponenta instanci
    }
    catch(Throwable ex)
    {
      System.out.println("Error: "+ex.getMessage());
    }
  }

JNDI

Izvietojuma caurspīdīgums

Fiziskais resursu izvietojums klientam EJB vidē ir noslēpts. Sekojošas priekšrocības:

  • Klienta kods nevar tikt piesaistīts konkrētās vides konfigurācijai, jo resursu atrašanās vietas nekur nav iešūtas. Atkalizmantojamās komponentes var cita citu atrast dažādās daudzslāņu situācijās.
  • EJB konteineri var veidot resursu klasterus un klientus automātiski pārsūtīt uz alternatīviem servisiem, ja sākotnēji pieprasītie servisi nedarbojas

A.Čehova stāstā "Vaņka Žukovs" galvenais varonis raksta garu vēstuli, kurai pievieno adresi "На деревню дедушке".

EJB aplikācijas klients, gribot atrast EJB komponentu raksta sekojoši:

// savāc objektu pēc vārdu servisa nosaukuma
Object obj = initialContext.lookup("BankSessionBean");
// pārveido par "Home" interfeisu
BankSessionEJBHome home = (BankSessionEJBHome)
    PortableRemoteObject.narrow(obj,
    BankSessionEJBHome.class);

Vārdu serviss

  • Vārdu serviss saņem vārdu un sameklē šim vārdam atbilstošo objektu
  • Piemēri - "118" telefona dienests, DNS (Domain Name Service), failu sistēma, kura pēc vārda atrod faila fizisko novietojumu, utml.
  • Dažus no objektiem vārdu sistēmā sauc par "direktorijiem" (directory object) - tiem var piemist atribūti
  • Līdzīgas vārdu servisiem ir arī java.util.Map datu struktūras, bet vārdu servisi parasti ir nevis "plakanas", bet gan "sazarotas" vārdnīcas

Vārdu servisu protokoli

  • Lightweight Directory Access Protocol (LDAP)
  • Network Information System (NIS)
  • Network Directory System (NDS) - Novell
  • JNDI - Javas platformneatkarīgs interfeiss uz visiem šiem protokoliem

Tāpat kā JDBC, arī JNDI piedāvā Javas klientiem unificētu interfeisu, bet JNDI funkcionalitāti priekš dažādiem serveriem nodrošina dažādi "servisa piegādātāji", kuri darbojas līdzīgi datubāžu draiveriem.

JNDI jēdzieni

  • Atomārs vārds (atomic name) - nedalāms komponents, kurš var ietilpt saliktā vārdā. Piemēram, /etc/fstab satur divus atomārus vārdus: "etc" un "fstab".
  • Salikts vārds - viens vai vairāki atomāri vārdi, kuri sarakstīti ar atdalītājsimbolu, piemēram "/"
  • Saistījums (binding) - (atomāra) vārda pierakstīšana konkrētam objektam
  • Konteksts - īpaša veida objekts, kurš satur 0 vai vairāk saistījumus
  • Apakškonteksts (subcontext) - tāds konteksts, kura saistījums ir augstāka līmeņa kontekstā
  • Vārdu sistēma (naming system) - savstarpēji saistīti konteksti, kuri izmanto konkrētu vārdu piešķiršanas mehānismu (LDAP personu direktorija, failu sistēma, Javas pakotņu sistēma)
  • Vārdtelpa (namespace) - visi vārdi, kuri ietilpst vārdu sistēmā (piemēram, visu failu vārdi uz diska)
  • Kompozīta vārdtelpa (composite namespace) - vairāku vārdu sistēmu kopsalikums vienā. Piemēram http://java.sun.com/products/ejb/index.html sastāv no šādām vārdtelpām:
    • http - protokolu vārdtelpas elements; tur var lietot arī, piemēram, ftp
    • java.sun.com - DNS kontekstā šim vārdam atbilst konkrēta IP adrese
    • products, ejb, index.html - failu sistēmas vārdtelpas elementi uz Web servera

Sākotnējais konteksts

Sākotnējā konteksta inicializācija:

Hashtable env = new Hashtable(); 
env.put(Context.INITIAL_CONTEXT_FACTORY, 
		  "com.evermind.server.rmi.RMIInitialContextFactory"); 
env.put(Context.SECURITY_PRINCIPAL, "admin"); 
env.put(Context.SECURITY_CREDENTIALS, "base"); 
env.put(Context.PROVIDER_URL, "ormi://localhost/ExampleBankApp"); 
InitialContext ic = new InitialContext(env); 

Šādi izskatās "JNDI pārlūka" spraudnis priekš Eclipse. Tas attēlo JNDI koka struktūru dotajiem JNDI servisa parametriem.

Darbības ar JNDI kontekstiem

list(String), listBindings(String)
Atgriež visu saistījumu sarakstu dotajam apakškontekstam. Piemēram, list("") atgriež paša konteksta saistījumus.
lookup()
Atgriež konkrētajam vārdam atbilstošo objektu. Var izmantot, lai mainītu kontekstus (tāpat kā "cd" komanda direktoriju maiņām)
rename()
maina konteksta vārdu
createSubcontext(), destroySubcontext()
veido un izmet apakškontekstu
bind()
izveido jaunu saistījumu kontekstā, rodas izņēmums, ja vārds jau ir aizņemts
rebind()
izveido jaunu saistījumu kontekstā, vai izmaina veco
unbind()
izmet saistījumu no konteksta

Konteksts tomēr uzvedas savādāk, nekā, piemēram failu sistēmas direktorija java.io.File. Konteksts var darboties tikai ar saviem saistījumiem, bet tas nevar pateikt savu absolūto taciņu (salikto vārdu), vai pāriet direktoriju kokā uz augšu. JNDI kontekstiem bieži nevar arī viennozīmīgi pateikt, kura ir saknes direktorija, jo InitialContext var uzstādīt dažādās vietās - to apakškonteksti pēc tam var daļēji pārklāties.

Komponentu konteinera un JNDI integrācija

  1. Konteiners publicē savas komponentes JNDI kokā
  2. Klients meklē komponenti labi zināmā JNDI sākotnējā kontekstā
  3. Pēc vārda savāc klienta puses starpnieku, utt.

3. nodaļa: Entīšu EJB komponenti

Mērķi

  • Saprast entīšu EJB komponentus
  • Zināt galvenās programmēšanas problēmas saistībā ar transakcijām

Entītes komponenti

Entītes komponenti apraksta biznesa objektus, kuru dati glabājas patstāvīgajā datu glabātuvē, kas parasti ir relāciju datubāze. Parasti katram entītes komponentam ir atbilstoša datubāzes tabula. Entītes komponenta klases mainīgie atbilst tabulas kolonām, katra entītes komponenta instance atbilst vienai rindai (jeb ierakstam) datubāzes tabulā. Entītes komponentus var uzskatīt par relāciju-objektu attēlošanas (O/R mapping) standartu.

Piemērs: Komponenta klase:

public abstract class AccountEJBBean implements EntityBean {
   public abstract String getKontaNumurs();
   public abstract void setKontaNumurs(String newKontaNumurs);
   public abstract BigDecimal getSumma();
   public abstract void setSumma(BigDecimal newSumma);
}

Datubāzes tabula:

Izvietošanas deskriptorā tiek norādīti entītes klases mainīgie, kuru dati tiek glabāti datubāzē, kā arī primārā atslēga.

 <entity>
      <description>Entity Bean ( CMP )</description>
      <display-name>AccountEJB</display-name>
      <ejb-name>AccountEJB</ejb-name>
      <local-home>ejbexample.ejb.AccountEJBLocalHome</local-home>
      <local>ejbexample.ejb.AccountEJBLocal</local>
      <ejb-class>ejbexample.ejb.AccountEJBBean</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.String</prim-key-class>
      <reentrant>False</reentrant>
      <cmp-version>2.x</cmp-version>
      <abstract-schema-name>AccountEJB</abstract-schema-name>
      <cmp-field>
        <field-name>kontaNumurs</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>summa</field-name>
      </cmp-field>
      <primkey-field>kontaNumurs</primkey-field>
</entity>

Entītes komponentiem var būt sekojošas alternatīvas:

  • JDO (Java Data Objects). Alternatīvs O/R mapping Java standarts. Piemēram, Oracle TopLink.
  • JDBC (SQL).

Entītes komponentu īpašības:

  • Komponenti ir datubāzes datu attēlojums objektu veidā. Entītes komponenta instances dati tiek sinhronizēti ar datubāzi. 
  • Datu sinhronizāciju var veikt  EJB konteiners (container managed persistence - CMP).
  • Datu sinhronizāciju var veikt EJB klase (bean managed persistence - BMP).  Šajā gadījumā komponenta klasē jāimplementē metodes, kas to dara (parasti ar JDBC izsaukumiem). Šis gadījums šajā kursā netiks apskatīts.
  • Komponentu instances var tik "atrastas". Komponenta home saskarnes metode findByPrimaryKey() izveido komponenta instanci, ja datubāzē eksistē ieraksts ar norādīto primāro atslēgu.
  • Komponentiem parasti ir tikai lokālās saskarnes.
  • Komponentiem var būt relācijas ar citiem komponentiem.
Piemēram, klientam var būt vairāki konti.
public abstract class CustomerEJBBean implements EntityBean {
  public abstract Collection getKonti();
  public abstract void setKonti(Collection newKonti);
}

Relācija ir aprakstīta izvietošanas deskriptorā.

<ejb-relation>
      <ejb-relation-name>Customer-Accounts</ejb-relation-name>
      <ejb-relationship-role>
        <multiplicity>One</multiplicity>
        <relationship-role-source>
          <ejb-name>CustomerEJB</ejb-name>
        </relationship-role-source>
        <cmr-field>
          <cmr-field-name>konti</cmr-field-name>
          <cmr-field-type>java.util.Collection</cmr-field-type>
        </cmr-field>
      </ejb-relationship-role>
      <ejb-relationship-role>
        <multiplicity>Many</multiplicity>
        <cascade-delete/>
        <relationship-role-source>
          <ejb-name>AccountEJB</ejb-name>
        </relationship-role-source>
      </ejb-relationship-role>
</ejb-relation>

Relācijas

Relācijām var būt visas klasiskās kardinalitātes:

  • viens-pret-vienu.
  • viens-pret-daudz.
  • daudz-pret-vienu.
  • daudz-pret-daudz.
Relācijām var būt virziens:
  • Vienvirziena (unidirectional). 
  • Divirzienu (bidirectional).

Entītes komponenta klases mainīgie var būt trīs tipu:

  • Parasti klases mainīgie.
  • Patstāvīgie lauki (persistent fields). Tie ir lauki, kas tiek saglabāti datubāzē.
  • Relāciju lauki (relationship fields).  Šie lauki satur saistīto entītes komponentu instances.

Patstāvīgie un relāciju lauki ir jānorāda izvietošanas deskriptorā.

Transakcijas

Atomāras darbības

  • Vairākus programmas izpildes soļus var vajadzēt apvienot vienā - nedalāmā jeb atomārā darbībā
  • Piemērs: Naudas pārskaitīšana no viena bankas konta uz citu - naudas atskaitīšanai no viena konta un pieskaitīšana citam kontam ir jānotiek vai nu tā, ka abas darbības ir veiksmīgas, vai (sliktākajā gadījumā) - abas ir neveiksmīgas.

Naiva programma

Ja apvienojamās darbības ir vienkāršas un to ir nedaudz, var izmantot vienkāršus vadības mehānismus:

try {
    // Atskaita summu no 1. konta
}
catch (Exception e) {
    // Ja notika kļūda, neiet tālāk
    return;
}
try {
    // Pieskaita summu 2. kontam
}
catch (Exception e) {
    // Ja notika kļūda, neiet tālāk
    // un atgriež summu atpakaļ 1. kontā
    return; 
}

Problēmas:

  • Vadības komandu var būt daudz
  • Jāparedz katra kļūda un atbilstoši jāaatritina uzsāktā darbība (rollback of the operation)
  • Kods kļūst stipri sarežģīts, ja atomārā darbība sastāv no daudziem soļiem

Nopietnākas problēmas

Transakcijas nekalpo vienīgi programmēšanas ērtumam, jo dalītās aplikācijās var rasties tīkla, datubāzu utml. traucējumi, kuri transakciju nelietošanas gadījumā noved pie katastrofiskām sekām.

  • Klients var saņemt tīkla darbības izņēmumu, piemēram java.rmi.RemoteException, bet tas parasti nesatur informāciju, vai tīkla kļūda radās pirms, vai pēc naudas noguldījuma.
  • Datubāze var nosprāgt datu rakstīšanas brīdī un tā paliek nekonsistentā stāvoklī. Datubāzes lietotājam ir jāinformē datubāzu serveris, kuras darbības ir jāveic kopā (un jāatrullē).
  • Ja vairāki lietotāji labo to pašu tabulu, viņiem ir jāsinhronizē savas darbības. Ja viņi redz viens otra izveidotos nepabeigtos labojumus, nevar garantēt konsistenci.

No šīm situācijām iespējams izvairīties, pienācīgi izmantojot transakcijas.

Transakciju jēdzieni

Transakciju komponents (transactional object)
Dalītās aplikācijas komponents, piemēram EJB komponents, kurš iniciē transakcijas. Piemēram, "banku operāciju komponents".
Transakciju pārvaldnieks (transactional manager)
Koordinē transakciju komponentu darbību
Resurss (resource)
Pastāvīga atmiņa, kurā var lasīt un rakstīt. Piemēram, datubāze, ziņu rinda vai kas cits
Resursu pārvaldnieks (resource manager)
Piemēram, relāciju datubāzes draiveris. Izplatīts interfeiss resursu pārvaldniekiem ir "X/Open XA" resursu pārvaldības interfeiss.
Sistēma (the system)
No transakciju viedokļa ar to var saprast kādas aplikācijas resursu kopumu

Transakciju 4 īpašības (ACID)

Atomicity
Consistency
Isolation
Durability
Atomaritāte (atomicity)
Transakcijā iesaistītās darbības uzvedas kā viena, nepārtraukta atomārā darbība. Uz atomārām darbībām attiecas likums "visu vai neko" - vai nu visas paredzētās darbības tiek izpildītas, vai arī nenotiek nekādas izmaiņas, ja kaut vienā solī gadījās kļūda. Šajā aspektā transakcijas ir robusts kļūdu apstrādes mehānisms.
Nepretrunīgums jeb saskanīgums (consistency)
Nepretrunīgums garantē, ka transakcija saglabā sistēmas stāvokļa invariantu. Piemēram, invariants bankas aplikācijā var prasīt: "Naudas daudzums kontā vienmēr ir pozitīvs". Transakcijas vidū šādu invariantu var izjaukt, radot pagaidu nesaskanīgumu, tomēr pēc transakcijas, invarianta prasības atkal atjaunojas. Ārējam sistēmas novērotājam šķiet, ka sistēma VIENMĒR ir nepretrunīgā stāvoklī.
Izolētība (isolation)
Vienlaikus izpildošās transakcijas neredz cita citas nepabeigtos (un, iespējams, nesaskanīgos) izmaiņu rezultātus. Katra transakcija tādējādi nejūt citus lietotājus un ir izolēta no citām. To sasniedz, lietojot datubāzē sinhronizācijas protokolus.
Ilgstamība (durability)
Garantē, ka resursu izmaiņas pārdzīvo avārijas datubāzē, cietajā diskā, utml. Atjaunojamajiem resursiem ir "log" fails šim mērķim.

Plakanas transakcijas

Pastāv dažādi transakciju modeļi, t.sk. plakanās transakcijas (flat transactions) un saliktās transakcijas (nested transactions). EJB specifikācija prasa, lai būtu plakano transakciju atbalsts.

  • Sākas atomārā darbība, kura sastāv no soļiem, starp kuriem daži rīkojas ar pastāvīgās atmiņas resursiem
  • Beidzot transakciju, rodas viens no diviem rezultātiem - vai nu transakcija tiek komitēta, vai atritināta.

Bieži to uztver kā "nobalsošanas modeli" - ja no daudzajiem soļiem, kuri ir atomārajā darbībā, kaut viens nobalso "pret", tad transakciju atritina.

Saliktas (nested) transakcijas veidotā stāvokļu diagramma drīzāk atgādina sazarotu koku. Kursā sīkāk šo modeli neaplūkosim.

EJB saistība ar transakcijām

EJB komponenti tieši nesadarbojas ne ar transakciju pārvaldnieku, ne ar resursu pārvaldniekiem. Aplikācijas loģika ir augstākā abstrakcijas līmenī. EJB komponenti toties var nobalsot par to, vai transakciju vajag atritināt.

Svarīgi zināt, kurš uzsāk transakciju, kurš izraisa komitēšanu vai atritināšanu, un kad tas notiek. Šīs darbības var uzskatīt par transakcijas robežu nospraušanu (demarcating transactional boundaries). EJB tehnoloģijās ir iespējami 2 veidi, kā nospraust transakciju robežas:

  • Programmējamās transakcijas: EJB komponents pats izsauc vispirms "begin()" un tad "commit()" vai "abort()" komandas
  • Deklaratīvas transakcijas: EJB konteiners pats nodarbojas ar transakcijām un EJB komponentam deleģē tikai aplikācijas loģiku

Ja lietojam deklaratīvas transakcijas, tad deskriptorā src/metadata/ejb-jar.xml attiecīgajam sesijas EJB komponentam rakstām sekojošo.

<ejb-jar>
  <enterprise-beans>
    ...
    <session>
      <description>Session Bean ( Stateless )</description>
      <display-name>BankSessionEJB</display-name>
      <ejb-name>BankSessionEJB</ejb-name>
      <home>ejbexample.ejb.BankSessionEJBHome</home>
      <remote>ejbexample.ejb.BankSessionEJB</remote>
      <ejb-class>ejbexample.ejb.BankSessionEJBBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
	  ...
    </session>
    ...
  </enterprise-beans>
  ...
</ejb-jar>

Tā kā entītes EJB komponenti uztic datu ielādi un ierakstīšanu EJB konteineram, tad tiem vienmēr jālieto deklaratīvās transakcijas - t.i. arī transakciju veikšanu jāuztic konteineram.

Piemērs

Sesijas EJB komponents lieto deklaratīvās transakcijas. Kāda izskatās viena atomāra darbība?

public void deposit(double amt) throws AccountException {
    System.out.println("deposit(" + amt + ") called."); 
	balance += amt;
}

Kas jādara, lai tekošo transakciju piespiestu atritināties? Piemēram, ja ir aizliegts noguldīt 1,000,000.00 vai vairāk. Vai pietiek ar to, ka metam šajā klasē AccountException?

Analoģisks kods, kurš izmanto programmējamās transakcijas:

public void deposit(double amt) throws AccountException {
  javax.transaction.UserTransaction userTran = null; 
  try {
    System.out.println("deposit(" + amt + ") called."); 
    userTran = ctx.getUserTransaction(); 
	userTran.begin(); 
    balance += amt;
    userTran.commit(); 
  }
  catch (Exception e) {
    if (userTran != null) userTran.rollback();
    throw new AccountException("Deposit failed because of " + 
      e.toString());
  }
}

Šo otro variantu mēs saprotamu iemeslu dēļ šajā kursā nelietosim.

Transakciju atribūts

  • Required
  • RequiresNew
  • Supports
  • Mandatory
  • NotSupported
  • Never

No šiem izmantojam "Required"

Transakciju izolācijas līmeņi

Ir sekojošas nevēlamas situācijas (sākot ar pašām nevēlamākajām):

Netīrs nolasījums (dirty read)
Transakcija A labo rakstu datubāzē, transakcija B nolasa šo rakstu, transakcija A atritinās, atgriežoties sākumstāvoklī. Rezultātā B iegūst nepareizus datus, kuri nekad nav bijuši komitēti.
Neatkārtojams nolasījums (unrepeatable read)
Transakcija A nolasa ierakstu, transakcija B labo šo ierakstu, tad transakcija A nolasa šo rakstu vēlreiz. Rezultātā A ir ieguvusi divas dažādas viena raksta vērtības.
Fantomu nolasījums (phantom read)
Transakcija A dod vaicājumu datubāzei ar meklēšanas kritēriju (WHERE apakšizteiksmi); pēc tam transakcija B izveido jaunus rakstus, kuri atbilst šim kritērijam. Visbeidzot A atkārto savu vaicājumu. Rezultātā A 2. vaicājumā ir nolasījusi jaunos - fantomu ierakstus, lai gan visiem vecajiem ierakstiem vērtības nav mainījušās.

Transakciju izolācijas līmeņi un iespējamās problēmas

Izolācijas
līmenis
Netīri
nolasījumi?
Neatkārtojami
nolasījumi?
Fantomu
nolasījumi?
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

Uzdevumi

ejbexercise1: Data source konfigurēšana OC4J konteinerā

Mērķis:

  • Iepazīties ar faila data-sources.xml saturu un konfigurēšanu.
  • Izveidot datu avotu, kuru izmantos piemēra entītes EJB komponenti.

Darbības īsumā:

  • Atvērt failu <OC4J INSTALL>/j2ee/home/config/data-sources.xml.
  • Atribūtā connection-driver norādiet JDBC draivera klasi. Oracle gadījumā tā nav jāmaina.
  • Norādiet atribūtus username, password un url.
  • Atribūtam ejb-location obligāti ir jābūt jdbc/OracleDS.

ejbexercise2: Piemērā doto komponentu kompilēšana un izvietošana OC4J.

Mērķis:

  • Iepazīties ar EJB komponentu arhivēšanu EAR pakotnē un izvietošanu serverī.
Darbības īsumā:
  • Uzbūvēt doto piemēru un izvietot to serverī.
ant
ant ear
deploy
bind
  • Ja datu avots ir sekmīgi izveidots un darbojas, tad komanda deploy paziņo par datubāzes tabulu izveidošanu.
  • Sākotnējo JSP lapu var izsaukt ar URLi http://localhost:8888/ejbexercise1

ejbexercise3: Konsoles EJB klienta izveide.

Mērķis:

  • Iepazīties ar JNDI lietošanu un vienkāršu konsoles
    EJB klientu.
  • Izmainīt un palaist konsoles klientu, kas izveido
    vairākus ierakstus datubāzē.

Darbības:

  • Pirms uzdevuma veikšanas izdzēst no datubāzes tabulas, kas tika izveidotas iepriekšējā lekcijā.
  • Izmantot esošo failu BankSessionEJBClient.
  • Izmainīt bankas klientu datus, piemēram, vārdu, uzvārdu
    vai adresi.
  • OC4J tīkla adrese, lietotājvārds un parole ir jānorāda failā jndi.properties.

EJB komponentus nepieciešams pārkompilēt uz izvietot uz servera ar šādām komandām.

ant ear
ant deploy
ant bind

Ja tas paveikts veiksmīgi, tad var atvērt URLu http://localhost:8888/exampleBankApp

Klientu var pārkompilēt un palaist ar sekojošām komandām.

      ant  compileClient
ant runClient


ejbexercise4: WEB aplikācijas - EJB klienta izveide.

Mērķis:


  • Iepazīties ar EJB izmantošanu JSP lapās. Izveidot
    JSP lappusi, kas parāda klientu sarakstu.

Darbības īsumā:

  • Lapā index.jsp izveidot norādi uz customerList.jsp.
  • Izmantot esošu faila sagatavi customerList.jsp.
  • Vajadzības gadījumā izmainiet OC4J konteinera
    paroli un lietotājvārdu.
  • Esošais kods izveido sesijas komponenta instanci,
    tās saskarne glabājas mainīgajā bankSessionEJB.
  • Jūsu uzdevums ir atrast sesijas komponenta metodi, kas atgriež
    klientu sarakstu un uzrakstīt JSP kodu, kas šo sarakstu parāda uz ekrāna.

EJB un WEB komponentus var pārkompilēt uz atkārtoti izvietot uz servera ar šādām komandām.

ant ear
ant deploy

Izmaiņām ir jābūt redzamām http://localhost:8888/exampleBankApp.



ejbexercise5: WEB aplikācijas papildināšana.


Mērķis:

  • Izveidot JSP lappusi, kas drukā klienta konta sarakstu.

Darbības:

  • Izmantot esošu faila sagatavi accountList.jsp.
  • Izmainīt iepriekšējā uzdevumā izveidotu failu customerList.jsp,
    tā lai tas klientu sarakstā katram klientam izveido norādi, pa kuru
    var nokļūt kontu saraksta lapā, kas parāda norādītā klienta kontu sarakstu.
  • Norādei ir jānodod parametrs ar klienta personas
    kodu.
  • Esošais kods izveido sesijas komponenta instanci, tās saskarne
    glabājas mainīgajā bankSessionEJB.
  • Jūsu uzdevums ir atrast sesijas komponenta metodi, kas atgriež
    kontu sarakstu pēc norādītā personas koda un uzrakstīt JSP kodu, kas
    šo sarakstu parāda uz ekrāna.
  • Norāde: Jums jānolasa JSP lapai padotais parametrs (personas
    kods) un šis kods jāpadod kā arguments sesijas komponenta metodei, kas
    nolasa klienta kontus.

EJB un WEB komponentus var pārkompilēt uz atkārtoti izvietot uz servera ar šādām komandām.

ant ear
ant deploy

Izmaiņām ir jābūt redzamām http://localhost:8888/exampleBankApp.

ejbexercise6: "Hello World" sesijas komponents izvietošana serverī un klienta palaišana

Mērķis:

  • Izvietot serverī "Hello World" sesijas komponentu un palaist klientu, kas to izsauc.

Darbības:

  • EJB komponenta kompilāciju un arhīva izveidi veic ar komandu.
ant ear
  • Ja nepieciešams, tad jāizmaina OC4J lietotājvārds un parole failā build.xml
ant deploy
  • Ja nepieciešams, tad jāizmaina OC4J lietotājvārds un parole failā jndi.properties
  • Klienta kompilāciju un palaišanu veic ar sekojošām komandām:
ant compileClient
ant runClient

ejbexercise7: Metodes pievienošana "Hello World" sesijas komponentam.


Mērķis:
  • Iepazīties ar sesijas komponentu programmēšanas modeli un jaunu metožu pievienošanu sesijas komponentam.
Darbības īsumā:
  • Pievienot sesijas komponentam metodi, kas saskaita divus skaitļus.
Darbības:
  • Pievienot metodes deklarāciju komponenta saskarnei HelloWorldSessionEJB. Norādiet , ka šī metode izsauc izņēmumu (exception) RemoteException. long summa(long a,long b) throws RemoteException.
  • Metodi implementējiet komponenta klasē HelloWorldSessionEJBBean.
  • EJB klienta klasē HelloWorldSessionEJBClient pievienojiet šīs metodes izsaukumu. Rezultātu parādiet uz ekrāna ar komandu System.out.println(...).
  • Izsauciet iepriekšējā uzdevumā minētās komandas.

ejbexercise8: Jaunas metodes pievienošana EJB komponentiem.


Mērķis:
  • Pievienot metodi, kas no konta noņem norādīto summu.

Darbības īsumā:

  • Metode withdraw(BigDecimal amount) jāpievieno konta komponenta klasē un tā lokālajā komponenta saskarnē.
  • Metode withdraw(BigDecimal amount) jāpievieno sesijas komponenta klasē un tā attālinātajā komponenta saskarnē.

Darbību apraksts:
  • Konta komponenta saskarnei AccountEJBLocal jāpievieno metodi void withdraw(BigDecimal amount) throws InsufficientAmountException.
  • Šo metodi nepieciešams implementēt komponenta klasē AccountEJBBean. Ja kontā nav pieprasītās summas, tad ir jāizsauc izņēmums InsufficientAmountException.
  • Sesijas komponenta saskarnē BankSessionEJB jāpievieno metode void withdraw(String kontaNumurs,BigDecimal amount) throws RemoteException, InsufficientAmountException,DoesntExistException.
  • Sesijas komponenta klasē šī metode ir jāimplementē. Tai ir jāatrod konts pēc norādītā numura, izsaucot metodi AccountEJBLocal account = getAccountEJBLocalHome().findByPrimaryKey(kontaNumurs).
  • Jāizsauc konta komponenta metode account.withdraw(amount).
  • Metodes kods jāieliek try blokâ ir izņēmumi ir jāapstrādâ šādi:
      
try
{
...
} catch (InsufficientAmountException ex)
{
this.ctx.setRollbackOnly();
throw ex;
} catch (FinderException ex)
{
throw new DoesntExistException("Account not found");
} catch (NamingException ex)
{
throw new EJBException(ex);
}

Komponentus var pārkompilēt un izvietot uz servera ar komandām:
ant ear
ant deploy

Nelaime #1: Pārāk jauna Javas versija

c:\javakursi\ejbexercise1>java -jar c:/oc4j/j2ee/home/admin.jar ormi://localhost
admin base -deploy -file ejbexercise1.ear -deploymentName ExampleBankApp
Fatal Error: Syntax error in source
...
Auto-deploying ExampleBankApp (Assembly had been updated)...
...
CustomerEJBLocal_EntityBeanWrapper2.java:11: cannot access java.lang.Object
bad class file: c:\j2sdk1.4.0\jre\lib\rt.jar(java/lang/Object.class)
class file has wrong version 48.0, should be 47.0
Please remove or make sure it appears in the correct subdirectory of the classpath.
...
  • Kļūdas cēlonis: OC4J 9.0.3 balstās uz JDK 1.3.1, nevis uz JDK 1.4. Tādēļ jāinstalē versija JDK 1.3.1.
  • Instalējiet, piemēram, JDK1.3.1-05
  • Izmainiet sistēmas mainīgo PATH tā, lai tas norādītu uz c:\jdk1.3.1_05\bin direktoriju
  • Atbilstoši izmainiet arī jakarta-ant-1.5\bin\ant.bat, tur ierakstot rindiņu:
    set JAVA_HOME=c:\jdk1.3.1_05
    

Nelaime #2: Deploy ziņo par nekompilēšanos

Pēc augšminētā "deploy" palaišanas iegūstam apmēram šādu paziņojumu:

Auto-deploying ejbexercise2.jar (ejb-jar.xml had been touched since the previous
 deployment)... Error compiling C:\oc4j\j2ee\home\applications\__ejbexercise2/ej
bexercise2.jar: Error instantiating compiler: IO error writing cache: C:\oc4j\j2
ee\home\application-deployments\HelloApp\ejbexercise2.jar\deployment.cache

Šis paziņojums var rasties arī situācijā, kad jaunais EJB kods uz servera ir veiksmīgi uzlikts. Paziņojumu vienkārši ignorējam.

Daži J2EE termini

ACID properties of transactionstransakciju ACID īpašības
aliassegvārds
atomic nameatomārs vārds
atomic operationatomāra darbība
atomicityatomaritāte
auditinguzraudzība
bindingsaistījums (vārdam ar objektu JNDI servisā)
commitkomitēšana
compound namesalikts vārds
consistencynepretrunīgums, saskanīgums
contextkonteksts (JNDI saistījumu kopa)
crash, catastrophic failureavārija
declarative transactionsdeklaratīvas transakcijas
demarcating transactional boundariesnospraust transakciju robežas
deployment descroptorizvietojuma deskriptors ("ejb-jar.xml" fails)
descriptor filedeskriptorfails (piem., dalītas aplikācijas iestatījumu glabāšanai)
directory objectdirektorijs (vārdu sistēmas jēdziens)
dirty readnetīrs nolasījums
distributed componentdalītais komponents
distributed objectdalīts objekts
dynamic redeploymentdinamiska programmatūras atjaunošana
EJB componentEJB komponents, EJB komponente (nejaukt ar "Java Bean" - parasto "Javas pupiņu")
entity beanentītes EJB komponents
explicit middlewareatklāta starpprogrammatūra
failure atteice
flat transactionplakana/vienkārša transakcija
hanginguzkāršanās
implicit middlewareslēpta starpprogrammatūra
Java 2 Enterprise EditionJavas 2 "Enterprise" izlaidums
Java API form XML Parsing (JAXP)Javas interfeiss XML parsēšanai
Java Authentication and Authorization Service (JAAS) Javas autentikācijas/autorizācijas serviss
Java Messaging Service (JMS)Javas ziņu/vēstu serviss
Java Naming and Directory Interface (JNDI)Javas vārdu un direktoriju interfeiss JNDI
Java Remote Method Invocation (RMI)attālinātie metožu izsaukumi RMI
Java Transaction API (JTA)Javas transakciju interfeiss JTA
Java Transaction Service (JTS)Javas transakciju serviss
legacy systemssenās/mantotās sistēmas
logging notikumu reģistrācija
lookupsameklēšana
message beanziņojumu EJB komponents
message-orientedziņojumorientēts
middlewarestarpprogrammatūra
multitierdaudzslāņu-
namespacevārdtelpa (vārdu sistēmas vārdu kopums); vārdaploks
naming servicevārdu serviss (piemēram JNDI)
naming systemvārdu sistēma
nested transactionsalikta transakcija
parent directoryvecāku direktorija? (1 līmenis augstāk failu sistēmā)
permanent stateilgstošs/permanents stāvoklis
persistent storage pastāvīga atmiņa (faili un datubāzes atšķirībā no programmu mainīgajiem)
phantom readfantomu nolasījums
programmatic transactionsprogrammējamas transakcijas
recoverable resource"atjaunojams resurss (pastāvīgās atmiņas, piemēram, datubāzes atjaunojamība pēc avārijas)"
reference implementationparaugimplementācija (piemēram, Sun standartam)
remotelyattālināti
robustnessrobustums
rollbackatritināšana
session beansesijas EJB komponents
shutdown(servera) apturēšana
skeletonservera stabs/starpnieks/skeletiņš/svira
stubklienta stabs/starpnieks/končiks/svira
test suitetestu virkne
to abortpārtraukt (nejaukt ar "interrupt" - datorarhitektūrā); sk. "rollback"
to crashavarēt
transaction managertransakciju pārvaldnieks (koordinē transakciju komponentu sadarbību
transactional componenttransakciju komponents (dalītas aplikācijas komponente, kura iniciē atomāras darbības)
unrepeatable readneatkārtojams nolasījums

Lapa mainīta 2004-11-15 22:36:26