Zugriff auf Backend-Systeme mit Eclipse RCP

Eclipse RCP im Test

Peter Friese, Stefan Reichert

Java hat zu Unrecht den Ruf, sich nur schlecht für die Realisierung von grafischen Benutzeroberflächen zu eignen. Insbesondere im Unternehmensumfeld wurde in den vergangenen Jahren vorzugsweise auf HTML gesetzt, um Java EE-Anwendungen mit Benutzeroberflächen zu versehen. Eclipse RCP vereinfacht die Realisierung von unternehmenstauglichen Desktopanwendungen. Dies bleibt jedoch nicht ohne Auswirkungen auf die Architektur der gesamten Enterprise-Anwendung.

Hauptargumente der Gegner von Java-basierten Clients sind die „langsame Verarbeitungsgeschwindigkeit“ (ein Relikt aus alten Applet-Zeiten) sowie das aufwändige Deployment-Verfahren (neben der Applikation muss auch noch ein JRE deployt werden). Aus diesen Gründen wurden in den vergangenen Jahren viele Anwendungen, die eigentlich besser als Rich Client umgesetzt worden wären, als Webapplikation umgesetzt. Dass diese Argumente nicht (mehr) stichhaltig sind, wissen Eclipse-Benutzer schon seit langem: Eclipse-basierte Anwendungen haben ein natives Look&Feel und werden nahezu genauso schnell ausgeführt wie native Anwendungen. Auch das Deployment ist dank Update-Manager mittlerweile unternehmenstauglich. Doch wie kann die Kopplung eines RCP Frontends an einen Backend-Service erfolgen und was gilt es sonst noch zu beachten?

Was ist eigentlich Enterprise Eclipse RCP?

Große Softwarelösungen im Unternehmensbereich werden aus unterschiedlichsten Gründen häufig mehrschichtig entworfen, denn reine Client/Serverarchitekturen, die einen Großteil der Applikationslogik in den Client verlagern, bringen etliche Nachteile mit sich. Da wäre zum Beispiel das Thema Sicherheit – ein Unternehmen gibt ungern das eigene Know-how in Form der Anwendung heraus. Ein weiterer Aspekt ist die Anforderung, den Business-Tier gegebenenfalls von mehreren Präsentationsschichten, z.B. einem Web-Frontend und einem Mobile Device, nutzbar zu machen oder als Service zur Verfügung zu stellen. Enterprise Eclipse RCP (EERCP) bezeichnet eben solche mehrschichtigen Anwendungen, die als Frontend Eclipse RCP verwenden. Es gibt also eine strikte Trennung des Presentation-Tiers und des Business-Tiers.

Im Gegensatz zu „traditionellen“ Java EE-Applikationen mit einem Web-Frontend sind Java EE-Applikationen mit einer Rich-Client-Applikation als Frontend nicht so weit verbreitet, und es herrscht bezüglich ihrer Architektur noch kein genereller Konsens. Wir stellen hier daher die gebräuchlichsten Architekturvarianten vor und diskutieren ihre jeweiligen Vor- und Nachteile.

Variante 1: Client/Serverarchitektur

Bei dieser Architekturvariante befinden sich sowohl die Präsentationsschicht als auch die Geschäftslogik auf dem Client (Abb. 1). Der Zugriff auf die Datenbank erfolgt direkt aus dem Client heraus. Strukturell ähnelt dieser Aufbau dem einer einfachen Java EE-Webapplikation. Auch hier befinden sich ja GUI (z.B. JSPs) und Businesslogik gemeinsam im Webcontainer, der Browser besorgt nur noch das Rendering (im Fall von Ajax-Applikationen gilt dies im Großen und Ganzen weiterhin, da sich auch hier die Geschäftslogik im Server abspielt).

Abb. 1: Client/Serverarchitektur

Die räumliche Nähe von GUI und Geschäftslogik ist ein wesentlicher Vorteil dieser Architekturvariante. So ist es zum Beispiel möglich, das Lazy-Loading-Feature von Hibernate zu verwenden, um so das Nachladen fehlender Daten zu realisieren.

Allerdings hat die Verlagerung des Datenbankzugriffscodes auf den Client einige Konsequenzen. Zunächst erhöht sich die Anzahl der gleichzeitigen Verbindungen, die die Datenbank verwalten muss, da nun jeder Client eine eigene Verbindung zur Datenbank aufbaut. Connection Pooling ist in diesem Falle nicht möglich. Darüber hinaus muss dafür Sorge getragen werden, dass die Datenbankverbindung zwischen Client und Datenbank sicher ist und nicht abgehört werden kann. Dies ist insbesondere dann wichtig, wenn sich die Clients außerhalb des Unternehmensnetzwerks befinden und über das Internet auf die Datenbank zugreifen sollen. Kaum ein Datenbankadministrator wird den ungeschützten Zugriff aus dem Internet auf seine Datenbank zulassen. Hinzu kommt, dass das JDBC-Protokoll auf der Firewall freigeschaltet werden müsste. Alternativ dazu unterstützen einige JDBC-Treiber das Tunneling des JDBC Protokolls über HTTP, was aber nur instabil funktioniert.

