Нативные библиотеки и Java Web Start
От: dshe  
Дата: 20.04.04 06:57
Оценка:
Привет всем,

Есть некая нативная dll'ка, которая содержит функциональность, которая должна использоваться в Java приложении, но по некоторым соображениям ее нельзя переписать на Java. Назовем ее native.dll. Эта библиотека успешно используется в существующих C/C++ приложениях, но она ничего не знает о том, что она будет использоваться в Java приложении, т.е. она не экспортирует имена в удобном для Java виде. Предположим, она экспортирует функцию под именем DoSomething.

Для того, чтобы использовать native.dll, написан класс (с нативной реализацией в библиотеке adapter.dll)
package com.comp.adapter;

public class Adapter {
     static {
          System.loadLibrary("adapter");
     }
     public native void doSomething();
}

с приблизительно такой реализацией
// adapter.dll: adapter.cpp
JNIEXPORT void JNICALL Java_com_comp_adapter_Adapter_doSomething
     (JNIEnv *env, jobject)
{
     HINSTANCE hLibrary = LoadLibrary(_T("native.dll"));
     void (*func)() = (void (*)()) GetProcAddress(hLibrary, _T("DoSomething"));
     func();
     FreeLibrary(hLibrary);
}


Это все дело работает, если запускается Java приложение, в текущей директории которого присутствуют обе библиотеки (native.dll и adapter.dll).

Это Java приложение деплоится через Java Web Start. Для этого обе нативные либы, упаковываются в native.jar, этот .jar подписывается и прописывается ссылка на него в .jnlp файл приложения.

Однако через Java Web Start это приложение не работает. В тот момент, когда приложение запускается, загружается (успешно) adapter.dll, выполняется вызов doSomething, пытается загрузиться библиотека native.dll, и она не находится. Почему не находится, в общем-то понятно -- вызов LoadLibrary ищет ее по "своим" местам: в директории экзешника (в данном случае %JRE_HOME%/bin), в текущей (десктоп текущего пользователя), в системной (C:\Windows\System32), в windows (C:\Windows), в директориях, указанных в %PATH%, но не там, куда ее скачал JWS.

Вопрос заключается в следующем: как сделать так, что бы native.dll находилась и загружалась, и могла быть использована?
--
Дмитро
Re: Нативные библиотеки и Java Web Start
От: Cider Россия  
Дата: 20.04.04 08:02
Оценка:
Здравствуйте, dshe, Вы писали:

D>Вопрос заключается в следующем: как сделать так, что бы native.dll находилась и загружалась, и могла быть использована?


Такое ощущение, что это вообще не в яву.
А в этом си-коде можно вытащить содержимое jar ? Если да, то наверное можно это содержимое подсунуть в loadlibrary...
Спроси у сишников.

Cider
Cider
Re[2]: Нативные библиотеки и Java Web Start
От: dshe  
Дата: 20.04.04 08:14
Оценка:
Здравствуйте, Cider, Вы писали:

C>Здравствуйте, dshe, Вы писали:


D>>Вопрос заключается в следующем: как сделать так, что бы native.dll находилась и загружалась, и могла быть использована?


C>А в этом си-коде можно вытащить содержимое jar ? Если да, то наверное можно это содержимое подсунуть в loadlibrary...


Ты имеешь ввиду распаковать? Думаю, можно. Было бы странно, если бы в нативном коде нельзя было бы сделать что-то, что можно в java. Проблема заключается в том, что я не знаю точно какой jar распаковывать (JWS сохраняет его не с оригинальным именем) и где он в файловой системе пользователя лежит.
--
Дмитро
Re: Нативные библиотеки и Java Web Start
От: Аноним  
Дата: 09.08.04 06:40
Оценка:
У меня такая же проблема. Т.е. в обыкновенном приложении dll подгружается и все работает, потом этот же код перевожу в вэб-приложение и вылетает вот такой эксэпшон:"java.lang.UnsatisfiedLinkError". Причем метод System.loadLibrary("xxxx") выполняется. А потом при вызове какого-либо метода все рушится.
И где найти ответ не знаю.
Елси ты разобрался, дай знать пожалуйста.
Спасибо.
Re: Нативные библиотеки и Java Web Start
От: LCR Россия lj://_lcr_
Дата: 09.08.04 08:29
Оценка: +1
Здравствуйте, dshe, Вы писали:

D>Для того, чтобы использовать native.dll, написан класс (с нативной реализацией в библиотеке adapter.dll)

D>
D>package com.comp.adapter;

D>public class Adapter {
D>     static {
D>          System.loadLibrary("adapter");
D>     }
D>     public native void doSomething();
D>}
D>

D>с приблизительно такой реализацией
D>
D>// adapter.dll: adapter.cpp
D>JNIEXPORT void JNICALL Java_com_comp_adapter_Adapter_doSomething
D>     (JNIEnv *env, jobject)
D>{
D>     HINSTANCE hLibrary = LoadLibrary(_T("native.dll"));
D>     void (*func)() = (void (*)()) GetProcAddress(hLibrary, _T("DoSomething"));
D>     func();
D>     FreeLibrary(hLibrary);
D>}
D>


D>Вопрос заключается в следующем: как сделать так, что бы native.dll находилась и загружалась, и могла быть использована?


