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

         

ECMAScript


Стандартизованный международный язык программирования на базе ядра JavaScript. Эта стандартизованная версия JavaScript работает одинаково во всех приложениях, поддерживающих данный стандарт. Компании могут использовать открытый стандартный язык для разработки своих реализаций JavaScript. См. также .



External function/внешняя функция


Функция, определённая во внешней библиотеке и используемая в приложении JavaScript.



Где Найти Информацию о JavaScript


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

Документацию по JavaScript, состоящую из следующих книг:

Серверный JavaScript. Руководство. (эта книга) предоставляет информацию о языке JavaScript и его объектах. Эта книга содержит информацию о ядре языка (версии 1.4) и о серверном JavaScript. Работа некоторых возможностей ядра на клиенте отличается от их работы на сервере; эти отличия обсуждаются в данной книге.

Серверный JavaScript. Справочник. предоставляет справочный материал по языку JavaScript, включая ядро и серверный JavaScript.

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

Серверный JavaScript, Справочник. для получения долее детальной информации об объектах и операторах.

Используйте материал этой книги для знакомства с ядром и серверным JavaScript. Пользуйтесь книгами

Клиентский JavaScript. Руководство. и

Клиентский JavaScript. Справочник. для получения информации о создании сценариев на HTML-страницах.

содержат информацию о Enterprise Server 4.x, в том числе - касающуюся серверного JavaScript для Enterprise Server 4.x.

Книга содержит резюме по разным интерфейсам программирования, доступным в версиях 4.x Netscape web-серверов. Используйте это учебник в качестве карты или отправной точки при изучении документации Enterprise Server для разработчиков.

Помимо этого, другие книги Netscape обсуждают отдельные аспекты JavaScript, особенно относящиеся к их области действия. Эти книги упоминаются в тексте данной книги там, где это возможно.



Сайт Netscape содержит большое количество информации, которая может понадобиться при создании приложений JavaScript. Вот некоторые URL, представляющие особый интерес:


Страница технической поддержки Netscape службы LiveWire Database Service. Содержит много ссылок на информацию по использованию LiveWire в приложениях JavaScript.


Страница технической поддержки Netscape с информацией о JavaScript. Для быстрого перехода на эту страницу щёлкните ссылку DevEdge в Netscape Enterprise Server Application Manager.


Это View Source Magazine, онлайновый магазин для разработчиков. Он обновляется каждую неделю и часто содержит статьи, представляющие интерес для разработчиков JavaScript.



Генерирование HTML


Как уже было сказано ранее в этой главе, функция write генерирует HTML на основе значения выражения JavaScript, заданного в качестве аргумента. Например, рассмотрим оператор:

write("<P>Customer Name is:" + project.custname + ".");

В ответ на этот оператор JavaScript генерирует HTML, вставляя тэг параграфа и некоторый текст, соединённый со значением свойства custname объекта project. Например, если свойство будет иметь значение "Fred's software company", клиент получит следующий HTML:

<P>Customer Name is: Fred's software company.

Как кажется клиенту, это нормальный HTML. Однако он в действительности динамически сгенерирован машиной выполнения JavaScript.



JavaScript. Обзор.


Это введение в JavaScript и обсуждение некоторых фундаментальных понятий.

В главе имеются следующие разделы:



В этой главе дан обзор


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





Технология Разработки Приложений JavaScript


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

Информацию об использовании только клиентского JavaScript см. в книге Клиентский JavaScript 1.3. Руководство.

В этой главе имеются следующие разделы:



Быстрое Начало с Примерами Приложений


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

В данной главе имеются следующие разделы:



Основы Серверного JavaScript


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

В главе имеются следующие разделы:

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



Служба Session Management Service


В этой главе рассматриваются объекты службы Session Management Service, доступные в серверном JavaScript и предназначенные для обеспечения совместного использования данных несколькими клиентскими запросами к приложению, несколькими пользователями одного приложения или даже несколькими приложениями на сервере.

Session Management Service это набор возможностей для управления созданием и уничтожением различных предопределённых объектов в ходе сессии сервера. Эти возможности предоставлены через объекты request, client, project и server.

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

В главе имеются следующие разделы:



Другая Функциональность JavaScript


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

В главе имеются следующие разделы:



Соединение с Базой Данных


В этой главе обсуждается использование службы LiveWire Database Service для соединения Вашего приложения с реляционными базами данных DB2, Informix, ODBC, Oracle или Sybase. Показано, как выбрать наилучшую методологию для Вашего приложения.

В главе имеются следующие разделы:



Работа с Базой Данных


В этой главе обсуждается работа с реляционными базами данных DB2, Informix, ODBC, Oracle и Sybase. Рассматривается, как запрашивать информацию из БД и использовать её в приложении, как работать с транзакциями и как выполнять хранимые процедуры.

Не забывайте, что, если Ваше приложение работает на Netscape FastTrack Server, а не на Netscape Enterprise Server, оно может иметь доступ только к серверам БД, использующим стандарт ODBC.

В главе имеются следующие разделы:



Конфигурирование Базы Данных


В этой главе рассматривается настройка Вашей Базы Данных для запуска со службой LiveWire Database Service. Вы должны прочесть эту главу и раздел перед тем как использовать LiveWire с Вашими JavaScript-приложениями.

ПРИМЕЧАНИЕ:

Могут понадобиться изменения в клиентах БД. Дополнительно см. .

В этой главе имеются следующие разделы:



Конвертация Типов Данных


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

В главе имеются следующие разделы:



Обработка Ошибок LiveWire


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

В главе имеются следующие разделы:



Приложения-Образцы Videoapp и Oldvideo


В этой главе описано приложение-образец videoapp, иллюстрирующее использование службы LiveWire Database Service. Рассмотрено, как сконфигурировать рабочую среду для запуска приложений videoapp и oldvideo.

В главе имеются следующие разделы:



LiveConnect. Обзор.


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

В главе имеются следующие разделы:

Дополнительно об использовании LiveConnect см.

