Freitag, 25. Juni 2010

OSGi-Bundles bauen mit Tycho

Hallo,

ich habe mit Hilfe des Tutorials von Mattias Holmqvist (Teil 1, Teil 2 und Teil 3) unser Projekt vom Headless PDE-Build bzw. BND-Build umgestellt auf Tycho.

Zunächst einmal: Es geht erstaunlich einfach. Das Tutorial ist unglaublich präzise. Und tycho funktioniert schon in der Version 0.8 sehr gut, die gerade die aktuelle ist (0.10-SNAPSHOT wollte ich nicht nehmen).

Aber natürlich gab es auch noch ein paar Probleme, die kein noch so gutes Tutorial aus der Welt schaffen kann. Ich liste die einfach mal hier auf, damit andere bei ähnlichen Problemen eine Hilfe bekommen:

Source- und Target-Versionen für den Code


Wir verwenden für unseren Source Java Version 6-Features, insbesondere @Override-Annotationen auch für Methoden, die Interface-Methoden überschreiben. Das resultiert dann in einem Fehler "must override a superclass method".

Das wollte ich zunächst mit einer Plugin-Konfiguration in der parent-pom lösen, hier hat aber Tycho in der Version 0.8 noch ein Problem.

Aber das osgi-compile-Plugin verwendet aber die gleichen Properties zur Konfiguration wie das "normale" compile-Plugin, ich konnte also einfach die Properties maven.compiler.source=6 und maven.compiler.target=6 in der Parent-POM setzen.

In zukünftigen Versionen wird Tycho diese Information aus dem Manifest ziehen.

eclipse-application


Wir hatten bisher die .product-Datei in einem ganz normalen Bundle zusammen mit ein paar Java-Klassen, den entsprechenden Ressourcen etc. Tycho baut ein eclipse-application-Bundle aber nicht als Bundle, so dass es ich einfach genau so gemacht habe, wie Mattias Holmqvist es als sein Standard-Vorgehen beschreibt: Ich habe ein eigenes Plugin in der Eclipse IDE angelegt, das nur die foo.bar.product-Datei enthält. Dieses muss noch nicht einmal als PDE-Projekt angelegt sein. Noch schnell eine POM für dieses Projekt geschrieben (wie beschrieben in Teil 2) und in die Parent-POM eingetragen.

Verschachtelte Projekte


Tycho arbeitet im Moment nur mit P2-Repositories, nicht aber mit dem Maven-Repository. Es ist also nicht möglich, die verschiedenen Layer einer Applikation aufeinander aufbauend in separaten Builds zu bauen. Also muss die Parent-POM wirklich alle Module auf einmal bauen.

Soweit dazu, aber selbst mit diesen kleinen Problemchen hatte ich mit tycho meine Eclipse-Applikation schneller gebaut als mit dem PDE-Build oder mit dem BND-Plugin.

Montag, 13. Juli 2009

OSGi-Bundles bauen mit Eclipse und Maven


Neu: Ich habe jetzt mal Tycho ausprobiert, damit ist alles besser :)

Allerdings mache ich dafür kein neues Tutorial, das von Mattias Holmqvist (Teil 1, Teil 2 und Teil 3) ist schon ziemlich perfekt. Meine Erfahrungen damit habe ich unter OSGi-Bundles bauen mit Tycho beschrieben.