Функция API LoadLibrary ищет библиотеки по следующим местам
    1. Каталог, откуда было запущено приложение
    2. Текущий каталог
    3. Системный каталог
    4. 16-битный системный каталог
    5. Каталог Windows
    6. Все каталоги из PATH

Следовательно, нужно всего лишь добавить нужный каталог в PATH. Либо можно в функции Java_com_comp_adapter_Adapter_doSomething использовать следующую функцию:

HMODULE LoadLibraryEx(
  LPCTSTR lpFileName,
  HANDLE hFile,
  DWORD dwFlags
);

где dwFlags может, в частности, включать флаг LOAD_WITH_ALTERED_SEARCH_PATH. Если в lpFileName указан путь, то стратегия поиска меняется на
    1. Каталог из lpFileName. Короче это каталог, где расположена библиотека
    2. Текущий каталог
    3. Системный каталог
    4. 16-битный системный каталог
    5. Каталог Windows
    6. Каталог из PATH.
Возможно это то, что тебе нужно.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re: Нативные библиотеки и Java Web Start
От: dfa Эстония  
Дата: 09.08.04 09:25
Оценка:
Здравствуйте, dshe, Вы писали:

D>Это Java приложение деплоится через Java Web Start. Для этого обе нативные либы, упаковываются в native.jar, этот .jar подписывается и прописывается ссылка на него в .jnlp файл приложения.


D>Вопрос заключается в следующем: как сделать так, что бы native.dll находилась и загружалась, и могла быть использована?


В jnlp файл native.jar добавлять следующим образом:

<jnlp ...>
[...]
    <resources os="Windows">
        <nativelib href="path/to/native.jar" download="eager" />
    </resources>
[...]
</jnlp>


пример layout'а для native.jar:

>jar -tf libs.jar

META-INF/
META-INF/MANIFEST.MF
swt-awt-win32-3043.dll
swt-win32-3043.dll
Re[2]: Нативные библиотеки и Java Web Start
От: UnSmoke  
Дата: 09.08.04 16:00
Оценка:
Друзья!! Да дело не в этом! У меня из обыкновенного приложения все грузится и работает.
А вот из вэб приложения, под резином — ничего. И нет у меня никаких xml файлов, я использую максимум web.xml, мне из моего класса надо подгрузитоь dll вsполнить несколько методов и все. И вроде сама dll находится и подгружается, а потом теряется, может дело в резине?
Оччень жду ответа, заранее бАльшое СПАСИБО
Re[3]: Нативные библиотеки и Java Web Start
От: dfa Эстония  
Дата: 09.08.04 16:19
Оценка:
Здравствуйте, UnSmoke, Вы писали:

US>Друзья!! Да дело не в этом! У меня из обыкновенного приложения все грузится и работает.

US>А вот из вэб приложения, под резином — ничего. И нет у меня никаких xml файлов, я использую максимум web.xml, мне из моего класса надо подгрузитоь dll вsполнить несколько методов и все. И вроде сама dll находится и подгружается, а потом теряется, может дело в резине?
US>Оччень жду ответа, заранее бАльшое СПАСИБО

Мы говорили про WebStart.

В твоем случае посмотри, что выдает

System.getProperty("java.library.path")


например с помощью такого jsp

<%
    out.println(System.getProperty("java.library.path"));
%>


Твои dll'ки должны лежать в указанном месте. Или можешь переопределить эту property.
Re[4]: Нативные библиотеки и Java Web Start
От: dfa Эстония  
Дата: 09.08.04 16:24
Оценка:
dfa>В твоем случае посмотри, что выдает

[skipped]

dfa>Твои dll'ки должны лежать в указанном месте. Или можешь переопределить эту property.


Забыл сказать, что понятия не имею, будет ли это работать.

Так, на всякий случай.
Re[5]: Нативные библиотеки и Java Web Start
От: UnSmoke  
Дата: 10.08.04 02:52
Оценка:
Здравствуйте, dfa, Вы писали:

dfa>>В твоем случае посмотри, что выдает


dfa>[skipped]


dfa>>Твои dll'ки должны лежать в указанном месте. Или можешь переопределить эту property.


dfa>Забыл сказать, что понятия не имею, будет ли это работать.


dfa>Так, на всякий случай.


dll-ки лежат по указанным путям. Все нормально. Но ничего не работает. Может все дело в явском обеспечении безопасности и переносимости? Может из-под вэб-приложения вообще нельзя dll-ки поднимать?
Re[6]: Нативные библиотеки и Java Web Start
От: Denis Afonin Эстония  
Дата: 10.08.04 07:11
Оценка:
> dll-ки лежат по указанным путям. Все нормально. Но ничего не работает. Может все дело в явском обеспечении безопасности и переносимости? Может из-под вэб-приложения вообще нельзя dll-ки поднимать?

Need more details. www.caucho.com -> Search -> loadLibrary

если бы из-за безопасности, то был бы SecurityException...

Другие поднимают. Что пытаешься решить с помощью JNI?
Posted via RSDN NNTP Server 1.9 beta
Re[7]: Нативные библиотеки и Java Web Start
От: UnSmoke  
Дата: 10.08.04 08:06
Оценка:
Здравствуйте, Denis Afonin, Вы писали:

>> dll-ки лежат по указанным путям. Все нормально. Но ничего не работает. Может все дело в явском обеспечении безопасности и переносимости? Может из-под вэб-приложения вообще нельзя dll-ки поднимать?


