RDM/2 The Russian Electronic Developer Magazine  
RDM/2 Русский электронный журнал разработчика  
ДомойОт редактораПишите намОбратная связьRU/2

NetData: Macro Processor

Что такое NetData

NetData -- это макропроцессор, интегрируемый в web-сервер, с помощью которого можно создавать динамические web-страницы. NetData позволяет объединить в своей среде логику, вычисления, обращения к базам данных для создания динамических html-страниц, а главное, она позволяет объединять в одном макросе различные языковые среды (java, javascript, perl, rexx, SQL), что существенно упрощает работу программиста. NetData также позволяет использовать и внешние приложения и дает интерфейс программам написанным на C/C++. NetData была разработана  IBM  и активно используется последней на разработанных ей серверах, например на сервере государственного Эрмитажа.
Простейший пример использования NetData может выглядеть следующим образом:
%{
******************************************************************************
Define Section:

  Use this section to define variables (e.g. DATABASE) used in your
macro file.  At a minimum, the DATABASE variable must be defined.
******************************************************************************
%}

%DEFINE{
   DTW_PRINT_HEADER="NO"
   DTW_SET_TOTAL_ROWS="YES"
   DATABASE="INFO"
   LOGIN="LOGIN"
   PASSWORD="PASSWORD"
   SHOWSQL="YES"
   RETURN_CODE=""
   TOTAL="0"
%}

%{
******************************************************************************
Function query:
******************************************************************************
%}

%FUNCTION(DTW_SQL) query_article() {
        select Word, Description from BES where Word = ucase('$(Word)') or Word like ucase('%$(Word)%') order by Word
%report{
        %ROW{
        <p align="JUSTIFY">
        $(ROW_NUM) <b>- $(V1)</b> <br> $(V2)
        </p>
        %}
%}
%message{
        +100: "<i>Увы. На сервере нет информации удовлетворяющей ваш запрос</i>": continue
        %}

%}



%FUNCTION(DTW_SQL) query_count() {
       select count(*) from BES
%report{
       @DTW_ASSIGN(TOTAL,V1)
       %}
%}


%{
******************************************
FRAME SECTION
******************************************
%}

%HTML(FRAME){
Content-type: text/html; charset=ibm866


<Html>
<FrameSet Rows="180,600" border=1>
   <Frame Name="top" Src="/cgi-bin/db2www/bes.d2w/start" Scrolling="NO" MarginWidth="0" MarginHeight="0">
   <Frame Name="bottom" Src="/cgi-bin/db2www/bes.d2w/empty" Scrolling="Auto" MarginWidth="0" MarginHeight="0">
</FrameSet>
</Html>
%}

%{
******************************************************************************
EMPTY Section:
******************************************************************************
%}
%HTML(EMPTY) {
Content-type: text/html; charset=ibm866

@query_count()
<HTML>
<FONT FACE="Swiss,Helvetica,Helv" SIZE=4>
<p align="JUSTIFY">
Коллекция сайта содержит $(TOTAL) словарных статей
</center>
</HTML>
%}

%{
******************************************************************************
START Section:
******************************************************************************
%}

%HTML(START){
Content-type: text/html; charset=ibm866


<Html>
<Form Method=Post Action="/cgi-bin/db2www.exe/bes.d2w/report" target="bottom">
Образец запроса словарной статьи:<br>
<input type="TEXT" name="Word" value="" size="50"><br>
<INPUT TYPE="submit" VALUE="Запрос">
</form>
</body>
</Html>
%}

%{
******************************************************************************
REPORT Section:
******************************************************************************
%}

%HTML(REPORT){
Content-type: text/html; charset=ibm866
<HTML>
@query_article()
</HTML>
%}
Работу этого макроса можно посмотреть на  http://udb.fcn.ru/cgi-bin/db2www/bes.d2w/frame.
В отличие от CGI-скриптов, и средств интегрированных в HTML (как, например, PHP), функциональные вызовы в NetData макросах естественно вписываются в код HTML без всяких специальных средств. Код NetData исполняется на сервере. так что клиент видит лишь результаты.

Идеология

