Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
/**********************************************************************
* 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.core.config;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright header

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfConfigurationException;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
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.core.trace.experiment.TmfExperiment;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;

/**
* This class meant to be extended by data provider factories that want to be
* able to handle configurations.
*
* @since 9.6
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need a @since 9.6 tag

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

public abstract class AbstractTmfDataProviderConfigurator implements ITmfDataProviderConfigurator{

/**
* Constructor
*/
protected AbstractTmfDataProviderConfigurator() {
TmfSignalManager.register(this);
}

/**
* The json file extension
* @since 9.5
*/
public static final String JSON_EXTENSION = "json"; //$NON-NLS-1$

private Table<String, ITmfTrace, ITmfConfiguration> fTmfConfigurationTable = HashBasedTable.create();

/**
* Return the configuration table
*
* @return a table mapping configuration id and trace (exp) to its configuration
*/
public Table<String, ITmfTrace, ITmfConfiguration> getConfigurationTable(){
return fTmfConfigurationTable;
}

/**
* Create instances implementing {@link ITmfConfiguration}. Override this
* method if the data provider configurator needs another configuration
* instead of the default {@link TmfConfiguration}
*
* @param configuration
* a object implementing implementing {@link ITmfConfiguration}.
* @return the instance of the class implementing {@link ITmfConfiguration}.
* Default is {@link TmfConfiguration}.
*/
protected ITmfConfiguration createConfiguration(ITmfConfiguration configuration) {
String description = configuration.getDescription();
if (configuration.getDescription().equals(TmfConfiguration.UNKNOWN)) {
description = "Data provider defined by configuration " + configuration.getName(); //$NON-NLS-1$
}

TmfConfiguration.Builder builder = new TmfConfiguration.Builder();
builder.setId(configuration.getId())
.setSourceTypeId(configuration.getSourceTypeId())
.setName(configuration.getName())
.setDescription(description)
.setParameters(configuration.getParameters())
.build();
return builder.build();
}

@Override
public @NonNull IDataProviderDescriptor createDataProviderDescriptors(ITmfTrace trace, ITmfConfiguration configuration) throws TmfConfigurationException {

if (configuration.getName().equals(TmfConfiguration.UNKNOWN)) {
throw new TmfConfigurationException("Missing configuration name"); //$NON-NLS-1$
}

if (configuration.getSourceTypeId().equals(TmfConfiguration.UNKNOWN)) {
throw new TmfConfigurationException("Missing configuration type"); //$NON-NLS-1$
}

ITmfConfiguration config = createConfiguration(configuration);

applyConfiguration(trace, config, true);
if (fTmfConfigurationTable.contains(config.getId(), trace)) {
throw new TmfConfigurationException("Configuration already existis with label: " + config.getName()); //$NON-NLS-1$
}
fTmfConfigurationTable.put(config.getId(), trace, config);
return getDescriptorFromConfig(config);
}

/**
* Return a data provider descriptor based on the configuration parameter
*
* @param config
* a configuration
* @return A data provider descriptor based on the configuration parameter
*/
protected abstract IDataProviderDescriptor getDescriptorFromConfig(ITmfConfiguration config);

/**
* This is the method that handles what happens when a configuration is
* applied
*
* @param trace
* trace to which the configuration should be applied
* @param config
* the configuration to be applied
* @param writeConfig
* true if the configuration should be written to disk, false
* otherwise
*/
protected abstract void applyConfiguration(ITmfTrace trace, ITmfConfiguration config, boolean writeConfig);

@Override
public void removeDataProviderDescriptor(ITmfTrace trace, IDataProviderDescriptor descriptor) throws TmfConfigurationException {
ITmfConfiguration creationConfiguration = descriptor.getConfiguration();
if (creationConfiguration == null) {
throw new TmfConfigurationException("Data provider was not created by a configuration"); //$NON-NLS-1$
}

String configId = creationConfiguration.getId();
ITmfConfiguration config = fTmfConfigurationTable.get(configId, trace);
if (config == null) {
return;
}
config = fTmfConfigurationTable.remove(configId, trace);
removeConfiguration(trace, config);
}

/**
* This is the method that handles what happens when a configuration is
* removed (e.g. remove analysis, dp etc)
*
* @param trace
* trace to which the configuration should be applied
* @param config
* the configuration to be applied
*/
protected abstract void removeConfiguration(@NonNull ITmfTrace trace, @NonNull ITmfConfiguration config);

/**
* Signal handler for opened trace signal. Will populate trace
* configurations
*
* @param signal
* the signal to handle
*/
@TmfSignalHandler
public void traceOpened(TmfTraceOpenedSignal signal) {
ITmfTrace trace = signal.getTrace();
if (trace == null) {
return;
}
try {
if (trace instanceof TmfExperiment) {
for (ITmfTrace tr : TmfTraceManager.getTraceSet(trace)) {
// Read configurations from sub-trace
List<ITmfConfiguration> configs = readConfigurations(tr);
readAndApplyConfiguration(trace, configs);
}
}
// Read configurations from trace or top level experiment
List<ITmfConfiguration> configs = readConfigurations(trace);
readAndApplyConfiguration(trace, configs);
} catch (TmfConfigurationException e) {
Activator.logError("Error applying configurations for trace " + trace.getName(), e); //$NON-NLS-1$
}
}

