Entwicklung eines Tools zur Messung von Testabdeckungen

Größe: px
Ab Seite anzeigen:

Download "Entwicklung eines Tools zur Messung von Testabdeckungen"

Transkript

1 Universität Hannover Fakultät für Elektrotechnik und Informatik Institut für Praktische Informatik Fachgebiet Software Engineering Entwicklung eines Tools zur Messung von Testabdeckungen Masterarbeit im Studiengang Angewandte Informatik von Przemyslaw Dul Prüfer: Prof. Dr. Kurt Schneider Zweitprüfer: Dipl.-Math. Christof Graß-De Iuliis Betreuer: Dipl.-Wirt.-Inform. Daniel Lübke Hannover, 18. Oktober 2005

2 Kurzfassung Die Messung von Testabdeckungen ist ein wichtiges Mittel zur Qualitätskontrolle von Tests. In dieser Arbeit werden zwei völlig verschiedene Verfahren vorgestellt, implementiert und untersucht, die als Basis für ein Werkzeug zur Messung von Testabdeckungen dienen können. Im Zentrum des Interesses befindet sich der Vergleich der beiden Verfahren. Anhand der Entwicklung und Integration zu einem Werkzeug für die Messung von Testabdeckungen wird eine Vielzahl von Eigenschaften der beiden Verfahren untersucht und miteinander verglichen. Die entwickelten Verfahren haben das Potential in diversen Werkzeugen eingesetzt zu werden, die sowohl Informationen über den Programmablauf in Echtzeit, als auch über die statische Programmstruktur selbst benötigen. Als Grundlage für die Implementierung der beiden Verfahren wird die Eclipse Platform verwendet. Eclipse ist eine erweiterbare Platform zur Erstellung integrierter Software. Die Erweiterbarkeit wird durch sogenannte Plugins ermöglicht. Beide Verfahren und weitere benötigte Komponenten für ein funktionsfähiges Werkzeug zur Messung von Testabdeckungen werden als Plugins für die Eclipse Platform entwickelt. Abstract The measurement of test coverage is an important way to control test quality. This thesis presents and analyses two completely different techniques that serve as a foundation for a test coverage tool. The main purpose of this thesis is to analyse and to compare both techniques with each other. This is realized by comparing the approaches, the implementation and the results of a benchmark. In general, the developed techniques can be used for tools, that need real-time information about the process and the structure of a program. The implementation depends on the Eclipse Platform. Eclipse is an extensible platform for building integrated software. Extensibility is reached by so-called plug-ins. Both techniques are developed as Eclipse plug-ins. As proof of concept some additional components are developed as Eclipse plug-ins to provide a test coverage tool that aid developers to control their test quality.

3 Inhaltsverzeichnis 1 Einleitung Motivation Aufgabenstellung Aufbau der Arbeit Ansätze und Grundlagen Instrumentierungsansatz Java Quellcode Instrumentierung Konstruktoren Schleifen- und Bedingungsanweisungen Typesafe Enumerations Tracingansatz Java Platform Debugger Architecture (JPDA) Java Virtual Machine (JVM) Java Debug Interface (JDI) Vergleich beider Ansätze Testabdeckungsmetriken Anweisungs- und Methodenüberdeckung Zweigüberdeckung Pfadüberdeckung Verwandte Arbeiten Implementierung Eclipse Runtime und Plugin Architektur Workspace User Interface Java Development Tools Architektur Überblick Instrumentierungsverfahren Instrumenter Inter-JVM-Kommunikation Probleme Tracingverfahren MarkerAnnotator BreakpointHandler Probleme Adapter Schnittstellen Messdaten Hilfsklassen Probleme Persistence ResultView SummaryDataViewProvider DetailsDataViewProvider Usability Vergleich der Implementierungen JUnit als Fallstudie I

4 4.1 Vorgehensweise Auswertung Methoden und Anweisungen Builddauer Ausführungdauer Projektgröße Vergleich der JUnit-Fallstudienergebnisse Abschlussbetrachtungen Ergebnisse und Fazit Ausblick II

5 Abbildungsverzeichnis Abbildung 1: Prinzip der Instrumentierung... 5 Abbildung 2: Java Platform Debug Architecture, vgl.[7]... 9 Abbildung 3: Interne Architektur der Java Virtual Machine...11 Abbildung 4: Ablauf einer Debugging Session...15 Abbildung 5: Fakultät-Kontrollflussgraph Abbildung 6: Eclipse Java-IDE Architektur, vgl. [26] S Abbildung 7: Workbench Fenster Abbildung 8: ASTNode Hierarchie vgl. [26] Abbildung 9: Abstract Syntax Tree Beispiel aus [26] S Abbildung 10: Eclipse Platform Debug Model. [31]...43 Abbildung 11: Breakpoint Model, vgl. [0] Abbildung 12: Architektur des Werkzeugs zur Messung von Testabdeckungen...46 Abbildung 13: Instrumenter-Plugin Abbildung 14: Instrumenter-Teilsystem...50 Abbildung 15: Inter-JVM-Kommunikation Abbildung 16: Tracer-Plugin Abbildung 17: MarkerAnnotator-Teilsystem...55 Abbildung 18: Adapter Abbildung 19: Persistence-Plugin...61 Abbildung 20: ResultView-Plugin Abbildung 21: SummaryDataView - Screenshot Abbildung 22: DetailsDataView - Screenshot Tabellenverzeichnis Tabelle 1: Vergleich der Ansätze...17 Tabelle 2: Testfall für vollständige Anweisungsüberdeckung der Fakultät-Methode...19 Tabelle 3: Testfälle für vollständige Zweigüberdeckung der Fakultät-Methode...20 Tabelle 4: Testfälle für gute Zweigüberdeckung der Fakultät-Methode Tabelle 5: Vergleich verschiedener Implementierungsaspekte Tabelle 6: Zusammenfassung der JUnit-Fallstudienergebnisse...68 Tabelle 7: Vergleich der implementierten Verfahren anhand der JUnit-Fallstudienergebnisse Quellcodeverzeichnis Quellcode 1: Einfaches Instrumentierungsbeispiel...5 Quellcode 2: Konstruktorinstrumentierung...6 Quellcode 3: Instrumentierung geschachtelter Schleifen-und Bedingungsanweisungen... 7 Quellcode 4: Instrumentierung einer Typesafe-Enumeration...8 Quellcode 5: Fakultät-Methode Quellcode 6: Multiple-Breakpoint-Problem III

6

7 1 Einleitung 1.1 Motivation Wie am Fachgebiet Software Engineering der Universität Hannover werden Java- Programme an vielen akademischen Institutionen, aber auch in verschiedenen Unternehmen mit der Entwicklungsumgebung Eclipse 1 [1] implementiert. Neben der kostenlosen Verfügbarkeit, ist ein weiterer Vorteil von Eclipse gegenüber anderen Entwicklungsumgebungen dessen leichte Erweiterbarkeit durch Plugins 2. Für den kommerziellen Einsatz stehen neben der kostenlosen Distribution von Eclipse kommerzielle Distributionen zur Verfügung, die die Standardfunktionen deutlich erweitern. Bei der Entwicklung von zuverlässiger Software werden Test-Werkzeuge eingesetzt, um die Qualität der Software zu kontrollieren. Ein bekanntes Werkzeug dieser Art für die Programmiersprache Java ist JUnit 3. [2] Dieses ist seit der Eclipse-Version 2 ein Bestandteil der Eclipse-Distribution. JUnit-Tests sind selbst ein Stück Software und werden so wie der zu testende Code von einem Programmierer geschrieben. Sie können automatisch und beliebig oft ausgeführt werden. In einem Test-Prozess sind Entwickler und Tester bestrebt möglichst alle Teile des Quellcodes durch die Tests mindestens einmal auszuführen. Ein JUnit-Test liefert jedoch als Ergebnis im wesentlichen nur, ob er gelungen oder misslungen ist. Über die Qualität eines Tests liefert JUnit damit keine Informationen. Ein wichtiges Merkmal der Testqualität ist die sogenannte Testabdeckung. Sie gibt an, wieviel des zu untersuchenden Quellcodes tatsächlich durch die Tests ausgeführt wurde und insbesondere welche Teile des Quellcodes nicht ausgeführt wurden. 4 An diesem Punkt setzt die vorliegende Masterarbeit an. 1 Seit Version 3.0 ist Eclipse tatsächlich eine eine Rich Client Platform, während es vorher als erweiterbare Entwicklungsumgebung konzipiert war. [1] 2 Aus dem Englischen to plug in - einstöpseln, anschließen. Ein Plugin ist ein Zusatzmodul, dass die Software um weitere Funktionalität erweitert. 3 JUnit ist ein Framework zum Testen von Java-Programmen, das besonders für automatisierte Tests einzelner Klassen (Units) geeignet ist. Es basiert auf Konzepten, die ursprünglich unter dem Namen SUnit für Smalltalk entwickelt wurden. Hauptentwickler des JUnit-Frameworks sind Erich Gamma und Kent Beck. Mittlerweile existieren JUnit-ähnliche Frameworks auch für viele andere Programmiersprachen. Oft werden diese Programme unter dem Namen xunit zusammengefasst. [3] 4 Von einer 100%igen Testabdeckung kann nicht auf die Fehlerfreiheit des Quellcodes geschlossen werden. 1

8 1.2 Aufgabenstellung Es soll ein Eclipse-Plugin zur Messung von Testabdeckungen entwickelt werden. Hierfür werden zwei verschiedene Verfahren untersucht: ein Instrumentierungsverfahren und ein Tracingverfahren. Während das Instrumentierungsverfahren auf der Annotation des Quellcodes basiert, verwendet das Tracingverfahren die Ablaufverfolgung des Eclipse-Debuggers. Beide Verfahren sollen implementiert und ausführlich miteinander verglichen werden. Dabei sollen die Vor- und Nachteile und damit auch die Performance und die Probleme beider Verfahren diskutiert werden. Zudem soll die Implementierung eine einfache Erweiterbarkeit durch weitere Plugins gewährleisten, um z. B. andere Visualisierungen der Daten zu ermöglichen. Natürlich soll das Plugin einfach zu bedienen sein und sich zusammen mit JUnit verwenden lassen. Piwowarski hat dazu in [4] (S. 5) folgendes festgestellt: In the survey of IBM testing organizations [...], we found that testers: were familiar with test case coverage measures, believed that the use of coverage measures would help them find errors and improve the quality of their products, but generally did not use test case coverage tools. Im darauf folgendem Satz schlussfolgert er: Testers did not use coverage tools, not because of a lack of knowledge of them, or lack of belief in their worth, but because coverage tools had proved to be to difficult to use. Daher ist die Usability ein wichtiger Gesichtspunkt bei der Umsetzung des Plugins. Das in dieser Arbeit zu entwickelnde Plugin zur Messung von Testabdeckungen ist der erste Schritt bei dem Entwurf einer Suite für Eclipse, die verschiedene Aspekte der Softwareentwicklung am Fachgebiet Software Engineering der Universität Hannover unterstützen soll. Weitere Pläne umfassen z. B. die Echtzeitvisualisierung von Programmabläufen, Bestimmung von häufig ausgeführten Programmteilen und Darstellung von Abhängigkeiten zwischen Klassen oder Modulen, sowie diverse andere Statistikfunktionen. Soweit möglich soll das in dieser Arbeit zu entwickelnde Plugin diese Pläne durch entsprechende Implementierungen, Schnittstellen und Modularisierung unterstützen oder umsetzen. Aufgrund dieses umfassenderen Zusammenhanges ergeben sich zwei besondere Anforderungen an das zu entwickelnde Plugin: Erstens soll die Messung der Testabdeckung in Echtzeit möglich sein. Das bedeutet, dass es eine Schnittstelle geben muss, über die weitere Module über jede ausgeführte Anweisung einzeln und unmittelbar benachrichtigt werden können. Zweitens sollen die vom Plugin gesammelten Daten derart umfangreich sein, dass z. B. eine Bestimmung und Visualisierung häufig ausgeführter Anweisungen, Methoden und Module möglich ist. 2

9 1.3 Aufbau der Arbeit Die vorliegende Arbeit ist folgendermaßen strukturiert: zunächst werden die beiden Ansätze des Instrumentierungs- und des Tracingverfahrens vorgestellt und die Grundlagen dieser Ansätze erläutert. In diesem Zusammenhang werden verschiedene verwandte Arbeiten zusammengefasst und skizziert. Im Rahmen des Kapitels Implementierung wird zunächst die Eclipse Platform vorgestellt, die als Basis für die Umsetzung der Ansätze dient, und anschließend werden die Bestandteile der Implementierung selbst dargelegt. Anhand des JUnit-Frameworks als Fallstudie werden dann die Eigenschaften der Implementierung untersucht und diskutiert. Abschließend wird ein Fazit gezogen und ein Ausblick auf weitere Entwicklungsmöglichkeiten geboten. Der Vergleich des Instrumentierungs- und des Tracingverfahrens ist ein zentrales Thema dieser Arbeit. Deshalb werden verschiedene Aspekte der beiden Verfahren auf drei unterschiedlichen Ebenen miteinander verglichen: den Ansätzen und Grundlagen, der Implementierung und der Performance. Die Ebenen spiegeln sich wesentlich im Aufbau dieser Arbeit wieder. Jeder dieser Ebenen ist ein Kapitel gewidmet, der einen ausführlichen Abschnitt enthält, in dem beide Verfahren direkt miteinander verglichen werden. Die Performance wird in Kapitel 4 anhand einer Fallstudie untersucht und verglichen. 3

10 2 Ansätze und Grundlagen Dieser Abschnitt wird zunächst die Grundlagen des Instrumentierungs- und des Tracingansatzes vorstellen. Hierbei wird der Kontext der Eclipse Umgebung außen vor gelassen, um zunächst die wesentlichen Aspekte beider Ansätze zu erläutern und anschließend direkt miteinander zu vergleichen. Beide Ansätze zielen in erster Linie dabei auf die Messung der Anweisungs- und Methodenüberdeckung ab. Diese und weitere Testabdeckungsmetriken werden in Abschnitt 2.4 erläutert. Beide Ansätze können jedoch auch für verschiedene andere Zwecke eingesetzt werden, die auf Informationen über die Programmstruktur und den Programmablauf angewiesen sind. Zuletzt wird ein Einblick in einige ausgewählte verwandte Arbeiten zum Thema Messung von Testabdeckungen gewährt. 2.1 Instrumentierungsansatz Viele heute zur Verfügung stehenden Werkzeuge zur Messung der Testabdeckung verwenden den Instrumentierungsansatz. Es ist ein besonders einfacher Ansatz und beruht auf der statischen Instrumentierung des Quellcodes. Dabei werden dem Quellcode vor dessen Kompilierung Anweisungen hinzugefügt. Um den original Code zu schützen wird die Instrumentierung auf einer Kopie durchgeführt. Während der Instrumentierung werden zudem alle relevanten statischen Daten des Quellcodes in tabellarischer Form gespeichert. Diese Daten beinhalten Informationen zu den Methoden und Anweisungen des originalen Codes, wie z. B. den Namen einer Methode, die Zeilenangabe oder den Typ einer Anweisung. Das Ziel dabei ist die Minimierung des Overheads bei der Ausführung des instrumentierten Programmes, indem so viele Berechnungen wie möglich auf die Instrumentierungsphase und die Auswertungsphase verlagert werden. Bei dem einfachsten Instrumentierungsansatz wird nach jeder Methode und vor jeder Anweisung zusätzlicher Code beigefügt. Abbildung 1 veranschaulicht das Prinzip der Quellcodeinstrumentierung. Diese Instrumentierung erlaubt die genaue Messung aller ausgeführten Anweisungen, unabhängig an welcher Stelle das Programm terminiert oder eine Ausnahme wirft. Die Instrumentierungsanweisungen können beliebigen Code beinhalten. In der Praxis werden über die Instrumentierungsanweisungen jedoch nur Informationen über die aktuelle Position im Programm oder gewisse Laufzeitinformationen (z. B. Thread-ID, Objekt-ID oder die Ausführungszeit) gesammelt. Entscheidend für die Auswertung ist, dass eine Zuordnung der während der Ausführung des instrumentierten Programmes gesammelten Daten mit den in der Instrumentierungsphase gesammelten Daten möglich ist. 4

11 Original Quellcode Instrumentierter Quellcode Instrumentierung durch Annotation Abbildung 1: Prinzip der Instrumentierung Der Instrumentierungsansatz führt offensichtlich zu einer erheblichen Zunahme der Programmgröße: Es wird eine Kopie des originalen Quellcodes generiert. Dann wird die Kopie instrumentiert, wodurch die Größe der Kopie circa verdoppelt wird. Anschließend wird die Kopie übersetzt, so dass auch der Bytecode sich circa verdoppelt Java Quellcode Instrumentierung Der folgende Quellcode zeigt exemplarisch die Instrumentierung eines einfachen Hello World Programmes. 1 public class HelloWorld { 2 3 private static CoverageTraceCollectorClient collector = CoverageTraceCollectorClient.getInstance(300); 4 5 public static void main(string[] args){ 6 collector.called( "Example<c D>example/HelloWorld.java<c D>0<c D>"); 7 collector.called( "Example<c D>example/HelloWorld.java<c D>1<c D>"); 8 System.out.println("HelloWorld"); 9 } 10 } Quellcode 1: Einfaches Instrumentierungsbeispiel Die Anweisungen in Zeile 3,6 und 7 sind Instrumentierungsanweisungen. Der Klasse HelloWorld wird in Zeile 3 ein statisches Objekt vom Typ CoverageTrace CollectorClient hinzugefügt. Es ist statisch damit alle Instanzen von Hello World darauf zugreifen können, ohne dass für jede neue HelloWorld Instanz ein neues CoverageTraceCollectorClient Objekt erzeugt werden muss. Bei der Deklaration des CoverageTraceCollectorClient Objektes wurde aus Platzgründen auf die vollständige Qualifizierung verzichtet. Die Anweisung in Zeile 6 instrumentiert die Main Methode, während die Anweisung in Zeile 7 das folgende System.out.println instrumentiert. Aufgrund des Parameters der Instrumentierungsanweisungen in Zeile 6 und 7 läßt sich eindeutig rück schließen, welche Methode oder Anweisung ausgeführt wurde: Example identifiziert das Projekt, example/helloworld.java den projektrelativen Pfad der Datei und 0 bzw. 1 5

12 die ID der Anweisung. Die Zeichenkette <c D> dient als Trennzeichen (Delimiter). Das Beispiel macht deutlich, dass Quellcode-Instrumentierungsverfahren potentiell Namenskonflikte auslösen können. Um die Wahrscheinlichkeit für einen Namenskonflikt zu minimieren wird für das CoverageTraceCollectorClient-Objekt ein möglichst ungewöhnlicher und selten vorkommender Name verwendet. In diesem Fall collector. Bei der Instrumentierung sind weitere kritische Fälle zu beachten, damit der Quellcode weiterhin der Spezifikation entspricht und kompilierbar bleibt. Auch Änderungen am ursprünglichen Programmablauf wären fatal. In den folgenden Abschnitten werden verschiedene kritische Fälle diskutiert Konstruktoren Konstruktoren dürfen als erste Anweisung einen Aufruf der Methode super() besitzen. super() wird als Aufruf des Superklassenkonstruktors interpretiert. 5 Falls kein Aufruf von super als erste Anweisung im Konstruktor steht, setzt der Compiler an dieser Stelle einen impliziten super-aufruf ein und ruft damit den parameterlosen Konstruktor der Vaterklasse auf. Alternativ ist es auch erlaubt, mit Hilfe der this-methode einen anderen Konstruktor der eigenen Klasse aufzurufen. In diesem Fall muss this() ebenfalls die erste Anweisung innerhalb eines Konstruktors sein. Deshalb müssen beim Vorhandensein einer super() oder this() Anweisung in einem Konstruktor, die Instrumentierungen für den Konstruktor und die super() oder this() Anweisung erst hinter dem Superklassenkonstruktoraufruf oder dem Aufruf eines Konstruktors der eigenen Klasse hinzugefügt werden. Quellcode 2 demonstriert die Instrumentierung eines Konstruktors mit super()-aufruf. Dabei sit zu beachten, dass die Instrumentierungen in Zeile 7 und 8 erst nach dem super()-aufruf hinzugefügt wurden und nicht wie bei Methoden sonst üblich direkt nach der Methodendeklaration. 1 public class Constructor { 2 3 private static CoverageTraceCollectorClient collector = CoverageTraceCollectorClient.getInstance(300); 4 5 public Constructor() { 6 super(); 7 collector.called( "Example<c D>example/Constructor.java<c D>1<c D>"); 8 collector.called( "Example<c D>example/Constructor.java<c D>0<c D>"); 9 } 10 } Quellcode 2: Konstruktorinstrumentierung 5 super wird wie eine normale Methode verwendet und kann mit oder ohne Parameter aufgerufen werden. Der Aufruf muß natürlich zu einem in der Superklasse definierten Konstruktor passen. 6

13 2.1.3 Schleifen- und Bedingungsanweisungen Falls Schleifen- und Bedingungsanweisungen keine Blockklammern (d.h. keine geschweiften Klammern) besitzen, beziehen sie sich auf die direkt folgende Anweisung. Während der Instrumentierung müssen deshalb Blockklammern für diese Schleifenund Bedingungsanweisungen erzeugt werden, bevor die darauf folgende Anweisung instrumentiert werden kann. Hierbei muss jedoch beachtet werden, dass die nachfolgende Anweisung ebenfalls eine Schleifen- oder Bedingungsanweisung ohne Blockklammern sein kann. Auf diese Weise können Schleifen- und Bedingungsanweisungen beliebig tief geschachtelt sein. Einen Sonderfall dieser Schachtelung stellen if-else-kaskaden dar. Dabei stellt jedes if eine Anweisung auf einer anderen Schachtelungstiefe dar. Die folgenden Quellcodefragmente zeigen die Instrumentierung einer if-else-kaskade, sowie einer geschachtelten while-schleife. Zu Gunsten der Übersichtlichkeit wurde auf den Parameter der called-methode verzichtet. Es ist deutlich zu erkennen, dass sich das Erscheinungsbild durch die Instrumentierung erheblich ändert. Instrumentiert //if-else-cascade collector.called(...); if(true) { collector.called(...); System.out.println("1"); } else { collector.called(...); if(true) { collector.called(...); System.out.println("2"); } else { collector.called(...); if(true) { collector.called(...); System.out.println("3"); } } } //nested while loops collector.called(...); while(true) { collector.called(...); while(true) { collector.called(...); System.out.println("4"); } } } //if-else-cascade Original if(true) System.out.println("1"); else if(true) System.out.println("2"); else if(true) System.out.println("3"); //nested while loops while(true) while(true) System.out.println("4"); Quellcode 3: Instrumentierung geschachtelter Schleifen-und Bedingungsanweisungen 7

