ros2: add causal message links analysis

This collects user-level annotation data for causal links between
publishers and subscriptions. This can then later be used by other
analyses to find causal links between specific messages.

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
Change-Id: I8e91bf7640b5e59e99b94448fe2b8c5d6debc446
Reviewed-on: https://git.eclipse.org/r/c/tracecompass.incubator/org.eclipse.tracecompass.incubator/+/192550
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/META-INF/MANIFEST.MF b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/META-INF/MANIFEST.MF
index b08c5f4..27bc07d 100644
--- a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/META-INF/MANIFEST.MF
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/META-INF/MANIFEST.MF
@@ -26,6 +26,7 @@
  org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.objects,
  org.eclipse.tracecompass.incubator.internal.ros2.core.model,
  org.eclipse.tracecompass.incubator.internal.ros2.core.model.executor,
+ org.eclipse.tracecompass.incubator.internal.ros2.core.model.messagelinks,
  org.eclipse.tracecompass.incubator.internal.ros2.core.model.messages,
  org.eclipse.tracecompass.incubator.internal.ros2.core.model.objects,
  org.eclipse.tracecompass.incubator.internal.ros2.core.trace;x-friends:="org.eclipse.tracecompass.incubator.ros2.core.tests,org.eclipse.tracecompass.incubator.ros2.ui",
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.properties b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.properties
index 627428b..4dd636a 100644
--- a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.properties
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.properties
@@ -18,4 +18,5 @@
 analysis.ros2 = ROS 2 (Incubator)
 analysis.ros2.objects = ROS 2 Objects
 analysis.ros2.messages = ROS 2 Messages
-analysis.ros2.executor = ROS 2 Executor
\ No newline at end of file
+analysis.ros2.executor = ROS 2 Executor
+analysis.ros2.messagelinks = ROS 2 Message Links
\ No newline at end of file
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.xml b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.xml
index fd9b61c..2f3f383 100644
--- a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.xml
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/plugin.xml
@@ -67,6 +67,22 @@
                class="org.eclipse.tracecompass.incubator.internal.ros2.core.trace.Ros2Experiment">
          </tracetype>
       </module>
