2017-10-27 3 views
0

Ich möchte eine Ressourcendatei (z. B. eine XML-Konfigurationsdatei) in mein Bundle einfügen und sie für alle anderen Bundles im Container sichtbar machen. Ist es möglich, ohne den Manifest-Header Fragment-Host zu verwenden? Ich möchte, dass diese Ressourcendatei immer im Klassenpfad aller Bundles angezeigt wird, die neben meinem Bundle ausgeführt werden, auch solche, die noch nicht vorhanden sind, aber möglicherweise in Zukunft hinzugefügt werden.Wie kann eine Ressourcendatei für alle Bundles in OSGi sichtbar gemacht werden?

EDIT:

Um zu klären - die Ressource muss passiv verfügbar sein, das heißt, die anderen Bündel sollen es in der Lage sein, in ihrem Classpath zu finden, und nicht von einem speziellen API oder Dienst meines Bündels beziehen.

Etwas mehr Hintergrund - meine Umgebung ist ein bisschen unordentlich, aber ich habe keine Kontrolle darüber und kann nicht ändern, die vorhandenen Bündel. Der einzige Weg, wie ich das ändern kann, ist das Hinzufügen eigener Bundles. Diese Umgebung enthält mehrere Kopien der ch.qos.logback.classic bundle. Wenn das Logback gestartet wird, sucht es im Klassenpfad nach bestimmten XML-Konfigurationsdateien. Wenn es keine von ihnen findet, ist das Standardverhalten, dass alles auf stdout mit Debug-Level gedruckt wird. Diese Umgebung wurde früher zum Hosten einer GUI-Anwendung verwendet, so dass es vorher nicht viel bedeutete, aber jetzt versuche ich, sie so anzupassen, dass ich einige ihrer Funktionen im Headless-Modus nutzen kann. Jetzt wird es mir wichtig, es so konfigurieren zu können, dass nur Warnungen und Fehler auf der Konsole ausgegeben werden.

Antwort

0

Im Allgemeinen können Sie dies nicht tun. Die Klassenraumisolierung ist das Herzstück von OSGi. Sie möchten jedoch eine Ressource in den Klassenlader eines Bündels einfügen und sie für alle anderen Bündel sichtbar machen. Das ist nicht OSGi, es ist der globale Klassenpfad der Anwendung.

Das einzige, was Sie tun können, um dem internen Klassenpfad eines bestimmten Pakets hinzuzufügen, besteht darin, ein Fragment zu schreiben, das an dieses Paket angehängt wird. Ein Fragment kann an mehrere Hostbündel anhängen, aber nur, wenn diese Hosts den gleichen symbolischen Namen haben, d. H. Weil sie verschiedene Versionen desselben Bündels sind. Siehe OSGi R6 Core-Spezifikation, Abschnitt 3.14.

Sie haben jedoch angegeben, dass die Bundles, die Sie anhängen möchten, alle Kopien von ch.qos.logback.classic sind. Wenn das bedeutet, dass sie alle diesen genauen symbolischen Namen haben, dann wird vielleicht ein Fragment funktionieren.

+0

Danke Neil. Leider wird 'ch.qos.logback.classic' als Host meines Fragments in meinem Fall nicht funktionieren. Dies liegt daran, dass die anderen Bundles das Logback intern als Lib enthalten und den Manifestheader "Bundle-ClassPath: lib/logback-classic.jar" enthalten. Es scheint also der einzige Weg zu sein, mehrere Fragmente zu erstellen - eines für jedes Bündel. Trotzdem danke. – yashu

1

Sie können den Klassenpfad anderer Bündel auf diese Weise nicht ändern.

Sie können den Klassenlader Ihres Bundles aus Ihrem bundleContext abrufen. Sie können diesen Classloader einem anderen Bundle zuweisen, um Ihre Ressource abzurufen.

ClassLoader cl = context.getBundle().adapt(BundleWiring.class).getClassLoader(); 

Eine andere Option ist, dem anderen Bündel die URL der Ressource zu geben.

+0

Christ, gibt es einen Weg, der keine Interaktion von dem anderen Bündel erfordern würde? In meinem Fall habe ich keine Kontrolle über die anderen Bündel und kann sie nicht ändern. Eine Methode, die ich kenne, besteht darin, mein Bündel zu einem Fragment des anderen Bündels zu machen, aber in diesem Fall muss ich explizit definieren, welches andere Bündel speziell der Host meines Fragments ist, und ich müsste es für jedes neue potentielle zukünftige Bündel erneut spezifizieren. Gäbe es eine Art "general fragment" -Mechanismus, dann könnte ich es ein für allemal lösen ... – yashu

0

Solange sich die Ressource im Klassenpfad befindet, kann jedes Paket auf die Ressource zugreifen, wenn es den Klassenlader des Bündels mit der Ressource erreichen kann.

Zum Beispiel:

ClassLoader classLoaderOfBundleWithResource = ... 
classLoaderOfBundleWithResource.getResourceAsStream("org/example/resource.xml"); 

Von einer Wartung und API Sicht würde ich empfehlen, nicht eine Ressource, die Art und Weise ausgesetzt werden. Java-Typen sind dafür viel besser geeignet. Lassen Sie das Ressourcenpaket stattdessen eine Klasse exportieren, die Clients Zugriff auf den Inhalt der Ressource gewährt.

Zum Beispiel:

public class XmlDocumentProvider { 
    public InputStream openDocument() { 
    return getClass().getResourceAsStream("resource.xml"); 
    } 
} 

Unter der Annahme, dass sowohl die resource.xml und die XmlDocumentProvider im gleichen Paket befinden, openDocument wird den Inhalt der Ressource zurück genau wie in dem ersten Beispiel.

+0

Danke Rüdiger. Tatsächlich suche ich nach etwas, das keine Interaktion von den anderen Bündeln erfordert - nur etwas, das die Ressource in ihrem Klassenpfad verfügbar machen würde. Etwas ähnlich wie Fragmente, aber allgemeiner. Ich sollte die Frage wahrscheinlich bearbeiten, um es klarer zu machen ... – yashu

Verwandte Themen