DA>Need more details. www.caucho.com -> Search -> loadLibrary


DA>если бы из-за безопасности, то был бы SecurityException...


DA>Другие поднимают. Что пытаешься решить с помощью JNI?


Есть dll. Из обыкновенного приложения она поднимается и работает, т.е. вызываются методы и т.п.
Когда к этой же dll обращаюсь из сервлета или из другого класса, ничего не получается.
Т.е. метод System.loadLibrary("native");отрабатывает, а при обращении к к.л. методу из этой dll вылетает ошибка java.lang.UnsatisfiedLinkError. Вот.

А dll позволяет коннектится к MatLab. И работать с ним из Java программы. Моя задача сделать чтобы через вэб-интерфейс, можно было вызывать функции матлаба, и получать данные из него. Dll уже написана, не мной. Это JMatLink.
Т.е. есть ява-класс, который реализует поднимание этой dll-ки и обращение к ее методам.На сайте разработчика никакой поддержки — последнее обновление в 2001 году. Самое интересное то,что эта штука работает, и очень меня устраивает, но только в обыкновенном приложении. т.е. все отрабатывает — запускается матлаб, принимает запросы, считает там что-нибудь, и отдает ответ.
Может в резине какие нибудь настройки особые есть по этому поводу.

dll эту уже куда только не клал, и в системные пути чего только не добавлял, никакого результата.

Ну вобщем я запарился конкретно уже.
Re[8]: Нативные библиотеки и Java Web Start
От: nant Россия  
Дата: 10.08.04 08:53
Оценка:
Здравствуйте, UnSmoke, Вы писали:

US>Здравствуйте, Denis Afonin, Вы писали:


>>> dll-ки лежат по указанным путям. Все нормально. Но ничего не работает. Может все дело в явском обеспечении безопасности и переносимости? Может из-под вэб-приложения вообще нельзя dll-ки поднимать?


DA>>Need more details. www.caucho.com -> Search -> loadLibrary


DA>>если бы из-за безопасности, то был бы SecurityException...


DA>>Другие поднимают. Что пытаешься решить с помощью JNI?


US>Есть dll. Из обыкновенного приложения она поднимается и работает, т.е. вызываются методы и т.п.

Приложение Java или native?
US>Когда к этой же dll обращаюсь из сервлета или из другого класса, ничего не получается.
А то если Java, то не вполне понятно, почему "из другого класса ничего не получается"
US>Т.е. метод System.loadLibrary("native");отрабатывает, а при обращении к к.л. методу из этой dll вылетает ошибка java.lang.UnsatisfiedLinkError. Вот.
Есть у меня резонное ощущение, что ты пытаешься напрямую вызвать DLL из Java путем простой декларации native-метода без описания его реализации.

Дай пожалуйста пример кода и stack trace ошибки на этом коде.
Re[9]: Нативные библиотеки и Java Web Start
От: Аноним  
Дата: 10.08.04 09:27
Оценка:
Здравствуйте, nant, Вы писали:


N>Приложение Java или native?


Приложение вот такое





public class Test {

    public static void main(String args[]) {
        JMatLink engine=new JMatLink();
        engine.engOpenSingleUse();
        engine.engEvalString("m=2");
        engine.engClose();
    }
}




JMatLink — это класс, который обращается к dll. Т.е. он и вызывает System.loadLibrary("JMatLink"), и остальные методы.
Вот он



import java.io.*;

public class JMatLink extends Thread { 

   // static declarations
   // the variable "status" is used to tell the main
   //   thread what to do.
   private final static int idleI             =   0;
   private final static int engOpenI          =   1;  
   private final static int engCloseI         =   2;  
   private final static int engEvalStringI    =   3;
   private final static int engGetScalarI     =   4;
   private final static int engGetVectorI     =   5;
   private final static int engGetArrayI      =   6;
   private final static int engPutArray2dI    =   9;
   private final static int engOutputBufferI  =  10;
   private final static int engGetCharArrayI  =  11;  
   private final static int destroyJMatLinkI  =  12;
   private final static int engOpenSingleUseI =  13;

   // All variables are global to allow all methods
   //   and the main thread to share all data
   private int              status           =   idleI;
   private String           arrayS;
   private String           engEvalStringS;
   private String           engOutputBufferS;
   private double           engGetScalarD;
   private double[]         engGetVectorD;
   private double[][]       engGetArrayD;
   private double           engPutArrayD;
   private double[]         engPutArray1dD;
   private double[][]       engPutArray2dD;
   private String[]         engGetCharArrayS;
   private int              epI;                 /* Engine pointer */
   private int              retValI;             /* return Value of eng-methods */
   private String           startCmdS;           /* start command for engOpen... */
   private int              buflenI;             /* output buffer length         */
   private boolean          debugB            =  false;

   // Locks
   private boolean          lockEngineB       =  false;
   private boolean          lockThreadB       =  false;
   private boolean          lockWaitForValueB =  false;
   private boolean          destroyJMatLinkB  =  false;

   private Thread runner;

   // ***********************  native declarations  ****************************
   // NEVER call  native methods directly, like
   //   JMatLink.engEvalStringNATIVE("a=1"). Matlab's engine has quite some 
   //   thread problems. 
   private native void       displayHelloWorld();
   private native void       engTestNATIVE();    