на сайте DevEdge, а также ищите соответствующую информацию на сайтах mozilla.org и developer.netscape.com.



Доступ к Сервису CORBA


В этой главе рассматривается использование LiveConnect для доступа к распределённым объектам CORBA. С помощью LiveConnect Вы можете получить доступ к Java; через Java - соединяться с CORBA-объектами, используя Netscape Internet Service Broker for Java.

В главе имеются следующие разделы:



Hangman


В этом разделе Вы запустите и модифицируете приложение-образец Hangman и получите представление о том, как:

Использовать исходные файлы на чистом JavaScript.

Исправлять ошибки времени компиляции/compile-time errors.

Использовать утилиту трассировки для отладки.

Hangman это классическая игра, в которой игроки пытаются угадать слово. Неизвестные буквы отображаются на экране звёздочками; звёздочка заменяется на букву, если игрок угадывает её. Если введённая буква некорректна, прорисовывается часть повешенного. Игра показывает также некорректные буквы, введённые Вами.

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

Запустите приложение Hangman, выбрав Hangman в Application Manager и щёлкнув Run. Можно также загрузить приложение в Navigator:

http://server.domain/hangman

В ответ Application Manager выведет страницу, показанную на следующем рисунке.

Рисунок 4.2Hangman

 Поиграйте в игру, чтобы получить представление о работе программы.



Hello World


В этом разделе Вы запустите приложение Hello World, пример простейшего приложения, и получите представление о следующих процедурах:

Чтение исходных файлов JavaScript

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

Построение/Building и рестарт приложения

Чтобы начать работу с образцами приложений, Вам необходим доступ к JavaScript Application Manager. Вы можете получить этот доступ, введя следующий URL в Navigator:

http://server.domain/appmgr

В этом и других URL в данном учебнике server это имя сервера, на котором Вы запускаете Ваше приложение, как, например research1 или www, domain это имя домена Internet, такое как netscape.com или uiuc.edu. Если Ваш сервер имеет Secure Sockets Layer (SSL), используйте https вместо http в URL.

В Application Manager'е выберите world в левом фрэйме и щёлкните кнопку Run. Вы можете также ввести URL приложения в поле Location Navigator'а:

http://server.domain/world

Application Manager выведет страницу, показанную на .

Рисунок 4.1   Hello World

Об Application Manager см. .



HTML


Hypertext Markup Language. Язык разметки, используемый для создания страниц для World Wide Web.



HTTP


Hypertext Transfer Protocol. Протокол соединения, используемый для передачи информации между серверами и клиентами web.



Идентификация Файлов Библиотек


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

Важно!

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

После идентификации внешних библиотек с помощью Application Manager все приложения, запущенные на данном сервере, могут вызывать функции этих библиотек (используя registerCFunction и callC).



Индивидуальные Соединения с Базой Данных


Как только Вы создали пул соединений, клиентская страница может получить доступ к индивидуальному соединению из пула. Если Вы используете объект database, соединение в данном объекте является неявным; то есть Вы используете методы объекта database для доступа к соединению. Если, однако, Вы используете объекты DbPool, соединение инкапсулируется в объекте Connection, который Вы получаете через вызов метода объекта DbPool. Например, в следующем пуле:

project.eng = new DbPool ("ORACLE", "myserver", "ENG", "pwd1", "", 5);

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

myconn = project.eng.connection ("My Connection", 60);

Оба параметра метода являются необязательными. Первый это имя соединения (используется при отладке); второй это целое число, обозначающее таймаут в секундах. В этом примере, если пул имеет доступное соединение или если оно становится доступным в течение 60 секунд, это соединение присваивается переменной myconn. Если соединение не становится доступным в течение указанного периода, этот метод возвращается без соединения. Дополнительно об ожидании получения соединения из пула см. раздел . О том, что делать, если соединение не получено, см. .

Если Вы закончили использование соединения, возвратите его в пул путём вызова метода release объекта Connection. (Если Вы используете объект database, Вам не нужно самостоятельно освобождать соединение). Прежде чем вызвать метод release, закройте все открытые курсоры, хранимые процедуры и результирующие наборы. Если Вы вызываете метод release, система ожидает, когда всё закроется, и возвращает затем соединение в пул базы данных. После этого соединение доступно следующему пользователю. Об использовании курсоров см. . О хранимых процедурах и результирующих наборах см. .

После получения соединения (через объект database или объект Connection), Вы можете работать с БД. В таблице резюмированы методы объектов database и connection для работы с единственным соединением. Объект database имеет и другие методы для обслуживания пула соединений, рассмотренные в разделе


МетодОписание


cursor


Создаёт курсор БД для специфицированного оператора SQL SELECT.


SQLTable


Отображает результаты выполнения запроса. Создаёт таблицу HTML для результата выполнения оператора SQL SELECT.


execute


Выполняет специфицированный оператор SQL. Используется для операторов SQL, отличных от запросов/queries.


connected


Возвращает true, если пул БД (и, следовательно, данное соединение) соединён с БД.


release


(Только для Connection) Освобождает соединение обратно в пул.


beginTransaction


Начинает транзакцию SQL.


commitTransaction


Подтверждает текущую транзакцию SQL.


rollbackTransaction


Выполняет откат текущей транзакции SQL.


storedProc


Создаёт объект хранимой процедуры и запускает специфицированную хранимую процедуру БД.


majorErrorCode


Важнейший код ошибки, возвращаемый сервером БД или ODBC.


majorErrorMessage


Сообщение о важнейшей ошибке, возвращаемое сервером БД или ODBC.


minorErrorCode


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


minorErrorMessage


Второе по значению сообщение о важнейшей ошибке, возвращаемое библиотекой производителя.

Информация Конфигурации


В этом разделе рассматривается информация конфигурации для использования серверного JavaScript. Дополнительно о настройке БД для работы с сервисом LiveWire Database Service см.



Informix


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

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

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


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

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

$NSHOME\js\samples\videoapp\ifx
$NSHOME\js\samples\oldvideo\ifx

