Серверный JavaScript 1.4. Руководство по использованию

         

Статус-Коды


В следующей таблице дан список статус-кодов, возвращаемых различными методами. Netscape рекомендует не использовать эти значения напрямую. Вместо этого, если метод возвращает ненулевое значение, используйте ассоциированные методы majorErrorCode и majorErrorMessage для определения конкретной ошибки.

Статус-Код

Пояснение

Статус-Код

Пояснение



0

Нет ошибки

14

Null-параметр

1

Недостаточно памяти

15

Объект database не найден

2

Объект не был инициализирован

16

Отсутствует необходимая информация

3

Ошибка конвертации типов

17

Объект не поддерживает несколько читателей

4

БД не зарегистрирована

18

Объект не поддерживает удаление

5

Ошибка, выданная сервером

19

Объект не поддерживает вставку

6

Сообщение сервера

20

Объект не поддерживает обновление

7

Ошибка в библиотеке поставщика

21

Объект не поддерживает обновление

8

Потеря соединения

22

Объект не поддерживает индексы

9

Конец fetch (не смог перевести - прим. перев.)

23

Объект не может быть уничтожен

10

Неверное использование объекта

24

Предоставлено некорректное соединение

11

Столбец не существует

25

Объект не поддерживает привилегии

12

Неверное позиционирование внутри объекта (нарушение границ)

26

Объект не поддерживает курсоры

13

Неподдерживаемая возможность

27

Невозможно открыть



Stopped application/остановленное приложение


Приложение, остановленное Application Manager'ом и недоступное клиентам.



Строка


Если метод возвращает строку, Вы обычно не получаете сообщения об ошибке. Если, однако, метод возвращает null, проверьте ассоциированный error-метод.

Следующие методы возвращают строку:

Connection.majorErrorMessage
Connection.minorErrorMessage

Cursor.columnName
database.majorErrorMessage
database.minorErrorMessage
DbPool.majorErrorMessage

DbPool.minorErrorMessage
Resultset.columnName



Строковые Значения


Когда Вы передаёте строковые типы JavaScript в качестве параметра Java-методам, Java конвертирует эти значения в соответствии с правилами, описанными в таблице:

Тип Java-параметра

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

lava.lang.String
java.lang.Object

Строка JavaScript конвертируется в экземпляр java.lang.String с ASCII-значением.

byte
double
float
int
long
short

Все значения конвертируются в числа, как описано в .

char

Все значения конвертируются в числа.

boolean

Пустая строка становится false.все другие значения становятся true.



В таблице перечислены предопределённые свойства


В таблице перечислены предопределённые свойства объекта request. Некоторые из них соответствуют переменным окружения CGI. Вы можете получить доступ к этим и другим переменным окружения CGI через использование функции ssjs_getCGIVariable, описанной в разделе .
СвойствоОписание
Пример значения
agent
Имя и версия клиентского программного обеспечения. Используйте это свойство для адресного применения расширенных возможностей некоторых браузеров.

Mozilla/1.1N (Windows; I; 32bit)
auth_type
Тип авторизации, если запрос защищён авторизацией какого-либо типа. Netscape web-серверы поддерживают базовую авторизацию доступа по HTTP. Соответствует переменной окружения CGI AUTH_TYPE.
basic
auth_user
Имя локального HTTP-пользователя web-браузера, если авторизация доступа HTTP была активирована для данного URL. Заметьте, что это не способ определения имени пользователя, получающего доступ к Вашей программе. Соответствует переменной окружения CGI REMOTE_USER.
vpg
ip
IP-адрес клиента. Может использоваться для авторизации или отслеживания доступа.
198.95.251.30
method
HTTP-метод, ассоциированный с запросом. Приложение может использовать его для определения соответствующего ответа на запрос. Соответствует переменной окружения CGI REQUEST_METHOD.
GET

protocol

Уровень протокола HTTP, поддерживаемый клиентским программным обеспечением. Соответствует переменной окружения CGI SERVER_PROTOCOL.

HTTP/1.0

query

Информация из запрашивающей HTML-страницы; это информация в URL, идущая после знака "?". Соответствует переменной окружения CGI QUERY_STRING.

button1=on&button2=off
imageX
Горизонтальная позиция курсора, когда пользователь щёлкает на карте изображений/image map. Описано в разделе .

45

imageY

Вертикальная позиция курсора, когда пользователь щёлкает на карте изображений. Описано в разделе

132
uri
Частичный URL запроса: с вырезанными протоколом, именем хоста и, возможно имеющимся, номером порта.

videoapp/add.html

1
Для HTTP 1.0 method имеет одно из значений: GET, POST или HEAD.

В объекте client отсутствуют значения


В объекте client отсутствуют значения предопределённых свойств, поскольку он предназначен для хранения специфических для приложения данных. Операторы JavaScript могут присваивать специфичные для приложения свойства и значения объекту client. Хорошим примером свойства объекта client является ID-номер потребителя. Когда пользователь в первый раз вызывает приложение, оно обязано присвоить customer ID, как в следующем примере:
client.custID = getNextCustID();
Здесь определяемая в приложении функция getNextCustID используется для вычисления customer ID. Машина выполнения затем присваивает этот ID свойству custID объекта client.
После установки customer ID может оказаться неудобным требовать от пользователя ввода ID на каждой странице приложения. Однако без использования объекта client нет иной возможности ассоциировать корректный customer ID с последующими запросами клиента.
Из-за использования такой техники для обслуживания свойств объекта client при наличии нескольких клиентских запросов имеется одно важное ограничение для значений свойств объекта client. Машина выполнения JavaScript не сервере конвертирует значения всех свойств объекта client в строки.
Не присваивайте объект в качестве значения свойства объекта client. Если Вы это сделаете, машина выполнения конвертирует этот объект в строку; после этого Вы не сможете больше работать с этим объектом. Если значение клиентского свойства представляет другой тип данных, например, number, Вы обязаны конвертировать строковое значение перед тем как его использовать. Например, Вы можете создать целочисленное свойство объекта client:
client.totalNumber = 17;
Затем Вы можете использовать parseInt для инкремента значения totalNumber:
client.totalNumber = parseInt(client.totalNumber) + 1;
Аналогично Вы можете создать Булево свойство объекта client:
client.bool = true;
А затем проверить его:
if (client.bool == "true")
write("It's true!");
else

   write("It's false!");

У объекта project нет предопределённых


У объекта project нет предопределённых свойств, поскольку он предназначен для содержания специфических для приложений данных, доступных для многих клиентов. Вы можете создавать свойства любого верного типа JavaScript, включая ссылки на другие JavaScript-объекты. Если Вы храните ссылку на другой объект в объекте project, машина выполнения не уничтожает объект, на который ссылаются, по окончании клиентского запроса, в котором объект создаётся. Объект доступен и в течение последующих запросов.
Хороший пример свойства объекта project - следующий доступный ID потребителя. Приложение может использовать это свойство для отслеживания последующих присваиваемых IDs. Любому клиенту, получающему доступ к приложению и не имеющему ID потребителя, присваивается этот ID, и его значение будет увеличиваться для каждого первоначального доступа.
Помните, что объект project существует только в течение периода работы приложения на сервере. Когда приложение останавливается, объект project уничтожается вместе со всеми значениями его свойств. Поэтому, если у Вас имеются данные приложения, которые нужно сохранять постоянно, их необходимо сохранять в БД (см. ) или в файле на сервере (см. ).

Свойства Объекта client как Куки


Если приложение использует технику клиентских кук для работы с объектом client, машина выполнения на сервере сохраняет имена и значения свойств объекта client как куки на клиенте. Об использовании кук для работы с объектом client см. раздел .

Для свойства объекта client propName машина выполнения автоматически создаёт куку с именем NETSCAPE_LIVEWIRE.propName, принимая, что приложение использует технику работы с клиентскими куками. Машина выполнения кодирует значения свойств так, как это требуется по протоколу кук Netscape cookie protocol.

Для доступа к этим кукам в клиентском JavaScript Вы можете извлечь эту информацию путём использования свойства document.cookie и такой функции как getSSCookie, как показано здесь:

function getSSCookie(name) {

   var search = "NETSCAPE_LIVEWIRE." + name + "=";
   var retstr = "";

   var offset = 0;
   var end = 0;

   if (document.cookie.length > 0) {

      offset = document.cookie.indexOf(search);

      if (offset != -1) {

         offset += search.length;

         end = document.cookie.indexOf(";", offset);

         if (end == -1)

            end = document.cookie.length;

         retstr = unescape(document.cookie.substring(offset, end));

      }
   }
   return(retstr)
}

Функция getSSCookie не является предопределённой функцией JavaScript. Если Вам нужна похожая функциональность, Вы обязаны определить её (функцию) в Вашем приложении.

Чтобы отправленная на сервер информация стала свойством объекта client, добавьте куку с именем, имеющим форму NETSCAPE_LIVEWIRE.propName. Предположим, Ваше приложение использует технику работы с клиентскими куками, а машина выполнения на сервере создаёт свойство объекта client под названием propName  для данной куки.


Тогда Вы можете использовать функцию типа следующей:
function setSSCookie (name, value, expire) {

   document.cookie =

      "NETSCAPE_LIVEWIRE." + name + "="

      + escape(value)

      + ((expire == null) ? "" : ("; expires=" + expire.toGMTString()));
}
Здесь функция setSSCookie также не является предопределённой функцией JavaScript. Если Вам необходима аналогичная функциональность, Вы обязаны определить функцию в Вашем приложении.
Вы можете вызывать эти функции в клиентском JavaScript для получения набора значений свойств объекта client, как в следующем примере:
var value = getSSCookie ("answer");
if (value == "") {

   var expires = new Date();
   expires.setDate(expires.getDate() + 7);

   setSSCookie ("answer", "42", Expires);
}
else

   document.write ("The answer is ", value);
Эта группа операторов проверяет, имеется ли свойство объекта client с названием answer. Если нет, код создаёт его и устанавливает значение 42; если найдено, выводится его значение.

Sybase


Чтобы использовать сервер Sybase, Вы обязаны иметь Netscape Enterprise Server. Вы не можете получить доступ к Sybase из Netscape FastTrack Server.

Если БД и web-сервер находятся на разных машинах, следуйте инструкциям раздела

Если БД и web-сервер находятся на одной машине, следуйте инструкциям раздела

Кроме того, если Вы используете Unix-платформу, и Sybase имеет многопоточный драйвер для этой платформы, следуйте инструкциям раздела См. в список Unix-платформ, на которых Sybase имеет многопоточный драйвер.


