diff --git a/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.test.ts b/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.test.ts index 97c53a85..6da19498 100644 --- a/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.test.ts +++ b/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.test.ts @@ -1,4 +1,4 @@ -import { visualizationService } from './visualization-service' +import { CamelNodeData, visualizationService } from './visualization-service' import path from 'path' import fs from 'fs' import { RouteStats } from '@hawtiosrc/plugins/camel/routes-service' @@ -9,9 +9,16 @@ jest.mock('@hawtiosrc/plugins/shared/jolokia-service') describe('visualization-service', () => { const routesXmlPath = path.resolve(__dirname, '../testdata', 'camel-choice-route.xml') const sampleRoutesXml = fs.readFileSync(routesXmlPath, { encoding: 'utf8', flag: 'r' }) + const routesStatsXmlPath = path.resolve(__dirname, '../testdata', 'camel-routes-stats.xml') const sampleRoutesStatsXml = fs.readFileSync(routesStatsXmlPath, { encoding: 'utf8', flag: 'r' }) + const multicastParallelRoutesXmlPath = path.resolve(__dirname, '../testdata', 'camel-multicast-parallel-route.xml') + const multicastParallelRouteXml = fs.readFileSync(multicastParallelRoutesXmlPath, { encoding: 'utf8', flag: 'r' }) + + const multicastRoutesXmlPath = path.resolve(__dirname, '../testdata', 'camel-multicast-route.xml') + const multicastRouteXml = fs.readFileSync(multicastRoutesXmlPath, { encoding: 'utf8', flag: 'r' }) + describe('loadRouteXmlNodes', () => { test('nodes and edges were correctly loaded from the file', async () => { const node = new MBeanNode(null, 'test', true) @@ -36,7 +43,36 @@ describe('visualization-service', () => { // check if label is parsed correctly expect(when2?.data.label).toBe(`When: \${body} == 'Hello Camel! - simple'`) }) + + test('should correctly link child nodes for multicast', async () => { + const node = new MBeanNode(null, 'test', true) + const { camelNodes, edges } = await visualizationService.loadRouteXmlNodes(node, multicastRouteXml) + expect(camelNodes.length).toBe(5) + expect(edges.length).toBe(4) + + expect(edges[2]!.target).toEqual(camelNodes[3]!.id) + expect(edges[2]!.source).toEqual(camelNodes[2]!.id) + + expect((camelNodes[2]!.data as CamelNodeData).uri).toEqual('direct:first') + expect((camelNodes[3]!.data as CamelNodeData).uri).toEqual('direct:second') + + expect(edges[3]!.target).toEqual(camelNodes[4]!.id) + expect((camelNodes[4]!.data as CamelNodeData).uri).toEqual('direct:outside') + }) + + test('should correctly link child nodes in parallel for multicast', async () => { + const node = new MBeanNode(null, 'test', true) + const { camelNodes, edges } = await visualizationService.loadRouteXmlNodes(node, multicastParallelRouteXml) + expect(camelNodes.length).toBe(5) + expect(edges.length).toBe(5) + + // check that both 'to' nodes are connected to direct:outsideNode + expect(edges[3]!.target).toEqual(camelNodes[4]!.id) + expect(edges[4]!.target).toEqual(camelNodes[4]!.id) + expect((camelNodes[4]!.data as CamelNodeData).uri).toEqual('direct:outside') // Each 'to' node inside multicast should have its own link + }) }) + describe('updateStats', () => { test('processor stats were updates on the nodes', async () => { const node = new MBeanNode(null, 'test', true) diff --git a/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.ts b/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.ts index 79115aba..51ac8ba5 100644 --- a/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.ts +++ b/packages/hawtio/src/plugins/camel/route-diagram/visualization-service.ts @@ -22,6 +22,7 @@ export type CamelNodeData = { type: string uri: string routeId: string + isParallel: boolean stats?: Statistics nodeClicked?: (node: Node) => void @@ -157,18 +158,18 @@ class VisualizationService { ): Promise { let rid = parent.getAttribute('id') let siblingNodes: number[] = [] - const parenNodeName: string = parent.localName + const parentNodeName: string = parent.localName /* * Whereas the id is unique across all routes in the xml, the * routeIdx defines an id for each node in the route so */ let routeIdx = -1 - for (const route of Array.from(parent.children)) { + for (const routeElement of Array.from(parent.children)) { const id: string = nodeDatas.length + '' routeIdx++ // from acts as a parent even though its a previous sibling :) - const nodeId = route.localName + const nodeId = routeElement.localName if (nodeId === 'from' && parentId !== '-1') { parentId = id } @@ -176,7 +177,7 @@ class VisualizationService { let nodeData: CamelNodeData | null = null if (nodeSettings) { let label: string = (nodeSettings['title'] as string) || (nodeId as string) - const uri = this.getRouteNodeUri(route) + const uri = this.getRouteNodeUri(routeElement) if (uri) { label += ` ${uri.split('?')[0]}` } @@ -185,10 +186,10 @@ class VisualizationService { tooltip += ' ' + uri } const { ignoreIdForLabel, maximumLabelWidth } = camelPreferencesService.loadOptions() - const elementID = route.getAttribute('id') + const elementID = routeElement.getAttribute('id') let labelSummary = label if (elementID) { - const customId = route.getAttribute('customId') + const customId = routeElement.getAttribute('customId') if (ignoreIdForLabel || !customId || customId === 'false') { labelSummary = 'id: ' + elementID } else { @@ -216,7 +217,8 @@ class VisualizationService { } } - let cid = route.getAttribute('_cid') || route.getAttribute('id') + let cid = routeElement.getAttribute('_cid') || routeElement.getAttribute('id') + const parallelProcessing: boolean = routeElement.getAttribute('parallelProcessing')?.toLowerCase() === 'true' nodeData = { id: id, routeIdx: routeIdx, @@ -231,7 +233,9 @@ class VisualizationService { type: nodeId, uri: uri ?? '', routeId: routeId, + isParallel: parallelProcessing, } + if (rid) { nodeData.cid = rid } @@ -244,13 +248,18 @@ class VisualizationService { // only use the route id on the first from node rid = null nodeDatas.push(nodeData) + const isParallelMulticastParent = (parentNodeName === 'multicast' && parentNode?.isParallel) || false if (parentId !== null && parentId !== id) { - if (siblingNodes.length === 0 || parenNodeName === 'choice') { + if (siblingNodes.length === 0 || parentNodeName === 'choice' || isParallelMulticastParent) { links.push({ id: parentId + '-' + id, source: parentId + '', target: id }) + if (isParallelMulticastParent) { + siblingNodes.push(parseInt(id)) + } } else { siblingNodes.forEach(function (nodeId) { links.push({ id: nodeId + '-' + id, source: nodeId + '', target: id }) }) + siblingNodes.length = 0 } } @@ -260,19 +269,20 @@ class VisualizationService { if (langSettings && parentNode) { // lets add the language kind const name = langSettings['name'] || nodeId - const text = route.textContent + const text = routeElement.textContent if (text) { parentNode.tooltip = parentNode.label + ' ' + name + ' ' + text - parentNode.label += ': ' + this.appendLabel(route, text, true) + parentNode.label += ': ' + this.appendLabel(routeElement, text, true) } else { - parentNode.label += ': ' + this.appendLabel(route, name, false) + parentNode.label += ': ' + this.appendLabel(routeElement, name, false) } } } - const siblings = await this.addRouteXmlChildren(node, route, nodeDatas, links, routeId, id, nodeData) - if (parenNodeName === 'choice') { + const siblings = await this.addRouteXmlChildren(node, routeElement, nodeDatas, links, routeId, id, nodeData) + + if (parentNodeName === 'choice' || (parentNodeName === 'multicast' && parentNode?.isParallel)) { siblingNodes = siblingNodes.concat(siblings) } else if ( nodeId === 'aggregate' || diff --git a/packages/hawtio/src/plugins/camel/testdata/camel-multicast-parallel-route.xml b/packages/hawtio/src/plugins/camel/testdata/camel-multicast-parallel-route.xml new file mode 100644 index 00000000..988292de --- /dev/null +++ b/packages/hawtio/src/plugins/camel/testdata/camel-multicast-parallel-route.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/hawtio/src/plugins/camel/testdata/camel-multicast-route.xml b/packages/hawtio/src/plugins/camel/testdata/camel-multicast-route.xml new file mode 100644 index 00000000..b34a7c5a --- /dev/null +++ b/packages/hawtio/src/plugins/camel/testdata/camel-multicast-route.xml @@ -0,0 +1,10 @@ + + + + + + + + + +