MPI#
MPI (Module Programming Interface) — контракт, через который пакет сборки core обращается к бизнес-логике из пакета сборки src без прямой зависимости от реализации API.
MPI нужен, когда внутренняя логика из core должна использовать методы, реализованные в src. Для этого общая часть выносится в интерфейс MPI, а реализация остаётся в основном API-классе. Код из core работает с MPI-контрактом, а не с конкретной реализацией API.
MPI используется только в модулях gtk, btk и доменной логике.
Реализация MPI#
1. Определите интерфейс MPI
Создайте трейт, расширяющий ApiMpi, в пакете сборки core, но в том же пакете (package), что и ваш API.
Примечание
В зависимости от типа интерфейса используйте AviMpi, LibMpi или PkgMpi.
Пример для Btk_AttrTemplateByClassAttrsApi, который находится в пакете ru.bitec.app.btk.templateObjectAttr.
package ru.bitec.app.btk.templateObjectAttr
import ru.bitec.app.btk.eclipse.mpi.ApiMpi
import ru.bitec.app.gtk.lang.*
trait Btk_AttrTemplateByClassAttrsApiMpi extends ApiMpi {
def idpOTGroup: NLong
def getidAttribute(idp: NLong): NLong
def getsCaption(idp: NLong): NString
}
2. Создайте фабрику MPI
Фабрика позволяет получать экземпляр MPI с подстановкой текущей сессии.
package ru.bitec.app.btk.templateObjectAttr
import ru.bitec.app.gtk.eclipse.mpi.ApiMpiFactory
object Btk_AttrTemplateByClassAttrsApiMpi extends ApiMpiFactory[Btk_AttrTemplateByClassAttrsApiMpi]
Имя объекта по соглашению должно совпадать с именем трейта и суффиксом Mpi. Фабрика наследуется от ApiMpiFactory с типом созданного трейта.
Примечание
В зависимости от типа интерфейса используйте AviMpiFactory, LibMpiFactory или PkgMpiFactory.
Итоговый файл Btk_AttrTemplateByClassAttrsApiMpi.scala:
package ru.bitec.app.btk.templateObjectAttr
import ru.bitec.app.gtk.eclipse.mpi.ApiMpiFactory
import ru.bitec.app.btk.eclipse.mpi.ApiMpi
import ru.bitec.app.gtk.lang.*
import ru.bitec.app.gtk.Lang.*
trait Btk_AttrTemplateByClassAttrsApiMpi extends ApiMpi {
def idpOTGroup: NLong
def getidAttribute(idp: NLong): NLong
def getsCaption(idp: NLong): NString
}
object Btk_AttrTemplateByClassAttrsApiMpi extends ApiMpiFactory[Btk_AttrTemplateByClassAttrsApiMpi]
3. Реализуйте MPI в основном API-классе
Добавьте созданный интерфейс MPI к основному API-классу через with, чтобы класс стал реализацией этого контракта.
package ru.bitec.app.btk.templateObjectAttr
class Btk_AttrTemplateByClassAttrsApi extends <...>Dpi[<...>] with Btk_AttrTemplateByClassAttrsApiMpi {
lazy val idpOTGroup: NLong = Btk_ObjectTypeApi().findByMnemoCodeAndClass(spGroupOTName, idClass)
def getidAttribute(idp: NLong): NLong = {
load(idp).get(_.idAttribute)
}
def getsCaption(idp: NLong): NString = {
load(idp).get(_.sCaption)
}
// Остальной код класса
}
Использование MPI#
Используйте MPI как обычный сессионный класс.
Btk_AttrTemplateByClassAttrsApiMpi().getsCaption(123.nl)
Ограничения и особенности#
В построителях из пакета ru/bitec/app/gtk/meta/builders нельзя использовать контракты или прямое обращение к классу. Обращение должно выполняться только через MPI.
Для построителей уже созданы классы расширения с MPI:
AutoNumDpiBuilder—ru.bitec.app.btk.Btk_Autonum_PkgMpi;DpiBuilder—ru.bitec.app.btk.Btk_DpiInjectionPkgMpi;DviBuilder—ru.bitec.app.btk.Btk_DviInjectionLibMpi.
В этих классах реализуется логика для DVI, DPI и автонумерации.
В пакетах построителей используются два варианта реализации:
ru/bitec/app/gtk/meta/builders— новый код, в котором используетсяMPI. Используется в коробочном решении;ru/bitec/app/gtk/meta/builders/old— старый код безMPI. Используется в проектных модулях.
Частые проблемы и их решения#
case class недоступен из core#
Если case class находится в объекте-компаньоне класса, для которого реализуется MPI, его необходимо вынести в фабрику MPI.
Если case class находится в пакете сборки src, его необходимо перенести в пакет сборки core.
Пример ru.bitec.app.btk.valueset.Btk_ValueSetApiMpi:
...
object Btk_ValueSetApiMpi extends ApiMpiFactory[Btk_ValueSetApiMpi] {
case class ValueSet(private val idQueryOpt: Try[String], private val gidQueryOpt: Try[String]) {
def idQuery: String = idQueryOpt.get
def gidQuery: String = gidQueryOpt.get
}
}
Поле объекта-компаньона недоступно из core#
Если в параметрах функции используется поле из объекта-компаньона, поле необходимо перенести в фабрику MPI.
Пример ru.bitec.app.btk.Btk_DpiInjectionPkgMpi:
object Btk_DpiInjectionPkgMpi extends PkgMpiFactory[Btk_DpiInjectionPkgMpi] {
lazy val nLongNoValue: NLong = NLong(-1)
}