Прежде чем использовать нижеуказанные инструкции, Вы обязаны сконфигурировать Ваш Sybase-клиент, как указано в разделе Кроме того, в Unix убедитесь, что переменная окружения PATH содержит $SYBASE\bin и DSQUERY указывает на ваш сервер.

SQL-файлы для создания видео-БД в Sybase, находятся в двух директориях:

$NSHOME\js\samples\videoapp\syb
$NSHOME\js\samples\oldvideo\syb

    Запустите соответствующий скрипт из командной строки. В Unix это:syb_video.csh userid password

    Например:$NSHOME\js\samples\videoapp\syb\syb_load.csh sa

    В NT это скрипт:syb_load userid password

    Например:c:\netscape\server\js\samples\videoapp\syb\syb_load sa

    Можно также запустить скрипт из директории oldvideo.

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

ПРИМЕЧАНИЕ:

Если у Вас на машине установлены и Sybase, и MS SQL Server или DB2, потенциально может возникнуть конфликт имён. Эти производители поставляют утилиты с одинаковыми названиями (bcp и isql). При запуске этих скриптов убедитесь, что переменная окружения настроена для запуска корректной утилиты.



Sybase (только для Unix)


На некоторых Unix-платформах Sybase имеет и однопоточный, и многопоточный драйверы. Если Sybase имеет многопоточный драйвер для конкретной Unix-машины, Вы обязаны использовать этот многопоточный драйвер с LiveWire. На этих платформах Ваш web-сервер будет вести себя непредсказуемо с однопоточным драйвером. Это требование применяется как для локальных, так и для удалённых соединений. оно не применяется к Windows-платформам.

См. в список Unix-платформ, на которых Sybase имеет многопоточный драйвер.

Чтобы убедиться в том, что Вы используете многопоточный драйвер, вы обязаны отредактировать Ваш файл $SYBASE/config/libtcl.cfg. Он содержит пару строк, которые включают однопоточный, либо многопоточный драйвер. Вы обязаны иметь одну из этих строк закомментированную, а другую активную. Например, на Solaris найдите эти строки:

[DRIVERS]
;libtli.so=tcp unused ; Это беспоточный tli-драйвер.

libtli_r.so=tcp unused ; Это поточный tli-драйвер.

Удостоверьтесь, что строка для однопоточного драйвера закомментирована, а строка многопоточного драйвера - не закомментирована. Имена файлов различаются на разных платформах, но эти строки всегда расположены в разделе DRIVERS и всегда закомментированы, чтобы различать однопоточный и многопоточный драйверы.

ПРИМЕЧАНИЕ:

Если вы хотите использовать утилиту Sybase isql, Вы обязаны использовать беспоточный tli -драйвер. В этом случае строка для libtli_r.so

обязана быть закомментирована. Об использовании этого драйвера см. документацию по Sybase.



Технология Обслуживания Объекта client


Объект client ассоциирован как с определённым приложением, так и с определённым клиентом. Как было сказано в разделе , машина выполнения создаёт новый объект client всякий раз при поступлении нового запроса от клиента к серверу. Однако целью является сохранение свойств объекта client от одного запроса до следующего. Для этого машине выполнения нужно сохранить свойства объекта client между запросами.

Есть два основных подхода при работе со свойствами объекта client: можно работать с ними на стороне клиента или на сервере. Эти два вида клиентской техники либо сохраняют имена свойств и их значения непосредственно в куках на клиенте, либо в URLs на генерируемой HTML-странице. Все три вида серверной техники сохраняют имена свойств и их значения в структуре данных в памяти сервера, но различаются по используемой для индексирования структуры этих данных схеме.

Вид техники выбирается, когда Вы используете JavaScript Application Manager для инсталяции или модификации приложения, как указано в разделе . Это даёт Вам (или менеджеру сайта) возможность изменять технику обслуживания без перекомпилирования приложения. Однако поведение Вашего приложения может меняться в зависимости от действующей техники обслуживания объекта client, как описано в следующих разделах. Обязательно объясните Вашему менеджеру сайта, от какого вида техники зависит работа Вашего приложения. Иначе менеджер может изменить эти установки и нарушить работу Вашего приложения.

Поскольку некоторые виды этой техники сохраняют информацию в структуре данных на сервере или в куки-файле на клиенте, машина выполнения JavaScript дополнительно должна определять, когда избавиться от этих свойств. В разделе рассматривается, как машина выполнения определяет это, и описываются методы, которые можно использовать для изменения этого поведения.



Тело Запроса


Для нормальных HTML-запросов content type (тип содержимого) запроса будет application/x-www-form-urlencoded. После получения запроса с этим content type машина выполнения JavaScript на сервере обрабатывает запрос, используя данные из тела запроса. В этой ситуации Вы не можете получить прямой доступ к необработанным данным тела запроса. (Конечно, Вы можете получить доступ к его содержимому через объекты request и client, сконструированные машиной выполнения).

Если, однако, запрос имеет любой иной content type, машина выполнения не обрабатывает автоматически тело запроса. В этом случае Ваше приложение должно определить, что делать с содержимым.

Возможно, другая страница Вашего приложения отправила запрос этой странице. Следовательно, Ваше приложение обязано предусматривать возможность получения необычного content type и должно знать, как его обработать.

Для получения доступа к телу запроса Вы используете метод getPostData объекта request. Этот метод принимает в качестве параметра количество символов тела. Если Вы специфицируете 0, тело возвращается целиком. return-значение это строка, содержащая запрошенные символы. Если доступных данных нет, метод возвращает пустую строку.

Можно использовать этот метод для получения всех символов за один раз или читать участки данных. Представляйте тело запроса как поток символов. При чтении Вы можете только продвигаться вперёд; Вы не можете читать одни и те же символы несколько раз.

Чтобы назначить всё тело запроса переменной postData, можно использовать следующий оператор:

postData = request.getPostData(0);

Если в качестве параметра специфицировано 0, метод получает весь запрос. Вы можете точно определить, сколько символов содержится в информации, используя свойство content-length шапки таким образом:

length = parseInt(header["content-length"], 10);

Для получения тела запроса небольшими блоками Вы можете специфицировать иной параметр. Например, следующий код обрабатывает тело запроса блоками по 20 символов:

var length = parseInt(header["content-length"], 10);
var i = 0;

while (i < length) {
   postData = request.getPostData(20);

   // ...обработка postData...
   i = i + 20;
}

Конечно, такой подход имеет смысл только тогда, когда Вы знаете, что блоки состоят из 20 символов информации.



Тэг SERVER


Тэг SERVER это наиболее распространённый способ внедрения серверного JavaScript в HTML-страницу. Вы можете использовать тэг SERVER в любой ситуации; обычно, однако, вместо него используются обратные кавычки, если Вы генерируете имена или значения атрибутов для HTML-страницы.

Большая часть операторов между тэгами <SERVER> и </SERVER> не появляется на HTML-странице, высылаемой клиенту. Эти операторы выполняются на сервере. Однако вывод вызовов функции write появляется в результирующем HTML.

Следующая выдержка из приложения Hello World иллюстрирует эти варианты:

<P>This time you are
<SERVER>
write(request.newname);

client.oldname = request.newname;
</SERVER>
<h3>Enter your name</h3>

Получив данный участок кода, машина выполнения генерирует HTML на базе значения request.newname в операторе write. Во втором операторе она просто выполняет операцию JavaScript, присваивая значение request.newname свойству client.oldname. Она не генерирует никакого HTML. Итак, если request.newname будет "Mr. Ed," машина выполнения генерирует из предыдущего отрывка следующий HTML:

<P>This time you are
Mr. Ed
<h3>Enter your name</h3>



Transaction/транзакция


Группа акций БД, которые выполняются вместе; все акции проходят или все терпят неудачу.



Удаление Приложения


Чтобы удалить приложение, выберите его в списке приложений и щёлкните Remove. Application Manager удалит приложение, и оно больше не сможет быть запущено на сервере. Клиенты не смогут больше получить доступ к приложению. Если Вы удалите приложение, а после этого захотите запустить его, нужно будет инсталировать его заново.

Хотя клиенты потеряют доступ к приложению, удаление его с помощью Application Manager не удаляет физически файлы приложения с сервера. Если Вы хотите полностью удалить файлы, сделайте это вручную.



Удалённый Informix


Только для Unix: Установите Informix ESQL/C Runtime Client 7.22 (называемый также Informix I-Connect), а затем установите следующие переменные окружения:

INFORMIXDIR

Специфицирует верхнюю директорию, в которой установлен Informix.

INFORMIXSERVER

Специфицирует имя Informix-сервера по умолчанию.

INFORMIXSQLHOSTS

Специфицирует путь файла sqlhosts, если Вы поместили его куда-нибудь кроме $INFORMIXDIR/etc/sqlhosts. Эту переменную устанавливать не нужно, если Вы оставили файл sqlhosts в этой директории.

SHLIB_PATH

(HP-UX) Обязана содержать $INFORMIXDIR/lib и $INFORMIXDIR/lib/esql.

Вы обязаны также изменить $INFORMIXDIR/etc/sqlhosts, чтобы оно соответствовал имени службы в файле /etc/services. О том, как это сделать, см. документацию Informix.

Только для NT: Установите Informix ESQL/C Runtime Client 7.20 (называемый также Informix I-Connect.) В процессе установки все необходимые переменные окружения также устанавливаются. Вы используете подходящую утилиту Informix для ввода нужной информации об удалённом сервере, с которым Вы хотите устанавливать соединение.

Если Ваш web-сервер запускается как System, убедитесь, что у вас запущен regcopy.exe.

Все платформы: В зависимости от используемой службы имён, Вам может понадобиться также отредактировать соответствующий файл - добавить IP-адрес удалённой хост-машины, с которой Вы соединяетесь. В NT это файл winnt\system32\drivers\etc\hosts ниже директории NT SystemRoot. На Unix это файл /etc/hosts.

В той же директории добавьте следующую строку к файлу services:

ifmx_srvc port/tcp # Informix Online Server

где ifmx_srvc это имя Вашей службы, а port - номер порта. Номер порта обязан совпадать с номером порта на удалённой машине, который прослушивается Informix-сервером. Чтобы эта строка начала действовать, Вы обязаны либо вставить как минимум один пробел после tcp, либо поместить комментарий в конце этой строки. Например, если Ваша служба Informix называется ifmx1 и номер порта 1321, Вы добавляете следующую строку:

ifmx1 1321/tcp # Informix Online Server



Удалённый Oracle


Только для NT: Вы обязаны установить клиентское программное обеспечение Oracle 7.3.2 для NT. Клиенты Oracle 7.1 и 7.2 не поддерживаются. Вы обязаны также создать файлы конфигурации Oracle, используемые соответствующей утилитой конфигурирования Oracle.

