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