// 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)
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_ }