14 2.1.4 Typesafe Enumerations Seit der Java Version 1.5 können in Programmen sogenannte Typesafe-Enumerations vorkommen. Eine Typesafe-Enumeration wird durch das Schlüsselwort enum deklariert. Sie besitzt im einfachsten Fall einen Namen und besteht aus einer Elementmenge eben dieses Typs. Optional können nach der Elementmenge zusätzlich Attribute, Methoden und parametrisierte Konstruktoren definiert werden. Instrumentierungsanweisungen dürfen in einem Typesafe-Enumeration-Konstrukt also erst hinter der Elementmenge hinzugefügt werden. Die folgenden Quellcodefragemte zeigen eine instrumentierte Typesafe-Enumeration und die zugehörige originale Definition der Typesafe-Enumeration. Dabei ist zu beachten, dass die Initialisierung des collector -Objektes erst nach der Aufzählung von Earth und Mars stattfindet. Instrumentiert public enum Planet { Earth(4), Mars(3); Original public enum Planet { Earth(4), Mars(3); private static CoverageTraceCollectorClient collector = CoverageTraceCollectorClient.get Instance(300); private int mass; private int mass; Planet(int mass) { collector.called(...); collector.called(...); this.mass = mass; } Planet(int mass) { this.mass = mass; } } public int getmass() { collector.called(...); collector.called(...); return mass; } } public int getmass() { return mass; } Quellcode 4: Instrumentierung einer Typesafe-Enumeration 2.2 Tracingansatz Fast jede Entwicklungsumgebung verfügt über Werkzeuge, sogenannte Debugger, die das auffinden und beseitigen von Fehlern eines Programmes ermöglichen. Das Tracing ist eine wichtige Debugfunktion 6, die das Mitverfolgen des Programmablaufes erlaubt. Der Tracingansatz zur Messung der Testabdeckung nutzt diese 6 Unter Debugging wird die Analyse und Bearbeitung eines Programmes verstanden, um Fehler zu finden und zu beseitigen. 8

15 Funktionalität, um während des Programmablaufes mitzuverfolgen, welche Methoden und Anweisungen ausgeführt werden. Der in dieser Arbeit implementierte Tracingansatz verwendet sogenannte Breakpoints (vgl. S. 13) um Informationen über die Testabdeckung zur Laufzeit des zu untersuchenden Programmes zu erhalten. Zu Gunsten der Ausführungsgeschwindigkeit wird der Quellcode beim Tracingansatz genau wie beim Instrumentierungsansatz bereits vor seiner Ausführung analysiert, um alle relevanten statischen Informationen des Quellcodes zu erfassen. Die meisten Java Debugger setzen auf die Java Platform Debugger Architecture auf. Deshalb wird dieser Abschnitt zunächst die Java Platform Debugger Architecture vorstellen, die eine standardisierte Schnittstelle für das Debuggen von Java-Programmen bereitstellt. Dann wird ein Einblick in die Architektur der Java Virtual Machine gegeben, um zu verstehen, welche Informationen mit Hilfe der Java Platform Debugger Architecture Schnittstellen geliefert werden können. Die folgenden Ausführungen basieren zum großen Teil auf der Diplomarbeit [5] von Mark Brörkens, sowie des Dokumentes [6] von Thomas Weniger und den beiden offiziellen Dokumentationen von Sun Microsystems [7] und [8] Java Platform Debugger Architecture (JPDA) Die Java Platform Debugger Architecture (JPDA) wurde mit der Version 1.2 des Java SDK eingeführt, um eine einheitliche Architektur für den Zugriff auf die Java Virtual Machine und das darauf laufende Programm (Debuggee) durch Debugger bereitzustellen. Die JPDA besteht aus zwei Schnittstellen (JVMDI und JDI), einem Protokoll (JDWP) sowie zwei Software-Komponenten, die diese Elemente miteinander verbinden (Front-End und Back-End) (siehe Abbildung 2). Das entscheidende Feature der JPDA ist die Trennung des Debuggers vom Debuggee. Würde der Debugger im selben Prozess wie das Debuggee ausgeführt, könnten sie sich gegenseitig beeinflussen und stören. Debuggee VM back-end JVMDI Java Virtual Machine Debugger Interface Comm Channel JDWP Java Debug Wire Protocol Debugger front-end UI JDI Java Debug Interface Abbildung 2: Java Platform Debug Architecture, vgl.[7] 9

16 Java Virtual Machine Debug Interface (JVMDI) Das JVMDI ist ein natives Interface. Es wird von einer Virtual Machine (VM) implementiert, die das Debugging eines in dieser VM ablaufenden Java Programmes ermöglicht. Das Interface stellt Informationen (z. B. zum aktuellen Stack Frame), Aktionen (z. B. das Setzen von Breakpoints) und Benachrichtigungen (z. B. wenn ein Breakpoint getroffen wurde) bereit. Auf diesem Interface basiert das Back-End welches die nativen Funktionsaufrufe für ein Plattform unabhängiges Protokoll (JDWP) aufbereitet. Das JVMDI wurde mit Java 1.0 eingeführt und blieb bis zur Version 1.4 nahezu unverändert. Seit der Version 1.4 können Filter für Ereignisse gesetzt werden. Zudem wurde eine Technik namens HotSwap eingeführt, die es ermöglicht Bytecode Classdateien zur Laufzeit und unter gewissen Bedingungen in der Java Virtual Machine auszutauschen. Diese Technik wird innerhalb der Methode Redifine Classes() des JVMDI realisiert. In Java 1.5 wurde das JVMDI durch das Java Virtual Machine Tools Interface (JVMTI) ersetzt. Das neue Interface soll eine höhere Performance erzielen und weitere Funktionen bereitstellen. Java Debugger Wire Protocol (JDWP) Das JDWP definiert das Format der Informationen und der Anfragen, die zwischen dem Front-End (im Debugger-Prozess) und dem Back-End (im Debuggee-Prozess) ausgetauscht werden. Es definiert jedoch nicht die Art der Übertragung, so dass hierfür z. B. Sockets, Shared Memory oder andere Übertragungsarten verwendet werden können. Java Debug Interface (JDI) Das Java Debug Interface (JDI) bietet eine vollständig in der Programmiersprache Java implementierte Schnittstelle für das Debugging von Java Applikationen. Es wird vom Front-End implementiert und bereitet die Informationen auf, die das JDWP liefert. Diese Java API ( Application Programming Interface ) ermöglicht den komfortablen Zugriff auf einen Debuggee von einer Entwicklungsumgebung aus Java Virtual Machine (JVM) Um zu verstehen, welche Informationen vom Java Debug Interface bereitgestellt werden können, ist ein mindest Verständnis über die Funktionsweise der JVM notwendig. Die Java Virtual Machine Spezifikation [9] beschreibt das Verhalten einer JVM durch Subsysteme, Speicherbereiche, Datentypen und Befehle. Diese Komponenten beschreiben abstrakt den inneren Aufbau der JVM. [10] Abbildung 3 zeigt die wichtigsten Subsysteme und Speicherbereiche, die in der Spezifikation beschrieben werden. 10

17 class files class loader subsystem method area heap Java stacks pc registers native method stacks runtime data areas execution engine native method interface native methods libraries Abbildung 3: Interne Architektur der Java Virtual Machine class loader Das Classloader Subsystem stellt einen Mechanismus zum Finden und Laden von Java Bytecode Dateien bereit. Es wird zwischen drei Typen von Class Loadern unterschieden: Der Bootstrap Class Loader ist Teil der Implementierung der Virtual Machine. Der Bootstrap Class Loader von Suns Java 2 SDK sucht ausschließlich in dem Verzeichnis, in welchem die Java Systemklassen untergebracht sind. Der Wert der Umgebungsvariablen Classpath wird nicht ausgewertet. Kann die Klasse mit dem Bootstrap Class Loader nicht gefunden werden, wird als nächstes geprüft, ob die Klasse in einem optionalen Paket (auch als Standard Extension oder einfach Extension bezeichnet) enthalten ist. Suns Java 2 SDK lädt beim Starten der Virtual Machine automatisch den System Class Loader. Der System Class Loader berücksichtigt den Classpath der Virtual Machine bei der Suche nach Classdateien. Durch einen benutzerdefinierten (user defined) Class Loader können Class- Dateien von unterschiedlichen Orten geladen werden (zum Beispiel: FTP, Http, Dateisystem, etc.). Weiterhin können die Classdateien zum Zeitpunkt des Ladens manipuliert oder gar vollständig neu erstellt werden. 11

18 execution engine Die Execution Engine verarbeitet den Bytecode der geladenen Klassen. runtime data areas Für das Ausführen von Programmen braucht die JVM Speicher. In diesem Speicher werden neben dem Bytecode und weiteren Informationen der Class Dateien auch Objekte, die das Programm instantiiert, Parameter von Methoden, Rückgabewerte, lokale Variablen sowie Zwischenergebnisse von Berechnungen abgelegt. Die JVM organisiert den Speicher in folgende Bereiche: Method Area - Der als method area bezeichnete Speicherbereich wird von allen Threads geteilt und speichert für jede Klasse den Bytecode der Methoden sowie Daten über Variablen und Methoden. Außerdem ist hier der Runtime Constant Pool zu finden, welcher den Konstanten Pool der Class- Dateien zur Laufzeit repräsentiert. Für jede Klasse werden hier Information über Konstanten sowie Referenzen zu Methoden und Variablen verwaltet. Nach dem Laden der Klassen beinhaltet der Runtime Constant Pool symbolische Referenzen zu Variablen und Methoden. Um die Zugriffsgeschwindigkeit zu erhöhen, werden diese später durch direkte Zeiger auf die Methoden und Variablen ersetzt. Heap - Im Heap werden zur Laufzeit erzeugte Elemente abgelegt. Java Stacks - Die Virtual Machine verwaltet für jeden Thread ein eigenes Befehlsregister, sowie einen eigenen Java Stack. Wird innerhalb eines Threads eine Java-Methode ausgeführt, enthält das Befehlsregister die Adresse des nächsten Befehls und der Stack speichert die Umgebung (lokale Variablen, Methoden-Parameter, Rückgabewerte, Zwischenergebnisse bei Berechnungen) der Methode. Wird eine native Methode ausgeführt, werden die Daten auf dem Native Method Stack abgelegt. Der Java Stack ist in einzelne Stack-Frames untergliedert. Ein Stack-Frame speichert die Umgebung des Aufrufs einer Methode. Sobald eine Methode aufgerufen wird, legt die Virtual Machine im Stack des aktuellen Threads ein neues Stack- Frame an. Sobald die Methode beendet ist, wird das dazugehörige Stack- Frame wieder vom Stack entfernt. Ein Stack-Frame enthält Speicherplatz für lokale Variablen, den Operand-Stack sowie weitere Informationen die von der konkreten Implementierung der Virtual Machine benötigt werden. Auf dem Operand-Stack werden vor dem Aufruf einer Methode die Methoden-Argumente sowie die Referenz zur Objektinstanz (falls vorhanden) abgelegt. Nach der Ausführung der Methode befindet sich der Rückgabewert auf dem Operand-Stack. PC-Registers Die Programmzähler speichern die aktuelle Position im Bytecode. Jeder Thread hat einen eigenen Programmzähler. Native Method Stacks - Der native Method Stack stellt Speicherplatz für die Ausführung nativer Methoden bereit. 12

19 Java Methoden Beim Aufruf einer Java Methode wird zunächst verifiziert, ob die Regeln der Java Sprache eingehalten wurden (z. B. ob der referenzierte Bytecode existiert) und ob die Methode aufgrund von Sicherheitsbestimmungen überhaupt aufgerufen werden darf (z. B. ob eine private Methode einer anderen Klasse aufgerufen wird). Java Programme werden symbolisch gebunden. Das bedeutet, dass die von der JVM geladenen Class-Dateien keine direkten Zeiger auf einzelne Methoden enthalten, sondern symbolische Referenzen. Beim ersten Aufruf einer Methode wird anhand des Namens der Klasse und der Methode, sowie deren Signatur (Anzahl und Typ der Argumente) der Zeiger zum Anfang des Bytecodes der Methode ermittelt. Dieser Zeiger ersetzt dann die symbolische Referenz im Runtime Constant Pool. Wird eine Instanz-Methode (eine nicht als static deklarierte Methode) aufgerufen, wird neben der Referenz zum Bytecode auch eine Referenz zu den Daten des Objektes benötigt. Diese Referenz wird vor dem Aufruf der Methode auf dem Operand- Stack der aufrufenden Methode abgelegt. Die Argumente der Methode werden ebenfalls auf dem Operand-Stack abgelegt. Bei jedem Aufruf einer Methode wird von der JVM ein neues Stack-Frame erzeugt. Die Methoden Argumente sowie die Objekt-Referenz (falls vorhanden) werden vom Operand-Stack der aufrufenden Methode genommen und auf dem Operand-Stack der aufgerufenen Methode abgelegt. Nach Verlassen der Methode wird der Rückgabewert auf den Operand-Stack der aufrufenden Methode geschrieben und das Stack-Frame der beendeten Methode entfernt. Beim Aufruf nativer Methoden wird kein neues Stack-Frame auf dem Java Stack abgelegt. Stattdessen wird ein separater Stack (native method stack) verwendet. Die Verarbeitung nativer Methoden ist von der Implementierung der Virtual Machine abhängig. Exceptions Als Exception wird eine Ausnahme bezeichnet, die den normalen Programmablauf unterbricht. Sie kann durch ein ungewöhnliches Ereignis in einem Programm zur Laufzeit verursacht werden. Tritt eine Exception auf, dann sucht die VM nach Code, der auf diese Exception reagiert. Dafür wird in der Exception Table der Methode gesucht, ob eine Behandlung für diese Ausnahme (durch das Schlüsselwort catch im Quellcode markiert) vorhanden ist. Ist dies nicht der Fall, wird die Suche in den folgenden Methoden auf dem Java Stack fortgesetzt. Breakpoints Breakpoints sind Stellen eines Programmes an denen die Ausführung des Programmes angehalten werden soll. Die Spezifikation der JVM sieht für die Realisierung von Breakpoints einen spezielle Opcode vor, der in den Bytecode der Methode eingefügt 13

20 werden kann. [9] Für das Setzen von Breakpoints muss die Debuggee-VM bereits gestartet worden sein. Falls die Breakpoints früher eingegeben werden sollen, müssen sie vom Debugger zwischengespeichert werden. (Dies geschieht in der JDI- Implementierung). Breakpoints können mit den Methoden des Interface Packages com.sun.jdi.request angefordert werden Java Debug Interface (JDI) Das Java Debug Interface (JDI) ist eine reine Java API, die Informationen für Debugger und ähnliche Tools bereitstellt, die auf die JVM zugreifen. Das JDI ermöglicht die Kontrolle einer VM über eine andere VM. Beispielsweise können geladene Klassen und Schnittstellen sowie erzeugte Instanzen und Arrays untersucht werden. Darüber hinaus kann auf den Programmablauf durch Manipulation von Variablen, Aufrufen von Methoden oder durch Anhalten und Starten einzelner oder aller Threads eingewirkt werden. Ablauf Die Verbindung vom Debugger zum Debuggee wird durch sogenannte Connectors hergestellt. Sobald ein Connector eine Verbindung zwischen Debuggee und Debugger aufgebaut hat, stellt der Connector ein VirtualMachine-Objekt bereit. Es spielt es eine zentrale Rolle beim Umgang mit dem JDI. Das VirtualMachine-Objekt spiegelt nämlich den Zustand der Debuggee-VM wieder. Außerdem gehen nahezu alle weiteren Möglichkeiten bzw. Aktionen des JDI von diesem Objekt aus. Pro Verbindung zu einem Debuggee existiert ein VirtualMachine-Objekt. Es implementiert das Java Interface com.sun.jdi.virtualmachine. Dieses Interface ermöglicht unter anderem das Registrieren für Ereignisse, die Abfrage von Ereignissen und die Änderung des Ausführungszustandes. Die Virtual Machine kann angehalten und wieder gestartet werden. Abbildung 4 veranschaulicht den Ablauf eines Debugvorganges. 14

21 Start Debuggee Für Ereignisse registrieren Verbindung mit Debuggee com.sun.jdi.request com.sun.jdi.connect Auf Ereignisse warten Debuggee terminiert Auf Ereignisse reagieren com.sun.jdi.event Abbildung 4: Ablauf einer Debugging Session Ereignisse Im Gegensatz zu Swing oder dem AWT können im JDI keine Listener für Ereignisse registriert werden. Stattdessen werden Ereignisse beim EventRequestManager angefordert. Tritt ein angefordertes Ereignis ein, so wird es in einer Liste, der EventQueue, gespeichert. Bestimmte Ereignisse können die Debuggee-VM gegebenenfalls anhalten. Das Auslesen der Ereignisse entfernt diese zugleich aus der Liste. Da mehrere Ereignisse gleichzeitig auftreten können liefert die Liste stets eine Menge von Ereignissen, ein EventSet. Es können folgende selbsterklärende Ereignisse angefordert werden: AccessWatchpointEvent, BreakpointEvent, ClassPrepareEvent, ClassUnloadEvent, ExceptionEvent, LocatableEvent, MethodEntryEvent, MethodExitEvent, ModificationWatchpointEvent, StepEvent, ThreadDeathEvent, ThreadStartEvent, VMDeathEvent, VMDisconnectEvent, VMStartEvent, WatchpointEvent. [8] Nutzung des JDI Um die volle Funktionalität des JDI nutzen zu können und ein Mapping zwischen der Quellcodedatei und der Bytecodedatei zu ermöglichen, muss das zu untersuchende Programm Debuginformationen enthalten. Dazu muss schon bei der Übersetzung des Programms ein entsprechendes Debug-Flag gesetzt werden. Dadurch fügt der Compiler den Class-Dateien zusätzliche Informationen hinzu. Bei diesen Informationen handelt es sich unter anderem um den Namen der Quellcodedatei, so 15

22 wie einer Zeilennummer Tabelle, die die Positionen im Bytecode der Class-Datei auf die korrespondierenden Zeilen im Quellcode abbildet. Einschränkungen des JDI Das JDI erlaubt weitreichenden Zugriff auf eine Virtual Machine. Aber gerade in Bezug auf den Tracingansatz weist es Einschränkungen auf: Verschiedene Faktoren führen zu einem beachtlichen Overhead, der die Performance reduziert. Die wichtigsten Ursachen dafür sind die hohe Flexibilität und die daraus resultierende Schichtung der JPDA, die Struktur der Ereignisbehandlung und die Tatsache, dass Breakpoints von der JDI Implementierung zwischen gespeichert werden müssen. Werden Breakpoints zum Verfolgen des Programmablaufes verwendet, kann lediglich eine zeilenbasierte Auflösung erreicht werden. Denn Breakpoints können nur zeilenbasiert und nicht anweisungsbasiert gesetzt werden. Damit hat die Formatierung des Quellcodes Einfluss auf die Messung der Testabdeckung. Aufgrund der Natur des JPDA kann die Messung der Testabdeckung nur im Debug Modus ausgeführt werden. 2.3 Vergleich beider Ansätze Basierend auf den oben vorgestellten Grundlagen und Prinzipien der beiden zu untersuchenden Ansätze werden in der folgenden Tabelle 1 die wichtigsten Aspekte beider Verfahren zusammengefasst und gegenübergestellt. Dabei handelt es sich um ein erstes wesentliches Ergebnis dieser Arbeit. 16

23 Instrumentierungsansatz Basiert auf dem Hinzufügen von Instrumentierungsanweisungen in eine Kopie des zu untersuchenden Quellcodes. Es besteht grundsätzlich die Gefahr den Programmablauf oder die Programmlogik durch das Hinzufügen von Instrumentierungs-anweisungen zu verändern. Es besteht grundsätzlich die Gefahr von Namenskonflikten oder der Verletzung der Java Spezifikation, die die Kompilierung unmöglich machen. Es ist eine anweisungsbasierte Messung der Testabdeckung möglich. Overhead wird durch zusätzliche Anweisungen im Quell- und Bytecode generiert. Tracingansatz Basiert auf den Fähigkeiten des Debuggers mittels der JPDA Informationen über das ablaufende Programm zu erhalten. Es besteht keine Gefahr, dass der Programmablauf oder die Programmlogik beim Tracingansatz verändert werden. Es besteht keine Gefahr, dass Namenskonflikte oder eine Verletzung der Java Spezifikation die Kompilierung stört. Es ist nur eine zeilenbasierte Messung der Testabdeckung möglich. Overhead wird durch die Anwendung der JPDA generiert. Tabelle 1: Vergleich der Ansätze Tabelle 1 macht deutlich, dass der Hauptnachteil des Instrumentierungsansatzes in der direkten Manipulation des zu untersuchenden Quellcodes und den damit verbundenen Gefahren liegt. Dies ist damit ein immanentes Problem des Instrumentierungsansatzes. Die für das Instrumentierungsverfahren benötigten größeren Ressourcen für den instrumentierten Quell- und Bytecode können zu einem Problem werden, wenn eine Messung der Testabdeckung direkt auf einem ressourcenbeschränkten Gerät (wie z. B. einem Mobiltelefon) ausgeführt werden soll. Die Zunahme der Programmgröße sollte jedoch bei der Entwicklung und Untersuchung von Java Anwendungen auf einem üblichen PC mit der enormen Kapazität heutiger Massen- und Hauptspeicher kein ernsthaftes Problem darstellen. Der Tracingansatz hat keinen dieser Nachteile. Jedoch können die Einschränkungen die durch die Implementierung des Debuggers und allgemein der JPDA-Architektur beträchtlich sein. Dies gilt nicht nur bei der Umsetzung der Ablaufverfolgung, sondern auch durch den generierten Overhead während der Ablaufverfolgung. 17

24 Der Begriff Overhead wird in dieser Arbeit allgemein verwendet und bedeutet, dass größere Ressourcen an CPU-Zeit und Speicher für die Verarbeitung 7 eines Programmes aufgrund von Zusatzinformationen benötigt werden. Beide Verfahren generieren in diesem Sinne einen Overhead bei der Verarbeitung eines zu untersuchenden Programmes und der Messung der Testabdeckung. Durch diesen Overhead kann ein zu untersuchendes zeitkritisches Programm sich indeterminiert verhalten oder zumindest anders als ohne jegliche Einwirkung durch die beiden Verfahren. Der Overhead kann sich z. B. negativ auf konkurrierende Threads oder auf Timeouts auswirken und auf diese Weise den Programmablauf auf unbestimmte Art verändern. Die Auswirkung des Overheads beider Verfahren auf die Verarbeitung eines zu untersuchenden Programmes ist eine zentrale Frage dieser Arbeit. Diese Frage wird in Abschnitt 4 anhand einer Fallstudie untersucht und beantwortet. 2.4 Testabdeckungsmetriken Testabdeckungsmetriken ermitteln den von Tests ausgeführten Code und liefern Maßzahlen über den erreichten Grad. Diese Funktionalität erweist sich aus verschiedenen Aspekten als relevant. Dem Tester gibt sie die Möglichkeit nicht getesteten Quellcode ausfindig zu machen. Die Maßzahl dient dann als Hilfe zu entscheiden, ob das Testen beendet werden kann, weil der geforderte Grad erreicht worden ist. Gleichzeitig können durch verschiedene Testabdeckungsmetriken Ergebnisse präsentiert werden, die eventuell die Sichtweise auf das Testdesign verändern. Für das Management läßt sich durch Testabdeckungsmetriken schnell eine Zahl ermitteln, die das Verhältnis von getestetem Quellcode zum Gesamtquellcode ausdrückt. [11] Es gibt eine Vielzahl von Testabdeckungsmetriken. Im folgenden werden die drei bekanntesten Metriken vorgestellt. Einen detailierteren Überblick bietet [12]. Für die Erläuterung der drei Metriken wird der Kontrollflussgraph aus Abbildung 5 benutzt. In einem solchen Graphen werden einzelne Anweisungen oder Blöcke von sequenziellen Anweisungen als Knoten, und der Kontrollfluss zwischen Anweisungen oder Blöcken als Kanten dargestellt. Der Kontrollflussgraph ergibt sich aus dem Quellcode 5. Dabei handelt es sich um eine Methode zur Berechnung der Fakultät einer Zahl x. Da Fakultäten nur von natürlichen Zahlen und Null berechnet werden können, wird der übergebene ganzzahlige Wert dahingehend durch die Methode überprüft, und gegebenenfalls der Fehlercode -1 zurückgegeben. [13] 7 Der Begriff Verarbeitung bedeutet: Übersetzung, Speicherung und Ausführung. 18