   private native int        engOpenNATIVE          (String startCmdS );
   private native int        engOpenSingleUseNATIVE (String startCmdS );

   private native int        engCloseNATIVE         (int epI);

   private native int        engEvalStringNATIVE    (int epI, String evalS );

   private native double     engGetScalarNATIVE     (int epI, String nameS );
   private native double[]   engGetVectorNATIVE     (int epI, String nameS );
   private native double[][] engGetArrayNATIVE      (int epI, String nameS );
   private native String[]   engGetCharArrayNATIVE  (int epI, String nameS );

   private native void       engPutArrayNATIVE      (int epI, String matrixS, double[][] valuesDD);

   private native String     engOutputBufferNATIVE  (int epI, int buflenI );

   private native void       setDebugNATIVE         (boolean debugB       );

   // *******************************************************************************
   // **************     load JMatLink library into memory     **********************
   static {
      try { //System.out.println("loading");
            System.loadLibrary("JMatLink");
            //System.out.println("loaded"); 
          }
      catch (UnsatisfiedLinkError e) {
          System.out.println("ERROR: Could not load the JMatLink library");
          System.out.println("       This error occures, if the path to");
          System.out.println("       matlab's <matlab>\\bin directory is");
          System.out.println("       not set properly.");
          System.out.println("       Or if JMatLink.dll is not found.");
      }
   }


    // ************************ JMatLink constructor ***************************
    /** This is the constructor for the JMatLink library. 
    *  
    * <p>E.g.:<br>
    * <pre>
    *   <b>JMatLink</b> engine = new <b>JMatLink()</b>;
    *   engine.engOpen();   
    *   engine.engEvalString("surf(peaks)");  
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public JMatLink() {
       if (debugB) System.out.println("JMatLink constructor");
       runner = new Thread(this);
       runner.start();
    }

    // **** terminate running thread ****
    public void destroy() {
      destroyJMatLinkB = true;
      notifyAll();
    }

    public void kill() {
      destroyJMatLinkB = true;
      callThread(destroyJMatLinkI);
    }

//////////////////////////////////////////////////////////////////////////////


    // *****************************   engOpen   *****************************
    /** Open engine. This command is used to open a <b>single</b> connection
    *  to matlab.
    *  
    * <p>E.g.:<br>
    * <pre>
    *   JMatLink engine = new JMatLink();
    *   engine.<b>engOpen()</b>;   
    *   engine.engEvalString("surf(peaks)");  
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized  int  engOpen()
    {
        return engOpen( "" );  // return value is pointer to engine
    }


    // *****************************   engOpen   *******************************
    /** Open engine. This command is used to open a <b>single</b> connection
    *   to matlab.<p> This command is only useful on unix systems. On windows
    *   the optional parameter <b>must</b> be NULL.
    *  
    * <p>E.g.:<br>
    * <pre>
    *   JMatLink engine = new JMatLink();
    *   engine.<b>engOpen("commands to start matlab")</b>;   
    *   engine.engEvalString("surf(peaks)");  
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized  int  engOpen(String startCmdS)
    {
        // startup MATLAB and set up connection
        lockEngineLock();             
        lockWaitForValue();

        this.startCmdS = startCmdS;

        callThread( engOpenI );    

        WaitForValue();
        releaseEngineLock();  

        return this.epI;
    }


    // **************************   engOpenSingleUse   *****************************
    /** Open engine for single use. This command is used to open
    *  <b>multiple</b> connections to matlab.
    *  
    * <p>E.g.:<br>
    * <pre>
    *   int a,b;
    *   JMatLink engine = new JMatLink();
    *   a = engine.<b>engOpenSingleUse()</b>;   // start first matlab session
    *   b = engine.<b>engOpenSingleUse()</b>;   // start second matlab session
    *   engine.engEvalString(a, "surf(peaks)");  
    *   engine.engEvalString(b, "foo=ones(10,0)");
    *   engine.engClose(a);
    *   engine.engClose(b);
    * </pre>
    ***************************************************************************/
    public synchronized int engOpenSingleUse()
    {
        return engOpenSingleUse("");
    }

    // **************************   engOpenSingleUse   *****************************
    /** Open engine for single use. This command is used to open
    *  <b>multiple</b> connections to matlab.
    *  
    * <p>E.g.:<br>
    * <pre>
    *   int a,b;
    *   JMatLink engine = new JMatLink();
    *   a = engine.<b>engOpenSingleUse("start matlab")</b>;   // start first matlab session
    *   b = engine.<b>engOpenSingleUse("start matlab")</b>;   // start second matlab session
    *   engine.engEvalString(a, "surf(peaks)");  
    *   engine.engEvalString(b, "foo=ones(10,0)");
    *   engine.engClose(a);
    *   engine.engClose(b);
    * </pre>
    ***************************************************************************/
    public synchronized int engOpenSingleUse(String startCmdS)
    {
        lockEngineLock();             
        lockWaitForValue();

        this.startCmdS = startCmdS;

        callThread( engOpenSingleUseI );    

        WaitForValue();
        releaseEngineLock();

        return this.epI;  
    }


    // *****************************   engClose   *****************************
    /** Close the connection to matlab.
    *
    * <p>E.g.:<br>
    * <pre>
    *  JMatLink engine = new JMatLink();
    *  engine.engOpen();
    *  engine.engEvalString("surf(peaks)");   
    *  engine.<b>engClose()</b>;  
    * </pre>
    ***************************************************************************/
    public synchronized void engClose()
    {
        engClose( this.epI );
    }


