Skip to content

Commit 8405a9e

Browse files
committed
Use array of strings for methods in data model
1 parent f38e67e commit 8405a9e

23 files changed

Lines changed: 439 additions & 4285 deletions

public/resources/preset-landscapes/distributed-petclinic.json

Lines changed: 1 addition & 1895 deletions
Large diffs are not rendered by default.

public/resources/preset-landscapes/petclinic-demo.json

Lines changed: 0 additions & 1141 deletions
This file was deleted.

public/resources/preset-landscapes/petclinic.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

public/resources/preset-landscapes/plant-uml.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

src/backend/generation.ts

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { strict as assert } from 'assert';
99
import { NameGenerator } from './naming';
1010
import { FakeSpan, FakeTrace } from './tracing';
1111

12-
import { AppGenerationParameters, FakeApp, FakeClass, FakeMethod, FakePackage } from './shared/types';
12+
import { AppGenerationParameters, FakeApp, FakeClass, FakePackage } from './shared/types';
1313

1414
// TraceGenerationParameters uses CommunicationStyle enum, so we keep a local version
1515
export interface TraceGenerationParameters {
@@ -115,7 +115,7 @@ function generateFakeApp(params: AppGenerationParameters, nameGenerator: NameGen
115115

116116
const classes: Array<FakeClass> = [];
117117
const packages: Array<FakePackage> = [];
118-
const methods: Array<FakeMethod> = [];
118+
const methods: Array<string> = [];
119119

120120
const classCount: number = faker.number.int({
121121
min: params.minClassCount,
@@ -146,11 +146,9 @@ function generateFakeApp(params: AppGenerationParameters, nameGenerator: NameGen
146146
max: params.maxMethodCount,
147147
});
148148
const newMethods = Array.from(Array(numMethods), () => {
149-
const newMethod = {
150-
identifier: nameGenerator.getRandomMethodName(),
151-
};
152-
methods.push(newMethod);
153-
return newMethod;
149+
const methodName = nameGenerator.getRandomMethodName();
150+
methods.push(methodName);
151+
return methodName;
154152
});
155153
const newClass = {
156154
identifier: nameGenerator.getRandomClassName(),
@@ -241,11 +239,9 @@ function generateFakeApp(params: AppGenerationParameters, nameGenerator: NameGen
241239
max: params.maxMethodCount,
242240
});
243241
const newMethods = Array.from(Array(numMethods), () => {
244-
const newMethod = {
245-
identifier: nameGenerator.getRandomMethodName(),
246-
};
247-
methods.push(newMethod);
248-
return newMethod;
242+
const methodName = nameGenerator.getRandomMethodName();
243+
methods.push(methodName);
244+
return methodName;
249245
});
250246
const newClass = {
251247
identifier: nameGenerator.getRandomClassName(),
@@ -515,10 +511,10 @@ export function generateFakeTrace(apps: Array<FakeApp>, params: TraceGenerationP
515511
}
516512
spanAttrs[ATTR_SERVICE_NAME] = startingApp.name;
517513
spanAttrs[SEMATTRS_CODE_NAMESPACE] = entryPointFqn;
518-
spanAttrs[ATTR_CODE_FUNCTION_NAME] = entryMethod.identifier;
514+
spanAttrs[ATTR_CODE_FUNCTION_NAME] = entryMethod;
519515

520516
const entrySpan: FakeSpan = {
521-
name: `${entryPointFqn}.${entryMethod.identifier}`,
517+
name: `${entryPointFqn}.${entryMethod}`,
522518
relativeStartTime: 0,
523519
relativeEndTime: params.duration,
524520
attributes: { ...spanAttrs },
@@ -540,7 +536,7 @@ export function generateFakeTrace(apps: Array<FakeApp>, params: TraceGenerationP
540536
// Collect all methods for visitAllMethods feature
541537
interface MethodReference {
542538
class: FakeClass;
543-
method: FakeMethod;
539+
method: string;
544540
}
545541
const allMethods: Array<MethodReference> = [];
546542
classes.forEach((cls) => {
@@ -566,7 +562,7 @@ export function generateFakeTrace(apps: Array<FakeApp>, params: TraceGenerationP
566562
// Select next class for method call
567563

568564
let nextClass: FakeClass;
569-
let nextMethod: FakeMethod;
565+
let nextMethod: string;
570566

571567
// If visitAllMethods is enabled and there are unvisited methods, prioritize them
572568
if (params.visitAllMethods && visitedMethods.size < allMethods.length) {
@@ -636,9 +632,9 @@ export function generateFakeTrace(apps: Array<FakeApp>, params: TraceGenerationP
636632
const classFqn = getClassFqn(nextClass);
637633
spanAttrs[ATTR_SERVICE_NAME] = nextClass.parentAppName;
638634
spanAttrs[SEMATTRS_CODE_NAMESPACE] = classFqn;
639-
spanAttrs[ATTR_CODE_FUNCTION_NAME] = nextMethod.identifier;
635+
spanAttrs[ATTR_CODE_FUNCTION_NAME] = nextMethod;
640636
const nextSpan: FakeSpan = {
641-
name: `${classFqn}.${nextMethod.identifier}`,
637+
name: `${classFqn}.${nextMethod}`,
642638
relativeStartTime: timePassed,
643639
relativeEndTime: -1,
644640
attributes: { ...spanAttrs },

src/backend/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export function createServer(): Express {
1616

1717
// Middleware
1818
app.use(cors());
19-
app.use(express.json());
20-
app.use(express.urlencoded({ extended: true }));
19+
app.use(express.json({ limit: '50mb' }));
20+
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
2121

2222
// Health check
2323
app.get('/health', (req, res) => {

src/backend/services/landscape.service.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { generateFakeApps } from '../generation';
22
import { LandscapeStore } from '../landscape';
33
import { AppGenerationParameters } from '../shared/types';
44
import { isValidInteger } from '../utils';
5+
import { convertStructureLandscapeToRegular, isStructureLandscape } from '../utils/landscape-structure-converter';
56
import {
67
CleanedLandscape,
78
cleanLandscapeForSerialization,
@@ -39,9 +40,19 @@ export class LandscapeService {
3940
/**
4041
* Update the landscape
4142
*/
42-
updateLandscape(landscapeData: any[]): CleanedLandscape[] {
43+
updateLandscape(landscapeData: any): CleanedLandscape[] {
44+
// Check if this is a structure landscape format
45+
if (isStructureLandscape(landscapeData)) {
46+
// Convert structure format to regular format
47+
const convertedLandscape = convertStructureLandscapeToRegular(landscapeData);
48+
const landscape = reconstructParentReferences(convertedLandscape);
49+
this.landscapeStore.setLandscape(landscape);
50+
return cleanLandscapeForSerialization(landscape);
51+
}
52+
53+
// Regular landscape format (array of CleanedLandscape)
4354
if (!Array.isArray(landscapeData)) {
44-
throw new Error('Landscape must be an array');
55+
throw new Error('Landscape must be an array or structure landscape format');
4556
}
4657
const landscape = reconstructParentReferences(landscapeData);
4758
this.landscapeStore.setLandscape(landscape);

src/backend/shared/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface FakeMethod {
88

99
export interface FakeClass {
1010
identifier: string;
11-
methods: Array<FakeMethod>;
11+
methods: Array<string>;
1212
parent?: FakePackage;
1313
parentAppName: string;
1414
linkedClass?: FakeClass;
@@ -27,7 +27,7 @@ export interface FakeApp {
2727
entryPoint: FakeClass;
2828
classes: Array<FakeClass>;
2929
packages: Array<FakePackage>;
30-
methods: Array<FakeMethod>;
30+
methods: Array<string>;
3131
}
3232

3333
/**
@@ -113,7 +113,7 @@ export interface CleanedLandscape {
113113
entryPointFqn: string;
114114
classes: CleanedClass[];
115115
packages: CleanedPackage[];
116-
methods: FakeMethod[];
116+
methods: string[];
117117
}
118118

119119
export interface CleanedPackage {
@@ -124,6 +124,6 @@ export interface CleanedPackage {
124124

125125
export interface CleanedClass {
126126
identifier: string;
127-
methods: FakeMethod[];
127+
methods: string[];
128128
parentAppName: string;
129129
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { CleanedClass, CleanedLandscape, CleanedPackage } from '../shared/types';
2+
3+
interface StructureMethod {
4+
name: string;
5+
methodHash?: string;
6+
}
7+
8+
interface StructureClass {
9+
name: string;
10+
methods: StructureMethod[];
11+
}
12+
13+
interface StructurePackage {
14+
name: string;
15+
subPackages: StructurePackage[];
16+
classes: StructureClass[];
17+
}
18+
19+
interface StructureApplication {
20+
name: string;
21+
language: string;
22+
instanceId: string;
23+
packages: StructurePackage[];
24+
}
25+
26+
interface StructureNode {
27+
ipAddress: string;
28+
hostName: string;
29+
applications: StructureApplication[];
30+
}
31+
32+
export interface StructureLandscape {
33+
landscapeToken: string;
34+
nodes: StructureNode[];
35+
}
36+
37+
/**
38+
* Check if the given data is a structure landscape JSON format
39+
*/
40+
export function isStructureLandscape(data: any): data is StructureLandscape {
41+
return (
42+
typeof data === 'object' &&
43+
data !== null &&
44+
typeof data.landscapeToken === 'string' &&
45+
Array.isArray(data.nodes) &&
46+
data.nodes.length > 0 &&
47+
data.nodes.every(
48+
(node: any) =>
49+
typeof node === 'object' &&
50+
node !== null &&
51+
typeof node.ipAddress === 'string' &&
52+
typeof node.hostName === 'string' &&
53+
Array.isArray(node.applications)
54+
)
55+
);
56+
}
57+
58+
/**
59+
* Convert structure landscape format to landscape format for trace generator
60+
*/
61+
export function convertStructureLandscapeToRegular(structureData: StructureLandscape): CleanedLandscape[] {
62+
const landscapes: CleanedLandscape[] = [];
63+
64+
// Process each node
65+
for (const node of structureData.nodes) {
66+
// Process each application in the node
67+
for (const app of node.applications) {
68+
const allClasses: CleanedClass[] = [];
69+
const allPackages: CleanedPackage[] = [];
70+
const allMethodsSet = new Set<string>();
71+
72+
// Convert structure packages to regular packages recursively
73+
function convertPackage(structPkg: StructurePackage): CleanedPackage {
74+
const regularPkg: CleanedPackage = {
75+
name: structPkg.name,
76+
classes: [],
77+
subpackages: [],
78+
};
79+
80+
// Convert classes
81+
for (const structClass of structPkg.classes) {
82+
const methods: string[] = [];
83+
for (const structMethod of structClass.methods) {
84+
const methodName = structMethod.name;
85+
methods.push(methodName);
86+
// Deduplicate methods by name
87+
if (!allMethodsSet.has(methodName)) {
88+
allMethodsSet.add(methodName);
89+
}
90+
}
91+
92+
const regularClass: CleanedClass = {
93+
identifier: structClass.name,
94+
methods,
95+
parentAppName: app.name,
96+
};
97+
98+
regularPkg.classes.push(regularClass);
99+
allClasses.push(regularClass);
100+
}
101+
102+
// Convert subpackages recursively
103+
for (const structSubPkg of structPkg.subPackages) {
104+
const regularSubPkg = convertPackage(structSubPkg);
105+
regularPkg.subpackages.push(regularSubPkg);
106+
}
107+
108+
allPackages.push(regularPkg);
109+
return regularPkg;
110+
}
111+
112+
// Convert all root packages
113+
const rootPackages: CleanedPackage[] = app.packages.map((structPkg) => convertPackage(structPkg));
114+
115+
// Build FQN for entry point - find first class with methods, or first class
116+
let entryPointFqn = '';
117+
if (allClasses.length > 0) {
118+
const entryPointClass = allClasses.find((cls) => cls.methods.length > 0) || allClasses[0];
119+
120+
// Build FQN by traversing package tree
121+
function buildFqnForClass(cls: CleanedClass): string {
122+
// Find the package containing this class
123+
function findPackageForClass(pkg: CleanedPackage, path: string[]): string | null {
124+
if (pkg.classes.includes(cls)) {
125+
path.push(pkg.name);
126+
path.push(cls.identifier);
127+
return path.join('.');
128+
}
129+
for (const subPkg of pkg.subpackages) {
130+
const found = findPackageForClass(subPkg, [...path, pkg.name]);
131+
if (found) return found;
132+
}
133+
return null;
134+
}
135+
136+
for (const rootPkg of rootPackages) {
137+
const fqn = findPackageForClass(rootPkg, []);
138+
if (fqn) return fqn;
139+
}
140+
141+
// Fallback: just return class name
142+
return cls.identifier;
143+
}
144+
145+
entryPointFqn = buildFqnForClass(entryPointClass);
146+
}
147+
148+
landscapes.push({
149+
name: app.name,
150+
rootPackages,
151+
entryPointFqn,
152+
classes: allClasses,
153+
packages: allPackages,
154+
methods: Array.from(allMethodsSet),
155+
});
156+
}
157+
}
158+
159+
return landscapes;
160+
}

0 commit comments

Comments
 (0)