+      <module
+            analysis_module="org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.messagelinks.Ros2MessageCausalLinksAnalysis"
+            applies_experiment="true"
+            automatic="false"
+            icon="icons/ros2.png"
+            id="org.eclipse.tracecompass.incubator.ros2.core.analysis.messagelinks"
+            name="%analysis.ros2.messagelinks">
+         <tracetype
+               applies="true"
+               class="org.eclipse.tracecompass.incubator.internal.ros2.core.trace.Ros2Trace">
+         </tracetype>
+         <tracetype
+               applies="true"
+               class="org.eclipse.tracecompass.incubator.internal.ros2.core.trace.Ros2Experiment">
+         </tracetype>
+      </module>
    </extension>
    <extension
          point="org.eclipse.tracecompass.tmf.core.dataprovider">
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/analysis/messagelinks/Ros2MessageCausalLinksAnalysis.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/analysis/messagelinks/Ros2MessageCausalLinksAnalysis.java
new file mode 100644
index 0000000..79cbef8
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/analysis/messagelinks/Ros2MessageCausalLinksAnalysis.java
@@ -0,0 +1,83 @@
+/**********************************************************************
+ * 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.analysis.messagelinks;
+
+import java.util.Collections;
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.AbstractRos2StateSystemAnalysis;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.IRos2ModelProvider;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.objects.Ros2ObjectsAnalysis;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.model.messagelinks.Ros2MessageCausalLinksModel;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * ROS 2 message causal links analysis. Collects causal links information from
+ * annotations.
+ *
+ * @author Christophe Bedard
+ */
+public class Ros2MessageCausalLinksAnalysis extends AbstractRos2StateSystemAnalysis implements IRos2ModelProvider<Ros2MessageCausalLinksModel> {
+
+    private static final @NonNull String ID_SUFFIX = ".messagelinks"; //$NON-NLS-1$
+
+    private Ros2MessageCausalLinksModel fModel;
+
+    /**
+     * Constructor
+     */
+    public Ros2MessageCausalLinksAnalysis() {
+        super(getFullAnalysisId());
+        fModel = new Ros2MessageCausalLinksModel();
+    }
+
+    /**
+     * @return the full ID of this analysis module
+     */
+    public static @NonNull String getFullAnalysisId() {
+        return AbstractRos2StateSystemAnalysis.getAnalysisIdFromSuffix(ID_SUFFIX);
+    }
+
+    @Override
+    public @Nullable Ros2MessageCausalLinksModel getModel() {
+        return fModel;
+    }
+
+    @Override
+    protected @NonNull ITmfStateProvider createStateProvider() {
+        @NonNull
+        ITmfTrace trace = Objects.requireNonNull(getTrace());
+        // Provide objects state system and (empty) message links model
+        ITmfStateSystem ss = getStateSystem(trace, Ros2ObjectsAnalysis.getFullAnalysisId());
+        return new Ros2MessageCausalLinksStateProvider(trace, Objects.requireNonNull(ss), fModel);
+    }
+
+    @Override
+    protected @NonNull Iterable<@NonNull IAnalysisModule> getDependentAnalyses() {
+        ITmfTrace trace = getTrace();
+        if (trace == null) {
+            return Collections.emptySet();
+        }
+        // Depends on the objects analysis
+        Ros2ObjectsAnalysis objectsAnalysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, Ros2ObjectsAnalysis.class, Ros2ObjectsAnalysis.getFullAnalysisId());
+        if (objectsAnalysis == null) {
+            return Collections.emptySet();
+        }
+        return Collections.singleton(objectsAnalysis);
+    }
+}
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/analysis/messagelinks/Ros2MessageCausalLinksStateProvider.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/analysis/messagelinks/Ros2MessageCausalLinksStateProvider.java
new file mode 100644
index 0000000..31490eb
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/analysis/messagelinks/Ros2MessageCausalLinksStateProvider.java
@@ -0,0 +1,97 @@
+/**********************************************************************
+ * 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.analysis.messagelinks;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.AbstractRos2StateProvider;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.model.messagelinks.Ros2MessageCausalLinkType;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.model.messagelinks.Ros2MessageCausalLinksModel;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.model.objects.Ros2ObjectHandle;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * State provider for the ROS 2 message causal links analysis.
+ *
+ * @author Christophe Bedard
+ */
+public class Ros2MessageCausalLinksStateProvider extends AbstractRos2StateProvider {
+
+    private static final int VERSION_NUMBER = 0;
+
+    private final ITmfStateSystem fObjectsSs;
+    private final Ros2MessageCausalLinksModel fModel;
+
+    /**
+     * Constructor
+     *
+     * @param trace
+     *            the trace
+     * @param objectsSs
+     *            the objects state system
+     * @param model
+     *            the message links model
+     */
+    public Ros2MessageCausalLinksStateProvider(ITmfTrace trace, ITmfStateSystem objectsSs, Ros2MessageCausalLinksModel model) {
+        super(trace, Ros2MessageCausalLinksAnalysis.getFullAnalysisId());
+        fObjectsSs = objectsSs;
+        fModel = model;
+    }
+
+    @Override
+    public int getVersion() {
+        return VERSION_NUMBER;
+    }
+
+    @Override
+    public @NonNull ITmfStateProvider getNewInstance() {
+        return new Ros2MessageCausalLinksStateProvider(getTrace(), fObjectsSs, fModel);
+    }
+
+    @Override
+    protected void eventHandle(@NonNull ITmfEvent event) {
+        if (!considerEvent(event)) {
+            return;
+        }
+
+        /**
+         * No need to actually fill in the state system or use the event
+         * timestamps.
+         */
+
+        // Periodic async
+        if (isEvent(event, LAYOUT.eventMessageLinkPeriodicAsync())) {
+            long[] subs = (long[]) getField(event, LAYOUT.fieldSubs());
+            long[] pubs = (long[]) getField(event, LAYOUT.fieldPubs());
+
+            fModel.addLink(toHandles(event, subs), toHandles(event, pubs), Ros2MessageCausalLinkType.PERIODIC_ASYNC);
+        }
+        // Partial sync
+        else if (isEvent(event, LAYOUT.eventMessageLinkPartialSync())) {
+            long[] subs = (long[]) getField(event, LAYOUT.fieldSubs());
+            long[] pubs = (long[]) getField(event, LAYOUT.fieldPubs());
+
+            fModel.addLink(toHandles(event, subs), toHandles(event, pubs), Ros2MessageCausalLinkType.PARTIAL_SYNC);
+        }
+    }
+
+    private static Collection<@NonNull Ros2ObjectHandle> toHandles(@NonNull ITmfEvent event, long[] handles) {
+        return LongStream.of(handles).boxed().map(h -> handleFrom(event, Objects.requireNonNull(h))).collect(Collectors.toUnmodifiableList());
+    }
+}
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLink.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLink.java
new file mode 100644
index 0000000..eee29e1
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLink.java
@@ -0,0 +1,95 @@
+/**********************************************************************
+ * 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.messagelinks;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.model.objects.Ros2ObjectHandle;
+
+import com.google.common.base.Objects;
+
+/**
+ * Complex causal link between subscriptions and publishers.
+ *
+ * @author Christophe Bedard
+ */
+public class Ros2MessageCausalLink {
+
+    private final Set<@NonNull Ros2ObjectHandle> fSubs;
+    private final Set<@NonNull Ros2ObjectHandle> fPubs;
+    private final @NonNull Ros2MessageCausalLinkType fType;
+
+    /**
+     * Constructor
+     *
+     * @param subs
+     *            the subscriptions
+     * @param pubs
+     *            the publishers
+     * @param type
+     *            the causal link type
+     */
+    public Ros2MessageCausalLink(Collection<@NonNull Ros2ObjectHandle> subs, Collection<@NonNull Ros2ObjectHandle> pubs, @NonNull Ros2MessageCausalLinkType type) {
+        fSubs = new HashSet<>(subs);
+        fPubs = new HashSet<>(pubs);
+        fType = type;
+    }
+
+    /**
+     * @return the subscriptions
+     */
+    public Set<@NonNull Ros2ObjectHandle> getSubs() {
+        return fSubs;
+    }
+
+    /**
+     * @return the publishers
+     */
+    public Set<@NonNull Ros2ObjectHandle> getPubs() {
+        return fPubs;
+    }
+
+    /**
+     * @return the message link type
+     */
+    public @NonNull Ros2MessageCausalLinkType getType() {
+        return fType;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(fSubs, fPubs, fType);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        Ros2MessageCausalLink o = (Ros2MessageCausalLink) obj;
+        return fSubs.equals(o.fSubs) && fPubs.equals(o.fPubs) && fType.equals(o.fType);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Ros2MessageCausalLink: subs=%s, pubs=%s, type=%s", fSubs.toString(), fPubs.toString(), fType.toString()); //$NON-NLS-1$
+    }
+}
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLinkType.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLinkType.java
new file mode 100644
index 0000000..a66a93c
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLinkType.java
@@ -0,0 +1,24 @@
+/**********************************************************************
+ * 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.messagelinks;
+
+/**
+ * Types of message causal links.
+ *
+ * @author Christophe Bedard
+ */
+public enum Ros2MessageCausalLinkType {
+    /** Periodic asynchronous many-to-many */
+    PERIODIC_ASYNC,
+    /** Partially synchronous many-to-many */
+    PARTIAL_SYNC
+}
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLinksModel.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLinksModel.java
new file mode 100644
index 0000000..09b153e
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/model/messagelinks/Ros2MessageCausalLinksModel.java
@@ -0,0 +1,74 @@
+/**********************************************************************
+ * 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.messagelinks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.analysis.IRos2Model;
+import org.eclipse.tracecompass.incubator.internal.ros2.core.model.objects.Ros2ObjectHandle;
+
+/**
+ * Container for message causal links.
+ *
+ * @author Christophe Bedard
+ */
+public class Ros2MessageCausalLinksModel implements IRos2Model {
+
+    private @NonNull Collection<@NonNull Ros2MessageCausalLink> fLinks;
+
+    /**
+     * Constructor
+     */
+    public Ros2MessageCausalLinksModel() {
+        fLinks = new ArrayList<>();
+    }
+
+    /**
+     * Add a new message link.
+     *
+     * @param subs
+     *            the subscriptions
+     * @param pubs
+     *            the publishers
+     * @param type
+     *            the causal link type
+     */
+    public void addLink(Collection<@NonNull Ros2ObjectHandle> subs, Collection<@NonNull Ros2ObjectHandle> pubs, @NonNull Ros2MessageCausalLinkType type) {
+        fLinks.add(new Ros2MessageCausalLink(subs, pubs, type));
+    }
+
+    /**
+     * Get causal link(s) for a given publisher handle.
+     *
+     * @param publisherHandle
+     *            the publisher handle
+     * @return the message links
+     */
+    public Collection<@NonNull Ros2MessageCausalLink> getLinksForPub(@NonNull Ros2ObjectHandle publisherHandle) {
+        return fLinks.stream().filter(l -> l.getPubs().contains(publisherHandle)).collect(Collectors.toUnmodifiableList());
+
+    }
+
+    /**
+     * Get causal link(s) for a given subscription handle.
+     *
+     * @param subscriptionHandle
+     *            the subscription handle
+     * @return the message links
+     */
+    public Collection<@NonNull Ros2MessageCausalLink> getLinksForSub(@NonNull Ros2ObjectHandle subscriptionHandle) {
+        return fLinks.stream().filter(l -> l.getSubs().contains(subscriptionHandle)).collect(Collectors.toUnmodifiableList());
+    }
+}
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/IRos2EventLayout.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/IRos2EventLayout.java
index 7a4bc8a..1487cef 100644
--- a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/IRos2EventLayout.java
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/IRos2EventLayout.java
@@ -209,6 +209,18 @@
      */
     String eventRclcppExecutorExecute();
 
