Использование интерфейса JNI в RDM Embedded

База данных (БД) RDM Embedded компании Birdstep включает в себя Java-интерфейс, который использует JNI. Интерфейс JNI предоставляет разработчикам на языке Java доступ к тому же компактному и высокопроизводительному ядру БД, которое используется с помощью С/С++. Эта статья поясняет, как максимально быстро настроить и начать использовать интерфейс JNI. Подразумевается, что вы обладаете базовыми знаниями по разработке на Java, а также понимаете, как пользоваться С-интерфейсом RDM Embedded.

Настройка

Вот что необходимо для доступа к данным в RDM Embedded (RDMe) из Java-приложения.

1. Пакет Java SDK (версии 1.2 или старше), который поддерживает JNI.

2. RDM Embedded 7.x для той платформы, на которой вы разрабатываете приложения, и на которой их будут развертывать.

После выполнения этих компонентов требуются три простых шага по конфигурации.

1. Среда

Есть две настройки окружения, которые необходимо применить для получения доступа к данным из программы на Java. Метод их установки будет зависеть от того, как вы используете компилятор java: напрямую или через интегрированную среду разработки (IDE).

  • Необходимо поместить путь к файлу rdm_embedded.jar в переменную CLASSPATH.
  • Также в переменной окружения, где хранятся пути, должен быть указан путь к файлам библиотеки RDM Embedded. Для интерфейса JNI требуются файлы rdm7, psp7 и rdmejni. В зависимости от платформы они могут быть как совместно используемыми объектами, так и динамически подключаемой библиотекой.

2. База данных

Доступ из Java к БД RDM Embedded (RDMe) предоставляется через несколько генерируемых классов, создаваемых компилятором БД RDM Embedded, который называется ddlp. Когда при запуске ddlp указывается флаг -JNI, будет создан исходный файл Java для каждой записи, указанной в определении БД. Для простой схемы, показанной в листинге, будет создан единственный исходный файл с названием SIMPLE_REC.java.

database simple_db {

data file "simple.d01" contains simple_rec;

record simple_rec {

char first_name[32];

char last_name[32];


}

}

 

3. Приложение

Для подготовки приложения к использованию интерфейса JNI нужно просто включить следующие операторы импорта в исходные файлы на Java:

import com.birdstep.rdme.jni.*;

import com.birdstep.rdm.*;

Теперь приложение готово для доступа к данным из RDM Embedded.

Приложение "Hello World" с использованием интерфейса JNI для RDM Embedded (RDMe)

Теперь мы создадим очень простое приложение "Hello World" ("Привет, мир"). Приложение будет открывать БД simple_db, добавлять новую запись simple_rec и показывать все данные, хранящиеся в simple_rec (включая вновь добавленную запись).

Есть два базовых Java-класса RDMe, которые используются для взаимодействия с ядром БД. Первый- это класс RDMe Task, второй - класс RDMe Database. Эти классы подробно описаны в документации на JNI, однако это описание можно свести к следующим двум положениям:

  • класс Task имеет функции-члены для всех интерфейсов RDMe API, которые не получают активный доступ к БД;
  • класс Database имеет функции-члены для всех интерфейсов API, которые получают доступ к БД.

Для этого примера я создал два класса: SimpleExample в качестве основного класса и SimpleDb в качестве класса доступа к БД. Класс SimpleDb имеет переменные-члены Task и Database, которые управляют доступом к БД simple_db.

1 шаг: создание объекта RDMe Task

В конструкторе для класса SimpleDb мы создадим и инициализируем наш объект Task. Мы проделаем минимальную необходимую инициализацию объекта Task, укажем тип Lock Manager и идентификатор пользователя БД. 

/* Создание объекта Task */

try{

taskObj = new Task();

taskObj.lockcomm("Internal");

taskObj.dbuserid("simple_user");

} catch(DBException e) {

throw e;

}

2 шаг: открытие БД

После создания объекта Task мы создадим объект Database путем вызова открытой функции-члена объекта Task. Для этого примера нужно, чтобы файлы БД


(simple_db.dbd и simple.d01) находились в том же каталоге, в котором мы выполняем приложение.

 /* Открытие БД */

try{

dbObj = taskObj.open("simple_db", "s");

}

catch (DBException e) {

System.out.println("Failed to open simple_db " +

e.getErrorNumber());

throw e;

} 

3 шаг: вставка новой записи

Теперь, когда мы успешно создали и инициализировали наши объекты Task и Database, мы можем их использовать для работы с нашей БД. Поскольку важно использовать хорошие методики разработки БД, мы начнем транзакцию, запросим блокировку, добавим новые данные и зафиксируем транзакцию.

