Rich Client Entwicklung mit Java Kai Aras Medieninformatik - SS 09 1 1. Rich-Client Entwicklung mit Java........................................................ 4 2. Was ist ein Rich-Client ?.............................................................................. 4 3. Was ist eine Rich-Client-Platform ?............................................................. 4 4. Wiso eine Rich-Client-Platform ?................................................................. 4 5. Netbeans Platform..................................................................................6 6. Geschichte der Netbeans Platform.............................................................. 6 7. Netbeans Platform Architektur Alles ist ein Modul........................................ 6 8. Netbeans Classloader System......................................................................... 7 9. Beispiel Netbeans IDE......................................................................................8 10.Grundliegende Konzepte............................................................................. 9 11. Strenge Modularisierung.................................................................................. 9 12. Loose Coupling................................................................................................ 9 13. Lazy Loading.................................................................................................. 10 14. Deklarative Beschreibung (System Filesystem)............................................. 10 15.Auszug aus Modulen und APIs.................................................................. 11 16. File Systems API............................................................................................ 11 17. Data Systems API........................................................................................... 11 18. Lookup API..................................................................................................... 11 19. Nodes API ..................................................................................................... 12 20. Explorer API.................................................................................................... 13 21. Visual Library API........................................................................................... 13 2 22.Anpassung und Deployment...................................................................... 15 23. Netbeans Module (NBM)................................................................................ 15 24. Zip Distribution............................................................................................... 15 25. Mac OSX Application......................................................................................15 26. Java WebStart (JNLP).................................................................................... 15 27.Quellen................................................................................................. 17 3 Rich-Client Entwicklung mit Java Was ist ein Rich-Client ? Der Begriff Rich Client stammt aus der Client-Server Architektur und beschreibt eine Anwendung bei der die eigentliche Datenverarbeitung lokal, also vom client, anstatt vom entfernten Server ausgeführt wird. In der Regel besitzt ein Rich-Client eine grafische Benutzeroberfläche (GUI) und bietet die Möglichkeit, neue Funktionalitäten in Form vom Modulen oder Plugins einzubinden. Grundsätzlich besitzt ein Rich-Client die folgenden Eigenschaften: a. b. c. d. e. f. Flexible und modulare Architektur kann leicht an den Benutzer angepasst werden ist Platformunabhänig unterstützt sowohl Online- wie auch Offline-Arbeiten bietet Möglichkeiten zum einfachen Deployment bietet Möglichkeiten den Client zu Aktualisieren Was ist eine Rich-Client-Platform ? Eine Rich Client- Platform ist ein Framework sowie eine Laufzeitumgebung zur Entwicklung von Rich-Client Anwendungen. Da sich viele grundsätzlichen Funktionalitäten und Komponenten, wie Menus, Toolbars, Splash-Screen, Konfigurations-Verwaltung oder Hilfe-System in beinahe allen DesktopAnwendungen wiederfinden, stellt eine Rich-Client-Platform ein Framework dar, mit hilfe dessen genau diese generischen Aufgaben einer Desktop-Anwendung schnell, einfach und stabil umgesetzt werden können, und dem Entwickler so mehr zeit für die eigentliche Anwendungslogik bleibt. Aufgrund der modularen Architektur einer Rich-Client-Platform, erfolgt die Entwicklung einer Anwendung auf Basis einer Rich-Client-Platform in einzelnen Modulen. Ein Modul kapselt eine bestimmte Funktionalität und definiert seine öffentlichen Schnittstellen, sowie eventuelle Abhänigkeiten zu anderen Modulen und stellt so einen unabhänigen, erweiterbaren Bestandteil der modularen Architektur der Platform dar. Wiso eine Rich-Client-Platform ? Die Verwendung einer Rich-Client-Platform zur Entwicklung von Desktop-Anwendungen bringt enorme Vorteile mit sich. Nachfolgende Auflistung gibt einen kurzen Überblick über die 4 überzeugendsten Argumente die für die Verwendung einer Rich-Client-Platform sprechen. • kürzere Entwicklungszeit Durch die vielzahl an zur verfügung gestellen APIs können nebensächliche Funktionalitäten weitaus schneller umgesetzt und ausserdem auch wiederverwendet werden. • Konsistente Benutzeroberfläche Die Bewertung von Software unter dem Aspekt der Usability spielt einer immer größere Rolle, so stellen Rich-Client-Platformen in der Regel Frameworks zur Oberflächengestaltung bereit, welche diesen Aspekt bereits berücksichtigen. • Software Updates Der von grund auf modulare Aufbau einer Rich-Client-Platform erleichtert das umsetzten, bzw Durchführen von Software Updates ungemein. Durch die strenge Modularisierung können Neuerungen Modulweise unabhängig von unterschiedlichen Teams entwickelt und andererseits auch unabhängig von einander ausgeliefert werden. • Platformunabhänigkeit Rich-Client-Platformen basieren auf gut durchdachten Standarts und wiederverwendbaren Komponenten, so ist beispielsweise eine Anwendung die auf einer java-basierten Rich-Client-Platform basiert automatisch auf einer vielzahl von Systemen lauffähig. Voraussetzung ist natürlich eine vorhandene Java- Virtual Machine, bzw Java Runtime Environment. 5 Netbeans Platform Geschichte der Netbeans Platform Anfangs noch ohne RCP-Platform und unter dem an Delphi angelehnten Namen Xelfi, erblickte Netbeans 1997 in Tschechien das Licht der Welt. Eine Gruppe Studenten hatte sich damals zur Aufgabe gemacht die erste komplett in Java geschriebene Entwicklungsumgebung zu erschaffen. Das daraus entstandene und später komerzialisierte Produkt Netbeans Developer X2 wurde schließlich ende der 90er Jahre von den Java machern selbst, Sun Microsystems übernommen und kaum ein halbes Jahr später schließlich auch "open sourced". Hier beginnt die eigentliche Geschichte der Netbeans Platform, nach der Übernahme von Sun und Veröffentlichung der Quellen wurde die Netbeans Runtime rasch als Basis zum Bau beliebiger Desktopanwendungen, fern ab von IDE-Anwendungen gebraucht. Daraufhin wurde in den folgenden Jahren, seitens Sun, viel Zeit in die entwicklung der Netbeans Platform gesteckt. Netbeans Platform Architektur Alles ist ein Modul Im Kontext der Netbeans-Platform ist alles ein Modul, d.h. das Prinzip der Modularisierung wird bis in den Kern der Platform selbst, dem Runtime Container, angewandt. So besteht nämlich dieser ebenfalls aus einzelnen Modulen, die zusammen die minimalste Form einer Rich-ClientAnwendung bilden. 1. Bootstrap initales Modul, erzeugt einen Boot-Classloader welcher das Startup Modul lädt und ausführt. 2. Startup initalisiert Module System und File System 3. Module System API verwaltet installierte Module und deren Abhänigkeiten 4. File System API stellt ein platformunabhäniges virtuelles Dateisystem zur verfügung. 5. Utilities API stellt diverse Basisfunktionalitäten u.a das Lookup für Intermodul-Kommunikation bereit. 6 Netbeans Classloader System Voraussetzung für die modulare Architektur und damit auch der Kapselung in Module ist das Netbeans Classloader System. Das System arbeitet mit drei unterschiedlichen Classloadern, dem: o o o Original Classloader Module Classloader System Classloader wobei der Original Classloader beim Start der Anwendung vom zughörigen Application Launcher erzeugt wird, und zunächst sämtliche Klassen und Resources vom original CLASSPATH lädt. Module- und System Classloader sind im gegensatz zum Original Classloader multiparent Classloader, können also mehrere Parent-Classloader besitzen. Findet der Original Classloader anhand seiner Manifest-Information ein Modul, erzeugt er dafür eine Instanz des Module Classloaders, dieser wiederum lädt dann die eigentlichen Klassen des Moduls. Ein Modul Classloader besitzt neben dem Original Classloader sämtliche Classloader der Module zu denen eine Abhänigkeit besteht als Parent. 7 Der System Classloader besitzt als Parent die Classloader aller bekannten Module, lädt allerdings keine Resourcen selbstständig, stattdessen kann er verwendet werden um Resourcen aus unbekannten Modulen zu laden. Beispiel Netbeans IDE Referenzbeispiel für eine Rich-Client Anwendung auf Basis der Netbeans Platform ist sicherlich die weitverbreitete Entwicklungumgebung Netbeans IDE. Generell kann man sagen, die Netbeans IDE setzt sich zusammen aus der Netbeans Platform und einem Satz von BasisModulen die grundsätzliche IDE Funktionalitäten zur verfügung stellen. Darauf aufbauend existieren Module oder Module-Suites, welche die Netbeans IDE um konkrete Sprach-Umgebungen wie Java, C/C++, SOA oder Python erweitern. Siehe nachfolgende Grafik. Aufgrund dieser Modularen Architektur ist es möglich verschiedene "schlankere" Distributionen der Entwicklungsumgebung wie Java- oder Python-only anzubieten. 8 Grundliegende Konzepte Nachfolgend möchte ich einige der zentralen Konzepte der Netbeans Platform vorstellen. Strenge Modularisierung Damit große und vorallem komplexe Anwendungen auch über die Zeit wart- und erweiterbar bleiben bietet sich das Konzept der Modularisierung an. Wie bereits erwähnt, lässt sich die Netbeans Platform durch das Kapseln von Funktionen in Modulen erweitern, dies bringt einige Vorteile mit sich. Loose Coupling Basierend auf der Modularen Architektur der Netbeans Platform existiert das so genannte Lookup (mehr hier zu in Kapittel ...) Eine der Hauptaufgaben des Lookups ist das Suchen und Finden von Services, das Lookup fungiert also als dynamischer Service Locator und ermöglicht so die Trennung von Service Interface und Service Provider. Durch diese Trennung kann ein ModulA Funktionalität aus einem ModulB nutzen, ohne dessen Implementation zu kennen, oder anders gesagt, es entsteht eine lose Kopplung zwischen diesen Modulen. Um dies zu verdeutlichen möchte ich hierzu ein kleines Beispiel aufführen. Wir nehmen an wir bauen einen Text-Editor und wollen dem Benutzer den Export in verschiedene Dateiformate ermöglichen. Um die Vorteile des Lookups nutzen zu können und somit Service Interface und Service Provider unabhänhig von einander bleiben, definieren wir 3 Module: 1. Modul A: export.spi (Service Provider Interface) 2. Modul B: exportDOC (Service Provider Implementation) exportPDF exportRTF exportTXT 3. Modul C: editor (unser Text-Editor) Um die export Funktionalität nun in ModulC, also unserem Editor nutzen zu können, definieren wir eine Abhänigkeit von ModulC zu ModulA, also vom Editor zum Service Provider Interface. Damit unsere Service Provider Implementierungen das zugehörige Service Provider Interface auch implementieren können, müssen wir zusätzlich eine Abhänigkeit von ModulB nach 9 ModulA definieren. Durch diese Trennung ist es jetzt möglich vom Editor aus, sämtliche Service Provider Implementierungen aus ModulB zu verwenden, ohne dass eine Abhänigkeit zu diesem Modul besteht, sie sind also entkoppelt. Lazy Loading Lazy Loading ist ein Design Pattern, das immer dann eingesetzt wird wenn es von Vorteil ist eine Anwendung nicht bereits beim Anwendungsstart komplett zu initialisieren. Stattdessen werden bestimmte Objekte erst denn initialisiert, wenn sie tatsächlich gebraucht werden. Es existiert auch ein gegenteiliges Pattern, genannt Eager Loading. So würde ein Filebrowser nach dem Lazy Pattern den Inhalt eines Ordners erst dann initialisieren, wenn der User diesen sehen möchte, wärend bei der Verwendung des Eager Patterns sofort das komplette vom Browser erfasste Dateisystem initialisiert werden würde. Die Vor- bzw Nachteile dieser Design Patterns liegen auf der Hand, und sollten je nach Anwendungsfall nicht unbeachtet gelassen werden. So würde ein Filebrowser nach dem EagerPattern einen erheblichen speicher-bedarf zur folge haben, wärend dies bei der Verwendung des Lazy-Patterns kein Problem darstellen würde, wäre stattdessen bei Ordnern mit vielen Kind-Elementen mit eventuellen wartezeiten zu rechnen. Deklarative Beschreibung (System Filesystem) Damit Anwendungen auf Basis der Netbeans Platform möglichst flexibel und erweiterbar bleiben, muss die Möglichkeit bestehen Änderungen oder Erweiterungen nicht nur über Änderungen am Code selbst einzubringen. Hierzu besteht die Möglichkeit, Fenster, Menus, Aktionen, Toolbars usw. durch blose deklarative Beschreibungen in einer Art Konfigurationsdatei einzubinden. Konkret benutzt man dazu das System Filesystem. Das System Filesystem ist ein virtuelles XML-Filesystem und besteht aus vielen einzelnen Layer-Files. Jedes Modul, dass deklarativ etwas zur Anwendung beitragen will, enthält ein solches LayerFile, im allgemeinen bezeichnet als XML-Layer und konkret benannt als layer.xml. Beim start der Anwendungen werden sämmtliche XML-Layer zu einem XML-Filesystem gemerged, und bilden so das System-Filesystem. 10 Auszug aus Modulen und APIs Im folgenden Abschnitt möchte ich einge der zentralen APIs ,der Netbeans Platform vorstellen. File Systems API Die Netbeans File Systems API bietet transparenten Zugriff auf Daten aller Art, bzw aus Dateisystemen aller art. So können mit ihrer Hilfe lokale Dateien, genau so wie entfernte Dateien oder Elemente in einem XML-Baum verwaltet werden. Dabei wird der Zugriff auf Daten nochmals abstrahiert und durch ein einheitliches Interface dargestellt. Die Klasse FileObject ist eine abstrakte Wrapper-Klasse und erweitert die standart JDK-FileKlasse um diverse Funktionen, ihre Implementation wird vom jeweiligen Filesystem bereitgestellt. Data Systems API Die DataSystems API, bildet eine logische Schicht, aufbauhend auf der FileSystems API. Zentrales Element ist hier die abstrakte Klasse DataObject. Wärend einem FileObject relativ egal ist, mit welchen DateiTypen es arbeitet stellt ein DataObject einen Wrapper auf ein FileObject eines bestimmten Typs dar. Verwendung findet dies z.B. bei der Einbindung eines neuen, oder speziellen Dateitypen anhand von Metainformationen oder Dateierweiterung in eine Platform-Anwendung. Lookup API Das Lookup Konzept findet fast überall innerhalb der Netbeans Platform verwendung und ist dementsprechend eines der wichtigstens Werkzeuge beim Umgang mit der Netbeans Platform. Vereinfacht, kann man das Lookup mit einer Map vergleichen, die als Key - Klassen, also Class-Objekte und als zugehörige Werte deren Instanzen beinhaltet. Sinn und Zweck dieses Konzeptes ist die Entkopplung von Komponenten, oder anders gesagt, das ermöglichen von Intermodulkommunikation ohne feste Abhänigkeiten definieren zu müssen. Die Verwendung dieses Konzepts bringt sehr viele Vorteile mit sich, so ergibts sich aus der definitions des Lookups implizit auch seine Typsicherheit, denn da als Key hier Class-Objekte 11 anstatt Strings verwendet werden, ist der Typ der zurückgegebenen Instanz bereits festgelegt, Fehler wie ClassCastExceptions können daher nicht auftreten und auf manuelle Typchecks im Code, kann verzichtet werden. Ausserdem bietet sich das Lookup zum finden von Service Providern an und ermöglicht gleichermaßen Konzepte wie Lazy Loading oder oder das bereits erwähnte Loose Coupling. Nodes API Die Nodes API stellt einen graphischen Präsentations Layer dar, so hat ein Node die Aufgabe Daten, Aktionen, Eigenenschaften oder andere Funktionalitäten an der Benutzeroberfläche zur Verfügung zu stellen. Um dies zu verdeutlichen stellt man sich am besten einen Dateibrowser vor, jeder Ordner und jede Datei stellen einen Node dar, dabei muss ein Node aber nicht zwangsläufig ein Datenobjekt repräsentieren, so könnte z.b eine Verknüpfung durch ein ProxyNode dargestellt werden. Standartmäßig stellt jeder Node bereits eine Vielzahl von Funktionen zur verfügung, so besitzen Nodes von haus aus u.a. bereits ein Icon, ein ContextMenu, einen html-kompatiblen DisplayName, Properties und viele mehr, ausserdem kann ein Node wiederum eine Menge von ChildNodes beinhalten, wodurch hierarchische Baumstrukturen ermöglicht werden, wie beispielsweise in jedem Datei-Browser zu finden sind. Die Nodes API ist ein sehr mächtiges Werkzeug und kann im übrigen wie sämmtliche anderen Platform Libraries auch "standalone", also ausserhalb der Netbeans Platform verwendet werden. 12 Explorer API Die Explorer API ist eng verwandt mit der Nodes API, ihre Aufgabe ist die Verwaltung und Darstellung von Nodes. Hierzu stellt die Explorer API diverse graphische Komponenten, sogenannte Explorer Views bereit, mit hilfe derer verschiedene Ansichten auf einen Baum von Nodes erstellt werden können. Die verwaltung einer Explorer View und eines Node-Sets übernimmt die Klasse ExplorerManager. Eine Instanz dieses Managers muss von der Parent-Komponente des ExplorerViews zur verfügung gestellt werden, hierzu implementiert diese in der Regel das Interface ExplorerManager.Provider, welches die Methode getExplorerManager(), die den ExplorerManager zurück gibt, spezifiziert. Dieses Vorgehen hat zur folge, dass ExplorerManager und ExplorerView in keinster Weiste miteinander gekoppelt werden müssen, stattdessen sucht die ExplorerView selbstständig in der Hierarchie seiner Parent-Komponenten nach einem geigneten ExplorerManager. Verwendung findet dies beim Überwachen von Selektionen von Nodes in einer ExplorerView. Durch den Manager können selektierte Nodes inkl. deren Lookup automatisch in einem eigenen Lookup zur verfügung gestellt werden und so für externe Klassen oder Module zugänglich gemacht werden. Visual Library API Die Visual Library ist eine generische Bibliothek zur Visualisierung von Strukturen, wobei das Haupteinsatzgebiert sicherlich die Visualisierung von Graphen in Form von graphischen Modelierungs-Editoren, wie dem Netbeans- eigenen Visual Mobile- oder UML Editor ist. Ähnlich wie bei Swing werden auch hier sämmtliche Komponenten baumartig aufgebaut und verwaltet. Die zentrale Klasse beim Umgang mit der Visual Library is die Basisklasse Widget. Neben der Widget-Klasse spielt auch die Klasse Scene und ihre Subklassen eine große Rolle. Die Klasse Scene selbst ist ebenfalls Subklasse von Widget und stellt den Root-Container einer mit Hilfe der Visual Libarary erstellten Anwendung dar. Die Subklasse ObjectScene von Scene, stellt eine Relation zwischen View, in Form von Widgets, und einem zugehörigen Datenmodell vom Typ Object her. Weiter existieren die generisch, abstrakten Subklassen GraphScene und GraphPinScene, die auf ein Graphenmodell mit Knoten und Kanten bzw Knoten, Kanten und Pins abbilden, sowie deren Implementierungen vom Typ String - GraphScene.StringGraph und GraphPinScene.StringGraph. Widgets können ähnlich wie bei Swing mit hilfe von Layouts und durch das hinzufügen von 13 Kind-Elementen, welche wiederum selbst Subklasse von Widget sind, gestaltet werden. Hierzu existieren eine Reihe von Basis-Widgets, wie Label- oder ImageWidget, es ist jedoch auch möglich ein Widget mit Hilfe der Java2D API selbst zu zeichnen. Ausserdem können Widgets Aktionen Aufnehmen, auch hier bietet die Library bereits eine Auswahl an Aktionen für Hover-,Edit-,Move- oder Connect-Events. Zum Erzeugen von Layouts und Aktionen existieren Factories, die bereits erzeugte Aktionsoder Layout-Klassen cachen und so wiederverwenden. 14 Anpassung und Deployment Zur Anpassung und Auslieferung einer Netbeans Platform Anwendung werden mehrere Möglichkeiten angeboten. Netbeans Module (NBM) Die Distribution als Netbeans Module, also als Erweiterung für eine bestehende NetbeansPlatform Anwendung, bietet sich an, wenn bereits eine Netbeans-Platform Anwendung besteht, bzw verwendet wird. Dabei kann es sich sowohl um eine Eigenentwicklung als auch um die bekannte Netbeans IDE handeln. Zip Distribution Die Distribution in Form einer Zip-Distribution wird in der Regel dann verwendet, wenn bisher kein Netbeans-Platform Anwendung benutzt wurde, bzw vorhanden war. Hierbei wird eine komplette, lauffähige Anwendung generiert und anschließend als Zip Archiv zur verfügung gestellt. Eine solches Archiv lässt sich leicht verschicken, oder zum Download anbieten, ausserdem beinhaltet es einen Application Launcher im .exe Format für Windows basierte Systeme, sowie ein Shellscript .sh für Linux basierte Systeme. Mac OSX Application Auch der Mac-Nutzer kommt nicht zu kurz, ein eigenes Build-Target zur erstellung einer Mac OSX Anwendung in Form eines .app Launchers kann ebenfalls, gesondert zu Windows/Linux Distribution erstellt werden. Java WebStart (JNLP) Besonders attraktiv ist auch das Deployment via Java Webstart unter zuhilfename des Java Network Launching Protocols (JNLP). Hierbei erzeugt das Build-System ein so genanntes Web-Archive (.war), welches anschließend auf einem Application Server mit Web-Container (bsp. Tomcat oder GlassFish) deployed werden kann. Der end-Benutzer kann die Anwendung dann aus seinem Web-Browser starten, wobei diese 15 dann vom Java Webstart Subsystem heruntergeladen und ausgeführt wird. Ein wesentlicher Vorteil dieser Variante ist auch die ständig gebene aktualität der Software, so wird die Anwendung beim wiederholten start nur dann erneut auf den lokalen Client heruntergeladen, wenn eine neuere Version zur verfügung steht, anderenfalls wird die lokal-gecachte Kopie gestartet, und die Downloadzeit entfällt. 16 Quellen [NBJDoc09a] http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/ modules/doc-files/classpath.html [NBWiki07a] http://wiki.netbeans.org/DevFaqLookup [NBWiki09a] http://wiki.netbeans.org/NetBeansDeveloperFAQ#sectionNetBeansDeveloperFAQ-Lookup [NBWiki09b] http://wiki.netbeans.org/NetBeansDeveloperFAQ#sectionNetBeansDeveloperFAQ-FilesAndDataObjects [NBWiki09c] http://wiki.netbeans.org/NetBeansDeveloperFAQ#sectionNetBeansDeveloperFAQ-NodesAndExplorer [NBGraph09a] http://graph.netbeans.org/documentation.html [Wiki09a] http://en.wikipedia.org/wiki/Lazy_loading [Boe08] Heiko Böck, Netbeans Platform 6, Galileo Press 2008 [WG09] Geertjan Walenga's Blog - http://blogs.sun.com/geertjan/entry/ how_to_deploy_netbeans_platform [NBxx] http://www.netbeans.org/about/history.html 17