| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // package arch_link -- связь между архитектурными объектами
- package arch_link
- import (
- "fmt"
- "gitp78su.ipnodns.ru/svi/kern/v3"
- "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
- "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
- "gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
- "gitp78su.ipnodns.ru/svi/goarch/lev0/types"
- "gitp78su.ipnodns.ru/svi/goarch/lev1/arch_text"
- )
- // ArchLink -- связь между архитектурными объектами
- type ArchLink struct {
- *arch_text.ArchText
- SrcId_ alias.ArchId `yaml:"src_id"` // Источник координат
- src types.IArchNode
- DstId_ alias.ArchId `yaml:"dst_id"` // Получатель координат
- dst types.IArchNode
- TypeLink_ string `yaml:"type_link"` // Тип связи
- }
- var (
- hassert = kern.GetFnHassert()
- )
- // NewArchLink -- возвращает новую связь
- func NewArchLink(archText *arch_text.ArchText) *ArchLink {
- hassert(archText != nil, "NewArchLink: archText == nil")
- sf := &ArchLink{
- ArchText: archText,
- }
- _ = types.IArchLink(sf)
- return sf
- }
- // InvarCheck -- самопроверка элемента
- func (sf *ArchLink) InvarCheck() ktypes.Option[error] {
- optErr := sf.InvarNode()
- if optErr.IsVal() {
- return optErr
- }
- if sf.SrcId_ == "" {
- err := fmt.Errorf("ArchLink.SelfCheck(): id=%v, Src_ == nil", sf.Id())
- return ktypes.NewSome(err)
- }
- if sf.DstId_ == "" {
- err := fmt.Errorf("ArchLink.SelfCheck(): id=%v, Dst_ == nil", sf.Id())
- return ktypes.NewSome(err)
- }
- if sf.TypeLink_ == "" {
- err := fmt.Errorf("ArchLink.SelfCheck(): id=%v, TypeLink_ is empty", sf.Id())
- return ktypes.NewSome(err)
- }
- return ktypes.NewNone[error]()
- }
- // TypeLink -- тип связи
- //
- //go:fix inline
- func (sf *ArchLink) TypeLink() string {
- return sf.TypeLink_
- }
- // Links -- ссылки актора
- func (sf *ArchLink) Links() []types.IArchNode {
- return []types.IArchNode{sf.src, sf.dst}
- }
- // Check -- проверяет связи между объектами
- func (sf *ArchLink) Check() string {
- if sf.DstId_ == sf.SrcId_ {
- return fmt.Sprintf("ВНИМАНИЕ! Источник и получатель совпадают\nsrc=%v, dst=%v\n",
- sf.SrcId_, sf.DstId_)
- }
- if msgErr := sf.checkSrc(); msgErr != "" {
- return "ОШИБКА при проверке связи источника\n" + msgErr
- }
- if msgErr := sf.checkDst(); msgErr != "" {
- return "ОШИБКА при проверке связи получателя\n" + msgErr
- }
- if sf.TypeLink_ == "" { // Проверка на правильность типа связи
- return "Пустой собственный тип связи\n"
- }
- return ""
- }
- // проверить связь получателя
- func (sf *ArchLink) checkDst() string {
- if sf.DstId_ == "" {
- return "ОШИБКА получатель `dst` не задан"
- }
- // Вычислить на допустимые типы для получателя
- switch sf.dst.Type() {
- case cons.TypeUseActor:
- actor, isOk := sf.dst.(types.IArchActor)
- if !isOk {
- return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n",
- sf.DstId_, sf.dst.Type())
- }
- isOk = false
- for _, id := range actor.GroupLink().Links() {
- if id == sf.Id() {
- isOk = true
- break
- }
- }
- if !isOk {
- return fmt.Sprintf("Невзаимная ссылка\nid=%q,dst=(%q)",
- sf.Id(), actor.Id())
- }
- case cons.TypeUseLink:
- link, isOk := sf.dst.(types.IArchLink)
- if !isOk {
- return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n",
- sf.DstId_, sf.dst.Type())
- }
- isOk = sf.Id() == link.DstId() || sf.Id() == link.SrcId()
- if !isOk {
- return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id(), link.Id())
- }
- case cons.TypeUseCase:
- useCase, isOk := sf.dst.(types.IArchUseCase)
- if !isOk {
- return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nтип=%q\n",
- sf.Id(), sf.DstId_, sf.dst.Type())
- }
- isOk = false
- for id := range useCase.Links() {
- if id == sf.Id() {
- isOk = true
- break
- }
- }
- if !isOk {
- return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n",
- sf.Id(), useCase.Id())
- }
- default: // Недопустимый источник
- return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nid=%q\n",
- sf.Id(), sf.dst.Type(), sf.DstId_)
- }
- return ""
- }
- // Проверяет связь источника
- func (sf *ArchLink) checkSrc() string {
- if sf.src == nil {
- return "ВНИМАНИЕ! Источник связи не задан(src)\n"
- }
- switch sf.src.Type() {
- case cons.TypeUseActor:
- isOk := false
- actor := sf.src.(types.IArchActor)
- for _, id := range actor.GroupLink().Links() { // Проверка на взаимность
- if id == sf.Id() {
- isOk = true
- break
- }
- }
- if !isOk {
- return fmt.Sprintf("Невзаимная ссылка с актором %q\n", actor.Id())
- }
- case cons.TypeUseLink:
- link, isOk := sf.src.(types.IArchLink)
- if !isOk {
- return fmt.Sprintf("Несоответствие типа источника(%q)\nтип='useLink'\n",
- sf.SrcId_)
- }
- isOk = sf.Id() == link.DstId() || sf.Id() == link.SrcId()
- if !isOk {
- return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n",
- sf.Id(), link.Id())
- }
- case cons.TypeUseCase:
- useCase, isOk := sf.src.(types.IArchUseCase)
- if !isOk {
- return fmt.Sprintf("id=%q, Тип источника(%q) не совпадает с фактическим\nтип='useCase'\n",
- sf.Id(), sf.SrcId())
- }
- isOk = false
- for id := range useCase.Links() { // Проверка на взаимность
- if id == sf.Id() {
- isOk = true
- break
- }
- }
- if !isOk {
- return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n",
- sf.Id(), useCase.Id())
- }
- default: // Неизвестный источник
- return fmt.Sprintf("id=%q, неизвестный тип источника(%q)<br>id=%q\n",
- sf.Id(), sf.src.Type(), sf.SrcId())
- }
- return ""
- }
- // SrcId -- возвращает ID источника связи
- //
- //go:fix inline
- func (sf *ArchLink) SrcId() alias.ArchId {
- return sf.SrcId_
- }
- // DstId -- возвращает ID получателя связи
- //
- //go:fix inline
- func (sf *ArchLink) DstId() alias.ArchId {
- return sf.DstId_
- }
|