Ratgeber

Equinox modernisiert Java-Legacy

09.11.2010 von Jörg Viola
Ältere Java-Systeme lassen sich zum Teil kaum noch beherrschen. Die OSGi-Implementierung Equinox hilft bei der Modernisierung.

Der objektorientierte Entwurf und die OO-Programmierung brachten eine Verheißung in die Szene der 80er Jahre: Information Hiding. Daten sollen nur dort gehalten werden, wo man sie wirklich braucht, und nur die passende Logik soll Zugriff darauf haben. Beides wird zusammen in einem Objekt untergebracht. Ein wohldefiniertes Interface stellt die Operationen nach außen zur Verfügung. Mit einem solchen Softwaredesign steht und fällt die Wartbarkeit einer jeden Anwendung.

Doch zwei Jahrzehnte später lassen viele Änderungen, Bugfixes und Release-Zyklen von den ursprünglichen Ideen und Strukturen aus der Erstellungsphase kaum noch etwas erkennen. Es sind Softwaresysteme entstanden, die aus Tausenden von Klassen und zur Laufzeit aus Millionen von Objekten bestehen. Darüber hinaus kann prinzipiell jedes Objekt die Schnittstelle jedes anderen benutzen. Kein Entwickler ist in der Lage, hier die Übersicht zu behalten.