Только для Unix: Прежде чем Вы сможете подключиться к Oracle под Irix, Вы обязаны иметь соответствующие патчи для Irix. См. в информацию о необходимых патчах.

Вы обязаны установить клиентов Oracle 7.3.x для Unix. Клиенты Oracle 7.1 и 7.2 не поддерживаются.

Вы обязаны установить следующие переменные окружения:

ORACLE_HOME

Специфицирует директорию верхнего уровня, в которой установлен Oracle.

TNS_ADMIN

Специфицирует место размещения файлов конфигурации, например, $ORACLE_HOME/network/admin. После инсталяции Oracle создаёт файлы конфигурации под /var/opt/oracle. Если listener.ora и tnsnames.ora находятся в этой директории, Вам может не понадобиться устанавливать TNS_ADMIN, поскольку по умолчанию Oracle использует /var/opt/oracle.

Если эти переменные не установлены надлежащим образом, Oracle возвращает код ошибки ORA-1019 при первой попытке установления соединения. Об обработке ошибок см.



Удалённый Sybase


Только для Unix: Установите следующие переменные окружения:

SYBASE

Директория верхнего уровня, в которой установлен Sybase.

LD_LIBRARY_PATH

(DEC) Обязана содержать $SYBASE/lib.

Для Solaris Вы обязаны также следовать инструкциям раздела

Все платформы: Вы обязаны установить SYBASE Open Client/C. Поддерживаемые поставщики перечислены в разделе

Вы можете использовать подходящую утилиту Sybase для ввода в файл sql.ini (NT) и файл interfaces (все платформы) информации об удалённом сервере, с которым Вы хотите установить соединение. Дополнительно см. документацию Sybase.



Уничтожение Объекта client


Приложение может явно уничтожать объект client методом destroy:

client.destroy();

Когда приложение вызывает destroy, JavaScript удаляет все свойства из объекта client.

Если Вы используете технику клиентских кук для работы с объектом client, метод destroy уничтожает все значения свойств объекта client, но не влияет на то, что хранится в клиентском cookie-файле. Чтобы удалить и значения свойств из этого cookie-файла, не используйте метод destroy; вместо него используйте expiration с аргументом 0 секунд.

Если Вы используете технику клиентского кодирования URL для работы с объектом client, метод destroy удаляет все свойства объекта client. Ссылки на странице до вызова destroy оставляют свойства объекта client в своих URL, а ссылки, расположенные после вызова метода, не имеют свойств. Поскольку маловероятно, что Вам понадобится, чтобы  только некоторые URL страницы содержали свойства объекта client, Вы, вероятно, должны будете вызывать destroy либо вверху, либо внизу страницы, когда используете работу с клиентскими URL. См. также .



Уникальная Ссылка на Объект client


Для некоторых приложений может понадобиться сохранять информацию, специфическую для пары клиент/приложение, в объектах project или server. Два обычных примера - сохранение соединения с БД между клиентскими запросами (описано в ) или хранение специального объекта, имеющего такой же период существования, что и предопределённый объект client, и содержащего значения объектов (описано в разделе ).

В этих случаях Вам необходим способ уникально обратиться к паре клиент/приложение. JavaScript имеет для этого две функции, ssjs_getClientID и ssjs_generateClientID. Они не принимают аргументов; обе возвращают уникальную строку, которую вы можете использовать для идентификации пары.

При каждом вызове ssjs_generateClientID машина выполнения возвращает новый идентификатор. Исходя из этого, если Вы используете эту функцию и Вам нужен идентификатор, существующий дольше, чем отдельный клиентский запрос, Вам нужно сохранить этот идентификатор, возможно, как свойство объекта client. Пример использования этой функции см. в разделе .

Если Вы используете эту функцию и сохраняете ID в объекте client, нужно проявлять осторожность, чтобы хакер не смог получить доступ к этому ID и, как следствие, к закрытой информации.

Альтернативой может стать использование функции ssjs_getClientID. Если Вы применяете одну из этих серверных технологий для объекта client, машина JavaScript генерирует и использует идентификатор для доступа к информации определённой пары клиент/приложение. (О работе с объектом client см. раздел ).

При использовании этих технологий ssjs_getClientID возвращает идентификатор, используемый машиной выполнения. Каждый раз при вызове этой функции из определённой пары клиент/приложение Вы будете получать тот же самый идентификатор. Соответственно, Вам нет необходимости сохранять идентификатор, возвращаемый функцией ssjs_getClientID. Однако, если Вы используете другую технику, эта функция возвращает "undefined"; тогда необходимо использовать функцию ssjs_generateClientID.

Если Вам нужен идентификатор и Вы используете серверную технологию, возможно, понадобится использовать функцию ssjs_getClientID. Тогда Вам не нужно будет самостоятельно сохранять идентификатор и отслеживать его использование; машина выполнения сделает это за Вас. При использовании клиентской техники, однако, Вы не сможете применять функцию ssjs_getClientID; тогда Вы обязаны использовать функцию ssjs_generateClientID.



Updatable cursor/обновляемый курсор


Курсор БД, в котором Вы можете обновлять таблицы на основе содержимого виртуальной таблицы.



Управление Доступом к Приложению


При инсталяции приложения Вам может понадобиться ограничить к нему доступ пользователей, особенно если приложение предоставляет доступ к закрытой информации.

Если Вы работаете на рабочем сервере за брандмауэром/firewall, то можете не беспокоиться об ограничении доступа в процессе разработки приложения. Удобно не иметь ограничений доступа в процессе разработки приложения, так как Вы можете быть уверены в защищённости приложения от атак за стеной firewall. Если Вы используете учебные данные на стадии разработки, то риск ещё меньше. Однако, если Вы публикуете Ваше приложение, Вы должны быть уверены, что любой посетитель Вашего приложения может им пользоваться.

Если Вы закончили разработку и готовы опубликовать приложение, необходимо предусмотреть его защиту. Вы можете ограничить доступ, применив к приложению стиль конфигурации сервера. О стилях конфигурации см. руководство администратора Вашего web-сервера.



URL


Universal Resource Locator. Схема адресации, используемая в World Wide Web.



URL Приложения


При установке приложения Вы обязаны задать ему имя. Это имя определяет базовый URL

приложения: тот URL, который клиенты используют для доступа к странице по умолчанию данного приложения JavaScript.

Базовый URL приложения имеет форму:

http://server.domain/appName

Здесь server это имя HTTP-сервера, domain это домен Internet (включая субдомены), а appName это имя приложения, которое Вы ему дали при инсталяции. Отдельные страницы приложения достигаются через URL приложения в форме:

http://server.domain/appName/page.html

Здесь page это имя страницы приложения. Например, если Ваш сервер называется coyote, а домен имеет имя royalairways.com, базовый URL для приложения hangman будет:

http://coyote.royalairways.com/hangman

Если клиент запрашивает этот URL, сервер генерирует HTML для страницы по умолчанию приложения и высылает её клиенту. URL приложения страницы winning в этом приложении:

http://coyote.royalairways.com/hangman/youwon.html

Важно!

Прежде чем инсталировать приложение, убедитесь, что выбранное Вами имя приложения не присвоило существующий URL на Вашем сервере. Машина выполнения JavaScript направляет все клиентские запросы по URL, соответствующим URL приложения, в директорию, специфицированную для web-файла. Таким образом можно "обмануть" нормальную корневую директорию.

Например, предположим, клиент запрашивает URL, который начинается с префикса из предыдущего примера:

http://coyote.royalairways.com/hangman

В этом случае машина выполнения на сервере ищет документ в директории samples\hangman, а не в нормальной корневой директории сервера. Сервер обслуживает в этой директории страницы, которые не компилируются в приложение.

Вы можете поместить Ваши исходные (неоткомпилированные) файлы серверного JavaScript в ту же директорию, что и web-файл; однако Вы должны делать это только для отладки. Если Вы публикуете Ваше приложение для общего пользования, Вы, по соображениям безопасности, не должны публиковать неоткомпилированные файлы серверного JavaScript.



Установка flexi как CORBA-Клиента


Файл start.html это начальная страница приложения JavaScript flexi. Эта страница использует LiveConnect для инициализации ISB for Java и установления соединения с FSA-Admin.

<server>
// Инициализируется orb.

project.orb = Packages.org.omg.CORBA.ORB.init();// Устанавливается соединение с сервисом "FSA-Admin".
// По умолчанию принимается, что name service запущен на текущем сервере.

nameHost = "http://" + server.hostname;
serviceName = "/FSA-Admin";

serviceURL = nameHost + serviceName;// Разрешается имя и получается ссылка на стаб Admin.
project.fsa_admin = Packages.Flexi.AdminHelper.narrow(

netscape.WAI.Naming.resolve(serviceURL));</server>

Первый оператор инициализирует ISB for Java, вызывая static-метод init Java-класса org.omg.CORBA.ORB. Он сохраняет возвращённый объект как свойство объекта project, так что он доступен для всего приложения.

Второй набор операторов определяет URL, который использовался для регистрации объекта FSA-Admin. Если Вы использовали при регистрации этого объекта другой URL (как описано в последнем разделе), Вам нужно сделать соответствующие изменения в этих операторах. URL, используемый в CORBA-сервере, обязан быть точно тем же, что и URL, используемый в CORBA-клиенте.

Код затем вызывает метод resolve объекта netscape.WAI.Naming для установления соединения с объектом Admin, который был зарегистрирован FlexiServer как FSA-Admin. Наконец, он вызывает метод narrow объекта AdminHelper для приведения полученного объекта к соответствующему типу Java-объекта. Этот Java-метод возвращает Java-объект, соответствующий распределённому объекту. Машина выполнения JavaScript обёртывает этот Java-объект как JavaScript-объект и сохраняет его как свойство объекта project. Теперь Вы можете вызывать методы и получать доступ к свойствам этого возвращённого объекта, как и любого другого Java-объекта. Другие страницы flexi работают через этот объект.

И ещё раз - о том, как работают CORBA-объекты, см. книгу  .



Установка FlexiServer как CORBA-Сервера


Функция main отдельного Java-приложения реализована в flexi\impl\FlexiServer.java. Его код таков:

