Работа со Столбцами
Метод columns класса Cursor возвращает количество столбцов в курсоре. Этот метод не принимает параметров:
custs.columns()
Вы можете использовать этот метод, если нужно итерировать по каждому столбцу курсора.
Метод columnName класса Cursor возвращает имя столбца виртуальной таблицы. Этот метод принимает параметр - целое число, специфицирующее порядковый номер столбца, начиная с 0. Первым столбцом виртуальной таблицы является столбец 0, вторым - столбец 1, и так далее.
Например, следующее выражение присваивает имя первого столбца курсора custs переменной header:
header = custs.columnName(0)
Если Ваш оператор SELECT использует шаблон (*) для выбора всех столбцов таблицы, метод columnName не гарантирует, что порядок присвоения номеров столбцам будет тем же. То есть, предположим, у Вас есть оператор:
custs = connobj.cursor ("select * from customer");
Если таблица customer имеет 3 столбца, ID, NAME и CITY, Вы не сможете заранее предугадать, который из этих столбцов будет custs.columnName(0). (Конечно, есть гарантия, что последовательные вызовы columnName дадут аналогичный результат). Если порядок для Вас важен, можно жёстко кодировать имена в операторе выборки, как здесь:
custs = connobj.cursor ("select ID, NAME, CITY from customer");
В этом операторе, custs.columnName(0) это ID, custs.columnName(1) это NAME, а custs.columnName(2) это CITY.
Регистрация Хранимой Процедуры
Этот этап выполняется только в DB2.
В DB2 имеются различные системные таблицы, в которые Вы можете записать Вашу хранимую процедуру. В общем, вставка хранимой процедуры в эти таблицы не обязательна. Однако, для того чтобы использовать Вашу хранимую процедуру с LiveWire, Вы обязаны создать вхождения в этих таблицах. Этот этап выполняется вне приложения JavaScript.
Для обычного DB2-сервера Вы обязаны создать системную таблицу DB2CLI.PROCEDURES и ввести в неё Ваши DB2-хранимые процедуры. DB2CLI.PROCEDURES это таблица-псевдокаталог.
Если Ваш DB2 предназначен для IBM MVS/EA версии 4.1 или более поздней, Вы обязаны определить имена Ваших хранимых процедур в таблице-каталоге SYSIBM.SYSPROCEDURES.
Не забывайте, что Вы используете C, C++ или другой язык для написания DB2-хранимой процедуры. Типы данных, которые Вы используете в этих языках, не соответствуют типам данных, доступным в DB2. Следовательно, если Вы добавляете хранимую процедуру в DB2CLI.PROCEDURES или в SYSIBM.SYSPROCEDURES, убедитесь, что записаны соответствующие типы данных DB2 для параметров хранимой процедуры, а не типы данных исходных языков.
Информацию о типах данных DB2 и о том, как сделать вхождения в таблицах, см. в документации по DB2.
Регистрация Внешних Функций
Используйте JavaScript-функцию registerCFunction для регистрации внешней функции для использования с приложением JavaScript. Эта функция имеет следующий синтаксис:
registerCFunction(JSFunctionName, libraryPath, CFunctionName);
Здесь JSFunctionName это имя функции как она будет вызываться в JavaScript функцией callC. Параметр libraryPath это полный путь к библиотеке, использующий соглашения Вашей ОС, а параметр CFunctionName это имя C-функции как она определена в библиотеке. В вызове этого метода Вы обязаны вводить имя точно в указанном регистре, указанном в Application Manager, даже в ОС NT.
ПРИМЕЧАНИЕ:
Backslash (\) это специальный символ в JavaScript, поэтому Вы обязаны использовать forward slash (/) или двойной backslash (\\) для отделения Windows-директории и имён файлов в libraryPath.
Данная функция возвращает true, если функция зарегистрирована успешно, и false - в ином случае. Функция может потерпеть неудачу, если JavaScript не сможет найти библиотеку по специфицированному пути или не найдёт специфицированную функцию в библиотеке.
Приложение обязано использовать registerCFunction для регистрации функции, прежде чем сможет использовать callC для её вызова. После того как приложение зарегистрировало функцию, оно может вызывать эту функцию любое число раз. Хорошим местом для регистрации функций является начальная страница приложения.
Рекомендации по Написанию Внешних Функций
Хотя Вы можете написать внешние библиотеки на любом языке, JavaScript использует соглашения языка C по вызову. Ваш код обязан подключать header-файл jsaccall.h, находящийся в директории js\samples\jsaccall\.
Эта директория также содержит исходный код примеров приложений, которые вызывают функции C, определённые в jsaccall.c. Просмотрите эти файлы, чтобы найти более конкретные рекомендации по написанию функций C для использования с JavaScript.
Функции, вызываемые из JavaScript, обязаны быть экспортируемыми и обязаны соответствовать этому определению типа:
typedef void (*LivewireUserCFunction)
(int argc, struct LivewireCCallData argv[],
struct LivewireCCallData* result, pblock* pb,
Session* sn, Request* rq);
Return-Значения
Как и вызов функции, хранимая процедура может иметь возвращаемое/return значение. Для Oracle и Sybase это return-значение является дополнением к возвращаемому результирующему набору.
Метод returnValue класса Stproc используется для доступа к return-значению. Однако return-значения для хранимой процедуры Informix используются для генерации её результирующего набора. Поэтому returnValue всегда возвращает null для хранимых процедур Informix. Помимо этого, return-значения недоступны для хранимых процедур ODBC и DB2.
Return-значение методов объектов LiveWire может указывать, имеется ошибка или нет. Методы могут возвращать значения различных типов. В зависимости от типа Вы можете получать различную информацию о возможных ошибках.
Результирующие Наборы
Хранимая процедура может выполнять один или более операторов SELECT, запрашивая информацию из БД. Вы можете представить эту информацию как виртуальную таблицу, очень похожую на курсор "только для чтения". (О курсорах см. раздел ).
LiveWire использует класс Resultset как контейнер рядов, возвращаемых одним оператором SELECT хранимой процедуры. Если хранимая процедура допускает наличие нескольких операторов SELECT, Вы получите отдельные объекты Resultset для каждого оператора SELECT. Метод resultSet класса Stproc используется для получения результирующего набора объектов, а затем методы этих объектов используются для манипулирования результирующим набором.
БД различных производителей возвращают результирующий набор по-разному:
Хранимые процедуры Sybase могут напрямую возвращать результат выполнения одного или более операторов SELECT.
Хранимые процедуры Informix могут иметь несколько return-значений. Несколько return-значений подобны столбцам одного ряда таблицы, за исключение того, что эти столбцы именованы. Кроме того, если Вы используете возможность RESUME, хранимая процедура может иметь набор этих return-значений. Это набор напоминает ряды таблицы. LiveWire создаёт один результирующий набор для вмещения этой виртуальной таблицы.Хранимые процедуры Oracle используют ref-курсоры для вмещения рядов, возвращаемых оператором SELECT. Вы можете открыть несколько ref-курсоров в хранимой процедуре Oracle, чтобы вместить ряды , возвращаемые разными операторами SELECT. LiveWire создаёт отдельные Resultset -объекты для каждого ref-курсора.
Хранимые процедуры DB2 используют открытые курсоры для возвращения результирующих наборов.
Roll back/откат
Отмена всех акций в БД в пределах выполнения одной транзакции.
Сбор Мусора
Серверный JavaScript имеет сборщика мусора, который автоматически освобождает память, выделенную для объекта, более не используемого. В большинстве случаев нет необходимости понимать досконально работу сборщика мусора. Этот раздел даёт обзор сборщика мусора и информацию о том, когда он вызывается.
Важно!
Этот раздел даёт возможность продвинутым пользователям взглянуть на внутренние процессы JavaScript. Netscape не гарантирует, что эти алгоритмы останутся такими же в последующих релизах.
Пространство объекта в JavaScript состоит из арен. То есть машина выполнения JavaScript размещает набор арен, из которого затем размещает объекты. Если машина выполнения получает запрос на новый объект, она сначала просматривает список свободных арен. Если в списке свободных есть место, машина выделяет его. Иначе машина выполнения выделяет место в текущей используемой арене. Если используются все арены, машина размещает новую арену. Если все объекты арены - мусор, сборщик мусора освобождает арену.
Строка JavaScript обычно размещается как GC-объект. Строка имеет ссылку на байты строки, которая также размещается в куче/heap процесса. Если строковой объект подвергся сборке мусора, байты строки высвобождаются.
Работа сборщика мусора JavaScript основана на пометке и уничтожении. Сборщик не перемещает объекты. Он всегда обрабатывает корневой набор объектов. Этот корневой набор/root set включает в себя стэк JavaScript, объект global для контекста JavaScript и любые объекты JavaScript, которые были явно добавлены в корневой набор. В фазе разметки сборщик мусора помечает все объекты, достижимые из корневого набора. В конечной фазе все непомеченные объекты уничтожаются. Все убранные объекты собираются в список свободных.
Сборка мусора считается необходимой, если количество текущих используемых байтов в 1.5 раза превышает количество байтов, бывших в использовании в конце последней уборки мусора. Машина выполнения проверяет это условие в следующих точках и начинает уборку, если это необходимо:
В конце каждого запроса.
Во время длительных вычислений JavaScript после предопределённого количества выполненных операций с байт-кодами JavaScript и только когда выполняется операция ветвления. Если у Вас код без операций ветвления, сбор мусора не происходит просто оттого, что выполняется предопределённое количество операций. (Операция ветвления/branch может быть в операторах if, while, вызове функции и т.п.).Когда делается попытка разместить новый объект JavaScript, но в JavaScript нет свободной памяти и дополнительная память не может быть получена от операционной системы.
Если вызывается функция lw_ForceGarbageCollection.
Server cookie/серверная кука
Один из видов техники JavaScript для обслуживания объекта client, когда сервер генерирует уникальное имя для клиента, сохраняемое в cookie-файле на стороне клиента и позднее использует сохранённое имя для обращения к структуре данных, содержащей значения свойств объекта client.
Server-side JavaScript/серверный JavaScript
Ядро JavaScript плюс расширения, относящиеся только к работе JavaScript на сервере. Например, серверные расширения дают приложению возможность соединяться с реляционной БД, сохранять непрерывность информации от одного вызова приложения до другого или выполнять манипуляции с файлами на сервере. См. также , .
Server URL encoding/серверная кодировка URL
Один из видов техники JavaScript для обслуживания объекта client, когда сервер генерирует для клиента уникальное имя, присоединяет его к URL и позднее использует сохранённое имя для обращения к структуре данных, содержащей значения свойств объекта client.
Серверная Техника
Есть три вида серверной техники:
IP-адресаСерверные куки
Серверное кодирование URL
Сравнение разных видов техники см. в разделе .
При любом виде техники машина выполнения на сервере сохраняет свойства объекта client и их значения в структуре данных в памяти сервера. Единая структура данных, сохраняемая в период между клиентскими запросами, используется для всех приложений, работающих на сервере. Виды техники различаются только в индексе, используемом для доступа к информации в этой структуре данных, гарантируя, что каждая пара клиент/приложение получает соответствующие свойства и значения для объекта client.
Ни одна из этих техник не записывает информацию на жёсткий диск сервера. Только техника серверных кук позволяет записывать информацию на диск клиентской машины при окончании работы браузера.
Поскольку эти виды техники сохраняют информацию объектов client в памяти сервера в промежутке между клиентскими запросами, нет или почти нет увеличения сетевого трафика. Имена и значения свойств никогда не пересылаются клиенту. Кроме того нет ограничения на количество свойств объекта client и на размер свойства.
Недостатком является, разумеется, то, что эти виды техники используют память сервера в промежутке между клиентскими запросами. Для приложений, используемых большим количеством потребителей, это может иметь важное значение. Конечно, это можно также рассматривать и как преимущество, так как Вы можете сохранять столько информации, сколько необходимо.
Серверный JavaScript
На сервере Вы также можете внедрять JavaScript в HTML-страницы. Серверные операторы могут соединяться с реляционными БД разных производителей, разделять информацию между пользователями приложения, получать доступ к файловой системе сервера или взаимодействовать с другими приложениями через LiveConnect и Java. HTML-страницы с серверным JavaScript могут содержать также клиентский JavaScript.
В отличие от страниц с чисто клиентским JavaScript, HTML-страницы, использующие серверный JavaScript, компилируются в байт-кодовые исполняемые файлы. Эти исполняемые приложения запускаются на выполнение web-сервером, имеющим машину времени выполнения JavaScript. Исходя из этого, создание приложений JavaScript это процесс из двух этапов.
На первом этапе, показанном на , Вы создаёте HTML-страницы (которые могут содержать операторы как клиентского, так и серверного JavaScript) и файлы JavaScript. Затем Вы компилируете все эти файлы в единый исполняемый блок.
Рисунок 1.3 Серверный JavaScript в процессе разработки
![](image/servernyj-javascript_1.gif)
На втором этапе, показанном на , страница приложения запрашивается клиентским браузером. Машина выполнения использует исполняемый блок для просмотра исходной страницы и динамической генерации HTML-страницы, возвращаемой клиенту. Она выполняет все найденные на странице операторы серверного JavaScript. Выполнение этих операторов может добавить новые операторы HTML или операторы клиентского JavaScript в HTML-страницу. Машина выполнения отсылает затем окончательный вариант страницы по сети Navigator-клиенту, который выполняет клиентский JavaScript и отображает результат.
Рисунок 1.4 Серверный JavaScript в процессе выполнения
![](image/servernyj-javascript_2.gif)
В отличие от стандартных программ Common Gateway Interface (CGI), все исходники JavaScript интегрированы непосредственно в HTML-страницы, ускоряя разработку и облегчая обслуживание. Служба Session Management Service серверного JavaScript содержит объекты, которые Вы можете использовать для работы с данными, существующими между клиентскими запросами, у нескольких клиентов или нескольких приложений. Служба LiveWire Database Service серверного JavaScript предоставляет объекты для доступа к БД, служащие интерфейсом для серверов Structured Query Language (SQL).
Серверный JavaScript 1.4. Руководство по Использованию.
Перевод выполнил Александр Пирамидин.
Прошу все замечания и предложения направлять по e-mail:
В этой книге рассматривается использование ядра и серверного JavaScript версии 1.4. JavaScript это созданный фирмой Netscape межплатформенный объектно-ориентированный язык скриптов (сценариев) для клиентских и серверных приложений.
Серверный Язык. Обзор.
И клиентский, и серверный JavaScript реализуют язык JavaScript. Но каждый при этом добавляет специфические объекты и функции для работы в клиентской или серверной среде. Например, клиентский JavaScript включает объект form для представления формы на HTML-странице, а серверный JavaScript включает объект database для соединения с внешней реляционной БД.
В книге
Клиентский JavaScript. Руководство. детально рассматривается ядро языка JavaScript и дополнительная специфика клиентского JavaScript.
ECMA, Европейская организация стандартизации систем информации и коммуникаций, выпустила стандарт ECMA-262 языка JavaScript. Вы можете загрузить эту спецификацию с сайта ECMA по адресу .
Session Management Service/Служба Обслуживания Сессий
4 предопределённых объекта JavaScript - request, client, project и server - и один класс, Lock, предоставляющие основу для совместного использования данных запросами, клиентами и приложениями.
Создание объекта request и конструирование или восстановление объекта client
Инициализируются встроенные свойства объекта request, такие как IP-адрес и элементы формы, ассоциированные с данным request. Если URL запроса специфицирует другие свойства, они инициализируются для объекта request, как описано в разделе .
Если объект client уже существует, машина выполнения запрашивает его на основе специфицированной техники обслуживания клиента. (См. ). Если объект client не существует, машина выполнения конструирует новый объект без свойств.
Вы не можете предвидеть, в каком порядке эти объекты конструируются.
Поиск исходной страницы и начало конструирования HTML-страницы
Когда Вы компилировали исходный код JavaScript, исходник включал HTML-страницы с операторами серверного JavaScript. Главной задачей машины выполнения является конструирование из одной из этих исходных страниц HTML-страницы, содержащей только HTML и операторы клиентского JavaScript. При создании этой HTML-страницы машина выполнения сохраняет её части в области памяти, называемой буфером, пока не придёт время отправки буферизованного содержимого клиенту.
Добавить в буфер вывода или выполнить код
Этот шаг выполняется для каждого участка кода исходной страницы. Детали процесса выполнения различных серверных операторов рассматриваются далее в этом учебнике. Дополнительно см. .
Для данного запроса/request машина выполнения выполняет этот шаг, пока не произойдёт одно из следующих событий:
Буфер содержит 64KB HTML.
В этой ситуации машина выполняет шаги 4 и 5 и возвращается к выполнению шага 3 с очищенным буфером, продолжая выполнение того же запроса. (Шаг 4 исполняется только один раз, даже если шаги 3 и 5 повторяются).
Сервер выполняет функцию flush.
В этой ситуации машина выполняет шаги 4 и 5 и возвращается к выполнению шага 3 с очищенным буфером, продолжая выполнять тот же самый запрос. (Шаг 4 исполняется только один раз, даже если шаги 3 и 5 повторяются).
Сервер выполняет функцию redirect.
В этой ситуации машина выполнения завершает данный запрос, выполняя шаги с 4 по 6. Она игнорирует любые вхождения после функции redirect в исходном файле и стартует новый запрос для страницы, специфицированной в вызове redirect.
Доходит до конца страницы.
В этой ситуации машина завершает данный запрос, выполняя шаги с 4 по 6.
Сохранение свойств объекта client
Машина выполнения сохраняет свойства объекта client непосредственно перед первой отправкой части HTML-страницы клиенту. Она сохраняет эти свойства только один раз. Машина выполнения может повторять шаги 3 и 5, но не может повторить данный шаг.
Машина выполнения сохраняет свойства в этот момент, чтобы поддерживать один из видов техники обслуживания объекта client. Например, схема кодирования клиентского URL высылает свойства client'а в шапке/header HTML-файла. Поскольку шапка высылается как первая часть файла, свойства client'а обязаны быть затем высланы.
Следовательно, Вы должны учитывать, где в Вашем файле-источнике устанавливаются свойства client'а. Вы всегда должны изменять свойства client'а в файле до любого вызова redirect или flush и до генерирования 64KB HTML-вывода.
Если Вы изменяете значения свойств объекта client в коде после того как HTML был выслан клиенту, эти изменения будут действовать для оставшейся части клиентского запроса, но затем будут отменены. Отсюда: следующий клиентский запрос не получит эти значения свойств; он получит значения, действовавшие в тот момент, когда содержимое было в первый раз отправлено клиенту. Например, ваш код содержит такие операторы:
<HTML>
<P>The current customer is
<SERVER>
client.customerName = "Mr. Ed";
write(client.customerName);
client.customerName = "Mr. Bill";
</SERVER><P>The current customer really is
<SERVER>
write(client.customerName);
</SERVER>
</HTML>
Эта серия операторов даст в результате такой HTML, отправляемый клиенту:
<P>The current customer is Mr. Ed
<P>The current customer really is Mr. Bill
Теперь, когда появится следующий клиентский запрос, значение свойства client.customerName будет "Mr. Bill". Этот очень похожий набор операторов даст в результате тот же HTML:
<HTML>
<P>The current customer is
<SERVER>
client.customerName = "Mr. Ed";
write(client.customerName);
flush();
client.customerName = "Mr. Bill";
</SERVER>
<P>The current customer really is
<SERVER>
write(client.customerName);
</SERVER>
</HTML>
Однако при появлении следующего клиентского запроса значение client.customerName будет "Mr. Ed"; а не "Mr. Bill".
Дополнительно см. .
Отправка HTML клиенту
Сервер отсылает содержимое страницы клиенту. Для страниц без операторов серверного JavaScript сервер просто передаёт HTML клиенту. Для других страниц - машина выполнения реализует логику приложения для конструирования HTML и затем высылает сгенерированную страницу клиенту.
Уничтожение объекта request и сохранение или уничтожение объекта client
Машина выполнения разрушает объект request, сконструированный для данного клиентского запроса. Она сохраняет значения объекта client и разрушает физический объект JavaScript. Она не разрушает объекты project или server.
Шапка/Header Ответа
Если отправляемый клиенту ответ/response использует специальный content type (тип содержимого), Вы должны кодировать этот content type в шапке ответа. Машина выполнения JavaScript автоматически добавляет content type по умолчанию (text/html) в шапку ответа/response header. Если вам необходима специальная шапка, Вы обязаны сначала удалить из шапки старый content type по умолчанию, а затем уже добавить новый. Это делается при помощи функций addResponseHeader и deleteResponseHeader.
Например, если Ваш response использует royalairways-format как специальный content type, Вы можете специфицировать его так:
deleteResponseHeader("content-type");
addResponseHeader("content-type","royalairways-format");
Вы можете использовать функцию addResponseHeader для добавления в шапку ответа любой другой нужной информации.
Важно!
Помните, что header отсылается с первой частью ответа/response. Следовательно, Вы должны вызывать эти функции раньше в скрипте на каждой странице. В общем, Вы должны быть уверены, что header ответа установлен до любого из следующих событий:
Машина выполнения сгенерировала 64KB содержимого для HTML-страницы (в этой точке буфер вывода автоматически очищается).
Вы вызываете функцию flush для очистки буфера вывода.
Вы вызываете функцию redirect для изменения клиентских запросов.
Дополнительно см. разделы и .
1
Шапка/Header Запроса
Для доступа к парам имя/значение шапки клиентского запроса используйте метод httpHeader объекта request. Этот метод возвращает объект, чьи свойства и значения соответствуют парам имя/значение шапки.
Например, если запрос содержит куки, header["cookie"] или header.cookie будет его значением. Свойство cookie, содержащее все пары имя/значение этой куки (со значениями, кодированными так, как описано в разделе ), обязано разбираться Вашим приложением.
Следующий код выводит свойства и значения шапки:
var header = request.httpHeader();
var count = 0;
var i;
for (i in header ) {
write(count + ". " + i + " " + header[i] + "<br>\n");
count++;
}
Если Вы отправили форму методом GET, на выходе получится примерно так:
0. connection Keep-Alive
1. user-agent Mozilla/4.0b1 (WinNT; I)
2. host piccolo:2020
3. accept image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Если для отправки формы использован метод POST, вывод будет таким:
0. referer http://piccolo:2020/world/hello.html
1. connection Keep-Alive
2. user-agent Mozilla/4.0b1 (WinNT; I)
3. host piccolo:2020
4. accept image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
5. cookie NETSCAPE_LIVEWIRE.oldname=undefined; NETSCAPE_LIVEWIRE.number=0
6. content-type multipart/form-data; boundary=---------------------------79741602416605
7. content-length 208
Системные Требования
Чтобы разрабатывать приложения JavaScript, использующие преимущества и клиентского, и серверного JavaScript, Вам нужна подходящая среда для разработки и публикации. В целом рекомендуется разрабатывать приложения на системе, отделённой от сервера публикации, поскольку разработка потребляет много ресурсов (порты соединений, пропускная способность, время процессора и память). При разработке также может быть нарушена работа уже опубликованных приложений конечного пользователя.
Среда разработки JavaScript состоит из:
Утилит для авторизации и компиляции приложений JavaScript. Эти утилиты обычно находятся на машине разработчика.
Машины разработчика с web-сервером для запуска приложений JavaScript, находящихся в стадии разработки. Машины публикации с web-сервером для публикации разработанных приложений. Конечные пользователи осуществляют доступ к приложениям, находящимся на этом сервере.
Необходимые утилиты:
Браузер с возможностью выполнения JavaScript, такой как Netscape Navigator, входящий в состав Netscape Communicator.
Компилятор приложений JavaScript, такой как компилятор web-серверов Netscape.
Редактор, такой как Emacs или Notepad.
Публикация и машины публикации требуют наличия следующего программного обеспечения:
Web-сервера;
Машины выполнения JavaScript, такой как машина web-серверов Netscape.
Возможности конфигурирования Вашего сервера для работы приложений JavaScript, как это сделано в JavaScript Application Manager, поставляемом вместе с web-серверами Netscape.
Кроме того, если ваше приложение использует JavaScript-службу LiveWire Database Service, Вам понадобится:
Программа - сервер реляционных БД на Вашей машине-сервере БД. См. документацию вашего сервера БД. В некоторых случаях Вам понадобится установить web-сервер и сервер БД на одной машине. О специфических требованиях серверного JavaScript см. Клиент БД и сетевое программное обеспечение на машине Вашего web-сервера. Если Вы используете одну машину и как сервер БД, и как web-сервер, типичное клиентское обеспечение БД как правило уже установлено при установке сервера БД. В противном случае Вам нужно удостовериться, что клиент БД установлен на той же машине, что и web-сервер, чтобы можно было иметь доступ к БД как клиент. О требованиях к клиентскому программному обеспечению см. дополнительно документацию поставщика БД.
Словарь
Здесь определены термины, используемые в приложениях JavaScript.
Служба Файловой Системы
JavaScript предоставляет класс File, который даёт приложению возможность записывать в файловой системе сервера. Это используется для генерации постоянных HTML-файлов и хранения информации без использования сервера БД. Одним из важнейших преимуществ хранения информации в файле вместо JavaScript-объектов является то, что информация сохраняется даже при отказе сервера.
Соединение и Процесс Работы
Когда пользователь инициирует сессию с приложением videoapp, входя на начальную страницу (home.htm), videoapp проверяет, имеется ли уже соединение с БД. Если это так, videoapp предполагает, что не только приложение, но и пользователь уже соединены с БД, и продолжает работу.
Если соединение не установлено, videoapp перенаправляет на страницу start.htm. На ней приложение создаёт единый пул соединений с БД, используемый всеми потребителями, получает соединение для пользователя и стартует транзакцию с БД для этого соединения. Затем перенаправляет обратно на home.htm для продолжения. Пользователь никогда не видит перенаправления.
Транзакция базы данных стартует на странице start.htm и остаётся открытой, пока пользователь явно не сохранит или не отменит изменения, щёлкнув кнопку Save Changes или Abort Changes. При этом запускается save.htm или abort.htm. Эти страницы подтверждают или откатывают изменения открытой транзакции, а затем немедленно начинают новую транзакцию. Поэтому соединение потребителя всегда остаётся открытым.
Получив соединение с БД, videoapp выводит пользователю главную страницу. С неё пользователь может сделать выбор - такой как аренда клипа или добавление нового потребителя. Каждая из этих опций выводит разные страницы, которые содержат операторы серверного JavaScript. Многие страницы имеют операторы, использующие соединение для взаимодействия с БД, выводя информацию или внося изменения в БД.
Первое, что Вы обязаны сделать при первом соединении, это добавить нового потребителя. Пока Вы этого не сделаете, отсутствуют потребители для выполнения других действий программы.
Соединение. Подходы.
Есть два основных способа соединения с БД с помощью сервиса LiveWire Database Service. Это объекты DbPool и Connection, либо объект database.
Соединение с БД и Рекомпиляция
Приложение videoapp находится в директории $NSHOME\js\samples\videoapp, где $NSHOME это директория установки Netscape-сервера. Приложение oldvideo находится в директории $NSHOME\js\samples\oldvideo.
Для каждого приложения Вы обязаны изменить строку с информацией о соединении в исходном HTML-файле start.htm, чтобы настроиться на среду окружения Вашей БД. О параметрах соединения см. раздел ; дополнительно см. также описание метода connect в книге
.
Для приложения videoapp измените эту строку:
project.sharedConnections.pool =
new DbPool ("<Server Type>", "<Server Identifier>", "<User>", "<Password>", "<Database>", 2, false)
Для приложения oldvideo измените эту строку:
database.connect ("INFORMIX", "yourserver", "informix", "informix", "lw_video")
Сохраните изменения и рекомпилируйте приложение. Для рекомпиляции приложения из командной строки запустите его build-файл, расположенный в директории приложения. Убедитесь, что переменная окружения PATH содержит путь к компилятору (обычно это $NSHOME\bin\https).
Рестартуйте приложения в JavaScript Application Manager'е.
Соединение с Объектом database
При этом подходе Вы используете предопределённый объект database для соединения с БД при наличии единственной конфигурации соединения БД и пользователя. Объект database выполняет все действия по работе с БД. Можно представить этот объект как database единый пул соединений с БД.
Этот подход несколько проще, так как используется только один объект database, а не несколько объектов DbPool и Connection. Однако при этом теряется гибкость первого подхода. Если Вы используете только объект database и хотите соединиться с разными БД или разными бюджетами, Вы обязаны отключиться от одной конфигурации, для того чтобы подключиться к другой. Также, при использовании объекта database, одна транзакция не может захватить несколько клиентских запросов, а соединения с несколькими БД-источниками не могут быть установлены одновременно.
Как описано в последующих разделах, Вы должны ответить на два основных вопроса, когда решаете, как устанавливать соединения с БД:
Сколько конфигураций и соединений БД и пользователей Вам нужно?
Будет ли одно соединение захватывать несколько клиентских запросов?
В таблице резюмируется, как ответ на эти вопросы влияет на установку и обслуживание пула соединений с БД и отдельных соединений. В последующих разделах обсуждаются детали этих вариантов.
1, используется всеми клиентами | Начальная страница приложения | Нигде | database | Нет | -- | ||||||
1, используется всеми клиентами | Начальная страница приложения | Нигде | 1 DbPool object | Да | DbPool: Именованное свойство;
Connection: 1 массив | ||||||
Фиксированный набор, используется всеми клиентами | Начальная страница приложения | Нигде | N DbPool-объектов | Да | DbPool: Именованное свойство;
Connection: N массивов | ||||||
Отдельный пул для каждого клиента | Клиентская страница запроса | Зависит от Многие объекты DbPool | Только если соединение захватывает клиентские запросы | DbPool: 1 массив;
Connection: 1 массив |
1
Если отдельное соединение не захватывает клиентские запросы, Вы можете соединять и отсоединять пул на каждой странице, в которой нужнó соединение. В этом случае пул не сохраняется в промежутке времени между запросами. Если отдельное соединение захватывает клиентские запросы, соединяйте на первой клиентской странице, которой необходимо соединение, и отсоединяйте на последней такой странице. Это может привести к появлению незанятых соединений/idle, и Ваше приложение должно будет обработать такую ситуацию. |
Соединение с Помощью Объектов DbPool и Connection
При этом подходе Вы создаёте пул соединений для работы с реляционной БД. Вы создаёте экземпляр класса DbPool,а затем получаете доступ к объектам Connection через этот объект DbPool. Объекты DbPool и Connection распределяют между собой работу по соединению с БД и обслуживанию набора соединений и доступ к БД через соединение.
Это весьма гибкий подход. Ваше приложение может иметь несколько пулов соединений, каждый со своей собственной конфигурацией БД и пользователя. Каждый пул может иметь несколько соединений при такой конфигурации. Это даёт одновременный доступ к нескольким БД или к одной БД из нескольких бюджетов. Вы можете также ассоциировать пул непосредственно с приложением, а не с отдельным клиентским запросом, и иметь таким образом транзакции, захватывающие несколько клиентских запросов. Это ассоциирование выполняется путём присвоения пула свойству объекта project и удаления этого присвоения после окончания работы с пулом.
Соглашения по Документам
Приложения JavaScript работают на многих операционных системах; данная информация применима ко всем версиям. Пути файлов и директорий даны в формате Windows (с обратной наклонной чертой в качестве разделителя имён директорий). Для Unix-версий пути директорий - те же, за исключением того, что в качестве разделителей используются слэши вместо backslash.
В этой книге используются uniform resource locators (URLs) в форме:
http://server.domain/path/file.html
В этих URL server это имя сервера, на котором запускается Ваше приложение, как, например, research1 или www; domain это имя домена Internet, такое как netscape.com или uiuc.edu; path это структура директорий на сервере; а file.html это имя файла. В целом элементы, выделенные italic в URL, являются заглушками, а элементы с нормальным моноширинным шрифтом являются литералами. Если на Вашем сервере имеется Secure Sockets Layer (SSL), Вы должны использовать https вместо http в URL.
В книге использованы следующие соглашения по шрифтам:
Моноширинный шрифт используется в примерах кода, API и элементах языка (таких как имена функций и классов), именах файлов, путях, именах директорий, тэгах HTML и в любом тексте, который должен выводиться на экран монитора. (Моноширинный italic используется для заглушек, вставленных в код.)Italic-шрифт
используется в названиях книг, при выделении текста, в переменных и заглушках и в словах, используемых в литеральном смысле.
Жирный шрифт используется в терминах словаря.
Дата последнего обновления: 29 сентября 1999 г.
© Copyright © 1999 Sun Microsystems, Inc. Некоторая часть Copyright © 1999 Netscape Communications Corp. Все Права Зарезервированы.
Сообщение Между Сервером и Клиентом
Нередко Вашим приложениям JavaScript нужно передать информацию либо с сервера клиенту, либо с клиента на сервер. Например, когда пользователь в первый раз выполняет доступ к приложению videoapp, оно динамически генерирует список категорий видео-файлов из текущего содержимого БД. Эта информация, генерируемая на сервере, должна быть передана обратно клиенту. И наоборот, когда пользователь щёлкает на категории из этого списка, выбор пользователя должен быть передан обратно на сервер, чтобы он мог сгенерировать набор файлов.
Соотношение Между Версиями JavaScript и ECMA
Netscape тесно сотрудничает с ECMA для создания спецификации ECMA.
Детальную информацию о соотношении версий спецификаций JavaScript и ECMA см. на сайте mozilla.org.
JavaScript всегда будет содержать возможности, не включённые в спецификацию ECMA; JavaScript совместим с ECMA, предоставляя дополнительные возможности.
Эти указания являются критичными для
Эти указания являются критичными для однопоточного доступа. Однако Вы должны думать об этом даже тогда, когда используете БД с многопоточным доступом.
Однопоточная библиотека БД может иметь существенные ограничения производительности. Поскольку только один поток имеет доступ к БД в единицу времени, все прочие потоки обязаны ждать, когда первый поток освободит соединение с БД, прежде чем один из них сможет получить доступ к БД. Если доступа ожидают одновременно несколько потоков, каждому придётся ожидать довольно долго.
При разработке доступа к БД Вы должны предусмотреть следующее:
Старайтесь максимально сократить взаимодействие с БД.
Каждый поток обязан ждать окончания работы другого потока. Чем короче время взаимодействия с БД, тем меньше ожидание.
Всегда освобождайте соединение сразу и закрывайте открытые курсоры и хранимые процедуры.
Вы должны делать это в любом случае. Но в случае с однопоточной БД это становится абсолютно необходимым для предотвращения ожидания.
Всегда используйте явное управление транзакциями.
Тогда будет ясно, когда завершена работа с соединением.
Не держите соединение открытым, ожидая ввода от пользователя.
Пользователи не всегда завершают начатое. Если пользователь сделал переход от Вашего приложения, когда соединение с БД открыто, система не должна заботиться об освобождении этого соединения. Если только Вы не реализуете схему с запросом незанятых соединений (как указано в разделе ), такое соединение может оказаться связанным на достаточно продолжительное время, ограничивая таким образом доступ других пользователей к БД.
Не оставляйте курсоры и транзакции открытыми для нескольких страниц Вашего приложения.
Когда взаимодействие с БД захватывает несколько страниц приложения, риск того, что пользователь не завершит транзакцию, значительно возрастает.
Ограничения на использование транзакций для клиентских библиотек БД, которые не являются многопоточными:
Если у Вас однопоточные библиотеки и Вы используете два соединения одновременно на одной странице с БД одного типа, Вы можете получить deadlock/мёртвую блокировку, если выполняете явные транзакции (то есть такие, которые начинаются с использования beginTransaction). Это может случиться с транзакциями на одной странице.
При многостраничных транзакциях с однопоточными библиотеками только одно соединение с БД может быть активным в единицу времени, или Вы получите мёртвую блокировку, как описано в предыдущем пункте.
Если клиентская библиотека БД не является многопоточной, только одна соединение с БД может быть активным в единицу времени. Хотя Вы не обязаны изменять свой код для обработки такой ситуации, Вы должны знать, что без многопоточной клиентской библиотеки БД Вы не получите выигрыша в производительности, даваемого многопоточными библиотеками при наличии нескольких одновременных соединений.
Некоторые библиотеки БД не являются многопоточными. По этой причине, если Вы используете объекты database() или DbPool(), Вы обязаны установить максимальное допустимое количество соединений с БД в Вашем приложении большим, чем количество клиентов, которые, как Вы предполагаете, будут использовать Ваше приложение. Иначе некоторые клиенты не смогут установить соединение с БД, и их приложения зависнут.
Совместное Использование Фиксированного Набора Пулов Соединений
Часто в приложении небольшой набор пулов соединений используется всеми пользователями данного приложения. Например, Вашему приложению нужно соединяться с тремя различными БД или с одной БД, которая использует 4 пользовательских ID, соответствующих 4 разным департаментам. Если у вас имеется небольшой набор возможных конфигураций соединения, Вы можете создать отдельный пул для каждой конфигурации. Для этого используйте объекты DbPool.
Тогда необходимо, чтобы пул работал в течение всего периода существования приложения, а не просто в течение периода существования клиента или отдельного клиентского запроса. Вы можете реализовать это, создав каждый пул БД как свойство объекта project. Например, начальная страница приложения может содержать эти операторы:
project.engpool = new DbPool ("ORACLE", "myserver1", "ENG",
"pwd1", "", 5, true);
project.salespool = new DbPool ("INFORMIX", "myserver2", "SALES",
"pwd2", "salsmktg", 2);
project.supppool = new DbPool ("SYBASE","myserver3","SUPPORT",
"pwd3", "suppdb", 3, false);
Эти операторы создают три пула для различных групп пользователей приложения.
Пул project.eng содержит 5 соединений Oracle и подтверждает любую неподтверждённую транзакцию при высвобождении соединения обратно в пул.
Пул project.sales имеет два соединения Informix и откатывает любую неподтверждённую транзакцию при окончании соединения.
Пул project.supp имеет три соединения Sybase и откатывает любую неподтверждённую транзакцию при окончании соединения.
Вы должны создавать такой пул как часть начальной страницы приложения. Эта страница выполняется только при старте приложения. На страницах, доступных пользователям, Вы не создаёте пул и не изменяете соединение. Вместо этого эти страницы определяют, к какой группе принадлежит текущий пользователь, и используют уже установленное соединение из соответствующего пула. Например, в следующем коде определяется, какую БД использовать (на основе значения свойства userGroup объекта request), в БД ищется некоторая информация, которая выводится пользователю, а затем соединение освобождается:
if (request.userGroup == "SALES") {
salesconn = project.salespool.connection("A sales connection");
salesconn.SQLTable ("select * from dept");
salesconn.release();
}
Вы можете также создать пул и изменить соединение на странице, доступной пользователю. В этом случае Вы должны быть осторожны, так как несколько пользователей, осуществляющих одновременный доступ к этой странице, не должны мешать друг другу. Например, только один пользователь должен иметь возможность создавать пул, используемый всеми остальными пользователями. О надёжности совместного использования информации см. раздел .
Совместное Использование Массива Пулов Соединений
В разделе описано, как Вы можете применить свойства объекта project для совместного использования фиксированного набора пулов соединений. Этот подход используется, если Вам в процессе разработки уже известно количество необходимых пулов соединений и Вам нужно только небольшое количество соединений.
Часто нельзя предугадать заранее количество необходимых пулов соединений. В других случаях это возможно, но это количество недопустимо велико. Например, предположим, что для каждого потребителя, имеющего доступ к Вашему приложению, приложение проверяет пользовательский профиль на предмет определения того, какую информацию из БД вывести. Вы можете дать каждому потребителю уникальный пользовательский идентификатор ID для БД. Такое приложение требует, чтобы каждый пользователь имел свой набор параметров соединений (соответствующий различным пользовательским ID в БД) и, соответственно, разные пулы соединений.
Вы можете создать объект DbPool и соединять и отсоединять его на каждой странице приложения. Это будет работать, только если одно соединение не должно захватывать несколько клиентских запросов. Иначе эта ситуация должна обрабатываться по-разному.
Для данного приложения, вместо создания фиксированного набора пулов соединений на начальной странице приложения или пула на каждой клиентской странице, Вы создаёте одно свойство объекта project, которое будет содержать массив пулов соединений. Доступ к элементам этого массива осуществляется по ключу на базе определённого пользователя.
Во время инициализации Вы создаёте массив, но не помещаете в него элементы (поскольку никто ещё не пытался использовать приложение), как показано здесь:
project.sharedPools = new Object();
Когда пользователь впервые стартует приложение, оно получает идентифицирующий пользователя ключ. На основе этого ключа приложение создаёт объект пула DbPool и сохраняет его в массиве пулов. Имея данный пул соединений, оно может либо соединяться на каждой странице, либо устанавливать соединение так, как описано в разделе Следующий код создаёт пул либо получает уже созданный, проверяет его соединение и работает затем с БД:
// Генерируется уникальный индекс для обращения к данному клиенту, если это
// ещё не было сделано на другой странице. О функции ssjs_generateClientID см.
// .
if client.id == null {
client.id = ssjs_generateClientID();
}
// Если пула для данного клиента ещё нет, он создаётся
// и производится его соединение с БД.
project.lock();
if (project.sharedPools[client.id] == null) {
project.sharedPools[client.id] = new DbPool ("ORACLE",
"myserver", user, password, "", 5, false);
}
project.unlock();// Для удобства устанавливается переменная для этого пула.
var clientPool = project.sharedPools[client.id];// Теперь у Вас есть пул: посмотрим, соединён ли он. Если нет, попытаемся соединить его.
// Если это не удаётся, перенаправляем на специальную страницу,
// чтобы проинформировать пользователя.
project.lock();
if (!clientPool.connected()) {
clientPool.connect("ORACLE", "myserver", user, password,
"", 5, false);
if (!clientPool.connected()) {
delete project.sharedPools[client.id];
project.unlock();
redirect("noconnection.htm");
}
}
project.unlock();// Если Вы дошли до этого места, Вы успешно соединились и
// можете работать с БД.
clientConn = clientPool.connection();
clientConn.SQLTable("select * from customers");
// ... другие операции с БД ...// Всегда освобождайте соединение, если оно Вам больше не нужно.
clientConn.release();
}
Когда пользователь в следующий раз войдёт в приложение (например, с другой страницы приложения), он использует тот же самый код и получит сохранённый пул соединений и (возможно, сохранённый,) объект Connection из объекта project.
Если Вы используете ssjs_generateClientID и сохраняете ID в объекте client, Вам может понадобиться защита от вторжения через доступ к этому ID и, следовательно, к закрытой информации.
ПРИМЕЧАНИЕ:
Объект sharedConns, использованный в этом примере кода, не является предопределённым объектом JavaScript. Он просто создан в этом примере и может иметь другое имя по Вашему выбору.
Совместное Использование Объекта project
Для каждого приложения имеется только один объект project. Таким образом, код, исполняемый в любом запросе к данному приложению, может получить доступ к тому же объекту project. Поскольку сервер является многопоточным, могут иметься несколько активных запросов в данный момент времени, либо от одного и того же клиента, либо от разных клиентов.
Для поддержания целостности данных Вы обязаны гарантировать исключительный доступ к свойству объекта project при изменении значения свойства. Неявной блокировки, как это было в предыдущих релизах, больше нет; Вы обязаны запрашивать исключительный доступ. Легче всего сделать это через использование методов lock и unlock объекта project. См. раздел .
Совместное Использование Объекта server
Для всего сервера имеется один объект server. Таким образом, код, выполняемый в любом запросе, в любом приложении, может иметь доступ к одному и тому же объекту server. Поскольку сервер является многопоточным, могут иметься несколько запросов в данный момент времени. Для поддержания целостности данных Вы обязаны гарантировать исключительный доступ к объекту server при внесении изменений.
Также Вы обязаны гарантировать, что имеется исключительный доступ к свойству объекта server, когда изменяется значение этого свойства. Неявной блокировки, как это было в предыдущих релизах, теперь нет; Вы обязаны запрашивать исключительный доступ. Легче всего сделать это через использование методов lock и unlock объекта server. См. раздел .
Создание Базы Данных
Имеются два набора скриптов создания БД для videoapp и oldvideo, находящиеся в соответствующих этим приложениям директориях. Наборы скриптов идентичны. Если Вы запустите один набор, оба приложения смогут использовать БД.
При первом запуске скриптов Вы можете получать ошибки, касающиеся стирания БД или таблиц, которые ещё не существуют. Это нормально; можно спокойно игнорировать эти сообщения.
Создание File-Объекта
Чтобы создать экземпляр класса File, используйте стандартный синтаксис JavaScript для создания объекта:
fileObjectName = new File("path");
Здесь fileObjectName это имя, по которому Вы обращаетесь к файлу, а path это полный путь к файлу. Этот path должен быть в формате серверной файловой системы, а не URL.
Вы можете отобразить имя файла, используя функцию write с File -объектом в качестве аргумента. Например, следующий оператор выводит имя файла:
x = new File("\path\file.txt");
write(x);
Создание Исходных Файлов Приложения
Первым шагом на пути создания приложения JavaScript будет создание и редактирование исходных файлов с кодом. Файл с расширением web для приложения JavaScript может быть исходным файлом одного из двух видов:
Файлом со стандартным HTML или с JavaScript, внедрённым в HTML. Эти файлы имеют расширение .html или .htm.
Файлом только с функциями JavaScript. эти файлы имеют расширение .js.
Если Вы используете JavaScript в HTML-файле, Вы обязаны следовать правилам, указанным в разделе .
Не используйте никаких специальных тэгов в файлах .js; компилятор приложений JavaScript на сервере и интерпретатор JavaScript на стороне клиента считают такие файлы написанными на JavaScript. Поскольку HTML-файл используется и на клиенте, и на сервере, один файл JavaScript обязан использоваться либо на сервере, либо на клиенте; он не может использоваться и там, и там. Следовательно, файл JavaScript может содержать либо клиентский, либо серверный JavaScript, но один файл не может содержать и клиентские, и серверные объекты или функции.
Компилятор приложений JavaScript компилирует и связывает HTML- и JavaScript-файлы, содержащие серверный JavaScript, в единый платформонезависимый байт-код web-файла (имеющего расширение .web), как описано в разделе .
Вы инсталируете web-файл, запускаемый машиной выполнения JavaScript, как описано в разделе .
Создание Курсора
Как только приложение установило соединение с БД, Вы можете создать курсор путём вызова метода cursor ассоциированного объекта database или Connection. Создание объекта Cursor также открывает курсор в БД. Вам не нужно выполнять отдельную команду open.
Можно предоставить следующую информацию при создании объекта Cursor:
Оператор SQL SELECT, поддерживаемый сервером БД. Чтобы гарантировать независимость от вида БД, используйте синтаксис SQL 89/92. Курсор создаётся как виртуальная таблица результата выполнения этого оператора SQL.
Необязательный Булев параметр указывает, является ли курсор обновляемым. Используйте этот параметр только в том случае, когда Вам нужно изменять содержимое БД, как указано в разделе . Не всегда возможно создать обновляемый курсор для каждого оператора SQL, так как это контролируется базой данных. Например, если оператор SELECT будет таким: "select count(*) from videos", Вы не сможете создать обновляемый курсор.
Например, следующий оператор создаёт курсор для записей таблицы CUSTOMER. Записи содержат столбцы id, name и city и упорядочены по значениям столбца id.
custs = connobj.cursor ("select id, name, city
from customer order by id");
Этот оператор устанавливает в переменную custs объект Cursor. Запрос SQL может вернуть следующие ряды:
1 Sally Smith Suva
2 Jane Doe Cupertino
3 John Brown Harper's Ferry
Затем Вы можете получить доступ к этой информации через использование методов Cursor-объекта custs. Этот объект имеет свойства id, name и city, соответствующие столбцам виртуальной таблицы.
Когда Вы первоначально создаёте Cursor-объект, указатель позиционируется сразу перед первым рядом виртуальной таблицы. В последующих разделах рассматривается, как получить информацию из виртуальной таблицы.
Вы можете также использовать оператор конкатенации строк (+) и строковые переменные (такие как значения свойств client или request) при конструировании оператора SELECT. Например, следующий вызов использует ранее сохранённый customer ID для последующей специализации запроса:
custs = connobj.cursor ("select * from customer where id = "
+ client.customerID);
При попытке создания Cursor-объекта Вы можете столкнуться с различными проблемами. Например, если оператор SELECT в вызове метода cursor обращается к несуществующей таблице, БД возвращает ошибку, и метод cursor возвращает null вместо Cursor-объекта. В этой ситуации Вы должны использовать методы majorErrorCode и majorErrorMessage для определения возникшей ошибки.
В качестве второго примера, предположим, что оператор SELECT обращается к существующей таблице, в которой нет рядов. В этом случае БД может не возвратить ошибку, а метод cursor возвратит верный Cursor -объект. Однако, поскольку этот объект не содержит рядов, при первой попытке использования метода next в этом объекте он возвратит false. Ваше приложение должно проверять возможность возникновения такой ситуации.
Создание Специального Объекта client
Как уже было сказано ранее, свойства предопределённого объекта client могут иметь только строковые значения. Это ограничение может представлять проблему для работы некоторых приложений. Например, Вашему приложению нужен объект, который существует столько же, сколько предопределённый объект client, но который может принимать в качестве значений свойств объекты или другие типы данных. В этом случае Вы можете создать Ваш собственный объект и сохранить его как свойство объекта client.
В этом разделе приведён пример создания такого объекта. Можете включить этот код как файл JavaScript в Ваше приложение. Затем в начале страницы, на которой нужно использовать этот объект, введите следующий оператор:
var customClient = getCustomClient()
(Разумеется, можно использовать другое имя переменной.) Если это первая страница, запрашивающая данный объект, метод getCustomClient создаёт новый объект. На других страницах он будет возвращать уже существующий объект.
Этот код сохраняет массив всех специальных объектов client, определённых в приложении как значения свойства customClients предопределённого объекта project. Он сохраняет индекс в этом массиве и строковое значение свойства customClientID предопределённого объекта client. Кроме того, этот код использует блокировку/lock, хранимую в свойстве customClientLock объекта project, чтобы гарантировать надёжность доступа к этому массиву. О блокировании см. раздел .
Переменная timeout в функции getCustomClient жёстко кодирует период окончания действия этого объекта. Если Вам нужен другой период окончания действия, специфицируйте другое значение для этой переменной. Независимо от используемого периода действия, Вы должны вызывать метод expiration предопределённого объекта client для установки его срока окончания действия в то же значение, какое специфицировано Вами для специального объекта. О работе этого метода см. раздел .
Для удаления всех закончивших работу специальных объектов приложения вызовите следующую функцию:
expireCustomClients()
Это всё, что нужно сделать! Если Вы используете этот код, предопределённые объекты client и project имеют следующие дополнительные свойства, которые Вы не должны изменять:
client.customClientID
project.customClientsproject.customClientLock
Вы можете специализировать класс путём изменения его методов onInit и onDestroy. Как показано здесь, эти методы - это просто основа. Вы можете добавить код для изменения действий при создании и уничтожении объекта.
Вот этот код:
// Эта функция создаёт новый специальный объект client или запрашивает существующий.
function getCustomClient()
{
// ==========> Измените жёстко кодированный период ожидания <==========
// Примечание: Не забудьте установить окончание обслуживания client-статуса
// в то же самое значение, что и использованное ниже в вызове
// client.expiration. Это даст возможность индексу отключать все предопределённые
// объекты client в то же время, которое содержится в объекте project.
var timeout = 600;
var customClient = null;
var deathRow = null;
var newObjectWasCreated = false;
var customClientLock = getCustomClientLock();
customClientLock.lock();
var customClientID = client.customClientID;
if ( customClientID == null ) {
customClient = new CustomClient(timeout);
newObjectWasCreated = true;
}
else {
var customClients = getCustomClients();
customClient = customClients[customClientID];
if ( customClient == null ) {
customClient = new CustomClient(timeout);
newObjectWasCreated = true;
}
else {
var now = (new Date()).getTime();
if ( customClient.expiration <= now ) {
delete customClients[customClientID];
deathRow = customClient;
customClient = new CustomClient(timeout);
newObjectWasCreated = true;
}
else {
customClient.expiration = (new Date()).getTime() +
timeout*1000;
}
}
}
if ( newObjectWasCreated )
customClient.onInit();
customClientLock.unlock();
if ( deathRow != null )
deathRow.onDestroy();
return customClient;
}
// Функция для удаления старых специальных объектов client.
function expireCustomClients()
{
var customClients = getCustomClients();
var now = (new Date()).getTime();
for ( var i in customClients ) {
var clientObj = customClients[i];
if ( clientObj.expiration <= now ) {
var customClientLock = getCustomClientLock();
customClientLock.lock();
if ( clientObj.expiration <= now ) {
delete customClients[i];
}
else {
clientObj = null;
}
customClientLock.unlock()
if ( clientObj != null )
clientObj.onDestroy();
} } }
// Не вызывайте эту функцию явно.
// Она используется методами getCustomClient и expireCustomClients.
function getCustomClientLock()
{
if ( project.customClientLock == null ) {
project.lock()
if ( project.customClientLock == null )
project.customClientLock = new Lock()
project.unlock()
}
return project.customClientLock
}
// Не вызывайте эту функцию явно.
// Она используется методами getCustomClient и expireCustomClients.
function getCustomClients()
{
if ( project.customClients == null ) {
project.lock()
if ( project.customClients == null )
project.customClients = new Object()
project.unlock()
}
return project.customClients
}
// Конструктор класса CustomClient. Не вызывайте его явно.
// Используйте вместо него функцию getCustomClient.
function CustomClient(seconds)
{
var customClients = getCustomClients();
var customClientID = ssjs_generateClientID();
this.onInit = CustomClientMethod_onInit;
this.onDestroy = CustomClientMethod_onDestroy;
this.expiration = (new Date()).getTime() + seconds*1000;>
client.customClientID = customClientID;
customClients[customClientID] = this;
}
// Если нужно специализировать, переопределите следующие две функции.
function CustomClientMethod_onInit()
{
// ==========> Добавьте код инициализации Вашего объекта <==========
// Этот метод вызывается при блокировке.
}function CustomClientMethod_onDestroy()
{
// ==========> Добавьте код очистки Вашего объекта <==========
// Этот метод не вызывается из блокировки.
}
Специальные Замки/Locks для Объектов project и server
Каждый из объектов project и server имеет методы lock и unlock. Вы можете использовать эти методы для получения исключительного доступа к свойствам этих объектов.
В этих методах ничего нового нет. Вам также необходима кооперация с другими участками кода. Вы можете представлять эти методы как имеющие флаги: один флаг с именем "project", а другой - флаг с именем "server." Если другой раздел кода не вызывает project.lock, первый может изменять любые свойства объекта project.
В отличие от метода lock класса Lock, Вы не можете специфицировать таймаут для метода lock объектов project и server. То есть, когда Вы вызываете project.lock, система ожидает бесконечно долго освобождения замка. Если Вы хотите ожидать только в течение определённого периода, используйте экземпляр класса Lock.
В примере использованы методы lock и unlock для получения исключительного доступа к объекту project для модификации свойства ID потребителя:
project.lock()
project.next_id = 1 + project.next_id;
client.id = project.next_id;
project.unlock();
SQL
Structured Query Language. Стандартный язык для определения, управления и запрашивания реляционных баз данных.
Сравнение Видов Техники Обслуживания Объекта client
Каждый вид техники имеет свои преимущества и недостатки, и то, что является недостатком в одной ситуации, может оказаться преимуществом в другой. Вам необходимо выбрать вид техники, наиболее подходящей для Вашего приложения. Виды техники описаны более детально в последующих разделах; в этом разделе даётся общее сравнение.
В таблице выполнено общее сравнение клиентской и серверной техники.
1. |
Не ограничивается количество хранимых свойств или занимаемое ими пространство. |
Ограничения на свойства. | |||
2. |
Занимает дополнительную память сервера в промежутке между клиентскими запросами. |
Не использует дополнительную память сервера в промежутке между клиентскими запросами. | |||
Эти различия относительны. Отсутствие ограничения на количество и размер свойств может быть и недостатком, и преимуществом. Вообще нужно ограничивать размер данных приложения, доступных через Internet, чтобы не перегрузить память Вашего сервера. Иначе лучше использовать клиентскую технику. Однако, если у вас приложение для Intranet (внутренней сети), где нужно хранить большой объём данных, можно допустить это на сервере, так как количество клиентов ограничено. | |||||
3. |
Свойства хранятся в памяти сервера и теряются при рестарте сервера или приложения. |
Свойства не хранятся в памяти сервера и не теряются при рестарте сервера. | |||
Если свойства являются настройками пользователя, Вам может понадобиться сохранить их между рестартами сервера; если они относятся к отдельной сессии, может понадобиться, чтобы они были стёрты. | |||||
4. |
Не увеличивает или незначительно увеличивает сетевой трафик. |
Увеличивает сетевой трафик. | |||
Клиентская техника пересылает имя и значение каждого свойства клиенту один или более раз. Это значительно увеличивает сетевой трафик. Поскольку все серверные виды техники хранят имена и значения свойств на сервере, максимум, что они пересылают клиенту, это сгенерированное имя клиента, используемое при идентификации доступа к структуре данных сервера. |
На и на видно, какая информация хранится при использовании каждого вида техники, где она хранится и передаётся ли по сети. На дана информация для клиентской техники.
Рисунок 6.3 Клиентская техника
![](http://cm/javascript/servguide14/graphics/csmaint.gif)
На дана информация для серверной техники.
Рисунок 6.4 Серверная техника
![](http://cm/javascript/servguide14/graphics/ssmaint.gif)
Имеются некоторые общие для видов (серверной и клиентской) техники вопросы. Для обоих типов техники, использующих куки, браузер обязан поддерживать протокол Netscape cookie protocol. В обоих случаях, когда браузер на клиентской машине закрывается, информация сохраняется в cookie-файле на клиентской машине. В других случаях ограничений нет.
Техника серверных кук создаёт единственную куку для идентификации соответствующего объекта client. В противоположность этому, техника клиентских кук создаёт отдельную куку для каждого свойства объекта client. На технику клиентских кук, следовательно, скорее повлияет ограничение в 20 кук на приложение.
В технике клиентских кук свойства объекта client высылаются клиенту, когда высылается первая часть HTML-страницы. Если Вы изменяете позднее значения свойств объекта client при выполнении действий на странице, эти изменения не отсылаются клиенту и теряются. Это ограничение не действует для другой техники.
Для обеих техник, использующих кодирование в URL, если Ваше приложение конструирует URL на этапе выполнения или использует функцию redirect, необходимо либо вручную присоединять свойства объекта client, которые должны быть сохранены, либо использовать addClient, чтобы машина выполнения присоединила эти свойства. Хотя присоединение свойств не является обязательным для других техник, Вам может понадобиться сделать это, чтобы изменение техники не нарушило работу Вашего приложения.
Кроме того, при использовании техник кодирования URL, как только браузер перейдёт на страницу за пределами приложения или даже отправит форму приложению с использованием метода GET, все свойства объекта client будут утеряны. Свойства не теряются в такой ситуации для других видов техники. Ваш выбор техники частично определяется тем, должны ли существовать свойства объекта client в такой ситуации.
Ваш выбор используемой техники опирается на требования Вашего приложения. Техника клиентских кук не использует дополнительной памяти сервера (как при серверной технике) и высылает информацию только один раз для страницы (в противоположность клиентской технике кодирования URL). Эти факты могут сделать использование техники клиентских кук предпочтительным для больших Internet-приложений. Однако в некоторых случаях другая техника может оказаться более подходящей. Например, серверный IP-адрес работает быстрее, не увеличивая сетевого трафика. Можно использовать это для приложений Вашей Intranet, для которых скорость работы является критичной.
Ссылки на Пакеты и Классы
Простые ссылки на пакеты и классы Java из JavaScript создают объекты JavaPackage и JavaClass. В одном из предыдущих примеров о корпорации Redwood, например, обращение Packages.redwood это JavaPackage -объект. Аналогично обращение java.lang.String это JavaClass -объект.
В большинстве случаев Вам не нужно беспокоиться об объектах JavaPackage и JavaClass: Вы просто работаете с пакетами и классами Java, а LiveConnect прозрачно создаёт эти объекты.
JavaClass -объекты не конвертируются автоматически в экземпляры java.lang.Class при передаче их в качестве параметров Java-методам -- Вы обязаны создать оболочку/wrapper вокруг экземпляра java.lang.Class. В следующем примере метод forName создаёт объект-оболочку theClass, который затем передаётся методу newInstance для создания нового массива.
theClass = java.lang.Class.forName("java.lang.String")
theArray = java.lang.reflect.Array.newInstance(theClass, 5)
Старт Flexi
Вы обязаны стартовать FlexiServer до старта flexi, поскольку стартовая страница flexi пытается соединиться с FlexiServer.
Добавьте $NSHOME\js\samples\flexi в CLASSPATH Вашего web-сервера. О том, как это сделать, см. "Установка LiveConnect".
Используя Application Manager, установите приложение flexi JavaScript, как описано в разделе "Установка Нового Приложения". Параметры, устанавливаемые Вами для flexi, показаны в следующей таблице.
Name | flexi | |
Web File Path/Путь к web-файлу | $NSHOME\js\samples\flexi\flexi.web | |
Default Page/Страница по Умолчанию | fsa.html | |
Initial Page/Начальная Страница | start.html | |
Client Object Maintenance/Обслуживание Объекта сlient | client-cookie |
Старт FlexiServer
FlexiServer это отдельное приложение Java. Оно может работать только на машине, имеющей JDK 1.0.2. В Enterprise Server 3.01 и в FastTrack Server 3.01 Вы можете также запускать его на машине с JDK 1.1.2. Прежде чем запустить FlexiServer, Вы должны убедиться, что среда работы корректна.
Из оболочки, где Вы запускаете FlexiServer, убедитесь, что Ваша переменная окружения PATH содержит $JDK\bin и что CLASSPATH включает следующее:
...
$NSHOME\js\samples\flexi
$NSHOME\wai\java\nisb.zip
$JDK\lib\classes.zip
Здесь $JDK это директория, в которой установлен JDK, а $NSHOME это директория, в которой установлен Ваш web-сервер.
Если среда корректна, Вы можете стартовать FlexiServer так:
cd $NSHOME\js\samples\flexi\impl
java FlexiServer
Вы должны увидеть такое сообщение:
Started FSA Admin: Admin[Server,oid=PersistentId[repId=IDL:Flexi/Admin:1.0,objectName=FSA-Admin]]
С этого момента FlexiServer стартовал как сервис CORBA и зарегистрировал в ORB объект с интерфейсом ::FSA::Admin и именем FSA-Admin. FlexiServer работает в фоновом режиме, ожидая запросов на обслуживание.
Старт, Остановка и Рестарт Приложения
После инсталяции приложения его можно запустить на выполнение. Выберите приложение в списке приложений и щёлкните Start. Если приложение запущено успешно, его статус изменяется со Stopped на Active.
Вы можете запустить приложение, загрузив его URL:
http://server.domain/appmgr/control.html?name=appName&cmd=start
Здесь appName это имя приложения. Вы не можете изменить этот URL, если не имеете привилегий доступа к Application Manager.
Чтобы остановить приложение и сделать его таким образом недоступным для пользователей, выберите имя приложения в списке приложений и щёлкните Stop. Статус приложения изменится на Stopped, и клиенты не смогут запускать его. Вы обязаны остановить приложение, если хотите переместить web-файл или обновить приложение с рабочего сервера на конечном сервере публикаций.
Вы можете также остановить приложение, загрузив следующий URL:
http://server.domain/appmgr/control.html?name=appName&cmd=stop
Здесь appName это имя приложения. Вы не можете изменить этот URL, если не имеете привилегий доступа к Application Manager.
Вы обязаны рестартовать приложение каждый раз после его перестроения/rebuild. Чтобы рестартовать активное приложение, выберите его в списке приложений и щёлкните Restart. Фактически рестарт реинсталирует приложение; программа ищет специфицированный web-файл. Если верного web-файла нет, Application Manager генерирует ошибку.
Вы можете также рестартовать приложение, загрузив следующий URL:
http://server.domain/appmgr/control.html?name=appName&cmd=restart
Здесь appName это имя приложения. Вы не можете изменить этот URL, если не имеете привилегий доступа к Application Manager.
Static-метод или свойство
Метод или свойство встроенного объекта, которые не могут быть свойством экземпляров объекта. Например, Вы можете инстанциировать (создать экземпляры) новые экземпляры объекта Date. Некоторые методы объекта Date, такие как getHours и setDate, являются также методами экземпляров объекта Date. Другие методы объекта Date, такие как parse и UTC, являются static/статическими, и экземпляры объекта Date не имеют этих методов.