25 x int factorial(int x) { int result = -1; int result = -1; a then b if if(x >= 0) { result = 1; result = 1; d for for(int i=2; i <= x; i++) { e c g result = result * i; h result = result * i; f endfor } i endif } Abbildung 5: Fakultät-Kontrollflussgraph k return result; } return result; Quellcode 5: Fakultät-Methode Anweisungs- und Methodenüberdeckung Die Anweisungs- und Methodenüberdeckung (engl. statement, method coverage) zur Ermittlung der Testfälle konzentriert sich auf die einzelnen Anweisungen oder Methoden des Testobjekts. Je nach festgelegtem Ziel sind ein gewisser Anteil oder alle Anweisungen bzw. Methoden im Code des Testobjekts abzuarbeiten. Um in dem Fakultät-Kontrollflussgraphen alle Knoten zu durchlaufen, ist nur ein Testfall nötig: Testfall assert(factorial(2)==2); Ablauf a, b, d, e, f, g, h, i, k Tabelle 2: Testfall für vollständige Anweisungsüberdeckung der Fakultät-Methode Dieser Testfall stellt den spezifikationsgemäßen Gebrauch der Methode dar, d.h. es wird eine natürliche Zahl übergeben. Ein Testfall, der in der Methode eine Ausnahmebehandlung verursacht (Rückgabe des Fehlercodes -1), wird dagegen nicht produziert. Dies liegt darin, dass bei der Anweisungsüberdeckung leere Zweige nicht durchlaufen werden. Somit können evtl. fehlende Anweisungen nicht entdeckt werden. Die Anweisungsüberdeckung heißt auch C0-Maß und ist wie folgt definiert: 19

26 Anzahl ausgeführter Anweisungen Anweisungsüberdeckung= Gesamtzahl der Anweisungen Mit obigem Testfall werden sämtliche Anweisungen der Methode factorial ausgeführt, d.h. die Anweisungsüberdeckung beträgt 100%. Für den Test kann zuvor aber auch eine geringere Anweisungsüberdeckung vereinbart worden sein. Es kann allerdings passieren, dass eine geforderte 100%ige Anweisungsüberdeckung auch durch eine große Zahl von Testfällen nie erreicht wird. Als mögliche Ursache kommt hier unerreichbarer Programmcode (engl. dead code) in Frage, d.h. es gibt im Programm Anweisungen, die unter keinen Umständen abgearbeitet werden können. In solchen Fällen ist es sicherlich lohnend, diese Stellen genauer zu untersuchen, um mögliche Defekte als Ursachen aufzufinden. [13] Zweigüberdeckung Die Zweigüberdeckung (engl. branch coverage) zur Ermittlung der Testfälle konzentriert sich auf die einzelnen Zweige des Testobjekts. Zweige stellen hier die Wegabschnitte des Kontrollflusses durch den Code des Testobjekts dar. Wiederum sind je nach festgelegtem Ziel ein gewisser Anteil oder alle Zweige im Code des Testobjekts zu durchlaufen. Um in dem Fakultät-Kontrollflussgraphen alle Kanten oder Zweige zu durchlaufen, sind folgende zwei Testfälle nötig: Testfall assert(factorial(2)==2); assert(factorial(-1)==-1); Ablauf (Kanten) a, b, d, e, f, g, h, i, k a, c, k Tabelle 3: Testfälle für vollständige Zweigüberdeckung der Fakultät-Methode Der erste Testfall entspricht dem, aus dem vorherigen Abschnitt und stellt den spezifikationsgemäßen Gebrauch der Methode dar. Der zweite Testfall überprüft die Methode factorial auf die Behandlung einer Ausnahmesituationen. Es wird eine negative Zahl übergeben, so dass der leere else-zweig durchlaufen und der Fehlercode -1 zurückgegeben wird. Die Zweigüberdeckung liefert also Testfälle, mit denen fehlende Anweisungen in leeren Zweigen entdeckt werden können. Die Zweigüberdeckung heißt auch C1-Maß und ist wie folgt definiert: Anzahl ausgeführte Zweige Zweigüberdeckung= Gesamtzahl der Zweige Mit obigen Testfällen werden sämtliche Zweige der Methode factorial ausgeführt, d.h. die Zweigüberdeckung beträgt 100%. Für den Test kann zuvor aber auch eine geringere Zweigüberdeckung als ausreichend vereinbart worden sein. Prinzipiell gilt, dass wenn nach der Zweigüberdeckungsmethode verfahren wird, mehr Testfälle als bei der Anweisungsüberdeckung erstellt werden. Dies liegt darin, dass die 20

27 Zweigüberdeckung auch leere Zweige berücksichtigt, und somit fehlende Anweisungen entdecken kann. [13] Pfadüberdeckung Die Pfadüberdeckung (engl. path coverage) konzentriert sich auf die einzelnen Pfade des Testobjekts. Pfade stellen dabei die Gesamtwege des Kontrollflusses durch den Code des Testobjekts dar. Je nach festgelegtem Ziel sind wie bei den beiden Metriken zuvor ein gewisser Anteil oder alle Pfade im Code des Testobjekts zu durchlaufen. Da reale Programme aber oft eine sehr große Anzahl von möglichen Pfaden aufweisen, ist ein Durchlauf sämtlicher Pfade durch Tests in der Praxis kaum relevant. Ein möglicher Pfad durch den Fakultät-Kontrollflussgraphen wird z. B. durch die Kantenabfolge a, c, k beschrieben (Ausnahmebehandlung der Methode factorial bei negativen x-werten). Weitere Pfade wären z. B. a, b, d, h, i, k (Schleife wird nicht durchlaufen, d.h. x ist 0 oder 1) oder a, b, d, e, f, i, k (Schleife wird einmal durchlaufen, d.h. x ist 2). Falls die Schleife mehrmals durchlaufen werden soll, so muß ein Rücksprung zum Schleifenanfang über die Kante g erfolgen. Der zugehörige Pfad für x gleich 3 ist a, b, d, e, f, g, e, f, i, k. Darüberhinaus existieren aber noch weitere Pfade, wie z. B. a, b, d, e, f, g, e, f, g, e, f, i, k. Die Anzahl der Schleifendurchgänge kann durch Vergrößern von x solange erhöht werden, bis die maximal darstellbare Zahl für result auf dem Rechner erreicht ist. Daraus wird deutlich, dass bei der Pfadüberdeckung extrem viele Testfälle gebildet werden können. Es stellt sich somit die Frage, welche dieser Testfälle sinnvollerweise ausgewählt werden sollen. Das C2-Abdeckungsmaß schreibt dazu vor, dass Testfälle generiert werden müssen, die 1. enthaltene Schleifen nicht durchlaufen, 2. enthaltene Schleifen nicht oft durchlaufen, 3. enthaltene Schleifen oft durchlaufen, wobei alle drei Bedingungen durch die Menge der Testfälle abgedeckt werden müssen. Für die Methode factorial entspricht das den folgenden Testfällen: Testfall assert(factorial(-1)==-1); assert(factorial(0)==1); assert(factorial(2)==2); assert(factorial(7)==7); Ablauf (Kanten) a, c, k a, b, d, h, i, k a, b, d, e, f, g, h, i, k a, b, d, [e, f, g] 5038, e, f, i, k Tabelle 4: Testfälle für gute Zweigüberdeckung der Fakultät-Methode Der Wert für häufige Schleifendurchläufe wurde hier auf 5038 festgelegt. Die Entscheidung, wie oft eine Schleife im Test durchlaufen werden soll, hängt jedoch stark 21

28 vom Testobjekt, der zu Verfügung stehenden Hardware und dem zu erwartenden Kosten-Nutzen-Verhältnis ab. [13] 2.5 Verwandte Arbeiten Der Kern der vorliegenden Masterarbeit ist die Untersuchung und Entwicklung zweier Verfahren zur Messung von Testabdeckungen. Die Fachliteratur liefert verschiedene weitere Arbeiten mit interessanten Ansätzen und Implementierungen, die für die Messung von Testabdeckungen geeignet sein könnten. Die Beurteilung dieser Arbeiten ist schwierig, denn sie verfolgen jeweils unterschiedliche Ziele oder basieren auf unterschiedlichen Grundvoraussetzungen: Einige Arbeiten konzentrieren sich z. B. vor allem auf die Skalierbarkeit und die Performance, andere setzen ihren Schwerpunkt auf die Flexibilität ihrer Werkzeuge. Desweiteren ist häufig unklar welche Metriken sich mit den Werkzeugen umsetzen lassen. Teilweise erlauben diese Werkzeuge nur die Messung von ausgeführten Methoden, nicht jedoch von Anweisungen. In wie weit also die im folgenden vorgestellten Arbeiten tatsächlich die Messung von Testabdeckungen ermöglichen, kann hier nicht vollständig geklärt werden. Anil Chawla und Allessandro Orso beschreiben in [14] ein Framework mit dessen Hilfe sowohl eine statische als auch eine dynamische Instrumentierung des Bytecodes (d.h. der Class-Dateien) eines Java Programmes möglich ist. Im statischen Modus werden zusätzliche Anweisungen in den vom Compiler generierten Bytecode vor dessen Ausführung durch eine Java Virtual Machine hinzufügt. Im dynamischen Modus wird der Bytecode zur Laufzeit instrumentiert, indem ein spezieller Classloader verwendet wird. Dies hat den Vorteil, dass nur Klassen instrumentiert werden, die tatsächlich ausgeführt werden. Denn in der Regel ist die Menge der von einem Programm zur Laufzeit gebrauchten Klassen deutlich kleiner als die Menge aller statisch vorhandenen Klassen. Desweiteren bietet dieses Framework für sogenannte instrumentierbare Entities zusätzliche dynamische Informationen an, die in eine Auswertung mit einbezogen werden können. Z. B. können für das Entity Method Entry die Argumente der Methode erfragt werden. Die Implementierung dieses Frameworks heißt InsECT (Instrumentation Execution Coverage Tool) und ist frei verfügbar [15]. Die aktuelle Versionsnummer 0.91 deutet jedoch auf eine noch nicht vollständige Implementierung hin. Zudem erfordert die hohe Flexibilität und Konfigurierbarkeit dieses Frameworks einen entsprechend hohen Aufwand in die Einarbeitung und der Verwendung dieses Frameworks. Einen vergleichbaren Weg geht auch Mikhail Dmitriev in [16]. Um eine dynamische Instrumentierung des Bytecodes zu ermöglichen, modifiziert Dmitriev die Java Virtual Machine um eine besonders effiziente HotSwap Funktion. Der Anwender kann über eine graphische Benutzeroberfläche (GUI) verschiedene Konfigurationen vor 22

29 nehmen und z. B. die zu untersuchenden Methoden auswählen. Das System aus der modifizierten Java Virtual Machine und der GUI heißt JFluid. JFluid (als Milestone 7) steht als Erweiterung für die von Sun Microsystems geförderte Entwicklungsumgebung NetBeans frei zur Verfügung. [17] Das Java Instrumentation API (JIAPI) Framework ermöglicht ebenfalls die statische und die dynamische Manipulation des Bytecodes, bevor dieser von der Java Virtual Machine geladen und ausgeführt wird. [18] Die Instrumentierung wird in JIAPI durch eine Kette von verschiedenen Instrumentierern ausgeführt. Dabei verändert jeder Instrumentierer die Liste der Anweisungen einer Methode und reicht diese Liste weiter an den nächsten Instrumentierer in der Kette. Auf diese Weise ermöglicht JIA PI weitreichende Veränderung des Bytecodes. Für das Sammeln von Daten über den Programmablauf des instrumentierten Bytecodes können Listener registriert werden, die über bestimmte Ereignisse benachrichtigt werden. Die aktuelle Versionsnummer deutet allerdings darauf hin, dass das Framework noch nicht ganz ausgereift ist. Die Arbeit [19] von Don Lance erläutert auf verständliche Art und Weise das Prinzip der Analyse und der direkten Manipulation von Java Bytecode. Die Java Instrumentation Engine (JIE) ist ein Framework, welches auf der Instrumentierung des Quellcodes basiert. [20] Deshalb ist die JIE besonders mit dem in dieser Arbeit vorgestellten Instrumentierungsansatz vergleichbar. Besonders interessant ist zudem das auf der JIE zugehörigen Internetseite ([20]) veröffentlichte Designdokument. Es gibt Auskunft über die verschiedenen Entwurfsentscheidungen und Schwierigkeiten des Frameworks. Beim JIE-Framework wird die Instrumentierung über eine XML Konfigurationsdatei spezifiziert. Diese Konfiguration legt die zu instrumentierenden Stellen im Quellcode fest und bestimmt welche Aktionen an jeder dieser Stellen ausgeführt werden. Für die Generierung eines Abstract Syntax Tree (AST) des Quellcodes nutzt das JIE Framework den von Kevin Tao entwickelten Java Tree Builder (JTB). [21] Nur mit Hilfe eines AST ist die präzise und sichere Instrumentierung von Quellcode möglich. Deshalb hat Eran Tromer, der Entwickler der JIE, in seinem Design Dokument verschiedene weitere Werkzeuge zur Generierung eines AST vorgestellt und miteinander verglichen. Das JIE Framework wird jedoch seit 1999 nicht mehr weiterentwickelt. Das von Bruce Childers et al. entwickelte Framework SoftTest basiert auf einem Ansatz [22], der dem in dieser Masterarbeit vorgestellten Tracingansatz ähnelt. Das Framework verwendet Breakpoints um Informationen über den Programmablauf zu erhalten. Bei den verwendeten Breakpoints handelt es sich um sogenannte fast Breakpoints, die dynamisch und besonders schnell hinzugefügt und wieder entfernt werden können, und so den Overhead minimieren. SoftTest ermöglicht die Spezifikation von Tests und führt dazu eine eigene Test-Spezifikationssprache ein. Für die Erstellung einer solchen Spezifikation wird eine graphische Benutzeroberfläche bereitgestellt. Die Testspezifikation wird auf einer Test Virtual Machine (TVM) ausgeführt, die zur Laufzeit die Instrumentierung des zu untersuchenden Programmes 23

30 vornimmt. Diese TVM ist als integrierter Bestandteil der IBM Jikes Java Research Virtual Machine implementiert worden. Als konkretes Proof of Concept für das Soft Test Framework hat das Team um Bruce Childers ein Werkzeug zur Messung der Pfadabdeckung implementiert. Ähnlich wie das oben vorgestellte InsECT Framework bietet das SoftTest Framework eine große Flexibilität und Konfigurierbarkeit, auf Kosten der Einarbeitungszeit und Verwendbarkeit dieses Frameworks. Es existieren noch viele weitere Lösungsansätze für das Instrumentierungsproblem, die nicht alle vorgestellt werden können. Zuletzt wird nun die Arbeit Efficient Use of Code Coverage in Large-Scale Software Development von Young Woo Kim vorgestellt. [23] Kim untersucht verschiedene Metriken und Verfahren, um den Aufwand (Overhead) bei der Analyse von Testabdeckungen zu minimieren und gleichzeitig die Wahrscheinlichkeit Fehler aufzudecken zu maximieren. Denn er hat festgestellt, dass der Aufwand zur detailierten Untersuchung (auf Anweisungsbasis) insbesondere für sehr umfangreiche Software Projekte zu groß ist. Seine Liste an Vorschlägen für die Analyse umfangreicher Projekte ist lang und basiert auf verschiedenen Feststellungen. So ist z. B. eine Pareto Verteilung zwischen den Fehlern in einem Programm und seiner Größe bzw. Komplexität 8 zu beobachten. Das bedeutet, dass ca. 80% aller Fehler von nur ca. 20% des Programmes ausgehen, während sich die restlichen 20 % der Fehler auf die restlichen 80% des Programmes verteilen. Desweiteren hat Kim bei der Suche nach Fehlern in Programmen eine positive Beziehung (Korrelation) zwischen der Messung der Methodenabdeckung und der Messung der Anweisungsabdeckung ermittelt, als auch eine positive Korrelation zwischen der Blockabdeckung 9 und der Pfadabdeckung. Deshalb schlägt Kim vor bei der Analyse besonders umfangreicher Software zunächst allgemein für das ganze Programm die Methodenabdeckung zu messen und detailiertere Messungen selektiv nur in Modulen auszuführen, in denen Fehler gefunden wurden, oder die ganz neu entwickelt wurden. Desweiteren reicht es auf Grund der positiven Korrelation zwischen der Block- und der Pfadabdeckung nur eine von beiden Metriken für die Untersuchung heranzuziehen. 8 Kim hat festgestellt, dass die Programmgröße (in lines of code) mit der Komplexität des Programmes korreliert. [23](Seite 3) 9 Block coverage: Ensures that all basic blocks are executed. A basic block is a sequence of instruction that is free of branches and function calls. [23](Seite 3f) 24

31 3 Implementierung Die Implementierung des Instrumentierungs- und Tracingverfahrens beschränkt sich auf deren Umsetzung als Eclipse-Plugin. Dieser spezielle Kontext vereinfacht in weiten Teilen die Implementierung der beiden Verfahren, weil auf verschiedene Mechanismen und Funktionen der Eclipse Platform zurückgegriffen werden kann, ohne diese selbst implementieren zu müssen. Jedoch erfordert dieser Kontext zunächst den Erwerb von Grundkenntnissen über die Eclipse Platform und schließlich die Einarbeitung in das Eclipse Framework selbst. Deshalb soll der nächste Abschnitt einen Überblick über die Eclipse Platform geben und die wichtigsten Komponenten für die Umsetzung der beiden Verfahren einführen. Danach wird die Architektur des entwickelten Werkzeugs vorgestellt und anschließend werden alle Komponenten der Architektur erläutert. 3.1 Eclipse Die Eclipse Platform ist eine universelle Platform für nahezu beliebige Werkzeuge. Meist jedoch wird Eclipse als eine freie Entwicklungsumgebung verwendet. Bis einschließlich zur Version 2.1 war Eclipse als erweiterbare IDE konzipiert. Seit der Version 3.0 ist Eclipse selbst nur der Kern, der die einzelnen Erweiterungen, sogenannte Plugins lädt. Diese Plugins stellen dann die eigentliche Funktionalität zur Verfügung. Der Kern von Eclipse nennt sich Rich Client Platform (RCP) und basiert auf dem OSGI-Standard [1], [24]. Die mit Eclipse 3.0 eingeführte Rich Client Platform stellt ein generisches Framework für eine weite Klasse von Eclipse-Anwendungen bereit. Die Eclipse Platform steht für verschiedene Betriebssysteme zur Verfügung, wie z. B. Windows, Linux, Solaris und Mac OS. Sowohl Eclipse als auch die Plugins sind vollständig in Java implementiert. Jedoch gibt es Plugins, die die Verwendung von Eclipse als IDE für verschiedene andere Programmiersprachen wie z. B. Perl, C/C++ und Cobol ermöglichen. Die Eclipse Java IDE Funktionalität ist damit nur ein herausragendes Beispiel für ein Eclipse Plugin. Für Entwickler stellt Eclipse (SDK) ein umfangreiches Framework für Java Plugins zur Verfügung. Die Eclipse-SDK-Distribution unterstützt die Entwicklung von Plugins, die die Umsetzung von IDEs für weitere Programmiersprachen erleichtern, indem zusätzliche generelle APIs bereitgestellt werden. So stehen mit den graphischen SWT- und JFace-Bibliotheken Alternativen zu Suns AWT- und Swing-Bibliotheken bereit. Die SWT- und JFace-Bibliotheken gestatten es, graphische Oberflächen zu erstellen, die in Bezug auf Ansprechverhalten und Look&Feel mit dem Verhalten nativer (also in C/C++ entwickelter, dem Betriebssystem eigener) graphischer Oberflä 25

32 chen nahezu identisch sind. 10 Über die GUI-Bibliotheken hinaus stehen höhere Klassen und Konzepte wie Editoren, Viewer, Ressourcenverwaltung, Aufgabenverwaltung, Problembehandlung, Debugmodel, Hilfesystem, verschiedene Assistenten und Wizards zum Einbau in eigene Plugins bereit. Alle diese Klassen und Konzepte werden von Eclipse selbst z. B. bei der Implementierung der Workbench oder bei der Java-IDE verwendet. Eclipse stellt den Nachfolger für IBMs Visual Age dar. Die Entwicklungskosten sollen mehr als 40 Millionen Dollar betragen haben. Der Quellcode für Eclipse wurde dann von IBM freigegeben. Die Verwaltung und Entwicklung von Eclipse wurde von der Eclipse-Foundation, einer Non-Profit Organisation übernommen, in der IBM allerdings eine einflussreiche Position einnimmt. Der gesamte Quellcode von Eclipse steht offen zur Verfügung, kann jederzeit eingesehen werden, sowie als Ausgangspunkt für eigene Entwicklungen dienen. Das Lizenzierungsmodell von Eclipse erlaubt es Anwendern, die Klassen des Eclipse Frameworks in eigene Anwendungen einzubetten, zu verändern und als Bestandteil der eigenen Anwendungen mit auszuliefern, ohne dass Lizenzgebühren fällig werden. [25] Die folgende Abbildung 6 veranschaulicht die wesentliche Java-IDE Architektur von Eclipse. Die oval eingekreisten Elemente sind dabei von besonderer Wichtigkeit für die Umsetzung des Plugins zur Messung der Testabdeckung. Die folgenden Abschnitte werden die verschiedenen Bestandteile der Abbildung 6 erläutern. Die Abschnitte 3.1.1, und basieren auf [27]. UI Workbench JFace SWT Java Java Development Tools AST (Abstract Syntax Tree) Debug Core Workspace Marker, Nature & Builder Runtime Plugin Infrastructure Abbildung 6: Eclipse Java-IDE Architektur, vgl. [26] S Die SWT Bibliothek erreicht dies durch den maximalen Gebrauch betriebssystemeigener API und Ressourcen. 26

