EJB Enterprise Java Beans
Willemers Informatik-Ecke

Enterprise Java Beans (EJB) sind Komponenten für JEE-Application-Server. Ihre Methoden können sowohl von außerhalb ihres Application Servers als auch lokal aufgerufen werden.

EJBs unterscheiden sich in folgender Hinsicht:

Anlegen eines EJB-Server-Projekts

Mit Eclipse wird ein EJB-Projekt angelegt:
  1. Aus dem Hauptmenü File | New | Other | EJB | EJB-Project, dann Next klicken.
  2. Der Projektname wird in der oberen Zeile eingegeben: EjbKunde
  3. Finish
In diesem Projekt soll eine Session Bean erzeugt werden, die remot aufgerufen werden kann. Dazu:
  1. Klick mit der rechten Maus auf das Projekt EjbKunde
  2. Aus dem Kontextmenü New | Session Bean anklicken
  3. Der Eintrag für das Package muss gefüllt werden: kunde
  4. Class name: KundeEJB
  5. Remote anklicken, so dass der Haken sichtbar wird. Auf diese Weise erhält die Klasse die Annotation @Remote. Als Alternative steht Local zur Verfügung, das zu einer Annotation @Local führt.
  6. Finish
Im Projekt entstehen im Verzeichnis ejbModule/kunde:
  1. Das Interface KundeEJBRemote.java:
    In diesem Interface wird als Beispiel eine abstrakte Methode sagHallo eingetragen. Das Ergebnis sieht so aus:
    package kunde;
    
    import javax.ejb.Remote;
    
    @Remote
    public interface KundeEJBRemote {
        public String sagHallo(String name);
    }
    
  2. Die Klasse KundeEJB.java. Sie implementiert das Interface und muss nun auch die abstrakte Methode implementieren:
    package kunde;
    
    import javax.ejb.LocalBean;
    
    @Stateless
    @LocalBean
    public class KundeEJB implements KundeEJBRemote {
    
        public KundeEJB() {
        }
    
        @Override
        public String sagHallo(String name) {
            return "Hallo, " + name;
        }
    }
    

Das Projekt EJBKunde kann gestartet werden. Dazu wird es mit der rechten Maustaste angeklickt und Run | Run on Server ausgewählt.

Erzeugen eines Remote-Clients

Sie können eine EJB von einem normalen Java SE-Programm ansprechen. Allerdings muss dieses Programm einiges tun. So muss die Verbindung zum Server und dessen Broker geschlagen werden, um dann die Verbindung zur EJB zu finden.

Unter Eclipse wird zunächst ein Client-Projekt angelegt:

  1. Aus dem Hauptmenü File | New | Project | Other | Java EE | Application Client, dann Next
  2. Als Name könnte beispielsweise EjbKundeClient verwendet werden.
  3. Finish
Das Client-Projekt wird mit dem EJB-Projekt verbunden.
  1. Rechte Maustaste auf Projekt, Properies auswählen.
  2. In der linken Spalte Java Build Path auswählen.
  3. Auf der rechten Seite den Reiter Projects anklicken.
  4. Den Button Add anklicken.
  5. Aus den Projekten das Serverprojekt EjbKunde mit einem Haken versehen. Dann OK klicken.
  6. Den Dialog mit Apply and Close schließen.

Anbindung an den Glassfish

Für die Anbindung an den Glassfish wird dem Client die JAR-Datei gf-client.jar hinzugefügt. Sie befindet sich in der Glassfish-Installation unter dem Pfad glassfish/lib/gf-client.jar.

Unter Eclipse kann diese Datei als externe JAR eingebunden, da sich die Installation des Glassfish wohl nicht ändern wird.

  1. Projekt mit rechter Maustaste anklicken und Properties wählen.
  2. In der linken Spalte Java Build Path anklicken.
  3. Auf der rechten Seite den Reiter Libraries anklicken.
  4. Den Button Add External JARs anklicken.
  5. Mit dem Dateiauswahl-Dialog nach glassfish/lib/gf-client.jar in der Glassfish-Installation suchen. Mit OK bestätigen.
  6. Dialog mit Apply and Close beenden.
Bei der Verwendung anderer Application Server müssen andere JAR-Dateien eingebunden werden.

JNDI: Java Name and Directory Interface

