Pzl-Компонента
Необходимые условия признания класса pzl-компонентой
Любой класс, порождающий объекты (имеющий интерфейс), может быть признан компонентой, если
- Имя интерфейса и имя класса различаются;
- Интерфейс класса поддерживает интерфейс pzlComponent;
- Интерфейс класса включает декларации констант:
- componentID_C с типом pzlDomains::entityUID_D
- componentAlias_C с типом string
- componentRunAble_C с типом core::booleanInt
- componentMetaInfo_C с типом core::namedValue*.
- сomponentDescriptor_C с типом pzlDomains::pzlComponentInfo_D;
- Декларация класса содержит единственный конструктор new(object ИспользуемыйОбъект);
- Имплементация класса наследует от класса pzlComponent;
- Пакетный файл деклараций класса (.PH) включает файл "System\Packs\pzlcomponent\pzlcomponent.ph".
Ниже приведены фрагменты различных составляющих компоненты, удовлетворяющей перечисленным выше условиям.
Декларация класса содержит коструктор new(...) и имя интерфейса отличается от имени класса. При этом класс содержит единственный конструктор new:(object UsingObject)
class сomponentExample:iComponentExample constructors new:(object UsingObject). end class
Интерфейс класса содержит квалификатор supports pzlComponent и декларацию констант
- componentID_C
- componentAlias_C
- componentRunAble_C=b_True
- componentMetaInfo_C
- componentDescriptor_C
interface iComponentExample supports pzlComponent open core constants componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo ( componentAlias_C, componentID_C, componentRunAble_C, componentMetaInfo_C ). componentID_C:pzlDomains::entityUID_D=pzlDomains::str("ComponentExample"). componentAlias_C="ПримерКомпоненты". componentRunAble_C=b_True. componentMetaInfo_C:namedValue_List=[]. predicates show:(). end interface iComponentExample
Имплементация класса содержать директиву наследования inherits pzlComponent и содержит клаузу для конструктора new(UsingObject)
implement componentExample inherits pzlComponent clauses new(UsingObject):- ... clauses show():- ... end implement componentExample
Файл деклараций пакета ComponentExample.PH содержит директиву включения файла PzlComponent.ph
#requires ... #include @"System\Packs\pzlcomponent\pzlcomponent.ph" #include @"pfc\core.ph"
Интерфейс pzlComponent
Интерфейс pzlComponent соответствует наследуемому pzl-Компонентой классу pzlComponent и делает класс pzl-компонентой, связывая ее с другими частями pzl-системы. Кроме того, этот интерфейс позволяет получать часть информации о компоненте.
В частности следующие предикаты поддерживаются содержательно pzl-системой
- getContainerVersion() - возвращает информацию о версии контейнера, в котором данная компонента содержится
- getContainerName() - возвращает информацию об имени файла-контейнера, в котором содержится данная компонента
- getClassInfo(className,classVersion) - возвращает информации об имени и версии класса pzlComponent
Остальные предикаты интерфейса:
- getComponentVersion()-> string
- getComponentID() -> entityUID_D
- getComponentAlias() -> string
- getComponentMetaInfo() -> namedValue*
- release
должны быть определены пользователем в имплементации базового класса компоненты. В противном случае генерируют исключения при обращении.
Предопределенные константы интерфейса pzl-компоненты
Константа componentID_С
Константа сomponentID_С определяет идентификатор компоненты, который (по-возможности) должен быть уникальным в глобальном смысле. То есть две программы в глобальном информационном пространстве (не говоря уже об одном копьютере), использующие компоненты с одним и тем же идентификатором могут быть уверены, что они используют точно одну и ту же pzl-компоненту. Этого можно добиться, если использовать способ, аналогичный способу, применяемому Microsoft для идентификации COM-компонент. Для этого в pzl-технологии используется структура с функтором uid:
uid( core::unsigned32 Unsigned, core::unsigned16 Short1, core::unsigned16 Short2, core::unsigned8 Byte1, core::unsigned8 Byte2, core::unsigned8 Byte3, core::unsigned8 Byte4, core::unsigned8 Byte5, core::unsigned8 Byte6, core::unsigned8 Byte7, core::unsigned8 Byte8).
что, на самом деле является полным аналогом структуры core::nativeGuid системы Visual Prolog. Идентификатор ComponentID используется в двух случаях:
- Он является идентификатором, под которым в реестре Windows или в файле регистрации приложения записывается регистрационная информация о компоненте
- Он является идентификатором, под которым эта компонента зарегистрирована в pzl-контейнере
Поскольку идентификатор в форме uid является громоздкой последовательностью цифр и букв, то применять его в процессе освоения технологии неудобно. С целью упрощения процесса освоения имеется вторая версия представления идентификатора - строковая - в форме str(string). Естественно, уникальность строкового представления обеспечить крайне трудно, но в процессе освоения, можно пожертвовать глобальной уникальностью и контролировать только уникальность идентификатора на данном компьютере. В результате мы получаем две альтернативные формы представления идентификатора в объявлении домена entityUID_D:
entityUID_D= str(string); uid(unsined16,...).
Константа componentAlias_C (Условное имя)
Наряду с уникальным идентификатором, pzl-технология предоставляет воможность присвоить каждой компоненте условное, содержательное имя, являющееся строкой символов. Для этого выбранное имя должно быть присвоено константе ComponentAlias_C. Однако уникальность Условного Имени (Alias) не является жестким требованием.
Так, Вы можете создать несколько текстовых редакторов с различными свойствами, которые поддерживают одни и те же интерфейсы. Каждый из этих текстовых редакторов будет иметь уникальный идентификатор типа entityUID_D и, возможно каждый из них будет иметь свое имя базового класса. Но все они могут иметь одно и то же условное имя "Текстовый Редактор". Тогда Ваша программа (подчеркнем, не зная имени класса), может при создании экземпляра pzl-компоненты использовать имя "Текстовый Редактор" и будет создаваться экземпляр той компоненты, которая в данный момент зарегистрирована на Вашем компьютере. Перерегистрировав новый редактор, вместо старого, Ваша программа будет использовать новый редактор с другими свойствами.
Однако не следует забывать, что все коллизии, связанные с возможной неуникальностью условных имен, должны разрешаться программистом.
Условное имя может использоваться различными средствами pzl-технологии для идентификации компонент как на экране, так и в сообщениях об ошибках.
Константа componentRunable_C
Эта константа сообщает о возможности запуска данной компоненты путем вызова предиката spbRun:(string UserInfo). Предикат spbRun декларируетс в одноименном интерфейсе spbRun.
Соответственно, компонента должна поддерживать интерфейс spbRun, если возможность вызова предиката spbRun предусматривается.
Если интерфейс spbRun компонентой поддерживается, то константа componentRunable_C должна иметь значение core::b_true и core::b_false - если не поддерживается.
Предикат spbRun - это, по крайней мере, один предикат в pzl-компоненте, который может этой компонентой поддерживаться и имя этого предиката известно.
Предикат spbRun имеет единственный входной параметр UserInfo типа string, назначение которого определяется создателем компоненты.
Если данная компонента может быть вызвана с помощью предиката spbRun, это означает, что в приложении для данной компоненты всегда имеются условия, которые позволяют этой компоненте выполнить какую-то функциональную задачу.
Это несколько напоминает функцию раздела GOAL - точка начала работы программы, но в случае с предикатом spbRun этот предикат может быть вызван, а может быть и не вызван.
Если приложение основано на использовании графического пользовательского интерфейса (pfc/GUI или pfc/VPI), то возможность запуска компоненты предикатом spbRun может означать, что будет создана какая-то форма на экране и эта форма далее позволит сделать что-то значимое (не обязательно полезное).
Если пользовательский интерфейс не используется, то предикат spbRun может быть использован и для других целей по усмотрению программиста.
Предикат spbRun:(string UserInfo) объявлен в интерфейсе spbRun, где он является единственным. Если компонента поддерживает интерфейс spbRun, то это декларируется стандартным способом:
interface componentInterface supports pzlComponent supports spbRun constants ... ComponentRunable_C = b_true. ... end interface componentInterface
либо один из интерфейсов, поддерживаемых базовым интерфейсом компоненты, должен поддерживать интерфейс spbRun, как показано ниже
interface componentInterface supports pzlComponent supports textEditor constants ... componentRunable_C = b_true. ... end interface componentInterface interface textEditor supports spbRun ... end interface textEditor
Константа componentMetaInfo_C
Константа componentMetaInfo_C имеет тип core::namedValue* и представляет список именованных данных, относящихся к данной компоненте - метаинформация о компоненте.
pzl-Система никак эту метаинформацию не обрабатывает, но при соотвествующем запросе к контейнеру данные этого списка доступны программисту.
Если метаинформация о компоненте отсутствует, то константа componentMetaInfo_C все равно должна быть определена и должна представлять пустой список.
constants componentMetaInfo_C = [].
Константа Описания Компоненты сomponentDescriptor_C
Константа сomponentDescriptor_C включает описания важнейших свойств компоненты перечисленные выше:
- ComponentID_C,
- ComponentAlias_C,
- ComponentRunable_C
- ComponentMetainfo_C
Константа сomponentDescriptor_C соответствует домену pzlDomains::pzlComponentInfo_D, объявленному в интерфейсном файле pzlDomains:
pzlComponentInfo_D=pzlComponentInfo ( string Alias, entityUID_D ComponentID, booleanInt Runable, core::namedValue_List UserDefinedInfo ).
Пример описания констант pzl-компоненты
В реальной компоненте константы описания могут выглядеть так:
constants componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo ( componentAlias_C, componentID_C, componentRunAble_C, componentMetaInfo_C ). componentID_C:pzlDomains::entityUID_D=pzlDomains::str("ComponentExample"). componentAlias_C="ПримерКомпоненты". componentRunAble_C=b_True. componentMetaInfo_C:namedValue_List=[].
или так
constants componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo ( componentAlias_C, componentID_C, componentRunAble_C, componentMetaInfo_C ). componentID_C:pzlDomains::entityUID_D=pzlDomains::uid(0x5701809E,0x0453,0x43A2,0xB1,0x82,0x8F,0xAE,0x2A,0x6B,0xA5,0x63). componentAlias_C="PzlAboutDialog". componentRunAble_C=b_False. componentMetaInfo_C:namedValue_List= [ namedValue("CodeExporter",string("AboutExporter")) ].
Конструктор компоненты new:(object UsingObject)
Базовый класс pzl-Компоненты должен включать только один конструктор, имеющий формат new:(object UsingObject).
Здесь параметр UsingObject (что предполагает трактовку "С использованием объекта") не имеет никакого назначения и может быть использован автором pzl-Компоненты по своему усмотрению.
Например, в случае компоненты на базе GUI этот параметр может передавать объект типа window, соответствующий родительскому окну. Но если вызов конструктора в форме new(ParentWindow) автоматически преобразует тип window в тип object, то следует иметь в виду, что клауза конструктора, получит этот параметр именно как параметр типа object и непосредственное обращение к этому объекту невозможно.
Для обращения к объекту, переданному в виде параметра, необходимо привести параметр к типу, соответствующему возможному типу существующего объекта.
Например, в рассматриваемом случае с передачей объекта родительского окна для получения его высоты (height) надо привести объект ParentWindowAsObject в тип window:
clauses new(ParentWindowAsObject):- ParentWindow=convert(window,ParentWindowAsObject), WindowHeight=ParentWindow:getHeight(), ...
Особенности использования pzl-компонент как VIP-классов
Pzl-Компоненты, являясь обычными классами системы программирования Visual Prolog (VIP-классы), не требуют каких-либо специальных приемов программирования. Более того, при практическом программировании никакой разницы между использованием обычных VIP-классов и pzl-компонент нет. Тем не менее мы отметим здесь некоторые детали техники их созданиия и использования.
Создание pzl-компоненты
Создание pzl-компоненты возможно двумя способами:
- Стандартными средствами IDE (не рекомендуется)
- Специальными средствами pzl-технологии
Процедура создания pzl-компоненты средствами IDE не является рекомендуемой и приводится для разрешения коллизий в экстраординарных случаях
- Создать в проекте, являющемся pzl-контейнером новый класс в пакете, который будет всегда связан с этим классом
- При создании класса указать, что класс порождает объекты
- После создания создания класса вручную модифицировать код для обеспечения всех ранее
перечисленных требований
Компиляция проекта, содержащего созданную таким образом pzl-компоненту, может привести к генерации множества ошибок, если не "зарегистрирована" в проекте-контейнере.
Для регистрации pzl-компоненты в pzl-контейнере необходимо:
- В файле PzlConfig.i определить константу usePzl[ИмяКомпоненты]_C:boolean=true.
- В файле PzlConfig.pack в раздел % privately used packages добавить полное имя заголовочного файла пакета
#include @"ИмяФайлаКомпоненты.ph"
- В файле PzlConfig.pro:
- в список, возвращаемый предикатом getComponentIDInfo() добавить элемент вида
[ИмяБазовогоИнтерфейсаКомпоненты]::componentDescriptor_C
- добавить клаузу
- в список, возвращаемый предикатом getComponentIDInfo() добавить элемент вида
new([ИмяБазовогоИнтерфейсаКомпоненты]::componentID_C,Container)=Object:- !, Object = [ИмяБазовогоКлассаКомпоненты]::new(Container)
.
Обращения к pzl-Компоненте
Существуют три способа вызова создания экземпляра pzl-компоненты:
- путем вызова конструктора new(...)
- путем вызова предиката newByName(...)
- путем вызова предиката newByID(...)
Первый способ выглядит следующим образом:
... MyClassInstance =myClass::new(SomeObject), MyClassInstance:callNeededPredicate(…) ...
Это соответствует обычным правилам VIP.
Второй способ использует pzl-систему явно и выглядит так:
... MyClassObj=pzl::newByName(“MyClass”,...), MyClassInstance=tryConvert(iMyClass, MyClassObj), MyClassInstance:сallNeededPredicate(…),
Здесь iMyClass является интерфейсом класса myClass, а “MyClass” является строковым именем класса (alias) myClass.
Третий способ также явно использует pzl-систему и выглядит так:
... MyClassObj=pzl::newByID(str(“MyClass”),...), MyClassInstance=tryConvert(iMyClass, MyClassObj), MyClassInstance:сallNeededPredicate(…),
Здесь iMyClass является интерфейсом класса myClass, а str(“MyClass”) является строковым представлением идентификатора класса.
Обращение к другим классам и компонентам
Обращение к другим классам и компонентам из текущей компоненты ничем не отличается от обычного стиля обращений к классам, объектам классов и объектам компонент. Следует иметь в виду, что для обращения к компоненте в стиле
... ОбъектКомпоненты=классКомпоненты::new(SomeObject), ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), ...
компонента классКомпоненты должна быть представлена в проекте, из которого производится это обращение, своим классом-представителем.
Однако, для обращения к компоненте в стиле
... ОбъектКомпонентыObj=pzl::newByName("УсловноеИмяКомпоненты",Object), ОбъектКомпоненты=convert(интерфейсКомпоненты,ОбъектКомпонентыObj), ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), ...
или
... ОбъектКомпонентыObj=pzl::newByID(ИдентификаторКомпоненты,Object), ОбъектКомпоненты=convert(интерфейсКомпоненты,ОбъектКомпонентыObj), ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), ...
класс-представитель компоненты не требуется.
Завершение использования
По завершении использования объекта компоненты все указатели на нее должны быть удалены. Такое стандартное для VIP обращение с объектами в случае pzl-Компоненты также приводит к гибели ее объекта.
Отладка
Если pzl-компонента находится в главном (исполняемом) приложении, то отладка текста ее праграммы ничем не отличается от приемов отладки обычного класса системы Visual Prolog.
Если pzl-компонента находится в pzl-Контейнере, представляющем собой DLL, то процесс отладки должен начинаться с проекта этого контейнера (DLL). Впрочем, это типичный подход к отладке DLL, принятый в системе Visual Prolog.
Регистрация
Если какой-либо класс и pzl-компонента находятся в одной и той же сущности (.EXE или та же самая DLL), и при этом обращение производится в форме
... MyClassInstance =myClass::new(SomeObject), MyClassInstance:callNeededPredicate(…) ...
то регистрация pzl-Компоненты, к которой производится обращение, может не производиться.
Во всех остальных случаях компонента должна быть зарегистрирована либо в локальном файле пользователя, либо в реестре системы Windows.
При регистрации компоненты в реестре системы Windows используются следующие имена директорий windows-реестра (указаны в файле VpPuZzle/System/Packs/pzlDomains.i)
constants registryVPPuZzleAtGlobal_C = "vp_PuZzle". registryComponentsAtGlobal_C = "vp_PuZzle\\pzlComponents". registryVPPuZzleAtLocalUser_C = "Software\\vp_PuZzle". registryComponentsAtLocalUser_C = "Software\\vp_PuZzle\\pzlComponents". registryRunAble_C = "RunAble".
При этом для именования свойств компонент используются константы
registryRunAbleTrue_C="True". registryRunAbleFalse_C="False".
Примечание. Для регистрации компонент следует использовать специальные средства pzl-Технологии. Регистрация компонент вручную не рекомендуется.
Получение информации о компоненте
Как уже упоминалось, следующие предикаты объявлены в интерфейсе pzlComponent и поддерживаются содержательно pzl-системой
- getContainerVersion() - возвращает информацию о версии контейнера, в котором данная компонента содержится
- getContainerName() - возвращает информацию об имени файла-контейнера, в котором содержится данная компонента
- getClassInfo(className,classVersion) - возвращает информации об имени и версии класса pzlComponent
Для того, чтобы внешние по отношению к данной компоненте средства могли бы получить информацию об идентификаторе, условном наименовании и метаинформации, рекомендуется помещать следующие клаузы в базовый класс pzl-компоненты:
caluses getComponentID()= componentID_C. getComponentAlias() = componentAlias_C. getComponentMetaInfo() = componentMetaInfo_C
Напоминаем, что объявления этих предикатов содержатся в интерфейсе pzlComponent.
Ограничения в несанкционированном использовании
Pzl-Компонента не содержит никаких средств для ограничения ее использования. Если программа получает доступ к контейнеру, в котором расположена pzl-Компонента, и программе известны интерфейсы для общения с компонентной, то эта pzl-Компонента оказывается доступной программе.
Вы, как автор pzl-Компоненты, можете предусмотреть дополнительные меры по ограничению прав использования pzl-Компоненты.
Например, Вы можете предусмотреть сеанс идентификации прав, в ходе которого в pzl-Компоненту должна быть передана информация, подтверждающая права на использование данной компоненты.
Если текст программы pzl-Компоненты недоступен широкому кругу пользвателей, то такого рода защита от несанкционированного использования может оказаться достаточно эффективной.