/**
* Handles trace closed signal
*
* @param signal
* the close signal to handle
*/
@TmfSignalHandler
public void traceClosed(TmfTraceClosedSignal signal) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This this class handles tmf signals, we need to register to the signal manager and also derigster when it's disposed. You can register in the constructor.

TmfSignalManager.register(this);

Probably this class should have a dispose method to deregister from the signal manager. The factory dispose() method would call then this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ITmfTrace trace = signal.getTrace();
fTmfConfigurationTable.column(trace).clear();
}

private void readAndApplyConfiguration(ITmfTrace trace, List<ITmfConfiguration> configs) throws TmfConfigurationException {
for (ITmfConfiguration config : configs) {
if (!fTmfConfigurationTable.contains(config.getId(), trace)) {
fTmfConfigurationTable.put(config.getId(), trace, config);
applyConfiguration(trace, config, false);
}
}
}

/**
* Reads the configurations for a given trace
*
* @param trace
* the trace to read configurations from
* @return list of configurations if any
* @throws TmfConfigurationException
* if an error occurs
*/
private @NonNull List<ITmfConfiguration> readConfigurations(@NonNull ITmfTrace trace) throws TmfConfigurationException {
IPath rootPath = getConfigurationRootFolder(trace);
File folder = rootPath.toFile();
List<ITmfConfiguration> list = new ArrayList<>();
if (folder.exists()) {
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles) {
IPath path = new Path(file.getName());
if (path.getFileExtension().equals(JSON_EXTENSION)) {
ITmfConfiguration config = TmfConfiguration.fromJsonFile(file);
list.add(config);
}
}
}
return list;
}

/**
* Serialize {@link ITmfConfiguration} to JSON file with name configId.json
*
* @param configuration
* the configuration to serialize
* @param rootPath
* the root path to store the configuration
* @throws TmfConfigurationException
* if an error occurs
* @since 9.5
*/
protected static void writeConfiguration(ITmfConfiguration configuration, IPath rootPath) throws TmfConfigurationException {
IPath supplPath = rootPath;
File folder = supplPath.toFile();
if (!folder.exists()) {
folder.mkdir();
}
supplPath = supplPath.addTrailingSeparator().append(configuration.getId()).addFileExtension(JSON_EXTENSION);
File file = supplPath.toFile();
try (Writer writer = new FileWriter(file)) {
writer.append(new Gson().toJson(configuration));
} catch (IOException | JsonParseException e) {
Activator.logError(e.getMessage(), e);
throw new TmfConfigurationException("Error writing configuration.", e); //$NON-NLS-1$
}
}

/**
* Return the path where the configuration for a trace is stored
*
* @param trace
* the trace to which the configuration should be applied to
* @return the path where the configuration should be stored
*/
@SuppressWarnings("null")
protected @NonNull abstract IPath getConfigurationRootFolder(@NonNull ITmfTrace trace);

/**
* Disposes the signal manager
*/
protected void dispose() {
TmfSignalManager.dispose();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfConfigurationException;

import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.Expose;
Expand All @@ -49,8 +48,11 @@ public class TmfConfiguration implements ITmfConfiguration {

/**
* The json file extension
*
* @since 9.5
* @deprecated use {@link AbstractTmfDataProviderConfigurator#JSON_EXTENSION} instead
*/
@Deprecated
public static final String JSON_EXTENSION = "json"; //$NON-NLS-1$
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't remove it just yet. It's api and needs to be deprecated first. In incubator master branch there is already a new class that uses it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


@Expose
Expand Down Expand Up @@ -327,7 +329,11 @@ public static ITmfConfiguration fromJsonFile(File jsonFile) throws TmfConfigurat
* @throws TmfConfigurationException
* if an error occurs
* @since 9.5
* @deprecated use
* {@link AbstractTmfDataProviderConfigurator#writeConfiguration(ITmfConfiguration, IPath)}
* instead
*/
@Deprecated
public static void writeConfiguration(ITmfConfiguration configuration, IPath rootPath) throws TmfConfigurationException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't remove it just yet. It's api and needs to be deprecated first. In incubator master branch there is already a new class that uses it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

IPath supplPath = rootPath;
File folder = supplPath.toFile();
Expand All @@ -343,4 +349,5 @@ public static void writeConfiguration(ITmfConfiguration configuration, IPath roo
throw new TmfConfigurationException("Error writing configuration.", e); //$NON-NLS-1$
}
}

}
Loading