Grundlagen der modellgetriebene Softwareentwicklung Teil 5
Transcription
Grundlagen der modellgetriebene Softwareentwicklung Teil 5
Grundlagen der modellgetriebene Softwareentwicklung Teil 5: Beispiele Prof. Dr. H. Drachenfels Hochschule Konstanz Version 7.0 18.4.2016 Übersetzerbau (1) Prinzipieller Aufbau eines Übersetzers (vereinfacht): Quellcode Zielcode Lexikalische Analyse Syntaxanalyse Token-Folge Semantikanalyse Syntaxbaum Codeerzeugung Symboltabelle, Zwischensprache Die Grammatik der Quellsprache legt fest, • welche Token es gibt (Schlüsselwörter, Namen, Zahlen, Operatoren, ...) • wie die Token syntaktisch verwendet werden dürfen Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-1 Übersetzerbau (2) Einsatz von Softwaregenerierung: • Scanner-Generator für die lexikalische Analyse (z.B. flex) erzeugt aus der Grammatik der Quellsprache einen endlichen Automaten, der die Zeichenfolge des Quellcodes in eine Token-Folge umsetzt. Token-Definition (reguläre Ausdrücke) Scanner-Generator Scanner • Parser-Generator für die Syntaxanalyse (z.B. bison, ANTLR) erzeugt aus der Grammatik der Quellsprache einen Kellerautomaten, der die syntaktische Korrektheit von Token-Folgen prüft. Syntax-Definition (EBNF) Prof. Dr. H. Drachenfels Hochschule Konstanz Parser-Generator Parser Grundlagen der modellgetriebene Softwareentwicklung 5-2 Verteilte Systeme (1) Ein verteiltes System besteht aus mehreren autonomen Knoten, die mittels Nachrichtenaustausch über ein Netz kooperieren. Der Nachrichtenaustausch wird durch die Heterogenität der Knoten erschwert: • unterschiedliche Hardware • unterschiedliche Betriebssysteme • unterschiedliche Programmiersprachen • deshalb neutrales Übertragungsformat für den Datenaustausch erforderlich Sender wandelt Daten von seinem lokalen in das neutrale Format Empfänger wandelt Daten vom neutralen in sein lokales Format Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-3 Verteilte Systeme (2) Beim RPC (Remote Procedure Call) wird der Nachrichtenaustausch zwischen zwei Knoten als Prozeduraufruf "verkleidet": Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-4 Verteilte Systeme (3) Einsatz von Softwaregenerierung: • Stub-Generator für den RPC erzeugt aus der Schnittstellen-Beschreibung (den Prozedur-Signaturen) die Stubs in den erforderlichen Programmiersprachen. Interface-Definition (IDL) Stub-Generator Client-Stub Server-Stub • der Client-Stub ist der Stellvertreter für den Server auf Clientseite verpackt den Prozeduraufruf mit den Aufrufparametern in eine Nachricht ("marshalling") packt die Ergebnisparameter aus der Antwortnachricht aus ("unmarshalling") • der Server-Stub (Skeleton) ist der Stellvertreter für den Client auf Server-Seite "unmarshalling" und "marshalling" in umgekehrter Reihenfolge Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-5 Beispiel CORBA (1) CORBA (Common Object Request Broker Architecture) ist eine von der OMG spezifizierte Plattform für verteilte objektorientierte Anwendungen • Mittels CORBA-IDL (Interface Definition Language) die per RPC aufrufbaren Methoden spezifizieren: // Echo.idl - ein einfaches über CORBA benutzbares Interface interface Echo { string echoString(in string mesg); }; • Mittels IDL-Compiler Client- und Server-Stubs generieren (z.B. für Java mit idlj, dem IDL-Compiler aus dem Java Development Kit): idlj -fall Echo.idl generiert Java-Interface Echo.java , Client-Stub _EchoStub.java , Server-Stub EchoPOA.java (POA = Portable Object Adapter) und weitere Hilfsklassen (EchoHelper, EchoHolder, EchoOperations) Prof. Dr. H. Drachenfels Hochschule Konstanz 5-6 Grundlagen der modellgetriebene Softwareentwicklung Beispiel CORBA (2) • Methoden-Implementierung durch Erweiterung des Server-Stubs (Skeletons): // MyEchoImpl.java - implementiert das IDL-Interface Echo public final class MyEchoImpl extends EchoPOA { public String echoString(String s) { return s; } } • Methode auf Server-Seite für Fernaufruf verfügbar machen: ... MyEchoImpl echoImpl = new MyEchoImpl(); POA poa = ... // Portable Object Adapter org.omg.CORBA.Object echoObj = poa.servant_to_reference(echoImpl); Echo echo = EchoHelper.narrow(echoObj); Server erzeugt Objekt und meldet Echo-Referenz dem CORBA Name Service NamingContextExt nc = ... // CORBA Name Service nc.rebind(nc.to_name("EchoObject"), echo); Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-7 Beispiel CORBA (3) • Methoden-Aufruf auf Client-Seite über Interface-Referenz: ... ORB orb = ORB.init(args, null); Client erfragt die Echo-Referenz beim CORBA Name Service org.omg.CORBA.Object ncObj = orb.resolve_initial_references("NameService"); NamingContextExt nc = NamingContextExtHelper.narrow(ncObj); org.omg.CORBA.Object echoObj = nc.resolve_str("EchoObject"); Echo echo = EchoHelper.narrow(echoObj); String s = echo.echoString("Hallo"); Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-8 Model Driven Architecture (1) Die Model Driven Architecture (MDA) ist ein Leitfaden der OMG mit dem Ziel, komplexe Systeme mit Hilfe von Modellen besser zu beherrschen. Ankündigung im Jahr 2001, MDA Guide 1.0.1 im Jahr 2003, Version 2.0 im Jahr 2014 Der Leitfaden ist ziemlich abstrakt und allgemein gehalten, fasst aber dennoch die zentralen Begriffe der modellgetriebenen Softwareentwicklung ganz gut zusammen. • Schwerpunkt ist die Plattformunabhängigkeit von Softwaresystemen • verwendet die OMG-Standards MOF (Meta Object Facility) und UML 2.0: MOF ist aufgeteilt in EMOF (Essential MOF) und CMOF (Complete MOF) → XMI (XML Metadata Interchange = XML-Mapping für EMOF-Modelle) → QVT (Query / View / Transformation) UML 2.0 ist spezialisierbar mittels Profilen (Stereotypen, Tagged Values, Constraints) → OCL (Object Constraint Language) Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-9 Model Driven Architecture (2) Modelle repräsentieren Systeme: • Domänenmodell (CIM = Computation Independent Model) Logisches Systemmodell (PIM = Platform Independent Model) Implementierungsmodell (PSM = Platform Specific Model) • System = Teile + Beziehungen + Zweck System = Anwendung + Plattform Metamodelle definieren Sprachen, in denen Modelle ausgedrückt werden Transformationen erzeugen aus Modellen andere Modelle, Modellrepräsentationen, Modellsichten oder sonstige Artefakte: • uni- oder bidirektional • model-to-model, model-to-artifact, artifact-to-model Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-10 Model Driven Architecture (3) Transformation eines PIM in ein PSM: PIM Transformation Specification Transformation Transformation Record Die " Transformation Specification" definiert die Abbildung von Modellelementen: • Metamodelle als Paramater • Modelle als Argumente für die Parameter Ein "Transformation Record " ist die Aufzeichnung einer durchgeführten Transformation • zur Konsistenzsicherung gedacht (PIM / PSM-Änderungen synchronisieren) PSM Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-11 Eclipse Modeling Project: Überblick Das Eclipse Modeling Project möchte die modell-basierte Entwicklung mit Frameworks, Werkzeugen und der Implementierung von Standards unterstützen. Themengebiete (entnommen www.eclipse.org/modeling/modeling-charter.php): Bereitstellung eines Framework für den Umgang mit Modellen (editieren, validieren, testen, speichern usw.) • Abstract Syntax Development • Concrete Syntax Development Unterstützung für sowohl graphische als auch textuelle Syntax • Model Transformation • Model to Text Generation OMG-Standards: MOF, UML, MDA, QVT, XMI, ... sonstige Standards: BPMN, BPDM, XSD • Industry Standards • Domain-Specific Modeling Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-12 Eclipse Modeling Project: EMF Das EMF (Eclipse Modeling Framework) unterstützt die Generierung von Werkzeugen und Anwendungen aus einem strukturierten Datenmodell. • enthält als Kern das (Meta-)Metamodell Ecore, mit dem die abstrakte Syntax von Datenmodellen definiert werden kann Klassen (EClass) mit Oberklassen, Attributen (EAttribute) und Referenzen (EReference) soll redundante Definitionen in UML, XML, Java ersetzen entspricht EMOF von MDA Metamodelle werden im XMI-Format als .ecore-Datei serialisiert • Generierung von Java-APIs für Modell-Instanzierung und -Zugriff • Generierung eines Modelleditors Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-13 Eclipse Modeling Project: Teilprojekte ausgewählte Teilprojekte nach Technologien gruppiert (entnommen eclipse.org/modeling): • Server and Storage EMFStore, Model Transaction, ... • User Interface EMF Client Platform, Extended Editing Framwork, ... • Graphical Modeling Sirius, GMF Tooling / Runtime / Notation, Graphiti • Modeling Tools OCL, Papyrus (als UML-Editor verwendbar), Sphinx, ... • Model Transformation ATL, Epsilon, MMT, ... • Textual Modeling Xtext (sehr ausgereift und erfolgreich) • Additional Modeling Frameworks Amalgam (mit allen erforderlichen Plug-Ins vorkonfigurierte Eclipse-Distributionen) EMF Compare / Diff / Merge Validation Framework ... Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-14 AspectJ: Aspektorientierte Programmierung mit Java In Software-Systemen gibt es oft Querschnitts-Aspekte ("Crosscutting Concerns"), die nicht in einer Komponente konzentriert werden können, sondern in viele Komponenten verwoben werden müssen. Beispiele: • Logging - Programmablauf protokollieren • Profiling - Programmverhalten vermessen • Sicherheit - Berechtigungen für Zugriffe prüfen • Beobachtermuster - Beobachter verwalten und benachrichtigen AspectJ erweitert Java um Sprachmittel zur Modularisierung solcher Aspekte: • Aspekte (aspects) fassen Code (advices) zusammen, der an verstreuten Stellen im Programm (join points / pointcuts) ausgeführt wird • Aspekte können Klassen um Deklarationen ergänzen (Inter-Type declarations) • Aspekte werden mit dem restlichen Code zu einem Java-Programm verwoben Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-15 AspectJ: Join Points und Pointcuts Ein Join Point ist ein wohldefinierter Punkt im Programmablauf, an dem potentiell Aspekt-Code eingefügt werden kann: • Aufruf einer Methode oder eines Konstruktors die Join Points sind • Ausführung eines Methodenrumpfs durch die Struktur der • Zugriff auf ein Feld Sprache Java vorgegeben • Behandlung einer Ausnahme Ein Pointcut ist ein benannter Ausschnitt aus der Menge aller Join Points: pointcut setter(): call(* Beispiel.set*(..)) alle Aufrufe von Methoden der Klasse Beispiel, deren Name mit set beginnt pointcut setterAndAdder(): call(* Beispiel.set*(..)) || call(* Beispiel.add*(..)) alle Aufrufe von Methoden der Klasse Beispiel, deren Name mit set oder add beginnt Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-16 AspectJ: Advices Ein Advice ist Code, der ausgeführt wird, wenn ein Join Point aus einem bestimmten Pointcut erreicht wird. Der Code kann direkt vor Erreichen des Join Points (before), direkt nach Erreichen des Join Points (after) oder sowohl als auch (around) ausgeführt werden. before(): setter() { System.out.println("calling " + thisJoinPoint); } vor Aufruf eines Setters eine Meldung ausgeben after() returning: setterAndAdder() { System.out.println("returned from " + thisJoinPoint); } nach erfolgreichem Aufruf eines Setters oder Adders eine Meldung ausgeben (nicht erfolgreiche Aufrufe: throwing statt returning, ohne Angabe beides) Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-17 AspectJ: Inter-Type Declarations Mit Inter-Type Declarations können bestehende Klassen um eine Oberklasse, Interfaces, Konstruktoren, Instanzvariablen und -methoden erweitert werden. declare parents: Beispiel implements Cloneable; public Object Beispiel.clone() throws CloneNotSupportedException { return super.clone(); } Erweiterung der Klasse Beispiel um die Implementierung des Interfaces Cloneable Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-18 AspectJ: Aspects Ein Aspect fasst Pointcuts, Advices und Inter-Type Declarations in einer syntaktischen Einheit zusammen. Definition im Stil einer Klasse: public aspect SetterTracing { pointcut setter(): call(* Beispiel.set*(..)) before(): setter() { System.out.println("calling " + thisJoinPoint); } declare parents: Beispiel implements Cloneable; public Object Beispiel.clone() throws CloneNotSupportedException { return super.clone(); } } Aspektinstanzen sind standardmäßig Singletons (alternativ perthis(), pertarget(), percflow(), percflowbelow()) Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-19 Generische Programmierung: Idee Die Idee der generischen Programmierung (Generic Programming) ist, bei der Programmierung von Algorithmen und Datenstrukturen von konkreten Typen zu abstrahieren. Die Typen werden erst bei der Benutzung der Algorithmen bzw. Datenstrukturen ergänzt (parametrische Polymorphie). • in Java ist die Idee ansatzweise mit Generics umgesetzt: z.B. verkettete Liste mit Elementtyp E im Paket java.util public class LinkedList<E> ... { ... } LinkedList<Integer> listOfIntegers = ...; LinkedList<String> listOfStrings = ...; z.B. Sortieralgorithmus für Felder mit Elementtyp T in der Klasse java.util.Arrays public static <T> void sort(T[] a, Comparator<? super T> c) { ... } Generics sorgen lediglich für statische Typsicherheit. Der übersetzte Code arbeitet einheitlich mit dem Elementtyp java.lang.Object. • in C++ ist die Idee deutlich weitergehend mit Templates umgesetzt Prof. Dr. H. Drachenfels Hochschule Konstanz Grundlagen der modellgetriebene Softwareentwicklung 5-20 Generische Programmierung: C++ Templates Der C++-Compiler verwendet Templates als Vorlage, um für jede Template-Instanzierung eigenen Code zu erzeugen: // templates.cpp #include <iostream> template<typename T> T max(T x, T y) { return x > y ? x : y; } int main() { std::cout << max(1, 2) << '\n'; std::cout << max(3.4, 4.5) << '\n'; } Prof. Dr. H. Drachenfels Hochschule Konstanz Der Compiler erzeugt hier zwei Implementierungen: int max(int x, int y) { return x > y ? x : y; } int max(double x, double y) { return x > y ? x : y; } Grundlagen der modellgetriebene Softwareentwicklung 5-21