arch_link.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // package arch_link -- связь между архитектурными объектами
  2. package arch_link
  3. import (
  4. "fmt"
  5. "gitp78su.ipnodns.ru/svi/kern/v3"
  6. "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
  7. "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
  8. "gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
  9. "gitp78su.ipnodns.ru/svi/goarch/lev0/types"
  10. "gitp78su.ipnodns.ru/svi/goarch/lev1/arch_text"
  11. )
  12. // ArchLink -- связь между архитектурными объектами
  13. type ArchLink struct {
  14. *arch_text.ArchText
  15. SrcId_ alias.ArchId `yaml:"src_id"` // Источник координат
  16. src types.IArchNode
  17. DstId_ alias.ArchId `yaml:"dst_id"` // Получатель координат
  18. dst types.IArchNode
  19. TypeLink_ string `yaml:"type_link"` // Тип связи
  20. }
  21. var (
  22. hassert = kern.GetFnHassert()
  23. )
  24. // NewArchLink -- возвращает новую связь
  25. func NewArchLink(archText *arch_text.ArchText) *ArchLink {
  26. hassert(archText != nil, "NewArchLink: archText == nil")
  27. sf := &ArchLink{
  28. ArchText: archText,
  29. }
  30. _ = types.IArchLink(sf)
  31. return sf
  32. }
  33. // InvarCheck -- самопроверка элемента
  34. func (sf *ArchLink) InvarCheck() ktypes.Option[error] {
  35. optErr := sf.InvarNode()
  36. if optErr.IsVal() {
  37. return optErr
  38. }
  39. if sf.SrcId_ == "" {
  40. err := fmt.Errorf("ArchLink.SelfCheck(): id=%v, Src_ == nil", sf.Id())
  41. return ktypes.NewSome(err)
  42. }
  43. if sf.DstId_ == "" {
  44. err := fmt.Errorf("ArchLink.SelfCheck(): id=%v, Dst_ == nil", sf.Id())
  45. return ktypes.NewSome(err)
  46. }
  47. if sf.TypeLink_ == "" {
  48. err := fmt.Errorf("ArchLink.SelfCheck(): id=%v, TypeLink_ is empty", sf.Id())
  49. return ktypes.NewSome(err)
  50. }
  51. return ktypes.NewNone[error]()
  52. }
  53. // TypeLink -- тип связи
  54. //
  55. //go:fix inline
  56. func (sf *ArchLink) TypeLink() string {
  57. return sf.TypeLink_
  58. }
  59. // Links -- ссылки актора
  60. func (sf *ArchLink) Links() []types.IArchNode {
  61. return []types.IArchNode{sf.src, sf.dst}
  62. }
  63. // Check -- проверяет связи между объектами
  64. func (sf *ArchLink) Check() string {
  65. if sf.DstId_ == sf.SrcId_ {
  66. return fmt.Sprintf("ВНИМАНИЕ! Источник и получатель совпадают\nsrc=%v, dst=%v\n",
  67. sf.SrcId_, sf.DstId_)
  68. }
  69. if msgErr := sf.checkSrc(); msgErr != "" {
  70. return "ОШИБКА при проверке связи источника\n" + msgErr
  71. }
  72. if msgErr := sf.checkDst(); msgErr != "" {
  73. return "ОШИБКА при проверке связи получателя\n" + msgErr
  74. }
  75. if sf.TypeLink_ == "" { // Проверка на правильность типа связи
  76. return "Пустой собственный тип связи\n"
  77. }
  78. return ""
  79. }
  80. // проверить связь получателя
  81. func (sf *ArchLink) checkDst() string {
  82. if sf.DstId_ == "" {
  83. return "ОШИБКА получатель `dst` не задан"
  84. }
  85. // Вычислить на допустимые типы для получателя
  86. switch sf.dst.Type() {
  87. case cons.TypeUseActor:
  88. actor, isOk := sf.dst.(types.IArchActor)
  89. if !isOk {
  90. return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n",
  91. sf.DstId_, sf.dst.Type())
  92. }
  93. isOk = false
  94. for _, id := range actor.GroupLink().Links() {
  95. if id == sf.Id() {
  96. isOk = true
  97. break
  98. }
  99. }
  100. if !isOk {
  101. return fmt.Sprintf("Невзаимная ссылка\nid=%q,dst=(%q)",
  102. sf.Id(), actor.Id())
  103. }
  104. case cons.TypeUseLink:
  105. link, isOk := sf.dst.(types.IArchLink)
  106. if !isOk {
  107. return fmt.Sprintf("Недопустимый тип получателя(%q)\nтип=%q\n",
  108. sf.DstId_, sf.dst.Type())
  109. }
  110. isOk = sf.Id() == link.DstId() || sf.Id() == link.SrcId()
  111. if !isOk {
  112. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n", sf.Id(), link.Id())
  113. }
  114. case cons.TypeUseCase:
  115. useCase, isOk := sf.dst.(types.IArchUseCase)
  116. if !isOk {
  117. return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nтип=%q\n",
  118. sf.Id(), sf.DstId_, sf.dst.Type())
  119. }
  120. isOk = false
  121. for id := range useCase.Links() {
  122. if id == sf.Id() {
  123. isOk = true
  124. break
  125. }
  126. }
  127. if !isOk {
  128. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n",
  129. sf.Id(), useCase.Id())
  130. }
  131. default: // Недопустимый источник
  132. return fmt.Sprintf("id=%q, Недопустимый тип получателя(%q)\nid=%q\n",
  133. sf.Id(), sf.dst.Type(), sf.DstId_)
  134. }
  135. return ""
  136. }
  137. // Проверяет связь источника
  138. func (sf *ArchLink) checkSrc() string {
  139. if sf.src == nil {
  140. return "ВНИМАНИЕ! Источник связи не задан(src)\n"
  141. }
  142. switch sf.src.Type() {
  143. case cons.TypeUseActor:
  144. isOk := false
  145. actor := sf.src.(types.IArchActor)
  146. for _, id := range actor.GroupLink().Links() { // Проверка на взаимность
  147. if id == sf.Id() {
  148. isOk = true
  149. break
  150. }
  151. }
  152. if !isOk {
  153. return fmt.Sprintf("Невзаимная ссылка с актором %q\n", actor.Id())
  154. }
  155. case cons.TypeUseLink:
  156. link, isOk := sf.src.(types.IArchLink)
  157. if !isOk {
  158. return fmt.Sprintf("Несоответствие типа источника(%q)\nтип='useLink'\n",
  159. sf.SrcId_)
  160. }
  161. isOk = sf.Id() == link.DstId() || sf.Id() == link.SrcId()
  162. if !isOk {
  163. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n",
  164. sf.Id(), link.Id())
  165. }
  166. case cons.TypeUseCase:
  167. useCase, isOk := sf.src.(types.IArchUseCase)
  168. if !isOk {
  169. return fmt.Sprintf("id=%q, Тип источника(%q) не совпадает с фактическим\nтип='useCase'\n",
  170. sf.Id(), sf.SrcId())
  171. }
  172. isOk = false
  173. for id := range useCase.Links() { // Проверка на взаимность
  174. if id == sf.Id() {
  175. isOk = true
  176. break
  177. }
  178. }
  179. if !isOk {
  180. return fmt.Sprintf("id=%q, Невзаимная ссылка(%q)\n",
  181. sf.Id(), useCase.Id())
  182. }
  183. default: // Неизвестный источник
  184. return fmt.Sprintf("id=%q, неизвестный тип источника(%q)<br>id=%q\n",
  185. sf.Id(), sf.src.Type(), sf.SrcId())
  186. }
  187. return ""
  188. }
  189. // SrcId -- возвращает ID источника связи
  190. //
  191. //go:fix inline
  192. func (sf *ArchLink) SrcId() alias.ArchId {
  193. return sf.SrcId_
  194. }
  195. // DstId -- возвращает ID получателя связи
  196. //
  197. //go:fix inline
  198. func (sf *ArchLink) DstId() alias.ArchId {
  199. return sf.DstId_
  200. }