Artikel

 
März 2009 | Artikel

Tutorial: Build-Umgebungen harmonisieren mit Eclipse

(Link zum Artikel: http://www.it-republik.de/jaxenter/artikel/2195)

Harmonischer Gleichklang: Classpath-Container zur Integration verschiedener Build-Umgebungen

Text: Dominik Hirt
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
In vielen Projekten existieren neben dem offiziellen Build-Prozess, der für das Erstellen der gesamten, unternehmensweiten Anwendung verantwortlich ist, die Build-Informationen der IDE des Entwicklers. Grundsätzlich sollte aber auch hier das Single-Source-Prinzip gelten, die notwendige Information nur an einer Stelle hinterlegt sein. Dieser Artikel zeigt einen Weg auf, mithilfe von Classpath-Containern dieses Ziel zu erreichen und die Arbeit für den Entwickler zu erleichtern.
Teil 1   Teil 2   Teil 3   

Wer kennt das nicht: Gerade im Anfangsstadium eines Softwareprojekts ist noch vieles im Fluss und ständige Änderungen sind an der Tagesordnung: Welche Softwarekomponenten benötigt mein Beitrag noch, wollen wir nicht doch noch auf dieses neue Open Source Framework wechseln usw. Die Settings für den Classpath sind so wechselhaft wie das Wetter im Hochgebirge. Neben den Einstellungen in der eigenen IDE muss auch der zumeist ANT-basierte Build-Prozess der Gesamtanwendung zufrieden gestellt, sprich mit den richtigen Einstellungen versehen werden. An dieser Stelle sind also die gleichen Informationen an mindestens zwei Stellen zu pflegen. Hier bemerkt der aufmerksame Entwickler sofort ein bekanntes Muster, den Hinweis von Hunt und David aus ihrem "Pragmatischen Programmierer" [1], sich doch bitte nicht selbst zu wiederholen, eine Informationen an einer Stelle zu hinterlegen, und nur dort. Doch wie soll man diese beiden Welten miteinander verheiraten?

Der erste Wurf
Als gläubiger Eclipse-Jünger will man natürlich gleich den Berg zum Propheten bringen: Mithilfe von ant4eclipse [2] ist es möglich, aus jedem normalen ANT-basierten Build-Prozess die Classpath-Informationen zu benutzten, die Eclipse für seine Projekte in den .classpath-Dateien vorhält. Das funktioniert gut, wenn man mit einem Projekt startet, alle Entwickler Eclipse verwenden und der Build-Prozess der Gesamtanwendung auf diese Art und Weise gestaltet wurde. Im vorliegenden Fall traf jedoch keine dieser Voraussetzungen zu: Das Gesamtprojekt, ProClassic/Enterprise (PC/E) ist eine J2EE-Anwendung für den SB-Kanal von Banken mit Filialnetzwerken (Retail Banking). Die Anwendung besteht aus ca. 100 einzelnen Komponenten, die von einem verteilten Entwicklungsteam erstellt und gepflegt werden. Dabei soll es auch noch Entwickler geben, die nicht Eclipse benutzen. Alle Komponenten nutzen den seit Langem etablierten ANT-basierten Build-Prozess. Diesen auf ant4eclipse umzustellen, kam daher nicht in Frage. Der Prophet musste also zum Berg: Die Eclipse-Projekte sollen die Classpath-Informationen aus dem existierenden Build-Prozess beziehen. Dieser sieht für jede Komponente eine Datei projectbuild.properties vor. In dieser Datei, die im antfile.xml als property-File eingebunden ist, wird der Classpath definiert. Listing 1 zeigt die Ausgangslage in Form einer bestehenden Datei aus diesem Build-Prozess.

Listing 1
  1. classpath=${pce.lib.dir}/PceClientBase.jar;\
  2. ${pce.lib.dir}/PceBaseFlow.jar;\
  3. ${pce.lib.dir}/PCEBusinessDomain.jar;\
  4. ${pce.lib.dir}/PCESmartClientConnector.jar;\
  5. ${jakarta-oro.jarfile};\
  6. ${uka.jarfile}


Die benutzten Variablen werden von ANT aus anderen, hierarchisch eingebundenen property-Files aufgelöst oder programmatisch durch eigene ANT-Tasks (um-)gesetzt. Nachdem somit die Ausgangslage klar ist, wird nun ein Weg benötigt, diese Informationen den Eclipse-Projekten zur Verfügung zu stellen. Diesem Weg ist dieser Artikel gewidmet. Sie erfahren hier, in welcher Form innerhalb von Eclipse mit Classpath-Informationen umgegangen wird. Danach wird eine Möglichkeit aufgezeigt, diese Informationen von einer externen Quelle zu ermitteln und den Java-Projekten zur Verfügung zu stellen. Schließlich wird noch gezeigt, wie Veränderungen an dieser externen Quelle festgestellt und die Projekte entsprechend aktualisiert werden. Beginnen wir mit einem kurzen Ausflug ins Eclipse-Universum und dazu, wie hier Information zum Classpath vorgehalten werden.

Classpath Entries
Jedes Java-Projekt definiert seinen Classpath in einer Datei .classpath im Root des Projekts. In dieser Datei werden verschiedene Typen von Einträgen benutzt, um den Classpath zu definieren. Insgesamt gibt es fünf Typen, die alle in org.eclipse.jdt.core.IClasspathEntry definiert sind:

  • Library – eine Bibliothek, also ein jar-File
  • Project – ein anderes Eclipse-Projekt
  • Source – ein Verzeichnis mit Quellcode
  • Variable – ein Pfad, der mit einer der Classpath-Variablen beginnt, die im Workspace deklariert wurden
  • Container – eine Sammlung von jar-Files, Projekten und Variablen unter einem gemeinsamen Namen

Diese Typisierung findet sich auch im Eclipse User Interface wieder: Schauen Sie auf die ersten drei Tabulatoren/Reiter des Dialogs zum Einstellen des Java Build Path für ein Projekt. Der Classpath eines Java-Projekts kann sich aus diesen Typen zusammensetzten. Besonders jedoch der letzte Typ, der so genannte Classpath-Container, ist interessant, da dieser programmatisch definiert und verändert werden kann. Er erscheint somit als geeigneter Kandidat, um das gewünschte Ziel zu erreichen, den Bezug der Classpath-Informationen für Java-Projekte zu externalisieren. Schauen wir uns also diesen Typ etwas genauer an.

Classpath-Container
Sie sind alle schon einmal mit einem speziellen Classpath-Container in Berührung gekommen: der JRE System Library. Hierunter werden die Systembibliotheken der benutzten JRE verwaltet. Ein anderes Beispiel ist der Classpath für JUnit. Auch hierfür stellt das JUnit-Plug-in einen Classpath-Container zur Verfügung. Der dynamische Aspekt, der mit einem Container erreicht werden kann, zeigt sich hier bereits: Auf dem Dialog mit den Einstellungen, der so genannten Container Page, ist es möglich, sich zwischen einzelnen Versionen von JUnit zu entscheiden. Erst in Abhängigkeit dieser Entscheidung wird der Classpath aufgebaut, der dann als JUNIT_CONTAINER den Projekten zur Verfügung gestellt wird.

Ein Classpath-Container stellt eine logische Referenz auf eine Sammlung von Classpath Entries zur Verfügung. Für die Entries selbst können die vier Entry-Typen Library, Source, Project oder Variable genutzt werden. Diese Menge von Classpath Entries wird als Container einem Java-Projekt zugewiesen und hilft somit, die abhängigen Referenzen zu strukturieren. Das wird auch im Package Explorer deutlich (Abb. 1). Alle Classpath Entries lassen sich unter dem Namen des Containers einklappen und verbergen. Die Ansicht erscheint damit übersichtlicher.

Im Gegensatz zu den User Libraries (Kasten: "Container und Libraries") werden keinerlei plattformspezifische Pfade gespeichert, was die Benutzung von Containern sehr portabel werden lässt. Die .classpath-Dateien können im Source Control Management eingecheckt und von allen Entwicklern genutzt werden. Die größten Vorteile gegenüber allen anderen Typen von Classpath Entries sind aber Dynamik und Programmatik. Keine der Informationen über die Containereinträge werden in irgendeiner Form im Workspace oder im Projekt gespeichert. Erst in dem Moment, in dem sie wirklich benötigt werden, z.B. zum Zeitpunkt des Kompilierens eines Java-Projekts, werden die Classpath-Container nach ihren Einträgen befragt. Die dazu notwendige Logik wird in Java programmiert.

Container und Libraries
Die Bezeichnungen innerhalb Eclipse werden nicht ganz konsistent gebraucht und wechseln zwischen Library und Container. Als Richtschnur kann gelten, dass nach außen hin häufiger von Library gesprochen wird, wenn intern ein Classpath-Container benutzt wird. Auch der Button zum Hinzufügen eines Containers ist mit Add Library beschriftet. Die User Libraries sind ein dem Classpath-Container verwandtes Prinzip. User Libraries können unter WINDOW | PREFERENCES | JAVA | BUILD PATH | USER LIBRARIES verwaltet werden. Eine User Library stellt eine Liste von Archiven (jarfiles etc.) unter einem gemeinsamen Namen zur Verfügung. Diese kann dann dem Build Path eines Java-Projekts zugewiesen werden. Die Liste der Archive ist jedoch rein statisch. Sie wird über einen Dialog mit Auswahlmöglichkeit auf jar- oder zip-Dateien erstellt. In den prefs-Dateien des Core Plug-ins org.eclipse.jdt.core werden die absoluten Pfade abgespeichert. Ist eine solche User Library also Änderungen unterworfen, müssen diese manuell über das UI nachgepflegt werden. Im Gegensatz dazu sind Classpath-Container dynamisch. Da sie programmatisch erstellt sind, stehen völlig andere Möglichkeiten zur Verfügung. Außerdem beginnt Eclipse erst zu dem Zeitpunkt, da ein Container durch ein konkretes Projekt benötigt wird, mit dem Produktionsprozess. Dem Container können nun beliebige Einträge hinzugefügt werden. Lazy-Loading also auch auf dieser Ebene.

Wenn es also gelingt, einen solchen Container zu etablieren und ihn mit Werten aus dem projectbuild.properties zu füllen, ist das Ziel fast erreicht. Es ist außerdem notwendig, diesen Container in den Java-Build-Path-Einstellungen dem Projekt hinzuzufügen. Wir müssen also Eclipse um einen Classpath-Container erweitern.

Teil 1   Teil 2   Teil 3   

Anzeige

Kommentare

Gravatar Edgar 19.03.2009
um 07:52 Uhr
Ich denke, dass sich für größere Projekte auch ein Blick auf Maven2 lohnt. Alleine das Dependency-Management würde einen Umstieg rechtfertigen. Man bekommt aber noch so viel mit dazu ...
MfG
Edgar
#zitieren
Gravatar Michael 20.03.2009
um 12:27 Uhr
Neben Maven2 sollte auch immer Ant + Ivy genannt werden.

Ausserdem ist es mit Hilfe von ant-eclipse [1] möglich die .classpath aus Ant Paths zu generieren.

[1] http://ant-eclipse.sourceforge.net/
#zitieren
Gravatar Zardosht 12.02.2010
um 11:21 Uhr
Hi,
why don't you contribute this to eclipse?
One of the most requested (but not yet implemented) features of eclipse is to make User Libraries protable, in a way that they can contain relative paths instead of absolute paths.
This could actually be another solution to this problem.
#zitieren

Anzeige

zurück zum Seitenanfang