    // *****************************   engClose   *****************************
    /** Close a specified connection to an instance of matlab.
    *
    * <p>E.g.:<br>
    * <pre>
    *  int a,b;
    *  JMatLink engine = new JMatLink();
    *  a = engine.engOpenSingleUse();       // start first  matlab session
    *  b = engine.engOpenSingleUse();       // start second matlab session
    *  engine.engEvalString(b, "surf(peaks)");   
    *  engine.engEvalString(a, "array = randn(23)");   
    *  engine.<b>engClose</b>(a);      // Close the first  connection to matlab
    *  engine.<b>engClose</b>(b);      // Close the second connection to matlab
    * </pre>
    ***************************************************************************/
    public synchronized void engClose( int epI)
    {
        // close connection and terminate MATLAB
        lockEngineLock();
        lockWaitForValue();

        this.epI = epI;

        callThread( engCloseI );

        WaitForValue();
        releaseEngineLock();

        // return retValI; Return value indicates success
    }


    // *****************************   engEvalString   *****************************
    /** Evaluate an expression in matlab's workspace.
    *
    * E.g.:<br>
    * <pre>
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen();   
    *   engine.<b>engEvalString</b>("surf(peaks)");
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized void engEvalString(String evalS)
    {
        engEvalString( this.epI, evalS);
    }


    // *****************************   engEvalString   *************************
    /** Evaluate an expression in a specified workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *  int a,b;
    *  JMatLink engine = new JMatLink();
    *  a = engine.engOpenSingleUse();  
    *  engine.<b>engEvalString</b>(a, "surf(peaks)");
    *  engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized void engEvalString(int epI, String evalS)
    {
        // evaluate expression "evalS" in specified engine Ep
        if (debugB) System.out.println("eval(ep,String) in  " + epI + " "+evalS);
        lockEngineLock();
        lockWaitForValue();

        this.epI       = epI;
        engEvalStringS = evalS;

        callThread( engEvalStringI );

        WaitForValue();
        releaseEngineLock();

        if (debugB) System.out.println("eval(ep,String) out "+epI+" "+evalS);
        // return retValI; Return value indicates success
    }


    // *****************************   engGetScalar   **************************
    /** Get a scalar value from matlab's workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *  double a;
    *  JMatLink engine = new JMatLink();
    *  engine.engOpen();
    *  engine.engEvalString("foo = sin( 3 )");
    *  a = engine.<b>engGetScalarValue</b>("foo");  
    *  engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized double engGetScalar(String arrayS)
    {
        return engGetScalar( this.epI, arrayS);
    }


    // *****************************   engGetScalar   **************************
    /** Get a scalar value from a specified workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   double a;
    *   int b;
    *   JMatLink engine = new JMatLink();
    *   b = engine.engOpenSigleUse();  
    *   engine.engEvalString(b, "foo = sin( 3 )");
    *   a = engine.<b>engGetScalarValue</b>(b, "foo");
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized double engGetScalar(int epI, String arrayS)
    {
        // Get scalar value or element (1,1) of an array from
        //   MATLAB's workspace  
        // Only real values are supported right now

        lockEngineLock();
        lockWaitForValue();

        /* copy parameters to global variables */
        this.epI    = epI;
        this.arrayS = arrayS;

        callThread( engGetScalarI );


        WaitForValue();
        releaseEngineLock();