import org.omg.CORBA.*;class FlexiServer {
public static void main(String[] args) {

   try {
      // Инициализируются orb и boa.

      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();

      org.omg.CORBA.BOA boa = orb.BOA_init();

      // Создаётся серверный объект.
       Admin __admin = new Admin();       // Информирует boa, что серверный объект готов.
       boa.obj_is_ready(__admin);       // Регистрируется имя объекта с именем сервиса.
       // Сначала определяется хост имени сервиса, по умолчанию это <localhost>:80.
       String _nameServiceHost = null;
      if (args.length > 0) {
         // Принимается, что первый arg это имя хоста имени
         // сервиса. Ожидаемый формат: <hostname>:<port>
          _nameServiceHost = args[0];
      }

      else {
          String _localHostName = null;
          try {
            _localHostName=
                java.net.InetAddress.getLocalHost().getHostName();
             _nameServiceHost = _localHostName + ":80";
          }
          catch (java.net.UnknownHostException e) {
             System.out.println("Couldn't determine local host;
             can't register name.");
          }
      }       String _regURL = "http://" + _nameServiceHost + "/FSA-Admin";
       System.out.println("Registering Admin object at URL: " + _regURL);       // Регистрируется серверный объект.


      netscape.WAI.Naming.register(_regURL, __admin);

      System.out.println("Started FSA Admin: " + __admin);       boa.impl_is_ready();

   }   catch (org.omg.CORBA.SystemException e) {
      System.err.println(e);
      }

   }
}

Этот код инициализирует ORB и создаёт экземпляр класса Admin. Затем экземпляр регистрируется как распределённый объект с URL в форме http://host

:port/FSA-Admin. По умолчанию host это имя хоста, на котором запущен FlexiServer, а port равен 80. Вы можете поставить Ваши собственные значения для host:port  путём передачи их как аргументов для FlexiServer при его старте. Чтобы использовать локальный хост, но другой номер порта, Вам нужно изменить исходный код и перекомпилировать его. Если код имеет соответствующее имя, он регистрирует объект, используя метод register объекта netscape.WAI.Naming. Дополнительно см. книгу .

Наконец, код печатает сообщение на консоль и ожидает запросы от CORBA-клиентов. В данном случае единственным CORBA-клиентом, который знает о нём, является приложения flexi на языке JavaScript.


Установка Нового Приложения


Вы не можете запустить приложение, и клиенты не могут получить к нему доступ, пока Вы не установите его. Инсталяция приложения идентифицирует его на сервере. После установки Вы можете перестроить/rebuild и запустить приложение любое число раз. Приложение нужно переустановить только тогда, когда Вы его удалили. Вы можете установить до 120 приложений JavaScript на один сервер.

Прежде чем устанавливать, Вы обязаны поместить все файлы, имеющие отношение к приложению, в соответствующую директорию путём публикации файлов. Иначе Вы получите сообщение об ошибке при попытке инсталяции. Из соображений безопасности, Вы можете не захотеть публиковать свои исходные файлы JavaScript на сервер публикации. См. в разделе об ограничениях на размещение файлов.

Чтобы установить новое приложение с помощью Application Manager, щёлкните Add Application. В ответ Application Manager выведет в правом фрэйме форму, показанную на . (Цветовая схема в Enterprise Server 4.0 будет другой).

Рисунок 3.4    Форма Add Application

Заполните поля в форме Add Application следующим образом:

Name: имя приложения. Это имя идентифицирует URL приложения. Например, имя приложения Hello World это "world," а URL приложения - это http://server.domain/world. Это необходимое поле, и имя, которое Вы запишете, обязано отличаться от имён других приложений на данном сервере. См. .

Web File Path: полное путево&#x0301;е имя web-файла приложения. Это поле необходимо. Например, если сервер Netscape установлен в директории c:\nshome, путь web-файла для приложения Hello World будет

Default Page: страница по умолчанию, которая загружается машиной выполнения JavaScript, если пользователь не специфицировал конкретную страницу в URL. Эта страница аналогична index.html для стандартного URL.

Initial Page: начальная страница, которая выполняется машиной выполнения JavaScript, когда Вы запускаете приложение в Application Manager. Эта страница выполняется точно один раз при запуске приложения. Она обычно используется для инициализации значений, создания блокировок/locks и установления соединения с БД. Любой исходный JavaScript на этой странице не может использовать предопределённые объекты request или client. Это необязательное поле.


Built- in Maximum Database Connections: значение по умолчанию - максимальное количество соединений с БД, которое может иметься в данном приложении в один момент времени через использование предопределённого объекта database. Код JavaScript может переопределить это значение путём вызова метода database.connect.

External Libraries: пути к внешним библиотекам, используемым в приложении. Если Вы специфицируете несколько библиотек, разделите имена запятыми или точкой с запятой. Это поле по выбору/optional. Библиотеки, установленные для одного приложения, могут использоваться всеми приложениями на данном сервере. См. .

Client Object Maintenance: техника, используемая для сохранения свойств объекта client. Это может быть клиентская "кука"/cookie, URL клиента, IP сервера, серверная кука или URL сервера. См. .

После того как Вы предоставили всю требуемую информацию, нажмите Enter для инсталяции приложения, Reset для очистки всех полей или Cancel для отмены операции.

Вы обязаны остановить и рестартовать сервер после добавления или изменения внешних библиотек. Вы можете рестартовать сервер из Server Manager; см. руководство администратора сервера.


Установки для LiveConnect


Чтобы использовать Java-классы в LiveConnect, Вам нужно установить CLASSPATH сервера. Полное описание этой процедуры дано в и в .



Версии JavaScript


Каждая версия Netscape Enterprise Server поддерживает свою версию JavaScript. Чтобы помочь Вам при создании скриптов, совместимых с несколькими версиями Enterprise Server, в этом учебнике используются сокращённые обозначения версий сервера, в которых каждая возможность реализована.

Версия JavaScriptВерсии Enterprise Server

JavaScript 1.2

Netscape Enterprise Server 3.6 (NES 3.6)

JavaScript 1.4

Netscape Enterprise Server 4.0 (NES 4.0)



Visigenic ODBC-Драйвер (только Unix)


При установке сервера он запускается как пользователь: root, nobody или определённый пользователь сервера. Выбранный вами пользователь должен иметь существующую домашнюю директорию, которую, возможно, понадобится создать. Например, домашняя директория по умолчанию для пользователя nobody в системе Irix это /dev/null. Если Вы устанавливаете Ваш сервер в Irix как nobody, Вы обязаны дать пользователю nobody другую домашнюю директорию.

В этой домашней директории обязан находиться файл .odbc.ini. Например, если Вы запускаете сервер как root, этот файл находится в корневой директории (/).

Установите следующие переменные окружения:

LD_LIBRARY_PATH

(Solaris и Irix) Добавьте местонахождение ODBC-библиотек в данную переменную. В предыдущем примере это может быть /u/my-user/odbcsdk/lib.

SHLIB_PATH

(HP-UX) Добавьте местонахождение ODBC-библиотек в данную переменную.

LIBPATH

(AIX) Добавьте местонахождение ODBC-библиотек в данную переменную.

ПРИМЕЧАНИЕ:

Visigenic больше не обновляет свои существующие ODBC--драйверы и SDK. Вместо этого Visigenic избрал INTERSOLV для предоставления обновлённого пути для этих драйверов и продуктов. (См. ). Visigenic будет предоставлять документ, проясняющий операционные различия между ODBC-драйверами Visigenic и INTERSOLV.



Visual JavaScript


Netscape Visual JavaScript это утилита визуальной разработки на базе компонентов для платформы Netscape Open Network Environment (ONE). Он первоначально предназначался для использования разработчиками межплатформенных стандартизованных web-приложений из готовых компонентов с минимальными затратами на программирование. Эти приложения базируются на HTML, JavaScript и Java.

О Visual JavaScript см.

.



Внедрение JavaScript в HTML


Есть два способа встроить операторы серверного JavaScript в HTML-страницу:

Тэгом SERVER.

Используйте этот тэг для размещения в нём одиночного оператора JavaScript или нескольких операторов. Оператор расположен между тэгами <SERVER> и </SERVER>.
Вы можете перемежать тэги SERVER полными операторами HTML. Никогда не помещайте тэг SERVER между открывающей (<) и закрывающей (>) угловыми скобками тэга HTML. (См. ). Также не используйте тэг <SCRIPT> между тэгами <SERVER> и </SERVER>.

С помощью обратной кавычки (`), известной также как тик/tick.

Используйте этот символ для включения выражений JavaScript внутрь тэгов HTML, обычно для генерирования атрибута или значения атрибута HTML на базе значений JavaScript. Эта техника используется внутри таких тэгов, как якоря, изображения или тэги элементов формы, например, для предоставления значения атрибута HREF якоря.

Не используйте обратные кавычки для включения выражений JavaScript вне тэгов HTML. (См. ).

Если Вы внедряете серверный JavaScript в HTML-страницу, машина выполнения JavaScript на сервере выполняет обнаруженные ею операторы при процессинге (обработке) страницы. Большинство операторов выполняют какие-либо операции на сервере, такие как открытие соединения с БД или блокировка совместно используемого объекта. Однако, если Вы используете функцию write в тэге SERVER или заключаете операторы в обратные кавычки, машина выполнения динамически генерирует новый HTML для модифицирования страницы, высылаемой клиенту.



Void


Некоторые методы не возвращают значение. Вы не можете ничего сказать о возможных ошибках в работе этих методов. Следующие методы не возвращают значения:

Connection.release
Cursor.close
database.disconnect
DbPool.disconnect

Resulset.close



Выполнение Хранимой Процедуры


Этот этап применяется ко всем хранимым процедурам.

Для выполнения хранимой процедуры Вы создаёте Stproc -объект, используя метод storedProc объектов database или Connection. Создание такого объекта автоматически вызывает хранимую процедуру. При создании объекта хранимой процедуры Вы специфицируете имя процедуры и любые параметры процедуры.

Например, у Вас есть хранимая процедура newhire, принимающая параметры - строку и целое число. Следующий вызов метода создаёт spObj -объект хранимой процедуры и вызывает хранимую процедуру newhire:

spObj = connobj.storedProc("newhire", "Fred Jones", 1996);

В общем, Вы обязаны предоставить значения для всех параметров ввода/вывода для хранимой процедуры. Если хранимая процедура имеет значение по умолчанию, определённое для одного из её параметров, Вы можете использовать директиву "/Default/" для специфицирования этого значения по умолчанию. Аналогично, если хранимая процедура может принимать null-значение одного из своих параметров, Вы можете специфицировать это null-значение либо директивой "/Null/", либо передав само null-значение.

Например, предположим, хранимая процедура demosp принимает два строковых параметра и один целочисленный. Вы можете предоставить эти параметры таким образом:

spobj = connobj.storedProc("demosp", "Param_1", "Param_2", 1);

Альтернативно, чтобы передать null для второго параметра и использовать значение по умолчанию для третьего параметра, Вы можете использовать один из следующих операторов:

spobj = connobj.storedProc("demosp", "Param_1", "/Null/", "/Default/"); spobj = connobj.storedProc("demosp", "Param_1", null, "/Default/");

ПРИМЕЧАНИЕ:

В Informix значения по умолчанию обязаны появляться только после всех специфицированных значений. Например, Вы не можете использовать /Default/ для второго параметра процедуры, а затем специфицировать значение для третьего параметра.


  Вы можете также использовать директивы "/Default/" и "/Null/" для параметров ввода/вывода.

В Oracle хранимая процедура может принимать ref -курсоры как параметры input/output или как output-параметры. Например, у Вас имеется хранимая процедура Oracle под названием proc1, принимающая 4 параметра: ref -курсор, целочисленное значение, другой ref -курсор и другое целочисленное значение.

Вызов этой хранимой процедуры из SQL Plus может выглядеть так:

execute proc1 (refcursor1, 3, refcursor2, 5);

Однако, если Вы вызываете эту процедуру из приложения JavaScript, Вы не предоставляете ref -курсор-параметры. Вместо этого эквивалент может быть таким:

spobj = connobj.storedProc("proc1", 3, 5);

О параметрах вывода см. Параметры вывода не могут быть null; однако Вы можете присвоить null-значение параметрам ввода или ввода/вывода.

В таблице дано резюме по методам объекта хранимой процедуры.

Метод

Описание


resultSet


Возвращает следующий результирующий набор для хранимой процедуры.

Для Informix Вы можете иметь нуль или более результирующих наборов. Для других БД Вы можете иметь нуль, один или более результирующих наборов.


returnValue


Запрашивает return-значение хранимой процедуры.

Для Informix, DB2 и ODBC этот метод всегда возвращает null.


outParameters


Возвращает специфицированный параметр вывода.

Поскольку хранимые процедуры Informix не используют параметры вывода, не используйте этот метод с Informix.


outParamCount


Возвращает количество параметров вывода.

Для Informix этот метод всегда возвращает 0, поскольку хранимые процедуры Informix не используют параметров вывода.

Выполнение Произвольных Операторов SQL


Метод execute объекта database или объекта Connection даёт приложению возможность выполнять произвольный оператор SQL. Использование execute называется выполнением передаваемого SQL, поскольку этот метод передаёт SQL непосредственно на сервер.

Вы можете использовать execute для выполнения оператора SQL любого языка определения данных/data definition language (DDL) или языка манипулирования данными/data manipulation language (DML), поддерживаемого сервером БД. Примером могут служить операторы CREATE, ALTER и DROP. Хотя Вы можете использовать execute для выполнения любого оператора SQL, Вы не можете с помощью этого метода возвращать данные.

Обратите внимание, что execute служит для выполнения стандартных операторов SQL, а не для выполнения расширений SQL, поставляемых некоторыми производителями БД. Например, Вы не можете вызвать функцию Oracle describe или функцию Informix load из метода execute.

Для выполнения передаваемых операторов SQL просто задайте оператор SQL как параметр метода execute. Например, Вам нужно удалить таблицу из БД, на которую имеется ссылка в свойстве oldtable объекта project. Чтобы выполнить это, Вы можете использовать такой вызов метода:

connobj.execute("DROP TABLE " + project.oldtable);

Важно!

При использовании execute Ваш SQL-оператор обязан строго соответствовать требованиям синтаксиса SQL данного сервера БД. Например, некоторые серверы требуют, чтобы каждый оператор SQL заканчивался символом "точка с запятой". Дополнительно см. документацию к Вашему серверу БД.

Если Вы не стартуете транзакцию явно, единственный оператор подтверждается автоматически. Об управлении транзакциями см. .

Для выполнения некоторых операций, таких как создание и удаление таблиц, Вам могут понадобиться права доступа, предоставляемые администратором базы данных. См. документацию Вашего сервера БД и обратитесь к администратору сервера БД.



Вызов Хранимых Процедур


Хранимые процедуры являются неотъемлемой частью работы с реляционной БД. Они являются средством автоматизации часто выполняемых процессов, но их использование даёт также и некоторые другие преимущества:

Ограничение доступа. Вы можете ограничить доступ к БД, давая пользователям доступ только через хранимые процедуры. Пользователь имеет доступ к данным, но только в пределах хранимой процедуры. Любой другой доступ запрещается.

Целостность данных. Хранимые процедуры создают гарантии правильного ввода и сохранения информации. Автоматизируя сложные транзакции, Вы уменьшите возможность возникновения ошибок по вине пользователя.

Эффективность. Хранимая процедура компилируется только один раз - при выполнении в первый раз. Последующие выполнения проходят быстрее, поскольку фаза компиляции пропускается. Это также помогает уменьшит нагрузку на сеть, так как код хранимой процедуры загружается только один раз.

Сервис LiveWire Database Service предоставляет два класса для работы с хранимыми процедурами: Stproc и Resultset. используя методы этих классов, Вы можете вызывать хранимые процедуры и манипулировать результатами их  работы.



Вызов Окончания Действия Свойств Объекта client


По умолчанию поведение механизма срока действия значений варьируется и зависит от вида используемой техники работы с объектом client, как видно из таблицы.

Для данного вида техники...

Свойства Объекта client...

клиентская кука

Перестают действовать, когда браузер закрывается.

клиентское кодирование URL

Никогда не перестают действовать.

серверная кука

Удаляются из структуры данных на сервере через 10минут. Кука на клиенте перестаёт действовать при выходе из браузера. Свойства объекта client более не доступны, как только структура данных удаляется или браузер закрывается.

серверное кодирование URL

Удаляются из структуры данных на сервере через 10 минут.

серверный IP-адрес

Удаляются из структуры данных на сервере через 10 минут.

Приложение может управлять периодом ожидания JavaScript перед зачисткой свойств объекта client. Для изменения величины этого периода используйте метод expiration, как в следующем примере:

client.expiration(30);

В ответ на это вызов машина выполнения зачищает свойства объекта client по прошествии 30 секунд. Для серверной техники этот вызов заставит сервер удалить свойства объекта из структур данных через 30 секунд. Для этих двух видов техники такой вызов устанавливает окончание срока действия через 30 секунд.

Если объект client перестаёт действовать, когда имеется активный клиентский запрос с использованием этого объекта, машина выполнения ждёт окончания этого запроса, прежде чем уничтожить объект client.

Вы обязаны вызывать expiration на каждой странице, срок окончания действия которой хотите специфицировать. Страницы, не специфицирующие срок действия, используют поведение по умолчанию.



Взаимодействие Java с JavaScript


Если Вам нужно использовать объекты JavaScript в Java, Вы обязаны импортировать пакет netscape.javascript в Ваш Java-файл. Этот пакет определяет следующие классы:

netscape.javascript.JSObject даёт Java-коду доступ к методам и свойствам JavaScript.

netscape.javascript.JSException позволяет Java-коду обрабатывать ошибки JavaScript.

Эти классы поставляются в .jar или .zip-файле. См. в книге дополнительную информацию об этих классах.

Например, в Navigator 4. 0 для Windows NT классы поставляются в файле java40.jar в директории Program\Java\Classes ниже директории Navigator'а. Вы можете специфицировать переменную окружения Windows NT, войдя в Control Panel и создав пользовательскую переменную окружения с названием CLASSPATH со значением типа такого:

D:\Navigator\Program\Java\Classes\java40.jar

Дополнительно о CLASSPATH см. .

Поскольку Java является строго типизированным языком, а JavaScript - слабо типизированным, машина выполнения JavaScript конвертирует значения аргументов в подходящие типы данных другого языка, при использовании LiveConnect. См. .



Взаимодействие JavaScript с Java


Когда Вы обращаетесь к пакету или классу Java или работаете с объектом или массивом Java, Вы используете один из специальных объектов LiveConnect. Доступ JavaScript к Java имеет место в объектах, резюме по которым дано в следующей таблице.

ОбъектОписание

JavaArray

Обёрнутый/wrapped массив Java, доступ к которому выполняется в коде JavaScript.

JavaClass

Ссылка JavaScript на Java-класс.

JavaObject

Обёрнутый объект Java, доступ к которому выполняется в коде JavaScript.

JavaPackage

Ссылка JavaScript на Java-пакет.

ПРИМЕЧАНИЕ:

Поскольку Java является строго типизированным, а JavaScript -слабо типизированным языком, машина выполнения JavaScript конвертирует значения аргументов в соответствующие типы данных тех языков, которые Вы используете с LiveConnect. См. .

Иногда существование объекта LiveConnect прозрачно, поскольку Вы работаете с Java интуитивно. Например, Вы можете создать в Java String -объект и присвоить его переменной JavaScript myString с помощью оператора new в конструкторе Java таким образом:

var myString = new java.lang.String("Hello world")

В предыдущем примере переменная myString это JavaObject, потому что она содержит экземпляр Java String-объекта. Как JavaObject, myString имеет доступ к методам public-экземпляра java.lang.String и его суперкласса java.lang.Object. Эти методы Java доступны в JavaScript как методы JavaObject, и Вы можете вызывать их так:

myString.length() // возвращает 11

Вы имеете доступ к конструкторам, полям и методам класса через тот же синтаксис, который используете в Java. Например, следующий код JavaScript использует свойства объекта request для создания нового экземпляра класса Bug и присвоения затем этого нового экземпляра переменной JavaScript bug. Поскольку Java-класс требует целочисленного значения для первого поля, этот код конвертирует строковое свойство объекта request к целому числу, перед тем как передать его конструктору.

var bug = new Packages.bugbase.Bug(
parseInt(request.bugId),
   request.bugPriority,
   request);



Взаимодействие с Базами Данных


Ваше JavaScript-приложение, запущенное на сервере Netscape Enterprise Server, может использовать LiveWire Database Service для доступа к БД серверов Informix, Oracle, Sybase и DB2 и серверов, использующих стандарт Open Database Connectivity (ODBC). Ваше приложение, запущенное на сервере Netscape FastTrack Server, может получать доступ только к БД на серверах, использующих ODBC.

В последующих обсуждениях предполагается, что Вы уже знакомы реляционными БД и Structured Query Language (SQL).

Прежде чем создать приложение JavaScript с использованием LiveWire, база или базы данных, к которым Вы планируете подключаться, должны уже существовать на сервере БД. Также Вы должны знать их структуру. Если Вы создаёте совершенно новое приложение, включающее БД, необходимо создать БД и заполнить её данными (как минимум в форме прототипа) до создания приложения.

До того как Вы попытаетесь использовать LiveWire, убедитесь, что Ваша рабочая среда сконфигурирована соответственно. О том, как конфигурировать, см. Вы можете также использовать приложение-образец videoapp, описанное в для изучения некоторых возможностей LiveWire.

Обычно для того чтобы взаимодействовать с БД, необходимо выполнить следующие общие действия:

    Использовать объект database или создать объект DbPool для установки пула соединений БД. Это обычно выполняется на начальной странице приложения, если только оно не требует установления специального соединения.

    Подключить пул к БД. Это также обычно выполняется на начальной странице приложения.

    Затребовать соединение из пула. Это выполняется неявно при использовании объекта database или явно - при использовании метода connection объекта DbPool.

    Если Вы изменяете информацию в БД, начинается транзакция. Транзакции БД обсуждаются в разделе .

    Создать курсор или вызывать хранимую процедуру для работы с информацией из БД. Здесь может происходить вывод результатов выполнения запроса или обновление содержимого БД. Закройте открытый курсор, результирующий набор или хранимую процедуру после окончания их использования. Курсоры обсуждаются в разделе ; хранимые процедуры обсуждаются в разделе .

    Подтвердить транзакцию или выполнить откат.

    Освободить соединение с БД (если используете объекты Connection).

В этой главе обсуждаются первые три пункта действий. В , обсуждаются остальные шаги.



Взаимодействие с Реляционной Базой Данных


Сервис LiveWire Database Service даёт возможность взаимодействовать с реляционной БД различными способами.

Вы можете:

Выполнять запросы к БД и заставить машину выполнения автоматически форматировать результаты.

Использовать курсоры для выполнения запросов к БД и представлять результаты в манере приложения или использовать их при вычислениях.

Использовать курсоры для изменения информации в БД.

Использовать транзакции.

Выполнять процессинг SQL без помощи курсоров.

Запускать хранимые процедуры.

Об установке и обслуживании соединений БД см. .



Взгляд на Исходные Файлы


В следующей таблице перечислены исходные файлы приложения Hangman.

hangman.html

Главная страница приложения. Она устанавливается как страница по умолчанию приложения Hangman в Application Manager'е. Она выводится, если пользователь введёт просто hangman в URL без специфицирования страницы.

hangman.js

Файл, содержащий только функции серверного JavaScript, используемые в hangman.html.

youwon.html
youlost.html
thanks.html

Страницы, выводимые, если пользователь победил, проиграл или закончил игру, соответственно.

директория images

Изображения программы , hang0.gif, hang1.gif, и т.д.

rules.html

Содержит текст с пояснениями об игре. Этот файл не компилируется вместе с приложением; он включён как пример неоткомпилированной страницы приложения, являющейся частью того сайта.

Основная логика приложения содержится в файле hangman.html. Базовая логика проста, как три рубля:

    Для новой игры: инициализируется угадываемое слово и другие переменные.

    Если игрок угадал букву, она замещается в вопросе.

    Если игрок не угадал, увеличивается число неудачных попыток.

    Проверяется, победил пользователь или проиграл.

    Прорисовывается текущий вариант изображения с использованием GIF-изображения с учётом неугаданных букв.

Тело/body HTML-файла hangman.html начинается кодом JavaScript в тэге SERVER. Сначала идёт код для инициализации новой игры:

if (client.gameno == null) {
   client.gameno = 1;

   client.newgame = "true";
}if (client.newgame == "true") {
   if (client.gameno % 3 == 1)

         client.word = "LIVEWIRE";

   if (client.gameno % 3 == 2)

      client.word = "NETSCAPE";

   if (client.gameno % 3 == 0)

         client.word = "JAVASCRIPT";

   client.answer = InitAnswer(client.word);
   client.used = "";


   client.num_misses = 0;
}

client.newgame = "false";

Этот код использует объект client для сохранения информации об игроке. Поскольку нет необходимости сохранять статус игры между вызовами разных клиентов, этот код не использует объекты project или server.

Первый оператор определяет, играл игрок до этого, или нет, проверяя существование client.gameno; если нет, код инициализируется в 1 и client.newgame устанавливается в true. Затем некоторая простая логика присваивает "секретное слово" свойству client.word; имеются только три секретных слов, по которым игра проходит по циклу. Свойство client.gameno хранит количество игр, сыгранных конкретным пользователем. Финальная часть инициализации использует InitAnswer, функцию, определённую в файле hangman.js, для инициализации свойства client.answer строкой звёздочек.

Затем идёт блок операторов обработки действий игрока по угадыванию:

if (request.guess != null) {

   request.guess = request.guess.toUpperCase().substring(0,1);

   client.used = client.used + request.guess + " ";

   request.old_answer = client.answer;
   client.answer = Substitute (request.guess, client.word,
      client.answer);

   if (request.old_answer == client.answer)

      client.num_misses = parseInt(client.num_misses) + 1;
}

Оператор if определяет, угадал ли игрок (введя букву в форму). Если да, код вызывает Substitute (другую функцию, определённую в файле hangman.js) для замены угаданной буквы в client.answer. Это постепенно прорисовывает слово в client.answer (например, "N*T**AP*").

Второй оператор if проверяет, было ли изменено свойство client.answer после последнего угадывания; если нет, код увеличивает client.num_misses для отслеживания количества некорректных ответов. Вы обязаны всегда использовать parseInt при работе с целочисленными значениями свойств предопределённого объекта client.



Как видно из следующего кода, последний оператор if в коде JavaScript проверяет, победил игрок или проиграл, и перенаправляет клиента соответственно. Функция redirect открывает специфицированный HTML-файл и передаёт управление в него.

if (client.answer == client.word)
   redirect(addClient("youwon.html"));

else if (client.num_misses > 6)
   redirect(addClient("youlost.html"));

Это конец начального тэга SERVER. Начинается HTML, дополненный выражениями JavaScript. Человек прорисовывается с использованием закавыченных выражений JavaScript внутри HTML-тэга IMG:

<IMG SRC=`"images\hang" + client.num_misses + ".gif"`>

Всё выражение между двумя обратными кавычками (`) это строка JavaScript. Она состоит из строкового литерала "images\hang", соединяемого со значением client.num_misses (которое является целым числом, но хранится как строка), соединяемого со строковым литералом ".gif". Имеются шесть GIF-файлов с изображениями повешенного человечка в различных стадиях: image0.gif, image1.gif и так далее. Выражение JavaScript в кавычках генерирует HTML вида:

<IMG SRC="images\hang0.gif">

Затем идут строки:

<PRE><SERVER>write(client.answer)</SERVER></PRE>

You have used the following letters so far:
<SERVER>write(client.used)</SERVER>

Они выводят значение client.answer (слово, содержащее все правильно угаданные буквы) и все угаданные буквы.

Оставшаяся часть файла это стандартный HTML. Важно отметить, что атрибут ACTION тэга FORM специфицирует файл hangman.html как URL, по которому отправляется форма. Это значит, что при отправке формы страница перезагружается с новыми (специфицированными) значениями формы.

Посмотрим на hangman.js, пример исходного файла, написанного с использование только серверного JavaScript. В нём определены две функции, InitAnswer и Substitute, используемые приложением. Заметьте, что в файлах с серверным JavaScript тэги SERVER не используются.


Взгляд на Исходные Файлы


Исходные HTML-файлы videoapp, перечисленные в следующей таблице, обильно комментируются.

home.htmСтраница по умолчанию. Имеет ссылки на pick.htm, status.htm, rentals.htm, customer.htm и delete.htm. Если нет соединения с БД, эта страница перенаправляет клиента на страницу start.htm.
start.htm Соединяет приложение с БД, стартует транзакцию и переводит обратно на home.htm.
abort.htm Отменяет одну транзакцию и начинает новую.
save.htm Подтверждает/Commits транзакцию и начинает новую.
pick.htmПозволяет потребителю взять клип напрокат. Содержит фрэймы для category.htm, videos.htm и pickmenu.htm.

Файл category.htm показывает категории видео.

Файл videos.htm показывает все видео в выбранной категории и соединён с rent.htm для аренды определённых видео.

Файл pickmenu.htm показывает другие страницы.

status.htm Выводит видео, имеющиеся у потребителя в данный момент. Если потребитель не выбрал ID, перенаправляет его на страницу client.htm, на которой можно выбрать customer ID.
rentals.htm Выводит список всех взятых видео. Когда администратор щёлкает на названии одного их них, выбранная позиция отправляется на return.htm, которая выполняет действия по возвращению видео, затем направляет обратно на rentals.htm.
customer.htm Администратор может ввести здесь нового потребителя. Отправляет введённые в форму данные на add.htm, где выполняются действия по вводу нового потребителя, затем возвращает на customer.htm.
delete.htm Здесь администратор может удалить потребителя. Выводит список потребителей со ссылками на remove.htm, где удаляется специфицированный ряд из таблицы потребителей, затем возвращает на delete.htm.
modify.htmАдминистратор может изменить здесь данные потребителя. Выводит список из первых 5 потребителей со ссылками на страницы modify1.htm и modify2.htm. Эти страницы обновляют специфицированный ряд в таблице потребителей и возвращают обратно на modify.htm. Файл modify3.htm выводит следующих потребителей, 5 за один раз.



Взгляд на Исходный Скрипт


Теперь посмотрим на исходный код JavaScript для данного приложения. Используйте для этого ваш привычный текстовый редактор, откройте файл $NSHOME\js\samples\world\hello.html, где $NSHOME это директория, в которой установлен ваш Netscape-сервер. Файл начинается обычным HTML:

<html>
<head>
<title> Hello World </title> </head>

<body>
<h1> Hello World </h1>

<p>Your IP address is <server>write(request.ip);</server>

Тэги SERVER в нижней строчке содержат код JavaScript, который выполняется на сервере. В данном случае оператор write(request.ip) выводит свойство ip объекта request (IP-адрес клиента, выполнившего доступ к странице). Функция write очень важна в приложениях JavaScript, поскольку используется для дополнения значений выражений JavaScript в HTML-страницу, отправляемую клиенту.

Объект request является частью службы JavaScript Session Management Service. Полное его описание см. в . Функция write это одна из функций JavaScript, которые не ассоциированы со специфическим объектом. О функции write см. раздел .

Далее идут операторы, пока не представляющие для нас интереса. Затем - оператор:

<server> client.oldname = request.newname; </server>

Этот оператор присваивает значение свойства newname объекта request свойству oldname объекта client. Объект client также является частью JavaScript Session Management Service. Его полное описание см. в . Пока просто отметьте, что client может содержать информацию о приложении, специфичную для определённого браузера, запускающего это приложение.

Значение свойства request.newname устанавливается, когда пользователь вводит значение в форме. Далее в файле можно найти такие операторы:

<form method="post" action="hello.html">

<input type="text" name="newname" size="20">

Значением атрибута ACTION формы является hello.html (имя текущего файла). Это означает, что, когда пользователь отправляет форму, щёлкая кнопку Enter или нажимая клавишу Enter, Navigator перезагружает текущую страницу. Вообще, ACTION может быть любая страница приложения JavaScript.


Значением атрибута NAME текстового поля является newname. Когда страница отсылается, этот оператор присваивает то, что пользователь ввёл в текстовом поле, свойству newname объекта request, к которому в JavaScript можно обратиться request.newname. Значения элементов формы всегда соответствуют свойствам объекта request. Свойства объекта request сохраняются только в течение одного (текущего) клиентского запроса.

Несколькими строками ниже находится другой тэг SERVER, указывающий, что следующие строки являются операторами серверного JavaScript. Вот первая группа операторов:

if (client.number == null)

client.number = 0
else
   client.number = 1 + parseInt (client.number, 10)

Данный условный оператор проверяет, инициализировано ли свойство number объекта client. Если нет, код инициализирует его в 0; иначе number увеличивается на 1 с использованием функции JavaScript parseInt, которая конвертирует строковое значение в число. Поскольку предопределённый объект client конвертирует все значения свойств в строки, Вы обязаны использовать parseInt или parseFloat для конвертации этих значений в числа.

Так как number это свойство объекта client, оно отличается для каждого клиента, выполняющего доступ к приложению. Это значение указывает количество раз, когда "you have been here/Вы здесь были."

Для отслеживания общего количества посещений Вы используете объект project, поскольку он совместно используется всеми клиентами, выполняющими доступ к приложению. Свойства объекта project существуют, пока приложение не будет остановлено. Следующая группа операторов отслеживает посещения:

project.lock()
if (project.number == null)

   project.number = 0
else
   project.number = 1 + project.number

project.unlock()

Первый оператор использует метод lock объекта project. Это даёт клиенту временный исключительный доступ к объекту project. Оператор if проверяет, было ли определено свойство project.number. Если нет, код инициализирует его в 0; иначе код увеличивает его на 1. Наконец, метод unlock освобождает объект project, и другие клиенты могут получить к нему доступ.

Последние операторы файла выводят значения свойств client.number и project.number.

<p>You have been here <server>write(client.number);</server> times.
<br>This page has been accessed <server>write(project.number);

</server> times.


Взятие Клипа Напрокат


Страница pick.htm содержит набор фрэймов, где пользователь может взять клип напрокат. Набор фрэймов состоит из страниц category.htm, videos.htm и pickmenu.htm.

Страница category.htm запрашивает в БД список известных категорий клипов. Затем выводит эти категории в виде списка ссылок в таблице левого фрэйма. Если пользователь щёлкает на одной из ссылок, videoapp выводит video.htm в правом фрэйме. Есть несколько интересных моментов, касающихся серверного кода, выполняющего эти задачи. На странице Вы можете найти такие строки:

var userId = unscramble(client.userId)

var bucket = project.sharedConnections.connections[userId]
var connection = bucket.connection

Эти операторы имеются на большинстве страниц videoapp. Они запрашивают соединение из того места, где оно хранится в объекте project. Следующая строка получает новый курсор, применимый для данной задачи:

cursor = connection.cursor("select * from categories");

Вариант этого оператора имеется в начале большинства задач.

Вот следующий интересный набор операторов:

<SERVER>
...
while (cursor.next()) {

   catstr = escape(cursor.category)
</SERVER>

<TR><TD><A HREF=`"videos.htm?category=" + catstr` TARGET="myright">
<SERVER>write(cursor.category);</SERVER></A>

</TD>
</TR>
<SERVER>} // окончание цикла while

Этот цикл создаёт в курсоре ссылку для каждой категории. Обратите особое внимание на оператор:

<A HREF=`"videos.htm?category=" + catstr` TARGET="myright">

Эта строка создаёт ссылку на videos.htm. Она содержит в URL имя категории. Предположим, это категория Comedy. Оператор создаёт такую ссылку:

<A HREF="videos.htm?category=Comedy" TARGET="myright">

Когда пользователь щёлкает на ссылке, сервер переходит на страницу videos.htm и устанавливает значение свойства category

объекта request в Comedy.

Страница videos.htm может обрабатываться из pick.htm или из category.htm. В первом случае свойство category не устанавливается, поэтому страница выводит сообщение, предлагающее пользователю выбрать категорию. Если category правильно установлено, videos.htm входит в БД для вывода информации обо всех клипах данной категории. Эта страница использует ту же технику, что и category.htm, для конструирования информации и создания ссылок на странице rent.htm.

Страница rent.htm фактически записывает взятые пользователем напрокат клипы. Она получает информацию из запроса и обновляет таблицу в БД для отражения новой аренды. Эта страница выполняет обновление, но не подтверждает изменения, пока пользователь не выберет Save Changes или Abort Changes.

Страница pickmenu.htm просто выводит кнопки для возврата на домашнюю страницу или на страницу для добавления нового потребителя.



Web-файл


Скомпилированная форма приложения JavaScript; содержит байт-коды. Обязана быть установлена на Netscape web-сервере, чтобы функционировать.



За Кулисами


Application Manager является удобным интерфейсом для модифицирования файла конфигурации $NSHOME\https-serverID\config\jsa.conf, где $NSHOME это директория, в которой установлен сервер, а serverID это идентификатор ID сервера. В случае фатальной ошибки Вам может потребоваться отредактировать этот файл самостоятельно. Вообще-то это не рекомендуется, но здесь мы даём информацию для такого случая.

Каждая строка файла jsa.conf соответствует приложению. Первый элемент каждой строки это имя приложения. Остальные элементы имеют формат name=value, где name это имя поля установки, а value это значение поля. Возможные значения name:

uri: часть - имя приложения в базовом URL приложения

object: путь к web-файлу приложения

home: страница по умолчанию

start: начальная страница приложения

maxdbconnect: максимальное количество соединений с БД, разрешённое для предопределённого объекта database

library: пути к внешним библиотекам, разделённые запятыми или точкой с запятой

client-mode: техника обслуживания объекта client

Файл jsa.conf имеет ограничение размера в 1024 строки, каждая строка может иметь не более 1024 символов. Если поля, введённые в Application Manager, превосходят этот лимит, строка усекается. Это ведёт обычно к потере последнего элемента, файлов внешних библиотек. Если это произошло, уменьшите количество используемых внешних библиотек и добавьте библиотеки в другие приложения. Поскольку установленные библиотеки доступны всем приложениям, любое приложение может использовать их.

Строка, начинающаяся с #, обозначает комментарий. Такая строка игнорируется. Можно также включать в файл пустые строки.

Не записывайте несколько строк, специфицируя одно и то же имя приложения. Это вызовет ошибки в работе Application Manager'а.



Запись в Файл


Для записи в файл имеются методы write, writeln, writeByte и flush.

Метод write записывает строку в файл. В случае успеха операции возвращает true и false - в ином случае.

fileObj.write(string);

Здесь fileObj это File -объект, в string это строка JavaScript.

Метод writeln записывает сроку в файл и вводит последующие \n (\r\n в текстовом режиме Windows). Возвращает true при успешном выполнении записи и false - в ином случае.

fileObj.writeln(string);

Метод writeByte записывает байт в файл. Возвращает true в случае успеха и false - в противном случае.

fileObj.writeByte(number);

Здесь fileObj это File -объект, а number это число.

Когда Вы используете один из этих методов, содержимое файла внутренне буферизуется. Метод flush записывает буфер в файл на диске. Этот метод возвращает true в случае успеха и false - в противном случае.

fileObj.flush();



Запрашивание Свободного Соединения


Если Ваше приложение запрашивает соединение из объекта DbPool, оно может не получить его. Доступные опции в этот момент зависят от архитектуры Вашего приложения.

Если каждое соединение существует только в период существования отдельного клиентского запроса, недоступность соединений невозможна из-за того, что пользователь оставил приложение в бездействии на значительный период времени. Это может произойти только из-за того, что весь код страницы JavaScript не закончил выполняться. В этом случае Вы не должны пытаться разорвать используемое соединение, чтобы воспользоваться им. Если Вы разорвёте соединение в этот момент, Вы рискуете оставить этот поток выполнения в несоответствующем состоянии. Вместо этого Вы должны удостовериться, что Ваше приложение освобождает каждое соединение по мере завершения его использования. Если Вы не хотите ожидать соединения, Вы должны предоставить пользователю возможность выбора другого варианта.

Если, наоборот, соединение захватывает несколько клиентских запросов, Вы можете захотеть запросить свободные соединения. В этой ситуации соединение может освободиться, поскольку пользователь не завершил транзакцию. Например, предположим, что пользователь отправляет данные на первой странице приложения и эти данные начинают многостраничную транзакцию БД. Вместо отправки данных для продолжения транзакции на следующей странице, пользователь переходит на другой сайт и никогда не вернётся к данному приложению. По умолчанию соединение остаётся открытым и не может использоваться другими клиентами.

Вы можете вручную запросить соединение, зачистив его и освободив в пул БД. Чтобы сделать это, напишите функции типа нижеследующих:

Bucket: Определяет тип объекта (в данном примере - с названием bucket) для содержания соединения и штампа времени.

MarkBucket: Помечает объект bucket штампом текущего времени.

RetrieveConnections: Проходит по массиву соединений в поисках объекта Connection, к которому не было доступа в течение установленного лимита времени, и использует CleanBucket (описан далее) для запрашивания этого объекта.


CleanBucket: Закрывает курсоры (и возможные хранимые процедуры и результирующие наборы), откатывает или подтверждает каждую открытую транзакцию и возвращает соединение в пул.

Ваше приложение может использовать эти функции так:



    Когда Вы получаете новое соединений, вызывайте Bucket для создания объекта bucket.

    На любой странице, получающей доступ к соединению, вызывайте MarkBucket для обновления штампа времени.

    Если приложение делает паузу (таймаут), пытаясь получить соединение их пула, вызывайте RetrieveConnection для поиска незанятых соединений, закройте все открытые курсоры, подтвердите или откатите работающие транзакции и верните незанятые соединения обратно в пул.

    Если соединение было возвращено в пул, попытайтесь получить соединение из пула.


Также на каждой странице, где Ваше приложение использует соединение, необходимо убедиться, что другой поток освободил соединение, до того как данная страница будет достигнута данным клиентом.



Создание Bucket


Функция bucket содержит соединение и штамп времени. Этот образец конструктора функции принимает соединение в качестве единственного параметра:

// Конструктор для Bucket
function Bucket(c)
{
   this.connection = c;
   this.lastModified = new Date();
}

Вы можете вызвать эту функцию для создания bucket для соединения, когда Вы получаете соединение из пула соединений. Вы можете добавить другие свойства для соединения bucket. Например, Ваше приложение может содержать курсор, который захватывает клиентские запросы. Тогда Вы можете использовать свойство для добавления курсора в bucket, так чтобы можно было закрыть открытый курсор при запрашивании соединения. Вы сохраняете курсор в bucket во время его создания, как видно из следующего оператора:

myBucket.openCursor =
   myBucket.connection.cursor("select * from customer", true);


Пометка Объекта Bucket


Функция MarkBucket принимает объект Bucket в качестве параметра и устанавливает в поле lastModified текущее время.



function MarkBucket(bucket)
{
   bucket.lastModified = new Date();
}

Вызывайте MarkBucket на каждой странице приложения, которая использует соединение, содержащееся в bucket. Это восстанавливает в lastModified значение текущей даты и предотвращает появление незанятых соединений.



Запрашивание Старых Соединений


RetrieveConnections сканирует массив объектов Bucket, ищет buckets соединения, штамп времени которых установлен ранее некоторого определённого времени. Если соединение найдено, функция вызывает CleanBucket (описан далее) для возвращения соединения в пул БД.

// Запрашиваются соединения, не занятые в течение специфицированного количества минут.
function RetrieveConnections(BucketArray, timeout)
{
   var i;
   var count = 0;
   var now;

   now = new Date();

   // Этот цикл выполняется для каждого bucket в массиве.

   for (i in BucketArray) {

 // Вычисляется разница во времени между текущей/now и последней/last
 // модифицированной датой. Эта разница выражается в миллисекундах.
// Если она больше значения timeout, вызывается функция зачистки.       if ((now - i.lastModified)/60000) > timeout) {

CleanBucket(i);// Избавляется от bucket, поскольку он больше не используется.

  delete i;count = count + 1;
      }
   }  return count;
}



