OSGI Frage

Also, ich habe mir letztens ein paar Gedanken zu OSGI gemacht und bin auf eine komische Situation gestoßen, die ich nicht ganz verstehe.
Soweit ich weiß lädt OSGI jedes Bundle in einem eigenen ClassLoader. Falls ein Bundle ne Klasse braucht, sucht der ClassLoader als erstes in seinen eigenen bekannten Klassen nach der Klasse, falls sie nicht vorhanden ist, wird in den ClassLoader der anderen Bundle gesucht, die das aktuelle Bundle benötigt (die Bundles, die man mit Bundle-Import festlegt).

Korrigiert mich falls ich falsch liege!

So weit, so gut. Diese ‘Technologie’ müsste es eigentlich möglich machen, mehrere Bundle mit einer Abhängigkeit zu z.B JUnit zu haben, jedes Bundle aber eine eigene und vor allem andere Version von JUnit benutzt (hierbei bin ich mir nicht ganz sicher, denn ich weiß nicht genau wie OSGI die ClassLoader hierarchisch gliedert, denn einen Parent ClassLoader muss es ja immer geben!).

Jetzt zu meinem eigentlichen Problem: OSGI ist ja eine Spezifikation, eine jar mit Interfaces und abstrakten Klassen. Diese Spezifikation an sich (also die jar) wird ja auch als OSGI-Bundle zum Download bereitgestellt (also mit den nötigen Manifest-Einträgen). Angenommen ich besitze nun eine Implementation von OSGI. Diese braucht ja (zur Laufzeit, wenn ich den Container starte), die OSGI Klassen, die in der jar liegen. Ich kann jetzt aber nicht einfach in der Manifest Datei der Implementation die Abhängigkeiten über Bundle-Import festlegen. Das kann ja einfach nicht funktionieren, da, bevor irgendwas von wegen Bundle Scans und hinzufügen anfängt, alle OSGI Klassen im Classpath liegen müssen. Aber wenn ich diese jetzt nun zum Classpath hinzufüge (z.B. über einen einfachen Eintrag in der Manifest-Datei, dann ergeben sich für mich zwei Folgerungen, die ich mir beide nicht erklären kann:

  1. Das OSGI Bundle ist zum Beispiel bei Apache Felix und Equinox auch registriert, also können andere Bundles es mittels ‘org.osgi.framework’ (glaube ich) nutzen. Wie wird das denn bewerkstelligt? Ich habe ja dann die osgi-jar schon im Classpath, also sind alle Klassen schon geladen. Daher kann ich das Bundle, wenn ich es über die osgi Routine laden würde, eigentlich nicht nutzen können. Der dazugehörige ClassLoader würde doch gar nicht funktionieren, da die Klassen schon geladen sind…?

  2. Wenn ich die OSGI Spezifikation in der Manifest zum Classpath hinzufüge, hindert mich das doch daran, die Implementation zu aktualisieren. Die enthält doch alle Klasse, die notwendig sind, um den Container am Laufen zu halten. Soweit ich weiß liegt doch auf jeder jar, die gerade von der JVM benutzt wird, ein FileLock, oder? Wie schafft es OSGI, seine eigene Implementation zu aktualisieren?

Ich hoffe das ist irgendwie ansatzweise verständlich…

Ja, jedes Bundle kann seinen eigenen Version haben, entweder aus dem Bundle selber(soz. embedded, Objekte davon koennen nciht mit anderen Bundles ausgetauscht werden), oder von der Platform provided.
Parent Classloader gibt es nicht in OSGi! (zumindest nicht nutzbar)

Ein Classdloader pro Bundle, und dann noch einer der fuer die Klassen verantwortlich ist die von der Platform bereitgestellt werden und per import aufgeloest werden(oder so aehnlich).

Nun ja, manchmal kann man die Klassen nicht mehr entladen…

Tue mir schwer, ist aber kein triviales Thema :slight_smile:

Das heißt sobald irgendeine OSGI Klasse geladen wird, muss die Implementation sozusagen im Hintergrund einen Classloader erstellen und ein Bundle, damit die Spezifikation auch für andere Bundles zur Verfügung steht? Das ist nämlich der Punkt, den ich nicht ganz verstehe… Wenn die JVM die Implementation lädt muss sie ja auch schon die Spezifikation kennen (also muss die irgendwie in den Classpath kommen, vllt über einen Launcher? Aber der müsste dann auch die alle Klassen, die gebraucht werden, im Classpath haben…). Das einzige, was ich mir vorstellen kann, sind:

  1. Die Implementation erstellt einen ClassLoader für ein Bundle ‚org.osgi.framework‘ und hinterlegt das dann einfach für die anderen Bundles (keine Ahnung wie die Container das machen, wahrscheinlich in den tiefen des Quelltexts in einer Map). Dieser ClassLoader muss dann ja als Parent-ClassLoader aber den Thread.getContextualClassLoader() haben, da dieser ja die Implementation geladen hat und somit alle Klassen, die im Classpath beim Start waren, kennt, oder?

Kenne mich da nicht so im Detail aus(sollte ich aber wohl), aber hier steht einiges dazu: Mine of Information - OSGi Classloading

Each OSGi classloader instance (ie OSGi bundle) has its own private mapping table that tells it which classloader is responsible for providing classes from a particular package to the current bundle. This is usually populated when the bundle is first loaded (“resolved”), although “dynamic imports” look things up via the “bundle registry” as needed.

When the jarfile for a bundle is loaded, OSGi’s Framework class first creates a Bundle object to represent it, and that in turn creates a classloader which is a child of an “osgi environment classloader”. The bunde-specific classloaders pass requests for classes in packages under java.* up to the parent classloader as is standard in java, ie classes from the very core of java are available automatically to all bundles and are loaded from the bootstrap classloader as normal. However for all other packages, requests are not passed up the chain to the parent; instead the bundle’s classloader resolves classes using the bundle-specific map of package-to-classloader. As a result, classes in the new bundle can’t by default see any classes from the Java JDK which are in namespaces like javax.* or org.*, nor classes on the normal Java application classpath ($CLASSPATH). To see those “standard but not core” packages, a bundle should simply use an Import-Package declaration, which tells OSGi to copy the appropriate entry from the shared map of all possible packages into the bundle-specific map of imported packages.

Note that because OSGi classloaders do not pass requests up to their parent (other than java.*), it is actually fairly irrelevant what their parent is. However current versions (as of end 2012) of Felix and Equinox both use the above classloader hierarchy layout.

Das erklärt einiges, danke :slight_smile: Das würde dann einfach bedeuten, sobald osgi sich selbst lädt, erstellt es ein Bund, um sich selbst darzustellen und fügt dann einfach die nötigen ClassLoader hinzu…