        return engGetScalarD;
    }


    // *****************************   engGetVector   **************************
    /** Get an array (1 * n) from matlab's workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   double[] array;
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen();
    *   engine.engEvalString("array = randn(10,1);");
    *   array = engine.<b>engGetVector</b>("array");
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized  double[]  engGetVector( String arrayS )
    {
        return engGetVector( this.epI, arrayS );
    }

    // *****************************   engGetVector   **************************
    /** Get an array (1 * n) from a specified workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   int b;
    *   double[] array;
    *   JMatLink engine = new JMatLink();
    *   b = engine.engOpenSingleUse();  
    *   engine.engEvalString(b, "array = randn(10,1);");
    *   array = engine.<b>engGetVector</b>(b, "array");
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized  double[]  engGetVector( int epI, String arrayS )
    {  
        // only real values are supported so far
        lockEngineLock();
        lockWaitForValue();

        this.epI    = epI;
        this.arrayS = arrayS;

        callThread( engGetVectorI );

        WaitForValue();
        releaseEngineLock();

        return engGetVectorD;
    }


    // *****************************   engGetArray   ***************************
    /** Get an array from matlab's workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   int b;
    *   double[][] array;
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen();
    *   engine.engEvalString("array = randn(10);");
    *   array = engine.<b>engGetArray</b>("array");
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized  double[][]  engGetArray( String arrayS )
    {
        return engGetArray( this.epI, arrayS );
    }


    // *****************************   engGetArray   ***************************
    /** Get an array from a specified instance/workspace of matlab.
    *
    * <p>E.g.:<br>
    * <pre>
    *   int b;
    *   double[][] array;
    *   JMatLink engine = new JMatLink();
    *   b = engine.engOpenSingleUse();
    *   engine.engEvalString(b, "array = randn(10);");
    *   array = engine.<b>engGetArray</b>(b, "array");
    *   engine.engClose(b);
    * </pre>
    ***************************************************************************/
    public synchronized  double[][]  engGetArray( int epI, String arrayS )
    {  
        // only real values are supported so far
        lockEngineLock();
        lockWaitForValue();

        this.epI    = epI;
        this.arrayS = arrayS;

        callThread( engGetArrayI );
        WaitForValue();
        releaseEngineLock();

        return engGetArrayD;
    }

    // **************************   engGetCharArray   *****************************
    /** Get an 'char' array (string) from matlab's workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   String array;
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen(); 
    *   engine.engEvalString("array = 'hello world';");
    *   array = engine.<b>engCharArray</b>("array");
    *   System.out.println("output = "+ array);
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized String[] engGetCharArray(String arrayS)
    {  
        // convert to double array
        engEvalString( "engGetCharArrayD=double(" + arrayS +")" );

        // get double array
        double[][] arrayD = engGetArray("engGetCharArrayD");

        // delete temporary double array
        engEvalString("clear engGetCharArrayD");

        // convert double back to char
        return double2String( arrayD );
    }


    // *****************************   engPutArray   ***************************
    /** Put an array into a specified workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   int array = 1;
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen();  
    *   engine.<b>engPutArray</b>("array", array);
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized void engPutArray( String arrayS, int valueI )
    {
        engPutArray( this.epI, arrayS, new Integer(valueI).doubleValue());
    }


    // *****************************   engPutArray   ***************************
   // public synchronized void   engPutArray( String arrayS, int[] valuesI )
   // {
   //     engPutArray( this.epI, arrayS, (double[])valuesI );
   // }


    // *****************************   engPutArray   ***************************
    /** Put an array into matlab's workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   double array = 1;
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen(); 
    *   engine.<b>engPutArray</b>("array", array);
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized void engPutArray( String arrayS, double valueD )
    {
        engPutArray( this.epI, arrayS, valueD);
    }


    // *****************************   engPutArray   *****************************
    /** Put an array into a specified instance/workspace of matlab.
    *
    * <p>E.g.:<br>
    * <pre>
    *   int b;
    *   double array = 1;
    *   JMatLink engine = new JMatLink();
    *   b = engine.engOpenSingleUse(); 
    *   engine.<b>engPutArray</b>(b, "array", array);
    *   engine.engClose(b);
    * </pre>
    ***************************************************************************/
    public synchronized void engPutArray( int epI, String arrayS, double valueD )
    {
        
        double vDD[][]   = {{0.0}};
               vDD[0][0] = valueD;
        engPutArray( epI, arrayS, vDD );  // nxn dimensional
    }


    // *****************************   engPutArray   ***************************
    /** Put an array (1 dimensional) into a specified instance/workspace of 
    *   matlab.
    *
    * <p>E.g.:<br>
    * <pre>
    *   double[] array = {1.0 , 2.0 , 3.0};
    *   JMatLink engine = new JMatLink();
    *   engine.engOpen();  
    *   engine.<b>engPutArray</b>("array", array);
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized void   engPutArray( String arrayS, double[] valuesD )
    {
        engPutArray( this.epI, arrayS, valuesD );
    }


    // *****************************   engPutArray   *****************************
    /** Put an array (1 dimensional) into a specified instance/workspace of 
    *   matlab.
    *
    * <p>E.g.:<br>
    * <pre>
    *   int b;
    *   double[] array = {1.0 , 2.0 , 3.0};
    *   JMatLink engine = new JMatLink();
    *   b = engine.engOpenSingleUse();  
    *   engine.<b>engPutArray</b>(b, "array", array);
    *   engine.engClose(b);
    * </pre>
    ***************************************************************************/
    public synchronized void   engPutArray(int epI, String arrayS, double[] valuesD)
    {
        double[][] vDD = new double[1][valuesD.length]; // 1xn array

        if (debugB) System.out.println("length  = "+valuesD.length);

        vDD[0] = valuesD; // copy row 

        engPutArray( epI, arrayS, vDD );
    }


    // *****************************   engPutArray   ***************************
    /** Put an array (2 dimensional) into matlab's workspace.
    *
    * <p>E.g.:<br>
    * <pre>
    *   double[][] array={{1.0 , 2.0 , 3.0},
    *                     {4.0 , 5.0 , 6.0}};
    *   JMatLink engine = new JMatLink();
    *   engine.engOpenSingleUse();  
    *   engine.<b>engPutArray</b>("array", array);
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public synchronized void engPutArray( String arrayS, double[][] valuesDD )
    {
        engPutArray( this.epI, arrayS, valuesDD );
    }


    // *****************************   engPutArray   ***************************
    /** Put an array (2 dimensional) into a specified instance/workspace of 
    *   matlab.
    *                  
    * <p>E.g.:<br>                                          
    * <pre>                                          
    *   int b;                                        
    *   double[][] array={{1.0 , 2.0 , 3.0},           
    *                     {4.0 , 5.0 , 6.0}};       
    *   JMatLink engine = new JMatLink();         
    *   b = engine.engOpenSingleUse();        
    *   engine.engPutArray(b, "array", array);         
    *   engine.engClose(b);             
    * </pre>     
    ***************************************************************************/
    public synchronized void engPutArray(int epI, String arrayS, double[][] valuesDD)
    {
        // send an array to MATLAB
        // only real values are supported so far
        lockEngineLock();
        lockWaitForValue();

        this.epI            = epI;
        this.arrayS         = arrayS;
        this.engPutArray2dD = valuesDD;

        callThread( engPutArray2dI );

        WaitForValue();
        releaseEngineLock();
    }


    // *****************************   engOutputBuffer   ***********************
    /** Return the outputs of previous commands from matlab's workspace.          
    *                                                                          
    * <p>E.g.:<br>                                                                
    * <pre>                                                                    
    *   String buffer;                                                         
    *   JMatLink engine = new JMatLink();                                    
    *   engine.engOpen();                                                   
    *   engine.engEvalString("surf(peaks)");                                   
    *   buffer = engine.<b>engOutputBuffer</b>();                              
    *   System.out.println("workspace " + buffer);                             
    *   engine.engClose();                                                     
    * </pre>                                                                   
    ***************************************************************************/
    public synchronized String  engOutputBuffer( )
    {
        return engOutputBuffer( this.epI, this.buflenI );
    }

    // *****************************   engOutputBuffer   ***********************
    /** Return the outputs of previous commands from a specified instance/
    *   workspace form matlab.          
    *                                                                          
    * <p>E.g.:<br>                                                                
    * <pre>                                                                    
    *   String buffer;                                                         
    *   JMatLink engine = new JMatLink();                                      
    *   engine.engOpen();                                                   
    *   engine.engEvalString("surf(peaks)");                                   
    *   buffer = engine.<b>engOutputBuffer</b>();                              
    *   System.out.println("workspace " + buffer);                             
    *   engine.engClose();                                                     
    * </pre>                                                                   
    ***************************************************************************/
    public synchronized String  engOutputBuffer( int epI )
    {
        return engOutputBuffer( epI, this.buflenI );
    }

    // *****************************   engOutputBuffer   ***********************
    /** Return the ouputs of previous commands in matlab's workspace.          
    *
    * Right now the parameter <i>buflen</i> is not supported.
    *                                                                          
    * <p>E.g.:<br>                                                                
    * <pre>                                                                    
    *   String buffer;                                                         
    *   JMatLink engine = new JMatLink();                                      
    *   engine.engOpen();                                                  
    *   engine.engEvalString("surf(peaks)");                                   
    *   buffer = engine.<b>engOutputBuffer</b>();                              
    *   System.out.println("workspace " + buffer);                             
    *   engine.engClose();                                                     
    * </pre>                                                                   
    ***************************************************************************/
    public synchronized String  engOutputBuffer( int epI, int buflenI )
    {
        // get the output buffer from MATLAB
        if (debugB) System.out.println("Thread in: "+Thread.currentThread().getName());

        lockEngineLock();
        lockWaitForValue();

        this.epI     = epI;
        this.buflenI = buflenI;

        callThread( engOutputBufferI );

        WaitForValue();
        releaseEngineLock();
        if (debugB) System.out.println("Thread out: "+Thread.currentThread().getName());

        return engOutputBufferS;
    }


    // *****************************  setDebug   *******************************
    /* Switch on or disable debug information printed to standard output.
    *
    * <p>Default setting is debug info disabled.
    * <p>E.g.:<br>
    * <pre>
    *   JMatLink engine = new JMatLink();
    *   engine.engOpenSingleUse();  
    *   engine.<b>setDebug(true)</b>;
    *   engine.engEvalString("a=ones(10,5);");
    *   engine.engClose();
    * </pre>
    ***************************************************************************/
    public void setDebug( boolean debugB )
    {
        this.debugB = debugB;
        setDebugNATIVE( debugB ); 
    }


    ////////////////////////////////////////////////////////////////////////////////
    // This method notifys the main thread to call matlab's engine
    //    Since threads don't have methods, we set a variable which
    //    contains the necessary information about what to do.
    private synchronized void callThread(int status)
    {
        this.status = status;
        lockThreadB = false;
        notifyAll();
    }