33 3.1.1 Runtime und Plugin Architektur Ein Plugin ist die kleinste funktionale Einheit der Eclipse Platform, die separat entwickelt und ausgeliefert werden kann. Während einfache Eclipse Anwendungen häufig nur aus einem einzigen Plugin bestehen, ist die Funktionalität komplexerer Eclipse Anwendungen meistens auf mehrere Plugins verteilt. Bis auf einen kleinen Kern, der sogenannten Platform Runtime, ist die gesamte Eclipse Funktionalität in den Plugins untergebracht. Jedes Plugin verfügt über eine sogenannte Manifest-Datei. Dabei handelt es sich um eine Beschreibung des Plugins und seiner Beziehungen zu anderen Plugins in Form einer XML-Datei. 11 Die Beziehung zu anderen Plugins ist einfach: ein Plugin deklariert beliebig vieler sogenannter Erweiterungspunkte (engl.: extension points) und Erweiterungen (engl.: extensions) zu einem oder mehreren Erweiterungspunkten anderer Plugins. Ein Erweiterungspunkt darf von anderen Plugins also erweitert werden. Zum Beispiel deklariert das Workbench-Plugin einen Erweiterungspunkt für Einstellungen. Jedes Plugin kann durch Erweiterung dieses Erweiterungspunktes seine eigenen Einstellungen hinzufügen. Ein Erweiterungspunkt kann zudem eine entsprechende Java API (Application Programming Interface) bereitstellen. Andere Plugins können Implementierungen dieser Schnittstelle durch Erweiterung des zugehörigen Erweiterungspunktes liefern. Jedes Plugin darf neue Erweiterungspunkte definieren und neu API für andere Plugins bereitstellen. Zur Identifikation besitzt jeder Erweiterungspunkt einen global eindeutigen Namen. Die Manifest-Datei ist die einzige absolut notwendige Komponente eines Plugins, alle anderen Komponenten wie Java Bytecode, fremde und/oder native Bibliotheken und andere Ressourcen wie Bilder oder Texte sind optional. Ein Plugin, das z. B. eine Online-Hilfe in Form von HTML Seiten anbietet, könnte ganz ohne Java Code auskommen. Alle Komponenten eines Plugins befinden sich zusammen in einem eigenen Plugin-Unterverzeichnis der Eclipse Installation. Nach dem Start überprüft das Platform-Runtime-Modul anhand der Manifest-Dateien, welche Plugins vorhanden sind und registriert diese. Die eindeutige Bezeichnung der Erweiterungspunkte wird für die Identifizierung der zugehörigen Erweiterungen verwendet. Auf diese Weise können Probleme, wie z. B. Erweiterungen zu fehlenden Erweiterungspunkten entdeckt und aufgezeichnet werden. Die Registry der Plugins ist durch die Platform API zur Laufzeit zugänglich. Allerdings können keine neuen Plugins zur Laufzeit der Registry hinzugefügt werden. Manifest-Dateien werden in XML definiert. Ein Erweiterungspunkt kann neue, spezielle XML-Elemente deklarieren. Dadurch können Plugins, die diesen Erweiterungspunkt nutzen, Informationen an das Plugin geben, welches den Erweiterungspunkt 11 Seit Eclipse 3.0 übernimmt das neue OSGi Bundle Manifest (MANIFEST.MF) einige Funktionen des alten XML-Manifests (plugin.xml). Bei vielen aktuellen Plugins koexistieren beide Manifest- Dateien nebeneinander. 27

34 bereitstellt. Desweiteren sind die Manifest-Informationen der Registry zugänglich, ohne das zugehörige Plugin aktivieren und seinen Code laden zu müssen. Diese Eigenschaft ist der Schlüssel, um eine Vielzahl installierter Plugins zu unterstützen, während nur ein kleiner Teil davon für einen Arbeitsvorgang tatsächlich gebraucht wird. Durch die Verwendung der Manifest-Datei kann der optionale Bytecode eines Plugins erst dann in den Speicher geladen, wenn irgendwelche seiner Funktionen zum ersten Mal angesprochen werden. 12 Solange der Code eines Plugins nicht geladen wurde, hat es einen unbedeutenden Speicherplatzverbrauch und einen vernachlässigbaren Einfluß auf die Startzeit von Eclipse. Wird ein Plugin aktiviert, kann es in der Registry nach Erweiterungen für seine Erweiterungspunkte suchen, die Informationen der Registry über diese Erweiterungen nutzen und die Erweiterungen bei bedarf ebenfalls aktivieren und benutzen. Zum Beispiel kann das Workbench-Plugin mit dem Erweiterungspunkt für die Einstellungen, die bereitgestellten Namen aller zugehöriger Erweiterungen nutzen, um diese in einer Liste anzuzeigen. Hierfür reichen allein die Informationen der Registry aus, ohne dass die entsprechenden Plugins aktiviert werden müssen. Diese Plugins werden erst aktiviert, wenn ein Anwender eine Einstellung (also ihren Namen) aus der Liste auswählt. Für eine solche explizite Aktivierung stehen besondere API-Methoden bereit. Ein einmal aktiviertes Plugin bleibt solange aktiv bis die Platform beendet wird. Jedes Plugin besitzt ein spezielles Verzeichnis, wo es seine (Zustands-)Daten ablegen kann, um sie bei einem Neustart zu nutzen. Die Eclipse Platform benötigt eine Java Virtual Machine, um ausgeführt werden zu können. Jedes Plugin bekommt seinen eigenen Java Classloader zugewiesen, der ausschließlich für das Laden der Klassen (und Java Resource Bundles ) des jeweiligen Plugins verantwortlich ist. Jedes Plugin deklariert explizit welche Klassen anderer Plugins es direkt benötigt. Desweiteren kontrolliert ein Plugin die Sichtbarkeit und damit den Zugriff auf seine öffentlichen (public) Klassen und Schnittstellen. Diese Information wird in der Manifest-Datei deklariert. Die Einhaltung der Sichtbarkeitsbzw. Zugriffsregeln wird zur Laufzeit durch die Plugin-Classloader überwacht und durchgesetzt. Der Plugin-Mechanismus partitioniert sogar die Eclipse Platform. Selbst die Runtime Komponente besitzt ihr eigenes Plugin. Nicht graphische Eclipse Anwendungen können einfach das Workbench-Plugin und alle darauf basierenden Plugins weglassen. Die Runtime Komponente deklariert einen speziellen Erweiterungspunkt für Anwendungen. Wenn die Platform gestartet wird, wird der Name der zu startenden Anwendung über die Kommandozeile spezifiziert. Nur das von der Anwendung deklarierte Plugin wird zu Beginn aktiviert. 12 Dies wird in der Literatur Lazily-Instantiation oder Lazily-Loading genannt und wird über die Java Reflection-API realisiert. Vgl. [26]. 28

35 Die Eclipse Platform besitzt einen Update-Manager, der neue Plugins (als Feature) herunterladen, installieren, wieder deinstallieren und bestehende Plugins aktualisieren kann. Eine sehr ausführliche Beschreibung über die Plugin-Architektur findet sich in [28] Workspace Die vielfältigen Eclipse-Anwendungen operieren auf normalen Dateien, die sich im sogenannten Workspace des Anwenders befinden. Der Workspace kann mehrere Projekte gleichzeitig beinhalten. Alle Dateien des Workspace sind hierarchisch in Projekten organisiert, die mit Verzeichnissen im Dateisystem assoziiert sind. Die Platform stellt für integrierte Eclipse-Anwendungen eine API bereit, um mit Workspace- Ressourcen (das ist die allgemeine Bezeichnung für Projekte, Verzeichnisse und Dateien) zu arbeiten. Jedoch sind alle Dateien im Workspace auch von Außen, also durch externe Anwendungen, zugänglich und können bearbeitet werden. Die Workspace API stellt einen generellen Mechanismus zum Verfolgen von Ressourcen-Änderungen bereit. Durch die Registrierung eines Ressource-Change- Listeners können Plugins sich über die Erstellung neuer Ressourcen, ihre Löschung und über Änderungen ihres Inhaltes benachrichtigen lassen. Bei den Benachrichtigungen handelt es sich um sogenannte after-the-fact Benachrichtigungen, die also nach dem Ereignis verschickt werden. Die Platform schiebt die Benachrichtigung jeweils bis zum Schluß einer Reihe von Ressourcen-Manipulationen auf. Die Benachrichtigungen haben die Form eines Delta-Baumes (resource tree delta), der die Reihe von Ressourcen-Manipulationen in der Terminologie von Erstellung, Löschung und Änderung genau beschreibt. Die Verwendung einer Baumstruktur für die Benachrichtigung über Ressourcen-Manipulationen ist nützlich und effizient für Werkzeuge, die Ressourcen als Baum graphisch darstellen, denn jedes Ressource-Delta des Benachrichtigungsbaumes zeigt welche graphischen Elemente hinzugefügt, entfernt oder aktualisiert werden müssen. Desweiteren können Plugins sich durch diesen Mechanismus präzise über Veränderungen bestimmter Ressourcen informieren, die zur gleichen Zeit von einem anderen Plugin manipuliert werden. Plugins können am sogenannten Save-Restore-Prozess partizipieren, um mit dem Workspace über mehrere Sitzungen koordiniert zu bleiben. Dieser zwei Phasen Prozess gewährleistet in der ersten Phase die Speicherung des Zustandes aller beteiligter Plugins bei ihrer Beendigung. In der zweiten Phase, wenn ein Plugin reaktiviert wird, erhält es ein Workspace-Weiten Ressource-Delta, der alle Unterschiede der Ressourcen seit seiner letzten Speicherung beinhaltet. Auf diese Weise ist ein Plugin bei seiner Aktivierung in der Lage seinen gespeicherten Zustand entsprechend der ausgeführten Ressourcen-Änderungen während seiner gesamten Deaktivierung anzupassen. 29

36 Marker Die Workspace-API stellt einen Marker-Mechanismus bereit, mit dem sich einzelnen Ressourcen Markierungen hinzufügen lassen. Von besonderer Wichtigkeit ist, dass Marker beliebige zusätzliche Informationen in Form von benannten Attributen aufnehmen können. Auf diese Weise lassen sich bestimmte Meta-Informationen über einen Marker mit einer Ressource assoziieren. Marker werden für verschiedenste Zwecke verwendet, wie z. B. Compiler-Fehler, To-Do-Listen, Lesezeichen (Bookmarks), Suchergebnisse und Debug-Breakpoints. Plugins können neue Marker-Subtypen in der Manifest-Datei deklarieren und kontrollieren, ob sie persistent gespeichert werden. Nature Der Nature-Mechanismus erlaubt es einem Projekt eine Charakteristik in Form einer Natur zuzuweisen. Z.B. kennzeichnet die Web-Site-Nature ein Projekt, das Web-Seiten beinhaltet, während die Java-Nature ein Projekt kennzeichnet, das Java Quellcode beinhaltet. Der wichtigste Zweck einer Natur ist es eine Verknüpfung zwischen einem Plugin, bzw. Werkzeug und einem Projekt herzustellen. Hierfür können neue Naturen deklariert werden. Über die zur Natur zugehörige API lassen sich entsprechende Konfigurationen an Projekten mit dieser Natur vornehmen. Genauer: Wenn eine Natur einem Projekt hinzugefügt wird, dann wird die configure-methode dieser Natur aufgerufen. Dies gibt dem Plugin die Gelegenheit bestimmte Initialisierungen an dem Projekt vorzunehmen, wie z. B. einen passenden Builder, Listener oder sonstige Meta-Daten für das Projekt zu initialisieren. Entsprechend wird die deconfigure-methode einer Natur aufgerufen, wenn diese Natur von einem Projekt entfernt wird. Das Plugin kann dadurch die installierten Builder und Listener wieder entfernen und die Meta-Daten löschen. Ein Projekt kann durchaus mehrere verschiedene Naturen zugleich besitzen. Dadurch können mehrere Plugins mit unterschiedlichen Werkzeugen am selben Projekt arbeiten, ohne sich kennen zu müssen. Zudem läßt sich über bestimmte Bedingungen kontrollieren ob eine Natur einem Projekt hinzugefügt werden kann: Bei einer one-of-bedingung wird eine Natur nur dann hinzugefügt, falls keine andere Natur aus einer vorgegebenen Menge aktiviert ist. Dies ist nützlich bei in Konflikt zu einander stehenden Naturen. Bei einer requires-bedingung wird eine Natur nur dann hinzugefügt, falls eine andere vorgegebene Natur bereits aktiviert ist. Dies ist bei Naturen nützlich, die auf das mit der vorgegebenen Natur verbundene Verhalten angewiesen sind. Die Eclipse Platform stellt sicher, dass diese Bedingungen eingehalten werden. Dies gilt für das Hinzufügen und das Entfernen von einzelnen Naturen aus einem Projekt, aber auch wenn mehrere Naturen einem Projekt gleichzeitig hinzugefügt oder ent 30

37 fernt werden. Die Plattform führt diesen Vorgang dann seriell in einer Reihenfolge aus, die diese Bedingungen einhält. Builder Compiler oder ähnliche Werkzeuge müssen in der Lage sein eine große Menge von Dateien zu analysieren, zu transformieren und den Ablauf dieser Aufgaben zu koordinieren. Die Eclipse Platform stellt dafür einen inkrementellen Projekt-Builder zur Verfügung. Als Eingabe erhält ein inkrementeller Projekt-Builder einen Delta-Baum, der die Unterschiede seit dem letzten Ablauf des Builders kapselt. Hoch entwickelte Werkzeuge können dadurch sehr aufwendige Aufgaben auf eine sehr skalierbare Art und Weise ausführen. Denn nach der ersten Ausführung des Builders muss dieser nur noch die Änderungen verarbeiten, die seit seiner letzten Ausführung vorgenommen wurden. Für eine Projekt können mehrere Builder gleichzeitig registriert sein. Die Reihenfolge mehrerer Builder wird in der Regel durch die requires-beziehung von Naturen bestimmt. Sie kann aber auch manuell über die API oder die GUI vom Anwender festgelegt werden. 13 Eine sehr ausführliche Beschreibung über Projekt-Builder und Naturen findet sich in [29] User Interface Die Benutzeroberfläche (User Interface, kurz UI) der Eclipse Plattform beruht auf einer dreiteiligen Architektur: Als Basis dient das Standard Widget Toolkit (SWT). Das SWT ist ein Satz von graphischen Komponenten (Widgets) und Graphikbibliotheken. Es nutzt soweit wie möglich das native fensterbasierte Betriebssystem, ist aber mit einer betriebssystemunabhängigen API ausgestattet. JFace erleichtert herkömmliche Aufgaben bei der Programmierung graphischer Oberflächen mit SWT. Die Workbench nutzt sowohl SWT, als auch JFace und bildet eine übergreifende Struktur, die dem Anwender der Eclipse Platform eine erweiterbare graphische Oberfläche zur Verfügung stellt. 13 Die Reihenfolge der Builder manuell zu verändern wird weder über die API noch über die GUI empfohlen. Vgl. [29]. 31

38 Standard Widget Toolkit (SWT) Das Standard Widget Toolkit stellt eine allgemeine und betriebssystemunabhängige 14 API zur Verfügung. Die Art der Implementierung ermöglicht eine eng gekoppelte Integration mit dem zugrundeliegenden nativen fensterbasierten Betriebssystem. Die gesamte Oberfläche der Eclipse Plattform und der eingebundenen Plugins benutzen SWT, um dem Benutzer Informationen darzustellen. Die immerwährende Herausforderung bei dem Design eines graphischen Werkzeugsatzes ist die Gegensätzlichkeit zwischen portierbaren Werkzeugsätzen und der Integration des nativen fensterbasierten Betriebssystems. Das Java AWT (Abstract Window Toolkit) stellt graphische Komponenten auf niedrigem Niveau zur Verfügung, wie z. B. Listen, Textfelder und Buttons. AWT Komponenten basieren direkt auf den graphischen Komponenten der unterstützten fensterbasierten Betriebssysteme. Eine Benutzeroberfläche nur mit AWT zu erstellen, bedeutet auf dem kleinsten gemeinsamen Nenner aller fensterbasierten Betriebssysteme zu programmieren. Der Java Swing Werkzeugsatz begegnet diesem Problem, indem es komplexe graphische Komponenten wie Baumstrukturen, Tabellen und Rich-Text-Darstellungen, aber auch einfache Komponenten emuliert. Swing stellt außerdem emulierte Look&Feels zur Verfügung, die versuchen Anwendungen so aussehen zu lassen wie das darunter liegende fensterbasierte Betriebssystem. Trotz allem hinken die emulierten Komponenten durch ihre Invarianz dem Look&Feel der nativen Komponenten hinterher und die Interaktion mit emulierten Komponenten ist im allgemeinen merkbar anders. Diese Tatsachen machen es schwierig Anwendungen zu entwickeln, die sich mit speziell für ein ganz bestimmtes Betriebssystem entwickelten Anwendungen messen können. SWT begegnet dieser Herausforderung indem es eine allgemeine API definiert, die für eine Anzahl unterschiedlicher fensterbasierter Betriebssysteme verfügbar ist. Für jedes dieser unterschiedlichen Betriebssysteme benutzt die SWT Implementierung soweit wie möglich native Komponenten des Betriebssystems. Dort wo dies nicht möglich ist, liefert die SWT Implementierung eine geeignete Emulation. Einfache Komponenten, wie Listen, Textfelder und Buttons sind durchgehend nativ implementiert. Aber einige im allgemeinen sehr nützliche Komponenten höheren Niveaus müssen nach wie vor auf einigen Systemen emuliert werden. Zum Beispiel ist die 14 Die Definition der Betriebssystemunabhängigkeit ist stets relativ. Normale Java-Programme sind in soweit besonders betriebssystemunabhängig, weil sie auf jedem Betriebssystem ausgeführt werden können, für das eine Java Virtual Machine existiert. Und in der Tat existiert für eine große Anzahl an verschiedenen Betriebssystemen eine Java Virtual Machine. Das SWT nutzt jedoch die nativen graphischen Betriebssystemkomponenten. Deshalb können Java-Programme, die SWT nutzen nur noch auf Betriebssystemen ausgeführt werden, für die sowohl eine JVM, als auch das SWT existiert. Das SWT ist jedoch für deutlich weniger Betriebssysteme vorhanden als die JVM und reduziert damit erheblich die Betribssystemunabhängigkeit dieser Programme. Trotzdem bezeichnet sich das SWT als betriebssystemunabhängig. 32

39 SWT Werkzeugleiste (toolbar) unter Windows nativ und unter Linux bei Motif emuliert. SWT bietet ebenso native systemspezifische APIs an, für die Fälle, wo ein bestimmtes fensterbasiertes Betriebssystem ein einzigartiges Feature aufweist, das auf anderen Betriebssystemen nicht zur Verfügung steht. Windows ActiveX ist dafür ein gutes Beispiel. Diese systemspezifischen APIs sind in Paketen mit besonderer Benennung gekapselt, um zu verdeutlichen, dass sie durch den Kern ihres Wesens nicht portierbar sind. Die interne Implementierung vom SWT stellt für jedes fensterbasierte Betriebssystem getrennte und individuelle Implementierungen in Java bereit. Diese internen Java Bibliotheken sind grundlegend verschieden, da sich jede über die speziellen APIs des darunter liegenden fensterbasierten Betriebssystems legt. Dadurch muss keine spezielle Logik in den nativen Bibliotheken implementiert werden. (Im Vergleiche dazu werden in der Java AWT Implementierung für betriebssystemspezifische Unterschiede verschiedene C Implementierungen innerhalb eines Satzes nativer Java Methoden verwendet.) Diese Strategie vereinfacht die Implementierung, die Fehlerkontrolle und die Wartung vom SWT. Für die Erstellung gewöhnlicher Anwendungen mit dem SWT, wird eine einheitliche und Betriebssystem unabhängige SWT API verwendet, die die interne SWT Implementierung komplett verdeckt. JFace JFace ist ein Satz aus Komponenten, die die Handhabung vieler herkömmlicher Aufgaben im Bereich der GUI-Programmierung erleichtert. JFace ist sowohl in seiner API als auch in der Implementierung betriebssystemunabhängig. Es ist für die Arbeit mit dem SWT ausgelegt, ohne das SWT zu verbergen. JFace beinhaltet gebräuchliche UI Komponenten für Bild- und Schriftregistrierungen, Rahmenwerke für Dialoge, Einstellungen und Fortschrittsanzeigen für zeitintensive Operationen. Zwei seiner interessanteren Features sind Actions und Viewers. Der Action-Mechanismus verwendet das Command-Pattern 15 und ermöglicht die Definition von Aktionen (actions) unabhängig von einer Angabe über die exakte Platzierung in der Benutzeroberfläche. Eine Aktion stellt einen Befehl dar, der vom Benutzer über einen Button, einem Menüelement oder einem Icon in einer Werkzeugleiste angestoßen werden kann. Jeder Aktion lassen sich ihre wichtigsten Oberflächenattribute (wie Beschriftung, Icon, Verwendungshinweis, etc.) zuweisen, um passende graphische Darstellungen der Aktion zu generieren. Diese Kapselung erlaubt es, die selbe Aktion an mehreren Stellen der Oberfläche zu verwenden, was wiederum bedeutet, dass sich die Position einer Aktion ohne Änderungen ihres Codes innerhalb der Oberfläche einfach variieren läßt. 15 Vgl. [30]. 33

40 Viewer sind modellbasierte Adapter für bestimmte SWT Komponenten. 16 Viewer vereinfachen die Verwendung von SWT-Komponenten, indem sie die gemeinsamen Programmieraufgaben für diese Komponenten abstrahieren und generalisieren. Die standard Viewer für Listen, Baumstrukturen und Tabellen unterstützen das Auffüllen der SWT-Komponenten mit den Daten des zugrunde liegenden Models, sowie die Synchronisation der SWT-Komponenten bei Änderung der Daten. Hierfür wird der Viewer mit einem Content-Provider und einem Label-Provider verbunden. Der Content-Provider bereitet die Daten für den erwarteten Viewer auf und regelt die Aktualisierung des Viewers bei Änderung der Daten. Der Label-Provider liefert passende Beschriftungen und Icons für die zu darstellenden Daten. Optional können Viewer mit Filtern und Sortierern konfiguriert werden. Viewer leisten entlang ihrer Vererbungs- und Abstraktionslinie Unterstützung für häufige Operationen, wie die Reaktion bei der Auswahl ihrer SWT-Komponenten, bei Doppelklicks, bei Drag&Drop, bei der Navigation oder beim Undo. Mehrerer Viewer können sich ein und das selbe zu Grunde liegende Datenmodell teilen und werden automatisch aktualisiert, falls sich das Datenmodell ändert. Workbench Im Gegensatz zu SWT und JFace, die für die allgemeine Verwendung konzipiert sind, bildet die Workbench den eigentlichen Benutzeroberflächencharakter der Eclipse Plattform und bietet die Strukturen und Vorlagen über die der Benutzer mit den Plugins interagiert. Auf Grund dieser zentralen und bestimmenden Rolle stellt die Workbench ein Synonym für die gesamte Benutzeroberfläche der Eclipse Plattform und dem Hauptfenster dar. Die API der Workbench ist abhängig von der SWT API und in einem geringeren Maße von der JFace API. Die Implementierung der Arbeitsstation baut sich aus der Verwendung von SWT und JFace auf. Java AWT und Swing werden nicht verwendet. Das Paradigma der Benutzeroberfläche der Eclipse Plattform basiert auf Editoren, Views (Ansichten) und Perspektiven. Für den Benutzer besteht das Fenster der Workbench aus Views und Editoren. Die Perspektiven manifestieren sich durch eine bestimmte Auswahl und Anordnung der präsentierten Views und Editoren. (Vgl. Abbildung 7) 16 Das Viewer-Konzept darf jedoch nicht mit einer View (Ansicht) gleichgesetzt werden. Das Viewer- Konzept dient als genereller und vorgefertigter Adapter zwischen den zugrundeliegenden Daten und den unterstützten SWT-Komponenten, in denen die Daten dargestellt werden sollen. Eine View kann jedoch auf diesen vorgefertigten Adapter, bzw. auf das Viewer-Konzept verzichten. 34

