Follow Us on Twitter

EJB 3.0, J2EE met beide benen op de grond

April 2005 Al bijna vanaf het begin van de J2EE specificatie, wordt deze bekritiseerd vanwege zijn complexiteit. De kritiek richt zich voornamelijk op de Enterprise JavaBeans (EJB). EJB's zijn het deel van de J2EE specificatie dat de bedrijfslogica (business tier) implementeert. Met bedrijfslogica bedoelen we de logica die vooral rekent, valideert en transformeert met de informatie van het bedrijfsproces, en in mindere mate gaat over de gebruikersinterface, specifieke details van dataopslag en andere technische interfaces. Een ander kenmerk van bedrijfslogica is dat het vaak herbruikbaar is over applicaties.

De complexiteit van de EJB's zou de reden zijn voor de langzame adoptie van J2EE. Java Community Process (JCP), het orgaan dat de Java en J2EE specificaties opstelt, heeft dit probleem onderkend. Daarom heeft JCP het doel van "Java Specification Request 220: Enterprise JavaBeans, Version 3.0" als volgt geformuleerd:

"The purpose of EJB 3.0 is to improve the EJB architecture by reducing its complexity from the enterprise application developer's point of view."

De huidige EJB 3.0 specificatie is nog een voorlopige versie. Bij verschillende partijen zoals JBoss en Oracle zijn er echter al voorlopige versies te vinden van J2EE applicatie servers conform EJB 3.0.

In dit Whitebook zal allereerst kort worden beschreven wat Enterprise JavaBeans zijn. Vervolgens zal getracht worden de kritiek op de huidige EJB specificatie te verduidelijken. Om daarna de oplossingen die de EJB 3.0 specificatie aandraagt te beschrijven. Afsluitend volgt de conclusie.

Wat zijn Enterprise JavaBeans?

Op Sun's website worden EJB's als volgt beschreven:

"Enterprise JavaBeans (EJB) technology is the server-side component architecture for the Java 2 Platform, Enterprise Edition (J2EE) platform. EJB technology enables rapid and simplified development of distributed, transactional, secure and portable applications based on Java technology."

De volgende dingen vallen op in deze beschrijving. EJB's zijn componenten die op een server draaien. In de EJB container van een J2EE applicatie server om precies te zijn. EJB's kunnen gedistribueerd draaien. Dit betekent dat een EJB aangeroepen kan worden over het netwerk. EJB's ondersteunen transacties op de applicatie server. Wanneer er halverwege de uitvoer van EJB methode een fout optreedt, wordt alles teruggedraaid. Dit werkt net als een transactie in een database. EJB's zijn te beveiligen in de configuratie van de EJB's. Ten slotte zijn EJB's uitwisselbaar over J2EE applicatie servers van verschillende leveranciers.

EJB's worden gebruikt om de bedrijfslogica in vast te leggen. In de onderstaande figuur valt te zien hoe EJB's passen binnen de J2EE specificatie. EJB's worden meestal aangeroepen door de web laag van web applicaties of rechtstreeks door Java desktop applicaties. Het ideaal is dat EJB's de logica bevatten die herbruikbaar is. Doordat EJB's gedistribueerd kunnen draaien op de applicatie server kunnen EJB's aangesproken worden door meerdere client applicaties.

EJB's In Context
Figuur 1: EJB's in context

Er zijn drie soorten EJB's. Session, entity en message driven beans. Session beans zijn beans die primair bedoelt zijn om logica/methoden op aan te roepen. Entity beans zijn entiteiten en vormen het domeinmodel van een systeem. Via entity beans kunnen gegevens worden opgeslagen in een database. Ten slotte message driven beans worden gebruikt om inkomende berichten die op een wachtrij (queue) binnenkomen af te handelen. Meer informatie over EJB's kunt u vinden op de webpagina van Sun.

Enterprise JavaBeans zijn complex

In de huidige EJB versie 2.1 moet men voor het draaien van een session of entity bean naast de implementerende klasse, twee interfaces en een xml configuratie bestand schrijven of genereren. De code uit de figuren 2, 3, 4 en 5 is nodig om het befaamde "Hello World" te schrijven. Deze code hoeft niet grondig doorgelezen te worden, de code is slechts bedoeld om een idee te geven wat het betekent om een EJB te implementeren met de huidige EJB versie.

Implementerende van de EJB klasse:

package nl.whitehorses.whitebook.ejb;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloWorldBean implements SessionBean { 
  public void ejbCreate() { } 
  public void ejbActivate() { } 
  public void ejbPassivate() { } 
  public void ejbRemove() { } 
  public void setSessionContext(SessionContext ctx) { } 
  public String helloWorld() { 
    return "Hello world"; 
  }
}

De EJB local home interface:

package nl.whitehorses.whitebook.ejb;import javax.ejb.EJBLocalHome;
import javax.ejb.CreateException;
public interface HelloWorldLocalHome extends EJBLocalHome { 
  HelloWorldLocal create() throws CreateException;
}

De EJB local interface:

package nl.whitehorses.whitebook.ejb;
import javax.ejb.EJBLocalObject;
public interface HelloWorldLocal extends EJBLocalObject { 
  String helloWorld();
}

Het EJB xml configuratie bestand:

<?xml version = '1.0' encoding = 'windows-1252'?>
<!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>HelloWorld</display-name> 
      <ejb-name>HelloWorld</ejb-name> 
      <local-home>nl.whitehorses.whitebook.ejb.HelloWorldLocalHome
      </local-home>
      <local>nl.whitehorses.whitebook.ejb.HelloWorldLocal</local>
      <ejb-class>nl.whitehorses.whitebook.ejb.HelloWorldBean</ejb-class>
      <session-type>Stateless</session-type> 
      <transaction-type>Container</transaction-type> 
    </session> 
  </enterprise-beans> 
  <assembly-descriptor> 
    <container-transaction> 
      <method> 
        <ejb-name>HelloWorld</ejb-name> 
        <method-name>*</method-name> 
      </method> 
      <trans-attribute>Required</trans-attribute> 
    </container-transaction> 
  </assembly-descriptor>
</ejb-jar>

Het bovenstaande code voorbeeld toont aan dat er veel code nodig is om het simpele "Hello World" programma met een session EJB te implementeren.

De huidige manier van werken heeft de volgende nadelen:

  • er is veel onnodig typewerk. De meeste java en xml bestanden kunnen logisch worden afgeleid van de klasse die de helloWorld methode implementeert;
  • het is lastig elementaire kenmerken van de Java taal te gebruiken, zoals overerving en polymorfisme;
  • er is veel specialistische kennis nodig van de interfaces en configuratie bestanden;
  • EJB's zijn moeilijk te testen buiten de J2EE applicatie server. EJB's moeten namelijk eerst op een J2EE applicatie server geïnstalleerd worden om getest te kunnen worden. Dit betekent een forse toename in de doorlooptijd van de bouw-test cyclus.

Enterprise JavaBeans 3.0 "to the rescue"?

Met deze problemen in het achterhoofd is men begonnen aan de EJB 3.0 specificatie . Het hoofddoel van de EJB 3.0 specificatie is het ontwikkelen met EJB's simpeler en productiever te maken.

Om dit te bewerkstelligen heeft JCP verschillende wijzigingen doorgevoerd. Dit zijn belangrijkste wijzigingen in de J2EE specificatie:

  • Afschaffen van EJB interfaces en superklassen;
  • Metadata in de code met behulp van J2SE 1.5 annotaties in plaats van xml configuratie bestanden;
  • Een nieuw lichtgewicht persistentie raamwerk in de plaats van de huidige entity beans;
  • Dependency Injection.

Het resultaat is dat het bovenstaande "Hello World" voorbeeld gereduceerd kan worden tot de code in figuur 6. Ten opzichte van het bovenstaande "Hello World" voorbeeld is dit een behoorlijke reductie aan code en complexiteit. In de komende paragrafen zullen de belangrijkste wijzigingen in de EJB 3.0 specificatie nader toegelicht worden.

Code voor "Hello World" met EJB 3.0:

package nl.whitehorses.whitebook.ejb;
import javax.ejb.*;
@Stateless
@Remote
public class HelloWorldBean { 
  public String helloWorld() { 
    return "Hello world"; 
  }
}

Afschaffen EJB interfaces en superkklassen