ПРИМЕЧАНИЕ:

Не забудьте, что пути в этом учебнике, если они относятся и к NT, и к Unix, даются в формате NT. В Unix Вы используете $NSHOME/js/samples/videoapp/ifx.

    В Unix войдите в систему как пользователь "informix" и запустите скрипт оболочки ifx_load.csh для videoapp и для oldvideo.

    В NT дважды щёлкните в группе программ Informix Server иконку Command-Line Utilities, чтобы открыть окно DOS, затем запустите следующие команды:cd c:\netscape\server\js\samples\videoapp\ifx
    ifx_load.bat

    Вы можете также запустить эти команды из директории oldvideo\ifx:

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



Initial page/начальная страница


Страница, специфицированная в Application Manager, которую Application Manager запускает, когда приложение первоначально стартует. Сравните с .



IP address/IP-адрес


Набор из четырёх чисел в диапазоне от 0 до 255 включительно, разделённых точками, который специфицирует место по протоколу TCP/IP.



IP address technique/техника IP-адреса


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



Исходные Файлы


В таблице показаны первичные файлы и директории для flexi.

flexi.idl

Файл, определяющий интерфейс с удалённым сервисом, включая Admin, Account, Claim.

Flexi\

Директория, содержащая код, сгенерированный из Flexi.idl программой idl2java. Эта директория содержит каркасы и стабы (каркасы\основы) интерфейсов.

impl\

Директория, содержащая Java-реализации всех интерфейсов, определённых во Flexi.idl. Она также содержит класс FlexiServer, реализующий main-программу приложения Java, которое работает как сервис.

*.html

Файлы, реализующие серверное приложение JavaScript. Сюда входит также web-файл приложения, flexi.web.

Просмотрите эти файлы, чтобы добиться полной ясности в вопросах работы приложения. Здесь обсуждаются лишь некоторые детали.



Исключение Мёртвой Блокировки/Deadlock


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

Рассмотрим предыдущий пример обработки заказов потребителей. Предположим, что приложение разрешает два действия. В одном - пользователь вводит нового потребителя; в другом - пользователь вводит новый заказ. Как часть создания нового потребителя приложение также создаёт новый заказ потребителя. Это действие выполняется на одной странице приложения, давая примерно такой код:

// Создать нового потребителя (customer).


if ( project.customersLock.lock() ) {

   var id = project.customers.ID;

   id = id + 1;
   project.customers.ID = id;

   // Стартовать новый заказ (order) для этого нового потребителя.

   if ( project.ordersLock.lock() ) {

      var c = project.orders.count;

      c = c + 1;

      project.orders.count = c;

      project.ordersLock.unlock();
   }

   project.customersLock.unlock();
}

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

// Стартовать новый заказ.


if ( project.ordersLock.lock() ) {

   var c = project.orders.count;
   c = c + 1;

   project.orders.count = c;


   if (...код определения неизвестного потребителя...) {

      // Создать нового потребителя.

      // Этот внутренний замок может вызвать проблемы!

      if ( project.customersLock.lock() ) {

          var id = project.customers.ID;
         id = id + 1;

         project.customers.ID = id;

          project.customersLock.unlock();
      }
   }

   project.ordersLock.unlock();
}

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

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

// Создать нового потребителя.

if ( project.customersLock.lock() ) {

   var id = project.customers.ID;

   id = id + 1;
   project.customers.ID = id;

   project.customersLock.unlock();
}

// Стартовать новый заказ для этого нового потребителя.



if ( project.ordersLock.lock() ) {

   var c = project.orders.count;
   c = c + 1;

   project.orders.count = c;

   project.ordersLock.unlock();
}

Второй фрагмент будет примерно таким:

// Стартовать новый заказ.

if ( project.ordersLock.lock() ) {

   var c = project.orders.count;

   c = c + 1;
   project.orders.count = c;

   project.ordersLock.unlock();
}

if (...код для определения неизвестного потребителя...) {

   // Создать нового потребителя.

   if ( project.customersLock.lock() ) {

      var id = project.customers.ID;

      id = id + 1;

      project.customers.ID = id;

      project.customersLock.unlock();

   }
}

Хотя это и надуманная ситуация, тупики это совершенно реальная проблема, и они могут произойти во многих случаях. Для этого даже не понадобится более одного замка или более одного запроса. Рассмотрим код, в котором две функции запрашивают один и тот же замок:

function fn1 () {
   if ( project.lock() ) {

      // ... какие-то действия ...

      project.unlock();
   }
}

function fn2 () {
   if ( project.lock() ) {

      // ... какие-то другие действия ...

      project.unlock();
   }
}

Сам по себе этот код не содержит проблем. Позднее слегка измените его, чтобы fn1 вызывала fn2, уже имея замок, как показано далее:

function fn1 () {
   if ( project.lock() ) {

      // ... какие-то действия ...

      fn2();
      project.unlock();

   }
}

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


Исключения Informix и Sybase


Хранимые процедуры Informix и Sybase могут возвращать коды ошибки, используя механизм исключений. После того как Вы запустили процедуру на выполнение, Вы можете запрашивать эти коды ошибок и сообщения об ошибках, используя методы majorErrorCode и majorErrorMessage ассоциированного объекта database или Connection.

Например, у Вас имеется хранимая процедура Informix:

create procedure usercheck (user varchar(20))
if user = 'LiveWire' then

raise exception -746, 0, 'User not Allowed';
endif
end procedure

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

spobj = connobj.storedProc("usercheck");

if ( connobj.majorErrorCode() ) {
   write("The procedure returned this error code: " +
      connobj.majorErrorCode());

   write("The procedure returned this error message: " +
       connobj.majorErrorMessage());
}



Использование


Вам необходимо знать, как компилятор приложений JavaScript распознаёт клиентский и серверный JavaScript в HTML-файле.

Операторы клиентского JavaScript могут появляться в следующих ситуациях:

Как операторы и функции внутри тэга SCRIPT

При специфицировании файла как JavaScript-исходника для тэга SCRIPT