Trends in Java-Projekten
Ältere Java-Versionen sind beliebt
Obwohl die heute <b>aktuelle Version 6</b> nun schon seit zwei Jahren verfügbar ist, wird eine Vielzahl von Projekten noch mit älteren Ausführungen betrieben. Die Abbildung zeigt, dass die vorletzte Version (<b>JDK 5 von 2004</b>) immer noch die größte Verbreitung hat und häufig eingesetzt wird. Die Version 6 wird hauptsächlich in neuen Projekten eingesetzt. <br/> Der Hauptgrund dürfe in dem nicht zu unterschätzenden <b>Migrationsaufwand</b> beim Umstieg auf eine neue Java-Version liegen. Eine Strategie könnte daher sein, Inkompatibilitäten zu identifizieren und den Umstieg auf eine neue Java-Version langfristig zu planen. Eine Migration kann beispielsweise schrittweise inkompatible Drittbibliotheken durch neuere Versionen ersetzen.
J2EE dominiert
Mit der <b>Java Platform Enterprise Edition</b> (Java EE) steht eine Software-Architektur zur Entwicklung verteilter, mehrschichtiger Anwendungen zur Verfügung. Dabei bezeichnet <b>J2EE</b> die Versionen 1.0 (Dezember 1999) bis 1.4 (November 2003). Mit der Version <b>Java EE 5</b> (Mai 2006) folgte dann ein deutlich überarbeiteter Standard, der sehr stark durch zwei Open-Source-Produkte beeinflusst wurde: Das <a href="http://www.springframework.org/" target="_blank"> Spring Framework</a> als leichtgewichtige Enterprise Plattform revolutionierte die Art und Weise, mit der Enterprise Anwendungen entwickelt wurden. Und <a href=" http://www.hibernate.org/" target="_blank">Hibernate</a> etablierte sich als Persistenzlösung. Die Erhebung zeigt, dass J2EE bislang noch die Projektwelt dominiert.
Skriptsprachen sind selten
Seit 2007 treten vermehrt auch Skriptsprachen auf der Basis der <b>Java Virtual Machine</b> (JVM) in Erscheinung. Offenbar sind sie aber im Kontext der Java-Entwicklung noch nicht weit verbreitet (siehe oben). Groovy liegt in dieser Statistik klar vorne - sie wird von zirka 30 Prozent der Befragten eingesetzt. Die Entwicklung in diesem Umfeld bleibt sicher spannend. Interessant wird auch sein, in welchen Bereichen diese Skriptsprachen sich bewähren werden. Erleichtert wird eine erste Annäherung an Skriptsprachen durch die enge Integration mit Java. So können einzelne Funktionen in aktuellen Projekten mit Skriptsprachen realisiert werden, ohne das gesamte Projekt zu beeinflussen. Solche Skripte können gegebenenfalls wieder recht einfach entfernt werden.
Abseits von Java gibt es wenig
Der Vollständigkeit halber: Dargestellt sind Techniken, auf die die Java-Experten ebenfalls zurückgreifen.
Alle nutzen Eclipse
Bei der Frage nach den Software-Entwicklungswerkzeugen zeigt sich, dass <b>Eclipse</b> (beziehungsweise eine auf Eclipse basierende Entwicklungsumgebung) die bevorzugte Wahl praktisch aller Java-Entwickler ist. Der Vergleich der anderen beiden bedeutenden Tools zeigt, dass <b>IntelliJ Idea</b> mehr häufige Nutzer als <b>Netbeans</b> hat. Allerdings hat Netbeans die Nase vorn, zählt man häufige und gelegentliche Nutzer zusammen.
Entwickler bauen auf Open Source
Bei den Build-Tools hat <b>Ant</b> die größte Verbreitung. Das neuere <b>Maven</b> (in Version 1 seit Ende 2004 verfügbar) findet schon Akzeptanz bei zwei Drittel der Entwickler. Der Trend zeigt also Richtung Maven.
Trend zur neuen Lösung
<b>Subversion</b> ist inzwischen das beliebteste System zur Quellcode-Verwaltung. Es hat damit das ältere <b>CVS</b> überholt. Doch der Vorsprung ist relativ klein. Immerhin nutzen fast 80 Prozent der Entwickler noch CVS. Doch auch hier gibt es einen Trend zur neueren Lösung Subversion.
Fehlerverfolgung ist üblich
Mehr als zwei Drittel der befragten Entwickler greift regelmäßig auf Werkzeuge zur <b>Fehlerverfolgung</b> zurück. Der Grund dafür ist vermutlich, dass Entwickler-Teams ohne solche Tools gar nicht sinnvoll zusammen arbeiten können. Dagegen ist der Einsatz einer <b>Integrationsumgebung</b> deutlich weniger verbreitet. Fachlich ist eine kontinuierliche Integration jedoch empfehlenswert, um mögliche Fehler frühzeitig entdecken zu können.
Swing für Desktop-Anwendungen
In der Java-Welt gibt es eine Vielzahl von Frameworks, die einem Entwickler das Leben erleichtern. Aus dem Projektalltag sind sie nicht mehr wegzudenken; sie sind also essentielle Bestandteile der Software-Entwicklung mit Java. Für die Entwicklung von Desktop-Anwendungen ist nach wie vor <b>Swing</b> bevorzugte Wahl. Vermutlich wird bei Neuentwicklungen aber auch häufig eine jüngere Technologie eingesetzt.
Viele Tools für Web-Anwendungen
In der Entwicklung von Web-basierenden Anwendungen sieht das Bild anders aus. Auch hier hat Spring die Nase vorn, gefolgt von <b>Ajax</b> und <b>JSF</b>. Aber auch <b>Struts</b> und Eigenentwicklungen sind noch relativ häufig im Einsatz. Wicket und JBoss Seam sind nicht so stark vertreten.
Herkömmliches DHTML im Einsatz
Die obige Abbildung zeigt, dass für die Entwicklung von Rich-Internet-Applikationen meistens herkömmliches <b>DHTML</b> und <b>Javascript</b> zum Einsatz kommen. Andere Technologien folgen mit deutlichem Abstand.
Servlet Container auch für kritische Anwendungen
Als Container werden bei Server-Entwicklungen tendenziell eher <b>Servlet-Container</b> wie beispielsweise Tomcat statt vollwertiger Application-Server eingesetzt, wenngleich Letztere auch häufige Verwendung finden. Die Praxis zeigt, dass sehr große und geschäftskritische Systeme auch heute schon zuverlässig auf Servlet-Containern betrieben werden.
Alle schätzen Open Source
Entwickler stehen auf <b>Open Source</b>, das belegt die Erhebung sehr eindrucksvoll. Die Beispiele Spring Framework und Hibernate zeigen zudem, welchen Einfluss Open-Source-Projekte nehmen können und welche Innovationskraft sie haben.
Keine Qualitätprobleme
Auch die Qualität der <b>Open-Source-Lösungen</b> steht außer Frage. Beide Ergebnisse untermauern die Bedeutung der Open-Source-Projekte für die kommerzielle Softwareentwicklung. Quelloffene Lösungen haben sich etabliert.
Es gibt keinen typischen Entwicklungsprozess
Befragt nach den <b>Prozessen und Vorgehensweisen</b> antworteten viele Experten, sie programmieren gemäß <b>agiler Softwareentwicklung</b>. Allerdings zeigt sich, dass es nicht das typische Vorgehen im Entwicklungsprozess gibt.
Vorgaben zum Teil falsch dosiert
In größeren Projektteams ist es wichtig, dass alle Team-Mitarbeiter die gleiche Entwicklungsumgebung und zugehörigen Plugins verwenden. Manche Auftraggeber schreiben in ihren Projekten die Entwicklungsumgebung vor, um die Teamarbeit zu fördern. Andere Arbeitgeber lassen den Entwicklern Freiräume, die bevorzugte Umgebung zu nutzen. Drei Viertel der befragten Java-Experten sind mit den Vorgaben zur <b>integrierte Entwicklungsumgebung</b> beziehungsweise mit den gewährten Freiräumen zufrieden sind. Im Umkehrschluss bedeutet dies, dass bei jedem vierten Projekt die Vorgaben ungenau oder unvollständig beziehungsweise falsch sind.
Kundenwünsche sind unklar
Die <b>Anforderungsanalyse</b> ist die Basis jedes Software-Entwicklungsprojekts. Nur wenn die Wünsche des Kunden bekannt sind, kann eine optimale Lösung entwickelt werden. Im Projektalltag gelten solche Überlegungen offenbar wenig. 58 Prozent der Java-Experten glauben, der Anforderungsanalyse werde zu wenig Bedeutung beigemessen. Der Hinweis ist wichtig, denn der Software-Entwickler ist in der Regel der Erste, dem eine ungenügender Spezifikation in Sonderfällen oder fehlende Prozessschritte auffällt.
Dokumentation unzureichend
Ähnliches gilt für die <b>Entwicklerdokumentation</b>. Sie ist wichtig für die Wartung einer Anwendung, da sie neuen Mitarbeitern auch nach Monaten und Jahren einen Überblick über die Software geben soll. Eine fehlende Dokumentation führt zu einem erhöhten Einarbeitungsaufwand für neue Entwickler und zu einer schwierige Weiterentwicklungen der Software. Zwei Drittel der befragten Java-Experten sind der Meinung, dass die Dokumentation vernachlässigt wird. Für die kurzfristigen Projektziele (Termintreue und Budgeteinhaltung) ist sie nicht von Bedeutung. Mittel- und langfristig führt eine fehlende oder schlechte Dokumentation zu erheblichen Mehrkosten.
Qualitätssicherung wird vernachlässigt
Auch um die <b>Qualitätssicherung</b> scheint es nicht gut bestellt. 62 Prozent der Befragten glauben, die Bedeutung der Qualitätssicherung werde unterschätzt. Dass eine gute Qualitätssicherung Geld spart, sollte hinlänglich bekannt sein, wird im Projektalltag aber offenbar gerne verdrängt. Hier sind die Unternehmens- und IT-Leiter gefordert, entsprechende Prozesse einzuführen. Wer sie nicht selbst betreiben möchte, kann auf Dienstleister zurückgreifen. Inzwischen gibt es auch <b>Offshore-Anbieter</b>, die sich auf die Qualitätssicherung von Softwareentwicklungen spezialisiert haben. Möglicherweise ist die Trennung der Entwicklung und Qualitätssicherung ohnehin vorteilhaft. Sie reduziert die Gefahr, dass Mitarbeiter der Qualitätssicherung bei Projektengpässen ins Entwicklerteam abgezogen werden.