Зачистка Bucket


После того как определено, что соединение должно быть запрошено (с помощью функции RetrieveConnections), Вам понадобится функция для зачистки подробностей соединения и возврата его обратно в пул базы данных.

Данная функция-образец закрывает открытые курсоры, откатывает открытые транзакции и освобождает соединение.

function CleanBucket(bucket)
{
   bucket.openCursor.close();
   bucket.connection.rollbackTransaction();
   bucket.connection.release();
}

CleanBucket принимает, что данный bucket содержит открытый курсор и его соединение имеет открытую транзакцию. Принимается также, что отсутствуют хранимые процедуры и результирующие наборы. В Вашем приложении может понадобиться и какая-нибудь другая проверка.





Направление Их Всех в Пул


Следующий пример кода использует уже определённые функции для запрашивания соединений, к которым не обращались в течение 10 минут. Сначала создаётся совместно используемый массив соединений и пул БД с 5 соединениями:

if ( project.sharedConns == null ) {
   project.sharedConns = new Object();
   project.sharedConns.pool = new DbPool ("ORACLE", "mydb",
      "user", "password", "", 5, false);
   if ( project.sharedConns.pool.connected() ) {
      project.sharedConns.connections = new Object();
   }else {
      delete project.sharedConns;
   }
}

Теперь используем следующий код для попытки получения соединения. После зачистки пула генерируется клиентский ID, который затем используется как индекс в массиве соединений. Далее пытаемся получить соединение. Если возникает таймаут, вызываем RetrieveConnections для возвращения старого соединения в пул.

