190 likes | 299 Views
9.2.2004. Seminar "Component and Aspect Engineering". Thema dieses Vortrages: Composition Filters und ComposeJ Bastian Demuth. 1. Ansatz, Motivation 2. Das CF Modell im Überblick 3. Filterprozess im Detail 4. Einige Filtertypen 5. Syntax der Filterdefinition 6. Beispiele.
E N D
9.2.2004 Seminar "Component and Aspect Engineering" Thema dieses Vortrages: Composition Filters und ComposeJ Bastian Demuth
1. Ansatz, Motivation 2. Das CF Modell im Überblick 3. Filterprozess im Detail 4. Einige Filtertypen 5. Syntax der Filterdefinition 6. Beispiele 7. Superimposition 8. Beispiel zur Superimposition 9. Fragen zur Implementation 10. Stand der Umsetzung 11. Bewertung Inhaltsübersicht
Ansatz bei der Entwicklung von Composition Filters • Implementation bestimmter Aspekte in Objekt-Orientierten (OO) Sprachen erfordert oft großen Aufwand • Mechanismen des OOP (Vererbung, Aggregation…) wichtig, aber nicht ausreichend Bsp: Zählen von Methodenaufrufen • Gesucht: Erweiterung für OOP Sprachen • Kontrolle der Kommunikation zwischen Objekten • Nachrichtenaustausch als zentrales Paradigma bei OOP • Potentiell äußerst mächtiger Ansatzpunkt
Kontrolle in welcher Form? • Ein- und ausgehende Nachrichten werden gefiltert • Filter sollen • einfach beschreibbar dennoch flexibel • kombinierbar (“orthogonal” aber geordnet) • transparent (“unsichtbar” für darunter liegende Objekte) • unabhängig von verwendeter OO-Sprache • wiederverwendbar sein • Composition Filters seit ca. 1989 von M. Aksit et al. an der Twente Universität entwickelt • syntaktisch aus der Sprache Sina hervorgegangen
Der Prozess des Filterns im Detail Semantik von „accept“/“reject“ hängt vom Filtertyp ab!
Einige Filtertypen • Der Error-Filter • lässt die Nachricht bei „accept“ durch, bei „reject“ verwirft er sie und erzeugt eine Exception • gut zum Abfangen von Nachrichten geeignet • Der Dispatch-Filter • bei „accept“ wird die Nachricht schließlich an ein Objekt übermittelt • jedes input-Filterset sollte am Ende einen Dispatch-Filter haben • erreicht eine Nachricht das Ende eines Filtersets: Exception wird ausgelöst • beschreibt multiple und konditionale Vererbung! • Der Send-Filter • output Filter, entspricht dem „Dispatch“-Filter
Einige Filtertypen (2) • Der Meta-Filter • dient u.a. zur Verwaltung von Metainformationen über den Nachrichtenverkehr (z.B. Logging, Zählen von Methodenaufrufen) • bei „accept“ wird Nachricht als „Parameter“ an eine spezifizierte Methode übergeben, bei „reject“ einfach weitergeleitet • „Meta-Methode“ kann Nachricht registrieren, ändern und reaktivieren • Der Wait-Filter • bei „reject“ (aufgrund nicht erfüllter Bedingung) werden Nachrichten zurückgehalten (in Queue placiert) • werden weitergegeben, sobald die Bedingung den Wahrheitswert „True“ annimmt (wird regelmäßig überprüft)
Die Syntax der Filterdefinition • Eine Filterspezifikation sieht so aus: <name> : <filter-type> = { <filter-elem>,<filter-elem>,… } Dabei hat jedes Filter-Element die Form matching part substitution part (anstatt => gibt es auch ~> als komplementären Operator) <condition> => [<match-target>.<match-sel>]<target>.<sel> • Teile der Filterelement-Deklaration können weggelassen werden. (siehe später) • substitution: Ziel der Nachricht veränderbar • Kritik am substitution part: mehrdeutig
Beispiel (1) bookkeeping : Meta = {[*] inner.count}; execute : Dispatch = {[*] inner.*, [*] internalObj.*}; • Filterset zum Zählen von Methodenaufrufen Auffällig: Minimalität (Methode „count“ + Mapping) Verwendete, noch nicht besprochene Features: • Bedingungen und „=>“ optional • Wildcards (*) • „inner“ Schlüsselwort bezeichnet inneres Objekt der CF-Objektinstanz • Methode, die die Nachricht als Parameter erhält ist für deren Reaktivierung zuständig => Nachricht geht zum nächsten Filter • Dispatch-Filter leitet Nachrichten automatisch an passende Instanzen (Signatur ausschlaggebend!)
Beispiel (2) • Synchronisation mittels Wait-Filter Verwendete Features: • Bedingungen • Wichtig: Bedingungs-Methoden dürfen keine Seiteneffekte haben! • matching part ist optional, aus substiution part abgeleitet • „True“ Schlüsselwort: Nachrichten matchen unabhängig von Bedingungen Queue : Wait = { True => unlock, Unlocked => * };
Beispiel (3): vollständiges Interface class Employee interface conditions taskLeft(); // true when there is at least one task to do. internals pers : Person; externals methods getTask() returns String putTask(String) returns Nil doTask() returns String inputfilters preCond : Error = {taskLeft~>putTask,!taskLeft~>{getTask,doTask}}; ~>{getTask, putTask} }; inherit : Dispatch = { inner.*, pers.* }; outputfilters end; // class Employee interface Alle Teile der Interfacedefinition sind optional dynamisches Interface!
Der Superimposition Mechanismus Dient der Wiederverwendung definierter Filtersets => „class crosscutting concerns“
Beispiel zur Superimposition concern Synchronization begin filterinterface synchronize begin conditions Unlocked methods lock() returns Nil inputfilters Queue : Wait = { True => unlock, Unlocked => * }; end filterinterface synchronize; superimposition begin selectors synchronizables = { *= Resource1, *= Resource2 }; filterinterfaces synchronizables <- self::synchronize; end superimposition; end concern Synchronization; Hier wird eine etwas neuere Syntax verwandt, um concerns zu beschreiben. ConcernJ soll später eine ähnliche Syntax unterstützen. Schlüsselwort „self“
Fragestellungen zur Implementation • Wann passiert das „weaving“? • wäre möglich, dynamisch Filter zur Laufzeit einzufügen • dynamisches Hinzufügen von Filtern kann Verständlichkeit und Korrektheit gefährden • geschieht teilweise auch aus Effizienzgründen nicht • Filter als Objekte • in OO Sprachen sinnvoll und logisch • durch Vererbung: neue Filtertypen für bisher „ungelöste“ Aspekte • müssen bestimmten Anforderungen genügen (Orthogonalität!) • sollten selbst keine Filter haben • schlecht überschaubar, unendliche Rekursion vermeiden
Stand der Umsetzung • Seit 1995: Umsetzungen für C++ und Smalltalk • enthalten die meisten der genannten Filtertypen, ohne Superimposition • Seit 1999 implementiert und weiterentwickelt: ComposeJ: Parser, der CF-Klassen in Java-Code umwandelt • weicht etwas von Standard-CF Syntax ab • unterstützt den Superimposition-Mechanismus bislang auch nicht • bisher nur Dispatch- und Errorfilter als Inputfilter implementiert • Identifikation von Methoden und internal/external Objekten funktioniert über entsprechende Namensgebung • zur Kompilierzeit wird Filter-Code in bestehenden Sourcecode eingefügt • In der Planungs-/Entwicklungsphase seit 2001: ConcernJ • soll Superimposition unterstützen • wird wahrscheinlich auf ComposeJ basieren
Bewertung: Wofür eignen sich CF gut? • Beispiele für Paradigmen und Aspekte, die im Zusammenhang mit CF speziell untersucht wurden: • Vererbung/Delegation (Dispatch-Filter und „server“ Schlüsselwort) • Multiple views/dynamische Interfaces (Error-Filter) • Sicherheit (Error-Filter) • Echtzeit-Anwendungen (Real-time-Filter) • Synchronisation/Locking (Wait und Error Filter) • Logging (Meta-Filter)
Wofür eignen sich CF weniger? • performance-bezogene Aspekte • starke Kapselung der inneren Objekte • Nachrichten müssen oft seriell alle Filter passieren • Filter produzieren viel overhead: • Meta-Filter transformieren Nachrichten in Objekte und umgekehrt (“reification” und “dereification”) • in der Praxis werden für jeden Filter weitere Hilfsobjekte benötigt (z.B. ca. 14 bei C++/CF)