Обслуживание Соединения по Нескольким Запросам
В некоторых случаях может понадобиться, чтобы единственное соединение захватывало несколько клиентских запросов. То есть Вы сможете использовать одно соединение на нескольких страницах HTML.
Обычно вы используете свойства объекта client для информации, захватывающего клиентские запросы. Однако значение свойства объекта client не может быть объектом. Исходя из этого, Вы не можете сохранять пул соединений БД в объекте client. Вместо этого Вы используете пул соединений, хранимый в объекте project, обслуживая их так, как описано в данном разделе. Если вы используете этот подход, Вам может понадобиться кодирование пользовательской информации, по соображениям безопасности.
ПРЕДУПРЕЖДЕНИЕ!
Будьте особенно осторожны при использовании такого подхода, поскольку сохранение соединения таким способом делает его недоступным для других пользователей. Если все соединения окажутся недоступны, новые запросы будут ожидать явного освобождения соединения или таймаута соединения. Это особенно проблематично для однопоточных библиотек БД. (Об установлении соединений так, что они будут запрашиваться, если не заняты в течение продолжительного времени, см. ).
В следующем примере соединение и транзакция захватывают несколько клиентских запросов. Код сохраняет соединение как свойство объекта sharedConns, который сам является свойством объекта project. Объект sharedConns не является предопределённым объектом JavaScript. Он просто создан в данном примере и может иметь другое имя, по Вашему выбору.
Поскольку один пул используется всеми клиентами, Вы должны создавать объект sharedConns и создавать и соединять сам пул на начальной странице приложения примерно таким кодом:
project.sharedConns = new Object();
project.sharedConns.conns = new Object();
project.sharedConns.pool = new DbPool ("SYBASE", "sybaseserver",
"user", "password", "sybdb", 10, false);
Затем на первой клиентской странице, получающей доступ к пулу, следуйте такой стратегии:
// Генерируется уникальный индекс для обращения к данному клиенту, если он ещё
// не сгенерирован на другой странице.
if client.id == null {
client.id = ssjs_generateClientID();
}// Для удобства устанавливается переменная для данного пула.
var clientPool = project.sharedConns.pool;// Проверяется, соединён ли пул. Если нет, перенаправляется
// на специальную страницу для информирования пользователя.
project.lock();
if (!clientPool.connected()) {
delete project.sharedConns.pool;
project.unlock();
redirect("noconnection.htm");
}
project.unlock();// Соединение получается из пула и сохраняется в объекте project.
project.sharedConns.conns[client.id] = clientPool.connection();
var clientConn = project.sharedConns.conns[client.id];
clientConn.beginTransaction();
cursor = clientConn.cursor("select * from customers", true");
// ... другие операции с БД ...
cursor.close();
}
Заметьте, что эта страница не выполняет откат или подтверждение транзакции. Соединение остаётся открытым, и транзакция продолжается. (Транзакции рассматриваются в разделе ).
Вторая HTML-страница запрашивает соединение, базируясь на значении client.id, и продолжает работать с БД так:
// Запрашивается соединение.
var clientConn = project.sharedConns.conns[client.id];
// ... Выполняются ещё какие-нибудь операции с БД ...
// Здесь, если операции с БД успешно прошли, okay устанавливается в 1.
// Если была ошибка при работе с БД, okay устанавливается в 0. В конце
// подтверждается или откатывается транзакция на основе этого значения.
if (okay)
clientConn.commitTransaction();
else
clientConn.rollbackTransaction();
// Соединение возвращается в пул.
clientConn.release();
// Избавляемся от значения свойства объекта. Оно Вам больше не нужно.
delete project.sharedConns.conns[client.id];
В этом примере объект sharedConns сохраняет единственный объект DbPool и соединения для данного пула, которые используются в данный момент. Ситуация может быть значительно сложнее. Если у Вас имеется фиксированный набор пулов БД, Вы можете определить отдельный объект для хранения соединений каждого пула.
Если у вас имеется массив пулов и каждому пулу необходимы соединения, захватывающие несколько запросов, Вам необходимо создать массив объектов, каждый из которых сохраняет пул и массив его соединений. Как ответвление, вместо немедленного перенаправления в том случае, если пул не соединён, клиентская страница может сделать новую попытку установить соединение.
Если Вы используете ssjs_generateClientID и храните ID в объекте client, Вам понадобится защита от вторжения и получения доступа к ID и, следовательно, к закрытой информации.
Обслуживание Транзакций
Транзакция это несколько действий с базой данных, выполняемых вместе. Либо все эти действия выполняются успешно, либо все вместе терпят неудачу. Если эти действия выполняют (окончательно) изменения БД, говорится, что транзакция подтверждена. Вы можете также выполнить откат /roll back транзакции, т.е. не подтвердить её; это отменяет все выполненные действия.
Транзакции важны для поддержания целостности и структуры данных. В то время как различные серверы БД реализуют механизм транзакций с некоторыми отличиями, сервис LiveWire Database Service предоставляет одни и те же методы для обслуживания транзакций на всех БД. Проверьте в документации продавца БД информацию о согласованности данных и уровнях изоляции транзакций.
Вы можете использовать явный контроль транзакции над выполнением любого набора действий. Например, акции, модифицирующие БД, должны проходить под управлением транзакций. Это акции, соответствующие операторам SQL INSERT, UPDATE и DELETE. Транзакции могут также использоваться для контролирования согласованности данных.
Для большинства БД, если Вы не выполняете явного управления транзакциями, машина выполнения использует фоновый механизм БД - autocommit/автоподтверждение, когда каждый оператор в БД рассматривается как отдельная транзакция. Каждый оператор подтверждается или откатывается немедленно на основе успеха или неуспеха выполнения каждого отдельного оператора. Явное управление транзакциями переопределяет работу этого механизма по умолчанию.
В некоторых БД, таких как Oracle, autocommit это явный механизм, который LiveWire включает для каждого отдельного оператора. В других БД, таких как Informix, autocommit это поведение по умолчанию, если Вы не создаёте транзакцию. В общем, LiveWire скрывает эти различия и переводит приложение в режим autocommit, если приложение не использует beginTransaction для явного старта транзакции.
Для ANSI-БД Informix, LiveWire не использует autocommit. Для этих БД приложение всегда использует транзакции, даже если никогда явно не вызывает beginTransaction. Приложение обязано использовать commitTransaction или rollbackTransaction для завершения транзакции.
ПРИМЕЧАНИЕ:
Настоятельно советуем всегда использовать явный контроль транзакций при выполнении изменений в БД. Это гарантирует, что изменения будут сделаны или отменены вместе. Кроме того, при использовании обновляемых курсоров Вы также всегда должны использовать явные транзакции для контроля за целостностью Ваших данных в период между чтением данных (с помощью next) и их изменением (с помощью insertRow, updateRow или deleteRow).
Как указано в разделе , использование явного контроля транзакций и обновляемых курсоров необходимо для того, чтобы исключить ошибки в некоторых БД, таких как Oracle и Informix.
Обзор Процессов Времени Прогона (Выполнения)
После того как Вы установили и стартовали приложение JavaScript, пользователь может получить к нему доступ.
Базовые процедуры таковы:
- Пользователь выполняет доступ к приложению по его URL в web-браузере, таком как Netscape Communicator. Браузер отправляет клиентский запрос страницы приложения на сервер.
Если это запрос к странице с URL приложения, машина выполнения JavaScript, запущенная на сервере, находит информацию в web-файле, соответствующем этому URL. О деталях этого процесса и о том, что происходит на этом и на последующих двух этапах, см. в разделе .
Машина времени выполнения конструирует HTML-страницу для отправки клиенту. Она выполняет байт-коды, ассоциированные с тэгами SERVER, из исходного кода HTML, создавая HTML-страницу на основе этих байт-кодов и иного HTML, имеющегося в оригинале. О том, как влиять на процесс конструирования страницы, см. в разделе .
Машина выполнения высылает новую HTML-страницу (которая может содержать операторы клиентского JavaScript) клиенту.
Машина выполнения JavaScript внутри web-браузера интерпретирует любые операторы клиентского JavaScript, форматирует вывод HTML и выводит результат пользователю.
иллюстрирует это процесс.
Рисунок 5.1Процессинг запроса JavaScript-страницы
![](image/proc.gif)
Конечно, пользователь обязан иметь Netscape Navigator (или иной браузер с возможностью выполнения JavaScript), чтобы клиент мог интерпретировать операторы клиентского JavaScript. Аналогично, если Вы создаёте страницу, содержащую серверный JavaScript, он должен быть установлен на Netscape-сервере, чтобы нормально функционировать.
Например, предположим, клиент запрашивает страницу с таким исходным кодом:
<html>
<head> <title> Add New Customer </title> </head>
<body text="#FFFF00" bgcolor="#C0C0C0" background="blue_marble.gif">
<img src="billlog2.gif">
<br><server>
if ( project.lock() ) {
project.lastID = 1 + project.lastID;
client.customerID = project.lastID;
project.unlock();
}
fields are required for the
</server><h1>Add a New Customer </h1>
<p>Note: <b>All</b> fields are required for the new customer
<form method="post" action="add.htm"></p>
<p>ID:
<br> <server>write("<STRONG><FONT COLOR=\"#00FF00\">" +
project.lastID + "</FONT></STRONG>");</server>
<!-- другие операторы html --></body>
</html>
При доступе к этой странице машина выполнения выполняет на сервере код, ассоциированный с тэгами SERVER. (Этот код выделен жирным шрифтом.) Если ID нового потребителя 42, сервер высылает клиенту для отображения такую HTML-страницу:
<html>
<head> <title> Add New Customer </title> </head>
<body text="#FFFF00" bgcolor="#C0C0C0" background="blue_marble.gif">
<img src="billlog2.gif">
<br><h1>Add a New Customer </h1>
<p>Note: <b>All</b> fields are required for the new customer
<form method="post" action="add.htm"></p>
<p>ID:
<br><STRONG><FONT COLOR="#00FF00">42</FONT></STRONG>
<!-- другие операторы html -->
</body>
</html>
Очистка Буфера Вывода
Для повышения производительности, JavaScript буферизует конструируемую им HTML-страницу. Функция flush сразу высылает данные из внутреннего буфера клиенту. Если Вы явно не вызываете функцию flush, JavaScript высылает данные клиенту после создания каждых 64KB содержимого конструируемой HTML-страницы.
Не путайте функцию flush с методом flush класса File. (Об использовании класса File для ввода и вывода в файл см. ).
Вы можете использовать flush для управления временем переноса данных клиенту. Например, Вы можете очищать буфер до операции, создающей задержку/delay, такой как запрос к базе данных. Также, если запрос к БД запрашивает большое количество рядов, очистка буфера каждый раз после получения нескольких рядов предотвращает паузы при отображении данных.
ПРИМЕЧАНИЕ:
Если Вы используете клиентские куки для обслуживания свойств объекта client, Вы обязаны делать все изменения объекта client до очистки буфера. Дополнительно см. .
Следующий фрагмент кода показывает, как используется flush. Предположим, Ваше приложение должно выполнить некоторые действия с каждым потребителем/customer в Вашей БД потребителей. Если потребителей много, процесс может затянуться. Поэтому, для того чтобы пользователь не ждал у застывшего экрана, Ваше приложение может высылать вывод клиенту до начала обработки и затем вновь - после конца обработки каждого ряда. Для этого Вы должны использовать примерно такой код:
flush();
conn.beginTransaction();
cursor = conn.cursor ("SELECT * FROM CUSTOMER", true);
while ( cursor.next() ) {
// ... обработка ряда ...
flush();
}
conn.commitTransaction();
cursor.close();
ODBC
Все платформы: О возможностях и об используемых ODBC-драйверах см.
Вам необходимо иметь соответствующие ODBC-драйверы для БД, с которой Вы устанавливаете соединение. Также необходимо иметь дополнительные файлы ODBC-соединений/connectivity.
Большинство программных продуктов, предоставляющие ODBC connectivity, поддерживают ODBC-драйвер или драйверы и ODBC connectivity.
Только для NT: В настоящее время Netscape сертифицирован с ODBC Manager версии 2.5. Если у вас имеется доступ к ODBC-драйверу, но не к файлам ODBC connectivity, Вы можете получить их в MS ODBC SDK. Чтобы получить обновлённые файлы для Access, Foxpro и Excel, Вам может понадобиться патч WX1350 от Microsoft.
Только для Unix: Для ODBC на Unix вы можете использовать драйвер от Visigenic либо от OpenLink. Если Вы используете драйвер от Visigenic, следуйте инструкциям раздела Если Вы используете драйвер от OpenLink, следуйте инструкциям раздела
ODBC Data Source Names/Имена Источников Данных (только NT)
Могут быть созданы два типа источников данных:
System/Системное DSN: Если вы используете системное DSN, web-сервер обязан стартовать в бюджете System.User/Пользовательское DSN: Если вы используете пользовательское DSN, web-сервер обязан стартовать в соответствующем пользовательском бюджете NT (user account).
Источник данных описывает параметры соединения для каждой БД, необходимые для ODBC connectivity. Источник данных определяется чрез использование ODBC-администратора. Если ODBC установлен, администратор также устанавливается. Каждый ODBC-драйвер требует различной информации для определения источника данных.
Однопоточные и Многопоточные Базы Данных
LiveWire поддерживает многопоточный доступ к БД. То есть она поддерживает наличие более чем одного потока доступа к одной БД в единицу времени. Отсюда ясно, для чего нужен пул соединений с более чем одним соединением. Однако библиотеки БД некоторых производителей не являются многопоточными. Для таких БД не имеет значения, сколько соединений имеется в Вашем пуле, так как только одно соединение может устанавливаться с БД в единицу времени.
В этой таблице дан список клиентских библиотек баз данных, которые являются многопоточными на указанных платформах.
NT | Есть | Есть | Есть | Есть | Есть | ||||||
Sun Solaris | Есть | Есть | Есть | Нет | Нет | ||||||
HP-UX | Есть | Есть | Нет | Нет | Нет | ||||||
IBM AIX | Есть | Есть | Нет | Есть | Нет | ||||||
SGI IRIX | Нет | Нет | Нет | Не поддерживается | Нет | ||||||
Digital Unix | Есть | Есть | Нет | Не поддерживается | Не поддерживается |
1
Все многопоточные тесты для ODBC были сделаны на MS SQL Server. Если Вы используете другой драйвер ODBC, узнайте у производителя, является ли драйвер многопоточным. |
Окружение (Рабочая Среда)
Возможности LiveConnect ядра языка JavaScript работают на сервере иначе, чем на клиенте. См. дополнительно .
JavaScript предоставляет дополнительную функциональность без использования объектов. Вы получаете доступ к этой функциональности через функции, не ассоциированные с каким-либо объектом (глобальные функции). Ядро языка JavaScript имеет глобальные функции, описанные в следующей таблице (также как и другие функции, описанные в документации Ядра JavaScript).
escape |
Возвращает 16-ричный код аргумента - символа из набора символов ISO Latin-1; используется при создании строк для добавления в URL. | |
unescape |
Возвращает ASCII-строку для специфицированного значения; используется при разборе строки, добавленной в URL. | |
isNaN |
Вычисляет аргумент для определения не является ли он "неЧислом". | |
parseFloat |
Разбирает аргумент-строку и возвращает число с плавающей точкой. | |
parseInt |
Разбирает аргумент-строку и возвращает целое число. |
Серверный JavaScript добавляет глобальные функции, описанные в следующей таблице.
write |
Добавляет операторы к генерируемой клиентской HTML-странице. (См. .) | |
flush |
Очищает буфер вывода. (См. .) | |
redirect |
Перенаправляет клиента по специфицированному URL. (См. .) | |
getOptionValue |
Получает значения отдельных опций в элементе HTML-формы SELECT. (См. .) | |
getOptionValueCount |
Получает количество опций в элементе HTML-формы SELECT. (См. .) | |
debug |
Выводит значения выражений в окне (фрэйме) трассировки. (См. .) | |
addClient |
Присоединяет клиентскую информацию к URL. (См. .) | |
registerCFunction |
Регистрирует внешнюю функцию для использования в серверном JavaScript. (См. .) | |
callC |
Вызывает внешнюю функцию. (См. .) | |
deleteResponseHeader |
Удаляет информацию из "шапки" ответа, высылаемого клиенту. (См. .) | |
addResponseHeader |
Добавляет новую информацию в "шапку" ответа, высылаемого клиенту. (См. .) | |
ssjs_getClientID |
Возвращает идентификатор для client -объекта, используемый при некоторых видах клиентской техники JavaScript. (См. .) | |
ssjs_generateClientID |
Возвращает идентификатор, который Вы можете использовать для уникального специфицирования объекта client. (См. .) | |
ssjs_getCGIVariable |
Возвращает значение специфицированной переменной окружения CGI. (См. .) |
OpenLink ODBC-Драйвер (только Solaris)
Установите брокер запросов OpenLink Workgroup Edition ODBC Driver на сервер БД. Он должен быть запущен, до того как Вы сможете соединиться с БД с использованием агента запросов OpenLink.
Установите агента запросов (request agent) в клиенте OpenLink Generic ODBC версии 1.5 на клиентской машине БД.
Переименуйте или скопируйте файл драйвера менеджера агента запросов из libiodbc.so в libodbc.so в директории $ODBCDIR/lib, где $ODBCDIR это директория, в которой установлен ODBC.
Когда Вы устанавливаете Ваш сервер, Вы делаете так, чтобы он запускался как некоторый пользователь: root, nobody или конкретный пользователь сервера. Выбранный Вами пользователь должен иметь домашнюю директорию, которую, возможно, понадобится создать. Например, по умолчанию домашняя директория для пользователя nobody на Irix это /dev/null. Если Вы устанавливаете Ваш сервер на Irix как nobody, Вы обязаны создать для пользователя nobody другую домашнюю директорию.
В этой домашней директории Вы обязаны иметь файл .odbc.ini. Например, если сервер запускается как root, этот файл находится в директории (/).
Установите следующие переменные окружения:
LD_LIBRARY_PATH |
(Solaris и Irix) Добавляет размещение ODBC-библиотек к данной переменной. | |
UDBCINI |
Специфицирует местонахождение файла .odbc.ini. |
Определение Прототипа для Хранимой Процедуры
Этот этап относится только к пользовательским и системным хранимым процедурам DB2, ODBC и Sybase. Вам не нужно определять прототип хранимых процедур БД Oracle или Informix.
Для DB2, ODBC и Sybase программа не может определить в процессе выполнения, предназначен определённый параметр для ввода, вывода, или для того и другого. Соответственно, после того как Вы подключились к БД, Вы обязаны создать прототип, предоставляющий информацию о хранимой процедуре, которую Вы хотите использовать, через метод storedProcArgs объекта database или DbPool.
Вам нужно использовать по одному прототипу для каждой хранимой процедуры Вашего приложения. Программа игнорирует дополнительные прототипы для одной и той же процедуры.
В прототипе Вы предоставляете имя хранимой процедуры и тип каждого из её параметров. Параметр обязан быть: для ввода/input (IN), вывода/output (OUT), а для ввода и вывода - (INOUT).
Например, чтобы создать прототип для хранимой процедуры newhire, имеющей два параметра ввода и один параметр вывода, можно использовать такой вызов метода:
poolobj.storedProcArgs("newhire", "IN", "IN", "OUT");
Oracle
Чтобы использовать сервер Oracle, Вы обязаны иметь Netscape Enterprise Server. Вы не можете получить доступ к Oracle из Netscape FastTrack Server.
Если БД и web-сервер находятся на разных машинах, следуйте инструкциям раздела
Если БД и web-сервер находятся на одной машине, следуйте инструкциям раздела
Только для Unix: Убедитесь, что Вы можете соединиться с Вашей БД Oracle через SQL*Net. Если Вы закончили инсталяцию, Вы можете использовать loopback-тест для проверки корректности соединения. Например, из sqlplus Вы можете попытаться соединиться с Вашей БД с помощью следующей команды:
connect username/password@service_name
Или из командной строки Unix:
sqlplus username/password@service_name
В этих командах Вы используете service_name из Вашего файла tnsnames.ora.
Прежде чем использовать нижеуказанные инструкции, Вы обязаны сконфигурировать Ваш Oracle-клиент, как указано в разделе Помимо этого, Ваш клиент обязан быть сконфигурирован для запуска утилит Oracle. Чтобы запускать SQL Plus, Вам может понадобиться установить переменную окружения ORACLE_SID.
SQL-файлы для создания видео-БД в Oracle, находятся в двух директориях:
$NSHOME\js\samples\videoapp\ora
$NSHOME\js\samples\oldvideo\ora
И в Unix, и в NT: стартуйте SQL Plus. Из промпта SQL> введите такую команду:Start $NSHOME\js\samples\videoapp\ora\ora_video.sql
Вы можете также запустить этот скрипт из директории oldvideo. Этот SQL-скрипт не создаёт новую БД. Он создаёт таблицы Oracle в текущем экземпляре.
В Unix: запустите скрипт-файл ora_load для загрузки видео-таблиц с данными. В NT: запустите пакетный файл ora_load.bat для загрузки видео-таблиц с данными. Вы обязаны отредактировать соответствующий файл для подключения к Вашему серверу; инструкции об этом содержатся в файле.
Теперь можно запускать приложение, сделав изменения, описанные в разделе .
Основные Этапы Создания Приложения
Обычно HTML статичен: после того как Вы написали HTML-страницу, её содержимое фиксируется. Фиксированное содержимое пересылается с сервера клиенту, когда клиент выполняет доступ к странице по её URL. С помощью JavaScript Вы можете создавать HTML-страницы, которые могут изменяться вслед за изменением данных или в ответ на действия пользователя. На показана базовая процедура создания и запуска приложения JavaScript.
Рисунок 3.1 Создание и Запуск Приложения JavaScript
![](image/devcycle.gif)
Для создания приложения JavaScript Вы должны выполнить следующие шаги:
Создать исходные файлы. Исходные файлы могут быть HTML-файлами с внедрённым JavaScript, файлами, содержащими только JavaScript, или исходными файлами на Java. (См. .)
Заметьте, что Виртуальная Машина JavaScript (VM), используемая в Netscape Enterprise Server 4.0, реализует значительные улучшения в процессинге локальных переменных (то есть переменных, объявленных внутри функций), по сравнению с NES 3.6. Отсюда следует, что нужно минимизировать использование глобальных переменных (то есть тех, которые объявлены между тэгами <server> и </server>) и переписать приложения так, чтобы максимально использовать функции. Это значительно увеличит скорость работы приложения.
Построить приложение с использованием компилятора приложений JavaScript для создания исполняемого байт-кода (файла .web). (См. .) Скомпилировать исходные файлы Java в файлы классов.
Опубликовать web-файл, все необходимые файлы HTML, изображений и клиентского JavaScript и откомпилированные файлы Java-классов в соответствующие директории на сервере. Вы можете использовать Netscape Web Publisher для публикации Ваших файлов, как описано в книге Web Publisher User's Guide.
Установить приложение в первый раз (см. ) с помощью Менеджера Приложений JavaScript. Вы можете также использовать Менеджер Приложений для рестарта приложения после его перестроения/rebuilding (см. ). Инсталяция или рестарт приложения заставляют машину выполнения JavaScript запустить это приложение на выполнение.
После инсталяции приложения Вам может потребоваться защитить его. См. раздел . Вам не нужно рестартовать приложение после его начальной инсталяции.
Запустить приложение, щёлкнув Run в Менеджере Приложений или загрузив URL приложения в браузер. (См. и .) Например, чтобы запустить Hello World, загрузите в браузер http://server.domain/world/. Вы можете выполнить также отладку приложения, щёлкнув Debug в Менеджере Приложений. (См. .)
После того как Вы завершили разработку и тестирование Вашего приложения, Вам нужно будет опубликовать его, чтобы сделать доступным для пользователей. Процесс публикации обычно включает в себя инсталяцию приложения на конечном сервере и изменение прав доступа. (См. .)
Прежде чем Вы сможете разрабатывать приложения на JavaScript, Вам нужно будет запустить машину выполнения на сервере и, возможно, защитить Менеджер Приложений JavaScript от неавторизованного доступа. Дополнительно см. разделы и .
Открытие и Закрытие Файла
После создания File -объекта Вы можете использовать метод open для открытия файла и чтения и записи. Метод open имеет следующий синтаксис:
result = fileObjectName.open("mode");
Это метод возвращает true, если операция прошла успешно, и false в ином случае. Если файл уже открыт, операция терпит неудачу, и оригинальный файл остаётся открытым.
Параметр mode это строка, специфицирующая режим открытия файла. В таблице описаны эти режимы.
r |
Открывает файл, если он существует, как текстовый файл для чтения и возвращает true. Если файл не существует, возвращает false. | ||
w |
Открывает файл как текстовый файл для записи. Создаёт новый (первоначально пустой) текстовый файл, независимо от того, существует файл или нет. | ||
a |
Открывает файл как текстовый файл для дополнения (записи в конец файла). Если файл ещё не существует, создаёт его. | ||
r+ |
Открывает файл как текстовый файл для чтения и записи. Чтение и запись начинаются в начале файла. Если файл существует, возвращает true. Если не существует, возвращает false. | ||
w+ |
Открывает файл как текстовый файл для чтения и записи. Создаёт новый (первоначально пустой) текстовый файл, независимо от того, существует файл или нет. | ||
a+ |
Открывает файл как текстовый файл для чтения и записи. Чтение и запись начинаются в конце файла. Если файл не существует, создаёт его. | ||
b |
Если присоединён к одному из вышеуказанных режимов, открывает файл как бинарный/двоичный файл, а не как текстовый. Применяется только для операционных систем Windows. |
Когда приложение заканчивает использование файла, оно может закрыть его, вызвав метод close. Если файл не открыт, close терпит неудачу. Это метод возвращает true при успехе и false - в противном случае.
Отладка Приложения
Для отладки приложения сделайте следующее:
Выбрать имя приложения в списке приложений и щёлкнуть Debug, как указано в разделе .
Загрузить URL отладки, как указано в разделе .
Можно использовать функцию debug для вывода отладочной информации, как описано в разделе .
После запуска отладки приложения JavaScript Вы не сможете остановить или рестартовать его. В этих случаях Application Manager выдаст сообщение "Trace is active/Трассировка включена". Если это произойдёт, сделайте следующее:
Закройте все окна отладки.
Закройте все окна с данным приложением.
В Application Manager выберите это приложение и щёлкните Run.
Теперь Вы можете остановить и рестартовать это приложение.
Отладка Приложения Hangman
Вы можете поэкспериментировать с JavaScript, чтобы получить представление о разработке приложений. Одна из важнейших задач - отладка. Выберите в Application Manager приложение Hangman и Debug/Отладить. Application Manager открывает окно с приложением в одном фрэйме и с отладочной информацией - в другом, слева, как показано на .
Рисунок 4.3 Отладка приложения Hangman
![](image/debug.gif)
Заметьте, что URL будет теперь
http://server.domain/appmgr/debug.html?name=hangman
Вы можете сделать закладку на этот URL для удобства работы с Hangman. После этого не нужно будет выходить в Application Manager.
Попытайтесь добавить в Hangman функцию, проверяющую, является ли введённый пользователем символ буквой (а не числом или знаком пунктуации). Можете использовать функцию InitAnswer из hangman.js для старта. После компиляции и рестарта приложения используйте закладку для запуска приложения в режиме отладки.
Отладка в JavaScript
JavaScript позволяет создавать сложные компьютерные программы. Как и во всех других языках, Вы можете ошибаться при написании скриптов. Отладчик Netscape JavaScript Debugger даёт возможность отлаживать Ваши скрипты.
об использовании Отладчика см.
.
Отображение Выражений и Агрегатных Функций
Операторы SELECT могут запрашивать значения, не являющиеся столбцами в БД, такие как агрегатные значения и выражения SQL. Для таких значений Cursor -объект не имеет именованного свойства. Вы можете получить к ним доступ только через использование свойства индекса массива Cursor -объекта для данного значения.
В следующем примере создаётся курсор с именем empData, делается переход к первому ряду этого курсора и затем отображается значение, запрошенное агрегатной функцией MAX. Выполняется также проверка того, что результаты из БД верны, перед тем как использовать их:
empData = connobj.cursor ("select min(salary), avg(salary),
max(salary) from employees");
if ( empData && (connobj.majorErrorCode() == 0) ) {
rowexists = empData.next();
if (rowexists) { write("Highest salary is ", empData[2]); }
}
Во втором примере создаётся курсор с именем empRows для подсчёта количества рядов в таблице, выполняется переход к ряду в этом курсоре, а затем отображается количество рядов параллельно с выполнением проверки на верность данных:
empRows = connobj.cursor ("select count(*) from employees");
if ( empRows && (connobj.majorErrorCode() == 0) ) {
rowexists = empRows.next();
if (rowexists) { write ("Number of rows in table: ", empRows[0]); }
}
Отображение Значений Записи
Когда Вы создаёте курсор, он получает свойство colName для каждого именованного столбца виртуальной таблицы (отличное от свойств, соответствующих агрегатным функциям), как определено оператором SELECT. Вы можете получать доступ к значениям текущего ряда, используя эти свойства. В вышеприведённом примере курсор имеет свойства для столбцов id, name и city. Вы можете вывести значения для первого возвращённого ряда, используя следующие операторы:
// Создаётся Cursor-объект.
custs = connobj.cursor ("select id, name, city
from customer order by id");// Прежде чем продолжить, убедитесь, что курсор действительно был возвращён
// и не было ошибки БД.
if ( custs && (connobj.majorErrorCode() == 0) ) { // Получаем первый ряд.
custs.next(); // Отображаем значение.
write ("<B>Customer Name:</B>" + custs.name + "<BR>");
write ("<B>City:</B> " + custs.city + "<BR>");
write ("<B>Customer ID:</B> " + custs.id);
//Закрываем курсор.
custs.close();
}
Сначала текущим рядом является первый ряд таблицы. Выполнение метода next передвигает текущий ряд на первый ряд таблицы. Например, предположим, что это первый ряд курсора:
1 Sally Smith Suva
Тогда предыдущий код выведет:
Customer Name: Sally Smith
City: Suva
Customer ID: 1
Вы можете обращаться к свойствам Cursor -объекта (или, в действительности, объекта JavaScript) как к элементам массива. Элемент массива с индексом [0] соответствует первому столбцу, элемент массива с индексом [1] соответствует второму столбцу, и так далее.
Например, Вы можете использовать индекс для отображения тех же значений столбцов, что и в предыдущем примере:
write ("<B>Customer Name:</B> " + custs[1] + "<BR>");
write ("<B>City:</B> " + custs[2] + "<BR>");
write ("<B>Customer ID:</B> " + custs[0]);
Эта техника особенно применима внутри циклов. Например, Вы можете создать Cursor -объект с названием custs и вывести результат выполнения запроса в виде таблицы HTML с помощью следующего кода:
// Создаётся Cursor-объект.
custs = connobj.cursor ("select id, name, city
from customer order by id");// Прежде чем продолжить, убедитесь, что курсор действительно был возвращён
// и не было ошибки БД.
if ( custs && (connobj.majorErrorCode() == 0) ) {
write ("<TABLE BORDER=1>");
// Отображаем имена столбцов как заголовки.
write("<TR>");
i = 0;
while ( i < custs.columns() ) {
write("<TH>", custs.columnName(i), "</TH>");
i++;
}
write("</TR>"); // Отображаем каждый ряд виртуальной таблицы.
while(custs.next()) {
write("<TR>");
i = 0;
while ( i < custs.columns() ) {
write("<TD>", custs[i], "</TD>");
i++;
}
write("</TR>");
}
write ("</TABLE>"); // Закрываем курсор.
custs.close();
}
Этот код может вывести примерно такую таблицу:
Sally Smith
Suva
2
Jane Doe
Cupertino
3
John Brown
Harper's Ferry
В примере использованы методы, обсуждаемые в последующих разделах.
Отправка Значений с Клиента на Сервер
Есть несколько способов отправки информации с клиента на сервер:
Машина выполнения автоматически создаёт свойства объекта request для каждого значения в HTML-форме. (См. ).
Если Вы используете основанную на URL технику обслуживания свойств объекта client, Вы можете модифицировать URL, отправленный серверу, чтобы включить значения свойств объектов client и request. (См. ).
Вы можете использовать куки для установки значений свойств объектов client и request. (См. ).
На стороне клиента Вы можете модифицировать шапку/header клиентского запроса. Вы можете затем использовать метод httpHeader объекта request для манипулирования шапкой и, возможно, телом запроса. (См. ).
Отправка Значений с Сервера Клиенту
Приложение JavaScript сообщается с клиентом через HTML и клиентский JavaScript. Если Вам нужно просто вывести информацию пользователю, нет никаких проблем: Вы создаёте HTML для форматирования этой информации так, как она будет отображаться.
Однако Вам может понадобиться выслать значения непосредственно клиентскому скрипту. Можно сделать это по-разному, включая такие способы:
Вы можете установить значения по умолчанию формы и значения для скрытых/невидимых элементов формы. (См. ).
Вы можете непосредственно заменить информацию в клиентских операторах SCRIPT или обработчиках событий. (См. ).
Вы можете использовать куки для отправки значений свойств объекта client или других значений клиенту. (См. ).
Вы можете изменить шапку/header ответа, высылаемую клиенту, используя функции deleteResponseHeader и addResponseHeader. (См. ).
Ожидание Соединения
В пуле, созданном объектом DbPool, соединений имеется фиксированное количество соединений. Если в момент попытки доступа все соединения заняты, Ваше приложение ожидает освобождения соединения в течение специфицированного периода таймаута. Вы можете управлять периодом ожидания.
Предположим, Вы определили следующий пул из 3 соединений:
pool = new DbPool ("ORACLE", "myserv", "user", "password", "", 3);
Предположим далее, что три клиента одновременно получают доступ к приложению и каждый использует одно из трёх соединений. Четвёртый клиент теперь запрашивает соединение через следующий вызов:
myconnection = pool.connection();
Этот клиент обязан ждать, пока один из трёх клиентов не освободит соединение. В данном случае, поскольку вызов connection не специфицирует таймаут, клиент ждёт освобождения соединения неопределённо долго, а затем возвращает это соединение.
Вы можете специфицировать различные периоды таймаута, задавая аргументы метода connection. Второй аргумент метода connection это период таймаута в секундах. Если Вы специфицируете таймаут 0, система ждёт бесконечно долго. Например, следующий код ожидает соединения только 30 секунд перед таймаутом:
myconnection = pool.connection ("Name of Connection", 30);
Если в течение специфицированного периода соединение не освобождается, метод возвращает null, и в сообщение об ошибке устанавливается сообщение о наименьшей ошибке. Вы можете получить это сообщение, вызвав метод minorErrorMessage объекта pool. Если Вы вызываете таймаут из connection, Вам может понадобиться освободить соединение, отключив одно из уже установленных. Дополнительно см. .
Параметры Вывода и Ввода/Вывода
Помимо стандартных параметров ввода, некоторые производители БД разрешают вводить другие типы параметров для хранимых процедур. Параметры вывода хранят информацию при возвращении из хранимой процедуры и параметры ввода/вывода, передающие и возвращающие информацию.
Для большинства БД Вы используете методы outParamCount и outParameters класса Stproc для доступа к параметрам вывода и ввода/вывода. Informix, однако, не разрешает параметры вывода и ввода/вывода. Соответственно, Вы не должны использовать методы outParamCount и outParameters с хранимыми процедурами Informix.
Переход к Новому Клиентскому Запросу
Функция redirect прерывает текущий клиентский запрос и стартует новый по специфицированному URL. Например, у вас имеется оператор:
redirect("http://www.royalairways.com/apps/page2.html");
Когда машина выполняет это оператор, она прерывает текущий запрос. Машина выполнения не продолжает обработку страницы-оригинала. Следовательно любые операторы HTML или JavaScript, идущие в оригинальной странице после вызова redirect, будут утеряны. Клиент сразу загрузит указанную страницу, отбросив предыдущее содержимое.
Параметром для redirect может быть любой оператор серверного JavaScript, вычисляемый до URL. Таким образом, Вы можете динамически генерировать URL, используемый в redirect. Например, если страница определяет переменную choice, Вы можете перенаправить клиента на страницу в зависимости от значения choice таким образом:
redirect ("http://www.royalairways.com/apps/page"
+ choice + ".html");
Если Вам нужно удостовериться, что текущие свойства client'а доступны в новом запросе и что Вы используете один из видов техники обслуживания объекта client на основе URL, Вы должны кодировать свойства в URL, передаваемом Вами в redirect. О том, как это сделать, см. .
В целом свойства объекта request и переменные верхнего уровня JavaScript существуют только в течение одиночного клиентского запроса. Если Вы выполняете перенаправление на новую страницу, Вам может понадобиться сохранить некоторую информацию для нескольких запросов. Вы можете сделать это, присоединив имена и значения свойств к URL, как описано в разделе .
Период Существования Объекта client
После того как клиент получил доступ к приложению, не гарантируется, будет он далее запрашивать продолжение обработки или продолжит выполнение до логического конца. В связи с этим объект client не имеет встроенного механизма окончания строка действия. Этот механизм позволяет JavaScript периодически "зачищать" старые объекты client, которые больше не нужны. Каждый раз, при получении сервером запроса на страницу приложения, JavaScript восстанавливает период существования объекта client.
Почтовая Служба/Mail Service
Вашему приложению может понадобиться отправить email-сообщение. Для этого Вы используете экземпляры класса SendMail. Единственным методом SendMail является send, для отправки сообщения, а errorCode и errorMessage служат для интерпретации ошибок.
Например, следующий скрипт отсылает почту в vpg со специфицированной темой/subject и телом сообщения:
<server>
SMName = new SendMail();
SMName.To = "vpg@royalairways.com";
SMName.From = "thisapp@netscape.com";
SMName.Subject = "Here's the information you wanted";
SMName.Body = "sharm, maldives, phuket, coral sea, taveuni, maui,
cocos island, marathon cay, san salvador";
SMName.send();
</server>
В таблице даны свойства класса SendMail. Свойства To и From необходимы; все остальные свойства - по выбору/optional.
To |
Список разделённых запятыми первичных/primary получателей сообщения. | ||
From |
Имя пользователя/user name отправляющего сообщение. | ||
Cc |
Список разделённых запятыми дополнительных получателей сообщения. | ||
Bcc |
Список разделённых запятыми получателей сообщения, чьи имена не должны быть видны в сообщении. | ||
Smtpserver |
Имя почтового сервера (SMTP). По умолчанию это свойство имеет значение, установленное на сервере администрирования. | ||
Subject |
Тема сообщения. | ||
Body |
Текст сообщения. |
Вы можете добавлять к этим свойствам любые другие. Все свойства класса SendMail включаются в шапку/header сообщения при фактической отправке. Например, следующий код отсылает сообщение получателю bill от vpg, устанавливая в поле vpg organization значение Royal Airways. Отвечает на сообщение от vpgboss.
mailObj["Reply-to"] = "vpgboss";
mailObj.Organization = "Royal Airways";
mailObj.From = "vpg";
mailObj.To = "bill";
mailObj.send();
Дополнительно о предопределённых полях шапки см. , стандарт формата текстовых сообщений Internet.
Класс SendMail позволяет отправлять простое текстовое почтовое сообщение или сложное MIME-сообщение. Вы можете также добавить в сообщению приложение/attachment. Для отправки MIME-сообщения добавьте свойство Content-type к объекту SendMail и укажите в нём MIME-тип сообщения.
Например, следующий участок кода отсылает изображение в формате GIF:
<server>
SMName = new SendMail();
SMName.To = "vpg@royalairways.com";
SMName.From = "thisapp@netscape.com";
SMName.Subject = "Here's the image file you wanted";
SMName["Content-type"] = "image/gif";
SMName["Content-Transfer-Encoding"] = "base64";
// В следующем операторе image2.gif обязан быть кодирован с базой 64/base 64.
// Если вы используете uuencode для кодирования GIF-файла, удалите header
// (например, "begin 644 image2.gif") и замыкающий ("end").
fileObj = new File("/usr/somebody/image2.gif");
openFlag = fileObj.open("r");
if ( openFlag ) {
len = fileObj.getLength();
SMName.Body = fileObj.read(len);
SMName.send();
}
</server>
Некоторые MIME-типы требуют больше информации. Например, если content type это multipart/mixed, Вы обязаны также специфицировать сепаратор границ для одного или более различных наборов данных тела. Например, следующий код отсылает многочастное сообщение, содержащее две части, каждая из которых является обычным текстом:
<server>
SMName = new SendMail();
SMName.To = "vpg@royalairways.com";
SMName.From = "thisapp@netscape.com";
SMName.Subject = "Here's the information you wanted";
SMName["Content-type"]
= "multipart/mixed; boundary=\"simple boundary\"";
fileObj = new File("/usr/vpg/multi.txt");
openFlag = fileObj.open("r");
if ( openFlag ) {
len = fileObj.getLength();
SMName.Body = fileObj.read(len);
SMName.send();
}
</server>
Вот файл multi.txt, содержащий многочастное сообщение:
Это место для преамбулы.
Она игнорируется.
Это удобное место для комментария, предназначенного для читателей, не знакомых с MIME.
--простая граница
Это первая часть тела сообщения.
Это НЕ конец с символом обрыва строки.
--простая граница
Content-Type: text/plain; charset=us-ascii
Это вторая часть тела сообщения.
Это КОНЕЦ с символом обрыва строки.
--простая граница--
Это эпилог. Он также игнорируется.
Вы можете вкладывать друг в друга многочастные сообщения. То есть, если у Вас есть сообщение, content type которого многочастный, Вы можете включить другой многочастное сообщение в его тело. В таких случаях будьте внимательны и убедитесь, штаа каждый вложенный многочастный объект использует разные ограничители.
Детали о MIME-типах см. в
, MIME-стандарте. Об отправке почтовых сообщений в JavaScript см. также описание этого класса в книге
.
Поддерживаемые Клиенты БД и ODBC-Драйверы
В следующей таблице дано резюме по конкретным поставщикам БД, поддерживаемых на каждой платформе Netscape Enterprise Server 3.x (относительно Netscape Enterprise Server 4.0 см. замечания Enterprise Server 4.0 Release Notes).
Данные поставщики БД не поддерживаются сервером Netscape FastTrack Server.
DB2 | CAE 2.1.2 | Не поддерживается | Не поддерживается | V5.2 | V5.2 | V5.2 | ||||||
Informix | Informix Client 7.22 | Informix Client 7.22 | Informix Client 7.22 | SDK 2.10 (ESQL 9.16) | SDK 2.10 (ESQL 9.16) | SDK 2.10 TC1 (ESQL 9.16) | ||||||
MicrosoftODBC | ODBC Mgr Visigenic 2.0 | Не поддерживается | ODBC Mgr Visigenic 2.0 | Не поддерживается | Поддерживается только на Solaris 2.5.1 | MS SQL Server 6.5 (драйвер 3.60)
SQL Anywhere 5.5 (драйвер 5.00) MS Access 7.0 (драйвер 3.51.171300) | ||||||
Oracle | Oracle Client 7.3.x | Oracle Client 7.3.x | Oracle Client 7.3.x | Oracle Client
8.0.5 | Oracle Client
8.0.5 | Oracle Client 8.0.5 | ||||||
Sybase | Open
Client /C 11.1 | Open Client /C 11.1 | Open
Client /C 11.1 | 11.1.1 | 11.1.1 | 11.1.1 |
1Версия Oracle SQL*Net 1.1 больше не поддерживается. |
В следующей таблице дано резюме по поддержке ODBC в Windows NT для Netscape Enterprise Server и Netscape FastTrack Server.
ODBC Manager | MS ODBC Manager 3.51 MCAD 2.0 SP2 | ||
ODBC-Драйверы | |||
MS SQL Server 6.5 | MS SQL Server Driver 3.60 (sqlsrv32.dll) | ||
MS Access 7.0 | MS Access Driver 3.51.171300 (odbcjt32.dll) | ||
Sybase SQL Anywhere 5.5 | Sybase SQL Anywhere Driver 5.00.0003 (wod50t.dll) |
Обратите внимание, что ODBC не поддерживается на платформах Unix.
ПРИМЕЧАНИЕ:
Visigenic больше не обновляет свои существующие ODBC-драйверы или SDK. Вместо этого Visigenic избрал INTERSOLV для предоставления пути для обновления этих драйверов и продуктов. (См. ). Visigenic предоставит документ, покрывающий различия между драйверами Visigenic и INTERSOLV ODBC. В таблице перечислены возможности поддерживаемых ODBC-драйверов для NT.
MS-SQL Server 6.5 | Да | Да | Да | Да | Да |
Sybase SQL Anywhere | Да | Да | Да | Да | Не проверено |
Access | Да | Да | Да | Нет | N/A |
и различные усовершенствования, которые обсуждаются
В JavaScript версии 1.4 появились новые возможности и различные усовершенствования, которые обсуждаются в онлайновом учебнике Core JavaScript Reference v1.4:
Также можно воспользоваться моим переводом на русский язык
.
В следующем списке резюмируются эти новые возможности:
Обработка исключений.
Вы можете вызывать/throw и отлавливать/catch исключения, используя операторы throw и try...catch.
Новые операторы in и instanceof.
Оператор in возвращает true, если специфицированное свойство имеется в специфицированном объекте. Оператор instanceof возвращает true, если специфицированный объект имеет специфицированный тип.
Изменения в LiveConnect.
Некоторые изменения в LiveConnect улучшили способ взаимодействия кодов Java и JavaScript:
Методы класса java.lang.Object наследуются в JavaArray. Дополнительно метод JavaArrary.toString теперь вызывает метод java.lang.Object.toString.
Вы можете передавать объект JavaClass в Java-метод, который требует аргумента типа java.lang.Class, вместо создания оболочки вокруг экземпляра класса java.lang.Class.
Вы не можете конструировать экземпляр JSException с детальным сообщением.Три первоначальных public-конструктора для Java-класса netscape.javascript.JSException, поддерживавшего эту возможность, не рекомендуются/deprecated.Вы не можете использовать операцию == для сравнения двух экземпляров JSObject. Используйте JSObject.equals.
Изменения в методе eval:
Метод верхнего уровня eval не может вызываться неявно. В предыдущих версиях лишь рекомендовалось, чтобы этот метод не вызывался неявно; начиная с JavaScript 1.4, неявный вызов eval может привести к ошибке времени выполнения. Это изменение повысит производительность.
Метод eval больше не доступен как метод класса Object; вместо него используйте функцию верхнего уровня eval.
Изменения в объекте Function:
Вы больше не должны специфицировать имя функции при использовании массива arguments; массив arguments это переменная, он больше не является свойством Function -объектов. Это изменение улучшит производительность.Не рекомендуется использовать свойство Function.arity. Оно заменено свойством Function.length.
Подключение Серверного JavaScript
Чтобы запускать приложения JavaScript на Вашем сервере, Вы обязаны подключить машину выполнения JavaScript в вашем Server Manager, щёлкнув Programs, а затем выбрав серверный JavaScript. После появления промпта "Activate the JavaScript application environment/Активизировать среду приложений JavaScript ?" выберите Yes и щёлкните OK. У Вас спросят также об ограничении доступа к Application Manager. Дополнительно см.
ПРИМЕЧАНИЕ:
Если Вы не подключите машину выполнения JavaScript, приложения JavaScript не смогут запускаться на этом сервере.
Чтобы использовать и сервлеты, и LiveWire, Вам необходимо подключить серверный JavaScript до подключения Java. Оба могут быть подключены через использование меню программ Administration Server'а. Если Вы модифицируете путь к классам/classpath в obj.conf, Ваши изменения будут утеряны, если Вы подключите/отключите серверный JavaScript или Java из программного меню Administration Server'а. Альтернативой редактирования директивы classpath в obj.conf является установка переменной окружения CLASSPATH в Unix или установка переменной CLASSPATH в установках System в Windows NT. Если Вам нужно редактировать obj.conf непосредственно, сохраните первоначальный файл на всякий случай. В Enterprise Server 4.0 Вы должны добавить CLASSPATH info в файлы конфигурации JVM (jvm12.conf для Solaris и NT) через интерфейс Enterprise Administration Server.
Как только Вы активируете среду приложений JavaScript, Вы обязаны остановить и рестартовать Ваш web-сервер, чтобы ассоциированные переменные окружения начали действовать. Если этого не сделать, приложения JavaScript, использующие службу LiveWire Database Service, работать не будут.
Получение Информации о Файле
Вы можете использовать несколько методов класса File для получения информации о файлах и работы с error-статусом.
Метод getLength возвращает число символов в текстовом файле или количество байтов в любом другом файле. Возвращает -1, если возникла ошибка.
fileObj.getLength();
Метод exists возвращает true, если файл существует, и false - в ином случае.
fileObj.exists();
Метод error возвращает статус ошибки или -1, если файл не открыт или не может быть открыт. Статус ошибки/error status это ненулевое значение, если ошибка возникла, и 0 в ином случае (нет ошибки). Коды статуса ошибки зависят от платформы; обратитесь к документации по Вашей ОС.
fileObj.error();
Метод clearError очищает error-статус (значение error) и значение eof.
fileObj.clearError();
Потоки
Java даёт вам возможность создавать раздельные потоки выполнения. Вы должны осторожно использовать эту возможность, если Ваш Java-код взаимодействует с JavaScript-кодом.
Каждый запрос серверного JavaScript обрабатывается в потоке, известном как request thread/поток запроса. Этот поток запроса ассоциируется с информацией о статусе, такой как контекст JavaScript, используемый для процессинга информации HTTP-запроса, и HTTP-буфер ответа.
Когда Вы вызываете Java-код из приложения JavaScript, этот код Java работает в том же самом потоке запроса, что и оригинальное приложение JavaScript. Java-код в этом потоке может взаимодействовать с приложением JavaScript и иметь гарантию, что оно является таким, как он ожидает. Точнее, он может полагаться на ассоциированную информацию статуса.
Однако Вы можете создать новый поток из Java-кода. Если Вы это сделаете, этот новый поток не сможет взаимодействовать с приложением JavaScript и не сможет опираться на информацию о статусе, ассоциированную с оригинальным потоком запроса. Если он попытается это сделать, поведение будет неопределённым. Например, создаваемый Вами Java-поток не может ни инициировать выполнение JavaScript-кода через использование JSObject, ни использовать writeHttpOutput, поскольку этот метод требует доступа к HTTP-буферу ответа.
Позиционирование Внутри Файла
Физический файл, ассоциированный с File -объектом, имеет указатель текущей позиции в файле. Когда Вы открываете файл, указатель находится в начале либо в конце файла, в зависимости от режима, использованного при открытии файла. В пустом файле начало и конец файла это одна точка.
Метод setPosition позиционирует указатель в файле, возвращая true при успехе и false - в ином случае.
fileObj.setPosition(position);
fileObj.setPosition(position, reference);
Здесь fileObj это File -объект, position это целое число, указывающее позицию указателя, а reference указывает относительную точку для position таким образом:
0: относительно начала файла1: относительно текущей позиции2: относительно конца файла
Иное (или unspecified): относительно начала файла
Метод getPosition возвращает текущую позицию в файле, где первый байт файла это всегда байт 0. Этот метод возвращает -1, если имеется ошибка.
fileObj.getPosition();
Метод eof возвращает true, если указатель находится в конце файла, и false - в ином случае. Этот метод возвращает true после первой операции чтения, которая пытается прочесть после конца файла.
fileObj.eof();
В этой книге рассматривается создание
В этой книге рассматривается создание приложений, написанных на языке "Серверный/Server-Side JavaScript" (SSJS). JavaScript это разработанный корпорацией Netscape платформонезависимый объектно-ориентированный язык скриптинга (сценариев) для клиентских и серверных приложений.
В данной главе имеются следующие разделы:
Предопределённые Объекты. Обзор.
Предопределённые объекты request, client, project и server содержат данные, существующие в течение различных периодов времени и доступные различным клиентам и приложениям. Имеется единственный объект server, используемый всеми запущенными на сервере приложениями. Имеется отдельный объект project для каждого запущенного приложения. Имеется один объект client для каждого браузера (клиент), выполняющего доступ к данному отдельному приложению. Наконец, имеется отдельный объект request для каждого клиентского запроса с определённого клиента к определённому приложению. На показаны возможности относительной доступности различных объектов.
Рисунок 6.1 Относительная доступность объектов, обслуживающих сессию
![](http://cm/javascript/servguide14/graphics/avail.gif)
Машина выполнения JavaScript на сервере конструирует объекты обслуживания сессии в разные моменты времени. Эти объекты применяются для хранения различных данных. Вы можете определить специфические для приложения свойства для любого из этих объектов.
Объект request
Содержит данные, доступные только для текущего клиентского запроса. Ничто в этом объекте не применяется для совместного пользования. Объект request имеет предопределённые свойства, к которым Вы можете получить доступ.
Объект request считается объектом только для чтения. Машина выполнения сохраняет текущие значения всех элементов формы как свойства объекта request. Вы можете использовать его для хранения, информации, специфичной для отдельного запроса, но для этого более эффективным будет использование переменных JavaScript.
Машина выполнения конструирует объект request каждый раз, когда сервер отвечает на клиентский запрос из web-браузера. Он уничтожает этот объект в конце выполнения клиентского запроса. Машина выполнения не сохраняет данные объекта request.
См. дополнительно .
Объект client
Содержит данные, доступные только для отдельной пары клиент/приложение. Если один клиент соединён с двумя разными приложениями одновременно, машина выполнения JavaScript конструирует отдельные объекты client для каждой пары клиент/приложение. Все запросы от одного клиента к одному и тому же приложению пользуются одним и тем же объектом client. Объект client не имеет предопределённых свойств.
В общем, используйте объект client для тех данных, которые должны использоваться несколькими запросами от того же самого клиента (пользователя), но они не должны использоваться разными клиентами приложения. Например, Вы можете сохранять пользовательский ID потребителя как свойство объекта client.
Машина выполнения физически конструирует объект client для каждого клиентского запроса, но свойства сохраняются в течение времени существования клиентского соединения с приложением. Следовательно, хотя физически объект client существует только для одного клиентского запроса, концептуально Вы можете представлять, что он конструируется при первом соединении клиента с приложением и не разрушается, пока клиент не прервёт свой доступ к приложению. Есть несколько подходов к работе со свойствами объекта client при множественных запросах. См. дополнительно раздел .
Машина выполнения разрушает объект client, когда клиент заканчивает использование приложения. На практике машине JavaScript непросто определить, когда объект client и его свойства должны быть уничтожены. О том, как выполняется это определение, см. раздел . См. также .
Объект project
Содержит данные, доступные всем клиентам, выполняющим доступ к любой части приложения. Все клиенты, выполняющие доступ к одному и тому же приложению, используют один объект project. Объект project не имеет предопределённых свойств.
В общем, применяйте объект project для совместного использования данных несколькими клиентами, работающими с одним приложением. Например, Вы можете хранить следующий доступный ID потребителя как свойство объекта project. Когда объект project применяется для совместного использования данных, Вы должны быть внимательны относительно обеспечения одновременного доступа к этим данным; см. . Из-за ограничений, действующих для свойств объекта client, Вам иногда придётся использовать объект project для хранения данных отдельного клиента.
Машина выполнения конструирует объект project при старте приложения в Application Manager или при старте сервера. Она разрушает объект при остановке приложения или сервера.
Дополнительно см. .
Объект server
Содержит данные, доступные всем клиентам и всем приложениям данного сервера. Все приложения и все пары клиент/приложение используют один объект server. Объект server имеет предопределённые свойства.
Применяйте объект server для совместного использования данных несколькими приложениями сервера. Например, Вы можете использовать объект server для отслеживания использования всех приложений сервера. Когда объект server применяется для совместного использования данных, Вы должны побеспокоиться об обеспечении одновременного доступа к этим данным; см. .
Машина выполнения конструирует объект server при старте сервера и разрушает его при остановке сервера.
См. дополнительно .
может помочь представить, как все эти объекты соответствуют URL страницы Вашего приложения.
Рисунок 6.2 Предопределённые объекты в URL
![](http://cm/javascript/servguide14/graphics/url.gif)
На этом рисунке Joe запрашивает URL http://www.royalairways.com/videoapp/category.html, соответствующий странице приложения videoapp. Когда машина выполнения получает запрос, она использует уже существующий объект server, соответствующий www.royalairways.com и уже существующий объект project, соответствующий приложению videoapp. Машина создаёт объект client, соответствующий комбинации Joe и приложения videoapp. Если Joe уже получал доступ к другим страницам этого приложения, новый объект client использует любые сохранённые свойства. Наконец, машина создаёт новый объект request для конкретного запроса на страницу category.html.
Образец Flexi
Приложение flexi иллюстрирует использование серверного JavaScript для доступа к удалённому сервису, запущенному на ORB с включённым протоколом IIOP, а также показывает удалённый сервис, написанный целиком на Java с использованием ISB for Java. И исходные файлы, и исполняемые файлы приложения flexi установлены в директории $NSHOME\js\samples\flexi.
A flexible spending account (FSA)/гибко расходуемый счёт это счёт, на котором служащие могут хранить доллары предоплаты, используемые для медицинских расходов. Служащие обычно подписываются на этот план через администратора плана и выбирают сумму в долларах, которую они хотят хранить на своих счетах. Если служащий осуществляет затраты на медицинские цели, он отправляет запрос, который, если одобрен, вызывает снятие суммы со счёта и перевод её служащему.
Приложение flexi предоставляет поддержку обслуживания FSA. В этом приложении администратор имеет следующие опции:
Создание нового счёта с указанным балансом.
Выбор существующего счёта по фамилии служащего.
Хранение дополнительных вложений на выбранном счёте.
Закрытие счёта.Принятие или отказ в выполнении запроса, отправленного служащим.
Для служащего имеются следующие опции:
Просмотр статуса счёта, включая статус любого отклонённого запроса.
Отправка нового запроса путём заполнения формы.
образец Viewer. Поскольку это приложение
На сервере Netscape имеется приложение- образец Viewer. Поскольку это приложение даёт возможность просматривать файлы на сервере, оно не устанавливается автоматически.
Viewer это хороший пример использования класса File. Если Вы установили это приложение, позаботьтесь об ограничении доступа к нему, чтобы неавторизованный пользователь не мог просматривать файлы на сервере. Об ограничении доступа к приложению см. раздел .
Следующий код из приложения Viewer создаёт экземпляр класса File, открывает его для чтения и генерирует HTML, отражающий строки файла, с разделительной линией после каждой строки.
x = new File("\tmp\names.txt");
fileIsOpen = x.open("r");
if (fileIsOpen) {
write("file name: " + x + "<BR>");
while (!x.eof()) {
line = x.readln();
if (!x.eof())
write(line+"<br>");
}
if (x.error() != 0)
write("error reading file" + "<BR>");
x.close();
}
JavaScript-Вызова Java
Директория $NSHOME\js\samples\bugbase содержит простое приложение, иллюстрирующее использование LiveConnect. В этом разделе описан код JavaScript этого приложения-образца. См. в разделе описание кода Java этого приложения.
Приложение bugbase представляет собой простую БД "жучков". Вы вводите bug, заполняя клиентскую форму номером жучка, приоритетом, продуктом, в котором он обнаружен, и кратким описанием. Другая форма позволяет просмотреть существующий bug.
Следующий JavaScript обрабатывает акцию входа:
// . проверить, что ID был введён.
if (request.bugId != "") {
// . Создаётся Bug-экземпляр и присваивается переменной.
var bug = new Packages.bugbase.Bug(parseInt(request.bugId),
request.bugPriority, request);
// . Получить доступ к массиву и сохранить экземпляр в нём.
project.bugsLock.lock();
project.bugs[parseInt(request.bugId)] = bug;
project.bugsLock.unlock();
// . Отобразить информацию.
write("<P><b><I>====>Committed bug: </I></b>");
write(bug, "<BR>");
}
// . Если ID не был введён, предупредить пользователя.
else {
write("<P><b><I>====>Couldn't commit bug: please complete
all fields.</I></b>");
}
Шаги в этом коде:
- Проверить, что пользователь ввёл ID для bug. Только в этом случае выполняется вход в bug.
Создать экземпляр Java-класса Bug и присвоить его переменной bug. Конструктор класса Bug принимает три параметра: два из них являются свойствами объекта request; третий это сам объект JavaScript request. Поскольку они являются элементами формы, эти свойства объекта request являются строками JavaScript. Код изменяет ID на целое число перед передачей его Java-конструктору. После передачи request -объекта Java-конструктору этот конструктор может затем вызывать его методы. Этот процесс обсуждается в разделе .Использовать project.bugsLock для получения исключительного доступа к массиву project.bugs и сохранить затем новый Bug -экземпляр в этом массиве, индексированным по номеру bug'а, специфицированному в форме. Заметьте, что этот код сохраняет ссылку на Java-объект как значение свойства JavaScript-объекта. О блокировке см. .
Отобразить клиенту информацию о bug'е, который Вы только что сохранили.Если bug ID не введён, вывести сообщение о том, что bug не может быть найден в БД.
Пример Вызывающего Серверного JavaScript
В директории $NSHOME\js\samples\bugbase содержится простое приложение, которое иллюстрирует использование LiveConnect. В это разделе описывается приложение-образец Java-кода. См. в разделе описание основ работы этого приложения и его JavaScript-кода.
// . Импортировать необходимые Java-объекты.
package Bugbase;
import netscape.javascript.*;
import netscape.server.serverenv.*;
// . Создать класс Bug.
public class Bug {
int id;
String priority;
String product;
String description;
String submitter;
// . Определить конструктор класса.
public Bug(int id, String priority, JSObject req)
throws java.io.IOException
{
// Записать часть http-ответа.
NetscapeServerEnv.writeHttpOutput("Java constructor: Creating
a new bug.<br>");
this.id = id;
this.priority = priority;
this.product = (String)req.getMember("bugProduct");
this.description = (String)req.getMember("bugDesc");
} // . Возвратить строковое представление объекта.
public String toString()
{
StringBuffer result = new StringBuffer();
result.append("\r\nId = " + this.id
+ "; \r\nPriority = " + this.priority
+ "; \r\nProduct = " + this.product
+ "; \r\nDescription = " + this.description);
return result.toString();
Многие шаги в этом коде не являются специфичными для взаимодействия с JavaScript. Только шаги 1 и 3 имеют отношение к JavaScript.
- Специфицировать пакет, используемый в файле, и импортировать пакеты netscape.javascript и netscape.server.serverenv. Если Вы пропустите этот шаг, Вы не сможете использовать объекты JavaScript.
Создать Java-класс Bug, специфицировать его поля.
Определить конструктор для этого класса. Этот конструктор принимает три параметра: целое число, строку и объект типа JSObject. Этот последний параметр является представлением JavaScript-объекта в Java. Через методы этого объекта конструктор может получить доступ к свойствам и вызвать методы объекта JavaScript. В этом случае он использует метод getMember объекта JSObject для получения значений свойств JavaScript-объекта. Также этот метод использует метод writeHttpOutput предопределённого объекта NetscapeServerEnv (из пакета netscape.server.serverenv) для вывода информации в процессе конструирования объекта. Этот метод записывает массив байтов в тот же поток вывода, который используется JavaScript-функцией write.
Определить метод toString. Это стандартный метод для Java-объекта, возвращающий строковое представление полей объекта.
Primitive value/примитивное значение
Данные, непосредственно представленные на самом нижнем уровне языка. Примитивное значение JavaScript является членом одного из следующих типов: undefined, null, Boolean, number или string.
Вот примеры некоторых примитивных значений:
a=true // Boolean/Булево
b=42 // number/число
c="Hello world" // string/строка
if (x==undefined) {} // undefined ("не определено")
if (x==null) {} // null
Присоединение Свойств Объекта client к URL Вручную
При использовании кодирования URL на клиенте или на сервере для работы с объектом client машина выполнения обычно должна сохранять соответствующую информацию (имена и значения свойств объекта client или индекс серверной структуры данных) во всех URL, высылаемых клиенту, вне зависимости от того, являются ли эти URL как статический HTML или были сгенерированы операторами серверного JavaScript.
Машина выполнения автоматически присоединяет соответствующую информацию к гиперссылкам HTML, находящимся вне тэгов SERVER. Так, например, предположим, что Ваша HTML-страница содержит следующие операторы:
<HTML>
For more information, contact
<A HREF="http://royalairways.com/contact_info.html">
Royal Airways</a>
...
</HTML>
Если приложение использует кодирование URL для объекта client, машина выполнения автоматически присоединит client -информацию в конец URL. Вы не должны ничего делать специально для поддержки этого поведения.
Однако ваше приложение может использовать функцию write для динамической генерации оператора HTML, содержащего URL. Вы можете также использовать функцию redirect для старта нового запроса. Когда Вы используете операторы серверного JavaScript для добавления URL к генерируемой HTML-странице, машина выполнения предполагает, что Вы специфицировали полный URL для отправки в нужном Вам виде. Она не присоединяет автоматически клиентскую информацию даже при использовании кодирования URL для работы с объектом client. Если Вам нужно присоединить клиентскую информацию, Вы обязаны сделать это сами.
Вы используете функцию addClient для добавления вручную соответствующей client -информации. Эта функция принимает URL и возвращает новый URL с присоединённой информацией. Например, предположим, что контактный URL варьируется в зависимости от значения свойства client.contact. Вместо вышеприведённого HTML Вы можете ввести следующее:
<HTML>
For more information, contact
<server>
if (client.contact == "VIP") {
write ("<A HREF='http://royalairways.com/vip_contact_info.html'>");
write ("Royal Airways VIP Contact</a>");
}
else {
write ("<A HREF='http://royalairways.com/contact_info.html'>");
write ("Royal Airways</a>");
}
</server>
...
</HTML>
Теперь машина выполнения не присоединяет свойства объекта client к URL. Если Вы используете один из видов техники кодирования URL для работы с объектом client, может возникнуть проблема. Тогда, если Вы хотите отправить свойства объекта client с этим URL, используйте такой код:
<HTML>
For more information, contact
<server>
if (client.contact == "VIP") {
write (addClient(
"<A HREF='http://royalairways.com/vip_contact_info.html'>"));
write ("Royal Airways VIP Contact</a>");
}
else {
write (addClient(
"<A HREF='http://royalairways.com/contact_info.html'>"));
write ("Royal Airways</a>");
}
</server>
...
</HTML>
Также всякий раз, когда Вы применяете функцию redirect для перенаправления клиентского запроса, Вы должны использовать addClient для присоединения информации, как здесь:
redirect(addClient("mypage.html"));
В противоположность этому, если Ваша страница имеет ссылку на URL вне Вашего приложения, Вам может не понадобиться присоединение клиентской информации. Тогда не используйте статическую строку в значении атрибута HREF. Вместо этого вычисляйте значение. Это предотвратит автоматическое присоединение машиной выполнения клиентского индекса или свойств к URL. Например, у вас имеется ссылка:
<A HREF="mailto:me@royalairways.com">
В этом случае машина выполнения присоединяет клиентскую информацию. Чтобы этого не было, используйте очень похожую ссылку:
<A HREF=`"mailto:me@royalairways.com"`>
Хотя приложение первоначально инсталировано для использования техники без кодирования URL для работы с client, оно может быть позднее модифицировано для использования техники кодирования URL. Следовательно, если Ваше приложение генерирует динамические URL или использует redirect, Вам всегда нужно будет использовать addClient.
Прямая Замена
Вы можете также использовать серверный JavaScript для генерирования клиентских скриптов. Эти значения могут использоваться в последовательности операторов на клиенте. В качестве простого примера Вы можете инициализировать клиентскую переменную по имени budget на основе значения client.amount таким образом:
<p>The budget is:
<SCRIPT>
<SERVER>
write("var budget = " + client.amount);
</SERVER>
document.write(budget);
</SCRIPT>
Если значение client.amount равно 50, это сгенерирует такой JavaScript:
<p>The budget is:
<SCRIPT>
var budget = 50
document.write(budget);
</SCRIPT>
При запуске на клиенте это будет выглядеть так:
The budget is: 50
Проблемы Безопасности
Соблюдайте осторожность при использовании класса File. Приложение JavaScript может читать или записывать файлы везде, где позволяет операционная система, в том числе, возможно, и в системных файлах. Вы должны быть уверены, что Ваше приложение не позволяет читать файлы паролей и другую закрытую информацию или записывать в файлы. Делайте так, чтобы имена файлов, которые Вы передаёте в методы, не могли быть изменены хакерами.
Например, не используйте свойства объектов client или request в качестве имён файлов, поскольку эти значения могут стать доступными хакеру через куки или URL. В таких случаях хакер сможет модифицировать куки или URL, чтобы получить доступ к закрытым файлам.
Исходя из таких же соображений, Navigator не предоставляет автоматического доступа к файловой системе клиентской машины. Если необходимо, пользователь может сохранять информацию непосредственно в клиентской файловой системе, делая соответствующий выбор в меню Navigator'а.
Процессинг Времени Прогона на Сервере
В разделе показано, что происходит на этапе прогона, если пользователь выполняет доступ к странице приложения JavaScript. В данном разделе детально рассматриваются этапы этого процесса со 2 по 4, чтобы Вы смогли лучше понять, что происходит на каждом этапе. Это описание предоставляет контекст для понимания того, что Вам нужно делать на клиенте и сервере.
При работе с приложениями JavaScript важно помнить об асинхронной природе процессов Web. Приложения JavaScript разрабатываются для использования многими пользователями одновременно. Машина выполнения JavaScript на сервере обрабатывает запросы нескольких пользователей по мере их поступления и выполняет их в порядке поступления.
В отличие от традиционного приложения, которое запускается отдельным пользователем на отдельной машине, Ваше приложение обязано поддерживать одновременный доступ нескольких пользователей. Фактически, поскольку каждый фрэйм (кадр) HTML-документа из нескольких фрэймов генерирует свой собственный запрос/request, для машины выполнения может оказаться, что запрос одного пользователя является множественным запросом.
HTTP (Hypertext Transfer Protocol) это протокол, по которому HTML-страница пересылается клиенту. Этот протокол является stateless\бесстатусным, то есть информация не сохраняется в период между запросами. В общем, любая информация, необходимая для обработки HTTP-запроса, должна пересылаться вместе с этим запросом. Это создаёт проблемы для многих приложений. Как использовать информацию одновременно различными пользователями приложения или даже различными запросами одного пользователя? Служба JavaScript Session Management Service была разработана для того, чтобы помочь разрешить эту проблему. Детально эта служба рассматривается в В данный момент просто помните, что машина выполнения автоматически обслуживает объекты client, server, project и request.
Если Netscape-сервер получает клиентский запрос на страницу приложения, он сначала выполняет авторизацию (идентификацию). Этот шаг является частью базовых функций администрирования сервера. Если попытка авторизации запроса не удалась, последующие шаги не выполняются. Если запрос получил авторизацию сервера, машина выполнения JavaScript продолжает работу. Она выполняет следующие шаги, описанные в последующих разделах:
Конструирует новый объект request и конструирует или восстанавливает объект client.
Находит страницу для запроса и начинает создание HTML-страницы для отправки клиенту.
Для каждого участка исходной HTML-страницы: добавляет его в буфер или исполняет код.Сохраняет свойства объекта client.
Высылает HTML клиенту.Уничтожает объект request и сохраняет или уничтожает объект client.
Прототипы
Как указано в книге , Вы можете использовать свойство prototype многих классов, чтобы добавлять новые свойства в класс и во все его экземпляры. Как описано в разделе , серверный JavaScript добавляет несколько классов и предопределённых объектов. В новых классах, имеющих свойство prototype, оно работает в серверном JavaScript точно так же, как и в клиентском JavaScript.
Вы можете использовать свойство prototype для добавления новых свойств в классы Blob, Connection, Cursor, DbPool, File, Lock, Resultset, SendMail и Stproc. Кроме того, Вы можете использовать свойство prototype класса DbBuiltin для добавления свойств в предопределённый объект database. Обратите внимание, что Вы не можете создать экземпляр класса DbBuiltin; вместо этого Вы используете объект database, предоставляемый машиной выполнения JavaScript.
Вы не можете использовать prototype с объектами client, project, request и server.
Так же, как и в клиентском JavaScript, Вы можете использовать свойство prototype для любого класса, который Вы определяете в своём приложении.
Помните, что все приложения JavaScript на сервере работают в одной среде. Вот почему Вы можете распределять информацию между клиентами и приложениями. Следствием этого, однако, является то, что при использовании свойства prototype для добавления нового свойства в любой серверный класс, добавленный языком JavaScript, новое свойство доступно всем приложениям, работающим на сервере, а не только приложению, в котором это свойство было добавлено. Это даёт возможность легко добавлять функциональность всем приложениям JavaScript на Вашем сервере.
В противоположность этому, если Вы добавляете свойство в класс, который Вы определили в своём приложении, это свойство доступно только в том приложении, где оно было создано.
Проверка Конфигурации Вашей БД
После выполнения установки, описанной в данной главе, Вы можете использовать приложение-образец dbadmin для проверки правильности работы Вашего соединения с БД. Вы используете это приложение JavaScript для соединения с Вашим сервером БД и выполнения различных несложных задач, таких как выполнение оператора SELECT и отображение результатов или отправки произвольных SQL-команд серверу.
Поскольку dbadmin может использоваться для модификации и удаления таблиц БД, доступ к ней автоматически ограничен, если Вы выбрали защищённый режим Application Manager. Дополнительно об ограничении Application Manager см. .
Первое, что Вы обязаны сделать при использовании dbadmin, это соединиться с БД. Выберите Connect to Database. Появится форма, показанная на , где вы можете ввести информацию о соединении. Введите параметры и щёлкните Connect, чтобы попытаться установить соединение с сервером. О параметрах соединения см. , а также описание метода connect в книге Серверный JavaScript. Справочник.
![](image/dba.gif)
Если соединение установилось, появляется страница Execute Query. Это означает, что ваша БД соответствующим образом сконфигурирована для работы с LiveWire Database Service. Если соединиться не удалось, появится страница Database Connect Error. В этом случае убедитесь, что Вы следовали инструкциям по конфигурированию конкретной БД и "железа".
Проверка Ошибочных Условий
При написании приложения на языке JavaScript Вы должны знать о различных ошибках. В тех случаях, когда Вы используете LiveWire Database Service для взаимодействия с реляционной БД, ошибки могут возникать по разным причинам. Например, SQL-операторы могут не выполняться из-за ограничений ссылочной целостности/referential integrity, потери привилегий доступа, блокировки записи или таблицы в многопользовательской БД и т.д. Если акция терпит неудачу, сервер БД возвращает сообщение об ошибке с указанием причины.
Ваш код должен проверять наличие ошибок и обрабатывать их соответствующим образом.
Публикация Приложения
После завершения разработки и тестирования приложения Вы можете опубликовать его и сделать доступным для предполагаемых пользователей. Это требует выполнения двух шагов:
перемещения/копирования приложения с рабочего сервера на сервер публикаций, доступный конечным пользователям;
применения или изменения прав доступа к приложению.
Вы должны скопировать web-файл приложения на сервер публикаций вместе с изображениям и неоткомпилированными файлами HTML и JavaScript, которые необходимы для работы приложения. О публикации файлов приложений см. дополнительно Netshare and Web Publisher User's Guide.
ПРИМЕЧАНИЕ:
В целом, по соображениям безопасности, Вы не должны публиковать файлы с исходным кодом.
В зависимости от приложения, Вы можете ограничить доступ для определённых пользователей или групп пользователей. В некоторых случаях любой пользователь может запускать приложение; тогда ограничений можно вообще не применять. Если приложение показывает специальную информацию или даёт доступ к файловой системе сервера, Вы должны предоставить доступ только авторизованным пользователям, имеющим соответствующие имена и пароли для входа.
Вы ограничиваете доступ к приложению, применяя стиль конфигурации сервера из Вашего Server Manager. Об использовании Server Manager и стилей конфигурации см. Enterprise Server 4.0 Administrator's Guide.
Пулы Соединений с БД
Если Вы хотите использовать объект database, Вам не нужно создавать его. Это предопределённый объект, предоставляемый машиной выполнения JavaScript. Если Вам нужны дополнительные возможности класса DbPool, Вы создаёте экземпляр класса DbPool и соединяете этот объект с конкретной БД, которая создаёт пул соединений.
Вы можете создать общий DbPool-объект и специфицировать позднее информацию соединения (используя метод connect), или можете специфицировать информацию соединения при создании пула. Общий DbPool-объект не имеет никаких доступных соединений в момент его создания. Исходя из этого, Вам может понадобиться установить соединение при создании этого объекта. Если Вы используете объект database, Вы всегда обязаны устанавливать соединение путём вызова метода database.connect.
connect (dbtype, serverName, userName, password,
databaseName, maxConnections, commitFlag);
При создании соединения Вы можете специфицировать следующую информацию, либо при создании DbPool-объекта, либо при вызове метода connect объекта DbPool или database:
dbtype: Тип БД. Обязан быть "DB2", "INFORMIX", "ODBC", "ORACLE" или "SYBASE". (Для приложений, запущенных на сервере Netscape FastTrack Server, обязан быть "ODBC".)
serverName: Имя сервера БД, с которым устанавливается соединение. Имя сервера обычно назначается при установке БД. В случае сомнений, узнайте у администратора БД или системы.
username: Имя пользователя, соединяющегося с БД.password: Пароль пользователя.
databaseName: Имя БД на данном сервере, с которой устанавливается соединение. Если Ваш сервер баз данных поддерживает множество БД на одном сервере, предоставьте имя используемой БД. Если предоставлена пустая строка, производится соединение с БД по умолчанию. Для Oracle, ODBC и DB2 Вы всегда обязаны предоставлять пустую строку.
maxConnections: (Optional/Необязательный Параметр) Допустимое количество соединений в пуле БД. Помните, что клиентская лицензия Вашей БД, возможно, специфицирует максимальное количество соединений. Не устанавливайте этот параметр в число, превышающее количество, допустимое по лицензии. Если Вы не предоставляете этот параметр для объекта DbPool, он имеет значение 1. Если Вы не предоставляете этот параметр для объекта database, его значением будет то, что Вы специфицировали в Application Manager как значение для Built-in Maximum Database Connections/Встроенное Значение Максимального Количества Соединений с БД, когда устанавливали приложение. (См. ). См. в разделе о том, что Вы должны предусмотреть при установке этого параметра.
commitflag: ( Необязательный Параметр) Булево значение, указывающее, подтвердить ли открытую транзакцию или выполнить её откат при закрытии соединения. Специфицируйте true для подтверждения открытой транзакции и false - для выполнения отката. Если этот параметр Вами не предоставлен для объекта DbPool, его значением будет false. Если этот параметр не предоставлен для объекта database, значением параметра будет true.
Например, следующий оператор создаёт новый пул БД из 5 соединений с БД Oracle. В этом пуле неподтверждённые транзакции откатываются:
pool = new DbPool ("ORACLE", "myserver1", "ENG", "pwd1", "", 5);
Приложение-образец dbadmin позволяет Вам экспериментировать с соединениями с различными БД как разным пользователям.
Для многих приложений Вы, возможно, захотите выполнять совместное использование набора соединений несколькими клиентами, или чтобы соединение захватывало несколько клиентских запросов. В этих случаях Вы должны устанавливать соединение на начальной странице Вашего приложения. Это позволит исключить возможные проблемы в тех случаях, когда отдельные клиенты выполняют совместные соединения с БД.
Однако для некоторых приложений каждый клиент должен выполнять своё собственное соединение. Как сказано в разделе клиенты могут совместно использовать объекты. Если это так, убедитесь, что блокировки используются для управления совместным использованием данных, как указано в разделе .
В следующей таблице показаны методы объектов DbPool и database для обслуживания пула соединений. (Объект database использует другие методы, рассмотренные ранее, для работы с соединением с БД.)
connect | Соединяет пул с определённой конфигурацией БД и пользователя. |
connected | Проверяет, соединён ли пул и все его соединения с базой данных. |
connection | (Только DbPool) Запрашивает доступный Connection-объект из пула. |
disconnect | Отсоединяет все соединения пула от БД. |
majorErrorCode | Главный код ошибки, возвращаемый сервером БД или ODBC. |
majorErrorMessage | Главное сообщение об ошибке, возвращаемое сервером БД или ODBC. |
minorErrorCode | Вторичный код ошибки, возвращаемый библиотекой продавца. |
minorErrorMessage | Вторичное сообщение об ошибке, возвращаемое библиотекой продавца. |
Работа с Датами и Базами Данных
Значения даты, запрошенные из базы данных, конвертируются в Date -объекты JavaScript. Чтобы вставить значение даты в БД, используйте Date -объект JavaScript так:
cursorName.dateColumn = dateObj
Здесь cursorName это курсор, dateColumn это столбец, соответствующий дате, а dateObj это Date -объект JavaScript. Вы создаёте Date -объект, используя оператор new и Date -конструктор:
dateObj = new Date(dateString)
где dateString это строка, представляющая дату. Если dateString - пустая строка, создаётся Date -объект для текущей даты. Например:
custs.orderDate = new Date("Jan 27, 1997")
Примечание:
Базы Данных DB2 имеют типы данных time и timestamp. Эти типы конвертируются в тип Date в JavaScript.
ПРЕДУПРЕЖДЕНИЕ! LiveWire Database Service не может обрабатывать даты после 5 февраля 2037 года. Дополнительно о работе с датами в JavaScript см.
Работа с Двоичными/Бинарными Данными
Двоичные данные для мультимедиа-содержимого, такого как изображение или звуковой файл, хранятся в БД в виде большого двоичного объекта/binary large object (BLOb). Можно использовать технику двух видов для обработки бинарных данных в приложениях JavaScript:
Хранить имена файлов в БД, а данные - в отдельных файлах.
Хранить данные в БД как BLOb'ы и осуществлять доступ к ним через методы класса Blob.
Если Вам не нужно хранить BLOb-данные в БД, Вы можете хранить в БД имена файлов и осуществлять доступ к этим файлам в Вашем приложении с помощью стандартных тэгов HTML. Например, если Вы хотите вывести изображение в каждом ряду таблицы БД, Вы можете создать в таблице столбец с названием imageFileName, содержащий имя нужного файла изображения. Затем можно использовать такое выражение HTML для показа изображения в каждом ряду:
<IMG SRC=`mycursor.imageFileName`>
Когда курсор проходит по таблице, имя файла в тэге IMG изменяется на ссылку на соответствующий файл.
Для того чтобы Вы могли манипулировать реальными двоичными данными в Вашей БД, машина выполнения JavaScript распознаёт значения столбца, являющиеся BLOb-данными. То есть, когда программа создаёт объект Cursor, если один из столбцов таблицы БД содержит BLOb-данные, программа создаёт Blob -объект для соответствующего значения в объекте Cursor. Вы можете затем использовать методы Blob -объектов для отображения этих данных. Также, если нужно вставить BLOb-данные в БД, программа предоставляет Вам для использования глобальную функцию.
В таблице показаны методы и функции для работы с BLOb-данными.
blobImage |
Метод, используемый при отображении BLOb-данных, хранимых в БД. Возвращает тэг HTML IMG для специфицированного типа изображения (GIF, JPEG и т.д.). | ||
blobLink |
Метод, используемый при создании ссылки, которая указывает на BLOb-данные гиперссылкой. Возвращает гиперссылку HTML на BLOb. | ||
blob |
Глобальная функция, используема для вставки или обновления данных в ряду, содержащем BLOb-данные. Присваивает BLOb-данные столбцу в курсоре. |
Метод blobImage вызывает BLOb из БД, создаёт временный файл специфицированного формата и генерирует HTML-тэг IMG, который ссылается на временный файл. Машина выполнения удаляет временный файл после генерации страницы и отправки её клиенту.
Метод blobLink вызывает BLOb-данные из БД, создаёт временный файл и генерирует гипертекстовую ссылку HTML на этот временный файл. Машина выполнения удаляет временный файл после того как пользователь щёлкнет на ссылке или через 60 секунд после того как запрос будет выполнен.
Следующий пример иллюстрирует использование blobImage и blobLink для создания временных файлов. В данном случае таблица FISHTBL содержит 4 столбца: ID(ентификатор), name/имя и два изображения. Одно из них является уменьшенной копией/thumbnail изображения; другое - большим изображением. Код записывает HTML для отображения имени, уменьшенной копии и ссылки на большое изображение.
cursor = connobj.cursor ("select * from fishtbl");if ( cursor && (connobj.majorErrorCode() == 0) ) {
while (cursor.next()) {
write (cursor.name);
write (cursor.picture.blobImage("gif"));
write (cursor.picture.blobLink("image\gif", "Link" + cursor.id));
write ("<BR>");
}
cursor.close();
}
Если FISHTBL содержит ряды для 4 рыб, пример может дать на выходе такой HTML:
Cod <IMG SRC="LIVEWIRE_TEMP9">
<A HREF="LIVEWIRE_TEMP10">Link1 </A> <BR>
Anthia <IMG SRC="LIVEWIRE_TEMP11">
<A HREF="LIVEWIRE_TEMP12">Link2 </A> <BR>
Scorpion <IMG SRC="LIVEWIRE_TEMP13">
<A HREF="LIVEWIRE_TEMP14">Link3 </A> <BR>
Surgeon <IMG SRC="LIVEWIRE_TEMP15">
<A HREF="LIVEWIRE_TEMP16">Link4 </A> <BR>
Если Вам нужно добавить BLOb-данные в БД, используйте глобальную функцию blob. Она вводит BLOb-данные в столбец в обновляемом курсоре. В противоположность blobImage и blobLink, функция blob является функцией верхнего уровня, а не методом.
Следующие операторы вставляют BLOb-данные в столбцы ряда, а затем обновляют этот ряд таблицы FISHTBL в БД. В курсоре имеется единственный ряд.
// Начало транзакции.
database.beginTransaction();
// Создание курсора.
fishCursor = database.cursor ("select * from fishtbl where
name='Harlequin Ghost Pipefish'", true);
// Убедимся, что курсор создан.
if ( fishCursor && (database.majorErrorCode() == 0) ) {
// Позиционируем указатель на ряд.
rowexists = fishCursor.next();
if ( rowexists ) { // Присваиваем/вставляем blob-данные.
fishCursor.picture = blob ("c:\\data\\fish\\photo\\pipe.gif"); // Обновляем ряд.
fishCursor.updateRow ("fishtbl"); // Закрываем курсор и подтверждаем изменения.
fishCursor.close();
database.commitTransaction();
}
else {
// Иначе закрываем курсор и выполняем откат транзакции.
fishCursor.close();
database.rollbackTransaction();
}
}
else {
// Иначе вообще не получаем курсор; откатываем транзакцию.
database.rollbackTransaction();
}
Помните, что backslash (\) это escape-символ в JavaScript. Исходя из этого, Вы обязаны использовать двойной обратный слэш в именах файлов NT, как было в данном примере.
Работа с Файлами
Класс File имеет несколько методов, которые можно использовать после открытия файла:
Позиционирование: setPosition, getPosition, eof. Это методы для установки и получения текущей позиции указателя в файле и для определения, не находится ли указатель в конце файла.
Чтение из файла: read, readln, readByte.
Запись в файл: write, writeln, writeByte, flush.
Конвертация двоичного и текстового форматов: byteToString, stringToByte. Конвертируют одно число в символ и наоборот.
Информационные методы: getLength, exists, error, clearError. Для получения информации о файле и для получения и очистки error-статуса.
Эти методы описаны в последующих разделах.
Работа с Картами Изображений/Image Maps
Атрибут ISMAP тэга IMG указывает на серверную карту изображений. Если пользователь щёлкает на карте, горизонтальная и вертикальная позиции курсора высылаются на сервер. Свойства imageX и imageY возвращают эти координаты. Рассмотрим такой HTML:
<A HREF="mapchoice.html">
<IMG SRC="images\map.gif" HEIGHT=599 WIDTH=424 BORDER=0
ISMAP ALT="SANTA CRUZ COUNTY">
</A>
Страница mapchoice.html получает свойства request.imageX и request.imageY на основе позиции курсора в момент щелчка мышью.
Работа с Массивами Java
Если какой-нибудь метод Java создаёт массив и Вы обращаетесь к этому массиву в JavaScript, Вы работаете с JavaArray. Например, следующий код создаёт JavaArray x из 10 элементов типа int:
theInt = java.lang.Class.forName("java.lang.Integer")
x = java.lang.reflect.Array.newInstance(theInt, 10)
Подобно объекту JavaScript Array, JavaArray имеет свойство length, возвращающее количество элементов массива. В отличие от Array.length, JavaArray.length является свойством только для чтения/read-only, поскольку количество элементов в Java-массиве фиксируется в момент создания.
Работа с Оболочками
В JavaScript wrapper\оболочка это объект типа данных целевого языка, который содержит в себе объект исходного языка. На стороне JavaScript Вы можете использовать объект-оболочку для доступа к методам и полям Java-объекта; вызывая метод или получая доступ к свойству в оболочке даёт в результате вызов Java-объекта. На стороне Java объекты JavaScript оборачиваются в экземпляры класса netscape.javascript.JSObject и передаются в Java.
Когда JavaScript-объект высылается в Java, машина выполнения создаёт Java-оболочку типа JSObject; когда JSObject высылается из Java в JavaScript, машина выполнения разворачивает его в объект оригинального типа JavaScript. Класс JSObject предоставляет интерфейс для вызова методов JavaScript и проверки свойств JavaScript.
Работа с Параметрами Вывода
Этот этап касается хранимых процедур Sybase, Oracle, DB2 или ODBC. Для процедур Informix методы, обсуждаемые здесь, не применяются.
Чтобы определить количество параметров вывода процедуры (включая параметры и вывода, и ввода/вывода), Вы используете метод outParamCount. Вы можете работать с параметрами вывода хранимой процедуры, используя метод outParameters объекта. Если outParamCount возвращает 0, хранимая процедура не имеет параметров вывода. В этой ситуации не вызывайте outParameters.
Например, предположим, Вы создали хранимую процедуру, которая находит фамилию служащего по заданному ID. Если имеется фамилия служащего, ассоциированная с данным ID, процедура возвращает 1, и её output-параметр содержит фамилию служащего. Иначе параметр вывода является пустым. Следующий код выводит фамилию служащего или сообщение о том, что фамилия не найдена:
id = 100;
getNameProc = connobj.storedProc("getName", id);
returnValue = getNameProc.returnValue();
if (returnValue == 1)
write ("Name of employee is " + getNameProc.outParameters(0));
else
write ("No employee with id = " + id);
Предположим, хранимая процедура имеет один параметр ввода, один параметр ввода/вывода и один параметр вывода. Далее примем, что вызов хранимой процедуры отсылает значение параметра ввода и параметра ввода/вывода, как показано здесь:
spobj = connobj.storedProc("myinout", 34, 56);
Метод outParameters возвращает любые параметры ввода/вывода до того как возвратит первый параметр вывода.
В предыдущем примере, если Вызывается outParameters(1), возвращается значение, возвращаемое хранимой процедурой. И наоборот, если вызывается outParameters(0), метод возвращает 56. Это значение, переданное хранимой процедуре в позиции параметра ввода/вывода.
ПРИМЕЧАНИЕ:
Параметры вывода не могут быть null; однако Вы можете присвоить null-значение параметра ввода или ввода/вывода. В DB2, ODBC и Sybase Вы обязаны запрашивать resultSet -объекты и использовать метод returnValue до того, как вызываете outParameters. После того как Вы вызвали returnValue или outParameters, Вы больше не сможете получить данные из результирующего набора и не сможете получить какие-либо дополнительные результирующие наборы. Вы должны вызывать outParameters после обработки результирующего набора и любых return-значений.
Работа с Return-Значениями
Этот этап относится к хранимым процедурам Sybase и Oracle. Для процедур Informix, ODBC и DB2 метод returnValue всегда возвращает null.
Если Ваша хранимая процедура возвращает значение (return value), Вы можете получить к нему доступ с помощью метода returnValue.
В DB2, ODBC и Sybase Вы обязаны использовать хранимые процедуры и курсоры последовательно. Вы не можете их перемешивать. Исходя из этого, Вы обязаны дать системе знать, что Вы закончили использование хранимой процедуры, прежде чем сможете работать с курсором. Это выполняется через вызов метода returnValue объекта хранимой процедуры. Этот метод выдаёт return-значение хранимой процедуры (если она его имеет) и завершает выполнение хранимой процедуры. Вы должны также закрыть все объекты, относящиеся к хранимым процедурам, когда завершаете их использование.
ПРИМЕЧАНИЕ:
Для DB2, ODBC и Sybase Вы обязаны запросить resultSet -объекты до вызова метода returnValue. После того как Вы вызвали returnValue, Вы больше не сможете получить данные из результирующего набора и не сможете получить какие-либо дополнительные результирующие наборы. Вы должны вызывать returnValue после того, как обработали результирующий набор, но до запроса параметров вывода.
Работа с Результирующими Наборами
Этот этап применяется ко всем хранимым процедурам.
Как указано в разделе , разные БД возвращают результирующие наборы разными способами. Например, у Вас имеется таблица CUSTINFO со столбцами id, city и name. В Sybase Вы можете использовать такую процедуру для получения первых 200 рядов таблицы:
create proc getcusts as
begin
select id, name, city from custinfo where custno < 200
end
Если CUSTINFO является таблицей Informix, эквивалентная процедура в Informix может быть:
create procedure getcusts returning int, char(15), char(15);
define rcity, rname char (15);
define i int;foreach
select id, name, city into i, rname, rcity
from custinfo
where id < 200;
return i, rname, rcity with resume;
end foreach;
end procedure;
Если CUSTINFO - таблица Oracle, эквивалентная процедура Oracle может быть:
create or replace package orapack as
type custcurtype is ref cursor return custinfo%rowtype
end orapack;create or replace custresultset (custcursor inout orapack.custcurtype)
as begin
open custcursor for select id, name, city from custinfo
where id < 200
end custresultset;
Во всех случаях Вы создаёте resultSet -объект для получения информации из хранимой процедуры. Вы делаете это через использование метода resultSet объекта хранимой процедуры так:
resObj = spObj.resultSet();
Как и для Cursor -объектов, resultSet -объекты содержат текущий ряд, то есть ряд, на котором стоит указатель в результирующем наборе. Вначале указатель позиционирован перед первым рядом результирующего набора. Чтобы увидеть значения рядов результирующего набора, Вы используете метод next для перемещения указателя по рядам результирующего набора, как показано в следующем примере:
spobj = connobj.storedProc("getcusts");
if ( spobj && (connobj.majorErrorCode() == 0) ) {
// Создаётся новый resultSet-объект.
resobj = spobj.resultSet(); // Перед тем как продолжить, убедитесь, что Вы получили результирующий набор.
if ( resobj && (connobj.majorErrorCode() == 0) ) { // Сначала перемещает указатель resultSet-объекта к первому // ряду результирующего набора, а затем циклически проходит по рядам.
while (resObj.next())
{
write("<TR><TD>" + resObj.name + "</TD>");
write("<TD>" + resObj.city + "</TD>");
write("<TD>" + resObj.id + "</TD></TR>");
}
resobj.close();
}
}
До тех пор, пока в результирующем наборе имеется следующий ряд, метод next возвращает true и перемещает указатель к следующему ряду. Если указатель достиг последнего ряда результирующего набора, метод next возвращает false.
Предыдущий пример работает с хранимой процедурой Sybase. В этом случае resultSet -объект содержит именованное свойство для каждого столбца результирующего набора. Для процедур Informix и DB2, по контрасту, объект не содержит именованных столбцов. В этом случае Вы можете получить значения, ссылаясь на позицию столбца. Так, для Informix и DB2 Вы можете использовать такой код для вывода аналогичной информации:
spobj = connobj.storedProc("getcusts");
if ( spobj && (connobj.majorErrorCode() == 0) ) { // Создаётся новый resultSet-объект.
resobj = spobj.resultSet();
// Перед тем как продолжить, убедитесь, что Вы получили результирующий набор.
if ( resobj && (connobj.majorErrorCode() == 0) ) {
// Сначала перемещает указатель resultSet-объекта к первому // ряду результирующего набора, а затем циклически проходит по рядам.
while (resObj.next())
{
write("<TR><TD>" + resObj[1] + "</TD>");
write("<TD>" + resObj[2] + "</TD>");
write("<TD>" + resObj[0] + "</TD></TR>");
}
resobj.close();
}
}
Вы можете использовать позицию столбца для результирующих наборов любой БД, а не только с Informix и DB2. Вы можете использовать имя столбца для хранимой процедуры всех типов БД, а не только Informix или DB2.
Работа с Внешними Библиотеками
Для взаимодействия с внешними приложениями рекомендуется использовать LiveConnect, как описано в . Однако Вы можете также вызывать функции, написанные на других языках, таких как C, C++ или Pascal, и скомпилированных в библиотеки. Такие функции называются native-функции или внешние функции. Библиотеки внешних функций, называемые внешними библиотеками, являются библиотеками динамической компоновки/dll в ОС Windows и совместно используемыми объектами/shared objects - в ОС Unix.
Важно!
Будьте осторожны при использовании внешних функций в Вашем приложении. Внешние функции могут нарушить защиту/безопасность, если внешняя программа выполняет команды пользователя в командной строке (например, программа, дающая возможность войти в ОС, или команды оболочки/shell). Эта функциональность опасна, так как хакер может присоединить дополнительные команды, используя точку с запятой для присоединения нескольких операторов. Лучше исключить использование ввода командной строки, если Вы не проверяете его достаточно жёстко.
Внешние функции используются в следующих случаях:
Если у Вас уже имеются сложные функции, написанные на других языках, которые можно использовать в приложении.
Если приложению нужны функции интенсивных вычислений. Обычно функции, написанные в native-коде, работают быстрее, чем функции, написанные на языке JavaScript.
Если приложение должно выполнять задачи, которые невозможно выполнить в JavaScript.
В директории примеров jsaccall есть несколько исходных и header-файлов, иллюстрирующих вызов функций внешних библиотек из приложения JavaScript.
В Application Manager Вы ассоциируете внешнюю библиотеку с
определённым приложением. Но после того как библиотека ассоциирована с одним из приложений, она становится доступной всем другим установленным приложениям.
Выполните следующие действия для использования библиотеки внешних функций в приложении JavaScript:
- Напишите и скомпилируйте библиотеку внешних функций в форме, совместимой с JavaScript. (См. ).С помощью Application Manager идентифицируйте используемую библиотеку, установив новое приложение или изменив параметры установки существующего приложения. После этого все приложения на данном сервере смогут вызывать внешние функции этой библиотеки. (См. ).Рестартуйте сервер, чтобы загрузить библиотеку с Вашим приложением. Функции внешней библиотеки теперь доступны для всех приложений на этом сервере.
В вашем приложении используйте функции JavaScript registerCFunction - для идентифицирования вызываемых функций библиотеки - и callC - для вызова этих функций. (См. и ).
Рекомпилируйте и рестартуйте Ваше приложение, чтобы изменения вступили в силу.
Важно!
Вы обязаны рестартовать Ваш сервер, чтобы установить библиотеку для использования с приложениями. Вы обязаны рестартовать сервер каждый раз после добавления файлов новых библиотек или изменения имён файлов библиотек, используемых приложениями.