При специфицировании выражения JavaScript как значения HTML-атрибута

При включении операторов как обработчиков событий в некоторых тэгах HTML

О деталях см. книгу

Клиентский JavaScript.

.

Операторы серверного JavaScript могут появляться в следующих ситуациях:

Как операторы и функции внутри тэга SERVER

При специфицировании файла как JavaScript-исходника для компилятора приложений JavaScript

При специфицировании выражения JavaScript как значения или имени HTML-атрибута

Заметьте, что Вы не можете специфицировать оператор серверного JavaScript как обработчик события. Дополнительно см. .



Использование Flexi


Чтобы стартовать flexi, Вы можете запустить его из Application Manager или ввести следующий URL:

http://server-name/flexi

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

    Администратор создаёт для пользователя баланс.

    Служащий выбирает счёт.

    Служащий отправляет запрос.

    Администратор выбирает счёт служащего.

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

    Администратор удаляет запрос.

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



Использование Функции debug


Вы можете использовать функцию debug в Вашем приложении JavaScript для помощи при отслеживании/трассировке проблем в приложении. Функция debug отображает значения для утилиты трассировки. Например, следующий оператор выводит значение свойства guess объекта request в окне трассировки вместе с некоторым идентифицирующим текстом:

debug ("Current Guess is ", request.guess);



Использование IP-Адреса


Техника с использованием IP-адреса индексирует структуру данных на основе IP-адресов приложения и клиента. Эта простая техника является также и самой быстрой, поскольку вообще не требует отправки информации клиенту. Так как индекс базируется на IP-адресах приложения и клиента, эта техника создаёт отдельный индекс для каждой пары приложение/клиент, работающей на сервере.

Эта техника хорошо работает, когда все клиенты имеют фиксированные IP-адреса. Она работает ненадёжно, если клиент не имеет гарантированно фиксированного IP-адреса, например, если клиент использует протокол Dynamic Host Configuration Protocol (DHCP) или провайдера Internet, который динамически размещает IP-адреса. Эта техника также не работает у клиентов, использующих прокси-сервер, поскольку все пользователи прокси сообщают один и тот же IP-адрес. Поэтому данная техника используется в основном только для приложений Intranet.



Использование Экземпляров Класса Lock


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

Рисунок 6.5 Thread (поток) 2 ожидает, пока thread 1 имеет lock (замок)

В терминах программирования замок/lock представлен экземпляром класса Lock. Вы можете использовать экземпляр класса Lock для получения исключительного доступа к любому совместно используемому объекту. Обычно Вы создаёте экземпляры Lock на начальной странице Вашего приложения (по причинам, которые будет изложены позднее).

На других страницах, перед критичным для совместно используемого объекта разделом (например, перед разделом, который запрашивает и изменяет значение свойства), Вы вызываете метод lock экземпляра Lock. Если этот метод возвращает true, Вы получаете замок и можете продолжать. В конце критичного раздела Вы вызываете метод unlock Lock -экземпляра.

Когда клиентский запрос в одиночном потоке выполнения вызывает метод lock, любой другой запрос, вызывающий метод lock для того же Lock -экземпляра, ожидает, пока первый поток не вызовет метод unlock, пока не закончится таймаут или пока не возникнет ошибка. Это верно независимо от того, находится второй запрос в другом потоке для того же клиента или в потоке для другого клиента.

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


Важно!

Использование замков находится всецело под управлением разработчика и требует кооперации. Машина выполнения не заставляет Вас ни вызывать lock, ни учитывать блокировку, полученную кем-либо другим. Если Вы не спрашиваете, Вы можете изменять всё что захотите. Поэтому очень важно выработать привычку всегда вызывать lock и unlock при входе и выходе из критичного раздела кода и проверять return-значение метода lock, чтобы гарантировать, что блокировка получена. Можно представлять это в терминах флага: если Вы не запрашиваете флаг, вы не будете находиться в режиме ожидания. Если Вы не находитесь в режиме ожидания, Вы можете изменять то, что изменять нельзя.

Вы можете создать столько замков, сколько Вам необходимо. Один и тот же замок может использоваться для управления доступом к нескольким объектам, либо каждый объект (или даже каждое свойство) может иметь собственный замок.

Замок/lock сам по себе является просто объектом JavaScript; Вы можете сохранить ссылку на него в любом другом объекте JavaScript. Таким образом, например, обычной практикой является конструирование экземпляра Lock и сохранение его в объекте project.

ПРИМЕЧАНИЕ:

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

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

// Создать новый Lock и сохранить в project.

project.ordersLock = new Lock();

if (! project.ordersLock.isValid()) {

   // Невозможно создать Lock. Перенаправить на страницу обработки ошибок.

   redirect ("sysfailure.htm");
}

Этот код создаёт экземпляр класса Lock и проверяет (вызовом метода isValid), не возвращено ли что-нибудь неправильное при его создании. Очень редко Ваш экземпляр Lock конструируется неправильно. Это случается только тогда, когда машина выполнения запущена вне системных ресурсов при создании объекта.



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

Если, однако, Ваше приложение создаёт замок на какой-либо иной странице, множественные запросы могут вызывать эту страницу в это время. Один запрос может проверять наличие замка и не обнаружить его, в то время как другой запрос создаёт замок, а третий запрос создаёт второй замок. Тем временем первый запрос вызывает метод lock своего объекта. Затем второй запрос вызывает метод lock своего объекта. Оба запроса теперь "думают", что они имеют безопасный доступ к критичному разделу кода и продолжают свою работу, нарушая работу другого.

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

// Начало критичного раздела -- получить замок.

if ( project.ordersLock.lock() ) {   var x = project.orders.count;

   x = x + 1;
   project.orders.count = x;

   // Конец критичного раздела -- освободить замок.

   project.ordersLock.unlock();

}
else
   redirect("combacklater.htm");

