Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования JAVA.pdf
Скачиваний:
374
Добавлен:
02.05.2014
Размер:
2.57 Mб
Скачать

converted to PDF by BoJIoc

Каждая статическая константа с атрибутом final представлена константой #define с префиксами (именем пакета и класса). Статические поля, не являющиеся final, не переводятся ни во что. Например, тип и константы для класса LockableFile определяются в заголовочном файле следующим образом:

typedef struct Classlocal_LockableFile { struct Hjava_lang_String *path;

/* недоступное статическое поле: separator */

/* недоступное статическое поле: separatorChar */ /* недоступное статическое поле: pathSeparator */

/* недоступное статическое поле: pathSeparatorChar */ #define local_LockableFile_READ 0L

#define local_LockableFile_WRITE 1L long fd;

} Classlocal_LockableFile;

Ссылки на объекты представляются типом дескриптор”, в составном имени которого Class заменяется на H. Ссылка на класс LockableFile будет называться Hlocal_LockableFile. Макрос unhand получает дескриптор и возвращает указатель на структуру, которая представляется этим дескриптором.

Ниже приведены сигнатуры функций языка C, в которых ниже мы определим родные методы класса LockableFile:

extern void local_Lockable_File_lock( struct Hlocal_LockableFile *, long);

extern void local_Lockable_File_unlock( struct Hlocal_LockableFile *);

В Java об ошибках сигнализируют исключения. В языке C исключений нет. Чтобы возбудить исключение из C, следует вызвать функцию SignalError и затем выйти. Runtime- система Java обнаруживает и возбуждает исключение, о котором сигнализировала функция SignalError. Ниже вы увидите несколько примеров того, как это делается.

А.2.5 Средства безопасности

Средства безопасности языка Java не имеют аналогов в C. Вы полностью отвечаете за работу программы на C (как это обычно бывает) без какой-либо автоматической помощи со стороны Java.

А.2.6 Работа с памятью

Родные методы могут создавать новые объекты Java с помощью функций, описанных ниже.

А.3 Пример

Давайте рассмотрим возможную реализацию родных методов для класса LockableFile. Прежде всего, мы должны сгенерировать заголовочный файл и файл-заглушку и скомпилировать последний. Затем нужно написать сами реализации методов. Например, метод lock может быть реализован следующим образом:

#include "local_LockableFile.h" #include <<javaString.h>> #include <<fcntl.h>>

#include <<errno.h>>

void local_LockableFile_lock(

converted to PDF by BoJIoc

struct Hlocal_LockableFile *this_h, long mode)

