karavan-core 4.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. package/.bebelrc +3 -0
  2. package/.mocharc.json +11 -0
  3. package/.prettierignore +9 -0
  4. package/.prettierrc +14 -0
  5. package/package.json +62 -0
  6. package/src/core/api/CamelDefinitionApi.ts +3271 -0
  7. package/src/core/api/CamelDefinitionApiExt.ts +757 -0
  8. package/src/core/api/CamelDefinitionYaml.ts +412 -0
  9. package/src/core/api/CamelDefinitionYamlStep.ts +4733 -0
  10. package/src/core/api/CamelDisplayUtil.ts +143 -0
  11. package/src/core/api/CamelUtil.ts +360 -0
  12. package/src/core/api/ComponentApi.ts +368 -0
  13. package/src/core/api/KameletApi.ts +147 -0
  14. package/src/core/api/MainConfigurationApi.ts +47 -0
  15. package/src/core/api/ProjectModelApi.ts +75 -0
  16. package/src/core/api/SpiBeanApi.ts +104 -0
  17. package/src/core/api/TemplateApi.ts +58 -0
  18. package/src/core/api/TopologyUtils.ts +392 -0
  19. package/src/core/api/VariableUtil.ts +104 -0
  20. package/src/core/model/CamelDefinition.ts +3783 -0
  21. package/src/core/model/CamelMetadata.ts +2714 -0
  22. package/src/core/model/ComponentModels.ts +106 -0
  23. package/src/core/model/IntegrationDefinition.ts +188 -0
  24. package/src/core/model/KameletModels.ts +223 -0
  25. package/src/core/model/MainConfigurationModel.ts +37 -0
  26. package/src/core/model/ProjectModel.ts +43 -0
  27. package/src/core/model/SpiBeanModels.ts +53 -0
  28. package/src/core/model/TopologyDefinition.ts +117 -0
  29. package/test/addStep.spec.ts +124 -0
  30. package/test/addStep1.yaml +27 -0
  31. package/test/allowableValues.camel.yaml +19 -0
  32. package/test/allowableValues.spec.ts +30 -0
  33. package/test/avro-serialize-action.kamelet.yaml +70 -0
  34. package/test/beans.spec.ts +92 -0
  35. package/test/beans1.yaml +36 -0
  36. package/test/beans2.yaml +42 -0
  37. package/test/beans3.yaml +7 -0
  38. package/test/checkRequired.spec.ts +53 -0
  39. package/test/circuitBreaker.spec.ts +57 -0
  40. package/test/circuitBreaker.yaml +19 -0
  41. package/test/cloneDefinition.spec.ts +106 -0
  42. package/test/createKamelet.spec.ts +38 -0
  43. package/test/cxf.json +615 -0
  44. package/test/cxf.spec.ts +44 -0
  45. package/test/cxf.yaml +15 -0
  46. package/test/deleteStep.spec.ts +74 -0
  47. package/test/demo.spec.ts +49 -0
  48. package/test/demo.yaml +32 -0
  49. package/test/doCatchOnWhen.camel.yaml +20 -0
  50. package/test/doCatchOnWhen.spec.ts +36 -0
  51. package/test/errorHandler.spec.ts +38 -0
  52. package/test/errorHandler1.yaml +27 -0
  53. package/test/expression.spec.ts +55 -0
  54. package/test/findStep.spec.ts +112 -0
  55. package/test/findStep.yaml +65 -0
  56. package/test/getElementProperties.spec.ts +32 -0
  57. package/test/getElementPropertiesByName.spec.ts +31 -0
  58. package/test/getExpressionLanguage.spec.ts +40 -0
  59. package/test/hasElementWithId.camel.yaml +98 -0
  60. package/test/hasElementWithId.spec.ts +57 -0
  61. package/test/hasElementWithId1.camel.yaml +16 -0
  62. package/test/hasElementWithIdError.camel.yaml +98 -0
  63. package/test/integration.spec.ts +60 -0
  64. package/test/integration1.yaml +24 -0
  65. package/test/integration2.yaml +23 -0
  66. package/test/integrationToYaml.spec.ts +51 -0
  67. package/test/intercept.spec.ts +62 -0
  68. package/test/intercept.yaml +19 -0
  69. package/test/is-not-integration.yaml +5114 -0
  70. package/test/isIntegration.spec.ts +45 -0
  71. package/test/kamelet.spec.ts +61 -0
  72. package/test/metadata/components.json +697 -0
  73. package/test/metadata/kamelets.yaml +23414 -0
  74. package/test/metadata/spiBeans.json +3094 -0
  75. package/test/multiObjectProperties.spec.ts +46 -0
  76. package/test/multiObjectProperties1.yaml +19 -0
  77. package/test/multiple.spec.ts +38 -0
  78. package/test/multiple.yaml +29 -0
  79. package/test/openapi.spec.ts +48 -0
  80. package/test/openapi.yaml +7 -0
  81. package/test/placeholder.spec.ts +32 -0
  82. package/test/placeholder.yaml +133 -0
  83. package/test/plain-try-catch.yaml +31 -0
  84. package/test/plain.spec.ts +72 -0
  85. package/test/plain1.yaml +22 -0
  86. package/test/plain2.yaml +13 -0
  87. package/test/plain3.yaml +5 -0
  88. package/test/plain4.yaml +5 -0
  89. package/test/postgresql-source.kamelet.yaml +113 -0
  90. package/test/restConfigDsl.yaml +15 -0
  91. package/test/restDsl.spec.ts +83 -0
  92. package/test/restDsl.yaml +29 -0
  93. package/test/routes.spec.ts +37 -0
  94. package/test/routes1.yaml +31 -0
  95. package/test/supported-components.json +1221 -0
  96. package/test/supportedComponents.spec.ts +34 -0
  97. package/test/template1.AggregationStrategy.java +21 -0
  98. package/test/template1.Processor.java +13 -0
  99. package/test/template2.AggregationStrategy.java +21 -0
  100. package/test/template2.Processor.java +13 -0
  101. package/test/templateApi.spec.ts +45 -0
  102. package/test/timer-source.kamelet.yaml +75 -0
  103. package/test/tod.spec.ts +31 -0
  104. package/test/tod.yaml +9 -0
  105. package/test/topology.spec.ts +51 -0
  106. package/test/topology1.camel.yaml +56 -0
  107. package/test/topology2.camel.yaml +44 -0
  108. package/test/topology3.camel.yaml +27 -0
  109. package/test/tsconfig.testing.json +14 -0
  110. package/test/updateStep.spec.ts +72 -0
  111. package/test/variable1.camel.yaml +42 -0
  112. package/test/variable2.camel.yaml +42 -0
  113. package/test/variables.spec.ts +34 -0
  114. package/tsconfig.json +34 -0
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one or more
3
+ * contributor license agreements. See the NOTICE file distributed with
4
+ * this work for additional information regarding copyright ownership.
5
+ * The ASF licenses this file to You under the Apache License, Version 2.0
6
+ * (the "License"); you may not use this file except in compliance with
7
+ * the License. You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { SpiBean, SpiBeanProperty } from '../model/SpiBeanModels';
18
+ import { CamelElement } from '../model/IntegrationDefinition';
19
+
20
+ const SpiBeans: SpiBean[] = [];
21
+
22
+ export class SpiBeanApi {
23
+ private constructor() {}
24
+
25
+ static jsonToSpiBean = (json: string): SpiBean => {
26
+ const fromJson: SpiBean = JSON.parse(json).bean as SpiBean;
27
+ return new SpiBean(fromJson);
28
+ };
29
+
30
+ static saveSpiBeans = (jsons: string[], clean: boolean = false): void => {
31
+ if (clean) SpiBeans.length = 0;
32
+ const spiBeans: SpiBean[] = jsons.map(json => SpiBeanApi.jsonToSpiBean(json));
33
+ SpiBeans.push(...spiBeans);
34
+ };
35
+
36
+ static saveSpiBean = (json: string): void => {
37
+ const spiBean: SpiBean = SpiBeanApi.jsonToSpiBean(json);
38
+ if (SpiBeans.findIndex((c: SpiBean) => c.name === spiBean.name) === -1) {
39
+ SpiBeans.push(spiBean);
40
+ }
41
+ };
42
+
43
+ static getSpiBeans = (): SpiBean[] => {
44
+ const comps: SpiBean[] = [];
45
+ comps.push(...SpiBeans);
46
+ return comps;
47
+ };
48
+
49
+ static findByName = (name: string): SpiBean | undefined => {
50
+ return SpiBeanApi.getSpiBeans().find((c: SpiBean) => c.name === name);
51
+ };
52
+
53
+ static findByInterfaceType = (interfaceType: string): SpiBean[] => {
54
+ return SpiBeanApi.getSpiBeans().filter((c: SpiBean) => c.interfaceType === interfaceType);
55
+ };
56
+
57
+ // Beans without properties or without required properties
58
+ static findByInterfaceTypeSimple = (interfaceType: string): SpiBean[] => {
59
+ return SpiBeanApi.getSpiBeans().filter((c: SpiBean) => {
60
+ if (c.interfaceType === interfaceType) {
61
+ const props = c.properties;
62
+ if (props === undefined) {
63
+ return true;
64
+ } else {
65
+ return Object.getOwnPropertyNames(props).filter((name: string) => props[name].required).length == 0;
66
+ }
67
+ }
68
+ return false;
69
+ });
70
+ };
71
+
72
+ static findStepSpiBean = (step?: CamelElement): SpiBean | undefined => {
73
+ return SpiBeanApi.findByName((step as any)?.uri)
74
+ };
75
+
76
+ static getSpiBeanProperties = (spiBeanName: string): SpiBeanProperty[] => {
77
+ const spiBean: SpiBean | undefined = SpiBeanApi.findByName(spiBeanName);
78
+ const properties: SpiBeanProperty[] = [];
79
+ if (spiBean !== undefined && spiBean.properties) {
80
+ for (const [key, value] of Object.entries(spiBean.properties) as [string, any][]) {
81
+ const prop = new SpiBeanProperty();
82
+ prop.name = key;
83
+ prop.index = value.index;
84
+ prop.description = value.description;
85
+ prop.type = value.type;
86
+ prop.displayName = value.displayName;
87
+ prop.javaType = value.javaType;
88
+ prop.type = value.type;
89
+ prop.deprecated = value.deprecated;
90
+ prop.secret = value.secret;
91
+ prop.autowired = value.autowired;
92
+ prop.kind = value.kind;
93
+ prop.required = value.required;
94
+ if (value.defaultValue) {
95
+ prop.defaultValue = value.defaultValue;
96
+ }
97
+ if (!value.deprecated) {
98
+ properties.push(prop);
99
+ }
100
+ }
101
+ }
102
+ return Array.from(new Map(properties.map(item => [item.name, item])).values());
103
+ };
104
+ }
@@ -0,0 +1,58 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one or more
3
+ * contributor license agreements. See the NOTICE file distributed with
4
+ * this work for additional information regarding copyright ownership.
5
+ * The ASF licenses this file to You under the Apache License, Version 2.0
6
+ * (the "License"); you may not use this file except in compliance with
7
+ * the License. You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ const Templates: Map<string, string> = new Map<string, string>();
19
+ const JavaCode: Map<string, string> = new Map<string, string>();
20
+
21
+ export class TemplateApi {
22
+ private constructor() {}
23
+
24
+ static saveTemplates = (templates: Map<string, string>, clean: boolean = false): void => {
25
+ if (clean) Templates.clear();
26
+ templates.forEach((value, key) => Templates.set(key, value));
27
+ };
28
+
29
+ static saveTemplate = (name: string, code: string): void => {
30
+ Templates.set(name, code);
31
+ };
32
+
33
+ static getTemplate = (name: string): string | undefined => {
34
+ return Templates.get(name);
35
+ };
36
+
37
+ static generateCode = (name: string, beanName: string): string | undefined => {
38
+ let template: string | undefined = TemplateApi.getTemplate(name);
39
+ if (template) {
40
+ return template.replaceAll('${NAME}', beanName);
41
+ } else {
42
+ throw new Error('Template not found');
43
+ }
44
+ };
45
+
46
+ static saveJavaCodes = (javaCode: Map<string, string>, clean: boolean = false): void => {
47
+ if (clean) JavaCode.clear();
48
+ javaCode.forEach((value, key) => JavaCode.set(key, value));
49
+ };
50
+
51
+ static saveJavaCode = (name: string, code: string): void => {
52
+ JavaCode.set(name, code);
53
+ };
54
+
55
+ static getJavaCode = (name: string): string | undefined => {
56
+ return JavaCode.get(name);
57
+ };
58
+ }
@@ -0,0 +1,392 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one or more
3
+ * contributor license agreements. See the NOTICE file distributed with
4
+ * this work for additional information regarding copyright ownership.
5
+ * The ASF licenses this file to You under the Apache License, Version 2.0
6
+ * (the "License"); you may not use this file except in compliance with
7
+ * the License. You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import {
18
+ DeleteDefinition,
19
+ FromDefinition,
20
+ GetDefinition,
21
+ HeadDefinition,
22
+ PatchDefinition,
23
+ PostDefinition,
24
+ PutDefinition,
25
+ RestDefinition, RouteConfigurationDefinition, RouteDefinition, SagaDefinition,
26
+ } from '../model/CamelDefinition';
27
+ import {
28
+ CamelElement,
29
+ Integration,
30
+ } from '../model/IntegrationDefinition';
31
+ import {
32
+ TopologyIncomingNode,
33
+ TopologyOutgoingNode,
34
+ TopologyRestNode, TopologyRouteConfigurationNode,
35
+ TopologyRouteNode,
36
+ } from '../model/TopologyDefinition';
37
+ import { ComponentApi, INTERNAL_COMPONENTS } from './ComponentApi';
38
+ import { CamelDefinitionApiExt } from './CamelDefinitionApiExt';
39
+ import { CamelDisplayUtil } from './CamelDisplayUtil';
40
+ import { CamelUtil } from './CamelUtil';
41
+
42
+ const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', 'PollEnrichDefinition', 'EnrichDefinition', 'WireTapDefinition', 'SagaDefinition', 'PollDefinition'];
43
+
44
+ export class ChildElement {
45
+ constructor(public name: string = '', public className: string = '', public multiple: boolean = false) {
46
+ }
47
+ }
48
+
49
+ export class TopologyUtils {
50
+ private constructor() {
51
+ }
52
+
53
+ static getOutgoingDefinitions = (): string[] => {
54
+ return outgoingDefinitions;
55
+ };
56
+
57
+ static isElementInternalComponent = (element: CamelElement): boolean => {
58
+ const uri = (element as any).uri;
59
+ const component = ComponentApi.findByName(uri);
60
+ if (INTERNAL_COMPONENTS.includes(uri?.split(':')?.[0])) return true;
61
+ return component !== undefined && component.component.remote !== true;
62
+ };
63
+
64
+ static getConnectorType = (element: CamelElement): 'component' | 'kamelet' => {
65
+ return CamelUtil.isKameletComponent(element) ? 'kamelet' : 'component';
66
+ };
67
+
68
+ static cutKameletUriSuffix = (uri: string): string => {
69
+ if (uri.endsWith('-sink')) {
70
+ return uri.substring(0, uri.length - 5);
71
+ } else if (uri.endsWith('-source')) {
72
+ return uri.substring(0, uri.length - 7);
73
+ } else if (uri.endsWith('-action')) {
74
+ return uri.substring(0, uri.length - 7);
75
+ } else {
76
+ return uri;
77
+ }
78
+ };
79
+
80
+ static getUniqueUri = (element: CamelElement): string => {
81
+ const uri: string = (element as any).uri || '';
82
+ let result = uri.startsWith('kamelet') ? TopologyUtils.cutKameletUriSuffix(uri).concat(':') : uri.concat(':');
83
+ const className = element.dslName;
84
+ if (className === 'FromDefinition' || className === 'ToDefinition') {
85
+ if (!CamelUtil.isKameletComponent(element)) {
86
+ const requiredProperties = CamelUtil.getComponentProperties(element).filter(p => p.required);
87
+ for (const property of requiredProperties) {
88
+ const value = CamelDefinitionApiExt.getParametersValue(element, property.name, property.kind === 'path');
89
+ if (value !== undefined && property.type === 'string' && value.trim().length > 0) {
90
+ result = result + property.name + '=' + value + '&';
91
+ }
92
+ }
93
+ } else {
94
+ const requiredProperties = CamelUtil.getKameletProperties(element, true);
95
+ for (const property of requiredProperties) {
96
+ const value = CamelDefinitionApiExt.getParametersValue(element, property.id);
97
+ if (value !== undefined && property.type === 'string' && value.toString().trim().length > 0) {
98
+ result = result + property.id + '=' + value + '&';
99
+ }
100
+ }
101
+ }
102
+ }
103
+ return result.endsWith('&') ? result.substring(0, result.length - 1) : result;
104
+ };
105
+
106
+ static hasDirectUri = (element: CamelElement): boolean => {
107
+ return this.hasUriStartWith(element, 'direct');
108
+ };
109
+
110
+ static hasSedaUri = (element: CamelElement): boolean => {
111
+ return this.hasUriStartWith(element, 'seda');
112
+ };
113
+
114
+ static hasUriStartWith = (element: CamelElement, text: string): boolean => {
115
+ if ((element as any).uri && typeof (element as any).uri === 'string') {
116
+ return (element as any).uri.startsWith(text);
117
+ } else if (element.dslName === 'SagaDefinition') {
118
+ const completion = (element as SagaDefinition).completion || '';
119
+ const compensation = (element as SagaDefinition).compensation || '';
120
+ return completion.startsWith(text) || compensation.startsWith(text);
121
+ } else {
122
+ return false;
123
+ }
124
+ };
125
+
126
+ static findTopologyRestNodes = (integration: Integration[]): TopologyRestNode[] => {
127
+ const result: TopologyRestNode[] = [];
128
+ integration.forEach(i => {
129
+ try {
130
+ const filename = i.metadata.name;
131
+ const routes = i.spec.flows?.filter(flow => flow.dslName === 'RestDefinition');
132
+ routes?.forEach((rest: RestDefinition) => {
133
+ const uris: string[] = [];
134
+ rest?.get?.forEach((d: GetDefinition) => {
135
+ if (d.to) uris.push(d.to);
136
+ });
137
+ rest?.post?.forEach((d: PostDefinition) => {
138
+ if (d.to) uris.push(d.to);
139
+ });
140
+ rest?.put?.forEach((d: PutDefinition) => {
141
+ if (d.to) uris.push(d.to);
142
+ });
143
+ rest?.delete?.forEach((d: DeleteDefinition) => {
144
+ if (d.to) uris.push(d.to);
145
+ });
146
+ rest?.patch?.forEach((d: PatchDefinition) => {
147
+ if (d.to) uris.push(d.to);
148
+ });
149
+ rest?.head?.forEach((d: HeadDefinition) => {
150
+ if (d.to) uris.push(d.to);
151
+ });
152
+ const title = '' + (rest.description ? rest.description : rest.id);
153
+ result.push(new TopologyRestNode(rest.path || '', '' + rest.id, uris, title, filename, rest));
154
+ });
155
+ } catch (e) {
156
+ console.error(e);
157
+ }
158
+ });
159
+ return result;
160
+ };
161
+
162
+ static findTopologyIncomingNodes = (integration: Integration[]): TopologyIncomingNode[] => {
163
+ const result: TopologyIncomingNode[] = [];
164
+ integration.forEach(i => {
165
+ try {
166
+ const filename = i.metadata.name;
167
+ const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition');
168
+ const routeElements = routes?.map(r => {
169
+ const id = 'incoming-' + r.id;
170
+ const title = CamelDisplayUtil.getStepDescription(r.from);
171
+ const type = TopologyUtils.isElementInternalComponent(r.from) ? 'internal' : 'external';
172
+ const connectorType = TopologyUtils.getConnectorType(r.from);
173
+ const uniqueUri = TopologyUtils.getUniqueUri(r.from);
174
+ return new TopologyIncomingNode(id, type, connectorType, r.id, title, filename, r.from, uniqueUri);
175
+ }) || [];
176
+ result.push(...routeElements);
177
+ } catch (e) {
178
+ console.error(e);
179
+ }
180
+ });
181
+ return result;
182
+ };
183
+
184
+ static findTopologyRouteNodes = (integration: Integration[]): TopologyRouteNode[] => {
185
+ const result: TopologyRouteNode[] = [];
186
+ integration.forEach(i => {
187
+ try {
188
+ const filename = i.metadata.name;
189
+ const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition');
190
+ const routeElements = routes?.map(r => {
191
+ const id = 'route-' + r.id;
192
+ const title = '' + (r.description ? r.description : r.id);
193
+ return new TopologyRouteNode(id, r.id, title, filename, r.from, r);
194
+ }) || [];
195
+ result.push(...routeElements);
196
+ } catch (e) {
197
+ console.error(e);
198
+ }
199
+ });
200
+ return result;
201
+ };
202
+
203
+ static findTopologyRouteConfigurationNodes = (integration: Integration[]): TopologyRouteConfigurationNode[] => {
204
+ const result: TopologyRouteConfigurationNode[] = [];
205
+ integration.forEach(i => {
206
+ try {
207
+ const filename = i.metadata.name;
208
+ const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteConfigurationDefinition');
209
+ const routeElements = routes?.map(r => {
210
+ const id = 'route-' + r.id;
211
+ const title = '' + (r.description ? r.description : r.id);
212
+ return new TopologyRouteConfigurationNode(id, r.id, title, filename, r);
213
+ }) || [];
214
+ result.push(...routeElements);
215
+ } catch (e) {
216
+ console.error(e);
217
+ }
218
+ });
219
+ return result;
220
+ };
221
+
222
+ static findTopologyRouteOutgoingNodes = (integrations: Integration[]): TopologyOutgoingNode[] => {
223
+ const result: TopologyOutgoingNode[] = [];
224
+ integrations.forEach(i => {
225
+ try {
226
+ const filename = i.metadata.name;
227
+ const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition');
228
+ routes?.forEach(route => {
229
+ const from: FromDefinition = route.from;
230
+ const elements = TopologyUtils.findOutgoingInStep(from, []);
231
+ elements.forEach((e: any) => {
232
+ const id = 'outgoing-' + route.id + '-' + e.id;
233
+ const title = CamelDisplayUtil.getStepDescription(e);
234
+ const type = TopologyUtils.isElementInternalComponent(e) ? 'internal' : 'external';
235
+ const connectorType = TopologyUtils.getConnectorType(e);
236
+ const uniqueUri = TopologyUtils.getUniqueUri(e);
237
+ if (
238
+ connectorType !== 'kamelet' ||
239
+ CamelUtil.getKamelet(e)?.metadata.labels['camel.apache.org/kamelet.type'] !== 'action'
240
+ ) {
241
+ result.push(new TopologyOutgoingNode(id, type, connectorType, route.id, title, filename, e, uniqueUri));
242
+ }
243
+ });
244
+ result.push(...TopologyUtils.findDeadLetterChannelNodes(route, filename));
245
+ });
246
+ } catch (e) {
247
+ console.error(e);
248
+ }
249
+ });
250
+ return result;
251
+ };
252
+
253
+ static findDeadLetterChannelNodes(route: RouteDefinition, filename: string): TopologyOutgoingNode[] {
254
+ const result: TopologyOutgoingNode[] = [];
255
+ try {
256
+ const deadLetterChannel = route.errorHandler?.deadLetterChannel;
257
+ const deadLetterUri = deadLetterChannel?.deadLetterUri;
258
+ if (deadLetterChannel !== undefined && deadLetterUri !== undefined) {
259
+ const parts = deadLetterUri.split(':');
260
+ if (parts.length > 1 && INTERNAL_COMPONENTS.includes(parts[0])) {
261
+ const id = 'outgoing-' + route.id + '-' + deadLetterChannel?.id;
262
+ const title = CamelDisplayUtil.getStepDescription(deadLetterChannel);
263
+ const type = 'internal';
264
+ const connectorType = 'component';
265
+ result.push(new TopologyOutgoingNode(id, type, connectorType, route.id || '', title, filename, deadLetterChannel, deadLetterUri));
266
+ }
267
+ }
268
+ } catch (e) {
269
+ console.error(e);
270
+ }
271
+ return result;
272
+ }
273
+
274
+ static findTopologyRouteConfigurationOutgoingNodes = (integrations: Integration[]): TopologyOutgoingNode[] => {
275
+ const result: TopologyOutgoingNode[] = [];
276
+ integrations.forEach(i => {
277
+ try {
278
+ const filename = i.metadata.name;
279
+ const rcs = i.spec.flows?.filter(flow => flow.dslName === 'RouteConfigurationDefinition');
280
+ rcs?.forEach((rc: RouteConfigurationDefinition) => {
281
+ const children: CamelElement[] = [];
282
+ children.push(...rc.intercept || []);
283
+ children.push(...rc.interceptFrom || []);
284
+ children.push(...rc.interceptSendToEndpoint || []);
285
+ children.push(...rc.onCompletion || []);
286
+ children.push(...rc.onException || []);
287
+ children.forEach(child => {
288
+ const elements = TopologyUtils.findOutgoingInStep(child, []);
289
+ elements.forEach((e: any) => {
290
+ const id = 'outgoing-' + rc.id + '-' + e.id;
291
+ const title = CamelDisplayUtil.getStepDescription(e);
292
+ const type = TopologyUtils.isElementInternalComponent(e) ? 'internal' : 'external';
293
+ const connectorType = TopologyUtils.getConnectorType(e);
294
+ const uniqueUri = TopologyUtils.getUniqueUri(e);
295
+ result.push(new TopologyOutgoingNode(id, type, connectorType, rc.id || 'undefined', title, filename, e, uniqueUri));
296
+ });
297
+ });
298
+ if (rc.errorHandler?.deadLetterChannel) {
299
+ const e = rc.errorHandler?.deadLetterChannel;
300
+ const id = 'outgoing-' + rc.id + '-' + e.id;
301
+ const title = CamelDisplayUtil.getStepDescription(e);
302
+ const comp = e?.deadLetterUri?.split(':')?.[0];
303
+ const type = INTERNAL_COMPONENTS.includes(comp) ? 'internal' : 'external';
304
+ const connectorType = 'component';
305
+ const uniqueUri = e?.deadLetterUri;
306
+ result.push(new TopologyOutgoingNode(id, type, connectorType, rc.id || 'undefined', title, filename, e, uniqueUri));
307
+ }
308
+ });
309
+ } catch (e) {
310
+ console.error(e);
311
+ }
312
+ });
313
+ return result;
314
+ };
315
+
316
+ static findOutgoingInStep = (step: CamelElement, result: CamelElement[]): CamelElement[] => {
317
+ if (step !== undefined) {
318
+ const el = (step as any);
319
+ try {
320
+ if (outgoingDefinitions.includes(el.dslName)) {
321
+ result.push(step);
322
+ } else {
323
+ const childElements = CamelDefinitionApiExt.getElementChildrenDefinition(el.dslName);
324
+ childElements.forEach(child => {
325
+ if (child.multiple) {
326
+ const sub = (el[child.name] as CamelElement[]);
327
+ TopologyUtils.findOutgoingInSteps(sub, result);
328
+ } else {
329
+ const sub = (el[child.name] as CamelElement);
330
+ TopologyUtils.findOutgoingInStep(sub, result);
331
+ }
332
+ });
333
+ }
334
+ } catch (e) {
335
+ console.error(e);
336
+ }
337
+ }
338
+ return result;
339
+ };
340
+
341
+ static findOutgoingInSteps = (steps: CamelElement[], result: CamelElement[]): CamelElement[] => {
342
+ if (steps !== undefined && steps.length > 0) {
343
+ steps.forEach(step => TopologyUtils.findOutgoingInStep(step, result));
344
+ }
345
+ return result;
346
+ };
347
+
348
+ static getNodeIdByUriAndName(tins: TopologyIncomingNode[], uri: string, name: string): string | undefined {
349
+ if (uri && name) {
350
+ const node = tins
351
+ .filter(r => r.from.uri === uri
352
+ && (r?.from?.parameters?.name === name || r?.from?.parameters?.address === name),
353
+ ).at(0);
354
+ if (node) {
355
+ return node.id;
356
+ }
357
+ }
358
+ }
359
+
360
+ static getNodeIdByUri(tins: TopologyIncomingNode[], uri: string): string | undefined {
361
+ const parts = uri.split(':');
362
+ if (parts.length > 1) {
363
+ return TopologyUtils.getNodeIdByUriAndName(tins, parts[0], parts[1]);
364
+ }
365
+ }
366
+
367
+ static getRouteIdByUriAndName(tins: TopologyIncomingNode[], uri: string, name: string): string | undefined {
368
+ if (uri && name) {
369
+ const node = tins
370
+ .filter(r => r.from.uri === uri
371
+ && (r?.from?.parameters?.name === name || r?.from?.parameters?.address === name),
372
+ ).at(0);
373
+ if (node) {
374
+ return 'route-' + node.routeId;
375
+ }
376
+ }
377
+ }
378
+
379
+ static getNodeIdByUniqueUri(tins: TopologyIncomingNode[], uniqueUri: string): string [] {
380
+ const result: string[] = [];
381
+ tins.filter(r => r.uniqueUri === uniqueUri)
382
+ ?.forEach(node => result.push(node.id));
383
+ return result;
384
+ }
385
+
386
+ static getRouteIdByUri(tins: TopologyIncomingNode[], uri: string): string | undefined {
387
+ const parts = uri.split(':');
388
+ if (parts.length > 1) {
389
+ return TopologyUtils.getRouteIdByUriAndName(tins, parts[0], parts[1]);
390
+ }
391
+ }
392
+ }
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one or more
3
+ * contributor license agreements. See the NOTICE file distributed with
4
+ * this work for additional information regarding copyright ownership.
5
+ * The ASF licenses this file to You under the Apache License, Version 2.0
6
+ * (the 'License'); you may not use this file except in compliance with
7
+ * the License. You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an 'AS IS' BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import {
18
+ CamelElement, Integration,
19
+ IntegrationFile,
20
+ } from '../model/IntegrationDefinition';
21
+ import { CamelDefinitionYaml } from './CamelDefinitionYaml';
22
+ import { FromDefinition} from '../model/CamelDefinition';
23
+ import { CamelDefinitionApiExt } from './CamelDefinitionApiExt';
24
+
25
+ const sendReceiveDSL: string[] =
26
+ ['ToDefinition', 'FromDefinition', 'ToDynamicDefinition', 'PollEnrichDefinition',
27
+ 'EnrichDefinition', 'WireTapDefinition', 'UnmarshalDefinition', 'MarshalDefinition'];
28
+
29
+ export const GLOBAL = 'global:';
30
+ export const ROUTE = 'route:';
31
+
32
+
33
+ export class VariableUtil {
34
+ private constructor() {
35
+ }
36
+
37
+ static findVariables = (files: IntegrationFile[]): string[] => {
38
+ const integrations = files.filter(file => file.name?.endsWith(".camel.yaml"))
39
+ .map(file => CamelDefinitionYaml.yamlToIntegration(file.name, file.code));
40
+ return VariableUtil.findVariablesInIntegrations(integrations);
41
+ };
42
+
43
+ static findVariablesInIntegrations = (integrations: Integration[]): string[] => {
44
+ const result: string[] = []
45
+ integrations.forEach(i => {
46
+ const filename = i.metadata.name;
47
+ const routes = i.spec.flows?.filter(flow => flow.dslName === 'RouteDefinition');
48
+ routes?.forEach(route => {
49
+ const from: FromDefinition = route.from;
50
+ VariableUtil.findVariablesInStep(from, result);
51
+ })
52
+
53
+ })
54
+ return VariableUtil.sortVariables(result);
55
+ };
56
+
57
+ static sortVariables = (variables: string[]): string [] => {
58
+ const global = [...new Set(variables.filter(v => v && v.startsWith(GLOBAL)))].sort();
59
+ const route = [...new Set(variables.filter(v => v && v.startsWith(ROUTE)))].sort();
60
+ const exchange = [...new Set(variables.filter(v => v && !v.startsWith(ROUTE) && !v.startsWith(GLOBAL)))].sort();
61
+ return global.concat(route, exchange);
62
+ }
63
+
64
+ static findVariablesInStep = (step: CamelElement, result: string[]) => {
65
+ if (step !== undefined) {
66
+ const el = (step as any);
67
+ if (sendReceiveDSL.includes(el.dslName)) {
68
+ VariableUtil.findVariablesInProps(el, 'variableSend', result);
69
+ VariableUtil.findVariablesInProps(el, 'variableReceive', result);
70
+ } else if (el.dslName === 'ConvertVariableDefinition') {
71
+ VariableUtil.findVariablesInProps(el, 'name', result);
72
+ VariableUtil.findVariablesInProps(el, 'toName', result);
73
+ } else if (el.dslName === 'SetVariableDefinition') {
74
+ VariableUtil.findVariablesInProps(el, 'name', result);
75
+ } else if (el.dslName === 'RemoveVariableDefinition') {
76
+ VariableUtil.findVariablesInProps(el, 'name', result);
77
+ }
78
+ // check children elements
79
+ const childElements = CamelDefinitionApiExt.getElementChildrenDefinition(el.dslName);
80
+ childElements.forEach(child => {
81
+ if (child.multiple) {
82
+ const sub = (el[child.name] as CamelElement[]);
83
+ VariableUtil.findVariablesInSteps(sub, result);
84
+ } else {
85
+ const sub = (el[child.name] as CamelElement);
86
+ VariableUtil.findVariablesInStep(sub, result);
87
+ }
88
+ })
89
+ }
90
+ }
91
+
92
+ static findVariablesInSteps = (steps: CamelElement[], result: string[]) => {
93
+ if (steps !== undefined && steps.length > 0) {
94
+ steps.forEach(step => VariableUtil.findVariablesInStep(step, result))
95
+ }
96
+ }
97
+
98
+ static findVariablesInProps = (step: CamelElement, propertyName: string, result: string[]) => {
99
+ const el = (step as any);
100
+ if (el.hasOwnProperty(propertyName)) {
101
+ result.push(el[propertyName])
102
+ }
103
+ }
104
+ }