Die Schaffung von Modulen, auch im Hinblick auf Service-orientierte Architekturen, gilt deshalb als guter Stil. In den OO-Sprachen des Mainstreams wird das jedoch nur durch schwache Sprachkonstrukte unterstützt. So ist zum Beispiel das Private/Protected/Public-Rechtesystem in Java auf Packages beschränkt, die ihrerseits keine sinnvolle Größenordnung für ein Modul darstellen. In Modula-3 oder Oberon ist das besser gelöst, aber wer benutzt das schon? Die Folge: Änderungen an einer Stelle haben potenziell Einfluss auf viele andere Teile einer Anwendung. Entwickler müssen dies entweder nachvollziehen, was erhöhten Aufwand bedeutet, oder sie können dies gar nicht leisten, und das verringert die Qualität.

Die Lösung für dieses konkrete Problem ist klar: Ein Modulbegriff muss her und auch durchgesetzt werden. Genau hierfür bietet OSGi die geeigneten Mittel: Ursprünglich für die automatische nachträgliche Installation (Provisioning) in Embedded-Systemen gedacht, macht es herkömmliche Java-Bibliotheken (JARs) zu Modulen mit gekapseltem Innerem und definierter Schnittstelle.

Was ist OSGi?

Die Open Services Gateway Initiative spezifiziert eine Java-Plattform, auf der Module und Dienste verwaltet werden können.

  • Module = "Bundle": ein JAR (Java Archive), dessen Manifest spezifiziert, welche Pakete von außen gesehen werden.

  • Bundles können einer laufenden Anwendung nachträglich hinzugefügt werden (Hot Deployment).

  • Bundles können gleichzeitig in verschiedenen Versionen vorliegen und benutzt werden.

  • Dienste: Java-Klassen können als Dienst registriert und dann von jedem Bundle aus gefunden und aufgerufen werden.

  • Die aktuelle Version 4.2 enthält mit der Enterprise-Specification auch Dienste, die die Plattform bereitstellen muss, zum Beispiel Bundle-Verwaltung, Rechte, Logging, Remoting, http-Service, Konfiguration, Benutzer, JTA, JMX, JNDI, JDBC und XML Parser.

