Kundendatenbanken mit EJB 3 virtualisieren - JAXenter
Abhängig vom zugreifenden Kunden die richtige Datenbank zur Laufzeit auswählen

Kundendatenbanken mit EJB 3 virtualisieren

Johann Zagler

Oft wird an ein System die Anforderung gestellt, dass damit mehrere Kunden mit unterschiedlichen Datenbankdistributionen verwaltet werden können. Dies kann unterschiedliche Gründe haben, meistens jedoch, stellt der Kunde selbst die Anforderung, dass seine Daten nicht mit denen von anderen Kunden vermischt werden. Diese Anforderung lässt sich mithilfe des EJB3 EntityManagers sowie Konfigurationen im ejb-jar.xml und einem generischen DAO (Data Access Object) Layer ohne viel Aufwand umsetzen.

Viele Applikationen sowie Java-EE-Anwendungen werden heute genau an Kundenanforderungen angepasst und so detailliert spezifiziert, dass diese ohne Modifikationen oder Neuentwicklungen nicht für weitere Kunden verwendet werden können. Durch die EJB3-(Enterprise-JavaBeans-)Spezifikation ist das Entwickeln solcher Systemen einfacher geworden. Die JPA (Java Persistence API) ermöglicht den Einsatz von Entity Beans und bringt ein standardisiertes OR Mapping (Object Relational Mapping) mit sich. Des Weiteren wird im Package javax.persistence das EntityManager Interface angeboten, um den Zugriff auf die Entitäten zu ermöglichen. Die Implementierung des EntityManagers wird von einem OR Mapping-Anbieter wie Hibernate oder Toplink bereitgestellt. Üblicherweise wird der EntityManager innerhalb eines EJB Containers mittels der Annotation @PersistenceContext aus dem Package javax.persistence, geladen:

@PersistenceContext(unitName = "PERSISTENCE_UNIT_NAME")
private EntityManager entityManager;

Der unitName-Parameter der Annotation muss bereits zur Programmierzeit bekannt sein und lässt somit keinen Spielraum für ein dynamisches Wechseln der dahinter liegenden Datenbanken zu. Es stellt sich die Frage, wie es nun möglich wird, eine solche Dynamik in den Code zu bringen.
Um für den oben genannten generischen DAO Layer eine bestmögliche Anwendung zu gewährleisten, ist es ratsam, ein eigenes Entity-Interface (Marker-Interface) anzubieten (Listing 1). Damit sollten alle Entitäten des Systems das Marker-Interface implementieren. Dieses Interface ermöglicht auch ein einfaches Anbinden an Legacy-Systeme.

Listing 1: Entity-Marker-Interface und konkrete Entity-Klasse
// Marker interface.
package javamagazin.virtual.entities;
import java.io.Serializable; 
public interface Entity extends Serializable { 
}
// Entity class
package javamagazin.virtual.entities;
@Entity
public class User implements Entity {
....private static final long serialVersionUID = -7931125774297472732L;
    @Column(nullable = false)
    private String username;
    private String firstname;
    private String lastname;
    // ... getter and setter Methods
}

Der generische DAO Layer teilt sich in ein BaseDao-Interface und eine BaseDaoImpl-Implementierung. Dieses BaseDao-Interface ist ein Wrapper für den EntityManager. Methoden für das Laden von einzelnen und mehreren Entitäten sowie das Speichern, Updaten und Löschen werden von Entitäten angeboten. Wie die Aufteilung in Interface und Implementierung vermuten lässt, wird dieses DAO als EnterpriseBean angeboten. Oft ist es sinnvoll, das BaseDao sowie die dazugehörige Implementierung nicht als EnterpriseBean zu deklarieren, sondern für unterschiedliche Projekte eigene DAO-Interfaces und -Implementierungen, die das BaseDao erweitern, anzubieten (Listing 2), um weitere spezifischere Methoden zur Verwaltung von Interaktion mit Entitäten bereitzustellen.

Listing 2: BaseDao und Erweiterung
// BaseDao interface
package javamagazin.virtual.dao;
public interface BaseDao {
     T get(String key, Class entity, Serializable id); 
     T load(String key, Class entity, Serializable id)
        throws NoSuchEntityException; 
     T getByQuery(String key, String namedQuery,
        Object... parameters); 
     T loadByQuery(String key, String namedQuery,
        Object... parameters) throws NoSuchEntityException; 
     List findByQuery(String key, String namedQuery,
        Object... parameters); 
     Serializable save(String key, T entity); 
     void update(String key, T entity); 
     void delete(String key, T entity); 
     Serializable merge(String key, T entity); 
     void refresh(String key, T entity); 
     void refresh(String key, List entities); 
}
// Concrete local dao interface
package javamagazin.virtual.dao;
@Local
public interface VirtualDao extends BaseDao {
    // Any specific methods for the VirtualDao.
}
// concrete stateless enterprise bean
package javamagazin.virtual.dao;
@Stateless
public class VirtualDaoImpl extends BaseDaoImpl implements VirtualDao {
    // Implementation of all specific VirtualDao methods.
}

Wie in Listing 2 zu sehen ist, übernimmt jede Interfacemethode einen Schlüssel (key). Dieser Schlüssel ist ausschlaggebend, um den für den zugreifenden Kunden richtigen EntityManager zu laden. Konfiguriert wird dieser Zugriff in der ejb-jar.xml.

Geschrieben von
Johann Zagler
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.