Этот код запрашивает замок. Если замок получен (то есть, если метод lock возвратил true), выполняется вход в критичный раздел, вносятся изменения и, наконец, замок освобождается. Если метод lock возвращает false, то данный код не получает замка. В этом случае приложение перенаправляет на страницу, которая сообщает, что приложение в данный момент не может выполнить запрос.


Использование Классов LiveConnect


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

Таким образом, всегда, когда Вы используете JavaScript-объекты в коде Java, Вы должны помещать вызов JavaScript-объекта внутри блока try...catch, который обрабатывает исключения netscape.javascript.JSException. Это позволяет Вашему Java-коду обрабатывать ошибки при выполнении кода JavaScript, которые появляются в Java как исключения типа JSException.



Использование Клиентского Кодирования URL


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

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

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

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

<SERVER>
...
client.numwrites = 2;
write (addClient(

   "<A HREF='page2.htm'>Some link</A>"));
client.numwrites = 3;

write (addClient(
   "<A HREF='page3.htm'>Another link</A>"));
...

</SERVER>

Когда машина выполнения обрабатывает первый оператор write, она использует 2 как значение свойства numwrites, а при обработке второго оператора write она использует в качестве значения 3.

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

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

<A HREF="mailto:me@royalairways.com">

Машина выполнения присоединяет свойства объекта client. Чтобы этого не происходило, используйте очень похожую ссылку:

<A HREF=`"mailto:me@royalairways.com"`>

При этой технике объект client не перестаёт действовать, поскольку существует только в URL-строке, находящейся на клиенте. Следовательно, метод client.expiration не производит никаких действий.

При клиентском кодировании URL Вы теряете все свойства объекта client, когда отправляете форму, используя метод GET, и когда выполняете доступ к другому приложению. Ещё раз - Вам может быть нужно или не нужно терять эти свойства, в зависимости от потребностей Вашего приложения.

В отличие от техники клиентских кук, клиентское кодирование URL не требует ни поддержки web-браузером протокола Netscape cookie, ни записи информации на клиентской машине.



Использование Клиентской Куки/Cookie


В технике клиентских кук машина выполнения JavaScript на сервере использует протокол Netscape cookie protocol для передачи клиенту свойств объекта client и их значений. Она создаёт по одной куке для каждого свойства объекта client. Свойства высылаются клиенту один раз в шапке/header ответа генерируемой HTML-страницы. Netscape cookie protocol описан в книге Клиентский JavaScript.

.

Для исключения конфликтов с другими куками, которые Вы можете создать в Вашем приложении, машина выполнения создаёт имя куки, добавляя NETSCAPE_LIVEWIRE. перед началом имени свойства объекта client. Например, если client имеет свойство custID, машина выполнения создаёт куку под названием NETSCAPE_LIVEWIRE.custID. Когда информация куки высылается клиенту, машина выполнения делает всё необходимое кодирование специальных символов в значении свойства, как описано в книге Клиентский JavaScript.

.

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

При использовании этой техники машина выполнения сохраняет свойства объекта client, когда она в первый раз очищает внутренний буфер, содержащий сгенерированную HTML-страницу. Исходя из этого, для того чтобы предотвратить потерю любой информации, Вы должны как можно раньше присвоить значения всем свойствам объекта client в скриптах на каждой странице. В особенности Вы должны гарантировать, что свойства объекта client будут высылаться перед тем как (1) машина выполнения сгенерирует 64KB содержимого HTML-страницы (она автоматически очищает буфер вывода в этой точке), (2) Вы вызовете функцию flush для очистки буфера вывода или (3) Вы вызовете функцию redirect для изменения клиентских запросов. Дополнительно см. разделы и .

По умолчанию, когда Вы используете технику клиентских кук, машина выполнения не устанавливает явно время окончания срока действия кук. В этом случае куки заканчивают работать, когда пользователь закрывает браузер. (Это поведение по умолчанию для всех кук.) Как указано в разделе , Вы можете использовать метод expiration объекта client для изменения срока окончания действия. Если Вы используете client.expiration, машина выполнения устанавливает соответствующий срок окончания работы куки в cookie-файле.


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

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

4KB для каждой куки (включая имя и значение куки). Если одна кука больше 4KB, её вхождение усекается до 4KB. Это может дать неверное значение свойства объекта client.20 кук на приложение. Если Вы создаёте более 20 для одного приложения, самая старая кука (созданная первой) уничтожается. Поскольку техника клиентских кук создаёт отдельную куку для каждого свойства объекта client, объект client может хранить максимум 20 свойств. Если Вы хотите использовать в Вашем приложении также и другие куки, общее их количество всё равно ограничено числом 20.

300 кук в cookie-файле. Если Вы создадите более 300 кук, самые старые куки (созданные первыми) уничтожаются.


Использование Кук


Куки это механизм, который Вы можете использовать на клиенте для сохранения информации между запросами. эта информация находится в файле с названием cookie.txt (куки-файл), хранящемся на клиентской машине. Протокол Netscape cookie детально описан в книге .

Вы можете использовать куки для отправки информации в обоих направлениях, от клиента серверу и с сервера клиенту. Куки, высылаемые с клиента, становятся свойствами объекта client или объекта request. Хотя Вы можете выслать с сервера клиенту любое строковое значение в качестве куки, простейший метод будет - отправить свойства объекта client.



Использование Менеджера Приложений/Application Manager для Отладки


Для отладки приложения выберите его в списке приложений и щёлкните Debug. Application Manager откроет новое окно Navigator, в котором будет запущено приложение. Запустится также утилита трассировки в отдельном фрэйме, в окне, содержащем приложение, или вообще в другом окне. (Вы можете определить появление отладочного окна при конфигурировании установок по умолчанию для Application Manager, как описано в разделе ).

Утилита трассировки выведет следующую отладочную информацию:

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

значения свойств объектов request и client до и после генерации HTML для страницы

значения свойств объектов project и server

индикацию присвоения новых значений свойствам

индикацию отправки машиной выполнения содержимого клиенту

На показано то, что Вы можете увидеть при отладке приложения Hangman.