NetData -- очень прост в изучении.
NetData макрос имеет секционную организацию, в которую входят секции определения переменных, ввода, результата и секции определения функций.  Естественно, секций может быть произвольное количество, за исключением секции определения переменных.  Секция определения переменных может быть только одна или не быть вовсе, т.к. допустимо динамическое определение переменной конструкцией %DEFINE. Секции можно рассматривать как функции в других языках - они просто позволяют организовывать как это сейчас модно называть "бизнес-логику".
Синтаксиса, как такового в NetData нет вовсе - есть набор функций (свыше сотни), предустановленные переменные (как, например, LOGIN) и несколько специальных конструкций. NetData позволяет писать быстро и интегрировать в себя ранее заготовленные куски через конструкцию %INCLUDE. NetData вполне удобен для работы с базами данных, причем знает не только UDB DB2, но и другие (Sybase). Также можно работать с данными хранимыми в файлах. NetData предоставляет следующие категории функций: общего назначения (дата, время, окружение, настройки, отправка почты, передача параметров в переменные и.т.д.), математические (сложение, вычитание, возведение в степень и.т.д.), работы со строками и словами, работы с таблицами , работы с файлами ( открыть, закрыть, добавить, вставить и.т.д.), а также функции регистрации соединений. С помощью этих функций можно сделать многое, но очень громоздко и неудобно в смысле писанины. Гораздо удобнее пользоваться окружением скриптовых языков типа rexx, хоть это и может слегка повлиять на производительность.
При работе с NetData следует помнить важную особенность ее реализации - сервер каждый раз прочитывает макрос заново, а значит передача параметров из одной секции в другую должна реализовываться специальными методами, например скрытыми  полями форм, а также то, что передача результатов SQL запросов в переменные должна быть явной, т.е. через специальную функцию @DTW_ASSIGN().
К достоинствам NetData следует отнести явно заданный и настраиваемый механизм LiveConnection, позволяющий держать пул открытых соединений с СУБД, а также ее бесплатность.

Установка

NetData устанавливается с помощью стандартного инсталятора IBM, после чего надо проверить записала-ли она файл DB2WWW.INI в каталог DATA вашего HTTP-сервера и DB2WWW.EXE в /cgi-bin/ каталог. В поставку входит программа - администратор позволяющая править настройки средствами GUI.
 

Примечание 1: иногда, в случаях установки NetData на машине-клиенте UDB приходится биндить ее ресурс с помощью файла D2WSQL.BND.

Примеры использования

Пример 1: обработка форм

Образец запроса 
Год 
Если вы

Код описывающий эту форму, а также секция обработки ее средствами NetData даны ниже.

%HTML(START){
Content-type: text/html; charset=ibm866


<Html>
<FONT FACE="Swiss,Helvetica,Helv" SIZE=4>
<body text="#000080" bgcolor="#CCCCCC">
<TABLE>
<TR>
<TD>
<Form Method=Post Action="report" target="bottom">
<table border=0  width="400">
<tr >
<td valign="top" width="17%">Образец запроса </td>
<td ><input type="TEXT" name="PERSON" value="" size="50"></td>
</tr>
<tr >
<td  align=right>Год </td>
<td><input type="TEXT" name="YYYY" value="" size="4" maxlength=4> <INPUT TYPE="submit" VALUE="Запрос"></td>

</tr>
</table>
</form>
</TD>
<TD bgcolor="#FF6666" align="center">
<font color="#FFFF80"><b>Если вы</b></font> <br>
<form Method=Post Action="expert" target="top">
<INPUT TYPE="submit" VALUE="Эксперт"></form>
</TD>
</TR>
</TABLE>
</body>
</Html>
%}