/* Начало транзакции, блокировка записи, добавление, фиксации */

try

{

taskObj.trbegin("simple_rec_insert");

dbObj.reclock(simple_db.SIMPLE_REC, "w");

dbObj.fillnew(simple_db.SIMPLE_REC, sr);

taskObj.trend();

}

catch (DBException e) {

System.out.println("Failure inserting record " +

e.getErrorNumber());

/* Прерывание транзакции в случае ошибки */

taskObj.trabort();

throw e;

}

4 шаг: чтение данных

Мы проверим данные, которые только что ввели. Для облегчения этой задачи мы заблокируем current_rec, используем recfrst/next для организации цикла по всем записям, считаем simple_rec и напечатаем содержимое.

/* Блокировка записи и цикл по всем экземплярам*/

try

{

dbObj.reclock(simple_db.SIMPLE_REC, "r");

for(stat = dbObj.recfrst(simple_db.SIMPLE_REC);

stat == RDME.S_OKAY;

stat = dbObj.recnext() )

{

/* чтение и показ записи */

dbObj.recread(sr);

System.out.println(sr.getFIRST_NAME() + " " +

sr.getLAST_NAME() );

}

/* снятие блокировки */

dbObj.recfree(simple_db.SIMPLE_REC);

}


catch (DBException e) {

System.out.println("Failure reading simple_rec " +

e.getErrorNumber());

/* снятие блокировки в случае ошибки */

dbObj.recfree(simple_db.SIMPLE_REC);

throw e;

}

5 шаг: очистка

Для завершения приложения мы используем метод финализации SimpleDb, чтобы закрыть объект Database и освободить ресурсы, связанные с объектом Task.

try {

if(dbObj != null)

{

dbObj.close();

dbObj = null;

}

if(taskObj != null)

{

taskObj.closetask();

taskObj = null;

}

}

catch(DBException e)

{

System.out.println("Failed to close " + e.getErrorNumber());

}

6 шаг: компиляция и выполнение

Все, что осталось сделать после выполнения этих шагов - это компиляция и выполнение программы. За 6 простых шагов мы создали приложение на Java, которое может использовать данные совместно с программой на С для RDM Embedded. Взяв эту программу в качестве исходной точки, не составит труда создать приложение для доступа к вашим собственным данным. 

"Подводные камни" программирования

Вот несколько ошибок программирования, которые я совершил при подготовке этого примера, и способы их исправления.

Компиляция

Проблема

simple_db.java:1: package com.birdstep.rdme.jni does not exist

Решение

Добавить путь к файлу rdm_embedded.jar в переменную classpath

Проблема

SimpleExample.java:63: cannot resolve symbol

symbol : class SIMPLE_REC

location: class SimpleDb

SIMPLE_REC sr;


Решение

  • Убедитесь, что при запуске  ddlp для создания файлов simple_db.java и SIMPLE_REC.java была указана опция.
  • Убедитесь, что вы скомпилировали файлы simple_db.java и SIMPLE_REC.java для создания файлов simple_db.class и SIMPLE_REC.class.
  • Убедитесь, что местоположение файлов simple_db.class и SIMPLE_REC.class указано в переменной classpath.

Запуск

Проблема

Exception in thread "main" java.lang.UnsatisfiedLinkError: no

RDMEjni in java.library.path

at java.lang.ClassLoader.loadLibrary(Unknown Source)

at java.lang.Runtime.loadLibrary0(Unknown Source)

at java.lang.System.loadLibrary(Unknown Source)

at com.birdstep.rdme.jni.Task.<clinit>(Task.java:71)

at SimpleDb.<init>(SimpleExample.java:21)

at SimpleExample.main(SimpleExample.java:134)

Решение

Убедитесь, что dll-файлы динамических библиотек RDM Embedded или совместно используемые объекты указаны в переменной окружения системных путей.

Проблема

Failed to open simple_db -4

DBException:

com.birdstep.rdm.DBException: RDM Database Error: -4

at

com.birdstep.rdme.jni.Database.validate(Database.java:716)

at com.birdstep.rdme.jni.Database.open(Database.java:150)

at

com.birdstep.rdme.jni.Database.<init>(Database.java:143)

at com.birdstep.rdme.jni.Task.open(Task.java:99)

at SimpleDb.<init>(SimpleExample.java:30)

at SimpleExample.main(SimpleExample.java:134)

Решение

Убедитесь, что вы скомпилировали (с помощью ddlp) и инициализировали (с помощью initdb) схему simple_db (simple_db.ddl).

Полный исходный код

Исходный код для схемы БД и код на Java можно загрузить с узла:

ftp://ftp.raima.com/outgoing/DatabaseInsights/simple_jni.tgz


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=8475