DLL de charge (à l'aide JNA) à l'intérieur d'un faisceau de OSGi
Question
OSGi ne peut pas trouver mon fichier DLL, et je ne peux pas à comprendre pourquoi.
Actuellement, j'ai le fichier DLL (de foo.dll
) à la racine de mon paquet, je l'ai aussi essayé d'avoir dans un répertoire libs
.
Le Manifeste pour le paquet en question ressemble à ceci:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: foobundle
Bundle-SymbolicName: com.foo.bar
Bundle-Version: 1.0.0
Bundle-Vendor: me
Import-Package: com.sun.jna,
com.sun.jna.ptr,
com.sun.jna.win32
Export-Package: com.foo.bar
Bundle-NativeCode: foo.dll;
osname=WindowsXP;
processor=x86
Alors dans mon interface JNA je joue un loadLibrary (selon la documentation):
public interface MyFooInterface extends com.sun.jna.Library{
static final MyFooInterface INSTANCE = (MyFooInterface)com.sun.jna.Native.loadLibrary("foo", MyFooInterface .class);
// specific interface defs here...
}
Ensuite, dans une autre classe que je tente d'utiliser l'interface JNA
// ...code
int var = MyFooInterface.INSTANCE.bar();
// ...more code
Je JNA fourni par un autre paquet (qui exporte com.sun.jna et les autres emballages importés ci-dessus), mais ont aussi essayé de l'emballage avec le faisceau défini ici (et ajouté au classpath dans ce cas, etc. ).
J'ai aussi essayé spécifier Bundle-NativeCode: /foo.dll
.
De plus d'intérêt, ce sont les propriétés OSGi pertinentes (que je tiré à l'aide getprop
)
org.osgi.framework.os.name=WindowsXP
org.osgi.framework.processor=x86
Même après tout cela (et avec tous les essais que j'ai fait) je finis toujours avec l'erreur suivante (et une trace de pile non représentée):
java.lang.UnsatisfiedLinkError: Unable to load library 'foo': The specified module could not be found.
... donc ce que je suis absent?
Modifier :. Je tiens également à noter que je l'ai testé et eu du succès le code d'interface JNA et la DLL qu'il parle dans le cadre d'un programme de test JUnit
Edit 2 : L'ajout de ce code à la classe qui vous appelle la bibliothèque semble permettre à la JNA de trouver la bibliothèque (quand Native.loadLibrary
est appelée plus tard). Il semble que je devrais être en mesure d'éviter cet appel en fonction de la directive Bundle-NativeCode dans le manifeste. De toute évidence, une fois la bibliothèque est chargée Native.loadLibrary saisit l'instance existante de celui-ci, mais je préférerais ne pas dépendre de cette tactique très spécifique ordre.
static{
System.loadLibrary("foo");
}
La solution
Le problème est l'appel spécialisé JNA loadLibrary, qui ne connaît pas OSGi. Lorsque vous appelez loadLibrary d'un faisceau de OSGi, il utilisera le classloader OSGi (qui est au courant bundle), pour trouver la DLL est, et dans ce cas, l'extraire hors du faisceau et de le rendre chargeable via le System.loadLibrary () appel contre un endroit précis.
Étant donné que cette JNA semble être (a) pas OSGi au courant, et (b) superflu, pourquoi ne pas simplement utiliser System.loadLibrary () à la place?
Si vous devez écrire à la fois, puis effectuer une méthode System.loadLibrary () dans le début () du paquet dans le BundleActivator, qui apportera la bibliothèque native dans (vous voulez probablement faire en sorte que si elle ne peut pas être chargé , le faisceau ne peut pas être démarré en tout cas).
Autres conseils
En regardant la documentation de la JNA, il est écrit:
- votre bibliothèque cible disponible à votre programme Java. Il y a deux façons de faire ça:
- La méthode préférée consiste à définir la propriété système
jna.library.path
sur le chemin à votre bibliothèque cible. Cette propriété est similaire àjava.library.path
mais applique uniquement aux bibliothèques chargées par la JNA. - Modifier la variable d'environnement d'accès à la bibliothèque appropriée avant de lancer la machine virtuelle. Ceci est
PATH
sous Windows,LD_LIBRARY_PATH
sous Linux, etDYLD_LIBRARY_PATH
sur OSX.
- La méthode préférée consiste à définir la propriété système
Donc, pour contourner cette lacune, vous pouvez résoudre le chemin absolu de la bibliothèque et de la charge que.
En supposant que son chargeur de classe standard de Eclipse, vous pouvez le faire ClassLoader.findLibrary()
qui devrait trouver la bibliothèque locale dans le paquet.
Je vous suggère d'essayer d'emballer le dll comme un pot:
jar cvf foo.dll.jar foo.dll
et la charge du pot comme lib régulier.