41 Abbildung 7: Workbench Fenster Editoren ermöglichen dem Benutzer Objekte zu öffnen, zu editieren und zu speichern, wie es viele Werkzeuge für das Dateisystem tun. Die Editoren sind aber enger in die Workbench integriert. Wenn ein Editor aktiv ist, kann dieser zusätzliche Aktionen in die Menüs und Werkzeugleisten der Workbench einbringen. Views liefern Informationen über Objekte, die der Benutzer innerhalb der Workbench für seine Arbeit verwendet. Eine View kann einem Editor assistieren, indem sie Informationen über das editierte Dokument anzeigt. Desweiteren kann eine View andere Views ergänzen, indem sie zusätzlich Informationen über das momentan ausgewählte Objekt beiträgt. Ein Workbench-Fenster darf mehrere unterschiedliche Perspektiven besitzen, wobei nur eine zu einem bestimmten Zeitpunkt sichtbar sein kann. Jede dieser Perspektiven hat ihre eigenen Views und Editoren, die in dem Workbench-Fenster auf eine besondere Weise angeordnet werden. Zahlreiche unterschiedliche Arten von Views und Editoren können innerhalb einer Perspektive zum selben Zeitpunkt geöffnet sein. Die Perspektive bestimmt welche davon von Anfang an angezeigt werden, ihre Position und Größe. Außerdem bestimmt die Perspektive das Layout und die Anzeige von Aktionen innerhalb einer View. Der Benutzer kann schnell zwischen unterschiedlichen Perspektiven wechseln, um an einer anderen Aufgabe zu arbeiten. Zudem können benutzerdefinierte Anpassungen an einer Perspektive vorgenommen 35

42 werden, um sie für die Arbeit an einer bestimmten Aufgabe anzupassen. Es läßt sich aber auch leicht die ursprüngliche Anordnung wieder herstellen. Plugins unterliegen einer wohldefinierten Integration in dieses Editoren-Views-Perspektiven-Paradigma. Die wichtigsten Erweiterungspunkte ermöglichen es Plugins der Workbench neue Editoren, Views und Perspektiven hinzuzufügen. Neue Perspektiven können alte und neue Views und Editoren gruppieren, um dem Benutzer neue Anwendungsmöglichkeiten zu eröffnen. Plugins können darüber hinaus bereits vorhandene Editoren, Views und Perspektiven erweitern durch: Hinzufügen neuer Aktionen zu der Menü- bzw. Werkzeugleiste einer View. Hinzufügen neuer Aktionen zu der Menü- bzw. Werkzeugleiste der Workbench, wenn ein vorhandener Editor aktiviert wird. Hinzufügen neuer Aktionen zu einem Pop-Up-Kontextmenü einer vorhandenen View oder eines Editors. Hinzufügen neuer Views, Aktionen und Shortcuts zu einer vorhandenen Perspektive. Die Plattform kümmert sich um alle Aspekte des Fenster- und Perspektivenmanagements. Editoren und Views werden nach Bedarf automatisch instantiiert und wieder entfernt wenn sie nicht mehr gebraucht werden. Die Beschriftungen und Icons zur Anzeige der Aktionen, die ein Plugin in die Workbench einbringt, sind in der jeweiligen Manifest-Datei des Plugins aufgelistet, so dass die Worbench die Menüs und Werkzeugleisten kreieren kann, ohne dabei die zur Funktion beitragenden Plugins aktivieren zu müssen. Die Workbench aktiviert ein Plugin erst, wenn der Benutzer wirklich die durch das Plugin eingebrachte Funktionalität in Anspruch nimmt. Erst einmal aktivierte Views und Editoren können an Benachrichtigungsdiensten der Workbench über Aktivierungen und Selektionen partizipieren. Der Aktivierungsdienst überwacht die Aktivierung von Views und Editoren innerhalb einer Perspektive und meldet diese Ereignisse an die registrierten Listener. Der Selektionsdienst übernimmt die Verteilung von Ereignissen, die durch eine Änderung der Auswahl innerhalb eines Editors oder einer View ausgelöst werden an die registrierten Listener. Sowohl Editoren, als auch Views können sich als Quelle für Selektionen bei dem Selektionsdienst anmelden Java Development Tools Die Java Development Tools (JDT) erweitern die Eclipse Platform um die Fähigkeiten einer modernen Java Entwicklungsumgebung (Java IDE). Die JDT sind als Plugins implementiert, die auf der Eclipse Platform aufsetzen. Die JDT sind ein integraler Bestandteil der Eclipse-SDK-Distribution. 36

43 Java Projekte Auf der Workspace-Ebene definiert das 17 JDT eine eigene Java-Projekt-Natur (vgl ), die Projekte als Java Projekte kennzeichnet. Jedes Java Projekt besitzt eine Classpath-Datei, die verschiedene Java spezifische Informationen enthält. Diese Informationen beinhalten die Pfade der Quellcodeverzeichnisse, der JAR-Bibliotheken und des Ausgabeverzeichnises für die vom Compiler generierten Class-Dateien. Java Compiler Die Java Natur konfiguriert jedes Java Projekt mit einem inkrementellen Java Projektbuilder (vgl ), der den eingebauten Java Compiler aufruft. Im Falle einer Initiierung oder eines vollständigen Builds (Ausführung aller Builder eines Projektes), erstellt der Compiler aus allen Quellcodedateien der Quellverzeichnise die entsprechenden binären Class-Dateien im Ausgabeverzeichnis des Projektes. Das JDT deklariert einen neuen Markertyp für Java Probleme (vgl ). Entdeckt der Compiler Fehler oder Probleme, dann fügt er den betroffenen Quellcodedateien die entsprechenden Marker hinzu. Während der Übersetzung erstellt der Compiler einen Abhängigkeitsgraphen mit Informationen über jede Quellcodedatei. Dies ermöglicht folgende Übersetzungen effizienter Auszuführen. Der inkrementelle Projektbuilder-Mechanismus unterrichtet den Java-Builder mit einem Delta-Baum über alle Änderungen der Ressourcen seit seiner letzten Ausführung. Dadurch kann der Java-Builder bestimmen welche Dateien neu kompiliert werden müssen, weil sie geändert, gelöscht oder hinzugefügt wurden. Der Compiler nutzt seinen Abhängigkeitsgraphen, um auch die Dateien neu zu übersetzen, die durch die eben genannten Änderungen indirekt ebenfalls betroffen sind. Das JDT partizipiert am Save-Restore-Prozess des Workspace (vgl ), damit der Abhängigkeitsgraph zwischen mehreren Sitzungen erhalten bleibt. Ansonsten müsste bei jeder neuen Sitzung ein vollständiger Build ausgeführt werden, nur um den Abhängigkeitsgraphen neu zu erstellen. Diese inkrementelle Strategie ermöglicht es dem JDT die Kompilierung regelmäßig auszuführen, z. B. nach jeder Speicherung einer Quellcodedatei, selbst wenn das Projekt hunderte oder tausende Quellcodedateien enthält. Java Element Model Das Java Element Model ermöglicht die Navigation durch die Java Elemente eines Java Projektes. Java Elemente basieren auf den Java Dateien eines Java Projektes und verfügen daher eine Baumstruktur: Package-Fragment-Roots (IPackageFragmentRoot) korrespondieren mit den Quellcodeverzeichnissen und JAR-Bibliotheken eines Projektes. 17 Im folgenden wird statt des Plurals für JDT das Singular verwendet, weil keine Unterscheidung zwischen den einzelnen Teilen des JDT gemacht wird und das JDT als ein umfassendes Werkzeug betrachtet wird. 37

44 Package-Fragments (IPackageFragment) korrespondieren mit Paketen innerhalb eines Package-Fragment-Roots. Compilation-Units (ICompilationUnit) korrespondieren zu Java Quellcodedateien und Class-Files (IClassFile) korrespondieren zu Java Bytecodedateien. Typen, Felder, Initializer und Methoden sind die kleinsten Einheiten einer Compilation-Unit, die durch das Java Model angesteuert werden können. Aufgrund der feinen Granulierung der Compilation-Units ist es nicht effizient den gesamten Java Elementbaum im Speicher zu halten. Zudem wäre die Konstruktion des Elementbaumes aufwendig, denn dazu müssten alle Java Quellcodedateien eingelesen und geparst werden. Stattdessen wird der Baum stückweise und nur auf Nachfrage konstruiert. Clients arbeiten damit lediglich mit Handels, solange nicht nach weiteren inneren Elementen gefragt wird. Deshalb eignet sich das Element- Model besonders zur Präsentation in Viewern. Der Elementbaum besitzt einen begrenzten Cache für bereits analysierte Compilation-Units. Der Cache nutzt einen Resource-Change-Listener des Workspace, um Einträge zu entfernen, wenn sich die entsprechenden Ressourcen geändert haben oder gelöscht wurden. Desweiteren gestattet das Java Element Model gewisse Modifikationen des Java Quellcodes. Hierzu zählt das Hinzufügen von neuen Feldern, Initializern, Methoden und Typen, sowie das Umbenennen, Verschieben, Kopieren oder Löschen von Java Elementen. Abstract Syntax Tree Das Java Element Model ist nicht fein genug, um eine detailiertere Analyse und Modifikation z. B. von Anweisungen innerhalb von Methoden zu ermöglichen. Deshalb bietet das JDT einen Zugang zum sogenannten Abstract Syntax Tree 18 (AST) einer Quellcodedatei. Der AST ist das Ergebnis einer Analyse einer Quellcodedatei durch einen Parser (ASTParser). Jeder Knoten (ASTNode) des AST repräsentiert einen definierten Teil des Java Quellcodes. Abbildung 9 zeigt ein Beispiel eines solchen AST. Es existieren über 60 hierarchisch strukturierte Knotentypen für die verschiedenen Teile des Quellcodes wie z. B. Importdeklarationen, Typendeklarationen, Methodenaufrufe, Feldzugriffe und Literale. 19 Abbildung 8 zeigt einen Teil der ASTNode-Hierarchie. Das JDT stellt einen ASTVisitor 20 bereit um die Knoten des AST zu durchlaufen und Aktionen in Abhängigkeit des Knotentyps auszuführen. 18 Die von Eclipse erzeugte interne Repräsentation eines Programms ist in Wahrheit eine Mischung eines Parse-Baums und eines abstrakten Syntax-Baums. So enthält der Baum Knoten für Klammern (zum Beispiel für den Ausdruck (1 + 1) ) oder Informationen zu Javadoc-Kommentaren, die in einem reinen abstrakten Syntax-Baum eigentlich nicht mehr vorkommen. 19 Für die neuen Sprachkonstrukte in Java 1.5 kommen weitere Knotentypen hinzu. 20 Vgl. das Visitor-Pattern in [30]. 38

45 Abbildung 8: ASTNode Hierarchie vgl. [26]. Die AST-API bietet zwei verschiedene Möglichkeiten an, den zugrunde liegenden Quellcode mit Hilfe des AST zu verändern: die modifizierende API und die deskriptive API. 21 Die modifizierende API ermöglicht den AST direkt zu verändern. Die Veränderung des Quellcodes bedarf in diesem Fall drei Schritte: Zunächst muss der AST aufgefordert werden die Modifikationen aufzunehmen. Dann können die entsprechenden Modifikationen an den Knoten des AST vollführt werden. Sind die AST-Modifkationen abgeschlossen, werden Quellcode-Modifikationen daraus generiert, die dann auf den Quellcode angewendet werden können. Die deskriptive AST-API nutzt den ASTRewriter. 21 Vgl. die Eclipse SDK Hilfe: JDT Plug-in Developer Guide Programmer's Guide JDT Core Manipulating Java code. 39

46 CompilationUnit imports() types() ASTNode$NodeList toarray() Object[] 0 ASTNode$NodeList toarray() Object[] 0 TypeDeclaration getmethods() MethodDeclaration[] 0 ImportDeclaration MethodDeclaration getbody() tostring(): import junit.framework.testcase; Block statements() Abbildung 9: Abstract Syntax Tree Beispiel aus [26] S.320 ASTRewriter Mit Hilfe des ASTRewriters lassen sich komplexe Manipulationen des Quellcodes auf eine etwas bequemere Art durchführen als durch die modifizierende API. Der AST Rewriter sammelt Informationen über die auszuführenden Manipulationen in Form von AST-Änderungen und berechnet daraus die nötigen Modifikationen des Quellcodes. Der AST selbst wird durch den ASTRewriter also nicht verändert. Die einfachere Handhabung ermöglichen Methoden wie z. B. createstringplaceholder des ASTRewriters. Als Parameter erhält diese Methode eine Zeichenkette, die an die entsprechende Stelle des Platzhalters (engl. Placeholder) im Quellcode hinzugefügt wird. Im Vergleich dazu muss in der modifizierenden API für jedes Element der Zeichenkette ein AST-Knoten erzeugt werden, und abhängig von der API der jeweiligen Knoten müssen diese auf unterschiedliche Weise miteinander verknüpft werden. IScanner Das JDT unterstützt auch eine Low-Level Analyse und Manipulation von Java Quellcode. Für eine noch feinere Analyse des Quellcodes stellt das JDT einen Scanner zur 40 ASTNode$NodeList toarray() Object[] 0 ExpressionStatement getexpression() MethodInvocation tostring(): fail()

47 Verfügung. Der Scanner parst und zerlegt den Quellcode in einzelne Token. Der Scanner kann zudem auf kleine Teile des Quellcodes angewandt werden. Für die Modifikation von Quellcode auf der Zeichenkettenebene, stellt das JDT effiziente Operationen für Char-Arrays zur Verfügung. Java UI Das JDT definiert eine Java Perspektive für Entwickler von Java Anwendungen. (Vgl. Abbildung 7 in Abschnitt 3.1.3) Diese Perspektive beinhaltet unter anderem folgende Java spezifische Workbencherweiterungen: eine Package-View, eine View zur Darstellung der Hierarchie von Java Typen, einen Java Editor, Aktionen für die Erzeugung von Java Elementen, das Refactoring des Quellcodes, sowie das Ausführen und Debuggen von Java Programmen. Die Package-View liefert eine hierarchische Sicht auf die Pakete, Quellcodedateien und JAR-Bibliotheken innerhalb eines Java Projektes. Die Elemente und Beziehungen dieser Ansicht kommen direkt vom Java Model. Die Typ-Hierarchie-View stellt die strukturelle Vererbungsbeziehung von Klassen und Schnittstellen dar. Diese Typ-Hierarchie verwendet eine indexbasierte Suche des Java Models kombiniert mit einer Untersuchung des Quellcodes, um die Namen der Supertypen zu extrahieren. Der Java Editor unterstützt vielfältige und nützliche Features, wie Syntax-Highlighting, Hervorhebung von Annotationen wie Breakpoints und Problemmarkierungen, Codeassistenten und Formatierungen. Die Aktionen nutzen verschiedene Assistenten (Wizards), um neue Java Projekte, Pakete, Klassen oder Schnittstellen zu erzeugen. Das Refactoring ermöglicht Operationen wie z. B. das Umbenennen von verschiedenen Java Elementen oder das Ändern von Methodensignaturen. Die Workbench beinhaltet desweiteren Aktionen, um Programme zu starten und zu debuggen. Für das Debuggen stellt das JDT eine Debug-Perspektive bereit, die für diese Aufgabe spezialisiert ist. Diese Perspektive beinhaltet eine View für alle laufenden oder kürzlich beendeten Prozesse und eine Konsole über die der Entwickler mit dem laufenden Programm über die standard Input- und Outputstreams interagieren kann. Die View für die Prozesse stellt zudem die Threads und die Stack-Frames der laufenden Anwendung dar. Bei einem unterbrochenem Programmablauf, z. B. durch Breakpoints, wird die nächste auszuführende Zeile im Editor hervorgehoben. Andere debug-spezifische Views zeigen die Liste aller gesetzten Breakpoints, die Felder der Objekte, sowie Werte der Felder. Desweiteren werden Breakpoints im 41

48 Editor in einer vertikalen Leiste direkt neben dem Quellcode angezeigt. Die genaue Darstellung der Breakpoints hängt vom Typ des Breakpoints bzw. von seinem Markertyp ab. Debugger Das JDT ist in der Lage Java Programme aus der Eclipse-IDE heraus zu starten und zu debuggen. Dabei wird eine neue JVM in einem separaten Prozess gestartet, die das Java Programm ausführt. Durch die Bereitstellung von entsprechenden Erweiterungspunkten unterstützt das JDT die Implementierung spezialisierter Launcher für verschiedene JVMs. Der JDT-Debugger arbeitet mit jeder JPDA unterstützenden JVM zusammen. Die Architektur des Debug-Frameworks ist komplex und vielschichtig. Einerseits nutzt das Debug-Framework das von der Eclipse-SDK bereitgestellte generelle Debug-Model. Andererseits setzt das Debug-Framework auf der Java Platform Debug Architektur auf. Da die Java Platform Debug Architektur bereits in Abschnitt behandelt wurde, soll im folgenden das Debug-Model der Eclipse Platform vorgestellt werden. Denn obwohl es nicht direkt zum JDT gehört, implementiert das JDT- Pendant alle Schnittstellen des Eclipse Platform Debug Models. Die Abbildung 10 zeigt das generelle Debug-Model der Eclipse Platform. Dieses Model beinhaltet die wichtigsten Abstraktionen für die meisten Programmierumgebungen. Desweiteren interagiert die Debug-UI der Eclipse Platform mit diesen Abstraktionen, während die verschiedenen sprachabhängigen Debug-Plugins die passenden Implementationen liefern. Die verschiedenen Interfaces des Models sollen an dieser Stelle kurz erläutert werden: Launch (ILaunch) Ein Container für Prozesse und Debug Targets. Debug Element (IDebugElement) Eine Gemeinsame Schnittstelle für eine ganze Reihe von Debug-Artefakten. Debug Target (IDebugTarget) - Der Kontext eines Prozesses oder einer VM, der debugt werden kann. Process (IProcess) Ein Prozess repräsentiert ein im normalen Modus (nicht Debug) ablaufendes Programm. Stack frames (IStackFrame) - Der Kontext eines suspendierten bzw. angehaltenen Threads, der lokale Variablen und Argumente beinhaltet. Thread (IThread) - Ein sequentieller Ablauf in einem Debug Target, der Stack- Frames beinhaltet. Variable (IVariable) Eine sichtbare Datenstruktur in einem Stack-Frame. Value (IValue) - Der Wert einer Variablen. Breakpoint (IBreakPoint) Ein Breakpoint kann den Programmablauf an einer bestimmten Stelle unterbrechen, sofern das Programm im Debug-Modus läuft. 42

49 Die Eclipse Platform stellt zudem ein (Source-Lookup-) Framework bereit, mit dessen Hilfe der zum Programmablauf gehörende Quellcode gefunden und dem Benutzer die auszuführende Zeile präsentiert werden kann. «Schnittstelle» ILaunch * 1 «Schnittstelle» IDebugElement 1 «Schnittstelle» IDebugTarget «Schnittstelle» IProcess * 1 * 1 «Schnittstelle» IThread 1 * «Schnittstelle» IStackFrame * 1 «Schnittstelle» IVariable 1 * 1 1 «Schnittstelle» IValue Abbildung 10: Eclipse Platform Debug Model. [31] * «Schnittstelle» IBreakPoint Breakpoints Mit Hilfe von Breakpoints kann der Ablauf eines Programmes an einer bestimmten Stelle unterbrochen werden, um dann Informationen über den Kontext der jeweiligen Stelle zu gewinnen. Abbildung 11 zeigt die Komponenten des generellen Breakpoint-Models. Das JDT implementiert die Schnittstellen dieses Models. Die Implementierung von Breakpoints nutzt den Marker-Mechanismus (vgl ). Durch die Verwendung von Markern, kann das Debug-Model existierende Markerfunktionen wie die Persistenz, die Suche, das Hinzufügen oder Löschen und die Darstellung in einem Editor nutzen. Deshalb muss bei der Deklaration eines neuen Breakpointtyps in der Manifest-Datei. spezifiziert werden, welcher Marker mit 43

50 diesem Breakpoint assoziiert werden soll. Hierfür definiert das Debug-Model den speziellen Markertyp org.eclipse.debug.core.breakpointmarker für Breakpoints. Sofern dieser Breakpointmarker als Supertyp für neue Breakpointmarker verwendet wird, ist der Breakpointmanager in der Lage die korrespondierenden Breakpoints bei einer neuen Sitzung (Session) zu finden, wiederherzustellen und in der Benutzeroberfläche darzustellen. Dafür sucht der Breakpointmanager in den Ressourcen eines Projektes nach Breakpointmarkern, dessen Supertyp der org.eclipse.debug.core.breakpointmarker ist. Mit Hilfe der Extension Registry kann der Breakpointmanager die mit den gefundenen Markern assoziierten Breakpointklassen finden und instantiieren. Desweiteren informiert der Breakpointmanager das DebugTarget über hinzugefügte, entfernte oder geänderte Breakpoints. Die Eclipse Debug-UI zeigt Breakpoints, die beim Breakpoint-Manager registriert wurden, in einer Liste an. Der Quellcodeeditor verwendet den Marker eines Breakpoints, um diesen darzustellen. Sollen Breakpoints für die Verfolgung des Programmablaufes, wie im Tracingverfahren, genutzt werden, so ist es wichtig diese Breakpoints vor dem Benutzer zu verbergen. Um einen Breakpoint vor dem Benutzer zu verbergen, darf der Breakpoint nicht beim Breakpointmanager registriert werden, und der zugehörige Marker muss entweder einen anderen Supertypen als org.eclipse.debug.core.breakpointmarker haben oder einer Ressource zugewiesen werden, die der Quellcodeeditor nicht darstellt. Wird jedoch der Breakpointmanager nicht verwendet, dann muss die Persistenz, bzw. die Wiederherstellung der Breakpoints bei einer neuen Sitzung (Session), sowie die Benachrichtigung des Debug Targets selbst implementiert werden. Dafür ist ein Listener namens org.eclipse.debug.core.idebugeventsetlistener hilfreich. Dieser Listener kann beim Debug-Plugin registriert werden, um über Ereignisse eines laufenden Programmes im Debug-Modus benachrichtigt zu werden. 44