Eine Spielart dieser Variante enthält mehr oder weniger große Teile der Geschäftslogik in der Datenbank (in Form von Stored Procedures), was aber an den prinzipiellen Eigenschaften nichts ändert.

Tab. 1: Vor- und Nachteile der Client/Serverarchitektur

[ header = Seite 2: Variante 2: 3-Tier-Architektur ]

Variante 2: 3-Tier-Architektur

Bei dieser Architekturvariante befindet sich die Geschäftslogik in einem eigenen Tier (Abb. 2). Der Client enthält nur die Präsentationslogik und gegebenenfalls einige einfache Routinen zur Eingabevalidierung. Der Zugriff auf die Datenbank wird vollständig vom Middle-Tier aus durchgeführt, üblicherweise wird hier das DAO-Pattern eingesetzt. Die Geschäftslogik ist gekapselt und kann über definierte Services angesprochen werden. Die dazu verwendeten Zugriffsprotokolle können den Anforderungen entsprechend gewählt werden.

Die Vorteile liegen auf der Hand: Der Zugriff auf die Datenbank ist gekapselt. Üblicherweise steht der Datenbankserver in einer separaten Netzwerkzone, auf die nur der Application-Server zugreifen kann. Dies bedeutet einen weitaus höheren Schutz für die Datenbank. Der Zugriff auf die Geschäftslogik erfolgt über Services. Je nach Anforderungen können entsprechende Endpoints bzw. Stubs geschaffen werden, z.B. für RMI, SOAP, REST oder HTTP. Auf diese Weise ist es auch möglich, die Businesslogik für unterschiedliche Clients (z.B. Eclipse RCP Frontend, Mobile Devices oder auch eine HTML-basierte Webapplikation) zugänglich zu machen.

Nachteilig an dieser Variante ist allerdings, dass die Nutzung des Lazy-Loading-Features des O/R-Mappers einigen Einschränkungen unterliegt. Da User Interface und Businesslogik in getrennten Adressräumen ausgeführt werden, kann der Clientcode das dynamische Nachladen von Datenbankinhalten nicht ausnutzen. Die Folge sind LazyInitializationExceptions. Diese lassen sich auf zwei Wegen umgehen: Entweder man lädt die gegebenenfalls erst später benötigten Daten bereits auf dem Server, indem man entweder das Lazy Loading ganz abschaltet oder die entsprechenden Assoziationen und Collections vorinitialisiert (im Fall von Hibernate mit Hibernate.initialize()). Die Alternative dazu ist die Verwendung des Data Transfer Object (DTO) Patterns: Man bildet pro Use Case (bzw. pro UI-Dialog) passende DTOs und füllt diese mit den Daten, die man mittels Hibernate aus der Datenbank geladen hat. Im Endeffekt initialisiert man auch hier die Entities. Da die DTOs jedoch nicht vom Persistence-Manager gemanaged werden, kann clientseitig niemals eine LazyIniatializationException auftreten.

Abb. 2: 3-Schichten-Architektur

Tab. 2: Vor- und Nachteile der 3-Tier-Architektur

[ header = Seite 3: Variante 3: N-Tier-Architektur ]

Variante 3: N-Tier-Architektur

Die Verlagerung der Geschäftslogik vom Client auf den Server spielt ihre Stärken besonders dann aus, wenn neben der Datenbank auch auf andere Systeme zugegriffen werden muss oder andere Systeme auf das eigene System zugreifen sollen (Abb. 3, 4). Das eigene Backend agiert in diesem Fall als Fassade und kapselt den Zugriff auf die Fremdsysteme. Müssen mehrere Systeme miteinander interagieren, wirkt das eigene Backend als Mediator, harmonisiert die Datenmodelle und routet die Nachrichten.

Bei besonders rechenintensiven Anwendungen können aufwändige Verarbeitungsschritte auf separate Systeme ausgelagert und somit die Anwendung skaliert werden.

Bei all diesen Vorteilen darf nicht vergessen werden, dass die Kommunikation in verteilten Systemen der üblichen Netzwerklatenz unterliegt. Um diese Effekte zu mildern, ist der feingranulare entfernte Zugriff auf Entities zu unterbinden. Grobgranulare Servicezugriffe und die Nutzung von DTOs sind das Mittel der Wahl.

