Rt

Rt (jandcode.utils.rt.Rt) - это древовидная структура данных, где каждый узел дерева имеет имя, атрибуты, дочерние элементы и предка.

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

<root>
    <field>
        <sys attr1="1"/>
        <number parent="field/sys" title="Int"/>
        <long parent="field/number" title="Long"/>
        <int parent="field/number" title="Int"/>
        <string parent="field/sys" title="String" size="20"/>
    </field>
    <table>
        <sys title="SysTable"/>
        <id parent="table/sys">
            <field>
                <id parent="field/long" title="Id"/>
            </field>
        </id>
        <tab1 parent="table/sys" title="Table1">
            <field>
                <name parent="field/string" title="Name" size="60"/>
            </field>
        </tab1>
        <tab2 parent="table/tab1" title="Table2">
            <field>
                <name size="100"/>
                <name2 parent="field/string" title="Name"/>
            </field>
        </tab2>
    </table>
</root>

В этом примере описан объект с именем root, который имеет дочерние объекты field, table. В свою очередь объект field имеет дочерние sys, string, int и т.д.

Имена атрибутов и узлов - регистронезависимые.

Точка допустима в имени узла и имени атрибута.

Имена дочерних узлов (в пределах одного родителя) должны быть уникальны.

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

field/string
table/tab2/field/name2

Атрибут parent интерпретируется особым образом. В нем указывается путь объекта rt, который является предком для этого. Если такой атрибут присутствует, то поиск значения атрибута и дочерних элементов осуществляется вверх по иерерхии, начиная с искомого. Первый найденный элемент будет возвращен.

Программный интерфейс

Создание нового корневого объекта Rt:

Rt root = new RtRoot()

Для доступа к значениям атрибутов используются методы getValue/setValue. В качестве параметра используется:

  • attribute_name - значение атрибута attribute_name объекта
  • path:attribute_name - значение атрибута attribute_name у объекта по пути path

Например:

root.getValue("field/string:title")    // => String

Rt t1 = root.findChild("field/string")
t1.getValue("title")                   // => String

Формат XML

Для xml-файлов, которые написаны для хранения rt, используется расширение .rt.

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

Если узел имеет атрибут name, то значение атрибута name интерпретируется как имя дочернего узла, который описывается этим тегом. Например:

<root>
    <table name="Tab1">
        <field name="f1" title="F1"/>
        <field name="f2" title="F1"/>
    </table>
</root>

эквивалентно:

<root>
    <table>
        <Tab1>
            <field>
                <f1 title="F1"/>
                <f2 title="F1"/>
            </field>
        </Tab1>
    </table>
</root>

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

<root>
    <path>
        <i value="c:/temp"/>
        <i value="d:/temp"/>
    </path>
</root>

Текст узла

Если узел имеет текст, то он сохраняется в атрибуте text:

<root>
    <node>TEXT VALUE</node>
</root>

эквивалентно:

<root>
    <node text="TEXT VALUE"></node>
</root>

Документирующий коментарий

Если коментарий начинается с символа @, то он сохраняется в атрибуте comment того узла, внутри которого был встречен:

<root>
    <node><!--@ COMMENT VALUE --></node>
</root>

эквивалентно:

<root>
    <node comment="COMMENT VALUE"></node>
</root>

Системные атрибуты

Атрибуты, имена которых начинается с x- обрабатываются специальным способом.

x-root

Устанавливает для узла флаг «виртуального корня». Для таких узлов все parent дочерних элементов обрабатываются относительно этого «виртуального корня». А если не найдено тут, то относительно реального корня. Используется для выделения частично независимых узлов в rt:

<root>
    <node x-root="true"/>
</root>

Системные узлы

Узлы, имена которых начинаются с x- обрабатываются особым способом.

x-include

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

Атрибуты:

  • path - путь до включаемого файла относительно текущего загружаемого. Может включать „*“ для загрузки группы файлов
  • recursive - по умолчанию=false. При значении true - если в path есть „*“, то файлы рекурсивно ищутся в дочерних каталогах указанного пути.
  • required - по умолчанию=true. При значении true - если файл не найден, генерируется ошибка. Иначе ошибка игнорируется.
  • rtpath - если указан, рассматривается как путь уже загруженного объекта, содержимое которого накладывается на узел (и атрибуты и дети), внутри которого объявлена директива. Накладывается не только сам узел, указанный в атрибуте, но и все его предки. Раскрытие при наложении не производится.
  • module - если указан, рассматривается как java-пакет, в котором должен лежать файл module.rt, который и загружается. Эквивалентно загрузке файла res:MODULEPATH/module.rt.
  • plugin - если указан, рассматривается как включение плагина загрузки в текущий узел. Т.е. выполняется метод плагина jandcode.utils.rt.IRtPlugin#handleInclude в контексте текущего узла.