////////////////////////////////////////////////////////////////////////////////
// The run methods does ALL calls to the native methods
// The keyword "synchronized" is neccessary to block the run()
//    method as long as one command needs to get executed.
public synchronized void run()
{ 
    int tempRetVal;

    if (debugB) System.out.println("JMatLink: thread is running");  
    while (true) {
        // System.out.println("Number of Java-Threads: "+Thread.activeCount()+"");
        // Thread thread = Thread.currentThread();
        // System.out.println("Name of active Java-Threads: "+thread.getName()+"");
        // System.out.println("active Java-Thread is Daemon: "+thread.isDaemon();+"");  
 

     switch (status) {
     case engOpenI:          epI = engOpenNATIVE( startCmdS );
                             releaseWaitForValue();
                             break;

     case engOpenSingleUseI: epI = engOpenSingleUseNATIVE( startCmdS );
                             releaseWaitForValue();
                             break;

     case engCloseI:         retValI = engCloseNATIVE( epI );
                             releaseWaitForValue();
                             break;

     case engEvalStringI:    retValI = engEvalStringNATIVE(epI, engEvalStringS);
                             releaseWaitForValue();
                             break;

     case engGetScalarI:     engGetScalarD  = engGetScalarNATIVE(epI, arrayS );
                             releaseWaitForValue();
                             break;

     case engGetVectorI:     engGetVectorD  = engGetVectorNATIVE(epI, arrayS );
                             releaseWaitForValue();
                             break;

     case engGetArrayI:      engGetArrayD  = engGetArrayNATIVE(epI, arrayS );
                             releaseWaitForValue();
                             break;

     case engGetCharArrayI:  engGetCharArrayS  = engGetCharArrayNATIVE(epI, arrayS );
                             releaseWaitForValue();
                             break;

     case engPutArray2dI:    engPutArrayNATIVE( epI, arrayS, engPutArray2dD );
                             releaseWaitForValue();
                             break;

     case engOutputBufferI:  engOutputBufferS = engOutputBufferNATIVE( epI, buflenI );
                             releaseWaitForValue();
                             break;


     default:                //System.out.println("thread default switch statem.");
     }  
     status=0;

     lockThreadB = true;
     while (lockThreadB == true) {
       synchronized(this) {
          try { wait();} // wait until next command is available
          catch (InterruptedException e) { }
       }
     }
     //System.out.println("JMatLink: thread awoke and passed lock"); 
     if (destroyJMatLinkB == true) break;
   } // end while
   if (debugB) System.out.println("JMatLink: thread terminated");
} // end run