Abb. 3: N-Schichten-Architektur

Abb. 4: N-Schichten-Architektur (mit externen Systemen)

Tab. 3: Vor- und Nachteile der N-Tier-Architektur

Besonderheiten von EERCP

Da im Unternehmensumfeld die 3+-Tier-Variante sehr verbreitet ist, werden wir uns in diesem Artikel auf diese Variante und ihre besonderen Aspekte konzentrieren. Wir möchten dabei nicht auf Eclipse RCP Basics eingehen, sondern die speziellen Herausforderungen einer 3-Schichten-Architektur im Zusammenhang mit Rich Clients herausstellen und im Projektalltag bewährte Lösungen beschreiben.

Die Trennung der Anwendung in einzelne Schichten eröffnet, wie beschrieben, sehr viele Möglichkeiten. Dennoch existieren auch einige Herausforderungen, die es zu bewältigen gilt. Der wesentliche Punkt, der EERCP-Anwendungen auszeichnet, ist die Verteilung, also die Verbindung des Clients mit dem Backend auf dem Server über ein Netzwerk. Die Verteilung bringt weitere Anforderungen an die Architektur mit sich. Diese Anforderungen sind:

  • Remoting: die Art und Weise des Zugriffs auf das Backend
  • Caching: das Vorhalten von Daten auf dem Client zur Reduzierung des Datenverkehrs
  • Security: Authentifikation und Autorisation für einzelne Funktionen des Backend
  • Fehlerbehandlung: Behandlung von serverseitigen und clientseitigen Fehlern
  • Deployment: Bereitstellung und Aktualisierung der fertigen Software

Remoting

Je nach Architekturvariante spielt Remoting eine mehr oder weniger große Rolle. Entscheidet man sich für eine Client/Serverarchitektur, wird die gesamte Remote-Kommunikation vom JDBC-Treiber durchgeführt. Möchte man jedoch eine 3+-Tier-Architektur implementieren, muss man sich intensiver mit dem Thema Remoting auseinandersetzen. Das Umfeld der Anwendung spielt dann eine wichtige Rolle und beeinflusst die Wahl des geeigneten Remoting-Protokolls entscheidend. Müssen die Clients von außerhalb des Unternehmensnetzwerks auf die Applikation zugreifen können, sollte die Kommunikation möglichst Firewall-transparent sein. Gibt es existierende Systeme, auf die zugegriffen werden soll? In diesem Fall muss man entweder das von diesen Systemen unterstützte Kommunikationsprotokoll (also z.B. CORBA-IIOP, SOAP) verwenden oder dieses System mithilfe einer Fassade kapseln (Abb. 3, 4).

Manche Anwendungen erfordern es, dass der Server Benachrichtigungen an das Frontend senden kann. Man muss sich in diesem Fall zwischen Polling und Publish/Subscribe entscheiden, was wiederum eine starke Auswirkung auf das genutzte Kommunikationsprotokoll hat.

Die Kommunikation mit dem Backend soll für das Frontend natürlich völlig transparent sein. Dies will bei der Wahl der Kommunikationstechnologie ebenfalls bedacht sein. Die gute Nachricht ist, dass dies tatsächlich möglich ist. Allerdings darf man hier nicht aus den Augen verlieren, dass die Kommunikation über ein Netzwerk deutlich langsamer ist als ein lokaler Methodenaufruf. Dies hat einen starken Einfluss auf das Design der Service-APIs: Es gilt, kleinteilige Aufrufe wie das sequenzielle Lesen von Attributen zu vermeiden und stattdessen lieber grobgranulare Aufrufe zu tätigen. Das DTO (Data Transfer Object) Pattern kommt hier zu neuen Ehren.

Anhand dieser Anforderungen ist die Wahl zwischen CORBA-IIOP, RMI, SOAP, HTTPInvoker, Hessian etc. zu treffen. Dieses Thema werden wir in einem späteren Artikel vertiefen.

[ header = Seite 4: Caching, Security, Fehlerbehandlung, Deployment, Ausblick ]

Caching