Рисунок 3.5   Отладка Приложения Hangman



Использование Методов Управления Транзакциями


Используйте следующие методы объектов database или Connection для явного управления транзакциями:

beginTransaction стартует новую транзакцию. Все действия, модифицирующие базу данных, группируются в данную транзакцию, называемую текущей транзакцией.

commitTransaction подтверждает текущую транзакцию. Этот метод пытается подтвердить все действия, выполненные после последнего вызова метода beginTransaction.

rollbackTransaction откатывает текущую транзакцию. Этот метод отменяет все изменения, сделанные с момента последнего вызова метода beginTransaction. Конечно, если Ваша БД не поддерживает транзакции, Вы не сможете использовать их. Например, БД Informix, созданная с использованием опции NO LOG, не поддерживает транзакции, и Вы получите ошибку при использовании данных методов.

Сервис LiveWire Database Service не поддерживает вложение транзакций. Если Вы вызовете beginTransaction несколько раз до подтверждения или отката первой открытой Вами транзакции, Вы получите ошибку.

Для объекта database максимум области видимости транзакции ограничен текущим клиентским запросом (HTML-страницей) в приложении. Если приложение существует на странице до вызова метода commitTransaction или rollbackTransaction, то транзакция автоматически подтверждается или откатывается на основе установок параметра commitflag, задаваемого при соединении с БД.

Для объектов Connection область видимости транзакции ограничена периодом существования этих объектов. Если Вы освобождаете соединение или закрываете пул соединений до вызова методов commitTransaction или rollbackTransaction, то транзакция автоматически подтверждается или откатывается на основе установок параметра commitflag, задаваемого при соединении с БД методом connect или в конструкторе DbPool.

Если текущая транзакция отсутствует (то есть, если приложение не вызывало beginTransaction), вызовы методов commitTransaction и rollbackTransaction могут привести к ошибке в БД.

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

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

Если Вы разбиваете Ваш процесс на несколько транзакций, убедитесь, что вызов next и ассоциированный вызов updateRow или deleteRow происходят внутри одной транзакции. Если Вы получаете ряд в одной транзакции, завершаете её, а затем пытаетесь обновить или удалить ряд, Вы можете получить ошибку в БД.

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



Использование Объекта Admin для Администрирования и Просмотра Новых Счетов


Код во flexi создаёт другие объекты, кроме объекта Admin, и осуществляет к ним доступ во FlexiServer. Эти объекты создаются путём вызовов метода объекта Admin. Например, если служащий отправляет запрос, новый запрос создаётся в account-empl.html следующим оператором:

__claim = __account.submitClaim(

parseFloat(request.claimAmount),
request.serviceDate,

request.providerName,
   request.details);

Этот код вызывает метод submitClaim объекта Account для создания нового запроса служащего. Реализация этого метода в файле impl\Account.java создаёт новый Claim-объект, который регистрируется в ORB и возвращается:

public Flexi.Claim submitClaim(float amount, String serviceDate,

   String providerName, String details)
{

Claim __clm = new Claim(this, amount, serviceDate,
       providerName, details);
   org.omg.CORBA.ORB.init().BOA_init().obj_is_ready(__clm);

   _current_clm = __clm;

System.out.println("***Created a new claim: " + __clm);
   return __clm;
};



Использование Серверной Кодировки URL


Техника серверного кодирования URL использует длинное уникальное имя, генерируемое машиной выполнения для индексации структуры данных на сервере. В этом случае, вместо того чтобы сделать это генерируемое имя клиентской кукой, сервер присоединяет имя к каждому URL на генерируемой HTML-странице. Следовательно, имя высылается столько раз, сколько имеется ссылок на генерируемой HTML-странице. (Имена и значения свойств не присоединяются к URLs, только генерируемое имя.) Ещё раз: Вы можете получить доступ к этому генерируемому имени с помощью функции ssjs_getClientID, описанной в разделе .

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

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

<A HREF="mailto:me@royalairways.com">

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

<A HREF=`"mailto:me@royalairways.com"`>

При серверном кодировании URL вы теряете идентификатор объекта client (и, соответственно, свойства и их значения) при отправке формы с методом GET. Вы можете терять или не терять эти свойств, в зависимости от потребностей Вашего приложения.



Использование Серверных Кук


Техника серверных кук использует длинное уникальное имя, генерируемое машиной выполнения для индексации структуры данных на сервере. Машина выполнения использует протокол Netscape cookie для хранения генерируемого имени как куки/cookie на клиенте. Она не сохраняет имена и значения свойств как куки. Поэтому данная техника создаёт одну куку, в то время как клиентская техника кук создаёт отдельную куку для каждого свойства объекта client.

Сгенерированное имя отсылается клиенту только один раз в шапке/header HTML-страницы. Вы можете получить доступ к этому имени через функцию ssjs_getClientID, описанную в разделе . Эта техника использует тот же самый cookie-файл, что и техника клиентских кук; эти виды техники отличаются тем, что информация сохраняется в cookie-файле. Протокол Netscape cookie protocol описан в книге .

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

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

При использовании серверной куки метод client.destroy уничтожает все значения свойств объекта client.

В общем, Netscape-куки имеют ограничения, перечисленные в разделе . Если Вы используете серверные куки, эти ограничения вряд ли будут достигнуты, так как создаётся только одна кука (содержащая индекс).

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



Использование Списков Select


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

itemValue = getOptionValue(name, index)

Здесь name это строка, специфицированная как атрибут NAME тэга SELECT, а index это порядковый индекс выбранной опции, начиная с 0. Функция getOptionValue возвращает значение выбранного элемента, как специфицировано ассоциированным тэгом OPTION.

Функция getOptionValueCount возвращает количество опций (специфицированных тэгами OPTION) в списке выбора. Она требует только одного аргумента, строки, содержащей имя тэга SELECT.

Например, у Вас имеется следующий элемент:

<SELECT NAME="what-to-wear" MULTIPLE SIZE=8>

   <OPTION SELECTED>Jeans
   <OPTION>Wool Sweater

   <OPTION SELECTED>Sweatshirt
   <OPTION SELECTED>Socks

   <OPTION>Leather Jacket
   <OPTION>Boots

   <OPTION>Running Shoes
   <OPTION>Cape
</SELECT>

Вы можете обработать ввод из этого select-списка таким образом:

<SERVER>
var i = 0;
var howmany = getOptionValueCount("what-to-wear");

while ( i < howmany ) {
   var optionValue =

      getOptionValue("what-to-wear", i);

   write ("<br>Item #" + i + ": " + optionValue + "\n");

   i++;
}
</SERVER>

Если пользователь оставил выбор по умолчанию, скрипт возвратит:

Item #0: Jeans
Item #1: Sweatshirt
Item #2: Socks



Использование URL Отладки


Вместо Application Manager вам может больше подойти использование URL отладки приложения. Для отображения утилиты трассировки приложения в отдельном окне введите следующий URL:

http://server.domain/appmgr/trace.html?name=appName

Здесь appName это имя приложения. Для отображения утилиты трассировки в том же самом окне, что и окно приложения (но в отдельном кадре/фрэйме), введите URL в форме:

http://server.domain/appmgr/debug.html?name=appName

Вы не сможете воспользоваться двумя вышеуказанными URL, если не имеете прав для запуска Application Manager. Для удобства можно сделать закладку на URL отладки.



Использование Внешних Функций в JavaScript


После того как Ваше приложение зарегистрировало функцию, оно может использовать callC для её вызова. Эта функция имеет следующий синтаксис:

callC(JSFunctionName, arguments);

Здесь JSFunctionName это имя функции, как она была идентифицирована с помощью registerCFunction, а arguments это список разделённых запятыми аргументов внешней функции. В качестве аргументов могут использоваться любые значения JavaScript: строки, числа, булевы значения, объекты или null. Количество аргументов обязано соответствовать количеству необходимых аргументов внешней функции. Хотя Вы можете специфицировать объект JavaScript в качестве аргумента, это используется редко, поскольку объект конвертируется в строку перед передачей внешней функции.

Эта функция возвращает строковое значение, возвращённое внешней функцией. Функция callC может возвращать только строковые значения.

Приложение-образец jsaccall иллюстрирует использование внешних функций. Директория jsaccall содержит исходный код C (в jsaccall.c), определяющий C-функцию с именем mystuff_EchoCCallArguments. Эта функция принимает любое количество аргументов и возвращает строку, содержащую HTML с перечислением аргументов. Это пример иллюстрирует вызов функций C из приложения JavaScript и возвращаемые значения.

Чтобы запустить jsaccall, Вы обязаны скомпилировать jsaccall.c имеющимся у Вас компилятором C. Командные строки для нескольких распространённых компиляторов даны в файле в виде комментариев.

Следующие операторы JavaScript (взятые из jsaccall.html) регистрируют C-функцию как echoCCallArguments в JavaScript, вызывают функцию echoCCallArguments, а затем генерируют HTML на основе значения, возвращённого данной функцией.

var isRegistered = registerCFunction("echoCCallArguments",

"c:\\mycode\\mystuff.dll", "mystuff_EchoCCallArguments");
if (isRegistered == true) {

   var returnValue = callC("echoCCallArguments",

      "first arg",
      42,

      true,
      "last arg");

   write(returnValue);
}
else {
   write("registerCFunction() returned false, "
      + "check server error log for details")
}

Функция echoCCallArguments создаёт результирующую строку, содержащую HTML, который выводит тип и значение каждого переданного ей аргумента JavaScript. Если registerCFunction возвращает true, вышеприведённый код генерирует такой HTML:

argc = 4<BR>
argv[0].tag: string; value = first arg<BR>

argv[1].tag: double; value = 42<BR>
argv[2].tag: boolean; value = true<BR>

argv[3].tag: string; value = last arg<BR>



Изменение Информации Базы Данных


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

custs = connobj.cursor ("select id, name, city from customer", true)

Чтобы курсор был обновляемым, оператор SELECT обязан быть обновляемым запросом (запросом, позволяющим производить обновление). Например, оператор не может запрашивать ряды из более чем одной таблицы или содержать условие GROUP BY, а также обычно он обязан запрашивать ключевые значения таблицы. Дополнительно о конструировании обновляемых запросов см. документацию производителя БД.

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

Например, Informix и Oracle возвращают сообщения об ошибке, если Вы используете курсор без явной транзакции. Oracle возвращает Error ORA-01002: fetch out of sequence; Informix возвращает Error -206: There is no current row for UPDATE/DELETE cursor.

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

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

В следующем примере обновляемый курсор вычисляет премию для продавцов, выполнивших норму. Затем этой информацией обновляется БД:

connobj.beginTransaction ();emps = connobj.cursor(
"select * from employees where dept='sales'", true);

// Прежде чем продолжить, убедитесь, что курсор действительно был возвращён
// и не было ошибки БД.


if ( emps && (connobj.majorErrorCode() == 0) ) {

// Производится итерация по рядам курсора с обновлением информации на базе // return-значения функции metQuota.

   while ( emps.next() ) {

      if (metQuota (request.quota, emps.sold)) {

         emps.bonus = computeBonus (emps.sold);

      }
      else emps.bonus = 0;

      emps.updateRow ("employees");
   }

   // После выполнения - закрывается курсор и подтверждается транзакция.

   emps.close();
   connobj.commitTransaction();
}
else {

   // Если курсор для работы отсутствовал, транзакция откатывается.

   connobj.rollbackTransaction();
}

Этот пример создаёт обновляемый курсор для всех employees/служащих департамента Sales. Производится итерация по рядам курсора через использование определяемой пользователем функции JavaScript metQuota, для того чтобы определить, выполнил ли служащий норму. Эта функция использует значение свойства quota объекта request (возможно, установленное в форме на клиентской странице) и столбец sold курсора для выполнения этого определения. Код затем устанавливает соответствующую премию и вызывает updateRow