////////////////////////////////////////////////////////////////////////////////
// The MATLAB engine is served by a thread. Threads don't have methods
//   which can be called. So we need to send messages to that thread
//   by using notifyAll. In the meantime NO OTHER methods is allowed to
//   access our thread (engine) so we lock everything up. 
   private void lockEngineLock(){
      synchronized(this){
         while (lockEngineB==true){
            try { //System.out.println("lockEngineLock locked");
                  wait();} // wait until last command is finished
            catch (InterruptedException e) { }
         }
         //now lockEngineB is false
         lockEngineB = true;   
      }
   } // end lockEngine

   private synchronized void releaseEngineLock(){
      lockEngineB = false;
      notifyAll();
   }

////////////////////////////////////////////////////////////////////////////////
// The MATLAB engine is served by a thread. Threads don't have methods
//    which can be called directly. If we send a command that returns data
//    back to the calling function e.g. engGetArray("array"), we'll notify
//    the main thread to get the data from matlab. Since the data is collected
//    in another thread, we don't know exactly when the data is available, since
//    this is a concurrent situation. 
//    The solution is simple: I always use a locking-mechanism to wait for the
//    data. The main thread will release the lock and the calling method can
//    return the data.
//
//    Steps:
//    1. a method that returns data calls the locking method
//    2. notify the thread to call matlab
//    3. wait for the returned data
//    4. after the thread itself got the data it releases the locks method
//    5. return data

   private synchronized void lockWaitForValue(){
      lockWaitForValueB = true;
   }

   private void WaitForValue(){
      synchronized(this){
         while (lockWaitForValueB==true){
            try { //System.out.println("lockWaitForValue locked");
                  wait();} // wait for return value
            catch (InterruptedException e) { }
         }
      }
      //System.out.println("WaitForValue released");
   } // end waitForValue

   private synchronized void releaseWaitForValue(){
      lockWaitForValueB = false;
      notifyAll();
   }


////////////////////////////////////////////////////////////////////////////////
////                        Utility methods                                 ////


  // Convert an n*n double array to n*1 String vector
  private String[] double2String(double[][] d) 
  {
      String encodeS[]=new String[d.length];  // String vector

      // for all rows
      for (int n=0; n<d.length; n++){
          byte b[] = new byte[d[n].length]; 
          // convert row from double to byte
          for (int i=0; i<d[n].length ;i++) b[i]=(byte)d[n][i];
     
          // convert byte to String
          try { encodeS[n] = new String(b, "UTF8");}
          catch (UnsupportedEncodingException e) {}
      }
      return encodeS;
  } // end double2String

} // end class JMatLink





N>А то если Java, то не вполне понятно, почему "из другого класса ничего не получается"

N>Есть у меня резонное ощущение, что ты пытаешься напрямую вызвать DLL из Java путем простой декларации native-метода без описания его реализации.

N>Дай пожалуйста пример кода и stack trace ошибки на этом коде.


Это работает.

А когда я в сервлете выполняю следующие действия:

        JMatLink engine=new JMatLink();
        engine.engOpenSingleUse();
        engine.engEvalString("m=2");
        engine.engClose();


выкидывается след. ошибка

java.lang.UnsatisfiedLinkError: engOpenSingleUseNATIVE
at beans.JMatLink.engOpenSingleUseNATIVE(Native Method)
at beans.JMatLink.run(JMatLink.java:867)
at java.lang.Thread.run(Thread.java:534)

причем если я создаю какой-нить класс, и делаю в нем метод который вызывает эти ф-ии, а потм в сервлете создаю объект этого класса и вызываю этот метод — та же история
Re[10]: Нативные библиотеки и Java Web Start
От: UnSmoke  
Дата: 10.08.04 10:33
Оценка: 16 (1)
Проблема решена:

http://www.caucho.com/support/resin-interest/0111/0044.html

That's a JDK "feature". You can't load a JNI library in more than one
classloader. That means if you try to load the .dll (or .so) with the
web-app loader, and then the application restarts (because you touched
the resin.conf or a .jar or a .class) the reloaded application will then
fail when it tries to load the JNI.


The easiest way to work around that is to put the class with the
System.loadLibrary in the global classpath, i.e. resin/lib, instead of
in WEB-INF/lib.


Спасибо за участие!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.