Ein weiterer Aspekt beim Einsatz von RCP-Oberflächen als Frontend für Java EE-Applikationen ist clientseitiges Caching. RCP-Oberflächen qualifizieren sich unter anderem als Frontend, da sie einen extrem guten Bedienkomfort ermöglichen. Datenstrukturen, die über die Oberfläche zum einen sichtbar und zum anderen bearbeitbar gemacht werden, sind in vielen Fällen komplex und umfangreich. Somit tendieren auch die einzelnen Oberflächenteile dazu, komplex und umfangreich auszufallen. Bedienkomfort bedeutet hier, dem Anwender möglichst früh eine Rückmeldung über seine Eingabe zu geben. So werden Fehleingaben vermieden, und die Bedienung der Maske beschleunigt sich erheblich. Ein weiteres Mittel, den Bedienkomfort zu erhöhen und die Validität der Eingabe sicherzustellen, ist die Feldvervollständigung (Content Assist). Dem Benutzer werden die Werte für ein Feld vorgeschlagen, die zu einer gültigen Eingabe führen.

Betrachten wir nun die beiden Anforderungen „clientseitige Validierung“ und „Feldvervollständigung“. Es wird deutlich, dass in beiden Fällen größere Mengen an Daten clientseitig zur Verfügung stehen müssen. Es liegt also nahe, die benötigten Daten wiederzuverwenden, um ein ständiges Laden vom Server und damit teuren (im Sinne der Performance) Traffic zu vermeiden. Allerdings existieren situativ Beschränkungen seitens des auf dem Client zur Verfügung stehenden Hauptspeichers. Wird der Client auf einer Virtualisierungsplattform wie z.B. Citrix ausgeführt, unterliegt der Client üblicherweise recht starken Randbedingungen bezüglich des zugeordneten virtuellen Hauptspeichers. Dies kann durchaus zu Problemen führen.

Eine Lösung dieser Anforderungen liegt in der Abstraktion des Datenzugriffs auf der Clientseite. Der Zugriff auf die Daten des Servers erfolgt über eine zusätzliche Schicht, die ähnlich wie DAOs arbeitet. Hier kann dann transparent ein Caching eingehängt werden, das flexibel auf die spezifischen Anforderungen reagieren kann.

Security

Security ist ein wichtiges Feature nahezu jeder Anwendung im Unternehmensumfeld. Die Daten eines Unternehmens haben einen großen Wert und müssen vor Missbrauch geschützt werden. Der Zugang zu den Daten ist also üblicherweise durch Authentifizierung (ist der Benutzer tatsächlich der, für den er sich ausgibt) und Autorisierung (darf der Benutzer die Daten sehen bzw. bearbeiten) geschützt. Eclipse selbst ist zunächst hauptsächlich als Plattform für Entwicklungstools entstanden und verfügt daher nicht über ein ausgeprägtes Sicherheitskonzept. Um Enterprise-Eclipse-RCP-Anwendungen abzusichern, muss also eine geeignete Authentifizierungs- und Autorisationskomponente integriert werden. Ein kurzer Überblick über die hier möglichen Ansätze:

  • Capabilities: Einzelne Oberflächenelemente werden je nach Nutzerrolle ein- oder ausgeblendet. Dieser Ansatz ist für eine Unternehmensanwendung nicht sicher genug, da er leicht umgangen werden kann (Kimberly Horne: Addressing UI Scalability in Eclipse, EclipseCon 2005 Talk).
  • Load-Time-Modifikation der plugin.xml mit Equinox Transforms. Je nach Nutzerrolle werden einzelne Oberflächenelemente ein- und ausgeblendet. Da diese Transformation nur beim Start der Anwendung durchgeführt wird, ist auch diese Lösung nicht flexibel genug (Heiko Seeberger, Martin Lippert: Getting Hooked on Equinoxwiki.eclipse).
  • Spring Security kann verwendet werden, um nicht nur funktionsorientierte (d.h. der Benutzer darf bestimmte Aktionen nicht ausführen), sondern auch datenorientierte (d.h. der Benutzer darf auf bestimmten Daten keine Aktionen ausführen) Sicherheit zu implementieren (Spring SecuritySpring Security Reference).
  • Equinox Security bietet schließlich Lösungen für die Bereiche User-Credential-Management (d.h. sichere Ablage von Benutzerpasswörtern inklusive Password-Recovery), User Authentication (d.h. Benutzeranmeldung mittels Dialog oder betriebssystemgestütztes Single Sign-on) sowie Codeautorisation (d.h. welcher Code darf ausgeführt werden, Einschleusen von bösartigem Code verhindern).

Alle oben genannten Ansätze lösen jedoch nur Teilaspekte der Sicherheitsanforderungen für Enterprise Eclipse-RCP-Projekte und müssen je nach Anforderung sinnvoll miteinander verbunden werden.

Fehlerbehandlung

