Diese Diplomarbeit untersucht die Praxistauglichkeit der aspektorierten Programmierung (AOP) mit Java am Beispiel einer konkreten J2EE Anwendung. Nach einer kurzen Einführung in die Grundzüge der aspektorientierten Programmierung, werden die versichenenen Einsatzgebiete, wie Logging, Pooling, Qualitätssicherung oder Testen von Software vorgestellt. Dabei wird die AOP Lösung immer mit einer herkönlichen Java Implementierung vergliechen und die Vor- und Nachteile der beiden Implementierungen untersucht. Als Ergebnis dieser Arbeit soll geprüft werden, ob AOP inzwischen bereit für den Praxiseinsatz ist und der Nutzen sowie Probleme dieser Technologie untersucht werden.
Inhaltsverzeichnis
I. Eidesstattliche Erklärung
II. Kurzfassung
III. Danksagung
IV. Inhaltsverzeichnis
VI. Abbildungsverzeichnis
Kapitel 1: Einführung
1.1 Einleitung
1.2 Ziel der Arbeit
1.3 Voraussetzungen
1.4 Motivation
1.5 Aspektorientierte Programmierung
1.6 Weben von Aspekten
1.6.1 statisches Weben
1.6.7 dynamisches Weben
1.7. AspectJ
1.7.1 Schnittpunkte (engl. pointcuts)
1.7.2 Advices
1.7.3 Aspekte
1.7.4 Introductions
1.7.5 Compiler Regeln
1.8. „Hello World“ mit AspectJ
1.9. Zusammenfassung
Kapitel 2: Die Anwengung - iPad
2.1 Anforderungen
2.2 Design
2.2.1 Klassen Design
2.2.2 Datenbank Design
2.2.3 Grafische Oberfläche
2.2.4 Architektur
2.3 Implementierung
2.3.1 Allgemeines
2.3.2 Technologien
2.3.2.1 Hibernate
2.3.2.2 Axis
2.3.2.3 Lucene
2.3.2.4 Eclipse RCP
2.3.2.5 JDIC
2.3.3 Probleme und Erfahrungen
2.3.3.1 SWT
2.3.3.1 Performance
2.4 Bewertung des Designs und Architektur
2.5 Zusammenfassung
Kapitel 3: Tracing und Logging
3.1 Konventionelles Logging
3.2 Logging mit AspectJ
3.2.1 Protokollieren von Methodenaufrufen
3.2.2 Protokollieren von Feldzugriffen
3.2.3 Protokollieren von Exceptions
3.3 Spezielle Logging Anwendungen
3.3.1 Protokollieren von SQL Statements
3.3.2 Protokollieren von Sessions
3.3.3 Protokollieren von Webservice Requests
3.4 Einsatz in der Beispielanwendung
3.5 Zusammenfassung
Kapitel 4: Qualitätssicherung
4.1 Best-Practices Richtlinien
4.2 EJB Richtlinien
4.3 Swing Richtlinien
4.4 Architektur Richtlinien
4.5 Benutzerdefinierte Richtlinien
4.6 Richtlinien für Namenskonventionen
4.7 Weitere Tools
4.8 Einsatz in der Beispielanwendung
4.9 Zusammenfassung
Kapitel 5: Pooling und Caching
5.1 Thread Pool
5.1.1 Java Implementierung
5.1.2 AspectJ Implementierung
5.1.3 Bewertung
5.2 XSLT Cache
5.2.1 Java Implementierung
5.2.2 AspectJ Implementierung
5.2.3 Bewertung
5.3 Einsatz in der Beispielanwendung
Kapitel 6: Design Patterns
6.1 Singleton Pattern
6.1.1 Java Implementierung
6.1.2 AspectJ Implementierung
6.1.3 Bewertung
6.2 Observer Pattern
6.2.1 Java Implementierung
6.2.2 AspectJ Implementierung
6.2.3 Bewertung
6.3 Zusammenfassung
Kapitel 7: Testen mit AspectJ
7.1 Prüfungen privater Variablen
7.2 Austausch von Methoden und Objekten
7.3 Virtuelle Mock Objekte
7.4 Unit Test Coverage
Kapitel 8: Fazit
8.1 Bewertung der Technologie
8.3 Ausblick in die Zukunft
8.4 Zusammenfassung
VII. Literaturverzeichnis
VIII. Abkürzungsverzeichnis
IX. Glossar
X. Anhänge
Anhang A: Eingesetzte Hilfsmittel
Anhang B: Inhalt der CD-ROM - nicht enthalten !!
Anhang D: Java AOP Implementierungen
Anhang E: AspectJ Plugins für Entwicklungsumgebungen
I. Eidesstattliche Erklärung
(gemäß § 31, Abs. 7 RaPO)
Hiermit erkläre ich, dass ich die Arbeit selbstständig verfasst, noch nicht anderweitig für
Prüfungszwecke vorgelegt, keine anderen als die angegebenen Quellen oder Hilfsmittel benutzt sowie wörtliche oder sinngemäße Zitate als solche gekennzeichnet habe.
Landshut, den 10.01.2005
(Eduard Hildebrandt)
II. Kurzfassung
Diese Diplomarbeit untersucht die Praxistauglichkeit der aspektorierten Programmierung (AOP) mit Java am Beispiel einer konkreten J2EE Anwendung. Nach einer kurzen Einführung in die Grundzüge der aspektorientierten Programmierung, werden die versichenenen Einsatzgebiete, wie Logging, Pooling, Qualitätssicherung oder Testen von Software vorgestellt. Dabei wird die AOP Lösung immer mit einer herkönlichen Java Implementierung vergliechen und die Vor- und Nachteile der beiden Implementierungen untersucht. Als Ergebnis dieser Arbeit soll geprüft werden, ob AOP inzwischen bereit für den Praxiseinsatz ist und der Nutzen sowie Probleme dieser Technologie untersucht werden.
III. Danksagung
Bei den meisten Diplomarbeiten steht auf der Titelseite in der Regel nur ein einziger Name als Autor der Arbeit. Dies ist eine arge Täuschung! Jede Diplomarbeit entsteht aus einer Kollaboration hingebungsvoller und talentierter Menschen. Beim Schreiben dieser Arbeit haben mir eine Vielzahl großzüger und kluger Leute mit Rat und Tat zur Seite gestanden. Besonderen tiefen Dank empfinde ich für:
Meine Eltern, denen diese Diplomarbeit gewidmet ist. Sie haben mir das Studium der Informatik überhaupt erst ermöglicht. Sie haben stets zu mir gehalten und mich immer unterstützt. Ich danke für ihre Liebe und Vertrauen. Sie sind die beiden Riesen, auf deren Schultern ich gestanden bin.
Frau Prof. Dr. Gudrun Schiedermeier, die mir meine erste Java Lektion während des Informatikstudiums gegeben hatte. Sie begleitete diese Diplomarbeit als Erstkorrektorin und gab mir die Freiheit ohne Zwänge und Auflagen eine neue Technologie zu erforschen. Stets war sie erreichbar und hatte immer gute Vorschläge, wie ich meine Arbeit verbessern kann. Dafür möchte mich herzlich bedanken.
Frau Prof. Dr. Monika Messerer, die mir die Themen Softwareengineering und Design Patterns im Laufe des Studiums beigebrachte hatte. Sie hat sich ebenfalls für diese Thematik als Zweitkorrektorin begeistern können.
Der Firma Kölsch & Altmann, wo ich die Möglichkeit hatte, meine Arbeit in einer sehr guten Arbeitsumgebung zu gestalten. Selten habe ich ein Unternehmen gesehen, in dem ein solch familiäres Arbeitsklima herrscht. Mein besonderer Dank gilt hier dem Geschäftsführer Dr. Werner Altmann, der mir diese Gelegenheit überhaupt erst ermöglichte und meine Arbeit stets mit großem Interesse verfolgte. Ein großer Dank gilt auch meinen beiden Betreuen Georg Süß und Klaus Dirlewanger, die mir immer mit Rat und Tat zur Seite gestanden haben.
Meinem besten Freund Matthias Schaufler, der immer für mich da ist. Er hat viel Zeit investiert
diese Arbeit auf Rechtschreib- und Grammatikfehler zu überprüfen. Für seine Mühen möchte ich mich besonders bedanken, da er sich eigentlich nicht für Informatik interessiert und daher auch relativ wenig vom Inhalt verstanden hat. Umso mehr konnte er durch seine Vorschläge die Ausdrucksweise verbessern.
Meine Studienkollegien Waldemar Mertke und Philipp Morgenthaler, die sich die Zeit genommen haben, meine Diplomarbeit durchzulesen und viel konstruktive Kritik gegeben haben.
Allen anderen Leuten, die ich hier nicht explizit erwähnt habe, die jedoch in vielen verschiedenen Dialogen durch Ihre Ansichten und Vorschläge ebenfalls zum Erfolg dieser Arbeit beigetragen haben.
VI. Abbildungsverzeichnis
Abbildung 1: Parsen einer XML Datei
Abbildung 2: Logging
Abbildung 3: Quellcode der Klasse Konto
Abbildung 4: Quellcode der Klasse Konto incl. technischer Belange
Abbildung 5: Weben von Aspekten
Abbildung 6: AOP als Lichtstrahl
Abbildung 7: Use-Case-Diagram Resource-Management-System
Abbildung 8: Klassendiagramm mit zentralen Klassen der Anwendung
Abbildung 9: Datenbank Design der Anwendung
Abbildung 10: Paper Prototyp der Benutzeroberfläche
Abbildung 11: Screenshot der Benutzeroberfläche
Abbildung 12: Architektur Übersicht
Abbildung 13: Eclipse IDE
Abbildung 14: Eclipse Architektur
Abbildung 15: AspectJ Laufzeit-Bibliothek
Abbildung 16: Vier Schichten Architektur
Abbildung 17: Sequenzdiagramm - Erzeugung und Benutzung von Ressourcen
Abbildung 18: Sequenzdiagram - Verwendung eines Pools
Abbildung 19: Klassendiagramm Singleton Pattern
Abbildung 20: Klassendiagram für Grafikprogramm
Abbildung 21: UML Diagramm für Mock Klassen
Abbildung 22: Downloads von AspectJ
Kapitel 1: Einführung
1.1 Einleitung
Der Mensch hätte nur selten Großes erreicht, wenn er alle Frustrationen hinnehmen würde. Treibt doch die Frage „Muss es so sein?“ unseren Erfindungsgeist an. Hieraus erwachsen politische Reformen und wissenschaftliche Erneuerungen. Die Römer mochten Frustrationen nirgendwo hinnehmen. Sie gingen nicht gerne auf schlammigen Straßen, also pflasterten sie diese. Sie verabscheuten die winterliche Kälte und ersannen so die Fußbodenheizung.
Nicht anderes verhält es sich mit dem Prozess der Softwareentwicklung. Die Unzufriedenheit der Programmierer treibt diese dazu, immer wieder neuere und effizientere Wege bei der Softwareentwicklung zu beschreiten.
In den frühen Tagen der Informatik haben die Entwickler ihre Programme direkt in Form von Maschinen-Befehlen eingegeben. Leider verbrachten die Programmierer mehr Zeit damit, über den Befehlsatz für den jeweiligen Prozessor, als über das eigentliche Problem nachzudenken. So entstanden die ersten höheren Programmiersprachen, die eine Abstraktion der zugrunde liegenden Maschine erlaubten.
Mit der Zeit kamen die prozeduralen Sprachen und ermöglichten es, die Probleme in kleinere Teilprobleme zu zerlegen und diese in Prozeduren abzubilden. Da die Komplexität der Programme jedoch ständig anwuchs, wurde bald eine ausgefeiltere Technik benötigt.
Während bei prozeduralen Programmiersprachen die Daten und Prozeduren getrennt betrachtet wurden, werden diese in der objektorientierten Programmierung zu einer Einheit in Form von Objekten zusammengefasst. Die objektorientierte Programmierung (OOP) betrachtet ein System als eine Menge von Objekten, die untereinander interagieren. Abstraktion, Kapselung, Vererbung und Polymorphie sind die grundlegenden Prinzipien der OOP. Dieser Programmierstil bietet softwaretechnisch gegenüber anderen älteren Verfahren große Vorteile, da hiermit eine wesentlich natürlichere Modellierung ermöglicht wird und große Systeme leichter verwaltet werden können.
Programmierparadigmen und -sprachen definieren die Art und Weise, wie wir uns mit Maschinen verständigen. Jede neue Methode präsentiert einen anderen Weg die realen Objekte der Welt - auf eine für uns Menschen natürlichere Art - in Datenkonstrukte auf dem Rechner abzubilden. Die Evolution der Programmiermethoden ermöglicht es uns immer bessere und komplexere Softwaresysteme zu bauen.
Zum Zeitpunkt der Erstellung dieser Arbeit ist OOP die am weitesten verbreitete Methodenlehre. In der Tat hat OOP seine Stärken beim Modellieren von allgemeinen Verhalten gezeigt. Ein Bankkonto, auf dem man einen Betrag einzahlen oder abheben kann, lässt sich mit OOP sehr leicht und elegant modellieren.
In der Praxis zeigt sich jedoch, dass es beim Entwurf eines Softwaresystems viele technische Anforderungen, wie z.B. Logging, Persistenz oder Authentifizierung gibt, die sich nicht klar auf eine funktionale Einheit beschränken lassen. Sie durchdringen das gesamte System und lassen sich nur sehr schwer und umständlich in Form von Klassen kapseln. Solche Anforderungen werden auch als „querschneidende Anforderungen“ oder „cross-cutting concerns“ bezeichnet.
Durch ausschließlich funktionale Dekomposition und Refaktorisierung ist es nur in wenigen Fällen möglich, solche Anforderungen unabhängig voneinander und vom Gesamtsystem mit reiner OOP zu modellieren. Beispielsweise ist es nicht möglich den Zugriff auf das Objekt Konto zu protokollieren, ohne die Struktur der Klasse zu verändern. Hier liegen die Grenzen von objektorientierter Programmierung.
Genau hier versucht die aspektorientierte Programmierung (AOP) Abhilfe zu leisten. Ziel der Aspektorientierten Programmierung ist es querschneidende Anforderungen in Form von Aspekten zu kapseln und die Komponenten des Systems von ihnen frei zu halten.
AOP könnte der nächste große Schritt in der Entwicklung der Programmiermethoden sein.
1.2 Ziel der Arbeit
Mit dieser Diplomarbeit soll die Praxistauglichkeit dieser neuen Technologie am Beispiel einer J2EE Anwendung evaluiert werden.
Es sei darauf hingewiesen, dass diese Arbeit keine vollständige Beschreibung der AspectJ- Sprache darstellen soll. Auch wenn eine ausführliche, deutschsprachige Dokumentation für AspectJ noch fehlt, ist es nicht Ziel dieser Arbeit eine solche zu erstellen. Der Autor erklärt zwar alle wichtigen Sprachelemente von AspectJ, für die Programmierung mit AspectJ ist jedoch ein Studium der Dokumentation [AJDOC] oder der im Anhang C vorgeschlagenen Literatur unumgänglich.
Es ist auch nicht Thema dieser Arbeit ist, das Design und die Architektur der Anwendung zu beschreiben. Aus diesem Grund beleuchtet das zweite Kapitel nur die wichtigsten Design- und Architekturentscheidungen und soll keine vollständige Dokumentation darstellen. Auch wenn viele Konzepte der Anwendung aus der Sicht eines Software-Architekten sehr interessant sind, wurde auf eine ausführliche Beschreibung dieser Konzepte zu Gunsten von AOP Themen verzichtet.
1.3 Voraussetzungen
Bei dieser Diplomarbeit werden Kenntnisse in der Modellierung und Implementierung von objektorientierten Softwaresystemen vorausgesetzt. Außerdem sind Programmierkenntnisse in Java sowie ein Grundverständnis der Java 2 Platform Enterprise Edition (J2EE) notwendig. Praktische Erfahrungen auf diesem Gebiet sind, zum Verständnis von großem Vorteil.
1.4 Motivation
Anforderungen, wie z.B. das Parsen einer XML Datei, lassen sich mit OOP relativ einfach implementieren. Die Grafik in der Abbildung 1 visualisiert den Quellcode von Apache Tomcat. Jeder Balken repräsentiert eine Klasse. Der Quellcode, welcher zum Parsen einer XML Datei notwendig ist, wurde in der Grafik hervorgehoben dargestellt. Wie man der Grafik entnehmen kann, ist der Code innerhalb einer einzigen Klasse gekapselt. Dies macht es einfach, den Code zu modifizieren und wieder zu verwenden.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 1: Parsen einer XML Datei
Betrachten wir nun eine Anforderung wie z.B. Logging: Abbildung 2 visualisiert auf dieselbe Art und Weise den Quellcode von Apache Tomcat. Der hervorgehobene Quellcode ist für das Logging innerhalb der Anwendung zuständig.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 2: Logging
Wie wir an der Grafik erkennen können, ist der Quellcode über das gesamte System verstreut. Anforderungen dieser Art werden auch als „querschneidende Anforderungen“ oder „cross- cutting concerns“ bezeichnet. Sie durchdringen das gesamte System und machen es notwendig, dass das System an mehreren Stellen verändert werden muss. Möchte man z.B. auf ein anderes Logging Framework umsteigen, so müssen alle betroffenen Codestellen gefunden werden und es muss sichergestellt werden, dass alle Änderungen konsistent durchgeführt werden. Die Modifizierung der Anwendung ist also relativ aufwendig. Eine solche Implementierung kann auch kaum wieder verwendet werden.
Betrachten wir ein weiteres Beispiel für querschneidende Anforderungen: In einer einfachen Bankanwendung würde die Klasse Konto Variablen für Kontonummer und Guthaben enthalten. Weiterhin würde die Klasse neben Getter- und Setter-Methoden auch Methoden für Ein- und Auszahlungen implementieren. Die Abbildung 3 zeigt den Quellcode für unsere vereinfachte Darstellung der Java Klasse Konto.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 3: Quellcode der Klasse „Konto“
Der Quellcode ist sehr einfach zu lesen und leicht zu verstehen. Die Geschäftslogik der Klasse ist auf den ersten Blick verständlich. Reale Systeme bestehen jedoch nicht nur aus reiner Geschäftslogik, sondern müssen auch jede Menge technische Belange, wie z.B. Logging, Authentifizierung oder Synchronisierung implementieren.
Die Abbildung 4 stellt den Quellcode derselben Klasse Konto dar. Diesmal sind jedoch auch Logging, Authentifizierung und Synchronisierung implementiert worden.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 4: Quellcode der Klasse Konto incl. technischer Belange
Der Quellcode der Klasse ist nun wesentlich schwerer zu überblicken. Verschiedene technische Belange sind jetzt mit der Geschäftslogik eng vermischt. Der Quellcode hat eine hohe Redundanz und es besteht eine starke Kopplung zwischen den Klassen. Bedenkt man, dass es in einem echten System in der Regel bedeutend mehr technische Anforderungen, wie z.B. Persistenz, Transaktionen oder Validierung gibt, so würde die Implementierung noch wesentlich komplexer werden.
Hier zeigt sich die Schwäche von OOP. Es ist sehr schwierig, querschneidende Anforderungen modular zu implementieren. Aspektorientierte Programmierung (AOP) versucht an dieser Stelle Hilfestellung zu leisten, indem es solche Anforderungen unabhängig vom Quellcode in Form von Aspekten kapselt.
1.5 Aspektorientierte Programmierung
Aspektorientierte Programmierung (AOP) ist ein Programmierparadigma für das Design und die Implementierung von Softwaresystemen. Es handelt sich um ein neues Konzept zur orthogonalen Programmierung. Dabei werden technische Anforderungen (wie z.B. Logging oder Persistenz) in so genannten Aspekten gekapselt. Es erfolgt eine logische und physische Trennung der Programmlogik für verschiedene Anforderungen. Diese unabhängigen Programmstücke werden dann von einem speziellen Compiler zu einem kompletten System kompiliert. Man sagt auch, dass die Programmstücke von einem Weber („Weaver“) zu einem System verwoben werden. Die Abbildung 5 visualisiert diesen Vorgang.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 5: Weben von Aspekten
Bildlich kann AOP mit einem Lichtstrahl und zwei Prismen verglichen werden. Wie auf der Abbildung 6 dargestellt, existieren zu Beginn die Anforderungen, die ein Kunde an ein System hat. Aufgabe des Designers ist es, die Anforderungen in verschiedene Aspekte zu trennen, damit diese getrennt implementiert werden können. Der Weber verwebt schließlich alle Aspekte mit der eigentlichen Geschäftslogik zu einem vollständigen System.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 6: AOP als Lichtstrahl1
Mit AOP ist es möglich, an einer zentralen Stelle festzulegen, dass alle Methoden, die bestimmten Bedingungen genügen, bei ihrem Aufruf eine bestimmte Aktion durchführen. Es ist z.B. möglich festzulegen, dass bei jedem Methodenaufruf in der Klasse Konto ein entsprechender Eintrag in die Log-Datei geschrieben wird. Ohne AOP müsste die Schreiboperation gesondert in jede Methode eingefügt werden.
Ziel der AOP ist die logische und physikalische Trennung der Geschäftslogik von den technischen Details. Dabei erhebt AOP nicht den Anspruch objektorientierte Paradigmen zu ersetzen, sondern ergänzt diese, um eine bessere Modularität und Wiederverwendbarkeit zu erreichen, die in dieser Form mit reiner OOP nicht möglich wäre. AOP verbessert die Lesbarkeit und Verständlichkeit des Quellcodes und ermöglich somit eine leichtere Wartung des Systems.
1.6 Weben von Aspekten
Das Kombinieren der Aspekte mit dem restlichen Programmcode wird auch „Weben“ genannt. Der dafür eingesetzte Compiler wird auch als „Aspektweber“ bezeichnet. Dabei wird grundsätzlich zwischen statischem und dynamischem Weben unterschieden:
1.6.1 statisches Weben
Beim statischen Weben wird der Aspektcode während der Kompilierung fest mit dem übrigen Programmcode verbunden. Dies kann z.B. durch Präprozessoren erfolgen. Dabei werden die Aspekte in traditionelle Programmierkonstrukte umgeformt. Der Vorteil dieser Technik ist die einfache Implementierung, da die bestehenden Compiler ohne große Änderungen weiterbenutzt werden können. Nachteilig an dieser Lösung ist jedoch die fehlende Integration in die Programmiersprache. Nach dem Kompilieren sind alle Informationen über Aspekte im Quellcode verloren und können nicht für Fehlermeldungen verwendet werden. Dies erschwert das Debugging und beinträchtigt den Entwicklungskomfort erheblich.
Eine Alternative zu Präprozessoren ist die Verwendung einer eigenen Sprache oder die Erweiterung einer bereits existierenden Sprache. Durch die direkte Integration der Aspekte in die Programmiersprache können die Fehlermeldungen beim Debugging speziell auf die Gegebenheiten der Aspekte zugeschnitten werden.
1.6.7 dynamisches Weben
Vom dynamischen Weben der Aspekte spricht man, wenn das eigentliche Weben zur Laufzeit der Anwendung geschieht. Dynamisches Weben erhöht die Flexibilität einer Anwendung, da das Verhalten des Programms zu Laufzeit dynamisch angepasst werden kann. Diese Flexibilität wird jedoch mit dem Preis von höherem Speicherverbrauch und schlechterem Laufzeitverhalten erkauft.
Zusammenfassend kann man sagen, dass statisches Weben Vorteile durch Optimierung während des Kompiliervorgangs bringt, während dynamisches Weben zur Laufzeit auf Veränderungen reagieren und das Programmverhalten anpassen kann.
1.7. AspectJ
AspectJ [AJHP] ist eine AOP Spracherweiterung für Java. AspectJ wurde selbst ebenfalls in Java implementiert und stellt momentan die wohl bekannteste und umfangreichste AOP Erweiterung für Java dar. Ursprünglich wurde AspectJ von Xerox im Palo Alto Research Center (Xerox PARC) [PARCHP] entwickelt. In der Zwischenzeit ist AspectJ ein Teilprojekt der Eclipse [ECHP] Entwicklungsumgebung und ist unter der Common Public License (CPL) [WCPL] komplett im Quellcode verfügbar. AspectJ erfreut sich einer sehr großen, aktiven Gemeinde und wurde auch bereits in vielen umfangreichen kommerziellen Projekten eingesetzt. Aufgrund der starken Verbreitung und des beträchtlichen Funktionsumfangs wurde beschlossen, AspectJ auch im Rahmen dieser Diplomarbeit als aspektorientierte Spracherweiterung einzusetzen. Eine Liste weiterer AOP Implementierungen für Java befindet sich im Anhang C.
AspectJ verwendet statisches Weben. Es handelt sich um eine eigenständige Sprache mit einem eigenen Compiler, welcher allerdings standardkonformen Java-Bytecode produziert. Dies hat den Vorteil, dass die bestehende Infrastruktur von Java weiter genutzt werden kann. AspectJ erweitert Java um fünf „kleine“ Sprachelemente:
- pointcut
- advice
- aspect
- introduction
- compiler rule
Im Folgenden werden diese Sprachelemente etwas genauer betrachtet:
14 von 88
1.7.1 Schnittpunkte (engl. pointcuts)
Webepunkte, auch „join points“ genannt, sind eindeutige Punkte im Programmablauf, an denen durch den Compiler zusätzliche Anweisungen eingefügt werden können. Ein Webepunkt könnte ein Methoden- oder Konstruktoraufruf, der Zugriff auf eine Variable oder die Initialisierung einer Klasse sein.
Mehrere Webepunkte werden zu so genannten Schnittpunkten, im Englischen auch „pointcuts“ genannt, zusammengefasst. Schnittpunkte selektieren mit einer Art Abfragesprache eine Menge von Webepunkten. Ein Beispiel für solch eine Auswahl von Webepunkte wäre: „Alle Variablenzugriffe in allen Klassen, die mit ‚EJB’ enden, jedoch nicht im Package com.mybank.konto.“
Die Syntax für die Definition eines Poincuts in AspectJ lautet:
[abstract] [ Modifikator ] pointcut Bezeichnung ([ Parameter ]) : Pointcut-Typ;
Mögliche Pointcut Typen in AspectJ sind das Aufrufen oder Ausführen einer Methode (call, execution), der Zugriff auf Variablen (get, set), Ausnahmebehandlung (handler), das Ausführen von Aspektcode (adviceexecution) oder die Initialisierung von Klassen und Variablen (staticinitialization, initialization, preinitialization). Weiterhin existieren so genannte strukturbasierte Pointcuts, mit denen es möglich ist, bestimmte Bereiche auszuwählen, wie z.B. den Code innerhalb eines bestimmten Typs bzw. einer Klasse (within, withincode) oder innerhalb eines Schnittpunktes (cflow, cflowbelow). Auch ist es möglich, den Typ der Klassen oder Methodenparameter (this, target, args) zu bestimmen.
Betrachten wir einige Beispiele für Pointcuts:
public pointcut loggingMethods() : call(void Konto.einzahlen(int));
Dieses Beispiel definiert einen öffentlichen Pointcut mit dem Namen loggingMethods, welcher jedes Mal beim Aufruf der Methoden einzahlen der Klasse Konto zutrifft.
Bei der Definition von Poincuts ist es möglich, Wildcards zu verwenden:
private pointcut toStringMethods() : execution(* *.toString*(..));
In diesem Fall wird ein privater Pointcut mit dem Namen toStringMethods definiert, der bei der Ausführung aller Methoden, die mit “toString”
Unterschied zwischen call und execute:
Immer wenn auf Methoden oder Konstruktoren zugegriffen wird, gibt es zwei verschiedene Zeitpunkte, die für die Ausführung wichtig sind. Zum einen der Aufrufzeitpunkt und zum anderem der Ausführungszeitpunkt. AspectJ unterscheidet diese Zeitpunkte anhand von call und execute Joinpoints. So ist es z.B. mit call möglich auch rekursive Methodenaufrufe abzufangen. Mit execute ist dies nicht möglich.
Um sich den Unterschied leichter vorstellen zu können, kann man sich merken, dass sobald etwas bei einem Methodenaufruf passieren soll, man call wählt. Soll etwas bei der Ausführung eines Codeteils geschehen, wird execute benutzt.
beginnen, aktiv wird. Dabei ist es egal, in welcher Klasse die Methode enthalten ist, welchen Rückgabewert diese hat oder welche Parameter übergeben werden.
Weiterhin besteht die Möglichkeit, Pointcuts mit Hilfe von logischen Operatoren zu kombinieren. Möchte man z.B. erreichen, dass ein Pointcut bei allen Schreibzugriffen auf Variablen, deren Namen nicht mit „m“ oder „l“ beginnen, aktiv wird und der Pointcut gleichzeitig aber nur bei Zugriffen innerhalb der Klasse „Konto“ aktiv werden soll, so würde der Pointcut folgendermaßen lauten:
public pointcut memberAccess() : set(*) && (!set(m*) || !set(l*)) && within(Konto);
Pointcuts selektieren also eine Menge von Zeitpunkten oder Ereignissen im Ablauf eines Programms.
1.7.2 Advices
Mit Empfehlungen bzw. „advices“ ist es möglich, die Ausführung von bestimmten Aktionen zu definieren, wenn ein gewisser Pointcut erreicht wird. In AspectJ werden solche Aktionen in Form von normalem Java Code innerhalb eines Advice Blocks definiert. Je nach Typ des Advices wird die Aktion dann vor dem Erreichen (before) des Pointcuts, nach dem Ausführen (after) des Pointcuts oder statt der Ausführung (around) des Pointcuts ausgeführt.
Die Syntax für die Definition eines Advices in AspectJ lautet:
Abbildung in dieser Leseprobe nicht enthalten
Einige Beispiele:
before(int i) : set(int Konto.kontostand) && args(i) { ... }
Die Anweisungen im Körper werden ausgeführt, bevor ein Schreibzugriff auf die Variable kontostand in der Klasse Konto stattfindet. Innerhalb des Körpers kann man auf den neuen Wert der Variable über den Variablennamen „i“ zugreifen.
after(int x) returning(): call(void Konto.abheben(int)) && args(x) { ... }; Der Körper wird nach der erfolgreichen Ausführung (returning) der Methode abheben() ausgeführt. Der übergebene Parameter steht innerhalb des Körpers unter der Variable „x“ zur Verfügung.
after() throwing(LimitException e) : call(void Konto.abheben(int)) { ... };
Der Advice wird nur nach dem Werfen (throwing) einer LimitException ausgeführt. Die Exception bekommt im Körper den Variablennamen „e“. int around() : call(int Konto.getKontostand()) {…}
In diesem Fall wird der Körper an Stelle der Methode getKontostand() ausgeführt. Im Körper gibt es jedoch die Möglichkeit, die Methode getKontostand() dennoch auszuführen. Dafür dient die Methode proceed(). Siehe dazu auch Kapitel 3.2.1.
1.7.3 Aspekte
Vergleichbar mit Klassen in Java können Aspekte Variablen und Methoden enthalten oder Eigenschaften von anderen Klassen und Aspekten erben und Interfaces implementieren. Darüber hinaus bieten Aspekte allerdings noch erweiterte Funktionalität und dienen als Container für Pointcuts und Advices.
Die Syntax für die Definition eines Advices in AspectJ lautet:
Abbildung in dieser Leseprobe nicht enthalten
Das oben gezeigte Beispiel implementiert einen Aspekt „A“, welcher sich von einem anderen Aspekt oder der Klasse „B“ ableitet sowie zusätzlich die Interfaces „I“ und „J“ implementiert. Weiterhin enthält der Aspekt einen Pointcut loggingMethods und einen before-Advice.
1.7.4 Introductions
Introductions können bestehende Klassenstrukturen verändern. Das heißt, es können neue Attribute und Methoden hinzugefügt werden oder neue Schnittstellen implementiert (declare parents) werden. Außerdem können Exceptions abgeschwächt werden (declare soft), so dass diese nicht mehr explizit abgefangen werden müssen.
Die Syntax für Introductions lautet:
Abbildung in dieser Leseprobe nicht enthalten
In diesem Beispiel sorgt der Aspekt NameableManagement dafür, dass die Klasse Resource
zusätzlich das Interface Nameable implementiert und die Klasse um die notwendigen Methoden erweitert.
1.7.5 Compiler Regeln
Des Weiteren bietet AspectJ die Möglichkeit, den Compiler durch zusätzliche Regeln intelligenter zu gestalten. Mit Hilfe von declare error bzw. declare warning ist es möglich, beim Aufruf von einem bestimmten Pointcut eine Warnung auszugeben oder den Kompilationsvorgang ganz abzubrechen. Die genaue Syntax lautet:
Abbildung in dieser Leseprobe nicht enthalten
Auch dazu einige Beispiele:
Möchte man z.B. erreichen, dass die Programmierer nicht System.out.println() für DebugMeldungen verwenden sondern das neu eingeführte Logging Framework einsetzen, so lässt sich dies mit den folgenden Codezeilen erreichen:
declare warning : get(* System.out) || get(* System.err) : “Verwenden Sie bitte die Logging API!";
In diesem Fall wird beim Kompilieren des Quellcodes jedes Mal, wenn auf System.out oder System.err zugegriffen wird, eine entsprechende Warnung ausgegeben.
Hat man eine Richtlinie festgelegt, wonach das Abspeichern von Daten in die Datenbank nur mit Hilfe eines Framework zu verrichten ist und der Zugriff auf die Datenbank aus anderen Klassen nicht erlaubt sein darf, so kann man dies mit relativ wenig Aufwand ständig vom Compiler überprüfen lassen.
declare error : call(* java*.sql.*.*(..)) && !(withhin(de.ka-muc.sqladapter.*)
: „JDBC Klassen dürfen nicht direkt benutzt werden!“;
In diesem Fall gibt der Compiler nicht nur eine Warnung aus, sondern bricht den
Kompilationsvorgang beim Zugriff auf die SQL Klassen außerhalb des Frameworks komplett ab und zeigt eine entsprechende Fehlermeldungen an.
1.8. „Hello World“ mit AspectJ
Im Folgenden werden die im Kapitel 1.7 vorgestellten Sprachkonstrukte noch einmal an einem kleinen Beispiel erläutert. Um dieses und alle folgenden Beispiele nachvollziehen zu können, benötigt man eine einsatzfähige AOP-Entwicklungsumgebung. Alle dafür notwendigen Schritte sind in der AspectJ Dokumentation im „Development Environment Guide“ erläutert. [AJDEV] Als Ausgangspunkt für unser Beispiel verwenden wir ein einfaches „Hello World!“ Programm.
Abbildung in dieser Leseprobe nicht enthalten
Dieses einfache Programm gibt nur „Hello World!“ auf der Konsole aus:
> java HelloWorld
Hello World!
Erweitern wir nun das Programm um einen Aspekt:
Abbildung in dieser Leseprobe nicht enthalten
Dieser Aspekt veranlasst das Programm vor der Ausführung der Methode sayHello(String) die Meldung „Before Advice!“ auszugeben.
> java HelloWorld
Before Advice! Hello World!
Was ist hier passiert? Dekompilieren wir einfach das Programm und betrachten wir, was der Compiler in diesem Fall gemacht hat.
Abbildung in dieser Leseprobe nicht enthalten
Die Klasse HelloWorld wurde in der Methode sayHello(String) um eine weitere Anweisung erweitert. Vor der Ausführung der ursprünglichen Logik erfolgt jetzt zusätzlich ein Sprung in die HelloWordAspect Klasse. Der HelloWorldAspect Aspekt wurde also in Form einer Klasse mit dem gleichen Namen kompiliert. Betrachten wir was in dieser Klasse enthalten ist:
Abbildung in dieser Leseprobe nicht enthalten
Der Quellcode der Klasse bedarf keiner weiteren Erklärungen. Die Methode ajc$before$HelloWordAspect$1$53011669(), welche aus der Klasse HelloWorld aufgerufen wird, enthält die von uns angegebenen Anweisungen, um den String „Before Advice“ auf der Konsole auszugeben. Aspektorientierte Programmierung ist also keine Zauberei! Der Compiler erstellt aus unseren Anweisungen ein standardmäßiges Java Programm, welches in jeder Virtuellen Maschine ablaufen kann. Man kann also Aspekte als eine Art Compiler-Anweisung betrachten, die angeben, wie verschiedene Codestücke miteinander verwebt werden sollen.
1.9. Zusammenfassung
In diesem Kapitel wurden die Begriffe „Querschneidende Anforderungen“ und „Aspektorientierte Programmierung“ definiert und die grundlegenden Begriffe genauer erläutert. Es wurde der Unterschied zwischen dynamischem und statischem Weben von Aspekten dargestellt. Das Programm „AspectJ“ wurde als AOP Spracherweitung für Java vorgestellt und die wichtigsten Syntaxelemente mit Hilfe von kleinen Beispielen erklärt. Schließlich wurde am Beispiel eines einfachen „Hello World!“ Programms gezeigt, wie Aspekte und normaler Programmcode vom Compiler miteinander verwoben werden.
Dies war ein sehr einfaches Beispiel für AOP und sollte ein Gefühl dafür geben, was man mit den einfachen Sprachelementen von AspectJ machen kann. Statt eine einfache Meldung auf der Konsole auszugeben, ist es grundsätzlich möglich, bei der Ausführung jeder Methode einen Log- Eintrag in eine Datei zu schreiben, den Benutzer zu authentifizieren oder eine Methode zu synchronisieren. Diese Anwendungsmöglichkeiten werden in den folgenden Kapiteln jedoch noch wesentlich genauer betrachtet. Bis hierhin reicht es aus, wenn man nachvollziehen kann, dass es mit AspectJ möglich ist, mehrere Punkte im Programmablauf zu definieren und an diesen Punkten zusätzlichen Code ausführen zu lassen. Diesen zusätzlichen Code verwaltet man an einer einzigen zentralen Stelle, ähnliche einer Klasse, in Form eines Aspektes.
Bevor wir uns weitere Einsatzmöglichkeiten von AOP zuwenden, wird im nächsten Kapitel das Design und die Architektur der Anwendung beschrieben, anhand welcher im Verlauf dieser Arbeit verschiedene AOP Anwendungsmöglichkeiten im praktischen Umfeld getestet werden sollen.
Kapitel 2: Die Anwengung - iPad
Um den Einsatz von AOP in der Praxis beurteilen zu können, wurde im Rahmen dieser Diplomarbeit eine Beispielanwendung implementiert. In diesem Kapitel werden die Designkriterien, die Architektur und die Implementierung der Anwendung beschrieben.
Ziel bei der Entwicklung der Anwendung war die Evaluierung von AOP im J2EE Umfeld. Die Architektur der Anwendung wurde so entworfen, dass ein möglichst breites Spektrum an verschiedenen Technologien zum Einsatz kommen konnte. Das primäre Ziel war es, Erfahrungen mit AOP und anderen Technologien zu sammeln. Die Entwicklung einer stabilen und einsatzfähigen Anwendung hatte nur eine untergeordnete Priorität.
2.1 Anforderungen
In diesem Kapitel werden die Anforderungen an die Anwendung beschrieben, wie diese auch von einem Kunden formuliert sein könnten. Bei der Niederschrift der Anforderungen wurde noch keine Entscheidung über die Technologie getroffen.
Es soll ein einfaches Informations-Management-System entwickelt werden. Mit Hilfe dieses Systems soll der Benutzer in der Lage sein, verschiedene Ressourcen in verschiedenen Kategorien verwalten zu können. Das Use-Case Diagramm in der Abbildung 2.1 zeigt die grundlegenden Anforderungen an das System.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 7: Use-Case-Diagram Resource-Management-System
Der Benutzer soll in der Lage sein, Kategorien sowie Ressourcen anzulegen, zu bearbeiten und zu löschen. Weiterhin soll es möglich sein, nach verschiedenen Ressourcen zu suchen.
Eine Ressource kann dabei jede beliebige Art von Information sein. Es könnten also z.B. eine Datei, eine E-Mail, Kontaktinformation, Notizen, Musik oder Bilder sein. Alle Ressourcen haben gemeinsame Eigenschaften: Ressourcen haben einen Namen, können mit mehreren Stichwörtern versehen und mit mehreren Notizen behaftet werden. Außerdem können die Ressourcen untereinander verknüpft werden. Ein Kontakt kann z.B. mit allen dazugehörigen E- Mails verknüpft werden, während ein Projektplan mit allen dazugehörigen Dokumenten und Mitarbeitern verknüpft werden kann. Ein Tagebucheintrag kann wiederum mit verschiedenen Bildern und Musik verknüpft werden usw.
Kategorien sollen helfen, die Ressourcen strukturieren zu können. Sie können Subkategorien enthalten und als eine hierarchische Baumstruktur aufgebaut sein. Eine Kategorie kann mit einem Verzeichnis und eine Ressource mit einer Datei in einem Dateisystem verglichen werden. Im Gegensatz zu einem Dateisystem kann eine Ressource jedoch zu mehreren Kategorien gehören. Der Weblink auf die Homepage der Firma Sun könnte also z.B. sowohl unter der Kategorie „Java“ als auch unter der Kategorie „Unternehmen“ liegen.
Neben der Möglichkeit, alle Ressourcen, die zu einer Kategorie gehören, auflisten zu können, soll auch eine Suche nach Ressourcen implementiert werden. Die Suche nach Ressourcen soll mit Hilfe der Stichwörter, die für jede Ressource vergeben werden können, erfolgen. Dabei soll es alternativ möglich sein, eine Volltextsuche durchzuführen und nach den Inhalten oder der Beschreibung der Ressource zu suchen.
Im Rahmen dieser Diplomarbeit beschränkt sich die Entwicklung der Anwendung auf die Implementierung eines einzigen Moduls. Es soll eine Weblink-Verwaltung entwickelt werden. Ein Weblink ist eine Ressource und kann mehreren Kategorien zugeordnet werden. Weitere Module sollen in Zukunft als eigenständige Plugins implementiert werden können.
Eine sehr wichtige Anforderung an die Suchfunktion ist die Erweiterbarkeit der Funktionalität. Die Anwendung sollte es ermöglichen, nicht nur nach Daten innerhalb der Anwendung zu suchen, sondern über einen Plugin-Mechanismus auch die Suche in anderen Anwendungen erlauben. So sollte z.B. die Suche nach Weblinks nicht nur lokal möglich sein, sondern über ein Plugin auch im Google Verzeichnis.
Für die Suchfunktion sollen im Rahmen dieser Arbeit nur zwei Plugins implementiert werden. Es sollte die Suche im Internet unter Zuhilfenahme von Google [GOHP] Webservices möglich sein. Außerdem soll eine Suchfunktion für Microsoft Outlook [MSOLHP] Einträge, wie z.B. E-Mail, Kontakte, Termine, Aufgaben und Notizen implementiert werden.
Die Anwendung soll eine zentrale Datenhaltung haben und von jedem internetfähigen Client gestartet und bedient werden können. Die Kommunikation mit dem Server soll auch über Firewalls funktionieren. Eine gute Performance für die Suchfunktion ist eine weitere, sehr wichtige Anforderung. Die grafische Oberfläche soll dabei möglichst benutzerfreundlich sein.
2.2 Design
Nachdem die Anforderungen für die Anwendung schriftlich festgehalten wurden, begann die Designphase. In der Designphase wurden die verschiedenen Komponenten mit Hilfe von UML durch Klassen-, Sequenz- und Aktivitätsdiagrammen modelliert. Um den Entwurf zu evaluieren, wurden immer wieder kleine Prototypen implementiert. Dieses Kapitel beschreibt die bedeutendsten Elemente und wichtigsten Designentscheidungen.
2.2.1 Klassen Design
Das Klassenmodell wurde in Form von Klassendiagrammen mit Hilfe von UML erstellt. Abbildung 8 zeigt die zentralen Klassen und Schnittstellen der Anwendung.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 8: Klassendiagramm mit zentralen Klassen der Anwendung
Die Klassen Ressource, Category, Comment und Weblink enthalten dabei nur die eigentlichen Daten und implementieren keinerlei Geschäftslogik. Die Geschäftlogik zum Hinzufügen, Bearbeiten und Löschen von Resourcen und Kategorien wird durch die entsprechenden Manager-Klassen implementiert. Dabei wurde darauf geachtet, dass die Implementierung der Geschäftslogik soweit wie möglich unabhängig von der verwendeten Technologie ist. Daher sind die Manager Klassen als abstrakte Klassen implementiert. Die EJB-Klassen erben die implementierten Methoden von den Manager-Klassen und implementieren zusätzlich die notwendigen technologieabhängigen Methoden. Zur Speicherung der Daten in der Datenbank wurde das DAO Pattern [J2EEPC] verwendet. Auf diese Weise kann der Persistenz-Mechanismus auf eine sehr einfache und elegante Art und Weise ausgetauscht werden.
2.2.2 Datenbank Design
Das Datenbank Design wurde in Form von ER-Diagrammen modelliert. Abbildung 9 zeigt das zentrale ER-Diagramm der Anwendung.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 9: Datenbank Design der Anwendung
Dabei wurde für jede Klasse eine eigene Tabelle angelegt. Diese Art der Modellierung erlaubt ein wesentlich natürlicheres und objektorientiertes Mapping der Klassen auf die Tabellen. Die Datenbank ist dabei optimal normiert und weist keine Redundanzen auf. Allerdings hat dies gleichzeitig den Nachteil, dass die Zugriffe auf die Datenbank durch viele Join Statements wesentlich langsamer sind als bei einem nicht normiertem Datenbank-Design.
2.2.3 Grafische Oberfläche
Die Grafische Oberfläche wurde nach dem „Paper Prototyping“ Prinzip [PPHP] geplant. Die Idee hinter „Paper Prototyping“ ist, die Benutzeroberfläche erst in Papierform zu entwerfen und die Interaktion mit dem Computer auf dem Papier zu simulieren. Abbildung 10 zeigt den Entwurf der Oberfläche, welche per Hand erstellt worden ist.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 10: Paper Prototyp der Benutzeroberfläche
Wird die Oberfläche auf diese Art geplant, liegt der Vorteil darin, dass eine Mock2 Oberfläche schnell erstellt werden kann, ohne eine einzige Codezeile schreiben zu müssen. Auf diese Weise können viele Probleme entdeckt und behoben werden, noch bevor man mit der Implementierung begonnen hat. Auf der anderen Seite hat es den Nachteil, dass eine solche Planung viel Zeit benötigt und nicht alle Bereiche und Probleme abdecken kann.
Nachdem die Oberfläche auf Papier fertig gestellt war, wurde diese mit dem IntelliJ GUI Designer [IJHP] auf den Computer übernommen und während der Implementierungsphase Stück für Stück mit der Geschäftslogik verbunden.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 11: Screenshot der Benutzeroberfläche
In Abbildung 11 ist der fertige Entwurf der Benutzeroberfläche zu sehen.
2.2.4 Architektur
Kernstück dieser Arbeit ist die Evaluierung von AOP im J2EE und Webservices Umfeld. Die Beispielanwendung basiert daher auf der J2EE Platform. Zur Kommunikation zwischen Client und Server wird ein Webservice Framework verwendet.
Die Java 2 Platform Enterprise Edition (J2EE) von Sun Microsystems ist die Spezifikation eines Standards für eine Reihe von Softwarekomponenten. Die Spezifikation stellt einen allgemein akzeptierten Rahmen zur Implementierung von modularen Komponenten für verteilte, mehrschichtige Anwendungen dar. Klar definierte Schnittstellen zwischen den Komponenten und Schichten sorgen dafür, dass Softwarekomponenten unterschiedlicher Hersteller interoperabel sind, wenn sie sich an die Spezifikation halten und die verteilte Anwendung gut skalierbar ist.
Ein Webservice ist ein Dienst, der über das Internet zur Verfügung gestellt wird und nicht mit menschlichen Benutzern, sondern mit Softwarekomponenten Informationen austauschen kann. Solche Dienste basieren in der Regel auf XML und benutzen SOAP oder XML-RPC zur Kommunikation, WSDL zur Beschreibung und UDDI als Verzeichnisdienst zur Registrierung von Webservices. Oft wird gesagt, dass Webservices für Rechner das sind, was Webseiten für den Menschen sind. Auch wenn das nur ein Teil der Möglichkeiten der Webservices beschreibt, ist diese Aussage durchaus zutreffend.
Der Autor dieser Arbeit setzt voraus, dass der Leser mit den Grundkonzepten der J2EE Platform sowie Webservices vertraut ist. Für weitere und ausführlichere Informationen über J2EE und Webservices sei der Leser auf die J2EE [J2EESPEC] und EJB [EJBSPEC] Spezifikation sowie auf J2EE [J2EEHP] und Webservices [WSHP] Homepage von Sun Microsystems verwiesen.
Unter Einsatz von AOP entstand eine Client/Server Anwendung, die über einen Rich Client bedient werden kann und mit Hilfe von Webservices über Firewallgrenzen mit dem Server kommuniziert. Die Idee dahinter besteht darin, ein zentralisiertes Informations-Management- System auf Basis von J2EE zu entwickeln, welches von jedem internetfähigen Client bedient werden kann. Dabei erfolgt die Bedienung der Anwendung nicht, wie bei den meisten J2EE Anwendungen üblich, über einen Web-Browser. Stattdessen wurde eine komplexe grafische Oberfläche erstellt, die eine möglichst nahe Integration mit dem Betriebsystem erlaubt. Abbildung 12 zeigt eine schematische Darstellung der Architektur.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 12: Architektur Übersicht
Wie man der Grafik entnehmen kann, handelt es sich um eine klassische n-Tier Architektur auf J2EE Basis. Der Client befindet sich im Internet und kommuniziert über HTTP mit dem Webserver, welcher sich in der DMZ des Providers befinden sollte. Der Webserver kann als Load Balancer dienen und die Last durch viele Clientzugriffe auf mehrere Enterprise Application Server verteilen, die sich, geschützt durch eine Firewall, im Intranet des Providers befinden sollten. Der Web Container beinhaltet das Webservice Framework. Dieses Framework generiert einen entsprechenden Wrapper über die Geschäftlogik, die in Form von Session Beans implementiert wird. Weiterhin sorgt dieses Framework auch für eine plattformunabhängige Kommunikation mit dem Client über SOAP. Die Kommunikation zwischen der Webservice-Implementierung im Web Container und den Session Beans im Application Server erfolgt über IIOP. Der Application Server enthält schließlich die gesamte Geschäftslogik, welche mit EJB implementiert wird. Der EJB Container sorgt auch für die - dem Programmierer transparente - Persistenz der Objekte. Die Daten werden schließlich in einer Datenbank Management Systems (DBMS) abgespeichert, welches über JDBC mit dem Application Server kommuniziert.
2.3 Implementierung
Nach Abschluss der Designphase wurde mit der Implementierung der Anwendung begonnen. Das Hauptaugenmerk lag dabei auf den Möglichkeiten von AOP. Beim Entdecken von Problemen oder besseren Lösungen wurde das Design iterativ angepasst. In diesem Kapitel werden die verwendete Systemumgebung, Technologien und Frameworks beschrieben.
2.3.1 Allgemeines
Als Application Server wurde JBoss [JPHP] und als Web Container Tomcat [TCHP] eingesetzt. Die Anwendung ist jedoch grundsätzlich unabhängig vom Application Server und Web Container. Sowohl JBoss als auch Tomcat sind kostenlos verfügbare Open-Source Anwendungen. JBoss steht unter der Lesser General Public Lizenz (LGPL), während Tomcat unter der Apache Lizenz vertrieben wird.
Die Anwendung ist plattformunabhängig. Im Rahmen dieser Arbeit wurde die Anwendung jedoch nur unter Windows XP und Linux getestet. Durch den Einsatz von JDBC ist die Anwendung grundsätzlich auch datenbankunabhängig. Zu Testzwecken wurde PostgreSQL [PGHP] und HSQLDB [HSDBHP] als Datenbank verwendet. PostgreSQL und HSQLDB sind ebenfalls zwei Open- Source Projekte und stehen beide unter der BSD Lizenz. PostgreSQL ist inzwischen zu einem sehr mächtigen Datenbanksystem angewachsen, welches sich hinter kommerziellen Anbietern nicht zu verstecken braucht. Es werden auch komplexe Funktionen, wie z.B. referentielle Integrität, Trigger, Views oder Stored Procedures unterstützt. Bei HSQLDB dagegen handelt es sich um eine kleine und abgespeckte Datenbank, die sogar auf mobilen Geräten, wie z.B. Palm, Verwendung findet. HSQLDB ist komplett in Java implementiert und es ist auch möglich die Datenbank innerhalb derselben virtuellen Maschine ablaufen zu lassen wie die eigentliche Anwendung. Daher ist HSQLDB optimal zur Speicherung von Daten auf dem Desktop geeignet.
2.3.2 Technologien
An dieser Stelle sollen in erster Linie die Vor- und Nachteile der verschiedenen Technologien festgehalten werden. Dies soll vor allem die Bewertung der Technologien und eine Entscheidung über den Einsatz in einem anderen Projekt erleichtern.
2.3.2.1 Hibernate
Hibernate [HIBHP] ist ein objekt-relationales Persistenz-Framework, welches sich ins Besondere durch sehr natürliche, objektorientierte Modellierung und Mapping auszeichnet. Es unterstützt sowohl Vererbung, Polymorphie als auch Komposition. Hibernate ist komplett im Quellcode verfügbar und kann unter der LGPL Lizenz kostenlos im Internet herunter geladen werden. Mit mehr als 13.000 Downloads pro Monat hat Hibernate eine hohe Bekanntheit erreicht und wird bald auch in JBoss Version 4.0 integriert werden.
Bei der Implementierung der Anwendung wurde bewusst eine Entscheidung gegen den Einsatz von Entity Beans getroffen. Stattdessen wurde beschlossen, das Hibernate Framework zum Speichern der Daten zu verwenden.
Bei Einsatz von Entity Beans mit CMP ist es relativ schwierig und umständlich Vererbung von Objekteigenschaften zu implementieren und vernünftig auf eine relationale Datenbank zu mappen. Hibernate dagegen verwendet „Plain Old Java Objects“ (POJO) und ermöglicht ein sehr einfaches, natürliches Mapping der Objekte auf die Tabellen der Datenbank. Dabei ist, im Gegensatz zu vielen anderen Persistenz Frameworks, wie z.B. Object Relational Bridge (OJB) [OJBHP] oder Castor [CASHP], keine Code-Generierung notwendig. Die Mapping Information wird in einer XML Datei gehalten und beim Start der Anwendung werden mit Hilfe von Reflections daraus entsprechende SQL Statements generiert. Diese Architektur gestattet eine unkomplizierte Änderung des Daten- bzw. Objektmodels.
Ein weiterer Vorteil von Hibernate gegenüber Entity Beans ist die Möglichkeit, den Code auch
außerhalb des EJB Containers testen zu können. Hibernate skaliert sehr gut und kann problemlos in einer J2EE Umgebung eingesetzt werden.
[...]
1 Quelle: http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect_p.html
2 Unter einer Mock Oberfläche versteht man eine Dummy-Benutzeroberfläche, die keinerlei Funktionalität enthält und nur zur Simulationszwecken entwickelt wird.
-
-
-
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X. -
-
Upload your own papers! Earn money and win an iPhone X.