На фоне роста популярности операционной системы Linux наблюдается острая нехватка развитых инструментальных средств. Важное качество таких систем — возможность создания и использования переносимых приложений, которые могли бы одинаково функционировать на нескольких программных и аппаратных платформах.
Linux продолжает на ряде направлений теснить Windows, однако нехватка развитых инструментальных средств сдерживает продвижение этой открытой среды. Учитывая распространенность Windows, такие инструментальные системы должны позволять создавать и использовать переносимые приложения, которые могли бы одинаково функционировать на нескольких программно-аппаратных платформах. Речь идет не только о Linux и Windows для Intel: достаточно широко используются Unix-подобные системы и другие аппаратные платформы. Большинство развитых систем категории RAD (rapid application development — «быстрая разработка приложений») ориентировано на Windows (Power Builder, Visual Basic, Delphi и т.д.). Исключением является, пожалуй, только система Kylix от Borland, но она предназначена для создания «собственных» (native) приложений под Linux и обеспечивает переносимость на уровне правильно написанных исходных текстов. Не всегда выглядит оправданным и использование языка Java ввиду немалой требовательности его виртуальной машины к ресурсам.
Данная проблема имеет особое звучание в России в свете курса на приоритетное развитие отечественных ИТ и использование в некоммерческих структурах лицензированных и сертифицированных программных средств [1]. Существует несколько отечественных разработок в области операционных систем, причем все они в основном являются разнообразными клонами Unix, однако применение таких систем невозможно без соответствующих средств разработки. В такой ситуации весьма актуальной стала задача разработки адекватного отечественного инструментария. Система LAB (Linter Application Builder) российской компании «Релэкс», создавшей реляционную СУБД «Линтер» [2], — один из немногих отечественных инструментариев быстрой разработки переносимых приложений для Unix и Windows.
Исходной целью проекта LAB [3] было создание удобного средства разработки для СУБД «Линтер», которое бы наиболее полно и эффективно использовало возможности этой СУБД. Впоследствии в LAB были реализованы компоненты для доступа к данным через ODBC, чтобы дать разработчикам возможность использования других коммерческих и свободно распространяемых реляционных СУБД: Oracle, Microsoft SQL Server, MySQL и т.п. Среда разработки и созданные на ее основе приложения переносимы, причем приложение, построенное на одной платформе, может исполняться на другой без дополнительных доработок и перекомпиляции. Достигается это за счет использования технологии компиляции приложений в байт-код (аналогично Java).
Архитектура LAB
Основу LAB составляют (рис. 1):
- расширяемая объектно-ориентированная библиотека компонентов для построения приложений;
- средства объектно-ориентированного языка программирования;
- интегрированная среда разработки;
- исполняющая подсистема, обеспечивающая исполнение скомпилированного приложения на требуемой программно-аппаратной платформе.
Компоненты — «кирпичики», из которых складывается приложение. В LAB все компоненты подчиняются ряду общих требований.
- Экземпляр каждого компонента всегда принадлежит экземпляру родительского компонента (за исключением компонента-приложения). Приложение, тем самым, представляет собой иерархию экземпляров компонентов.
- В рамках одного родителя все экземпляры имеют уникальные имена, так что всегда можно найти компонент, зная его символическое "маршрутное имя".
- Все экземпляры каждого компонента имеют сходные характеристики, конкретные значения которых устанавливаются при помощи механизма свойств. Значения свойств могут быть представлены простыми типами данных, такими как числа и цепочки символов, а также сложными объектами, для которых сам компонент может предоставлять подходящий способ (диалог) для установки значений.
- Для компонентов определен набор методов, посредством вызова которых можно воздействовать на поведение компонента.
- В жизни каждого компонента могут происходить разнообразные события, на которые может реагировать любое число других компонентов, зарегистрировавших свой метод-обработчик (концепция подписки на события).
- Компоненты наследуются; более специализированный вариант компонента может иметь дополнительные свойства, методы, события и переопределять существующие.
- Несколько подчиненных друг другу компонентов можно рассматривать как новый, составной компонент со своими дополнительными свойствами, методами и событиями.
Стандартная библиотека включает компоненты, реализующие методы доступа к данным реляционной СУБД, организации пользовательского интерфейса, генерации всевозможных отчетов и т.д.
Иерархия компонентов с их свойствами и обработкой событий представляется в виде кода на объектно-ориентированном языке, в котором компонент соответствует классу, экземпляр компонента — объекту, а свойства и методы — атрибутам и методам класса и объекта. Таким образом, объектно-ориентированный язык используется как средство представления иерархии компонентов и манипулирования ими для реализации всей необходимой логики приложения. LAB генерирует полный код приложения на объектно-ориентированном языке; поэтому исходных текстов приложения и библиотеки компонентов достаточно для того, чтобы скомпилировать и выполнить приложения. Все необходимые функции системы реализуются внутри компонентов и исходного текста, который их использует.
Разработка в LAB во многом упрощается за счет того, что сами компоненты стандартной библиотеки достаточно выразительны и выполняют большую работу внутри себя. Поскольку стандартные компоненты полностью реализованы на C++ минимизируются потери производительности приложения, собственный компилированный код которого интерпретируется виртуальной машиной. Реализация стандартных компонентов основана на Win32 API в среде Windows и библиотеке Qt в среде Unix.
Интегрированная среда разработки позволяет визуальными средствами формировать иерархию компонентов (в частности, пользовательский интерфейс приложения) и сохранять результаты разработки в виде кода на объектно-ориентированном языке, а также компилировать и отлаживать приложение (рис. 2).
В состав интегрированной среды входят:
- палитра компонентов;
- окно проекта;
- инспектор компонентов, позволяющий просматривать и изменять свойства компонентов и назначать каждому событию компонента список обработчиков из числа любых других компонентов приложения;
- визуальный редактор форм;
- генератор и редактор исходного текста;
- анализатор исходных текстов, позволяющий в визуальной среде воссоздать структуру и свойства компонентов приложения;
- модули-"мастера", ускоряющие процесс разработки за счет реализации набора типовых действий;
- средства запуска компилятора исходных текстов;
- средства запуска исполняющей подсистемы;
- мастера для создания новых компонентов и подготовки инсталляционных пакетов с целью последующей установки приложения на выбранной платформе.
Графический интерфейс приложения
Графический интерфейс реализуется посредством визуальных компонентов, которые располагаются внутри других визуальных компонентов (контейнеров). Одной из отличительных особенностей контейнерных компонентов является их способность автоматически управлять расположением и видимостью вложенных элементов внутри себя на основе функций менеджера компоновки. Для этого используются свойства выравнивания вложенного компонента, позволяющие задать желаемое расположение компонента внутри контейнера и требуемые размеры (в абсолютных единицах или в процентах от размера объемлющего контейнера). Особые возможности компоновки предоставляет компонент CGridPanel, позволяющий задать расположение вложенных компонентов относительно одной или нескольких ячеек его сетки и реализующий тем самым аналог GridBagLayout — самого мощного типа менеджера компоновки, имеющегося в языке Java.
Общие свойства, методы и события визуальных компонентов помогают реализовать единообразный графический интерфейс, сохранив вместе с тем собственные отличительные черты каждого из них.
Стандартные визуальные компоненты включают все необходимое для реализации полноценного графического интерфейса: контейнеры, элементы для ввода и отображения данных и источники команд приложению. Кроме визуальных компонентов в качестве источников команд могут выступать меню, панель инструментов и акселераторы (таблицы «горячих» клавиш), которые создаются в интегрированной среде разработки визуально, при помощи соответствующих мастеров.
Работа с базами данных
При создании LAB особое внимание уделялось средствам разработки приложений, работающих с реляционными базами данных. Основной абстракцией доступа к данным является понятие источника данных — невизуального компонента, обладающего следующими свойствами:
- для источника данных определена структура - перечень элементов данных, каждый со своим логическим именем и типом данных;
- каждый элемент структуры данных может быть либо связан с колонкой в базе данных, либо вычисляться при помощи произвольного алгоритма, либо просто хранить информацию в оперативной памяти;
- активный источник данных содержит несколько строк, каждая из которых содержит конкретные значения всех элементов данных;
- для источника данных определено понятие текущей строки, причем можно устанавливать текущую строку в произвольном порядке, перемещаясь по строкам в любом направлении; это реализуется либо непосредственно средствами СУБД, если она поддерживает скроллируемые курсоры, либо кэшированием данных в памяти;
- к источнику данных может быть привязано любое число визуальных компонентов, при этом однострочные компоненты всегда автоматически показывают актуальные значения из текущей строки, а многострочные - данные для всех строк и текущую строку; любые изменения данных и положения текущей строки автоматически отражаются в связанных компонентах;
- данные в любой строке могут быть изменены путем вызова соответствующих методов источника данных или в результате изменений содержимого визуальных компонентов, которые привязаны к источнику;
- все изменения кэшируются в памяти до тех пор, пока не поступит команда на фиксацию изменений в базе данных или на откат;
- у источников данных есть ряд событий, позволяющих определять алгоритмы вычисления значений полей, реакции на изменения данных, обработки ошибок и т.д.
Отличительная особенность механизма работы с данными — возможность привязать любой визуальный элемент к любому источнику данных, независимо от того, выступает ли в таком качестве СУБД, источник ODBC или память. Это позволяет использовать одну форму как для временного ввода информации, так и для непосредственной работы с базой данных. Благодаря этому в LAB нет нескольких семантически повторяющихся наборов элементов управления, как, скажем, в Delphi и Kylix. Одни и те же элементы управления могут использоваться с разной целью, что определяется привязкой компонента к конкретному источнику данных. Данные из источников могут отображаться различными визуальными компонентами. Например, CTreeView будет автоматически строить дерево по структуре данных, содержащей дополнительное поле LEVEL (уровень иерархии).
Для того чтобы упростить работу с взаимосвязанными сущностями модели данных приложения, механизм для работы с базой данных в LAB включает возможность связки произвольного числа источников данных при помощи специального компонента «связь». При этом выбирается главный и подчиненный источники и соответствие списков ключевых полей для связи. При смене текущей строки в главном источнике данных, в подчиненном источнике автоматически происходит фильтрация строк. В простейшем случае, два источника данных и связь реализуют схему master — detail. Однако этим возможности не ограничиваются. Источник данных может быть связан с любым числом других источников, и все эти связи обрабатываются автоматически.
Разработчики прикладных систем часто сталкиваются с ситуацией, когда в форме приложения вместо данных основного запроса должны показываться другие, выбираемые из внешней справочной таблицы по простому или составному внешнему ключу. Кроме того, при вводе данных пользователю должен предоставляться интерфейс, позволяющий выбрать информативное значение из внешней таблицы так, чтобы в основной источник данных вставлялись соответствующие значения ее первичного ключа. Во многих мощных средствах быстрой разработки имеется соответствующий тип компонентов — поисковые поля (lookup field). Есть такая возможность и в LAB, причем в нескольких вариантах.
Чтобы выбрать данные из внешних таблиц, можно выполнить несколько простых поисковых SELECT-запросов для каждой строки основного источника данных, содержащей несколько внешних ссылок. Если таких ссылок немного, более оптимальным будет выполнение одного SELECT-запроса с соединением по всем внешним справочным таблицам так, чтобы необходимые информативные поля уже содержались в источнике данных. Компоненты LAB позволяют реализовать любой из этих вариантов, а также обеспечить стандартную форму с контекстным поиском для выбора справочного значения.
При желании разработчик приложения может переопределить форму выбора, создав свою собственную форму, реализующую произвольный интерфейс (например, иерархический выбор в виде дерева или нескольких взаимосвязанных списков). Можно использовать одну и ту же форму выбора многократно, если структура выбираемых справочных данных повторяется.
Приложения LAB могут работать не только с данными обычных типов, но и с большими двоичными объектами (LOB, CLOB, BLOB, LONG RAW и т.д.). При этом можно сохранять и отображать изображения в форматах JPEG, PNG, BMP; отображать и редактировать большие текстовые поля; хранить в BLOB-столбцах любую двоичную информацию, содержимое любых файлов.
Вынесение большинства общих функций источников данных на абстрактный уровень дает гибкость в реализации приложений, в которых все особенности собственно работы с СУБД вынесены на уровень конкретных компонентов — источников данных. Среди конкретных компонентов: работа с СУБД «Линтер» через собственный CALL-интерфейс; работа с реляционными СУБД через ODBC в среде Windows или Unix; работа с памятью.
Компоненты для работы с реляционными СУБД могут использовать, в том числе, такие возможности, как предварительно транслированные запросы, пакетное получение/изменение данных и исполнение хранимых процедур. Ведется работа над такими новыми возможностями механизма взаимодействия с базой данных, как фильтрация данных внутри источника данных (на клиенте) и использование составных источников данных, в которых отдельный элемент данных не обязан быть атомарным, а может представлять собой еще один, вложенный источник.
Генераторы отчетов
Одной из особенностей LAB является наличие встроенных средств генерации отчетов разной сложности, доступных на любой платформе. Основой средств генерации отчетов в LAB является специальный компонент — отчет CReport, способный выводить на печать содержимое своих вложенных визуальных компонентов, перебирая строки некоторого источника данных. В простейшем случае CReport позволяет формировать табличные отчеты, привязываясь к источнику данных, поставляющему нужную информацию.
Каждая область может содержать несколько визуальных компонентов с данными и несколько графических примитивов (например, линии и прямоугольники), используемых для формирования границ таблицы (графические примитивы могут пересекать несколько областей). Для более удобной привязки визуальных компонентов к данным можно использовать мастер связи с источником данных. Он же позволяет вставить в отчет поля, выводящие номер страницы и промежуточные или итоговые суммы по данным. Последняя функция реализована путем генерации обработчиков специальных событий, которые вызываются компонентом до и после печати каждой области. Обработчику этих событий доступно много методов, позволяющих влиять на видимость отдельных компонентов или целых областей в отчете, получать информацию о промежуточных и итоговых суммах, управлять разбиением на страницы и т.д.
CReport поддерживает возможность группировки данных в отчете и вывода сводной информации о группах и промежуточных итогах по группе. Уровень вложенности групп не ограничен.
Для компонента-отчета может быть указан второй источник данных, который обеспечит расширение отчета по горизонтали. Как и в вертикальном, в горизонтальном разбиении можно задавать области печати заголовков и концов отчета, страницы, группы и тела отчета. Совмещение вертикального и горизонтального разбиения отчета по двум источникам данных обеспечивает возможность генерации отчетов с переменным числом строк и колонок. Для редактирования формы отчетов используется стандартный визуальный редактор форм.
Формирование отчета выполняется при помощи специальных методов компонента CReport. При этом существуют следующие возможности: предварительный просмотр отчета на экране; печать отчета на принтере; экспорт отчета в форматы RTF, HTML, текстовый файл и PDF. Визуально разработанные отчеты могут использоваться не только в клиентских приложениях, но и, например, как часть Web-приложения, функционирующего на сервере под управлением Unix или Windows.
Объектно-ориентированный язык АТОЛЛ
Создание языка АТОЛЛ преследовало несколько целей: получить простой в освоении и реализации язык для разработки приложений; обеспечить их переносимость; снизить требования к ресурсам по сравнению с Java.
Основной единицей компиляции языка является класс, который может содержать переменные и методы — члены класса, имеющие различную область видимости. Каждый класс может быть унаследован от одного родительского класса. При этом методы дочернего класса могут полиморфно перекрывать методы родительского.
Одной из отличительных черт языка АТОЛЛ является организация распределения памяти под динамические объекты. Ссылка на созданный объект может сохраняться в одной или нескольких переменных. Объект может быть удален двумя способами: в результате исчезновения всех ссылок на него (автоматическая сборка мусора) или явно, при помощи операции destroy.
Никакие переменные, процедуры или функции в языке не могут существовать за пределами классов. Исполнение приложения начинается с автоматического создания главного объекта приложения (имя его класса задается извне виртуальной машины) и вызова у него метода main, через который передаются аргументы приложения.
Сами классы и методы могут содержать константы и переменные скалярных типов, массивы и ссылки на другие объекты. Как язык, ориентированный на RAD-системы, АТОЛЛ поддерживает в качестве скалярных типов целые и дробные числа, цепочки символов, перечисления, логический тип и дату-время. Для всех этих типов определены различные унарные и бинарные операции (так, можно конкатенировать цепочки символов или прибавить к дате определенное количество дней). Кроме того, переменная любого типа может содержать значение NULL.
Для реализации процедурной логики приложения каждый метод может содержать последовательно выполняющиеся операторы, ветвления (if, case), циклы (while, for). Для обработки ошибок предусмотрен механизм возбуждения и перехвата исключений.
Язык АТОЛЛ включает библиотеку стандартных функций, позволяющих выполнить разнообразные действия от преобразования значений различных типов и вычисления математических функций до динамического создания объекта по имени класса. Последняя функция позволяет приложению создавать классы, о которых ничего не известно на момент компиляции приложения, кроме одного из его базовых классов. Такая функциональность возможна благодаря тому, что каждый класс АТОЛЛ компилируется в байт-код, содержащий необходимую информацию о классе и исполняемый на любой платформе. Полная переносимость достигается, в частности, благодаря хранению всех строк в формате UTF-8, что позволяет корректно получить из байт-кода строки в нужной кодировке или в представлении Unicode.
При исполнении программы виртуальная машина АТОЛЛ ищет байт-коды классов в отдельных файлах, а также в архивах (библиотеках), содержащих байт-коды нескольких классов. Соответственно, среда разработки LAB позволяет создавать несколько библиотек классов в рамках одного проекта и использовать их в этом и других проектах. Виртуальная машина включает также развитые функции отладки.
Расширение библиотеки компонентов
Стандартную библиотеку компонентов можно расширить двумя способами (рис. 3):
- объявить некоторую совокупность компонентов новым компонентом;
- добавить компонент, реализованный в качестве внешней разделяемой (динамически подключаемой) библиотеки.
Первый способ позволяет повторно использовать функциональные и визуальные блоки, созданные в одной форме, при разработке других форм и проектов. Второй способ позволяет расширить возможности LAB, реализовав на уровне внешних компонентов функциональность, которая не реализована в стандартных средствах LAB (например, использование сетевых протоколов).
Первый способ реализуется в интегрированной среде LAB при помощи мастера новых компонентов. Любой компонент, созданный в рамках текущего проекта, может стать основой для нового компонента.
Мастер новых компонентов создает описание и исходный текст класса нового компонента, который помещается в репозиторий пользовательских компонентов — каталог, где хранятся все пользовательские компоненты, доступные в палитре компонентов интегрированной среды LAB. Среда может настраиваться на работу с различными репозиториями, а сами компоненты могут переноситься из одного репозитория в другой.
Внешние компоненты LAB реализуются при помощи интерфейса, разработанного для языка C++. Пользовательский компонент описывается в виде класса C++, производного от одного из базовых классов библиотеки LAB и включающего декларацию и реализацию свойств, методов и событий. Для удобства используются специальные макроопределения. Один или несколько таких классов компилируются в динамически подключаемую библиотеку, из которой LAB извлекает описание компонентов.
В настоящее время разрабатывается компилятор из языка IDL в интерфейс внешних компонентов LAB. Наличие таких средств позволит интегрировать приложения LAB в распределенную среду, поддерживающую, например, спецификации CORBA.
Перспективы LAB
Кроме наращивания функциональности компонентов, среды разработки и языка, LAB будет также развиваться по нескольким крупным направлениям:
- включение в среду разработки средств моделирования и проектирования схемы данных на основе нотации UML;
- создание компонентов и соответствующих расширений для разработки Internet-приложений в среде Web-серверов Apache и Microsoft IIS; эти средства позволят совместить простоту доступа к данным и гибкие возможности формирования интерфейса Internet-приложения на основе технологий XML/XSL;
- поддержка C++ как альтернативы языку АТОЛЛ;
- интеграция приложений LAB в распределенную компонентную среду, поддерживающую CORBA и другие спецификации.
Используя инструментарий LAB, разработчики могут быстро создавать переносимые приложения с графическим интерфейсом, использующие реляционные СУБД, поддерживающие язык запросов SQL для доступа к данным. На данный момент поддерживаются платформы Windows, Linux, FreeBSD, Intel/Solaris и SPARC/Solaris.
Литература
[1] «Доктрина информационной безопасности Российской Федерации». // Российская газета, 2000, № 187, 28 сентября
[2] В. Максимов, Л. Козленко, С. Маркин, И. Бойченко, «Защищенная реляционная СУБД ?Линтер?». // «Открытые системы», 1999, № 11-12
[3] А.В. Эксаревский, В.Е. Максимов, «LAB — отечественный инструмент быстрой разработки переносимых приложений». // Технология клиент-сервер, 2001, № 1
Алексей Эксаревский (ave@relex.ru) — сотрудник компании «Релэкс» (Воронеж).