diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml
index 11ac1c4c46..bd5aa28967 100644
--- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml
+++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml
@@ -16,5 +16,14 @@
class="org.eclipse.tracecompass.tmf.analysis.xml.core.tests.stubs.XmlSchemaParserStub">
-
+
+
+
+
+
+
+
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/src/org/eclipse/tracecompass/tmf/analysis/xml/core/tests/module/XmlUtilsWithTraceTest.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/src/org/eclipse/tracecompass/tmf/analysis/xml/core/tests/module/XmlUtilsWithTraceTest.java
new file mode 100644
index 0000000000..28dcba7c3b
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/src/org/eclipse/tracecompass/tmf/analysis/xml/core/tests/module/XmlUtilsWithTraceTest.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2025 Ericsson
+ *
+ * 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.tmf.analysis.xml.core.tests.module;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlAnalysisModuleSource;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.tests.Activator;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.tests.common.TmfXmlTestFiles;
+import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
+import org.eclipse.tracecompass.tmf.core.TmfProjectNature;
+import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
+import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
+import org.eclipse.tracecompass.tmf.core.io.ResourceUtil;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStubNs;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test the XML Utils delete supplementary directory
+ *
+ * @author Geneviève Bastien
+ */
+public class XmlUtilsWithTraceTest {
+
+ private static final @NonNull String TEST_TRACE_NAME = "testTrace4.xml";
+
+ private static final @NonNull String TEST_TRACE = "test_traces/" + TEST_TRACE_NAME;
+
+ private static final @NonNull String ANALYSIS_ID = "xml.core.tests.simple.pattern";
+
+ private static IProject sfProject;
+
+ /**
+ * Class setup
+ *
+ * @throws CoreException
+ * if an error occurs
+ */
+ @BeforeClass
+ public static void startUp() throws CoreException {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot()
+ .getProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME);
+ if (!project.exists()) {
+ project.create(null);
+ if (!project.isOpen()) {
+ project.open(null);
+ }
+ IProjectDescription description = project.getDescription();
+ description.setNatureIds(new String[] { TmfProjectNature.ID });
+ project.setDescription(description, null);
+ }
+ if (!project.isOpen()) {
+ project.open(null);
+ }
+
+ IFolder tracesFolder = project.getFolder("Traces"); //$NON-NLS-1$
+ if (!tracesFolder.exists()) {
+ tracesFolder.create(true, true, null);
+ }
+
+ IFolder supplRootFolder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME);
+ if (!supplRootFolder.exists()) {
+ supplRootFolder.create(true, true, null);
+ }
+ sfProject = project;
+ }
+
+ /**
+ * Class tear down
+ *
+ * @throws CoreException
+ * if an error occurs
+ */
+ @AfterClass
+ public static void tearDown() throws CoreException {
+ if (sfProject != null) {
+ sfProject.delete(true, null);
+ }
+ }
+
+ /**
+ * Load the XML files for the current test
+ */
+ @Before
+ public void setUp() {
+ XmlUtils.addXmlFile(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile());
+ XmlAnalysisModuleSource.notifyModuleChange();
+ }
+
+ /**
+ * Clean
+ */
+ @After
+ public void cleanUp() {
+ XmlUtils.deleteFiles(ImmutableList.of(
+ TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName()));
+ XmlAnalysisModuleSource.notifyModuleChange();
+ }
+
+ private ITmfTrace getTrace() throws CoreException {
+ TmfXmlTraceStubNs trace = new TmfXmlTraceStubNs();
+ String absolutePath = Activator.getAbsolutePath(new Path(TEST_TRACE)).toOSString();
+ IStatus status = trace.validate(null, absolutePath);
+ if (!status.isOK()) {
+ fail(status.getException().getMessage());
+ }
+
+ IResource resource = createResource(absolutePath);
+ try {
+ trace.initTrace(resource, absolutePath, TmfEvent.class);
+ } catch (TmfTraceException e) {
+ trace.dispose();
+ fail(e.getMessage());
+ }
+
+ // Initialize the trace and module
+ TmfTraceOpenedSignal signal = new TmfTraceOpenedSignal(this, trace, null);
+ trace.traceOpened(signal);
+ // The data provider manager uses opened traces from the manager
+ TmfTraceManager.getInstance().traceOpened(signal);
+ return trace;
+ }
+
+ @SuppressWarnings("null")
+ private static IResource createResource(String path) throws CoreException {
+ IPath targetLocation = new Path(path);
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IProject project = root.getProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME);
+ project.refreshLocal(IResource.DEPTH_INFINITE, null);
+ IFolder tracesFolder = project.getFolder("Traces");
+ IResource resource = tracesFolder.getFile(TEST_TRACE_NAME);
+ ResourceUtil.createSymbolicLink(resource, targetLocation, true, null);
+
+ IFolder supplRootFolder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME);
+ IFolder supplFolder = supplRootFolder.getFolder(resource.getProjectRelativePath().removeFirstSegments(1));
+ if (!supplFolder.exists()) {
+ supplFolder.create(true, true, null);
+ }
+ resource.setPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER, supplFolder.getLocation().toOSString());
+
+ return resource;
+ }
+
+ private static void runModule(ITmfTrace trace) {
+ IAnalysisModule module = trace.getAnalysisModule(ANALYSIS_ID);
+ assertNotNull(module);
+ module.schedule();
+ assertTrue(module.waitForCompletion());
+ }
+
+ /**
+ * Test delete supplementary dir when trace is open
+ *
+ * @throws CoreException
+ * if an error occurs
+ */
+ @Test
+ public void testDeleteSupplDirWithTraceOpen() throws CoreException {
+ ITmfTrace trace = getTrace();
+ assertNotNull(trace);
+ try {
+ runModule(trace);
+ String supplPathString = TmfTraceManager.getSupplementaryFileDir(trace);
+ IPath path = new Path(supplPathString);
+ IPath ssFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("ht");
+ IPath segFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("dat");
+ assertTrue(ssFile.toFile().exists());
+ assertTrue(segFile.toFile().exists());
+ XmlUtils.deleteSupplementaryResources(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName(), null);
+ assertFalse(ssFile.toFile().exists());
+ assertFalse(segFile.toFile().exists());
+ } finally {
+ trace.dispose();
+ TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace));
+ }
+ }
+
+ /**
+ * Test delete supplementary dir when trace is open
+ *
+ * @throws CoreException
+ * Exception thrown by analyses
+ */
+ @Test
+ public void testDeleteSupplDirWithTraceClosed() throws CoreException {
+ ITmfTrace trace = getTrace();
+ assertNotNull(trace);
+ try {
+ runModule(trace);
+ String supplPathString = TmfTraceManager.getSupplementaryFileDir(trace);
+ IPath path = new Path(supplPathString);
+ IPath ssFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("ht");
+ IPath segFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("dat");
+ assertTrue(ssFile.toFile().exists());
+ assertTrue(segFile.toFile().exists());
+
+ TmfTraceClosedSignal signal = new TmfTraceClosedSignal(this, trace);
+ TmfTraceManager.getInstance().traceClosed(signal);
+ trace.dispose();
+
+ XmlUtils.deleteSupplementaryResources(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName(), null);
+ assertFalse(ssFile.toFile().exists());
+ assertFalse(segFile.toFile().exists());
+ } finally {
+ trace.dispose();
+ TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace));
+ }
+ }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF
index ee16dadf3f..a3ceb66c5e 100644
--- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF
+++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF
@@ -17,7 +17,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.tracecompass.analysis.profiling.core,
org.eclipse.core.commands,
com.google.guava,
- org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
+ org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional,
+ org.eclipse.core.resources
Export-Package: org.eclipse.tracecompass.internal.tmf.analysis.xml.core;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests",
org.eclipse.tracecompass.internal.tmf.analysis.xml.core.callstack;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests",
org.eclipse.tracecompass.internal.tmf.analysis.xml.core.config;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests",
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java
index 8e91ced31f..948d37903a 100644
--- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java
+++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java
@@ -108,7 +108,7 @@ public ITmfConfiguration update(String id, Map parameters) throw
if (!XmlUtils.listFiles().containsKey(id)) {
return null;
}
-
+ XmlUtils.deleteSupplementaryResources(id, null);
XmlUtils.deleteFiles(ImmutableList.of(id));
XmlUtils.saveFilesStatus();
XmlAnalysisModuleSource.notifyModuleChange();
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java
index db31bb23e9..8179231d4d 100644
--- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java
+++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java
@@ -42,12 +42,20 @@
import javax.xml.validation.SchemaFactory;
import org.apache.commons.io.FilenameUtils;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
@@ -61,6 +69,11 @@
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.ITmfXmlSchemaParser;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.TmfXmlStrings;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.TmfXmlUtils;
+import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
+import org.eclipse.tracecompass.tmf.core.TmfProjectNature;
+import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.osgi.framework.Bundle;
import org.osgi.service.prefs.BackingStoreException;
import org.w3c.dom.Document;
@@ -722,4 +735,65 @@ public static String createXmlFileString(String baseName) {
});
return enabledFiles;
}
+
+ /**
+ * Deletes all supplementary resources created by an XML analysis file
+ *
+ * @param xmlFileName
+ * the file name of xml analysis
+ * @param monitor
+ * a progress monitor
+ */
+ public static void deleteSupplementaryResources(String xmlFileName, @Nullable IProgressMonitor monitor) {
+ final IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
+ // Get unique list of analysis IDs
+ Set analysisIds = new HashSet<>();
+ analysisIds.addAll(XmlUtils.getAnalysisIdsFromFile(xmlFileName));
+
+ // Delete persistent data of all open traces (this will close the file before deleting it)
+ for (ITmfTrace trace : TmfTraceManager.getInstance().getOpenedTraces()) {
+ for (ITmfTrace tr : TmfTraceManager.getTraceSetWithExperiment(trace)) {
+ analysisIds.forEach(analysisId -> {
+ IAnalysisModule module = tr.getAnalysisModule(analysisId);
+ if (module != null) {
+ module.clearPersistentData();
+ }
+ });
+ }
+ if (mon.isCanceled()) {
+ return;
+ }
+ }
+ // Delete applicable persistent data of non-opened traces
+ for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
+ try {
+ if (project.hasNature(TmfProjectNature.ID)) {
+ project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ IFolder supplFolder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME);
+ if (supplFolder != null && supplFolder.exists()) {
+ supplFolder.accept((IResourceVisitor) resource -> {
+ if (mon.isCanceled()) {
+ return false;
+ }
+ if (resource instanceof IFile) {
+ analysisIds.forEach(analysisId -> {
+ if (resource.getName().startsWith(analysisId)) {
+ try {
+ resource.delete(true, null);
+ } catch (CoreException e) {
+ Activator.logError("Can't delete supplementary resource " + resource.getName(), e); //$NON-NLS-1$
+ }
+ }
+ });
+ }
+ return true;
+ }, IResource.DEPTH_INFINITE, IResource.NONE);
+ }
+ }
+ } catch (CoreException e) {
+ Activator.logError("Can't delete supplementary resources for XML analyses", e); //$NON-NLS-1$
+ }
+ }
+ }
+
}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java
index fc1cb34bc7..c8c2b28e95 100644
--- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java
+++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java
@@ -381,4 +381,10 @@ public boolean waitForCompletion(@NonNull IProgressMonitor monitor) {
return properties;
}
+ @Override
+ public void clearPersistentData() {
+ super.clearPersistentData();
+ fSegmentStoreModule.clearPersistentData();
+ fStateSystemModule.clearPersistentData();
+ }
}