Если RetrieveConnections возвращает соединение в пул, пытаемся получить соединение вновь. Если всё ещё не можем получить соединение, выполняется перенаправление на другую страницу с информацией, что свободных соединений нет. Если запрашивается соединение, сохраняем его в новом bucket соединения и сохраняем этот bucket соединения в совместно используемом массиве соединений.

if ( project.sharedConns != null ) {
   var pool = project.sharedConns.pool;   // Этот код запускается, только если пул уже соединён.
   // Если нет, возможно, Вам нужен код для соединения.
   if ( pool.connected() == true ) {

      // Генерируется клиентский ID.

      client.id = ssjs_generateClientID();

      // Попытка получить соединение.

      var connection = pool.connection("my connection", 30);



      // Если соединение null, тогда ничего не будет доступно       // в течение специфицированного лимита времени. Пытаемся запросить старые соединения.
      if (connection == null) {

         // Запрашиваются соединения, не используемые в течение последних 10 минут.

var count = RetrieveConnections(project.sharedConns.connections, 10);

         // Если count не равен 0, делаем какое-нибудь соединение доступным.

if (count != 0){

connection = pool.connection("my connection", 30);

    // Если connection всё ещё null, отказываемся.

      if (connection == null)

        redirect("nofreeconnections.htm");

      }
         else {

            // Отказываемся.

         redirect("nofreeconnections.htm");

       }}

      // Если Вы не дошли досюда, Вы получили соединение и можете продолжить работу.
      // Поместите это connection в новый bucket, стартуйте транзакцию,
      // получайте курсор, сохраняйте его в bucket и продолжайте работу.
      project.sharedConns.connections[client.id] =         new Bucket(connection);

 connection.beginTransaction();

project.sharedConns.connections[client.id].cursor =

connection.cursor("select * from customer", true);      // Помечаем bucket соединения как использованный.

      MarkBucket(project.sharedConns.connections[client.id]);

   // Операторы Базы Данных.
   ...
}

На следующей странице многостраничной транзакции выполняются операции БД по этому соединению. После последней операции БД по соединению помечается bucket соединения:

var Bucket = project.sharedConns.connections[client.id];

if ( Bucket == null) {
   // Повторное соединение.
}else {

   // Взаимодействие с БД.

...   // Последняя операция БД на странице.

   row = Bucket.cursor.next();
   row.customerid = 666;

 Bucket.openCursor.insertRow("customer");   // Помечается bucket соединения как использованный на данной странице.
   MarkBucket(Bucket);
}


Запуск Приложения


После инсталяции и компиляции приложения Вы можете запустить его двумя способами:

Выбрать имя приложения в списке приложений и щёлкнуть Run. Application Manager откроет новое окно Navigator.

Загрузить базовый URL приложения в Navigator, напечатав его в поле Location/Адрес.

Сервер сгенерирует HTML для специфицированной страницы и вышлет его клиенту.



Запуск Videoapp


В этом разделе говорится о запуске приложения videoapp. Это значительно более сложный пример, нежели образцы, рассмотренные в . В этой главе дан только его обзор. Вы должны просмотреть также некоторые файлы, чтобы получше познакомиться с приложением.

После создания видео-БД и изменения параметров соединения с БД Вы можете запустить приложение:

http://server.domain/videoapp

После соединения с БД менеджер Application Manager выводит домашнюю страницу videoapp,

как показано на .

Если соединение с БД невозможно установить, Вы увидите сообщение об ошибке. Убедитесь, что введены корректные параметры соединения с БД, как указано в разделе , приложение рекомпилировано и рестартовало.

Первое, что нужно сделать при установлении соединения, это создать нового потребителя/customer. Пока Вы этого не сделаете, нет ни одного потребителя, который может использовать другие функции приложения.

Вы можете использовать videoapp как customer или как administrator. Как customer Вы можете:

Арендовать клип

Показать все клипы/movies, арендованные Вами

Как administrator Вы можете:

Показать все клипы и тех, кто их арендует

Вернуть video потребителюДобавить нового потребителяУдалить потребителя

Изменить потребителя

Запустите приложения и сделайте несколько выборов для выполнения различных действий.



Защита Application Manager'а


Application Manager предоставляет контроль над приложениями JavaScript. В связи с его особыми возможностями Вы должны защитить его от неавторизованного доступа. Если Вы не ограничиваете доступ к Application Manager'у, любой может добавлять, удалять, изменять, стартовать и останавливать приложения на Вашем сервере. Это, естественно, может привести к нежелательным последствиям.

Вы (разработчик приложений на JavaScript) должны иметь права доступа для использования Application Manager'а на сервере разработчика, так как Вы используете его для работы с приложением при разработке. Администратор Вашего web-сервера, однако, может не предоставить Вам таких прав на сервере разработчика.

Если Вы подключите машину выполнения JavaScript в Server Manager'е, промпт спросит Вас, ограничивать ли доступ к Application Manager'у. Выберите Yes и щёлкните OK. (Yes - по умолчанию.) После этого любой, кто попытается получить доступ к Application Manager'у, обязан будет ввести имя пользователя и пароль Server Manager'а, чтобы получить возможность использовать Application Manager и приложение-образец dbadmin. Дополнительно см. руководство администратора для Вашего web-сервера.

Если Ваш сервер не использует Secure Sockets Layer (SSL), имя пользователя и пароль для Application Manager'а передаются по сети в некодированном виде. Перехватив эти данные, можно получить доступ к Application Manager'у. Если Вы используете тот же самый пароль для Вашего сервера администратора, хакер получит также контроль и над этим сервером. Следовательно, можно рекомендовать не использовать Application Manager вне прокси-сервера, если Вы не используете SSL. О том, как подключить SSL к серверу, см. справочник администратора Вашего web-сервера.



Значения по Умолчанию Формы и Скрытых Элементов Формы


Чтобы отобразить HTML-форму с набором значений по умолчанию в элементах формы, используйте тэг INPUT для создания необходимых элементов формы, замещая выражения серверного JavaScript атрибутов VALUE. Например, Вы можете использовать следующий оператор для отображения элемента text и установки значения по умолчанию на основе значения переменной client.custname:

<INPUT TYPE="text" NAME="customerName" SIZE="30"

VALUE=`client.custname`>

Начальным значением этого текстового поля становится значение переменной client.custname. Так, если значением client.custname является Victoria, клиенту будет выслан такой оператор:

<INPUT TYPE="text" NAME="customerName" SIZE="30" VALUE="Victoria">

Вы может использовать аналогичную технику со скрытыми элементами формы, если не хотите показывать значения пользователю, как в следующем примере:

<INPUT TYPE="hidden" NAME="custID" SIZE=5 VALUE=`client.custID`>

В обоих случаях Вы можете использовать эти значения клиентского JavaScript в значениях свойств объектов, доступных клиенту. Если эти два элемента находятся в форме с именем entryForm, то значения станут свойствами JavaScript document.entryForm.customerName и document.entryForm.custID, соответственно. Вы можете затем выполнять обработку этих значений на стороне клиента. См. также книгу .