Alle klassen die gebruikt worden voor het implementeren van EJB's zijn "Plain Old Java Objects" (POJO's) en Plain Old Java Interfaces (POJI's). EJB's hoeven geen J2EE interfaces meer te implementeren. Zoals te zien is in figuur 6 is de HelloWorldBean een gewone Java klasse zonder levenscyclus methoden als ejbCreate, ejbActivate etc. zoals die in 2 wel te zien zijn. Dit maakt de code leesbaarder en het voorkomt veel nodeloos typewerk, want in de praktijk blijkt dat deze methodes toch veelal leeg blijven.

Annotaties

Voor het genereren van de interfaces en configuratie bestanden wordt al jaren Xdoclet gebruikt. Xdoclet maakt gebruik van JavaDoc-achtige tags in de code om metadata over die code vast te leggen. Met de komst van Java 2 Standard Edition (J2SE) 1.5 ook wel J2SE 5 genoemd zijn dit soort tags (annotaties genoemd) onderdeel van de Java taal . In figuur 6 zijn "@Stateless" en "@Remote" voorbeelden van annotaties. Deze tags vertellen de J2EE applicatie server dat het hier om een sessie EJB gaat. Deze annotaties vervangen het xml configuratie bestand in figuur 5. Deze manier van het vastleggen van metadata is makkelijker, omdat de metadata vastligt bij de code waar de metadata betrekking op heeft. Met minimale toevoegingen kan de benodigde metadata toegevoegd worden. Het grootste voordeel is dat deze annotaties gecontroleerd worden bij het compileren. Bij de meeste ontwikkelomgevingen, zoals JDeveloper en Eclipse worden de code en de annotaties al tijdens het typen gecompileerd. Eventuele syntax fouten in de metadata kunnen hierdoor direct worden gecorrigeerd door de ontwikkelaar. In de huidige situatie komt men er pas runtime achter nadat men de EJB heeft geïnstalleerd op de J2EE server dat men een fout heeft gemaakt. Dit kost aanzienlijk meer tijd tijdens het ontwikkelen.

Persistentie raamwerk entity beans

Het huidige raamwerk van entity beans gaat vervangen worden door een meer lichtgewicht persistentie raamwerk. De entity beans EJB 3.0 specificatie is gebaseerd op de ervaring opgedaan met raamwerken als Toplink en Hibernate. Partijen als de JBoss Group en Oracle zijn sterk vertegenwoordigd in het panel voor JSR-220. Het code voorbeeld in figuur 7 is een voorbeeld van een entity bean. Deze klasse kan worden opgeslagen in de voor Oracle ontwikkelaars bekende tabel EMP. Dit wordt aangegeven met de annotaties @Entity en @Table(name = "EMP"). De annotaties @Id en @Column(name="EMPNO", primaryKey=true) geven aan dat het attribuut empNo de primaire sleutel is van de EMP tabel. Voor de rest van de get<attribuut naam> methoden geldt dat als er een kolom is met dezelfde naam als het attribuut dan wordt het attribuut automatisch gekoppeld aan de kolom in de desbetreffende tabel.

Entity bean Employee met annotaties voor de Emp tabel:

package nl.whitehorses.whitebook.ejb;
import javax.persistence.CascadeType;
...
@Entity
@Table(name = "EMP")
public class Employee implements java.io.Serializable { 
  private int empNo; 
  private String eName; 
  private double sal; 
  @Id 
  @Column(name="EMPNO", primaryKey=true) 
  public int getEmpNo() { 
    return empNo; 
  } 
  public void setEmpNo(int empNo) { 
    this.empNo = empNo; 
  } 
  public String getEname() { 
    return eName; 
  } 
  public void setEname(String eName) { 
    this.eName = eName; 
  } 
  public double getSal() { 
    return sal; 
  } 
  public void setSal(double sal) { 
    this.sal = sal; 
  }
}

Entity beans kunnen, opgevraagd, veranderd en verwijderd worden met behulp van de EntityManager API (Application Program Interface). In het onderstaande codevoorbeeld is te zien hoe in een session bean bewerkingen op EMP tabel/Employee klasse gedaan kunnen worden met behulp van de EntityManager API.

Session bean dat de enity manager API gebruikt om entity beans op te vragen en te bewerken:

package nl.whitehorses.whitebook.ejb;
import java.util.*;
import javax.persistence.*;
import javax.ejb.*;
@Stateless
public class EJBEmployeeManagerImpl implements EmployeeManager { 
  @Inject protected EntityManager em; 
  public void setEntityManager(EntityManager em) { 
    this.em = em; 
  } 
  public EntityManager getEntityManager() { 
    return em; 
  } 
  public void createEmployee(String eName) { 
    Employee employee = new Employee(); 
    employee.setEname(eName); 
    em.persist(employee); 
  } 
  public Collection findAllEmployees() {
    Collection employees = em.createQuery( 
      "SELECT OBJECT(employee) FROM employee employee") 
      .setHint("refresh", new Boolean(true)) 
      .getResultList(); 
    return employees; 
  } 
  public void updateEmployee(String eName, Integer employeeId) { 
    Employee employee = (Employee)em.find("Employee", employeeId); 
    employee.setEname(eName); 
  }
}

Bijvoorbeeld de methode createEmployee maakt een nieuw Employee object aan. Zet de naam van het Employee object. Ten slotte wordt in de createEmployee methode het Employee object in de database opgeslagen door op de variabele van het type EntityManager de persist methode aan te roepen en het Employee object mee te geven als parameter. Door de metadata in figuur 7 weet de EntityManager dat het Employee object opgeslagen moet worden in de EMP tabel.

Dependency injection

Ten slotte is er de nieuwe feature "dependency injection". De annotatie @Inject in figuur 8 is een voorbeeld van "dependecy injection". De J2EE applicatie server injecteert bij het aanmaken van deze Session bean een object van het type EntityManager. De J2EE applicatie server doet dit door de setEnityManager methode aan te roepen bij de creatie van EmployeeManager EJB. Dit zogenaamde injecteren van afhankelijkheden vergemakkelijkt het testen en voorkomt te strakke koppelingen tussen objecten.

Het zetten van afhankelijkheden is erg handig bij het module testen van de EJB's. Doordat de afhankelijkheden van een klasse te zetten zijn met setter methoden is het erg makkelijk om onderliggende afhankelijkheden van EJB's in module tests te vervangen door stubs. Dit maakt het makkelijker om module tests uit te voeren buiten applicatie server. Het testen buiten de applicatie server is erg belangrijk omdat de tijd tussen het corrigeren van een probleem in de software en het kunnen verifiëren of de correctie het probleem heeft opgelost drastisch afneemt. Het installeren op een applicatie server kost namelijk relatief veel tijd. En het is een handeling die een J2EE ontwikkelaar soms wel 30 of 50 keer per dag uitvoert.

Conclusie

Het ziet er naar uit dat de komende EJB 3.0 specificatie veel van de bezwaren die Java gemeenschap heeft tegen huidige specificatie kan wegnemen. Zoals bovenstaande voorbeelden aantonen maakt de EJB 3.0 specificatie het ontwikkelen van EJB's simpeler, productiever en beter testbaar. De veranderingen worden ingegeven door jarenlange praktische ervaring van de Java gemeenschap. J2EE zal een grote stap voorwaarts maken door een eenduidige API te leveren voor het implementeren van bedrijfslogica. De portabiliteit van de bedrijfslogica over J2EE applicatie servers en de portabiliteit van Java programmeurs over projecten zal toenemen met de adoptie van EJB 3.0.

Naast toenemende portabiliteit zal het voor Java programmeurs makkelijker zijn om zich het programmeren met J2EE eigen te maken. Het wordt niet simpel, maar het wordt in ieder geval een stuk minder complex.

Door de betere testbaarheid van EJB's zal het mogelijk zijn om ervaring opgedaan met module testen ook toe te passen op de ontwikkeling van bedrijfslogica met behulp van EJB's. Bij een juiste toepassing van deze ervaring zal de kwaliteit van de bedrijfslogica toenemen in een vroeg stadium van het ontwikkeltraject. Dit zal ongetwijfeld kostenbesparingen met zich mee brengen.

De vraag is echter of de Java gemeenschap niet al te lang gewend is om zijn eigen alternatieven te vinden voor het bouwen van bedrijfslogica. De ontwikkeling van lichtgewicht containers en persistentie raamwerken zoals Spring, PicoContainer en Hibernate heeft namelijk niet stilgestaan. Deze raamwerken zijn alternatieven voor het ontwikkelen van bedrijfslogica. Zij leveren namelijk ook lichtgewicht persistentie, dependency injection en dergelijke. Deze oplossingen bieden echter niet het voordeel van een standaard API. Bijna elk project moet de programmeur weer een nieuw raamwerk leren met zijn eigenaardigheden en eigen API.

Referenties

 

Over de auteur
Joris Wijlens is een van de trekkers van de Java groep. Zijn carriere begon als Oracle consultant, waarna hij zich gespecialiseerd heeft in Java/J2EE applicatieontwikkeling. Joris heeft zijn SUN Programmer en Web Component Developer certificering afgerond en doorloopt nu het architect traject.

Waardering:
 
Tags:

Reacties

Nieuwe reactie inzenden

De inhoud van dit veld is privé en zal niet openbaar worden gemaakt.

Meer informatie over formaatmogelijkheden

CAPTCHA
Deze vraag is om te testen of u een persoon bent en om spam te voorkomen
Image CAPTCHA
Enter the characters shown in the image.