Zwei Wege bei der Modularisierung

Der Unterschied zum eingangs erwähnten Information Hiding auf Objektebene liegt in der Granularität. Entwickler sind nun gehalten, die gesamte Anwendung in Module zu unterteilen, deren gegenseitige Nutzung vergleichsweise einfach strukturiert ist. Während man dies auf der grünen Wiese von vornherein berücksichtigen kann - und hoffentlich auch ohne OSGi bereits getan hat -, ist die Modularisierung einer Altanwendung eine größere Herausforderung. Entgegen der häufig zu beobachtenden Praxis, eine große Anwendung gleich zu Beginn in viele kleine Teile zu zerlegen, bis sie letztlich völlig destabilisiert ist, raten wir zu einem Vorgehen in kleinen Schritten. Generell wählt man dafür ein iteratives Vorgehen, trennt also Modul um Modul aus der Anwendung heraus, definiert seine Schnittstelle und prüft nach jedem Schritt die korrekte Funktion der Anwendung.

Dabei muss klar sein, dass die Modularisierung zur Laufzeit ein OSGi-Container übernimmt, in dem die Module (OSGi-Jargon: "Bundles") installiert werden. Es gibt also prinzipiell zwei Möglichkeiten, die Modularisierung vorzunehmen:

1. Container-in-App:

