Skip to content

Commit

Permalink
feat(RouteDiagram): Proper visualisation of parallel processing of th…
Browse files Browse the repository at this point in the history
…e multicast
  • Loading branch information
mmelko committed Jul 12, 2024
1 parent e6a61a1 commit 736cce6
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type CamelNodeData = {
type: string
uri: string
routeId: string
isParallel: boolean
stats?: Statistics

nodeClicked?: (node: Node) => void
Expand Down Expand Up @@ -157,26 +158,26 @@ class VisualizationService {
): Promise<number[]> {
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
}
const nodeSettings = await schemaService.getSchema(node, nodeId)
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]}`
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -231,7 +233,9 @@ class VisualizationService {
type: nodeId,
uri: uri ?? '',
routeId: routeId,
isParallel: parallelProcessing,
}

if (rid) {
nodeData.cid = rid
}
Expand All @@ -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
}
}
Expand All @@ -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' ||
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="testRoute">
<from uri="direct:a"/>
<multicast parallelProcessing="true">
<to uri="direct:first"/>
<to uri="direct:second"/>
</multicast>
<to uri="direct:outside"/>
</route>
</routes>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="testRoute">
<from uri="direct:a"/>
<multicast>
<to uri="direct:first"/>
<to uri="direct:second"/>
</multicast>
<to uri="direct:outside"/>
</route>
</routes>

0 comments on commit 736cce6

Please sign in to comment.