51 <<extension>> Marker Type = linebreakpointmarker <<extension>> Marker specifies class (on restore) <<extension>> Breakpoint «Schnittstelle» IBreakpoint instantiates (on restore) «Schnittstelle» IBreakpointManager notifies (add, change, remove) instantiates (on restore) «Schnittstelle» IMarker looks for breakpoint markers (on restore) AbstractDecoratedTextEditor AbstractMarkerAnnotationModel «Schnittstelle» IDebugTarget Abbildung 11: Breakpoint Model, vgl. [0] Die JDT-Debug-API stellt zudem den Listener org.eclipse.jdt.debug.core.ijavabreakpointlistener bereit, mit dessen Hilfe ein Plugin über getroffene Breakpoints (breakpoint hits) während des Programmablaufes benachrichtigt werden kann, und zugleich entscheiden, ob der Programmablauf durch den jeweiligen Breakpoint unterbrochen werden soll. Das JDT Debug-Plugin stellt verschieden Breakpointtypen zur Verfügung. Die wichtigsten Typen für diese Arbeit bzw. das Tracingverfahren sind IJavaLine Breakpoint, IJavaMethodBreakpoint und IJavaClassPrepareBreakpoint. Zusammen mit dem IJavaBreakpointListener können diese Breakpoints für die Verfolgung des Programmablaufes genutzt werden. Mit Hilfe von IJavaClassPrepareBreakpoints können Breakpoints der beiden anderen Typen nur in die Klassen installiert werden, die tatsächlich auch von der VM geladen werden. 3.2 Architektur Überblick Die Architektur des Werkzeuges zur Messung von Testabdeckungen umfasst insgesamt fünf Komponenten. Die gesamte Architektur des Werkzeuges ist in Abbildung 12 abgebildet. Um die größt mögliche Entkopplung der Komponenten des Werkzeuges zu erreichen, ist jedes selbst jeweils als ein Plugin implementiert. Auf diese Weise lassen sich die Komponenten leicht austauschen, als Beispielimplementierungen nutzen, oder durch weitere Plugins erweitern. Es folgt eine kurze Erläuterung der Komponenten: 45

52 ResultView IPersistentCoverageDataListener Persistence ICoverageRunListener Adapter «uses» «uses» Instrumenter Tracer Abbildung 12: Architektur des Werkzeugs zur Messung von Testabdeckungen Die ResultView präsentiert dem Anwender die Ergebnisse der Testabdeckungsmessung. Die Persistence Komponente speichert alle anfallenden Daten persistent ab. Die Adapter Komponente dient als Adapter für die beiden Verfahren zur Messung der Testabdeckung. An diesen Adapter lassen sich weitere Verfahren anschließen. Die Instrumenter Komponente implementiert das Instrumentierungsverfahren. Die Tracer Komponente implementiert das Tracingverfahren. Die öffentlichen Schnittstellen ICoverageRunListener und IPersistentCoverageDataListener sind jeweils in den darunter liegenden Plugins definiert und in den korrespondierenden Manifest-Dateien deklariert. Sie erlauben das Austauschen der Persistence-Komponente und der ResultView durch andere Implementierungen, ohne die darunter liegenden Plugins modifizieren zu müssen. Es ist sogar denkbar ganz auf die Persistenzschicht zu verzichten und eine neue View direkt über die ICoverageRunListener Schnittstelle anzuschließen. 46

53 3.3 Instrumentierungsverfahren Die Instrumenter-Komponente umfasst eine ganze Reihe von Klassen. Abbildung 13 stellt die meisten davon dar und veranschaulicht, wie die Klassen miteinander in Beziehung stehen. CoveragePropertyPage enables, disables for project CoveragePlugin «eclipse mechanism» add to project CoverageNature initialize uses «eclipse mechanism» add to project set port LaunchListener ClasspathUtils CoverageBuilder start, terminate add to project path from uses «Teilsystem» CoverageTraceCollectorServer CoverageTraceCollectorClient sends runtime data uses «Teilsystem» Instrumenter update runtime data sources instruments Adapter UpdateInformer update static data Abbildung 13: Instrumenter-Plugin Die CoveragePropertyPage nutzt einen UI-Mechanismus der Eclipse Platform, um das Plugin für ein bestimmtes Projekt aus der Benutzeroberfläche heraus aktivieren und deaktivieren zu können. Bei Aktivierung des Instrumenter-Plugins für ein bestimmtes Projekt fügt das CoveragePlugin diesem Projekt eine Coverage- Nature hinzu. Desweiteren initialisiert das CoveragePlugin einen LaunchListener, der stets benachrichtigt wird, wenn ein Java Programm aus der Eclipse Platform heraus ausgeführt wird. Auf diese Weise kann der CoverageTraceCollectorServer nur für Java-Programme gestartet werden, die eine CoverageNature aufweisen und nach Beendigung des Programms kann auch der Server terminiert werden. Die Klasse CoverageNature konfiguriert und verwaltet nicht nur den CoverageBuilder für ein Projekt, sondern auch den Pfad zum CoverageTrace 47

54 CollectorClient. Diese Klasse stellt die Kommunikation zwischen dem instrumentierten Programm und dem CoverageTraceCollectorServer zur Laufzeit her, um Daten über den Programmablauf an das Plugin zu senden. Der Coverage Builder verwendet den Instrumenter, um die Quellcodedateien zu instrumentieren und gleichzeitig Daten über die statische Struktur der Quellcodedateien zu erfassen. Die instrumentierten Quellcodedateien werden dann vom Coverage Builder kompiliert. Sowohl der CoverageTraceCollectorServer als auch der Instrumenter nutzen die Klasse UpdateInformer der Adapter-Komponente, um die Daten nach Außen zu geben. Im folgenden wird das Instrumenter-Teilsystem näher erläutert, und anschließend wird die Kommunikation zwischen dem Plugin zur Messung von Testabdeckungen und dem zu untersuchenden Programm beschrieben Instrumenter Abbildung 14 zeigt ein UML-Diagramm mit den wichtigsten Klassen für die Instrumentierung des Quellcodes. Die Aufgaben dieser Klassen sind folgende: Die Klasse Instrumenter ist in der Lage sowohl ein ganzes Java Projekt, als auch nur eine einzelne ICompilationUnit 22 (Quellcodedatei) zu instrumentieren. Soll das gesamte Java Projekt instrumentiert werden, so wird über den Java Elementbaum des Projektes iteriert, bis eine ICompilationUnit gefunden wurde. Diese wird dann genauso instrumentiert, als würde der Instrumenter eine einzelne ICompilationUnit verarbeiten. Eine einzelne ICompilationUnit wird wie folgt instrumentiert: Zunächst generiert der ASTParser aus der ICompilationUnit (Java Element Model) eine CompilationUnit (AST). Letzteres ist bereits die Wurzel des AST. Für diesen AST wird ein ASTRewriter erzeugt und als Parameter an den ASTInstrumenter übergeben. Der AST wird mittels des ASTInstrumenters durchlaufen, der diese Fähigkeit vom ASTVisitor erbt. Für bestimmte Knoten, die z. B. Anweisungen, Methoden oder Schleifen repräsentieren, generiert der TraceGenerator passende Instrumentierungen in Form von Zeichenketten. Der ASTRewriter erzeugt für diese Zeichenketten entsprechende StringPlaceHolder-Knoten und merkt sich die Stellen, an denen die Änderungen eingefügt werden sollen. Bei der Instrumentierung des Quellcodes sind verschiedene Sonderfälle zu berücksichtigen (vgl , und 2.1.4). Alle Sonderfälle können dennoch im selben Durchgang mittels des ASTRewriters behandelt werden. Nach dem Durchlaufen des gesamten AST, wird mit dem ASTRewriter eine temporäres TextEdit-Objekt erzeugt, das die 22 Eine ICompilationUnit repräsentiert eine Quellcodedatei im Java Element-Model. Eine CompilationUnit (ohne I) repräsentiert ebenfalls eine Quellcodedatei, jedoch im AST-Model. Beide Modele und damit auch beide Klassen existieren unabhängig voneinander. 48

55 gesamten Modifikationen enthält. Diese Modifikationen lassen sich schließlich auf ein Document-Objekt der Quellcodedatei anwenden und abspeichern. ASTParser ASTRewriter Instrumenter ASTVisitor «uses» 1 1 TraceGenerator 1 1 ASTInstrumenter Abbildung 14: Instrumenter-Teilsystem Inter-JVM-Kommunikation Die Eclipse Platform wird in einer JVM-Instanz ausgeführt. Um ein Java Programm eines Java Projektes aus der Eclipse Platform heraus laufen zu lassen, wird zunächst eine neue Instanz der JVM gestartet. Diese JVM erhält dabei alle Informationen, wie z. B. Pfadangaben, um das Programm zu starten als Parameter. Anhand dieser Informationen lädt die JVM die kompilierten Klassen des Projektes und führt das Java Programm aus. Da jedoch die Eclipse Platform und damit auch das Plugin zur Messung von Testabdeckungen in einer anderen JVM ausgeführt werden als das zu untersuchende Programm, muss ein Kommunikationsweg zwischen diesen beiden JVMs aufgebaut werden. Prinzipiell stehen mehrere Möglichkeiten zur Verfügung um die Inter-JVM- Kommunikation zu realisieren: Verwendung einer gemeinsamen Datei. Verwendung einer gemeinsamen Datenbank. Verwendung einer Socket-Verbindung. Die Verwendung einer gemeinsamen Datei oder Datenbank wäre die effizienteste Möglichkeit die Kommunikation zwischen den beiden JVMs herzustellen und zugleich eine Persistenz der Daten umzusetzen. Jedoch ist die Persistenz keine zwingende Anforderung für die Messung von Testabdeckungen oder anderer Statistkfunktionen. Zudem läßt sich der Programmablauf nur in Echtzeit 23 verfolgen und visualisieren, falls eine Kommunikation in Echtzeit stattfinden kann. Die Flexibilität ganz auf die Persistenz zu verzichten und/oder den Programmablauf in 23 Damit ist jeweils eine unmittelbare Benachrichtigung vor oder nach dem Aufruf einer instrumentierten Anweisung oder Methode gemeint. Diese Benachrichtigung muss also stets vor dem Aufruf der folgenden Anweisung oder Methode ausgeführt werden. 49

56 Echtzeit zu visualisieren bietet nur eine Socket-Verbindung. Zu Gunsten der Flexibilität und auf Kosten der Performance wurde für die Implementierung der Inter-JVM- Kommunikation der Socket-Ansatz gewählt. 24 Abbildung 15 stellt die Realisierung der Inter-JVM-Kommunikation des Instrumenter-Plugins dar. Eclipse VM Instrumenter-Plugin CoverageTraceCollector Server launches notification per socket Java Application VM Application CoverageTraceCollector Client attaches Workspace loads Project CoverageTraceClient.jar Abbildung 15: Inter-JVM-Kommunikation Wird das Instrumenter-Plugin für ein Java Projekt im Workspace aktiviert, wird diesem Projekt zunächst die CoverageTraceCollectorClient-Bibliothek hinzugefügt. Bei Ausführung des Projektes wird dann eine neue JVM-Instanz gestartet, die die benötigten Klassen des Projektes lädt. Gleichzeitig wird der Coverage TraceCollerctorServer als Thread gestartet. Die CoverageTraceCollectorClient-Bibliothek besteht lediglich aus einer einzigen Klasse, die genauso wie die Bibliothek benannt ist. Die zu untersuchende Anwendung greift auf die Klasse CoverageTraceCollectorClient aufgrund ihrer Instrumentierung zu. Die Klasse CoverageTraceCollectorClient ist als ein Singleton realisiert, auf das alle Klassen der zu untersuchenden Anwendung zugreifen. Der CoverageTrace CollectorClient erzeugt bei seiner Instantiierung eine Socket-Verbindung zum CoverageTraceCollectorServer. Damit auch bei mehreren Threads einer zu untersuchenden Anwendung jeweils nur ein Thread Daten an den Server sendet, ist die Sende-Operation als atomare (synchronized) Methode implementiert. 24 Grundsätzlich wäre auch eine Hybrid-Lösung denkbar, die die Wahl der Kommunikationsart dem Benutzer überläßt. Diese Lösung wäre jedoch nur mit einem erheblichen Mehraufwand bei der Architektur und der Implementierung realisierbar. 50

57 3.3.3 Probleme Ein bedeutendes Problem für die Implementierung des Instrumentierungsverfahrens stellt die Tatsache dar, dass das Eclipse Framework keine öffentliche API für die Kompilierung einer Java Quellcodedatei bereitstellt, die sich nicht im Source-Path des Projektes befindet. 25 Es darf auch kein Source-Path für die instrumentierten Quellcodedateien hinzugefügt werden, weil es sonst zu Namenskonflikten käme. Der CoverageBuilder greift deshalb auf das ANT-Plugin zu, um ein ANT-Skript auszuführen, welches die notwendige Kompilierung der instrumentierten Quellcodedateien übernimmt. Das ANT-Skript ist in der Lage für die Kompilierung auf den Eclipse eigenen Compiler zuzugreifen und diesen zu verwenden. Auf diese Weise muss kein zusätzlicher Compiler installiert und konfiguriert werden. Ein weiteres Problem ergibt sich durch die Instrumentierung des Quellcodes. Denn dadurch verändern sich die Zeilenangaben so, dass keine Breakpoints mehr im Debug-Modus getroffen werden. Die ASTRewriter-API bietet keine Möglichkeit die Erzeugung neuer Zeilen bei der Einfügung neuer Anweisungen zu unterdrücken. 26 Bisher konnte dieses Problem nicht behoben werden. Grundsätzlich könnten die eingefügten Zeilenumbrüche direkt aus dem Quellcode entfernt werden, indem alle Positionen der eingefügten Anweisungen gespeichert werden. Dabei könnten jedoch zusätzlich eingefügte Blöcke ({...}) für Schleifen- oder Bedingungsanweisungen Probleme bereiten, insbesondere wenn diese geschachtelt wären. Alternativ könnte ein spezieller Rewriter implementiert werden, der keine Zeilenumbrüche erzeugt. Aber auch in diesem Fall wären Blöcke für geschachtelte Schleifen- oder Bedingungsanweisungen eine besondere Herausforderung. 3.4 Tracingverfahren Abbildung 16 stellt die wichtigsten Klassen der Tracer-Komponente dar. Der Vergleich mit der Abbildung 15 veranschaulicht die Ähnlichkeit der Tracer-Komonente und der Instrumenter-Komponente. Die Klassen CoveragePropertyPage, CoveragePlugin, CoverageNature, LaunchListener und CoverageBuilder sind in beiden Komponenten enthalten und und erfüllen dieselben Aufgaben. Jedoch unterscheiden sich die Implementierungen dieser Klassen in einigen Details, weshalb diese Klassen nicht in eine gemeinsame Bibliothek ausgelagert werden konnten. Durch die Ausnutzung des Debug-Mechanismus ist die Tracer-Komponente jedoch deutlich einfacher strukturiert als die Instrumenter-Komponente. So kann z. B. auf die Inter- 25 Die IJavaProject-API bietet eine build-methode an, die den JavaBuilder veranlasst das entsprechende Java Projekt zu übersetzen. Diese Methode erlaubt allerdings nicht die Kompilierung einzelner Quellcodedateien, die sich nicht im Quellverzeichnis des Projektes befinden. 26 Vgl. [32]. 51

58 JVM-Kommunikation, aber auch auf die Kompilierung des Quellcodes innerhalb der CoverageBuilder-Klasse verzichtet werden. CoveragePropertyPage enables, disables for project CoveragePlugin «eclipse mechanism» add to project CoverageNature initialize LaunchListener «eclipse mechanism» add to project CoverageBuilder start, terminate handle Breakpoint Hits uses BreakpointHandler create Breakpoints for Markers sources adds Marker «Teilsystem» MarkerAnnotator update runtime data update static data Adapter UpdateInformer Abbildung 16: Tracer-Plugin Der CoverageBuilder verwendet das MarkerAnnotator-Teilsystem, um den Quellcodedatein Marker hinzuzufügen und gleichzeitig Daten über die statische Struktur zu sammeln. Sobald das zu untersuchende Programm gestartet wird, registriert der LaunchListener den BreakpointHandler beim DebugTraget, d.h. der Virtual Machine in der das Programm ausgeführt wird. Der BreakpointHandler generiert anhand der Marker Breakpoints mit eindeutigen ID-Attributen und fügt die Breakpoints dem DebugTarget hinzu. Außerdem registriert sich der BreakpointHandler selbst als BreakpointListener beim Debug-Model. Auf diese Weise wird der BreakpointHandler über jeden Breakpointtreffer (breakpoint hit) benachrichtigt und ist damit in der Lage den UpdateInformer über den Programmablauf zu unterrichten. 52

59 3.4.1 MarkerAnnotator Das MarkerAnnotator-Teilsystem ist dem Instrumenter-Teilsystem ähnlich. Die Klasse MarkerAnnotator entspricht der Klasse Instrumenter, die Klasse ASTAnnotator entspricht der Klasse ASTInstrumenter und schließlich entspricht die Klasse TraceMarkerGenerator der Klasse TraceGenerator. Der wesentlichste Unterschied ist, dass eine Manipulation des Quellcodes nicht stattfindet. Deshalb wird ein ASTRewriter nicht gebraucht. Stattdessen werden Marker vom TraceMarkerGenerator erzeugt und den Quellcodedateien hinzugefügt. Abbildung 17 stellt die statische Struktur des MarkerAnnotator-Teilsystems als UML-Diagramm dar. ASTParser 1 1 MarkerAnnotator 1 1 ASTVisitor TraceMarkerGenerator 1 1 ASTAnnotator Abbildung 17: MarkerAnnotator-Teilsystem BreakpointHandler Sowohl Marker als auch Breakpoints können dynamisch zur Laufzeit gesetzt und wieder entfernt werden. Diese Tatsache ermöglicht Breakpoints und Marker in verschiedenen Kombinationen zu setzen. Zum Beispiel könnten alle Breakpoints generiert werden, sobald ein DebugTarget zur Verfügung steht, also sobald das zu untersuchende Programm im Debug-Modus ausgeführt wird. Dieser Ansatz skaliert jedoch nicht mit zunehmender Programmgröße und mit wachsender Breakpointanzahl. Damit würde es zu einer erheblichen Verzögerung beim Programmstart kommen. Eine andere, besonders entgegengesetzte Möglichkeit wäre das Setzen von ClassPrepareBreakpoints für jede Klasse beim Programmstart. Erst bei einem Treffer eines ClassPrepareBreakpoint würden MethodBreakpoints und schließlich bei einem Treffer eines MethodBreakpoints könnten LineBreakpoints gesetzt werden. Diese Möglichkeit würde einen vergleichsweise schnellen Programmstart zur Folge haben und nur für die Programmteile Breakpoints erzeugen, die tatsächlich ausgeführt werden. Für die Implementierung des BreakpointHandlers wurde ein Ansatz gewählt, der dem zu letzt genannten ähnelt. Um die Erzeugung von vielen Breakpoint-Objekten noch weiter einzuschränken, wurde auf die Verwendung von ClassPrepare 53

60 Breakpoints verzichtet und stattdessen generelle MethodBreakpoints eingesetzt. Dabei wird ein genereller MethodBreakpoint pro Klasse erzeugt. Ein genereller MethodBreakpoint wird bei jedem Methodenaufruf innerhalb einer Klasse getroffen. Bei einem Treffer wird mit Hilfe des zugehörigen Stack-Frames die aktuelle Position im Programmablauf bestimmt, die nötigen LineBreakpoints für die aktuelle Methode erzeugt und schließlich der UpdateInformer benachrichtigt. Dieses Vorgehen senkt zwar die Erzeugung von Breakpoints erheblich, erhöht aber gleichzeitig die Komplexität der dazu notwendigen Logik. Im Rahmen dieser Arbeit wurden verschiedene Ansätze ausprobiert, jedoch konnte nicht ausreichend überprüft werden, welcher Ansatz für das Setzen der Breakpoints am besten geeignet ist. Deshalb befinden sich einige alternative Ansätze in separaten Verzeichnissen des Tracer-Plugins Probleme Die Implementierung des Tracer-Plugin ist im Vergleich zum Instrumenter-Plugin einfacher gewesen. Ein Problem stellte jedoch die grundsätzliche Visualisierung der verwendeten Breakpoints in der GUI dar. Hierdurch könnten Benutzer die für die Messung notwendigen Breakpoints deaktivieren und die Messung verfälschen. Das Verbergen dieser Breakpoints war entscheidend für die Benutzbarkeit des Tracer- Plugins. Dieses Problem erhöhte den Aufwand der Implementierung erheblich. Um die Breakpoints vor dem Anwender zu verbergen, durfte der Breakpoint-Manager nicht verwendet werden. Ein Teil seiner Funktionalität musste deshalb nachgebaut werden, wie z. B. das Generieren und Hinzufügen von für die Messung nötigen Breakpoints, sobald ein Programm mit aktiviertem Tracer-Plugin im Debug-Modus gestartet wird. Zudem mussten spezielle Breakpoint-Marker definiert werden, die keine Icons anzeigen. Ein bedeutenderes Problem haben Vergleichsmessungen ergeben: Die Messergebnisse des Tracer-Plugin unterscheiden sich deutlich von den Ergebnissen des Instrumenter-Plugins. Dies betrifft jedoch ausschließlich die dynamisch erfassten Daten (also Daten, die zur Laufzeit des zu untersuchenden Programmes gesammelt werden). Dafür konnten mehrere Ursachen ausfindig gemacht werden, die das Tracer-Plugin betreffen. 1. Es befindet sich mindestens ein Bug in der Implementierung der Breakpoints bzw. des dazugehörigen Java-Debug-Frameworks. 27 Aufgrund dieses Bugs werden Breakpoints, die an bestimmten Stellen gesetzt werden nicht getroffen. Dies hat zur Folge, dass bestimmte Methoden (und damit alle darin enthaltenen Anweisungen) als nicht ausgeführt gezählt werden, obwohl dies tatsächlich nicht zutrifft. 27 Vgl. [33]. Dieser Bug soll in der Version 3.2 beseitigt werden. 54

61 2. Breakpoints können nicht jedem Java-Sprachkonstrukt hinzugefügt werden. So kann ein JavaLineBreakpoint nicht auf eine Case-Anweisung gesetzt werden. 3. Bei mehreren Anweisungen in einer Zeile kann durch JavaLineBreakpoints nicht unterschieden werden, welche der Anweisungen tatsächlich ausgeführt wird. Quellcode 6 demonstriert dieses Problem. Für Zeile 5 werden zwei JavaLineBreakpoints gesetzt, einer für die If-Anweisung und ein weiterer für die darauf folgende Zuweisung. Sobald Zeile 5 erreicht wird, werden jedoch beide Breakpoints getroffen und das Plugin zählt beide Anweisungen als ausgeführt, obwohl die Zuweisung (b=true;) tatsächlich gar nicht ausgeführt werden konnte. 1 public class BreakpointProblem { 2 3 public static void main(string[] args) { 4 boolean b = false; 5 if(b){b=true;} 6 } 7 } Quellcode 6: Multiple-Breakpoint-Problem Es konnte bis zum jetzigen Zeitpunkt nicht endgültig geklärt werden, ob ausschließlich die oben genannten Ursachen für die unterschiedlichen Messergebnisse verantwortlich sind, oder ob noch weitere vorhanden sind. Aufgrund von zusätzlichen Vergleichsmessungen mit einem kommerziellen Werkzeug (vgl. Kapitel 4) kann das Instrumenter-Plugin mit hoher Wahrscheinlichkeit als Ursache für die unterschiedlichen Messergebnisse ausgeschlossen werden. Denn das Instrumenter-Plugin liefert bei den Vergleichsmessungen stets die gleichen Ergebnisse wie das kommerzielle Werkzeug. 3.5 Adapter Die Adapter-Komponente dient nicht nur als gemeinsame Schnittstelle nach Außen für verschiedene innere Verfahren, sondern stellt zudem Hilfsklassen bereit, die von unterschiedlichen Verfahren genutzt werden können. 55