Charakteristisch für EERCP-Anwendungen ist, wie wir festgestellt haben, die Verteilung einzelner Schichten auf die Client- bzw. Serverseite. An der Bearbeitung einer Anfrage sind allerdings sämtliche Schichten beteiligt. Selbstverständlich kann die Bearbeitung an sämtlichen Stellen entweder gewollt, durch beispielsweise fehlende oder falsche Daten, oder ungewollt, durch andere Rahmenbedingungen wie Stale Data, unterbrochen werden. In jedem Fall erwartet der Anwender eine für ihn verständliche Darstellung des aufgetretenen Fehlers und im Idealfall eine Handlungsanweisung für dessen Behebung.

Aus Sicht der Architektur gilt es, bei der Fehlerbehandlung das Remoting zwischen Client und Server zu beachten. Fehler, die auf der Serverseite auftreten, müssen in einer dem Client verständlichen Weise zurückgeliefert werden. Der Client sollte diese lediglich darstellen müssen und nicht gezwungen sein, den Fehler mühsam aufzulösen. Es ist wünschenswert, die Fehlerbehandlung möglichst nach einem einheitlichen Schema an einer einzigen Stelle zu halten.

Serverseitig ist die ideale Stelle zur Fehlerbehandlung der Service, der vom Client verwendet wird. Zum einen können hier alle serverseitig auftretenden Fehler der Anfrage zentral abgefangen werden, zum anderen stehen weitere Informationen zur Verfügung, die möglicherweise zur Darstellung des Fehlers benötigt werden. Auch ist denkbar, die Fehlermeldung mit zusätzlichen Daten wie Handlungsanweisungen oder Fehlercodes anzureichern.

Auf der Clientseite ist es ein wenig komplizierter, da die Fehlerbehandlung sich hier in die Aspekte „Darstellung“ und „Behandlung des Fehlers“ teilt. Für die Darstellung empfiehlt es sich, analog zur Serverseite einen zentralen Punkt zu definieren, um eine einheitliche Anzeige zu gewährleisten. Dies kann mit einem Interceptor bzw. einem Aspekt geschehen. Dieser kann im Fehlerfall die Informationen einheitlich darstellen. Die Behandlung des Fehlers muss selbstverständlich individuell von der aufrufenden Stelle erledigt werden.

Deployment

IT-Abteilungen möchten die Kosten für das Rollout und den Betrieb von Anwendungen möglichst gering halten. Dies ist einer der maßgeblichen Gründe für die starke Verbreitung von Webapplikationen im Unternehmensumfeld.

Eclipse bietet bereits seit langem mit dem Update-Manager einen Mechanismus, der die Aktualisierung von Eclipse-RCP-Anwendungen ermöglicht. Seit Eclipse 3.4 steht mit P2 eine aktualisierte Generation des Update-Managers zu Verfügung, die technologisch einen großen Fortschritt bedeutet. Neue Features sind z.B. ein Standalone-Installationsprogramm, ausfallsicherer Download mit der Möglichkeit, abgebrochene Downloads wieder aufzunehmen, sowie die Verwendung des nächstgelegenen Update-Servers (insbesondere bei weltweiten Unternehmensnetzwerken von großer Bedeutung).

Ausblick

Die Implementierung von Enterprise-Eclipse-RCP-Anwendungen ist komplex und erfordert das Nachdenken über eine Vielzahl von Aspekten. Aufgrund der Tatsache, dass es sich hier um eine noch relativ junge Technologie handelt, liegt noch keine Erfahrung auf breiter Basis vor, wie dies bei Java EE-Webapplikationen der Fall ist. Mit dieser Artikelserie soll dazu beigetragen werden, diesen Umstand zu ändern. Feedback zur Serie ist herzlich willkommen.

Geschrieben von
Peter Friese
Peter Friese
Peter Friese arbeitet als Developer Advocate bei Google im Developer Relations Team in London. Er trägt regelmäßig zu Open-Source-Projekten bei, spricht auf Konferenzen und bloggt unter http://www.peterfriese.de. Auf Twitter findet man ihn unter @peterfriese und auf Google+ unter +PeterFriese.
Stefan Reichert
Stefan Reichert
Stefan Reichert, Diplom-Wirtschaftsinformatiker (FH), arbeitet als Software Engineer bei Zühlke Engineering in Hamburg. Er beschäftigt sich seit mehreren Jahren mit verteilten Java-Enterprise-Anwendungen, serviceorientierten Architekturen, Eclipse und Eclipse RCP. Seit einiger Zeit begeistert ihn die Entwicklung von Apps mit Android. Darüber hinaus ist er Buchautor und verfasst regelmäßig Fachartikel. Kontakt: stefan[at]wickedshell.net, http://www.wickedshell.net/blog
Kommentare

Schreibe einen Kommentar

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