%HTML(REPORT){
Content-type: text/html; charset=ibm866


<HTML>
<FONT FACE="Swiss,Helvetica,Helv" SIZE=4>

%IF (PERSON=="LIST" || PERSON=="!LIST" || PERSON=="list" || PERSON=="!list")
    %IF (PERSON=="LIST" || PERSON=="list")
        @DTW_ASSIGN(REQUEST,"")
    %ELSE
        @DTW_ASSIGN(REQUEST,"WHERE ID NOT IN (select id_pr from relation)")
    %ENDIF
    <table>
    @query_list()
    </table>
%ELSE
    %IF (PERSON=="*")
        @query_count()
        @DTW_ASSIGN(REQUEST,@rand_req(TOTAL_PHOTOS))

    %ELSE
       %IF (PERSON !="")
          @DTW_ASSIGN(PERSON,@p2s(PERSON))
          @DTW_ASSIGN(REQUEST,"ID_PHOTO IN (")
          @DTW_CONCAT(REQUEST,PERSON,REQUEST)
          @DTW_CONCAT(REQUEST,")",REQUEST)
       %ELSE
          @DTW_ASSIGN(STRING,"select id_photo from photos")
          %IF ( YYYY !="")
              @DTW_CONCAT(STRING," where yyyy=",STRING)
              @DTW_CONCAT(STRING,YYYY,STRING)
              @DTW_ASSIGN(YYYY,"")
          %ENDIF
          @DTW_ASSIGN(REQUEST,"id_photo in ((")
          @DTW_CONCAT(REQUEST,STRING,REQUEST)
          @DTW_CONCAT(REQUEST,") except (select id_ph from relation)) FETCH FIRST 32 ROWS ONLY",REQUEST)
       %ENDIF
    %ENDIF
    %IF ( YYYY !="")
        @DTW_CONCAT(REQUEST," AND YYYY=",REQUEST)
        @DTW_CONCAT(REQUEST,YYYY,REQUEST)
    %ENDIF
    @DTW_GETENV("REMOTE_ADDR",CLIENT_IP)
    @DTW_ASSIGN(CLIENT_IP,@log_client(CLIENT_IP,REQUEST))
    @query2()
%ENDIF
</HTML>
%}
Секция REPORT реализует логику приложения и формирует запрос к UDB DB2, который выводится прямо в нее.
Реализация запроса имеет следующий вид:

%FUNCTION(DTW_SQL) query2() {
         select SPHOTO, ID_PHOTO, YYYY, ID_PERSON, NOTE from PHOTOS where $(REQUEST)
%REPORT{
                   <table>
                   %ROW{
                            @DTW_ADD(COUNT,"1",COUNT)
                            %IF  ($(COUNT)=="1")
                                    <tr>
                            %ENDIF
                            <TD>
                            <form method="get" action="info">
                            <input type=image SRC="$(V1)" weight="80" Height="100" border=0>
                            <input type="hidden" name=SPHOTO value=$(V1)>
                            <input type="hidden" name=ID_PHOTO value=$(V2)>
                            <input type="hidden" name=YYYY value=$(V3)>
                            <input type="hidden" name=ID_PERSON value=$(V4)>
                            @DTW_ASSIGN(NOTE,"'")
                            @DTW_CONCAT(NOTE,V5,NOTE)
                            @DTW_CONCAT(NOTE,"'",NOTE)
                            <input type="hidden" name=NOTE value=$(NOTE)>
                            </form>
                            </TD>
                            %IF ($(COUNT)=="4")
                                    @DTW_ASSIGN(COUNT,"0")
                                    </tr>
                            %ENDIF
                            %}
                    </table>
                    %}
%message{
                   -104: "Запрос содержит синтаксическую ошибку - $(RETURN_CODE)": continue
                   +100: "<i>Увы. На сервере нет информации удовлетворяющей ваш запрос</i>": continue
                   +default : "<i>Увы. Что-то в вашем запросе есть порочное</i> - $(RETURN_CODE)" : continue
                   %}
%}

Здесь ответ сервера через внутреннии переменные (V1,V2...) встраивается в HTML код генерируемой страницы.
Как видите хоть и слегка громоздкий, но все же вполне понятный  и  работающий  пример.

Ссылки по теме

http://www-4.ibm.com/software/data/net.data/
http://www.citforum.ru/seminars/cbd99/db2_02.shtml
http://www.hermitage.ru
http://udb.fcn.ru/cgi-bin/db2www/image.d2w/frame
http://udb.fcn.ru/cgi-bin/db2www/bes.d2w/frame
Joseph Shrago

---
Интересные ссылки:

---

---
Комментариев к странице: 0 | Добавить комментарий
---
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов
(C) Russian Underground/2