62 3.5.1 Schnittstellen «Schnittstelle» ICoverageListener +statechanged () +runstarted () +runtracecall () +runfinished () +annotationstarted () +annotationtracecall () +annotationfinished () * de.uni.hannover.se.coverage Singelton 1 UpdateInformer +getinstance() : UpdateInformer +firestatechanged () +firerunstarted () +firetracecall () +firerunfinished () +fireannotationstarted () +fireannotationtracecall () +fireannotationfinished () Abbildung 18: Adapter de.uni.hannover.se.coverage.internal Die Schnittstelle ICoverageRunListener und die Klasse UpdateInformer sind der Kern der Adapter-Komponente. Die Klasse UpdateInformer ist als Singelton implementiert, und dient als zentrale Instanz für die Anknüpfung des Tracer- und des Instrumenter-Plugins. Beide Plugins nutzen die UpdateInformer-Instanz, um interessierte Plugins über alle statischen und dynamischen Messdaten, sowie über die Erhebung der Messdaten zu informieren. Interessierte Plugins müssen die ICoverageListener-Schnittstelle implementieren und den Extension-Point des Adapter-Plugins benutzen. Jede fire-methode des UpdateInformers ruft das jeweilige pendant der registrierten ICoverageListener auf. Die Instantiierung und die Registrierung der über die Extensions bekannten Listener findet erst statt, wenn die Klasse UpdateInformer instantiiert wird. Dies ist der Fall, sobald eine der fire-methoden der Klasse UpdateInformer zum ersten mal aufgerufen wird. Auf diese Weise kann die zu frühe oder sogar unnötige Instantiierung der Listener und ihrer zugehöriger Plugins verhindert werden Messdaten Während der Analyse des Quellcodes werden folgende Daten erfasst und über die annotationtracecall-methode an die registrierten Listener weitergegeben: der Projektname 56

63 der projekt-relative Pfad der Quellcodedatei der ASTNode-Typ einer Methode oder Anweisung die Startposition einer Methode oder Anweisungen die Länge einer Methode oder Anweisungen die Zeilennummer einer Methode oder Anweisungen der Methodenname Zur Laufzeit einer Messung werden lediglich der Projektname, der Pfad der Quellcodedatei und die Id über die runtracecall-methode weitergereicht. Dabei entspricht die Id der Reihenfolge der analysierten Methoden oder Anweisungen bezogen auf eine Quellcodedatei Hilfsklassen Die Adapter-Komponente enthält drei Hilfsklassen: NatureUtils hilft beim Hinzufügen und Entfernen von Naturen eines Projektes. BuilderUtils hilft beim Hinzufügen und Entfernen von Buildern eines Projektes. CoverageFolderUtils bietet verschiedene Methoden an, um ein Unterverzeichnis in einem Projekt für die anfallenden Messdaten und, im Falle des Instrumenter-Plugins, für die instrumentierten Quellcodedateien zu verwalten Probleme Die erfassten Daten und die verwendeten Schnittstellen sind bereits recht umfangreich und für die Messung der Testabdeckung völlig ausreichend. Es ist jedoch vorstellbar, dass für bestimmte Anwendungen noch weitere Laufzeitinformationen benötigt werden, wie z. B. eine Indentifikationsnummer eines Objektes oder eines Threads. Solche speziellen Anforderungen können derzeit jedoch nur durch Anpassungen des Instrumenter- und/oder des Tracer-Plugins, sowie der bestehenden Schnittstellen erreicht werden. 3.6 Persistence Die Persistence-Komponente sammelt alle anfallenden Daten, die die ICoverageListener-Schnittstelle liefert und speichert diese persistent in einer Datenbank ab. Hierfür fordert die Klasse CoverageListenerImpl von der Klasse Database 57

64 Manager eine Datenbank mit der IDatabase-Schnittstelle an. Die Klasse DatabaseImpl implementiert diese Schnittstelle. Intern nutzt die Klasse DatabaseImpl die freie und objektorientierte DB4O-Datenbank 28. Der DatabaseManager verwaltet die Datenbanken auf Projektbasis, d.h. für jedes Projekt generiert der DatabaseManager eine separate Datenbank-Instanz. Das Persistence-Plugin stellt zudem die öffentliche Schnittstelle IPersistentCoverageDataListener, sowie einen Extension-Point bereit, den Plugins implementieren und verwenden können, um über neue oder geänderte Datensätze benachrichtigt zu werden. Die Klasse PersistentCoverageDatabaseManager ermöglicht den Zugriff auf eine projektbezogene Datenbank über die ICoverageDataHandle-Schnittstelle. Diese Schnittstelle hat nur einen Lese-Zugriff auf die Datenbank. Über den Lese-Zugriff können die Datensätze für die Quellcodedateien in Form von CoverageData-Objekten angefordert werden. Adapter «Schnittstelle» ICoverageListener Persistence CoverageListenerImpl DatabaseImpl uses db4o saves data requests database for project singleton DatabaseManager «Schnittstelle» IDatabase notificates about changes uses intern public «Schnittstelle» IPersistentCoverageDataListener provides CoverageData singleton PersistentCoverageDatabaseManager «Schnittstelle» ICoverageDataHandle provides Abbildung 19: Persistence-Plugin Abbildung 19 stellt die oben genannten Klassen des Persistence-Plugins dar und veranschaulicht die Beziehungen der Klassen zueinander. 28 Die DB4O-Datenbank ist über [34] beziehbar. Sie unterliegt der General Public Licence. 58

65 3.7 ResultView Das ResultView-Plugin präsentiert dem Benutzer die Ergebnisse einer Testabdeckungsmessung innerhalb der Eclipse UI. Es setzt auf der Persistence-Komponente auf. Um die View bei Änderung der Daten zu aktualisieren, implementiert das ResultView-Plugin den vom Persistence-Plugin bereitgestellten Extension-Point. Die zum Extension-Point zugehörige IPersistentCoverageDataListener-Schnittstelle wird von der Klasse CoverageViewPoper implementiert. Diese Klasse sorgt für das Erscheinen der CoverageResultView, sofern diese dem Benutzer noch nicht present ist, und benachrichtigt diese über Änderungen der Daten. Da die Klasse CoverageResultView den Workbench-View-Mechanismus nutzt, kann die CoverageResultView vom Benutzer jederzeit über das Menü Window > show View geöffnet werden. Die Klasse CoverageResultView dient sowohl als visueller Container für den SummeryDataViewProvider und den DetailsDataViewProvider, als auch als Manager dieser Komponenten. So stellt die CoverageResultView Aktionen zum Wechseln zwischen der tabellarischen Zusammenfassungsansicht des SummaryDataProviders und der Detailansicht des DetailDataViewProviders. Außerdem benachrichtigt die CoverageResultView alle ihr unterliegenden Komponenten über die Änderung von Daten. Die Komponenten greifen dann mittels des PersistentCoverageDatabaseManagers auf die persistenten Daten zu und aktualisieren sich selbst. Die Klasse MarkerCreator sorgt für die Markierung nicht ausgeführter Anweisungen im Quellcodeeditor. Abbildung 20 veranschaulicht die oben beschriebenen Klassen und Zusammenhänge. 59

66 «Schnittstelle» IPersistentCoverageDataListener CoverageResultViewPoper «eclipse mechanism» activates, updates CoverageResultView manages, shows, koordinates, updates SummaryDataViewProvider DetailDataViewProvider MarkerCreator Abbildung 20: ResultView-Plugin SummaryDataViewProvider Abbildung 21: SummaryDataView - Screenshot Der SummaryDataViewProvider stellt eine Zusammenfassung einer Messung der Testabdeckung für ein Projekt dar. Dafür benutzt es das Table-Widget des SWT, sowie den entsprechenden JFace-TableViewer für die Abbildung der Daten auf das Table-Widget. Abbildung 21 zeigt ein Screenshot einer solchen Zusammenfassung der Messdaten. 60

67 3.7.2 DetailsDataViewProvider Der DetailsDataViewProvider präsentiert dem Benutzer verschiedene Details einer Messung der Testabdeckung. Hierfür wird ein Tree-Widget des SWT benutzt. Für die Abbildung der Daten auf das Tree-Widget wird der JFace-TreeViewer verwendet. Über einen einfachen Filter können alle Anweisungen und Methoden ausgeblendet werden, die mindestens einmal ausgeführt wurden. Abbildung 22 zeigt ein Screenshot des DetailsDataViewProviders ohne aktivierten Filter. 29 Abbildung 22: DetailsDataView - Screenshot 3.8 Usability Die Verwendung des Instrumenter- und des Tracer-Plugins ist einfach. Um eines der beiden Plugins für ein Projekt einzuschalten, wird in der Package- oder Navigatorview über das Kontextmenü des betreffenden Projektes der Propertieseintrag ausgewählt. Daraufhin öffnet sich der Propertiesdialog, in dem sich der Instrumenter oder der Tracer aktivieren läßt. Nach der Aktivierung wird, sofern der automatische Build eingeschaltet ist, ein Build des gesamten Projektes ausgeführt. Dieser und alle nachfolgenden Builds dauern aufgrund der Analyse des Quellcodes und seiner Annotation länger als ohne Aktivierung des Instrumenters oder des Tracers. Dies ist für einen Benutzer vor allem bei einem vollständigen Build spürbar oder im Falle des Instrumenters bei sehr großen Quellcodedateien. (Vgl. Abschnitt 4) Ansonsten ändert sich für einen Benutzer während der Entwicklung eines Java Projektes nichts. Ein Projekt läßt sich mittels der Run As - und Debug As -Aktionen wie gewohnt starten. Erst nach der Ausführung eines Projektes erscheint dem Benutzer die ResultView mit den Ergebnissen der Testabdeckungsmessung. Da bisher kein Filter für die zu untersuchenden Quellcodedateien vorhanden ist, sollten die JUnit-Tests in ein separates Projekt ausgelagert werden, damit diese bei der Messung nicht mit erfasst werden. Dies 29 Bei einer schwarz-weißen Darstellung des Screenshots kommt vielleicht nicht zur Geltung, dass die Icons in der Ressource-Spalte sich farblich unterscheiden: bei Anweisungen und Methoden, die mindestens einmal ausgeführt wurden, sind die Icons grün, ansonsten gelb. 61

Trace- und Zeit-Zusicherungen beim Programmieren mit Vertrag

Trace- und Zeit-Zusicherungen beim Programmieren mit Vertrag Trace- und Zeit-Zusicherungen beim Programmieren mit Vertrag Mark Brörkens Universität Oldenburg, Fachbereich Informatik Email: Mark.Broerkens@informatik.uni-oldenburg.de Einleitung Programmieren mit Vertrag

Mehr

Übung: Verwendung von Java-Threads

Übung: Verwendung von Java-Threads Übung: Verwendung von Java-Threads Ziel der Übung: Diese Übung dient dazu, den Umgang mit Threads in der Programmiersprache Java kennenzulernen. Ein einfaches Java-Programm, das Threads nutzt, soll zum

Mehr

Session Beans & Servlet Integration. Ralf Gitzel ralf_gitzel@hotmail.de

Session Beans & Servlet Integration. Ralf Gitzel ralf_gitzel@hotmail.de s & Servlet Integration Ralf Gitzel ralf_gitzel@hotmail.de 1 Themenübersicht Ralf Gitzel ralf_gitzel@hotmail.de 2 Übersicht Motivation Das Interface Stateful und Stateless s Programmierung einer Stateful

Mehr

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Java Kurs für Anfänger Einheit 4 Klassen und Objekte Java Kurs für Anfänger Einheit 4 Klassen und Ludwig-Maximilians-Universität München (Institut für Informatik: Programmierung und Softwaretechnik von Prof.Wirsing) 13. Juni 2009 Inhaltsverzeichnis klasse

Mehr

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015 Software Engineering Zur Architektur der Applikation Data Repository Franz-Josef Elmer, Universität Basel, HS 2015 Software Engineering: Mit acht bewährten Praktiken zu gutem Code 2 Schichtarchitektur

Mehr

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7 Java 7 Elmar Fuchs Grundlagen Programmierung 1. Ausgabe, Dezember 2011 JAV7 5 Java 7 - Grundlagen Programmierung 5 Kontrollstrukturen In diesem Kapitel erfahren Sie wie Sie die Ausführung von von Bedingungen

Mehr

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren Lineargleichungssysteme: Additions-/ Subtraktionsverfahren W. Kippels 22. Februar 2014 Inhaltsverzeichnis 1 Einleitung 2 2 Lineargleichungssysteme zweiten Grades 2 3 Lineargleichungssysteme höheren als

Mehr

Hilfe Bearbeitung von Rahmenleistungsverzeichnissen

Hilfe Bearbeitung von Rahmenleistungsverzeichnissen Hilfe Bearbeitung von Rahmenleistungsverzeichnissen Allgemeine Hinweise Inhaltsverzeichnis 1 Allgemeine Hinweise... 3 1.1 Grundlagen...3 1.2 Erstellen und Bearbeiten eines Rahmen-Leistungsverzeichnisses...

Mehr

5. Tutorium zu Programmieren

5. Tutorium zu Programmieren 5. Tutorium zu Programmieren Dennis Ewert Gruppe 6 Universität Karlsruhe Institut für Programmstrukturen und Datenorganisation (IPD) Lehrstuhl Programmierparadigmen WS 2008/2009 c 2008 by IPD Snelting

Mehr

Software-Engineering und Optimierungsanwendungen in der Thermodynamik

