|
1 | 1 | package mpr |
2 | 2 |
|
3 | | -const microflowDocumentType = "Microflows$Microflow" |
4 | | - |
5 | | -func enrichMicroflowDocument(mf MxDocument) MxDocument { |
6 | | - mf = addMicroflowPseudocode(mf) |
7 | | - mf = transformMicroflow(mf) |
8 | | - return mf |
9 | | -} |
10 | | - |
11 | | -func transformMicroflow(mf MxDocument) MxDocument { |
12 | | - log.Infof("Transforming microflow %s", mf.Name) |
| 3 | +import "go.mongodb.org/mongo-driver/bson" |
13 | 4 |
|
14 | | - cleanedData := bsonToMap(mf.Attributes) |
15 | | - objs, flows, ok := extractMicroflowGraphData(mf.Name, cleanedData) |
16 | | - if !ok { |
17 | | - return mf |
18 | | - } |
19 | | - startEvent, ok := getMxMicroflowObjectByType(objs, "Microflows$StartEvent") |
20 | | - if !ok { |
21 | | - log.Warnf("StartEvent not found for microflow %s, skipping transformation", mf.Name) |
22 | | - return mf |
23 | | - } |
24 | | - |
25 | | - root := MxMicroflowNode{ |
26 | | - Type: startEvent.Type, |
27 | | - ID: startEvent.ID, |
28 | | - Attributes: startEvent.Attributes, |
29 | | - } |
30 | | - buildDAG(&root, nil, flows, objs) |
31 | | - mainFlow := make([]map[string]interface{}, 0) |
32 | | - labels := make(map[string]interface{}, 0) |
33 | | - extractMainFlow(&mainFlow, &root, &labels) |
34 | | - mf.Attributes["MainFunction"] = mainFlow |
35 | | - // remove ObjectCollection |
36 | | - delete(mf.Attributes, "ObjectCollection") |
37 | | - return mf |
38 | | -} |
| 5 | +const microflowDocumentType = "Microflows$Microflow" |
39 | 6 |
|
40 | | -func addMicroflowPseudocode(mf MxDocument) MxDocument { |
41 | | - cleanedData := bsonToMap(mf.Attributes) |
42 | | - pseudocode, err := generateMicroflowPseudocode(mf.Name, cleanedData) |
| 7 | +func addMicroflowPseudocode(name string, attributes bson.M) { |
| 8 | + cleanedData := bsonToMap(attributes) |
| 9 | + pseudocode, err := generateMicroflowPseudocode(name, cleanedData) |
43 | 10 | if err != nil { |
44 | | - log.Warnf("Could not generate pseudocode for microflow %s: %v", mf.Name, err) |
45 | | - return mf |
46 | | - } |
47 | | - mf.Attributes["pseudocode"] = pseudocode |
48 | | - return mf |
49 | | -} |
50 | | - |
51 | | -func extractMicroflowGraphData(name string, cleanedData map[string]interface{}) ([]MxMicroflowObject, []MxMicroflowEdge, bool) { |
52 | | - objsCollectionRaw, ok := cleanedData["ObjectCollection"] |
53 | | - if !ok || objsCollectionRaw == nil { |
54 | | - log.Warnf("ObjectCollection not found for microflow %s, skipping transformation", name) |
55 | | - return nil, nil, false |
56 | | - } |
57 | | - |
58 | | - objsCollection, ok := objsCollectionRaw.(map[string]interface{}) |
59 | | - if !ok { |
60 | | - log.Warnf("ObjectCollection is not a map for microflow %s, skipping transformation", name) |
61 | | - return nil, nil, false |
62 | | - } |
63 | | - |
64 | | - objectsRaw, ok := objsCollection["Objects"] |
65 | | - if !ok || objectsRaw == nil { |
66 | | - log.Warnf("Objects not found in ObjectCollection for microflow %s, skipping transformation", name) |
67 | | - return nil, nil, false |
68 | | - } |
69 | | - |
70 | | - objects, ok := objectsRaw.([]interface{}) |
71 | | - if !ok { |
72 | | - log.Warnf("Objects is not a slice for microflow %s, skipping transformation", name) |
73 | | - return nil, nil, false |
74 | | - } |
75 | | - |
76 | | - flowsRaw, ok := cleanedData["Flows"] |
77 | | - if !ok || flowsRaw == nil { |
78 | | - log.Warnf("Flows not found for microflow %s, skipping transformation", name) |
79 | | - return nil, nil, false |
80 | | - } |
81 | | - |
82 | | - flowsSlice, ok := flowsRaw.([]interface{}) |
83 | | - if !ok { |
84 | | - log.Warnf("Flows is not a slice for microflow %s, skipping transformation", name) |
85 | | - return nil, nil, false |
86 | | - } |
87 | | - |
88 | | - return convertToMxMicroflowObjects(objects), convertToMxMicroflowEdges(flowsSlice), true |
89 | | -} |
90 | | - |
91 | | -func extractMainFlow(mainFlow *[]map[string]interface{}, current *MxMicroflowNode, labels *map[string]interface{}) { |
92 | | - c := convertMxMicroflowNodeToMap(current) |
93 | | - *mainFlow = append(*mainFlow, c) |
94 | | - if current.Type == "Microflows$EndEvent" { |
95 | | - return |
96 | | - } |
97 | | - |
98 | | - if current.Type == "Microflows$ExclusiveMerge" { |
99 | | - id, ok := c["ID"].(string) |
100 | | - if !ok { |
101 | | - log.Warn("ID is not a string or is nil") |
102 | | - return |
103 | | - } |
104 | | - // check if label already exists |
105 | | - if _, ok := (*labels)[id]; !ok { |
106 | | - (*labels)[id] = c |
107 | | - // continue expanding this subflow |
108 | | - } else { |
109 | | - log.Infof("Loop detected; not traversing") |
110 | | - return |
111 | | - } |
112 | | - } |
113 | | - |
114 | | - children := current.Children |
115 | | - //current.Children = nil |
116 | | - if children == nil { |
117 | | - return |
118 | | - } |
119 | | - if len(*children) == 0 { |
| 11 | + log.Warnf("Could not generate pseudocode for microflow %s: %v", name, err) |
120 | 12 | return |
121 | | - } else if len(*children) == 1 { |
122 | | - // sequence |
123 | | - child := (*children)[0] |
124 | | - extractMainFlow(mainFlow, &child, labels) |
125 | | - } else { |
126 | | - // split |
127 | | - splits := make([]interface{}, 0) |
128 | | - for _, child := range *children { |
129 | | - subflow := make([]map[string]interface{}, 0) |
130 | | - extractMainFlow(&subflow, &child, labels) |
131 | | - splits = append(splits, subflow) |
132 | | - } |
133 | | - c["Splits"] = splits |
134 | | - } |
135 | | -} |
136 | | - |
137 | | -func buildDAG(current *MxMicroflowNode, parent *MxMicroflowNode, flows []MxMicroflowEdge, objects []MxMicroflowObject) { |
138 | | - |
139 | | - current.Parent = parent |
140 | | - children := make([]MxMicroflowNode, 0) |
141 | | - |
142 | | - switch current.Type { |
143 | | - case "Microflows$ExclusiveMerge": |
144 | | - start := backtrack(current, current.Parent) |
145 | | - if start == nil { |
146 | | - // no loop |
147 | | - edges := getMxMicroflowEdgesByOrigin(flows, current.ID) |
148 | | - |
149 | | - for _, edge := range edges { |
150 | | - edgeNode := MxMicroflowNode{ |
151 | | - Type: edge.Type, |
152 | | - ID: edge.ID, |
153 | | - Attributes: edge.Attributes, |
154 | | - } |
155 | | - |
156 | | - buildDAG(&edgeNode, current, flows, objects) |
157 | | - children = append(children, edgeNode) |
158 | | - } |
159 | | - } else { |
160 | | - log.Infof("Loop detected; not traversing") |
161 | | - return |
162 | | - } |
163 | | - case "Microflows$SequenceFlow": |
164 | | - destination, _ := current.Attributes["DestinationPointer"].(string) |
165 | | - obj, ok := getMxMicroflowObjectByID(objects, destination) |
166 | | - if !ok { |
167 | | - log.Warnf("Destination object %s not found for sequence flow %s", destination, current.ID) |
168 | | - return |
169 | | - } |
170 | | - objectNode := MxMicroflowNode{ |
171 | | - Type: obj.Type, |
172 | | - ID: obj.ID, |
173 | | - Attributes: obj.Attributes, |
174 | | - } |
175 | | - buildDAG(&objectNode, current, flows, objects) |
176 | | - children = append(children, objectNode) |
177 | | - default: |
178 | | - edges := getMxMicroflowEdgesByOrigin(flows, current.ID) |
179 | | - |
180 | | - for _, edge := range edges { |
181 | | - edgeNode := MxMicroflowNode{ |
182 | | - Type: edge.Type, |
183 | | - ID: edge.ID, |
184 | | - Attributes: edge.Attributes, |
185 | | - } |
186 | | - |
187 | | - buildDAG(&edgeNode, current, flows, objects) |
188 | | - children = append(children, edgeNode) |
189 | | - } |
190 | | - } |
191 | | - current.Children = &children |
192 | | -} |
193 | | - |
194 | | -func backtrack(current *MxMicroflowNode, parent *MxMicroflowNode) *MxMicroflowNode { |
195 | | - if parent == nil { |
196 | | - return nil |
197 | | - } |
198 | | - if parent.ID == current.ID { |
199 | | - return parent |
200 | | - } |
201 | | - return backtrack(current, parent.Parent) |
202 | | -} |
203 | | - |
204 | | -func getMxMicroflowEdgesByOrigin(edges []MxMicroflowEdge, originId string) []MxMicroflowEdge { |
205 | | - result := make([]MxMicroflowEdge, 0) |
206 | | - for _, edge := range edges { |
207 | | - if edge.Origin == originId { |
208 | | - result = append(result, edge) |
209 | | - } |
210 | | - } |
211 | | - return result |
212 | | -} |
213 | | - |
214 | | -func getMxMicroflowObjectByType(objs []MxMicroflowObject, objType string) (MxMicroflowObject, bool) { |
215 | | - for _, obj := range objs { |
216 | | - if obj.Type == objType { |
217 | | - return obj, true |
218 | | - } |
219 | | - } |
220 | | - return MxMicroflowObject{}, false |
221 | | -} |
222 | | - |
223 | | -func getMxMicroflowObjectByID(objs []MxMicroflowObject, objID string) (MxMicroflowObject, bool) { |
224 | | - for _, obj := range objs { |
225 | | - if obj.ID == objID { |
226 | | - return obj, true |
227 | | - } |
228 | | - } |
229 | | - return MxMicroflowObject{}, false |
230 | | -} |
231 | | - |
232 | | -func convertToMxMicroflowObjects(objs []interface{}) []MxMicroflowObject { |
233 | | - result := make([]MxMicroflowObject, 0, len(objs)) |
234 | | - for _, o := range objs { |
235 | | - castedObject, ok := o.(map[string]interface{}) |
236 | | - if !ok { |
237 | | - continue |
238 | | - } |
239 | | - objType, _ := castedObject["$Type"].(string) |
240 | | - id := readMicroflowID(castedObject["$ID"]) |
241 | | - if objType == "" || id == "" { |
242 | | - continue |
243 | | - } |
244 | | - result = append(result, MxMicroflowObject{ |
245 | | - Type: objType, |
246 | | - ID: id, |
247 | | - Attributes: castedObject, |
248 | | - }) |
249 | | - } |
250 | | - return result |
251 | | -} |
252 | | - |
253 | | -func convertToMxMicroflowEdges(flows []interface{}) []MxMicroflowEdge { |
254 | | - result := make([]MxMicroflowEdge, 0, len(flows)) |
255 | | - for _, f := range flows { |
256 | | - castedFlow, ok := f.(map[string]interface{}) |
257 | | - if !ok { |
258 | | - continue |
259 | | - } |
260 | | - flowType, _ := castedFlow["$Type"].(string) |
261 | | - id := readMicroflowID(castedFlow["$ID"]) |
262 | | - origin := readMicroflowID(castedFlow["OriginPointer"]) |
263 | | - destination := readMicroflowID(castedFlow["DestinationPointer"]) |
264 | | - if flowType == "" || id == "" || origin == "" || destination == "" { |
265 | | - continue |
266 | | - } |
267 | | - result = append(result, MxMicroflowEdge{ |
268 | | - Type: flowType, |
269 | | - ID: id, |
270 | | - Origin: origin, |
271 | | - Destination: destination, |
272 | | - Attributes: castedFlow, |
273 | | - }) |
274 | 13 | } |
275 | | - return result |
| 14 | + attributes["pseudocode"] = pseudocode |
276 | 15 | } |
0 commit comments