Bei dieser Vorgehensweise wird ein zunächst leerer OSGi-Container in die Altanwendung eingebunden, und anschließend wird getestet, ob die Anwendung in dieser Konfiguration problemlos startet. Ist das der Fall, beginnt man schrittweise, kleine Funktionen aus der Anwendung zu isolieren und als Bundle in den Container zu packen. Nach jedem dieser "Umzüge" ist ein Test angeraten. Da OSGi selbst keinen Aufruf der Anwendungs-Bundles von außerhalb des Containers vorsieht, muss für die Kommunikation von Altanwendung und Bundle ein Dispatcher-Dienst im Container vorhanden sein. Er sorgt dafür, dass ein Aufruf von der Altanwendung OSGi-konform an ein Container-Bundle delegiert wird. Entsprechend sind die Aufrufe der Altanwendungsrümpfe zu ändern und die isolierten Bundles mit einer Schnittstelle zum Dispatcher-Dienst zu versehen.

2. App-in-Container:

Auf einem etwas radikaleren Weg kann man die gesamte Altanwendung zu einem großen Bundle schnüren und in den Container packen - der eigentlich von OSGi vorgesehene Ansatz. Das Anwendungs-Bundle startet daraufhin die Anwendung wie gewohnt. Der Anwender startet statt der Anwendung den Container, was typischerweise in Start-up-Skripten verborgen wird.

Anschließend beginnt die eigentliche Arbeit, indem Anwendungscode aus dem großen Bundle extrahiert und als weiteres Bundle installiert wird.

Während der erste Ansatz die Installationsumgebung unangetastet lässt, ist der zweite mit weniger Aufwand für die Kommunikation des Altanwendungsrumpfes mit den Bundles verbunden. In beiden Fällen erhält man ein Geschenk: die einfache Erweiterbarkeit der Anwendung durch Plug-ins. Dies gilt insbesondere, wenn man sich für den OSGi-Container Equinox aus dem Eclipse-Projekt entscheidet. Außerdem gibt es eine Reihe von Standarddiensten, die ein OSGi-basierendes Projekt nutzen kann: Remoting, Logging und Benutzerverwaltung sind nur einige Beispiele.

Eclipse Equinox

Die beliebte Java-Entwicklungsumgebung Eclipse bringt ihren eigenen OSGi-Container mit. Zusätzlich bietet er zum Beispiel:

  • Plug-ins: Module können "Extensions" deklarieren, die die Anwendung abfragen und aufrufen kann.

  • Module können "Buddy"-Modulen tiefere Einsichten erlauben.

  • Mit P2 steht eine mächtige Provisioning (Installations- und Update)-Umgebung zur Verfügung.

Fallstricke

Bei diesem Vorgehen gilt es allerdings, einige Fallstricke zu beachten. Wir haben die skizzierte Blaupause auf eine größere Applikation angewendet: Das quelloffene ERP-System ADempiere ist umfangreich und glänzt durch bestechende fachliche Features sowie einige architektonische Geniestreiche, ist jedoch nicht unbedingt für sauberes Softwaredesign oder Erweiterungsfähigkeit bekannt. Diese Schwächen wollten wir abstellen und haben dafür beide Vorgehensweisen ausprobiert.

Während die Umstellung des Swingbasierenden Fat Client zunächst nach Lehrbuch funktionierte, traten im weiteren Verlauf in beiden Ansätzen einige Probleme zutage.

Fazit und Links

Die Modularisierung einer Altanwendung bekommt man auch mit OSGi nicht geschenkt. Reine Entwicklungsrichtlinien und konsequente Code-Reviews mögen das Gleiche ausrichten. Sind jedoch auch einfache Erweiterbarkeit und ein Plug-in-Konzept gefragt, sollte Eclipse Equinox in die engere Wahl gezogen werden. (ue)