2011-01-14 17 views
16

Część 1

Zajmuję się tworzeniem aplikacji Java, które należy zwolnić w słoiku. Ten program zależy od zewnętrznych bibliotek C++ wywoływanych przez JNI. Aby je załadować, używam metody System.load z absolutną ścieżką i to działa dobrze.Java - Załadowanie biblioteki DLL przez ścieżkę względną i ukryć je wewnątrz słoik

Jednak naprawdę chcę "ukryć" je wewnątrz JAR, więc stworzyłem pakiet do ich zbierania. To zmusza mnie do załadowania ścieżki względnej - ścieżki pakietu. Dzięki takiemu podejściu pozwoliłem użytkownikowi uruchomić JAR w dowolnym katalogu, nie martwiąc się o łączenie bibliotek DLL lub znudzony poprzednim procesem instalacji.

To rzuca spodziewany wyjątek:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Expecting an absolute path of the library

Jak mogę dostać tę pracę?

CZĘŚĆ 2

Podejście kopiowanie DLL do folderu (wyjaśnione poniżej) działa tylko wtedy, gdy go uruchomić w środowisku Eclipse. Prowadzenie eksportowany JAR, pliki binarne DLL są dobrze utworzona, ale załadowaniu jednego JNI rzuca kolejny wyjątek:

Exception in thread "main" java.lang.reflect.InvocationTargetException

at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56) 
Caused by: java.lang.UnsatisfiedLinkError: C:\Users\Supertreta\Desktop\nm files\temp\jniBin.dll: Can't find dependent libraries at java.lang.ClassLoader$NativeLibrary.load(Native Method) 

biegnę tę metodę ładowania:

public static void loadBinaries(){ 
     String os = System.getProperty("os.name").toLowerCase(); 

     if(os.indexOf("win") >= 0){ 
      ArrayList<String> bins = new ArrayList<String>(){{ 
       add("/nm/metadata/bin/dependence1.dll"); 
       add("/nm/metadata/bin/dependence2.dll"); 
       add("/nm/metadata/bin/dependence3.dll"); 
       add("/nm/metadata/bin/dependence4.dll"); 
       add("/nm/metadata/bin/jniBin.dll"); 
      }}; 

      File f = null; 
      for(String bin : bins){ 
       InputStream in = FileManager.class.getResourceAsStream(bin); 
       byte[] buffer = new byte[1024]; 
       int read = -1; 
       try { 
        String[] temp = bin.split("/"); 
        f = new File(TEMP_FOLDER, temp[temp.length-1]);  
        FileOutputStream fos = new FileOutputStream(f); 

        while((read = in.read(buffer)) != -1) { 
         fos.write(buffer, 0, read); 
        } 
        fos.close(); 
        in.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 

      System.load(f.getAbsolutePath()); 
     } 
    } 

myślę, że to może być problemem uprawnienia dostępu , ale nie wiem, jak to rozwiązać. Co myślisz?

+0

Dlaczego chcesz je ukryć? –

+0

Aby zapewnić czysty słoik – supertreta

Odpowiedz

21

Nie wierzę, że można załadować bibliotekę DLL bezpośrednio z pliku JAR. Musisz podjąć pośredni krok polegający na skopiowaniu biblioteki DLL z JAR. Poniższy kod należy zrobić:

public static void loadJarDll(String name) throws IOException { 
    InputStream in = MyClass.class.getResourceAsStream(name); 
    byte[] buffer = new byte[1024]; 
    int read = -1; 
    File temp = File.createTempFile(name, ""); 
    FileOutputStream fos = new FileOutputStream(temp); 

    while((read = in.read(buffer)) != -1) { 
     fos.write(buffer, 0, read); 
    } 
    fos.close(); 
    in.close(); 

    System.load(temp.getAbsolutePath()); 
} 
+0

To wydaje mi się szybki i łatwy sposób na rozwiązanie tego problemu. Próbowałem, ale mam problem: metoda createTempFile dołącza numer do nazwy pliku, tzn. Lib "hello.dll" staje się "hello.dll4975093656535427331", nawet z tymi parametrami (nazwa, "").Moje podstawowe dll JNI zależy również od innych bibliotek dll, więc muszę być świadomy nazw. Czy wiesz, jak sobie z tym poradzić? – supertreta

+0

Tak, wystarczy zmienić sposób, w jaki zainicjowano "File temp": 'Plik temp = nowy Plik (nowy plik (System.getProperty (" java.io.tmpdir ")), nazwa)'; –

+0

Teraz kopiuję wszystkie pliki DLL, ale kiedy ładuję plik JNI otrzymuję następny wyjątek: Wyjątek w wątku "główny" java.lang.UnsatisfiedLinkError: C: \ Documents and Settings \ Administrator \ Local Settings \ Temp \ hello.dll : Ta aplikacja nie została uruchomiona, ponieważ konfiguracja aplikacji jest niepoprawna. Ponowne zainstalowanie aplikacji może rozwiązać ten problem. Potwierdziłem, że wszystkie biblioteki są w folderze temp ... – supertreta

2

Zasadniczo to powinno zadziałać. W ten sposób JNA to robi, po prostu pobierz i przestudiuj kod. Nawet mieć kilka wskazówek, aby platforma ta niezależna ...

EDIT

JNA przynosi jej kodu macierzystego wraz w słoiku, rozpakowuje poprawny plik binarny przy starcie und ładuje go. Może to być dobry wzór do naśladowania (jeśli mam poprawne pytanie).

+3

Niestety, brakowało Ci czegoś w odpowiedzi? Z "tym" odnosisz się do czego? dzięki – supertreta

-1

trzeba zagruntować classloader z lokalizacji DLL - ale może być ładowany bez wydobywania go ze słoika. Coś prostego przed wykonaniem wywołania obciążenia jest wystarczające. W swojej głównej klasie dodaj:

static { 
    System.loadLibrary("resource/path/to/foo"); // no .dll or .so extension! 
} 

Szczególnie doświadczyłem w zasadzie tego samego issue with JNA and OSGi's handling of how the DLLs are loaded.

+0

Myślę, że uruchomiłem to poprawnie. I działa to dobrze, gdy debuguję go na Eclipse. Problem pojawia się po wyeksportowaniu słoika i uruchomieniu go. Zaktualizowałem odpowiedź moją metodą ładowania. Dzięki! – supertreta

+0

@supertreta: Założę się, że nie pakujesz biblioteki DLL do twojego JARa. Spróbuj zmienić nazwę pliku JAR na plik zip i zapoznaj się z nim. –

+0

Widzę słoik tworząc biblioteki DLL w folderze. Potwierdziłem, że usunąłem je przed uruchomieniem. Sprawdziłem teraz, zamieniając go w zamek błyskawiczny, i oni tam są. – supertreta