Пример:

<root>
     <x-include path="data/*.rt" recursive="true"/>
     <table name="Abonent">
         <x-include rtpath="includes/datatable"/>
     </table>
</root>

Пример загрузки модулей:

<root>
     <x-include module="myapp.module1"/>
     <x-include module="myapp.module2"/>
</root>

x-module

Определение модуля.

Модулем является java-пакет, в котором есть файл module.rt и системный узел x-module должен быть использован только в этом файле.

Атрибуты:

  • name - имя модуля. Должно совпадать с именем java-пакета, где расположен module.rt

Дочерние узлы:

  • depend - зависимость модуля. В атрибуте name указывается имя модуля, который должен быть включен до этого.

Пример:

<!-- file: d:/project/myproject/src/myproject/mymodule/module.rt -->
<root>
    <x-module name="myproject.mymodule" any_attr="any_value">
        <depend name="jandcode.app"/>
        <depend name="jandcode.dbm"/>
        <depend name="jandcode.web"/>
    </x-module>
</root>

Узел отправляется на обработку всем плагинам загрузки (описанных в узлах x-plugin) в метод handleSysChild. После обработки, узел модуля сохраняется как дочерний узла module:

<root>
     <module>
        <myproject.mymodule any_attr="any_value">
            <depend>
                <jandcode.app/>
                <jandcode.dbm/>
                <jandcode.web/>
            </depend>
        </myproject.mymodule>
     </module>
</root>

x-parentexpander

Определение правила раскрытия сокращенных значений атрибута parent. Атрибуты:

  • path regex для пути узла
  • parentvalue regex для значения атрибута parent
  • replace на что заменять

Пример:

<root>
   <x-parentexpander
       path=".*domain/(.*?)/field/(.*?)"
       parentvalue="^(\w*)$"
       replace="field/$1"/>
</root>

Если для значения parent не определено правило и в нем нет /, то тогда используется значение имя_владельца/значение_parent.

Если значение parent начинается с /, то раскрытие для него не производится. Считается что указан явный абсолютный путь.

x-attr

Определение атрибута с многострочным значением. В атрибуте name имя атрибута, в тексте узла - значение атрибута. Пример:

<root>
   <mynode attr1="a1">
       <x-attr name="attr2">
         a2-1
         a2-2
       </x-attr>
   </mynode>
</root>

x-plugin

Определение плагина загрузки.

Плагином является класс, который участвует в процессе загрузки и может изменять узел, внутри которого он был включен. Включение плагина в процесс загрузки осуществляется через тег x-include, в атрибуте plugin которого указывается имя включаемого плагина.

Атрибуты:

  • name - имя плагина. Должно быть уникальным среди всех плагинов. Можно не указывать, тогда имя генерируется. Плагины без имени нельзя будет использовать в x-include
  • class - имя класса плагина загрузки. Должен реализовывать интерфейс jandcode.utils.rt.IRtPlugin. Если не указан, то должен быть указан атрибут path.
  • path - если указан и не указан атрибут class, то подразумеватся специальный плагин, который будет включать в узел файл(ы), указанный в этом атрибуте
  • остальные - атрибуты, которые передаются экземпляру плагина и используются им по своему усмотрению

Дочерние узлы:

  • depend - зависимость плагина. В атрибуте name указывается имя плагина, который должен быть использован до этого.

Подстановки

В значениях атрибутов и текста узлов раскрываются подстановки #{VAR}, где VAR:

  • path - абсолютный путь до текущего файла
  • pathup:FILENAME - абсолютный путь вверх до каталога, содержащего файл FILENAME, начиная с текущего каталога
  • pathprop:PROPNAME - значение из UtFile.getPathprop(String, String), начиная с текущего каталога
  • rt:RTPATH - значение по пути RTPATH из загруженной к этому времени rt
  • остальные - значение из System.getProperties()

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

  • текущий файл - файл, в котором встретилась подстановка
  • текущий каталог - каталог, в котором лежит файл в котором встретилась подстановка

Пример:

<root>
    <!-- attr1 равен пути, в котором лежит текущий файл -->
    <n1 attr1="#{path}"/>

    <!-- если текущий файл лежит в каталоге d:\projects\myproject\myconfig
         и существут каталог d:\projects\myproject\dir\subdir
         то значение attr1 равно d:\projects\myproject\dir\subdir\cfg1.rt
     -->
    <n2 attr1="#{pathup:dir/subdir}/cfg1.rt"/>

    <!-- attr1 равен пути в временном каталоге d:\temp\myproject\myfile.txt -->
    <n3 attr1="#{java.io.tmpdir}/myproject/myfile.txt"/>

    <config>
        <node1 value="123"/>
    </config>

    <!-- attr1 равен 123 -->
    <n4 attr1="#{rt:config/node1:value}"/>

</root>