Software aus Komponenten
Download
Report
Transcript Software aus Komponenten
Gliederung: Teil 3 - Anpassungen
1. Einführung
– Motivation
– Definition,
– Konzepte für Komponenten (klassische, kommerzielle, akademische)
2. Industrielle Komponentensysteme der 1. Generation
1. CORBA
2. Enterprise JavaBeans
3. (D)COM
3. Anpassungen
– Daten und Funktion
– Interaktion
• Kommunikation
• Synchronisation
• Protokolle
– Lebendigkeit
Dr. Welf Löwe und Markus Noga
1
Problem
3.1 Anpassungen von Funktionen
Dr. Welf Löwe und Markus Noga
2
Daten- als Funktionsanpassung
Datenanpassung
–
–
–
–
–
Transformation von Wertetypen
Transformation von Schnittstellen
Können Auswirkung auf Implementierung von Diensten haben
Sind damit spezielle Funktionsanpassungen
Modell: Herausziehen generischer Klassen
Funktionsanpassung
– Hinzufügen, Entfernen und Ändern von Funktionalität
– Allgemeiner
Dr. Welf Löwe und Markus Noga
3
Domäne der Datenanpassung
Quelle: Class X {
R1 m1(P1);
R2 m2(P2);
...
Rn mn(Pn);
}
Ziel: Class Y {
R`1 m1(P‘1);
R`2 m2(P‘2);
...
R`n mn(P‘n);
}
Mittel: Class GX (
GP1 < TS1, (von Impl.)
GP2 < TS2,
...,
GR1 <, (von Benutzung)
GR2 <,
...,
) {
GR1 m1(GP1);
GR2 m2(GP2);
...
GRn mn(GPn);
}
Dr. Welf Löwe und Markus Noga
4
Datenanpassung mit generischen Klassen
Konkrete Parameter und Ergebnisse
– Als einen zusammengesetzten Typ auffassen
– Durch generischen Typ ersetzen
Einsetzen neuer spezieller Typen bildet neue Instanz
Anpassungen von
– Parametern
– Resultaten
– Methodenimplementierung (implizit)
Weitere nicht-generische Anpassungen
– Methodennamen
Dr. Welf Löwe und Markus Noga
5
Beispiel
Quelle: class SetOfComplex {
void
add(double re,
double im);
boolean has(double re,
double im);
int
size();
}
Ziel: class SetOfComplex {
void
set(Complex c);
boolean get(Complex c);
boolean empty();
}
Mittel: class Set<Type T> {
void
add(T t);
boolean has(T t);
int
size();
}
Dr. Welf Löwe und Markus Noga
6
Techniken revisited
XSLT & Co
– Umformen von WSDL-Beschreibungen
– Umformen konkreter Aufrufe, z.B.
• Permutation von Parametern
• Umbenennungen
Compost
–
–
–
–
Leistet Typanalyse
Identifiziert Stellen für innere Anpassung
Bietet Grundwerkzeuge zur Anpassung
Werkzeug mächtiger als (hier) benötigt
Dr. Welf Löwe und Markus Noga
7
Beispiel: Umbenennen mit Compost
public ProblemReport analyze() {
transformations = new TwoPassTransformationArrayList();
CrossReferenceServiceConfiguration config = getServiceConfiguration();
ProblemReport report = EQUIVALENCE;
AbstractTreeWalker tw = new
ForestWalker(getSourceFileRepository().getKnownCompilationUnits());
while (tw.next()) {
ProgramElement pe = tw.getProgramElement();
TwoPassTransformation t;
if (pe instanceof TypeDeclaration) {
TypeDeclaration td = (TypeDeclaration)pe;
if (td.getName() != null) {
t = new RenameType(config, td, createName(td));
report = t.analyze();
if (report instanceof Problem)
return setProblemReport(report);
transformations.add(t);
}
} else if (pe instanceof VariableSpecification) {
// ...
Dr. Welf Löwe und Markus Noga
8
Grenzen
Nur Anpassung einzelner Methoden
– Keine Aggregation
– Keine Zerlegung
– Keine Rekombination
Anpassung von Feldern teilweise problematisch
– Wann ist Typgleichheit Zufall?
– Wie identifiziere ich diese Fälle?
Nur implizite Änderung von Funktionalität
– Gezielte Änderungen unmöglich
Dr. Welf Löwe und Markus Noga
9
Grenzen am Beispiel
Quelle: class SetOfComplex {
void
add(double re,
double im);
boolean has(double re,
double im);
int
size();
double getReAt(int iter);
double getImAt(int iter);
void
}
Ziel: class SetOfComplex {
void
add(Complex c);
booelan has(Complex c);
int
size();
Complex get(int iter);
setLoad(double d);
}
Dr. Welf Löwe und Markus Noga
10
Funktionsanpassungen
Datenanpassungen (subsumiert)
Neue Sichten auf Funktionalität
– Aggregation
– Zerlegung
– Rekombination
Veränderungen der Funktionalität
– Erweitern
– Einschränken
– Ändern
(mit neuem Code)
(durch explizites Löschen)
(beides)
Dr. Welf Löwe und Markus Noga
11
Beispiel Aggregation
Quelle: class Konto {
void abheben (double euro);
void einzahlen(double euro);
Ziel: class Konto {
void abheben (double euro);
void einzahlen(double euro);
}
void überweise(Konto k,
double euro);
}
mit Semantik
Void überweise(double euro) {
this.abheben (euro);
k
.einzahlen(euro);
}
Dr. Welf Löwe und Markus Noga
12
Beispiel Zerlegung
Quelle: class Filter {
Filter(Config c);
void run(Input i);
}
Ziel: class Filter {
Filter();
void setup(Config c);
void run(Input i);
}
Dr. Welf Löwe und Markus Noga
13
Beispiel Rekombination
Quelle: class ModelView {
void addAndEnable(Model m);
}
Ziel: class ModelView {
void add
(Model[] m);
void enable(Model[] m);
}
Mittel: class ModelView {
void add
(Model m);
void enable(Model m);
}
Dr. Welf Löwe und Markus Noga
14
Beispiel Erweiterung
Quelle: class Signal {
void set(double[] data);
void multiply(double s);
void resample(double f);
void haarWavelet();
void haarWaveletInv();
}
Ziel: class Signal {
void set(double[] data);
void multiply(double s);
void resample(double f);
void wavelet
(Wavelet w);
void waveletInv(Wavelet w);
}
Implementierung spezifiziert durch
Benutzer.
Dr. Welf Löwe und Markus Noga
15
Beispiel Einschränkung
Quelle: class GrooveFiles {
Handle add
(File f);
File
get
(Handle h);
void
update
(Handle h,
File f);
void
setRights(Handle h,
Rights r);
void
enterpriseFunc2();
void
enterpriseFunc3();
}
Ziel: class GroovePreviewFiles {
Handle add
(File f);
File
get
(Handle h);
void
update(Handle h,
File f);
}
Dr. Welf Löwe und Markus Noga
16
Techniken
Anpassung ist Codetransformation
Einsatz von Compost
– Analyse der Quellen
– Spezifikation der Anpassungen als Metaprogramm
– Umsetzung mit Grundbausteinen aus Bibliothek
Beispiele zeigen primär Anpassung auf Signaturenmengen
– Erweiterungen/Einschränkungen denkbar, die quer zum OO-Modell
liegen
– Z.B. Hinzufügen/Entfernen von Tests, Persistenz etc.
– Auch mit Compost möglich.
Dr. Welf Löwe und Markus Noga
17
Beispiel: Erweitern mit Compost
public ProblemReport execute() {
MutableSet inserted = new IdentityHashSet();
CrossReferenceServiceConfiguration config = getServiceConfiguration();
ProgramFactory pf = getProgramFactory();
SourceInfo si = getSourceInfo();
CompilationUnitList units =
getSourceFileRepository().getKnownCompilationUnits();
for (int i = 0; i < units.size(); i += 1, inserted.clear()) {
CompilationUnit cu = units.getCompilationUnit(i);
TreeWalker tw = new TreeWalker(cu);
while (tw.next()) {
ProgramElement pe = tw.getProgramElement();
if (pe instanceof MethodReference) {
// [omitted: treat some special cases ...]
MethodReference caller = (MethodReference)pe;
MethodReference insert = (MethodReference)
pf.parseExpression("System.out.println(\"\")");
// [omitted: build expression to insert ...]
TwoPassTransformation t =
new PrependExpressionWithStatements(config, caller, insert);
ProblemReport report = t.analyze();
Dr. Welf Löwe und Markus Noga
18
Warum Unterscheidung?
Datenanpassungen sind
– Einfacher
– Stärker lokalisiert
– Mit einfacheren Werkzeugen (z.B. XSLT) behandelbar
Funktionsanpassungen sind
– Komplexer
– Weniger lokalisiert
– Erfordern aufwendigere Werkzeuge.
Praktische Unterscheidung für Ingenieure sinnvoll
Theoretische Unterscheidung evtl. nicht sinnvoll
– Jede Anpassung ist durch Wegwerfen und Neuschreiben möglich
Dr. Welf Löwe und Markus Noga
19
Problem
3.2 Anpassungen von Interaktionen
Dr. Welf Löwe und Markus Noga
20
Grau ist alle Theorie
Ansatz
– Interaktion = Datenfluß + Kontrollfluß
Kollision mit der Realität
– Häufigstes Interaktionsmittel ist der Prozeduraufruf
– Datenfluß legt Kontrollfluß fest
– Ebenso
•
•
•
•
RMI
Ereignisse
Synchrone Kommunikationskanäle
etc.
– Variablenzugriffe sind Methodenaufrufe (bei Verteilung)
Auflösung in Bestandteile theoretisch denkbar
Spätestens bei Rückabbildung große Probleme!
Dr. Welf Löwe und Markus Noga
21
Literatur
Understanding Software - Static and Dynamic Aspects
(Löwe, Ludwig, Schwind)
Aspect-Oriented Configuration and Adaptation of
Component Communication
(Heuzeroth, Löwe, Ludwig, Aßmann)
Compost: siehe vorangehende Vorlesung
Dr. Welf Löwe und Markus Noga
22
Definition
Interaktion = Kommunikation + Synchronisation
Kommunikation ist Daten- und Kontrollfluß
–
–
–
–
Lokaler Methodenaufruf
Java/Corba RMI
Ereignisse
etc.
Synchronisation stimmt Steuerflüsse ab
– Semaphore
– Kritischer Abschnitt
– Monitor
Explizite Manipulation von Steuerflüssen
– z.B. Threads
– hier nicht betrachtet
Dr. Welf Löwe und Markus Noga
23
Warum Kommunikation anpassen?
OO Entwurf
– aktive Objekte
– Relationen meist eigenständig
– Kommunikation über Nachrichten
OO Umsetzung
–
–
–
–
passive Objekte
wenig aktive Threads
Relationen meist in Objekte eingemischt
Kommunikation und Aktivierung durch Methodenaufrufe
Folge
– Große Spielräume bei der Umsetzung
– Verwendung von Entwurfsmustern kann Kompatibilität nicht garantieren
– Mangelnde Kompatibilität von Umsetzungen verschiedener Hersteller
Dr. Welf Löwe und Markus Noga
24
Ein Beispiel
Produzent passiv
Konsument passiv
Registrierung in beiden
Anpassung nötig!
Class Producer {
}
Class Consumer {
void register(Consumer c);
void register(Producer p);
Product produce();
void consume(Product p);
}
Dr. Welf Löwe und Markus Noga
25
Kommunikationsanpassung
Finde Kommunikationsports
Ersetze konkrete durch abstrakte/generische Aufrufe
Konfiguriere neu
Instanziiere gemeinsam (passfähig)
Abstract
Communication
Model
Program P1
Source Code
of
- components
- existing systems
Analysis
Abstract Model
Instance
for Program P1
Configuration
Configured
Abstract Model
Instance
for Program P1
Program P2
(Re-)Production
Transformation
Source Code
of
- adapted components
- restructured systems
Programming
Language
Dr. Welf Löwe und Markus Noga
26
Analyse
Statische Analyse identifiziert Methodenaufrufe
Problem: modellgebundene uneigentliche Kommunikation
– Z.B. Registrierung eines Listeners
– Identifikation: Semantikwissen in Muster übertragen
Problem: unvollständige Information
– M EventSources, N Listener
– Alle erben/benutzen abstrakte Interfaces
– Wer kommuniziert wirklich mit wem?
Lösung: Zusätzliche dynamische Analyse
– Auflösung polymorpher Aufrufe aufzeichnen
– Nur exemplarisch möglich (konkreter Programmlauf)
Dr. Welf Löwe und Markus Noga
27
Analysewerkzeug VizzAnalyzer
Statische Analyse
– Nutzt Compost
– Konzepte: Bezug-auf, Enthält, Unterklasse-von
Dynamische Analyse
– Nutzt Java Debug Interface
– Zeichnet (Ausschnitt aus) Programmlauf auf
– Konzepte: Ruft-auf, Zugriff-auf, Kennt, Instanz-von
Gefilterte Visualisierung
– Ignorieren von Paketen
– Hierarchische Aggregation
– Automatisches Layout
Dr. Welf Löwe und Markus Noga
28
Beispiel Analyse
class Producer {
private Channel<DataType> c;
class Consumer {
private Channel<DataType> c;
public Producer(Channel<DataType> c) {
this.c = c;
}
public doSomething() {
some calculations...
c.out(d);
further calculations...
}
public Consumer(Channel<DataType> c) {
this.c = c;
}
Communication
Out-Port
public doSomething() {
some calculations...
d = c.in();
further calculations...
}
Communication
In-Port
}
}
DataType
Channel
in() : DataType
out(d : DataType)
Channel
in() : DataType
out(d : DataType)
Dr. Welf Löwe und Markus Noga
29
Konfiguration
Semantik der Kommunikation festlegen
–
–
–
–
–
–
Gepuffert / ungepuffert
Koordination (FIFO, LIFO etc.)
Destruktives / nicht-destruktives Lesen
Aktivität
Verteilung
Basiskommunikation
Bibliokthek von Konnektoren
– Deckt verbreitete Fälle ab
– Erweiterbar
Konfigurator
– Metaprogramm, das Anpassung an Konnektor vornimmt
Dr. Welf Löwe und Markus Noga
30
class Producer {
private Buffer<DataType> b;
class Consumer {
private Buffer<DataType> b;
public Producer(Buffer<DataType> b) {
this.b = b;
}
A
public doSomething() {
some calculations...
b.out(d);
further calculations...
}
}
public Consumer(Buffer<DataType> b) {
this.b = b;
A}
Abstract Communication Connector
Communication
Out-Port
Communication
In-Port
public doSomething() {
some calculations...
d = b.in();
M1further calculations...
}
Beispiel Konfiguration
}
M1
DataType
Buffer
in() : DataType
out(d : DataType)
BufferedQueueChannel
counterInit : int
in() : DataType
out(d : DataType)
Metaprogram
Configuration
Communication Configurator
Dr. Welf Löwe und Markus Noga
31
Transformation
Ziel
– Ersetze abstrakte durch konkrete Kommunikation
– Abbildung auf Zielsprache
Mittel
– Metaprogramme der Konfiguratoren ausführen
Mögliche Optimierungen
– Einsparen von Puffern
– Einsparen von Kanal-Objekten
– etc.
Werkzeug
– Compost
Dr. Welf Löwe und Markus Noga
32
Ergebnis am Beispiel
Produzent aktiv
Konsument passiv
Registrierung beim Produzenten
Class Producer {
Class Consumer {
void consume(Product p);
void register(Consumer c);
void produce() {
}
Product p=myProduce();
for(int i=0; i<cs.length; i++)
cs[i].consume(p);
}
}
Dr. Welf Löwe und Markus Noga
33
Warum Anpassungen der Synchronisation?
Methodenausführung ist nicht atomar
– Synchronisation nötig um Semantik zu erhalten
Viele Mechanismen (alle äquivalent)
–
–
–
–
–
Mutexe
Semaporen
Kritische Abschnitte
Barrieren
usw.
Abbildung aufeinander i.A. nicht einfach
Oft Entwicklung im threadfreiem Raum
– Wiederverwendung in multi-threaded Umgebungen nicht gesichert
Dr. Welf Löwe und Markus Noga
34
Synchronisation
Behandlung wie Kommunikation
–
–
–
–
Analyse der konkreten Synchronisation
Abbildung auf abstrakte Synchronisation
Konfiguration
Transformation auf neue konkrete Synchronisation
Kern
– Abstrakter Synchronisations-Port
Evtl. erweitern um
– Explizite und implizite Manipulation von Threads
(fork / waitpid etc.)
Dr. Welf Löwe und Markus Noga
35
Beispiel
Quelle: class SyncUser {
Semaphore s;
void insensitive() {
s.wait();
sensitive();
s.post();
}
Ziel: class SyncUser {
synchronized void
sensitive() {
// perform some operations
// that need synchronization
}
}
void sensitive() {
// perform some operations
// that need synchronization
}
}
Dr. Welf Löwe und Markus Noga
36
Analyse
Erkennt abstrakte Synchronisation durch Muster
–
–
–
–
Keine Synchronisation
Exklusivzugriff auf Objekte
Exklusivzugriff auf Methodenmengen eines Objektes
Entweder N Leser oder 1 Schreiber
Einfach für implizite Synchronisation
– Kritische Abschnitte (z.B. Java synchronized)
– Barrieren
Schwieriger für explizite Synchronisation
– Mutexe
– Semaphoren
I.A. nicht statisch lösbar
Evtl. Einsatz dynamischer Analysen
Dr. Welf Löwe und Markus Noga
37
Grenzen
Explizite Synchronisation kennt Objekte und Referenzen
Generelle Probleme
– Gehört das Objekt zu einem speziellen Codeabschnitt?
– Wird es für andere Abschnitte wiederverwendet?
Aliasing-Probleme
– Worauf zeigt eine Referenz?
– Ist sie die einzige, die dorthin zeigt?
– Welche Aussagen über Synchronisationszustand sind möglich?
Lebendigkeit
– Welche Auswirkungen auf das Gesamtsystem treten ein?
Selbststabilisierende Algorithmen
– Was definiert die Sprache?
Dr. Welf Löwe und Markus Noga
38
Beispiel für Grenzen
class SyncUser {
Semaphore s;
void insensitive() {
s.wait();
sensitive();
s.post();
}
class SyncRoulette {
Vector us;
Random r=new Random(
System.currentTimeMillis() );
void add(SyncUser u) {
us.add(v.get());
}
void sensitive();
void roulette() {
int i=r.nextInt(us.size());
Semaphore s=(Semaphore)
us.elementAt(I);
if(r.nextBoolean()) s.wait();
else
s.post();
}
Semaphore get() {
return s;
}
}
}
Dr. Welf Löwe und Markus Noga
39
Konfiguration
Festlegen der Semantik
– Synchronisationsform
(z.B. Exklusivzugriff auf Objekt)
– Synchronisationsmechanismus
(z.B. OS, Runtime, Dienstgeber)
– etc.
Bibliothek von Synchronisatoren
– deckt gängige Fälle ab
Konfigurator
– Metaprogramm, das Anpassung an Synchronisator vornimmt
Dr. Welf Löwe und Markus Noga
40
Transformation
Ziel
– Ersetzen der abstrakten durch konkrete Synchronisation
– Abbildung auf Zielsprache
Mittel
– Metaprogramme der Konfiguratoren ausführen
Mögliche Optimierungen
– Einsparen von Objekten durch implizite Synchronisation
– Einsparen von Synchronisationen
(z.B. durch Dominanz- und Escape-Analyse)
– etc.
Werkzeug
– Compost
Dr. Welf Löwe und Markus Noga
41
Synchronisation und
Transaktionen
Synchronisation
– Ausführung einer Methode ist atomar
Transaktion
– Ausführung mehrerer Methoden ist atomar
(z.B. Abheben,Einzahlen = Überweisung)
– Unterschiedliche Anforderungen je nach Einsatzkontext
Modellierung von Transaktionen
– Abstrakten Sync- oder Lock-Ports
– Statische Analyse schwer
– Weitgehend ungelöst
Dr. Welf Löwe und Markus Noga
42
Synchronisation in der Praxis
Theorie zeigt viele schwer beherrschbare Probleme auf
Abbildungen zwischen Mechanismen eher selten
In der Praxis entscheidend: Threadfähigkeit
Single threaded multi threaded
– Funktional erforderlich
– Beherrschbar mit einfachen Mitteln
– Wrapping mit Synchronisationsbarriere ausreichend
Multi threaded single threaded
– Funktional kein Problem
– Geschwindigkeitsgewinne möglich
– Einsatz alter Bekannter: Escape-Analyse etc.
Dr. Welf Löwe und Markus Noga
43
Zusammenfassung
Unterscheidung nach Ingenieurskriterien sinnvoll
Gemeinsamer Ansatz
– Konkrete Umsetzung analysieren
– Abstrakte/Generische Anknüpfungspunkte identifizieren
– Diese neu instantiieren
Unnötig bei völlig generischem Programmieren, aber
– Keine Sprache kann alle Sichten vorsehen
– Neue Sprachen helfen nicht beim Umgang mit Altsystemen
– Es gibt immer mehr Altsysteme
Also
– Analyse und Transformation sind der Schlüssel zum Reengineering
– Übersetzerbau ist ein aktuelles Thema
Dr. Welf Löwe und Markus Noga
44