CDI für Rich Clients

Integration von JPA

Mithilfe des Resource-Plug-ins von OpenWebBeans ist es möglich, sich bestimmte Ressourcen des Containers injizieren zu lassen. Zum Beispiel kann man sich den EntityManager von JPA über @PersistenceContext und die EntityManagerFactory über @PersistenceUnit injizieren lassen. Dazu wird vom Resource-Plug-in der StandaloneResourceInjectionService zur Verfügung gestellt. Dieser Service verwendet Persistence.createEntityManagerFactory(unitName), um die EntityManagerFactory zu erstellen. Leider hat dieser Aufruf in unserer Eclipse-RCP-Version nicht funktioniert, und wir mussten den PersistenceProvider von EclipseLink zum Erstellen der EntityManagerFactory verwenden. Wir erweiterten dazu den Standardservice und erstellten den EclipseOsgiResourceInjectionService, der – wie der Scannerservice – in der OpenWebBeans-Konfigurationsdatei unter org.apache.webbeans.spi.ResourceInjectionService registriert werden musste. Jetzt konnten wir uns über @PersistenceContext den aktuellen Entity Manager in alle unsere Klassen injizieren lassen.

Projektarchitektur

Bewaffnet mit jeder Menge Dependency Injection Support, wurde das gesamte Projekt umstrukturiert. Wir entschieden uns für eine klare Schichtentrennung von User Interface, Services und Persistenz. Zum User Interface zählten dabei alle Klassen, die wir über unsere CdiExtensionFactory erstellen lassen; also Extension-Point-Implementierungen und Command Handler von Eclipse RCP. Diese Klassen kümmerten sich um die gesamte Benutzerinteraktion und mussten für jegliche Logikoperationen bzw. Datenzugriffe die darunterliegende Serviceschicht verwenden. Wir erstellten für alle logisch zusammenhängenden Geschäftsfälle ein Serviceinterface und die passende Implementierung dazu, die wir mit @ApplicationScoped annotierten. Anschließend konnten wir uns die Serviceinstanzen in die UI-Klassen injizieren lassen. Listing 5 zeigt die Injektion von TicketService in einen Editor.

Listing 5
@EclipseExtension(SellTicketsEditor.ID)
public class SellTicketsEditor extends EditorPart {

    public static final String ID = "at.ticketline.kassa.ui.editor.sellTickets";
    
    @Inject
    private TicketService ticketService;

    // Code, der ticketService verwendet.
}

In der Serviceschicht verwendeten wir den gleichen Architekturansatz, um auf die Persistenzschicht zuzugreifen. Wir erstellten pro Entität ein dazugehöriges Data Access Object (DAO), das wir wiederum mit @ApplicationScoped annotierten. Nun konnten wir uns in unsere Service-Implementierungen die benötigten DAOs injizieren lassen. Listing 6 zeigt die Injektion einiger DAOs in die Implementierung von TicketService.

Listing 6
@ApplicationScoped
public class TicketServiceImpl implements TicketService {
    
    @Inject
    private SeatDao seatDao;
    
    @Inject
    private TransactionDao transactionDao;
    
    @Inject
    private CustomerDao customerDao;
    
    // Implementierung von TicketService.
}

Durch klare Spezifikation der Interfaces zwischen den Schichten war es uns möglich, große Teile des Projekts komplett unabhängig voneinander zu entwickeln und zu testen.

Kommentare

Schreibe einen Kommentar

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