Software-Engineering und Optimierungsanwendungen in der Thermodynamik Software-Engineering und Optimierungsanwendungen in der Thermodynamik Software-Engineering 5 Programmentwicklung und Debuggen mit IDE und CASE-Tools Übungen Prof. Dr. Rolf Dornberger OPTSWE_SWE: 5 Programmentwicklung

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Objektorientierte Programmierung 1 Geschichte Dahl, Nygaard: Simula 67 (Algol 60 + Objektorientierung) Kay et al.: Smalltalk (erste rein-objektorientierte Sprache) Object Pascal, Objective C, C++ (wiederum

Mehr

etutor Benutzerhandbuch XQuery Benutzerhandbuch Georg Nitsche

etutor Benutzerhandbuch XQuery Benutzerhandbuch Georg Nitsche etutor Benutzerhandbuch Benutzerhandbuch XQuery Georg Nitsche Version 1.0 Stand März 2006 Versionsverlauf: Version Autor Datum Änderungen 1.0 gn 06.03.2006 Fertigstellung der ersten Version Inhaltsverzeichnis:

Mehr

Technische Dokumentation SilentStatistikTool

Technische Dokumentation SilentStatistikTool Technische Dokumentation SilentStatistikTool Version 1.0 Marko Schröder 1115063 Inhalt Einleitung... 3 Klasse Program... 3 Klasse ArgumentHandler... 3 Bereitgestellte Variablen... 3 Bereitgestellte Methoden...

Mehr

J.5 Die Java Virtual Machine

J.5 Die Java Virtual Machine Java Virtual Machine Die Java Virtual Machine 22 Prof. Dr. Rainer Manthey Informatik II Java-Compiler und Java Virtual Machine Quellcode-Datei class C... javac D.java Java-Compiler - Dateien class class

Mehr

Einführung in die Programmierung

Einführung in die Programmierung : Inhalt Einführung in die Programmierung Wintersemester 2008/09 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund - mit / ohne Parameter - mit / ohne Rückgabewerte

Mehr

Einführung zum Arbeiten mit Microsoft Visual C++ 2010 Express Edition

Einführung zum Arbeiten mit Microsoft Visual C++ 2010 Express Edition In den nachfolgenden Schritten finden Sie beschrieben, wie Sie in der Entwicklungsumgebung Microsoft Visual Studio 2010 eine Projektmappe, ein Projekt und einen ersten Quellcode erstellen, diesen kompilieren,

Mehr

Einführung in die Programmierung

Einführung in die Programmierung Technische Universität München WS 2003/2004 Institut für Informatik Prof. Dr. Christoph Zenger Testklausur Einführung in die Programmierung Probeklausur Java (Lösungsvorschlag) 1 Die Klasse ArrayList In

Mehr

Tutorial. Bibliothek AutoGUITest V1.0. Windows-Benutzeroberflächen automatisiert testen. Ausgabe: 6.6.02. 06.06.02 / 13:51 Seite 1

Tutorial. Bibliothek AutoGUITest V1.0. Windows-Benutzeroberflächen automatisiert testen. Ausgabe: 6.6.02. 06.06.02 / 13:51 Seite 1 Bibliothek AutoGUITest V1.0 Windows-Benutzeroberflächen automatisiert testen Tutorial Ausgabe: 6.6.02 06.06.02 / 13:51 Seite 1 Inhalt 1 Übersicht...3 2 Funktionsweise...3 3 Funktionsumfang...3 4 Einsatz

Mehr

JetSym. Programmierung in Hochsprache ST nach IEC-61131-3. We automate your success.

JetSym. Programmierung in Hochsprache ST nach IEC-61131-3. We automate your success. JetSym Programmierung in Hochsprache ST nach IEC-61131-3 We automate your success. JetSym das Tool JetSym ist das zentrale Programmiertool der Jetter AG, das alle Funktionen der Automatisierungstechnik

Mehr

Mediator 9 - Lernprogramm

Mediator 9 - Lernprogramm Mediator 9 - Lernprogramm Ein Lernprogramm mit Mediator erstellen Mediator 9 bietet viele Möglichkeiten, CBT-Module (Computer Based Training = Computerunterstütztes Lernen) zu erstellen, z. B. Drag & Drop

Mehr

Java Virtual Machine (JVM) Bytecode

Java Virtual Machine (JVM) Bytecode Java Virtual Machine (JVM) durch Java-Interpreter (java) realisiert abstrakte Maschine = Softwareschicht zwischen Anwendung und Betriebssystem verantwortlich für Laden von Klassen, Ausführen des Bytecodes,

Mehr

Einführung in Javadoc

Einführung in Javadoc Einführung in Javadoc Johannes Rinn http://java.sun.com/j2se/javadoc Was ist Javadoc? Javadoc ist ein Werkzeug, dass eine standardisierte Dokumentation für die Programmiersprache Java unterstützt. Vorteil:

Mehr

Zwischenablage (Bilder, Texte,...)

Zwischenablage (Bilder, Texte,...) Zwischenablage was ist das? Informationen über. die Bedeutung der Windows-Zwischenablage Kopieren und Einfügen mit der Zwischenablage Vermeiden von Fehlern beim Arbeiten mit der Zwischenablage Bei diesen

Mehr

Rundung und Casting von Zahlen

Rundung und Casting von Zahlen W E R K S T A T T Rundung und Casting von Zahlen Intrexx 7.0 1. Einleitung In diesem Werkstattbeitrag erfahren Sie, wie Zahlenwerte speziell in Velocity, aber auch in Groovy, gerundet werden können. Für

Mehr

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {... PIWIN I Kap. 8 Objektorientierte Programmierung - Vererbung 31 Schlüsselwort: final Verhindert, dass eine Methode überschrieben wird public final int holekontostand() {... Erben von einer Klasse verbieten:

Mehr

Programmieren in Java

Programmieren in Java Programmieren in Java objektorientierte Programmierung 2 2 Zusammenhang Klasse-Datei In jeder *.java Datei kann es genau eine public-klasse geben wobei Klassen- und Dateiname übereinstimmen. Es können

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags keine Pommes... Praktikum A 230 C 207 (Madeleine + Esma) F 112 F 113

Mehr

5 DATEN. 5.1. Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

5 DATEN. 5.1. Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu Daten Makro + VBA effektiv 5 DATEN 5.1. Variablen Variablen können beliebige Werte zugewiesen und im Gegensatz zu Konstanten jederzeit im Programm verändert werden. Als Variablen können beliebige Zeichenketten

Mehr

WORKFLOW DESIGNDOKUMENT

WORKFLOW DESIGNDOKUMENT Architectural Design WORKFLOW DESIGNDOKUMENT Softwareentwicklung Praktikum, Übungsbeispiel 2 Gruppe 86 Andreas Hechenblaickner [0430217] Daniela Kejzar [0310129] Andreas Maller [0431289] Gruppe 86 Seite

Mehr

Wir arbeiten mit Zufallszahlen

Wir arbeiten mit Zufallszahlen Abb. 1: Bei Kartenspielen müssen zu Beginn die Karten zufällig ausgeteilt werden. Wir arbeiten mit Zufallszahlen Jedesmal wenn ein neues Patience-Spiel gestartet wird, muss das Computerprogramm die Karten

Mehr

Testen mit JUnit. Motivation

Testen mit JUnit. Motivation Test First Design for Test in Eclipse (eigentlich: ) zu einer Klasse Beispiel zur Demonstration Ergänzungen Test First "Immer dann, wenn Du in Versuchung kommst, etwas wie eine print- Anweisung oder einen

Mehr

The ToolChain.com. Grafisches Debugging mit der QtCreator Entwicklungsumgebung

The ToolChain.com. Grafisches Debugging mit der QtCreator Entwicklungsumgebung The ToolChain Grafisches Debugging mit der QtCreator Entwicklungsumgebung geschrieben von Gregor Rebel 2014-2015 Hintergrund Neben dem textuellen Debuggen in der Textkonsole bieten moderene Entwicklungsumgebungen

Mehr

Synchronisations- Assistent

Synchronisations- Assistent TimePunch Synchronisations- Assistent Benutzerhandbuch Gerhard Stephan Softwareentwicklung -und Vertrieb 25.08.2011 Dokumenten Information: Dokumenten-Name Benutzerhandbuch, Synchronisations-Assistent

Mehr

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen: VBA Programmierung mit Excel Schleifen 1/6 Erweiterung der Aufgabe Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen: Es müssen also 11 (B L) x 35 = 385 Zellen berücksichtigt

Mehr

ObjectBridge Java Edition

ObjectBridge Java Edition ObjectBridge Java Edition Als Bestandteil von SCORE Integration Suite stellt ObjectBridge Java Edition eine Verbindung von einem objektorientierten Java-Client zu einer fast beliebigen Server-Komponente

Mehr

Zählen von Objekten einer bestimmten Klasse

Zählen von Objekten einer bestimmten Klasse Zählen von Objekten einer bestimmten Klasse Ziel, Inhalt Zur Übung versuchen wir eine Klasse zu schreiben, mit der es möglich ist Objekte einer bestimmten Klasse zu zählen. Wir werden den ++ und den --

Mehr

2. ERSTELLEN VON APPS MIT DEM ADT PLUGIN VON ECLIPSE

2. ERSTELLEN VON APPS MIT DEM ADT PLUGIN VON ECLIPSE 2. ERSTELLEN VON APPS MIT DEM ADT PLUGIN VON ECLIPSE 2.1 Die Einrichtung der Benutzeroberfläche Das Einrichten einer Android-Eclipse-Entwicklungsumgebung zur Android-Entwicklung ist grundsätzlich nicht

Mehr

Handbuch. NAFI Online-Spezial. Kunden- / Datenverwaltung. 1. Auflage. (Stand: 24.09.2014)

Handbuch. NAFI Online-Spezial. Kunden- / Datenverwaltung. 1. Auflage. (Stand: 24.09.2014) Handbuch NAFI Online-Spezial 1. Auflage (Stand: 24.09.2014) Copyright 2016 by NAFI GmbH Unerlaubte Vervielfältigungen sind untersagt! Inhaltsangabe Einleitung... 3 Kundenauswahl... 3 Kunde hinzufügen...

Mehr

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff Programmieren in C Macros, Funktionen und modulare Programmstruktur Prof. Dr. Nikolaus Wulff Der C Präprozessor Vor einem Compile Lauf werden alle Präprozessor Kommandos/Makros ausgewertet. Diese sind

Mehr

Komponententest. Testen von Software Systemen. Übung 02 SS 2009 Version: 1.0 09.06.2009

Komponententest. Testen von Software Systemen. Übung 02 SS 2009 Version: 1.0 09.06.2009 Testen von Software Systemen Übung 02 SS 2009 Version: 1.0 09.06.2009 Komponententest Kunde: Dr. Reinhold Plösch Dr. Johannes Sametinger Kundenreferenz: 259.019 Team 19 Mitarbeiter: Christian Märzinger

Mehr

GITS Steckbriefe 1.9 - Tutorial

GITS Steckbriefe 1.9 - Tutorial Allgemeines Die Steckbriefkomponente basiert auf der CONTACTS XTD Komponente von Kurt Banfi, welche erheblich modifiziert bzw. angepasst wurde. Zuerst war nur eine kleine Änderung der Komponente für ein

Mehr

Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten

Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten 2008 netcadservice GmbH netcadservice GmbH Augustinerstraße 3 D-83395 Freilassing Dieses Programm ist urheberrechtlich geschützt. Eine Weitergabe

Mehr

Softwareentwicklungspraktikum Sommersemester 2007. Grobentwurf

Softwareentwicklungspraktikum Sommersemester 2007. Grobentwurf Softwareentwicklungspraktikum Sommersemester 2007 Grobentwurf Auftraggeber Technische Universität Braunschweig

Mehr

Einsatz von xalerator. bei den. Ergo Direkt Versicherungen. Bereich Versicherungstechnik/Leben

Einsatz von xalerator. bei den. Ergo Direkt Versicherungen. Bereich Versicherungstechnik/Leben Einsatz von xalerator bei den Ergo Direkt Versicherungen Bereich Versicherungstechnik/Leben Einführung Die Ergo Direkt Versicherungen wurden 1984 als Finanzdienstleistungs-Segment des Quelle Versandhandels

Mehr

Mastermind. Testplan. Hochschule Luzern Technik & Architektur. Programmieren 2 FS12. Gruppe 10

Mastermind. Testplan. Hochschule Luzern Technik & Architektur. Programmieren 2 FS12. Gruppe 10 Testplan Programmieren 2 FS12 Gruppe 10 Redzepi Iljasa Reichmuth Marco Rey Philipp Rohrer Felix Eine interdisziplinäre Projektarbeit der Studiengänge Elektrotechnik und Informatik. Horw, 11.05.2012 Autoren

Mehr

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen Binäre Bäume 1. Allgemeines Binäre Bäume werden grundsätzlich verwendet, um Zahlen der Größe nach, oder Wörter dem Alphabet nach zu sortieren. Dem einfacheren Verständnis zu Liebe werde ich mich hier besonders

Mehr

Flashfragen in ILIAS Test & Assessment. Helmut Schottmüller

Flashfragen in ILIAS Test & Assessment. Helmut Schottmüller Flashfragen in ILIAS Test & Assessment Helmut Schottmüller Flashfragen in ILIAS Test & Assessment Helmut Schottmüller Veröffentlicht Januar 2009 Copyright 2009 Helmut Schottmüller Inhaltsverzeichnis 1.

Mehr

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version 1.0.0. 23. September 2015 - 1 -

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version 1.0.0. 23. September 2015 - 1 - Matrix42 Use Case - Sicherung und Rücksicherung persönlicher Version 1.0.0 23. September 2015-1 - Inhaltsverzeichnis 1 Einleitung 3 1.1 Beschreibung 3 1.2 Vorbereitung 3 1.3 Ziel 3 2 Use Case 4-2 - 1 Einleitung

Mehr

1 Mathematische Grundlagen

1 Mathematische Grundlagen Mathematische Grundlagen - 1-1 Mathematische Grundlagen Der Begriff der Menge ist einer der grundlegenden Begriffe in der Mathematik. Mengen dienen dazu, Dinge oder Objekte zu einer Einheit zusammenzufassen.

Mehr

MCRServlet Table of contents

MCRServlet Table of contents Table of contents 1 Das Zusammenspiel der Servlets mit dem MCRServlet... 2 1 Das Zusammenspiel der Servlets mit dem MCRServlet Als übergeordnetes Servlet mit einigen grundlegenden Funktionalitäten dient

Mehr

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1 CMS.R. Bedienungsanleitung Modul Cron Revision 1 Copyright 10.09.2009 www.sruttloff.de CMS.R. - 1 - WOZU CRON...3 VERWENDUNG...3 EINSTELLUNGEN...5 TASK ERSTELLEN / BEARBEITEN...6 RECHTE...7 EREIGNISSE...7

Mehr

C# im Vergleich zu Java

C# im Vergleich zu Java C# im Vergleich zu Java Serhad Ilgün Seminar Universität Dortmund SS 03 Gliederung Entstehung von C# und Java Überblick von C# und Java Unterschiede und Gemeinsamkeiten Zusammenfassung und Ausblick Entstehung

Mehr

1 topologisches Sortieren

1 topologisches Sortieren Wolfgang Hönig / Andreas Ecke WS 09/0 topologisches Sortieren. Überblick. Solange noch Knoten vorhanden: a) Suche Knoten v, zu dem keine Kante führt (Falls nicht vorhanden keine topologische Sortierung

Mehr

mobilepoi 0.91 Demo Version Anleitung Das Software Studio Christian Efinger Erstellt am 21. Oktober 2005

mobilepoi 0.91 Demo Version Anleitung Das Software Studio Christian Efinger Erstellt am 21. Oktober 2005 Das Software Studio Christian Efinger mobilepoi 0.91 Demo Version Anleitung Erstellt am 21. Oktober 2005 Kontakt: Das Software Studio Christian Efinger ce@efinger-online.de Inhalt 1. Einführung... 3 2.

Mehr

Vererbung & Schnittstellen in C#

Vererbung & Schnittstellen in C# Vererbung & Schnittstellen in C# Inhaltsübersicht - Vorüberlegung - Vererbung - Schnittstellenklassen - Zusammenfassung 1 Vorüberlegung Wozu benötigt man Vererbung überhaubt? 1.Um Zeit zu sparen! Verwendung

Mehr

Delegatesund Ereignisse

Delegatesund Ereignisse Delegatesund Ereignisse «Delegierter» Methoden Schablone Funktionszeiger Dr. Beatrice Amrhein Überblick Definition eines Delegat Einfache Delegate Beispiele von Delegat-Anwendungen Definition eines Ereignisses

Mehr

Javakurs zu Informatik I. Henning Heitkötter

Javakurs zu Informatik I. Henning Heitkötter Javakurs zu Informatik I Arrays vergleichen Implementieren Sie folgende Methode, die prüft, ob die Elemente der beiden Arrays an jeder Position übereinstimmen: public static boolean identisch(int[] a,

Mehr

Erwin Grüner 09.02.2006

Erwin Grüner 09.02.2006 FB Psychologie Uni Marburg 09.02.2006 Themenübersicht Folgende Befehle stehen in R zur Verfügung: {}: Anweisungsblock if: Bedingte Anweisung switch: Fallunterscheidung repeat-schleife while-schleife for-schleife

Mehr

Programmierparadigmen. Programmierparadigmen. Imperatives vs. objektorientiertes Programmieren. Programmierparadigmen. Agenda für heute, 4.

Programmierparadigmen. Programmierparadigmen. Imperatives vs. objektorientiertes Programmieren. Programmierparadigmen. Agenda für heute, 4. Agenda für heute, 4. Mai, 2006 Programmierparadigmen Imperative Programmiersprachen In Prozeduren zusammengefasste, sequentiell ausgeführte Anweisungen Die Prozeduren werden ausgeführt, wenn sie als Teil

Mehr

Produktskizze. 28. November 2005 Projektgruppe Syspect

Produktskizze. 28. November 2005 Projektgruppe Syspect 28. November 2005 Carl von Ossietzky Universität Oldenburg Fakultät II Department für Informatik Abteilung Entwicklung korrekter Systeme Inhaltsverzeichnis 1 Einleitung 3 2 Die graphische Oberfläche der

Mehr

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007 Fachhochschule Bonn-Rhein-Sieg University of Applied Sciences Fachbereich Informatik Prof. Dr. Peter Becker Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Mehr

Vorlesung Informatik II

Vorlesung Informatik II Vorlesung Informatik II Universität Augsburg Wintersemester 2011/2012 Prof. Dr. Bernhard Bauer Folien von: Prof. Dr. Robert Lorenz Lehrprofessur für Informatik 02. JAVA: Erstes Programm 1 Das erste Java-Programm

Mehr

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein. Schritt 1: Installation des Javacompilers JDK. Der erste Start mit Eclipse Bevor Sie den Java-Compiler installieren sollten Sie sich vergewissern, ob er eventuell schon installiert ist. Gehen sie wie folgt

Mehr

Bedienungsanleitung: Onlineverifizierung von qualifiziert signierten PDF-Dateien

Bedienungsanleitung: Onlineverifizierung von qualifiziert signierten PDF-Dateien Sie haben von der VR DISKONTBANK GmbH ein signiertes PDF-Dokument (i.d.r. eine Zentralregulierungsliste mit dem Status einer offiziellen Rechnung) erhalten und möchten nun die Signatur verifizieren, um

Mehr

Arbeiten mit UMLed und Delphi

Arbeiten mit UMLed und Delphi Arbeiten mit UMLed und Delphi Diese Anleitung soll zeigen, wie man Klassen mit dem UML ( Unified Modeling Language ) Editor UMLed erstellt, in Delphi exportiert und dort so einbindet, dass diese (bis auf

Mehr

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss Systeme 1 Kapitel 6 Nebenläufigkeit und wechselseitiger Ausschluss Threads Die Adressräume verschiedener Prozesse sind getrennt und geschützt gegen den Zugriff anderer Prozesse. Threads sind leichtgewichtige

Mehr

Programmierkurs Java

Programmierkurs Java Programmierkurs Java Dr. Dietrich Boles Aufgaben zu UE16-Rekursion (Stand 09.12.2011) Aufgabe 1: Implementieren Sie in Java ein Programm, das solange einzelne Zeichen vom Terminal einliest, bis ein #-Zeichen

Mehr

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten Version 1.0 Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten In unserer Anleitung zeigen wir Dir, wie Du Blogbeiträge

Mehr

Java und XML 2. Java und XML

Java und XML 2. Java und XML Technische Universität Ilmenau Fakultät für Informatik und Automatisierung Institut für Praktische Informatik und Medieninformatik Fachgebiet Telematik Java und XML Hauptseminar Telematik WS 2002/2003

Mehr

Gemeinsamer Bibliotheksverbund: Übertragung von Datenexporten für den Verbundkatalog Öffentlicher Bibliotheken

Gemeinsamer Bibliotheksverbund: Übertragung von Datenexporten für den Verbundkatalog Öffentlicher Bibliotheken Gemeinsamer Bibliotheksverbund: Übertragung von Datenexporten für den Verbundkatalog Öffentlicher Bibliotheken Mit Anleitung zur Erstellung einer FTP Verbindung unter Windows 7 Matthias Lange

Mehr

Mandant in den einzelnen Anwendungen löschen

Mandant in den einzelnen Anwendungen löschen Mandant in den einzelnen Anwendungen löschen Bereich: ALLGEMEIN - Info für Anwender Nr. 6056 Inhaltsverzeichnis 1. Allgemein 2. FIBU/ANLAG/ZAHLUNG/BILANZ/LOHN/BELEGTRANSFER 3. DMS 4. STEUERN 5. FRISTEN

Mehr

Anzeige von eingescannten Rechnungen

Anzeige von eingescannten Rechnungen Anzeige von eingescannten Rechnungen Wenn Sie sich zu einer Eingangsrechnung die eingescannte Originalrechnung ansehen möchten, wählen Sie als ersten Schritt aus Ihrem Benutzermenü unter dem Kapitel Eingangsrechnung

Mehr

Propädeutikum. Dipl.-Inf. Frank Güttler

Propädeutikum. Dipl.-Inf. Frank Güttler Propädeutikum 2015 Vorbereitungskurs Informatikstudium Erfolgreich Studieren Programmieren (C-Kurs) guettler@informatik.uni-leipzig.de Universität Leipzig Institut für Informatik Technische Informatik

Mehr

Java Kurs für Anfänger Einheit 5 Methoden

Java Kurs für Anfänger Einheit 5 Methoden Java Kurs für Anfänger Einheit 5 Methoden Ludwig-Maximilians-Universität München (Institut für Informatik: Programmierung und Softwaretechnik von Prof.Wirsing) 22. Juni 2009 Inhaltsverzeichnis Methoden

Mehr

DIE ANWENDUNG VON KENNZAHLEN IN DER PRAXIS: WEBMARK SEILBAHNEN IM EINSATZ

DIE ANWENDUNG VON KENNZAHLEN IN DER PRAXIS: WEBMARK SEILBAHNEN IM EINSATZ Kurzfassung DIE ANWENDUNG VON KENNZAHLEN IN DER PRAXIS: WEBMARK SEILBAHNEN IM EINSATZ Mag. Klaus Grabler 9. Oktober 2002 OITAF Seminar 2002 Kongresshaus Innsbruck K ennzahlen sind ein wesentliches Instrument

Mehr

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang sysplus.ch outlook - mail-grundlagen Seite 1/8 Outlook Mail-Grundlagen Posteingang Es gibt verschiedene Möglichkeiten, um zum Posteingang zu gelangen. Man kann links im Outlook-Fenster auf die Schaltfläche

Mehr

Anton Ochsenkühn. amac BUCH VERLAG. Ecxel 2016. für Mac. amac-buch Verlag

Anton Ochsenkühn. amac BUCH VERLAG. Ecxel 2016. für Mac. amac-buch Verlag Anton Ochsenkühn amac BUCH VERLAG Ecxel 2016 für Mac amac-buch Verlag 2 Word-Dokumentenkatalog! Zudem können unterhalb von Neu noch Zuletzt verwendet eingeblendet werden. Damit hat der Anwender einen sehr

Mehr

Step by Step Softwareverteilung unter Novell. von Christian Bartl

Step by Step Softwareverteilung unter Novell. von Christian Bartl Step by Step Softwareverteilung unter Novell von Softwareverteilung unter Novell 1) Starten von einfachen *.EXE-Dateien: Starten sie ConsoleOne Erstellen sie eine eigene Organisationseinheit für ihre Anwendungen

Mehr

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom 21.10.2013b

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom 21.10.2013b AGROPLUS Buchhaltung Daten-Server und Sicherheitskopie Version vom 21.10.2013b 3a) Der Daten-Server Modus und der Tresor Der Daten-Server ist eine Betriebsart welche dem Nutzer eine grosse Flexibilität

Mehr

Programmierkurs Java

Programmierkurs Java Programmierkurs Java Konstruktor, Statische Methoden Packages Prof. Dr. Stefan Fischer Institut für Telematik, Universität zu Lübeck http://www.itm.uni-luebeck.de/people/fischer Initialisierung von Datenstrukturen

Mehr

SEP 114. Design by Contract

SEP 114. Design by Contract Design by Contract SEP 114 Design by Contract Teile das zu entwickelnde Programm in kleine Einheiten (Klassen, Methoden), die unabhängig voneinander entwickelt und überprüft werden können. Einheiten mit

Mehr

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag Ludwig-Maximilians-Universität München WS 2015/16 Institut für Informatik Übungsblatt 13 Prof. Dr. R. Hennicker, A. Klarl Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung:

Mehr

Modellierung und Programmierung 1

Modellierung und Programmierung 1 Modellierung und Programmierung 1 Prof. Dr. Sonja Prohaska Computational EvoDevo Group Institut für Informatik Universität Leipzig 19. November 2015 Gültigkeitsbereich (Scope) von Variablen { int m; {

Mehr

4 Aufzählungen und Listen erstellen

4 Aufzählungen und Listen erstellen 4 4 Aufzählungen und Listen erstellen Beim Strukturieren von Dokumenten und Inhalten stellen Listen und Aufzählungen wichtige Werkzeuge dar. Mit ihnen lässt sich so ziemlich alles sortieren, was auf einer

Mehr

Dokumentation IBIS Monitor

Dokumentation IBIS Monitor Dokumentation IBIS Monitor Seite 1 von 16 11.01.06 Inhaltsverzeichnis 1. Allgemein 2. Installation und Programm starten 3. Programmkonfiguration 4. Aufzeichnung 4.1 Aufzeichnung mitschneiden 4.1.1 Inhalt

Mehr

Abschnitt 12: Strukturierung von Java-Programmen: Packages

Abschnitt 12: Strukturierung von Java-Programmen: Packages Abschnitt 12: Strukturierung von Java-Programmen: Packages 12. Strukturierung von Java-Programmen: Packages 12.1 Strukturierung durch Packages 12.2 Zugriffsspezifikationen 12.3 Zusammenfassung 12 Strukturierung

Mehr

Erstellung von Reports mit Anwender-Dokumentation und System-Dokumentation in der ArtemiS SUITE (ab Version 5.0)

Erstellung von Reports mit Anwender-Dokumentation und System-Dokumentation in der ArtemiS SUITE (ab Version 5.0) Erstellung von und System-Dokumentation in der ArtemiS SUITE (ab Version 5.0) In der ArtemiS SUITE steht eine neue, sehr flexible Reporting-Funktion zur Verfügung, die mit der Version 5.0 noch einmal verbessert

Mehr

4. BEZIEHUNGEN ZWISCHEN TABELLEN

4. BEZIEHUNGEN ZWISCHEN TABELLEN 4. BEZIEHUNGEN ZWISCHEN TABELLEN Zwischen Tabellen können in MS Access Beziehungen bestehen. Durch das Verwenden von Tabellen, die zueinander in Beziehung stehen, können Sie Folgendes erreichen: Die Größe

Mehr

ec@ros2-installer ecaros2 Installer procar informatik AG 1 Stand: FS 09/2012 Eschenweg 7 64331 Weiterstadt

ec@ros2-installer ecaros2 Installer procar informatik AG 1 Stand: FS 09/2012 Eschenweg 7 64331 Weiterstadt ecaros2 Installer procar informatik AG 1 Stand: FS 09/2012 Inhaltsverzeichnis 1 Download des ecaros2-installer...3 2 Aufruf des ecaros2-installer...3 2.1 Konsolen-Fenster (Windows)...3 2.2 Konsolen-Fenster

Mehr

Informationen zur Verwendung von Visual Studio und cmake

Informationen zur Verwendung von Visual Studio und cmake Inhaltsverzeichnis Informationen zur Verwendung von Visual Studio und cmake... 2 Erste Schritte mit Visual Studio... 2 Einstellungen für Visual Studio 2013... 2 Nutzung von cmake... 6 Installation von

Mehr

Folge 18 - Vererbung

Folge 18 - Vererbung Workshop Folge 18 - Vererbung 18.1 Ein einfacher Fall der Vererbung Schritt 1 - Vorbereitungen Besorgen Sie sich - vielleicht aus einer der Übungen der Folge 17 - ein fertiges und lauffähiges Listenprojekt,

Mehr

Ihr IT-Administrator oder unser Support wird Ihnen im Zweifelsfall gerne weiterhelfen.

Ihr IT-Administrator oder unser Support wird Ihnen im Zweifelsfall gerne weiterhelfen. Dieses Dokument beschreibt die nötigen Schritte für den Umstieg des von AMS.4 eingesetzten Firebird-Datenbankservers auf die Version 2.5. Beachten Sie dabei, dass diese Schritte nur bei einer Server-Installation

Mehr

Abschluss Version 1.0

Abschluss Version 1.0 Beschreibung Der Abschluss wird normalerweise nur einmal jährlich durchgeführt. Dieses Tech-Note soll helfen, diesen doch seltenen aber periodisch notwendigen Vorgang problemlos durchzuführen. Abschlussvarianten

Mehr

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005 Einführung in die objektorientierte Programmierung mit Java Klausur am 19. Oktober 2005 Matrikelnummer: Nachname: Vorname: Semesteranzahl: Die Klausur besteht aus drei Frageblöcken zu den Inhalten der

Mehr

Handbuch ECDL 2003 Basic Modul 5: Datenbank Access starten und neue Datenbank anlegen

Handbuch ECDL 2003 Basic Modul 5: Datenbank Access starten und neue Datenbank anlegen Handbuch ECDL 2003 Basic Modul 5: Datenbank Access starten und neue Datenbank anlegen Dateiname: ecdl5_01_02_documentation_standard.doc Speicherdatum: 14.02.2005 ECDL 2003 Basic Modul 5 Datenbank - Access

Mehr

Lizenzierung von SharePoint Server 2013

Lizenzierung von SharePoint Server 2013 Lizenzierung von SharePoint Server 2013 Das Lizenzmodell von SharePoint Server 2013 besteht aus zwei Komponenten: Serverlizenzen zur Lizenzierung der Serversoftware und CALs zur Lizenzierung der Zugriffe

Mehr

Kapitel 4 Die Datenbank Kuchenbestellung Seite 1

Kapitel 4 Die Datenbank Kuchenbestellung Seite 1 Kapitel 4 Die Datenbank Kuchenbestellung Seite 1 4 Die Datenbank Kuchenbestellung In diesem Kapitel werde ich die Theorie aus Kapitel 2 Die Datenbank Buchausleihe an Hand einer weiteren Datenbank Kuchenbestellung

Mehr

Vorkurs Informatik WiSe 15/16

Vorkurs Informatik WiSe 15/16 Java 1 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe, 12.10.2015 Technische Universität Braunschweig, IPS Überblick Organisatorisches Arbeitsablauf Hello! 12.10.2015 Dr. Werner Struckmann / Stephan

Mehr

Implementation of a Framework Component for Processing Tasks within Threads on the Application Level

Implementation of a Framework Component for Processing Tasks within Threads on the Application Level Implementation of a Framework Component for Processing Tasks within Threads on the Application Level Deutsches Krebsforschungszentrum, for Processing Task within Threads on the Application Level Motivation

Mehr