-
Notifications
You must be signed in to change notification settings - Fork 0
/
context_graph.go
166 lines (153 loc) · 4.8 KB
/
context_graph.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package pp_ioc
import (
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
g "github.com/wlad031/pp-algo/graph"
logCtx "github.com/wlad031/pp-logging"
)
type contextGraph struct {
logger logCtx.NamedLogger
graph g.OrientedGraph
sorted []int
}
func newContextGraph() *contextGraph {
return &contextGraph{
logger: logCtx.Get("IOC.ContextGraph"),
graph: g.NewOrientedGraph(),
}
}
func (ctxG *contextGraph) build(beanDefinitions *beanDefinitionContainer) error {
ctxG.logger.Info("Building the dependency graph...")
e := ctxG.addGraphNodes(beanDefinitions)
if e != nil {
return e
}
e = ctxG.addGraphEdges(beanDefinitions)
if e != nil {
return e
}
ctxG.sorted, e = ctxG.graph.TopologicalSort()
if e != nil {
return e
}
return nil
}
func (ctxG *contextGraph) iterate() <-chan *beanDefinition {
c := make(chan *beanDefinition)
go func() {
for _, ind := range ctxG.sorted {
data, _ := ctxG.graph.GetDataForIndex(ind)
c <- data.(*beanDefinition)
}
close(c)
}()
return c
}
func (ctxG *contextGraph) addGraphNodes(beanDefinitions *beanDefinitionContainer) error {
for definition := range beanDefinitions.iterate() {
index, e := ctxG.graph.AddNode(definition)
if e != nil {
return errors.Wrap(e, "Cannot add binding key "+definition.shortString())
}
definition.updateGraphIndex(index)
ctxG.logger.WithFields(log.Fields{
"beanDef": definition.String(),
"index": index,
}).Trace("Added binding key")
}
return nil
}
func (ctxG *contextGraph) addGraphEdges(beanDefinitions *beanDefinitionContainer) error {
for beanDefinition := range beanDefinitions.iterate() {
for _, dependency := range beanDefinition.dependencies {
if !dependency.isBean {
continue
}
from, e := findDefinitionIndexForDefinition(beanDefinitions, beanDefinition)
if e != nil {
return e
}
toList, e := findDefinitionIndexesForDependency(beanDefinitions, dependency)
if e != nil {
return e
}
for _, to := range toList {
graphError := ctxG.graph.AddEdge(from, to)
if graphError != nil {
return errors.Wrap(graphError, "Cannot add dependency for " + beanDefinition.shortString())
}
ctxG.logger.WithFields(log.Fields{
"from": beanDefinition.String(),
"fromIndex": from,
"to": dependency.String(),
"toIndex": to,
}).Trace("Added dependency")
}
}
}
return nil
}
func findDefinitionIndexesForDependency(
beanDefinitions *beanDefinitionContainer,
dependency *dependency,
) (foundIndexes []int, e error) {
var isBeanDefinitionFound = false
for beanDefinition := range beanDefinitions.iterate() {
isBeanDefinitionSuitable :=
(dependency.hasQualifier &&
beanDefinition.isSuitableForDependencyByQualifier(dependency) &&
beanDefinition.isSuitableForDependencyByType(dependency)) ||
(!dependency.hasQualifier &&
beanDefinition.isSuitableForDependencyByType(dependency))
if isBeanDefinitionSuitable {
isBeanDefinitionFound = true
foundIndexes = append(foundIndexes, beanDefinition.graphIndex)
}
}
if !isBeanDefinitionFound {
return nil, errors.New("Cannot find bean definition for dependency " + dependency.String())
}
return foundIndexes, nil
}
// TODO: refactor this function
func findDefinitionIndexForDefinition(
beanDefinitions *beanDefinitionContainer,
key *beanDefinition,
) (int, error) {
found := false
ind := -1
for definition := range beanDefinitions.iterate() {
if foo1(definition.key.qualifiers, key.key.qualifiers) /*&& definition.key.type_ == key.key.type_*/ {
found = true
ind = definition.graphIndex
break
}
}
if !found {
return -1, errors.New("Cannot find bean definition " + key.shortString())
}
return ind, nil
}
func foo1(names1 []string, names2 []string) bool {
if len(names1) != len(names2) {
return false
}
allFound := true
for _, name1 := range names1 {
found := false
for _, name2 := range names2 {
if name1 == name2 {
found = true
break
}
}
if !found {
allFound = false
break
}
}
if !allFound {
return false
}
return true
}