{

Classlocal_LockableFile *this = unhand(this_h); struct flock lock;

if (this->>fd == -1 && !open_fd(this))

*/

return;

/* произошла ошибка

if (!setup_lock(&lock, mode)) return;

if(fcntl(this->>fd, F_SETLKW, &lock) == -1) SignalError(EE(),

"java/io/IOException", strerror(errno));

}

Сначала мы включаем нужные заголовочные файлы сгенерированный файл для LockableFile, вспомогательный заголовочный файл для работы со строками <<javastring.h>>, системный заголовочный файл <<fcntl.h>>, определяющий вызовы для осуществления блокировки в POSIX, и системный заголовочный файл <<errno.h>> для обработки ошибок, полученных в ходе вызовов системных функций.

Первая строка в реализации метода lock переводит дескриптор this_h в указатель на структуру Classlocal_LockableFile, для чего используется макрос unhand, который возвращает объект, соответствующий данному дескриптору. Ссылкам null в Java ставится в соответствие указатели на дескрипторы, которые также равны NULL. Чтобы убедиться в том, что передача ссылки null не приведет к ошибкам, необходимо проверить дескриптор перед тем, как вызывать для него макрос unhand это демонстрируется в последующих примерах.

Во второй строке local_LockableFile_lock объявляется структура flock. Структура flock используется для работы с блокировкой в POSIX. Реализации open_fd и setup_lock приводятся в разделе Внутреннее строение LockableFile”.

Далее мы проверяем, имеется ли файловый дескриптор. Если он отсутствует и функция open_fd не может открыть файл, видимо, было возбуждено исключение, сигнализирующее об ошибке, поэтому мы просто выходим из функции. Если же дескриптор имеется, то структуру flock необходимо подготовить вызовом внутренней функции setup_lock. Вызов функции также может закончиться неудачей (например, если mode имеет недопустимое значение) и возбуждением исключения и в этом случае мы выходим из функции. Функции open_fd и setup_lock являются частью кода, специфичного для POSIX.

Затем мы пытаемся заблокировать файл с помощью режима F_SETLKW функции POSIX с именем fcntl, который при необходимости ожидает возможности блокировки. Если fcntl возвращает -1, то попытка блокировки оказалась неудачной, и мы возбуждаем исключение, вызывая runtime-функцию Java с именем SignalError:

void SignalError(ExecEnv *exenu, char *type, char *constructor)

Сигнализирует о том, что после выхода из родного метода должно быть возбуждено исключение. Структура exenu обычно возвращается функцией EE и представляет текущее состояние среды. Параметр type является полным именем класса возбуждаемого объекта-исключения, в котором каждая точка (.) заменяется чертой (/). Последний параметр содержит строковое описание исключения или NULL при его отсутствии.

В нашем случае используется значение функции POSIX с именем strerror, которая возвращает строку с описанием номера ошибки. Практически это самое лучшее, что мы можем сделать для описания ошибок в родных методах.

converted to PDF by BoJIoc

Функция SignalError лишь подготавливает исключение; она не возбуждает его. В языке C исключения не предусмотрены, поэтому возбудить их из программы невозможно. После выхода из функции, содержащей реализацию родного метода, runtime-система проверяет флаги и по ним определяет, был ли получен сигнал о возбуждении исключения. Если такой сигнал получен, то runtime-система возбуждает исключение. Подобная схема позволяет в программе на C выполнить необходимые завершающие действия после возбужденияисключения. В функции local_LockableFile_lock такие действия не требуются, поэтому после возбужденияисключения мы просто выходим из нее.

Реализация unlock выглядит проще. Мы подготавливаем структуру flock и вызываем fcntl для режима F_UNLCK (снятие блокировки). И снова при неудаче возбуждается исключение, содержащее строку с описанием ошибки:

void local_LockableFile_unlock(

struct Hlocal_LockableFile *this_h)

{

Classlocal_LockableFile *this = unhand(this_h); struct flock lock;

lock.l_whence = lock.l_start = lock.l_len = 0; lock.l_type = F_UNLCK;

if (fcntl(this->>fd, F_SETLKW, &lock) == -1) SignalError(EE(),

"java/io/IOException", strerror(errno));

}

В класс LockableFile можно внести ряд усовершенствований. Например, создать функцию для проверки того, заблокирован ли файл и если да, то каким программным потоком. Можно сконструировать специальный вариант lock без ожидания, который лишь осуществляет блокировку, если она возможна, а в противном случае завершает свою работу. Или создать отдельные исключения для каждой ошибки, чтобы ошибка файл не существуетотличалась от доступ запрещен”.

Упражнение А.1

Если у вас имеется доступ к системе, отличной от POSIX и поддерживающей блокировку файлов, реализуйте класс LockableFile с использованием ее механизмов.

Упражнение А.2

Если вы работаете только с POSIX-совместимыми системами или выполнили упражнение А.1, включите в класс описанные выше возможности.

А.3.1 Внутреннее строение LockableFile

Для полноты картины приведем текст внутренних функций, используемых классом LockableFile. Статические функции open_fd и setup_lock используются при реализации родных методов lock и unlock:

static int open_fd(Classlocal_LockableFile *this)

{

char *path = allocCString(this->>path);

if ((this->>fd = open(path, O_RDWR)) == -1) SignalError(EE(),

"java/io/IOException", strerror(errno)); free(path); /* больше не требуется */

return (this->>fd != -1);