Der Cient erreicht die Verbindung zum Server über den Namensdiens Java Name and Directory Interface (JNDI). Dazu wird zunächst ein InitialContext angelegt, dessen Konstruktor eine Properties aufnimmt, über die der Server erreicht wird. Die Einträge für die Properties sind Glassfish-spezifisch.
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import kunde.KundeBeanRemote;

public class Main {
    public static void main(String[] args) throws NamingException {
        new Main();
    }

    public Main() throws NamingException {
        Properties verb = new Properties();
        verb.setProperty(Context.INITIAL_CONTEXT_FACTORY, 
                "com.sun.enterprise.naming.SerialInitContextFactory");
        verb.setProperty(Context.URL_PKG_PREFIXES,
                "com.sun.enterprise.naming");
        verb.setProperty(Context.STATE_FACTORIES,
                "com.sun.corba.ee.imp.presentation.rmi.JNDIStateFactoryImpl");
        verb.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
        verb.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
        Context context = new InitialContext(verb);
        
        KundeBeanRemote kunde = (KundeBeanRemote) context.lookup(
        // ...
Erst durch den Aufruf von lookup wird der Zugriff auf das Kundenobjekt im EJB möglich.

In Zeiten von SOAP und REST ist ein Aufruf einer EJB von einer Standalone-Anwendung eher ungewöhnlich.

Zeitgesteuerte Dienste

Der Application Server verfügt über einen Timer-Service. Um diesen zu nutzen, wird eine Stateless oder Singleton Session Bean angelegt. Unter Eclipse erfolgt dies in folgenden Schritten:
  1. Das EJB-Projekt mit der rechten Maustaste anklicken.
  2. New | Other | EJB | Session Bean auswählen.
  3. Klick auf Next
  4. Im folgenden Dialog wird der Name der Bean eingegeben und ein Haken bei Stateless gesetzt.

Regelmäßig wiederholender Kurzzeit-Timer

Die Bean fügt den TimerService hinzu.

Hinter der Annotation @PostConstruct wird die Methode implementiert, die nach dem Start der Bean laufen soll. Ein Konstruktor ist nicht interessant, weil dieser bereits bei Erstellung der Klasse startet.

Hier wird mit der Methode createTimer ein Timer aufgesetzt, der im Minutentakt regelmäßig die Time-Out-Methode aufruft. Der Start des Timers wird um eine Sekunde verzögert.

Mit der Annotation @TimeOut wird die Methode markiert, die durch den Timer ausgelöst wird. Der Name ist nicht so wichtig, wie der Parameter vom Typ Timer.

@Stateless
@LocalBean
public class TimerSessionEJB {
    
    @Resource
    private TimerService timerService;

    public TimerSessionEJB() {    }

    @PostConstruct
    private void init() {
        timerService.createTimer(1000, 60*1000, "MeineTimerInformation");
    }
    
    @Timeout
    public void execute(Timer timer) {
        System.out.println("Timer: " + timer.getInfo() // obiger String
        + timer.getNextTimeout()      // nächstes Event (Date)
        + timer.getTimeRemaining());  // ms bis zum nächsten Event
    }
}

Zeitversetzte Ausführung

Soll nur eine zeitversetzte Aktion erfolgen, verwendet man TimerConfig.
@PostConstruct
private void init() {
    TimerConfig timerConfig = new TimerConfig();
    timerConfig.setInfo("MeineTimerInformation");
    timerService.createSingleActionTimer(5*1000, timerConfig);
}
Auch hier wird die mit @TimeOut markierte Methode aufgerufen. Der Zeitversatz ist 5 Sekunden.

Scheduling nach Zeitplan

Ähnlich wie beim crontab unter UNIX und Linux kann die Annotation @Schedule eine Ausführung zu bestimmten Zeitpunkten auslösen.

Unter Eclipse können Sie eine Bean mit einem @Schedule erzeugen, indem Sie New | Other | EJB | EJB Timer aus dem Kontextmenü des EJB-Projekts anklicken.

@Stateless
public class TimerEJB {
    public TimerEJB() {    }
    
    @SuppressWarnings("unused")
    @Schedule(second="*/10", minute="*", hour="8-23", dayOfWeek="Mon-Fri",
        dayOfMonth="*", month="*", year="*", info="MyTimer")
    private void scheduledTimeout(final Timer t) {
        System.out.println("@Schedule called at: " + new java.util.Date());
    }
}