---
Alter Post (Vorsicht, mir hat's Groß- und Kleinschreibung zerlegt und das Aufräumen lohnt aus oben beschreibenem Grund nicht mehr) :


OSGi-Bundles und Eclipse Plugins zu bauen war bisher immer sehr umständlich und fehleranfällig. Das bringt mich ja zu der Haltung, dass ich OSGi eher vermeiden würde. Insbesondere bringt es ja in der Regel auch keinen Business-Value. Anderes Thema, ich bin nun mal durch das Umfeld gezwungen, Plugins für die Eclipse Rich Client Platform zu bauen.

Meine Randbedingungen sind Folgende: Ich möchte in Eclipse entwickeln und dort auch alle Möglichkeiten der PDE nutzen. Andererseits ist es für mich keine Option, fertige Bundles durch einen Entwickler aus seiner IDE exportieren zu lassen. Ich nutze nämlich sowieso ein automatisches Build-System (schließlich bin ich nicht alleine auf der Welt, sondern kooperiere mit anderen, zum Teil verteilt sitzenden Kollegen), um Continuous Builds und Nightly Builds zu machen (siehe mein letzter Post). Dort möchte ich die Bundles über Maven bauen. Bisher haben wir das hier in der Firma über den automatisierten PDE-Build gemacht, der Prozess ist aber höchst umständlich und fehleranfällig.

Mit dem bnd-Tool und dem maven-bundle-plugin aus dem Apache Felix-Projekt gibt es jetzt aber eine spannende und benutzbare Option. Spannend deswegen, weil bnd einen völlig neuen Weg geht - es basiert nämlich nicht (nur) auf Deklarationen, sondern analysiert den compilierten Code, um Abhängigkeiten zu entdecken und in die MANIFEST.MF einzutragen.

Jetzt zur Lösung: Da ich nicht nur ein Bundle verwende, habe ich eine "common-pom.xml" als gemeinsame Parent-POM meiner Bundle-Projekte.

Dort verwende ich folgenden Eintrag unter Plugins:



<plugin>
  <groupid>org.apache.felix</groupid>
  <artifactid>maven-bundle-plugin</artifactid>
  <extensions>true</extensions>
  <configuration>
    <manifestlocation>META-INF</manifestlocation>
    <instructions>
      <bundle-symbolicname>${pom.groupId}.${pom.artifactId};singleton:=true</bundle-symbolicname>
      <bundle-activator>${bundle.activator}</bundle-activator>
      <embed-dependency>*;scope=compile|runtime;type=!pom,inline=false</embed-dependency>
      <embed-transitive>true</embed-transitive>
      <embed-directory>lib</embed-directory>
      <import-package>${bundle.import-packages}*;resolution:=optional</import-package>
    </instructions>
  </configuration>
</plugin>

Die notwendigen Properties habe ich in der Parent-POM wie folgt definiert:


<properties>
  <bundle.activator>${pom.groupId}.${pom.artifactId}.internal.Activator</bundle.activator>
  <bundle.import-packages></bundle.import-packages>
</properties>


Für das Zusammenspiel mit Eclipse als IDE sorgen dabei einige Einträge: Zunächst verwende ich als manifestLocation natürlich den "default"-Pfad von Eclipse (META-INF) und nicht den maven-default unter target.

Zum anderen verwende ich ein "Embed-Directory" (lib), in das ich per maven-dependency-plugin alle notwendigen Abhängigkeiten (d.h. 3rd-Party-Libraries, die ich nicht zu OSGi-Bundles konvertiere) kopiere. Der entsprechende Abschnitt der Parent-POM sieht wie folgt aus:

<profiles>
  <profile>
    <id>eclipse</id>
    <build>
      <plugins>
        <plugin>
          <artifactid>maven-clean-plugin</artifactid>
          <executions>
            <execution>
              <id>clean-dependencies-eclipse</id>
              <phase>process-resources</phase>
              <goals>
                <goal>clean</goal>
              </goals>
              <configuration>
                <filesets>
                  <fileset>
                    <directory>${basedir}/lib</directory>
                    <includes>
                      <include>**/*</include>
                    </includes>
                  </fileset>
                </filesets>
              </configuration>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <artifactid>maven-dependency-plugin</artifactid>
            <executions>
              <execution>
                <id>copy-dependencies-eclipse</id>
                <phase>process-resources</phase>
                <goals>
                  <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                <outputdirectory>${basedir}/lib</outputdirectory>
                <includescope>compile</includescope>
                <includescope>runtime</includescope>
                <excludetypes>pom</excludetypes>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
  ...
</profiles>


Für ein konkretes Bundle sind jetzt "nur noch" relativ wenige Schritte notwendig:

Natürlich muss das Projekt die Parent-POM entsprechend referenzieren (ich mache das bei mir per relative-path wie folgt):



<parent>
  <groupid>de.vizmind</groupid>
  <artifactid>common</artifactid>
  <version>0.0.1-SNAPSHOT</version>
  <relativepath>../de.vizmind.common/pom.xml
</parent>


Als Packaging muss man bundle verwenden:

<packaging>bundle</packaging>


Jetzt kann man ganz wie gewohnt seine Dependencies eintragen, wobei die Compile und Runtime-Dependencies wie oben gesagt in den lib-Ordner kopiert werden und so für den PDE-Mechanismus von Eclipse verwendbar sind - dieser hat nämlich so seine Probleme mit den "Maven Dependencies" des m2eclipse-Plugins.

Abhängigkeiten zu anderen Bundles markiert man einfach mit dem Scope "provided", diese werden dann herangezogen, um die "import-packages" zu bestimmen, aber nicht mit in das Bundle kopiert.

Jetzt muss man gegebenenfalls noch die Properties aus der Parent-POM "überdefinieren", z.B. wenn man keinen Activator definiert hat (der default wird unter ${pom.groupId}.${pom.artifactId}.internal.Activator erwartet).

Wenn man Abhängigkeiten definieren muss, die sich nicht aus den class-Dateien ergeben, so ist das manuell über das Property "bundle.import-packages" zu tun. Da dieses Property einfach vor die automatisch bestimmten gehängt wird, muss man es (noch) mit einem Komma beenden, sofern es nicht leer ist. (Ein weiterer Punkt für Verbesserungen). In unserem Beispiel hier verwenden wir in einem Bundle spring und referenzieren in der context.xml einen PropertyPlaceholderConfigurer. Der Import für diese Klasse kann natürlich nicht automatisch aus .class-Dateien bestimmt werden, also muss er manuell hinzugefügt werden. (Ein weiterer Punkt für Verbesserungen - Automatische Analyse von Spring-Dateien).

Zusammen sieht das dann wie folgt aus:


<properties>
  <bundle.activator></bundle.activator>
  <bundle.import-packages>org.springframework.beans.factory.config,</bundle.import-packages>
  <!-- Close with "," if you have a non-empty list -->
</properties>


Jetzt ist mein Projekt fertig. Die Verwendung eines Profils (in der Parent-POM, siehe oben) sorgt dafür, dass ich mit folgendem Maven-Kommando ein Eclipse-Projekt anlegen kann, ohne dem eigentlichen Build später in die Quere zu kommen.

mvn eclipse:clean eclipse:m2eclipse process-resources compiler:compile bundle:manifest -Declipse.pde=true -Peclipse

Das Kommando ist noch etwas umständlich, evtl. mache ich später hier noch etwas "Feinarbeit". Für jetzt funktioniert es erst mal.

Das Projekt kann nun in Eclipse importiert werden. Einziger Wermutstropfen: Aktuell wird die .classpath-Datei noch nicht so aufgebaut, dass die embedded 3rd-Party-Libraries auch referenziert werden. Die muss man noch einmal "von Hand" in den Build-Path aufnehmen.

Damit ist der Weg frei, das Bundle in der Eclipse IDE zu verwenden und zu entwickeln.

Mit

mvn package

kann man nun das Bundle auch bauen, so dass auch dem automatisierten Build nichts mehr im Wege steht.


Ciao

Chris

Montag, 11. Mai 2009

Video vom Vortrag

Den Hudson-Vortrag hab ich gleich nochmal gehalten - beim Arbeitskreis Objekttechnologie Norddeutschland.

Diesmal gibt's auch ein Video davon.

Mittwoch, 18. März 2009

Vortrag bei der JUGHH: Continous Integration mit Hudson

Hallo!

Gestern habe ich einen Vortrag bei der Java User Group Hamburg über Continuous Integration mit Hudson gehalten. Die Folien dazu gibt's unten.

Wie üblich haben sich neben und nach dem Vortrag interessante Diskussionen ergeben, die im wesentlichen in zwei Richtungen gehen:

Zum einen ist der Build von Eclipse-Applikationen ein echter Schwachpunkt, für den jeder Lösungen sucht bzw. ähnliche Workarounds findet. Ein wirklich schwerwiegendes Problem dabei ist, dass man kaum verwertbare Dokumentation dazu findet. Ich werde versuchen, das in einem meiner nächsten Posts zu beheben und unseren Eclipse-PDE-Build-Prozess zu beschreiben. Die Einbindung in Hudson ist dabei Gott sei Dank nicht das Problem.

Zum anderen stellte sich einmal mehr heraus, dass auch das Bauen von Software immer wieder neue und interessante Facetten hat. Hudson kann ja mit mehreren Build-Prozessoren umgehen. Welche Build-Schritte kann man eigentlich parallelisieren? Welche müssen in jedem Fall erst nach einer Menge anderer Teil-Schritte bearbeitet werden. Wie synchronisiert man diese Builds. Wie testet man? Auch das sind Themen, auf die ich jetzt (noch) keine Antwort habe. Demnächst mehr.

Gute Nacht!

Continuous Integration mit Hudson
View more presentations from cb.betz.

Dienstag, 13. Januar 2009

Neues Jahr, neues Glück

So - neuer Vorsatz... eigentlich hab ich's ja nicht so mit Vorsätzen, aber dieses Jahr ist gut dafür. Unser Nachwuchs kommt und ich hab mir überlegt, dass es endlich Zeit ist, web2.0ig zu werden. Also nicht passiv, sondern aktiv. Selbst bloggen, twittern, flickrn und so weiter, was das Zeug hält. Was Nachwuchs und Web 2.0 miteinander zu tun haben? Erst mal gar nix. Außer dass ich natürlich drüber nachdenke, was mir wichtig ist und was ich gern mache. Und das werde ich hier mit allen teilen, die's interessiert.

Also kurz über mich - ich bin ja eigentlich schon Web 2.0. Viel im Internet unterwegs und schon eher das, was sich so gemeinhin Early Adopter nennt. Immer eher technisch, aber auch mit einem starken Bezug zum Nutzen, zu User und Usage Experience bis hin zum Marketing. Den Fokus auf Benutzbarkeit habe ich schon in meiner Promotion gehabt. Da ging es darum, wie man eLearning-Systeme durch Fachexperten mit einer möglichst geringen Einstiegshürde erstellen kann und wie diese dann nach und nach so wachsen, dass sie "intelligent" auf die Lerner reagieren können. Ich habe schon Expertensysteme entwickelt, Musikportale im Internet gebaut und auch größere Web-Systeme für Banken. Nicht gerade Web 2.0 - aber für die konservative Branche schon recht fortschrittlich. Manches davon habe ich in meiner eigenen Firma gemacht, manches bei einem der größten deutschen Interactive-Dienstleister.

Seit etwas über einem Jahr bin ich jetzt in einer ganz anderen Branche. Ich baue Software zur Kommunikationsanalyse in einer alteingesessen Hamburger Firma. Zum Thema Visuelle Analyse werde ich hier sicher noch das ein oder andere schreiben.

Samstag, 18. Oktober 2008

session building

hey, spannend. Es ist total egal, wie viele Leute sich für ein Thema interessieren. Die Themen werden immer in den Schedule gepinnt.

barcamp...

make wine tasting visible, accessible places, tomocos, theatre 2.0, 

Die Themen sind recht unterschiedlich und bei weitem nicht soooo technisch, wie die ursprünglich angekündigten Themen. Fragt sich, ob nur die Nerds ihre Themen schon vorher präsentieren?

Dienstag, 14. Oktober 2008

Website Navigation

Interessant, sollte man mal ausprobieren: Eine Website ohne eigene (hierarchische) Navigation, weil Benutzer die sowieso nicht benutzen. Stattdessen "teleportieren" sich die Benutzer mit Googles Hilfe von einer Website zur nächsten.

Das würde völlig neue Wege der Visualisierung erlauben. Raus mit diesem ganzen Overhead zur Navigation. Stattdessen würde vielleicht eine Customized Search Sinn machen.