+    // Message causal links
+
+    /**
+     * <code>message_link_periodic_async</code>
+     */
+    String eventMessageLinkPeriodicAsync();
+
+    /**
+     * <code>message_link_partial_sync</code>
+     */
+    String eventMessageLinkPartialSync();
+
     // DDS
 
     /**
@@ -273,6 +285,10 @@
     String fieldTimeout();
     String fieldHandle();
 
+    // Message causal links
+    String fieldSubs();
+    String fieldPubs();
+
     // DDS
     String fieldGidPrefix();
     String fieldGidEntity();
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/Ros2RollingEventLayout.java b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/Ros2RollingEventLayout.java
index 3b70f2e..5ad329f 100644
--- a/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/Ros2RollingEventLayout.java
+++ b/tracetypes/org.eclipse.tracecompass.incubator.ros2.core/src/org/eclipse/tracecompass/incubator/internal/ros2/core/trace/layout/Ros2RollingEventLayout.java
@@ -52,6 +52,9 @@
     private static final String RCLCPP_EXECUTOR_WAIT_FOR_WORK = "ros2:rclcpp_executor_wait_for_work";
     private static final String RCLCPP_EXECUTOR_EXECUTE = "ros2:rclcpp_executor_execute";
 
+    private static final String MESSAGE_LINK_PERIODIC_ASYNC = "ros2:message_link_periodic_async";
+    private static final String MESSAGE_LINK_PARTIAL_SYNC = "ros2:message_link_partial_sync";
+
     private static final String DDS_CREATE_WRITER = "dds:create_writer";
     private static final String DDS_WRITE_PRE = "dds:write_pre";
     private static final String DDS_WRITE = "dds:write";
@@ -91,6 +94,10 @@
     private static final String GOAL_LABEL = "goal_label";
     private static final String TIMEOUT = "timeout";
     private static final String HANDLE = "handle";
+
+    private static final String SUBS = "subs";
+    private static final String PUBS = "pubs";
+
     private static final String GID_PREFIX = "gid_prefix";
     private static final String GID_ENTITY = "gid_entity";
     private static final String WRITER = "writer";
@@ -322,6 +329,22 @@
         return RCLCPP_EXECUTOR_EXECUTE;
     }
 
+    // Message causal links
+
+    // message_link_periodic_async
+
+    @Override
+    public String eventMessageLinkPeriodicAsync() {
+        return MESSAGE_LINK_PERIODIC_ASYNC;
+    }
+
+    // message_link_partial_sync
+
+    @Override
+    public String eventMessageLinkPartialSync() {
+        return MESSAGE_LINK_PARTIAL_SYNC;
+    }
+
     // DDS
 
     // dds:create_writer
@@ -523,6 +546,18 @@
         return HANDLE;
     }
 
+    // Message causal links
+
+    @Override
+    public String fieldSubs() {
+        return SUBS;
+    }
+
+    @Override
+    public String fieldPubs() {
+        return PUBS;
+    }
+
     // DDS
 
     @Override