Архитектурные особенности LUWRAIN
Подпроект core — центральный компонент платформы LUWRAIN.
Он содержит основной исполняемый код, который собирается в главный JAR-файл luwrain.jar, и предоставляет базовую функциональность для разработки приложений и расширений.
Ниже рассмотрена архитектура этого подпроекта с особым вниманием к встроенной поддержке сценариев.
Основные абстракции. Архитектура ядра LUWRAIN основана на нескольких ключевых абстракциях, которые образуют каркас всей платформы.
Интерфейс org.luwrain.core.Luwrain служит основной точкой доступа приложений и расширений к службам ядра.
Через него можно управлять синтезом речи, выводом на брайлевский дисплей, воспроизведением звуков, рабочими областями, запуском приложений, буфером обмена, конфигурацией и другими возможностями платформы.
Каждое приложение и расширение получает собственный экземпляр Luwrain.
Благодаря этому ядро может определять источник запросов и разграничивать уровни доступа к системным функциям.
Приложения.
Любое интерактивное приложение LUWRAIN реализует интерфейс org.luwrain.core.Application.
К его основным методам относятся:
onLaunchApp(Luwrain)— выполняет первоначальную инициализацию приложения;getAreaLayout()— возвращает компоновку рабочих областей;onAppClose()— вызывается при завершении работы приложения.
Интерфейс MonoApp расширяет Application и предназначен для приложений, которые могут быть запущены только в одном экземпляре.
Рабочие области.
Фундаментальной единицей пользовательского интерфейса LUWRAIN является область — area.
Область представляет собой интерактивный рабочий объект, например поле текстового ввода, структурированный документ, дерево или форму.
Она формирует текстовое представление содержимого, обрабатывает события ввода и управляет «горячей точкой» (hot point).
Горячая точка определяет текущую позицию взаимодействия пользователя с содержимым области и фактически выполняет роль фокуса.
Расширения.
Интерфейс org.luwrain.core.Extensions определяет основной контракт для подключения внешних расширений.
Расширения загружаются с помощью механизма ServiceLoader.
Они могут предоставлять приложения и команды для их запуска, фабрики компонентов панели управления, средства интернационализации и другие объекты, дополняющие возможности платформы.
События и речевой вывод.
События ввода, представленные классом org.luwrain.core.events.InputEvent, и системные события, представленные классом org.luwrain.core.events.SystemEvent, передаются активным областям.
В ответ области формируют объекты EventResponse, которые, помимо прочего, управляют речевой обратной связью.
Непосредственное взаимодействие с подсистемой синтеза речи осуществляется через класс org.luwrain.core.Speech и интерфейс org.luwrain.speech.Engine.
Одной из важных архитектурных особенностей LUWRAIN является встроенная поддержка сценариев, реализованная в пакете org.luwrain.script и его подпакетах.
Сценарии позволяют расширять функциональность платформы без предварительной компиляции Java-кода.
Для их выполнения используется JavaScript-среда GraalVM.
Загрузкой сценариев управляет ExtensionsManager.
При запуске ядро сканирует каталоги js/, расположенные как в общей структуре платформы, так и внутри установленных пакетов, и ищет файлы с расширением .js.
Имена файлов должны соответствовать шаблону <компонент>-<имя>.js.
Примерами допустимых имён являются core-startup.js и core-commander.js.
Класс org.luwrain.script.core.ScriptCore управляет жизненным циклом сценариев.
Он реализует интерфейс org.luwrain.core.HookContainer, благодаря чему сценарии могут регистрировать обработчики системных событий в виде хуков.
При загрузке сценария ScriptCore создаёт новый экземпляр класса Module.
Этот объект инкапсулирует контекст GraalVM и отвечает за выполнение сценария.
Система хуков.
Сценарии регистрируют обработчики событий с помощью метода Luwrain.addHook(name, func).
Ядро запускает зарегистрированные обработчики посредством метода HookContainer.runHooks().
Пакет org.luwrain.script.hooks предоставляет несколько стратегий выполнения хуков:
ChainOfResponsibilityHookреализует цепочку обязанностей: хуки вызываются последовательно, а первый обработчик, вернувшийtrue, останавливает дальнейшее выполнение цепочки;ProviderHookреализует стратегию поставщика и возвращает первый результат, отличный отnull;CollectorHookвызывает все хуки и собирает полученные результаты;PermissionHookиспользуется для проверки разрешений, при которой каждый хук должен вернутьtrue;NotificationHookвызывает все зарегистрированные хуки, игнорируя возвращаемые ими значения;TransformerHookпоследовательно передаёт значение через цепочку хуков, позволяя каждому из них преобразовать результат предыдущего обработчика.
Такая архитектура делает механизм сценариев гибким и позволяет использовать его для обработки событий, предоставления данных, проверки разрешений, рассылки уведомлений и последовательного преобразования значений.