для модифицирования таблицы employees. Когда пройдены все ряды курсора, подтверждается транзакция. Если вызов метода cursor не вернул никакого курсора, транзакция откатывается.

Помимо метода updateRow, Вы можете использовать методы insertRow и deleteRow для вставки нового ряда или удаления текущего. При использовании deleteRow не нужно присваивать никакого значения, поскольку этот метод просто удаляет весь ряд.

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

ПРИМЕЧАНИЕ:


В DB2 имеется тип данных Time. JavaScript не имеет соответствующего типа данных. Поэтому Вы не можете обновлять ряды значениями, использующими тип данных DB2 Time.


Изменения в JavaScript Application Manager


Функциональность менеджера JavaScript Application Manager не изменилась в Enterprise Server 4.0 по сравнению с Enterprise Server 3.x. Однако он теперь использует ту же новую схему цветов, что и Server Manager в Enteprise Server 4.0, и имеет некоторые изменения внешнего вида.

JavaScript Application Manager теперь имеет три вкладки:

Applications

Слева - список установленных приложений и кнопки Start, Stop, Restart, Run, Debug, Modify и Remove. Правая панель содержит информацию о приложении, выбранном в списке приложений. Если Вы щёлкните мышью кнопку Modify, в правой панели отобразятся поля, которые дают Вам возможность модифицировать выбранное приложение.Add Application

Добавить новое приложение.Preferences

Специфицировать значения по умолчанию при добавлении нового приложения.

Хотя названия и внешний вид вкладок и кнопок в JavaScript Application Manager в Enterprise Server 4.0 слегка отличается от Enterprise Server 3.6, их функциональность не изменилась.



Ядро JavaScript


Клиентский и серверный JavaScript имеют следующие общие элементы:

Ключевые слова

Синтаксис операторов и грамматику

Правила написания выражений, переменных и литералов

Лежащую в основе объектную модель (хотя клиентский и серверный JavaScript имеют разные предопределённые объекты)

Предопределённые объекты и функции, такие как Array, Date и Math



Ядро, Клиентский и Серверный JavaScript


Компоненты JavaScript показаны на рисунке:

Рисунок 1.1   Язык JavaScript

В следующем разделе разбирается работа JavaScript на стороне клиента и на сервере.



JavaScript и Java


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

В отличие от системы времени компиляции Java, построенной на объявлениях, JavaScript поддерживает систему времени выполнения, основанную на небольшом количестве типов данных: числовых, Булевых и строковых. JavaScript имеет объектную модель на базе прототипов вместо более общей объектной модели на базе классов. Модель на базе прототипов предоставляет возможность динамического наследования; то есть, то, что наследуется, может отличаться для разных объектов. JavaScript также поддерживает функции без специальных требований объявления. Функции могут быть свойствами объектов, исполняемыми как нетипизированные методы.

JavaScript это язык, свободный по форме, по сравнению с Java. Вы не должны объявлять все переменные, классы и методы. Вы не должны учитывать, являются ли методы public, private или protected, и не обязаны реализовывать интерфейсы. Return-типы переменных, параметров и функций не типизированы явно.

Java это язык на базе классов, разработанный для быстрого выполнения и строгой типизации. Строгая типизация означает, к примеру, что Вы не можете привести/cast целое число Java (integer) к ссылке на объект или получить доступ к private-памяти, нарушая байт-коды Java. Модель Java на базе классов означает, что программы состоят исключительно из классов и их методов. Наследование классов в Java и строгая типизация обычно требуют тесно выстроенной иерархий объектов. Эти требования делают программирование на Java более сложным, чем авторизация на JavaScript.

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


JavaScript Java


Интерпретируется (не компилируется) клиентом.


Скомпилированные байт-коды, загруженные с сервера, выполняются на клиенте.


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


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


Коды интегрированы и внедрены в HTML.


Аплеты отличаются от HTML (доступ к ним осуществляется из HTML-страниц).


Типы переменных не объявляются (динамическая типизация).


Типы переменных обязаны быть объявлены (статическая типизация).


Не может автоматически записывать на жёсткий диск.


Не может автоматически записывать на жёсткий диск.

JavaScript и Спецификация ECMA


Netscape изобрела JavaScript, и JavaScript был впервые использован в браузерах Netscape. Одновременно Netscape работает с (European Computer Manufacturers Association) для создания стандартизованного международного языка программирования на базе ядра JavaScript. ECMA это международная ассоциация стандартов в области систем информации и коммуникаций. Эта стандартизованная версия JavaScript, называемая ECMAScript, ведёт себя совершенно одинаково во всех приложениях, поддерживающих этот стандарт. Компании могут использовать этот открытый стандартный язык для создания своих реализаций JavaScript. Первая версия стандарта ECMA документирована в спецификации ECMA-262.

Стандарт ECMA-262 одобрен также (International Organization for Standards) как ISO-16262. Вы можете найти на Netscape DevEdge Online. Вы также можете найти эту на сайте ECMA. Спецификация ECMA не описывает Document Object Model (DOM), которая стандартизуется консорциумом . DOM определяет способ, которым объекты HTML-документа экспонируются в скрипте.



JavaScript и Технология ECMA


Спецификация ECMA использует терминологию и синтаксис, которые могут быть незнакомы программистам JavaScript. Хотя описание языка может отличаться в ECMA, сам язык остаётся тем же самым. JavaScript поддерживает всю функциональность, данную в спецификации ECMA.

Документация по JavaScript описывает аспекты языка, необходимые программисту на JavaScript. Например:

Объект global не обсуждается в документации JavaScript, поскольку Вы не используете его явно. Методы и свойства объекта global, используемого Вами, обсуждаются в документации JavaScript, но называются функциями и свойствами верхнего уровня.

Конструктор без параметров (zero-argument) с объектами Number и String не обсуждается в документации JavaScript, поскольку то, что генерируется, используется мало. Number -конструктор без аргументов возвращает +0, а String -конструктор без аргументов возвращает "" (пустую строку).