-
Notifications
You must be signed in to change notification settings - Fork 10
/
Ros2MessageFlowBuilder.java
112 lines (99 loc) · 3.82 KB
/
Ros2MessageFlowBuilder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**********************************************************************
* Copyright (c) 2022 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.tracecompass.incubator.internal.ros2.core.model.messageflow;
import java.util.Collection;
import java.util.HashMap;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNull;
/**
* Message flow builder. Finds segments that come after and before a given
* segment.
*
* This class and the ones it uses implement the technique described in the
* following paper:
*
* C. Bédard, P.-Y. Lajoie, G. Beltrame, and M. Dagenais, "Message Flow Analysis
* with Complex Causal Links for Distributed ROS 2 Systems," Robotics and
* Autonomous Systems, vol. 161, p. 104361, 2023.
* https://doi.org/10.1016/j.robot.2022.104361
*
* Preprint: https://arxiv.org/abs/2204.10208
*
* @author christophe.bedard
*/
public class Ros2MessageFlowBuilder {
private final @NonNull Ros2MessageFlowBuildInfo fBuildInfo;
/** Known/existing segments */
protected final @NonNull HashMap<@NonNull Ros2MessageFlowSegment, @NonNull Ros2MessageFlowSegment> fSegments;
/**
* Constructor
*
* @param buildInfo
* the message flow build information
* @param segments
* a reference to the known segments
*/
public Ros2MessageFlowBuilder(@NonNull Ros2MessageFlowBuildInfo buildInfo, @NonNull HashMap<@NonNull Ros2MessageFlowSegment, @NonNull Ros2MessageFlowSegment> segments) {
fBuildInfo = buildInfo;
fSegments = segments;
}
/**
* @return the build info
*/
public @NonNull Ros2MessageFlowBuildInfo getBuildInfo() {
return fBuildInfo;
}
/**
* Find and connect the next segments with relation to the given segment,
* recursively.
*
* @param segment
* the segment
*/
public void getNextSegments(@NonNull Ros2MessageFlowSegment segment) {
getNextSegments(segment, true);
}
/**
* Find and connect the previous segments with relation to the given
* segment, recursively.
*
* @param segment
* the segment
*/
public void getPreviousSegments(@NonNull Ros2MessageFlowSegment segment) {
getNextSegments(segment, false);
}
private void getNextSegments(@NonNull Ros2MessageFlowSegment segment, boolean forward) {
Collection<@NonNull Ros2MessageFlowSegment> nextSegments = forward ? segment.getDirectSuccessors(getBuildInfo()) : segment.getDirectPredecessors(getBuildInfo());
for (@NonNull
Ros2MessageFlowSegment nextSegment : nextSegments) {
/**
* If we already have this next segment, we should use it instead.
* This might happen when two segments have a common nextSegment,
* for example when there is a "merge" in the flow. This also avoids
* loops.
*/
boolean nextExistsAlready = fSegments.containsKey(nextSegment);
if (nextExistsAlready) {
nextSegment = Objects.requireNonNull(fSegments.get(nextSegment));
} else {
fSegments.put(nextSegment, nextSegment);
}
// Link segments together
nextSegment.addPrevious(segment);
segment.addNext(nextSegment);
// Do all of this again for each new next segment (yay recursion)
if (!nextExistsAlready) {
getNextSegments(nextSegment, forward);
}
}
}
}