Интеграционный слой #
Интеграционный слой предоставляет высокоуровневый API, позволяющий реализовать редакторы и панели Eclipse, используя в качестве основного хранилища данных объектное хранилище BM. В частности, интеграционный слой предоставляет следующую функциональность:
- Разделение контекстов редактирования,
- Отслеживание истории изменений и выполнения операций отмены / повтора,
- Отслеживание изменений, которые не отражены в ресурсах рабочей области,
- Сохранение изменений в ресурсах рабочей области,
- Рассылка событий об изменениях в объектной модели.
BmModel #
Компонент BmModel
(см. интерфейс
com._1c.g5.v8.bm.integration.IBmModel) представляет собой фасад, посредством которого вы получаете доступ к основной функциональности интеграционного слоя BM.
Создание BmModel #
Создать экземпляр IBmModel
можно только посредством вызова BmModels.create
.
Обзор основных методов #
IBmEditingContext createLocalContext(String name)
Создает локальный контекст редактирования с заданным именем. Что такое контекст редактирования, будет написано далее в этом документе.
IBmEditingContext getGlobalContext()
Получает экземпляр глобального контекста редактирования.
void addSyncEventListener(IBmSyncEventListener listener)
Производит подписку на синхронную рассылку событий.
void removeSyncEventListener(IBmSyncEventListener listener)
Производит отписку от синхронной рассылки событий.
void addAsyncEventListener(IBmAsyncEventListener listener, BmEventFilter... filters)
Производит подписку на асинхронную рассылку событий.
void removeAsyncEventListener(IBmAsyncEventListener listener)
Производит отписку от асинхронной рассылки событий.
<T> T execute(IBmTask<T> task)
Выполняет задачу BM без добавления записи в историю изменений. Что такое задача BM, будет написано далее в этом документе. При успешном выполнении задачи (если в процессе выполнения задачи не было выброшено исключение) производится рассылка событий BM.
<T> T executeReadonlyTask(IBmTask<T> task)
Выполняет задачу BM, выполняющую доступ к данным BM только на чтение.
<T> T executeAndRollback(IBmTask<T> task)
Выполняет задачу BM, после выполнения сразу же откатывает изменения (без рассылки событий).
Понятие задачи #
Задача BM — unit of work, объединяющий некоторый набор операций по редактированию данных BM, выполнение которых должно приводить модель в консистентное с точки зрения прикладного решения состояние.
Для выполнения задачи BM необходимо создать класс, реализующий интерфейс
com._1c.g5.v8.bm.integration.IBmTask
IBmModel.execute
,IBmModel.executeReadonlyTask
,IBmModel.executeAndRollback
,IBmEditingContext.execute
,IBmGlobalEditingContext.executeImportTask
.
Интерфейс IBmTask
определяет следующие методы:
getName
возвращает имя задачи, которое будет отображаться в логах и в пользовательском интерфейсе (например, в пункте меню Edit - Undo)execute
содержит логику, отвечающую непосредственно за редактирование данных BM. Редактирование должно производиться в рамках транзакции, которая передается в данный метод в качестве параметра. При этом в данном методе не должны выполняться фиксация или откат транзакции, за это отвечает компонент, выполняющий задачу.
|
|
Понятие контекста редактирования #
Контексты редактирования предоставляют возможность отделения модификаций произведенных в разных редакторах. Таким образом предоставляется возможность применения и отката задач, выполненных в данном контексте, независимо от других контекстов (естественно, с ограничениями, связанными с особенностями редактирования конфигураций 1С).
Основной метод интерфейса com._1c.g5.v8.bm.integration.IBmEditingContext
- execute
. Он выполняет задачу BM в данном контексте. При успешном выполнении задачи (если в процессе выполнения задачи не было выброшено исключение) данная задача добавляется в историю изменений данного контекста.
Контекст помечается как dirty
. Это означает, что он содержит изменения, не сохраненные в ресурсах рабочей области. При этом стоит заметить, что модификации уже отражены в основном хранилище BM и, таким образом, видны всем остальным пользователям BM.
Также при успешном выполнении данного метода производится рассылка событий BM.
|
|
Локальный контекст редактирования #
Локальные контексты предназначены для использования при реализации редакторов Eclipse. Задачи, выполненные в локальном контексте, могут отменяться и повторяться (в случае, если нет конфликтующих изменений в других контекстах), сохранение изменений в ресурсах рабочей области происходит только при явном вызове метода save
. При вызове метода dispose
все несохраненные изменения отменяются.
Локальный контекст представлен интерфейсом com._1c.g5.v8.bm.integration.IBmLocalEditingContext
:
canUndo
,canRedo
проверяют возможность выполнения операций отмены и повтора, соответственно,undo
,redo
производят операции отмены и повтора, соответственно,isDirty
проверяет наличие изменений, не отраженных в ресурсах рабочей области,save
при наличии изменений, не отраженных в ресурсах рабочей области, производит сохранение изменений в ресурсах рабочей области,dispose
уничтожает данный контекст редактирования.
|
|
Глобальный контекст редактирования #
Глобальный контекст редактирования предназначен для выполнения всех задач, не привязанных к определенному редактору, т.е. манипуляции в различных панелях, рефакторинг и т.п. После успешного выполнения задачи в глобальном контексте сохранение производится автоматически. Задачи, выполненные в глобальном контексте, в текущей версии не могут быть отменены или повторены. В будущих версиях такая возможность может быть добавлена.
Глобальный контекст представлен интерфейсом com._1c.g5.v8.bm.integration.IBmGlobalEditingContext
и предоставляет один дополнительный метод по сравнению с базовым интерфейсом контекста executeImportTask
. Он выполняет задачу импорта в глобальном контексте, при этом происходит рассылка событий, сохранение всех несохраненных локальных контекстов и уничтожение их истории.
|
|
Обработка отмена / повтора задачи #
Для обработки undo / redo какой-либо задачи используется интерфейс com._1c.g5.v8.bm.integration.IBmPostUndoRedoHandler
, который эта задача должна реализовывать. onUndo
, onRedo
выполняются по факту отмены и повтора задачи, соответственно. Эти методы предназначены для расположения в них нетранзакционной логики, не затрагивающей данные BM. Например, для рассылки бизнес-событий.
|
|
Редактирование вне контекста #
Иногда возникает необходимость выполнения задач, которые не должны попадать в историю изменений, а модификации модели, которые они производят, не должны отражаться в ресурсах рабочей области. Например, к такому классу задач относится расчет производных данных объектов.
Специально для этих целей на интерфейсе IBmModel
был введен метод execute
. При успешном выполнении данного метода производится сохранение произведенных изменений в объектном хранилище BM, производится рассылка событий, но не производится добавление задачи в историю изменений и не производится сохранение изменений в ресурсах рабочей области.
События #
Интерфейс IBmModel
предоставляет методы для подписки на синхронную и асинхронную рассылку событий. Асинхронная рассылка событий производится в фоновом потоке. Синхронная рассылка производится в потоке выполнения задачи, сразу после ее успешного завершения. Поскольку синхронная рассылка событий удерживает рабочий поток, не следует подписываться на синхронную рассылку событий без крайней на то необходимости.
В обработчик события BM (и в синхронный, и в асинхронный) в качестве параметра передается экземпляр класса BmEvent
, содержащий информацию обо всех изменениях произведенных в рамках задачи BM. В частности, класс BmEvent
предоставляет два метода:
BmAssociationEvent getAssociationEvent()
. Данный метод возвращает экземплярBmAssociationEvent
в том случае, если в рамках выполнения задачи производились операции по добавлению или удалению объектов BM. В противном случае возвращаетсяnull
. ОбъектBmAssociationEvent
содержит информацию обо всех добавленных и удаленных объектах.BmLongHashMap<BmChangeEvent> getChangeEvents()
. Данный метод возвращаетmap
, в котором в роли ключа выступает числовой идентификатор модифицированного объекта, а в роли значения — экземплярBmChangeEvent
, содержащий информацию о том, какие features, BM-свойства и BM-бинарные вложения были изменены. Если в рамках выполненной задачи BM не было модификаций, то возвращаетсяnull
.
Примеры #
Чтение данных справочника #
Для чтения данных справочника вам необходимо выполнить следующие действия:
- Получить собственно справочник. В зависимости от ситуации, это может быть получение объекта по его FQN, либо получение объекта из
Selection
со стороны пользовательского интерфейса, и т.п., - Сформировать задачу (
IBmTask
), осуществляющую получение необходимых данных из объекта метаданных типаCatalog
. В этой задаче:- Полученный справочник актуализируется, подключаясь к транзакции, либо получается непосредственно из транзакции,
- Производится чтение данных справочника,
- Возвращается результат (опционально),
- Выполнить эту задачу в режиме “только чтение”
Теперь реализуйте подготовленный план в виде программного кода:
|
|
Обратите внимание на следующие моменты:
IBmTask
может возвращать значение в качестве результата выполнения. Тип данного значения задается параметром классаIBmTask
. В данном примере вы использовали результат типаInteger
—IBmTask<Integer>
,- Вы использовали базовую реализацию задач
AbstractBmTask
, содержащую необходимый минимум функциональности для выполнения задачи. Как вы видите, она также параметризуема типом возвращаемого результата —AbstractBmTask<Integer>
, - Само тело задачи задается в методе
execute
, который возвращает параметр типа, указанного вами ранее через параметризацию задачи —public Integer execute(IBmTransaction transaction, IProgressMonitor progressMonitor)
, - Все данные модели, используемые внутри задачи, должны быть присоединены к транзакции. Для этого все данные должны быть получены через объект
IBmTransaction
, передаваемый в качестве параметра методаexecute
:public Integer execute(IBmTransaction transaction, IProgressMonitor progressMonitor)
. Также данные могут быть получены путем прохода по свойствам объекта, уже присоединенного к данной транзакции (собственно, получение значения поля и есть такая операция), - В случае, если вам не нужно возвращать значение из вашей задачи, можно использовать тип
Void
, задача в этом случае создается так:IBmTask<Void> someTask = new AbstractBmTask<Void>("Some task")
, с соответствующим типом в методеexecute
:public Void execute(IBmTransaction transaction, IProgressMonitor progressMonitor)
, - Для
Void
в конце задачи необходимо вернутьnull
в качестве результата —return null