From c534dc9d30f90357d0d380a3fcb2c6b0a2de83df Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Tue, 22 Apr 2025 09:41:22 -0400 Subject: [PATCH] tmf.core: Introduce arbitrary/abstract data provider ITmfDataProvider Add methods in IDataProviderFactory to create provider returning only this new ITmfDataProvider interface. Deprecate existing createProvider methods in IDataProviderFactory. Add new methods to fetch and create data providers implementing ITmfDataProvider interface. Deprecate existing get and create methods for data providers in DataProviderManager. [Added] base data provider ITmfDataProvider interface [Added] IDataProviderFactory.createDataProvider(ITmfTrace) [Added] IDataProviderFactory.createDataProvider(ITmfTrace, String) [Added] DataProviderManager.fetchExistingDataProvider(ITmfTrace, String, Class) [Added] DataProviderManager.fetchOrCreateDataProvider(ITmfTrace, String, Class) [Deprecated] IDataProviderFactory.createProvider(ITmfTrace) [Deprecated] IDataProviderFactory.createProvider(ITmfTrace, String) [Deprecated] DataProviderManager.getExistingDataProvider(ITmfTrace, String, Class) [Deprecated] DataProviderManager.getOrCreateDataProvider(ITmfTrace, String, Class) Change-Id: I8861028af4c368e2bbd610dd10d4b7b20d7a05de Signed-off-by: Matthew Khouzam Signed-off-by: Bernd Hufmann --- .../DataProviderManagerTest.java | 50 +++++++++--- .../dataprovider/DataProviderManager.java | 75 +++++++++++++++--- .../dataprovider/IDataProviderFactory.java | 47 +++++++++++- .../tmf/core/model/ITmfDataProvider.java | 76 +++++++++++++++++++ .../core/model/tree/ITmfTreeDataProvider.java | 18 +---- 5 files changed, 225 insertions(+), 41 deletions(-) create mode 100644 tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/ITmfDataProvider.java diff --git a/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java b/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java index 85aad4fe23..626137cb01 100644 --- a/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java +++ b/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java @@ -415,17 +415,45 @@ public void test() { public void testGetter() { ITmfTrace trace = fKernelTrace; assertNotNull(trace); - ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp = DataProviderManager.getInstance().getExistingDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); - assertNull(dp); - dp = DataProviderManager.getInstance().getOrCreateDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); - assertNotNull(dp); - ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp2 = DataProviderManager.getInstance().getExistingDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); - assertNotNull(dp2); - assertTrue(dp == dp2); - ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp3 = DataProviderManager.getInstance().getOrCreateDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); - assertNotNull(dp3); - assertTrue(dp == dp3); - assertTrue(dp == dp2); + try { + ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp = DataProviderManager.getInstance().getExistingDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNull(dp); + dp = DataProviderManager.getInstance().getOrCreateDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNotNull(dp); + ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp2 = DataProviderManager.getInstance().getExistingDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNotNull(dp2); + assertTrue(dp == dp2); + ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp3 = DataProviderManager.getInstance().getOrCreateDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNotNull(dp3); + assertTrue(dp == dp3); + assertTrue(dp == dp2); + } finally { + DataProviderManager.getInstance().removeDataProvider(trace, CPU_USAGE_DP_ID); + } + } + + /** + * Test different get methods + */ + @Test + public void testGetterNew() { + ITmfTrace trace = fKernelTrace; + assertNotNull(trace); + try { + ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp = DataProviderManager.getInstance().fetchExistingDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNull(dp); + dp = DataProviderManager.getInstance().fetchOrCreateDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNotNull(dp); + ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp2 = DataProviderManager.getInstance().fetchExistingDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNotNull(dp2); + assertTrue(dp == dp2); + ITmfTreeXYDataProvider<@NonNull ITmfTreeDataModel> dp3 = DataProviderManager.getInstance().fetchOrCreateDataProvider(trace, CPU_USAGE_DP_ID, ITmfTreeXYDataProvider.class); + assertNotNull(dp3); + assertTrue(dp == dp3); + assertTrue(dp == dp2); + } finally { + DataProviderManager.getInstance().removeDataProvider(trace, CPU_USAGE_DP_ID); + } } /** diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderManager.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderManager.java index 0380ad8576..250aff4549 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderManager.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderManager.java @@ -45,6 +45,7 @@ import org.eclipse.tracecompass.internal.tmf.core.Activator; import org.eclipse.tracecompass.tmf.core.component.DataProviderConstants; import org.eclipse.tracecompass.tmf.core.config.ITmfConfiguration; +import org.eclipse.tracecompass.tmf.core.model.ITmfDataProvider; import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; @@ -88,7 +89,7 @@ public class DataProviderManager { private Multimap fHideDataProviders = HashMultimap.create(); private Multimap fShowDataProviders = HashMultimap.create(); - private final Multimap> fInstances = LinkedHashMultimap.create(); + private final Multimap fInstances = LinkedHashMultimap.create(); /** * Get the instance of the manager @@ -219,15 +220,38 @@ private void loadHiddenDataProviders() { * @return the data provider or null if no data provider is found for the * input parameter. * @since 8.0 + * + * @deprecated As of version 9.7, use {@link #fetchOrCreateDataProvider(ITmfTrace, String, Class)} instead */ + @Deprecated(since = "9.7", forRemoval = true) public synchronized @Nullable > T getOrCreateDataProvider(@NonNull ITmfTrace trace, String id, Class dataProviderClass) { - ITmfTreeDataProvider dataProvider = getExistingDataProvider(trace, id, dataProviderClass); + return fetchOrCreateDataProvider(trace, id, dataProviderClass); + } + + /** + * Gets or creates the data provider for the given trace. + *

+ * This method should never be called from within a + * {@link TmfSignalHandler}. + * + * @param trace + * An instance of {@link ITmfTrace}. Note, that trace can be an + * instance of TmfExperiment, too. + * @param id + * Id of the data provider. This ID can be the concatenation of a + * provider ID + ':' + a secondary ID used to differentiate + * multiple instances of a same provider. + * @param dataProviderClass + * Returned data provider must extend this class + * @return the data provider or null if no data provider is found for the + * input parameter. + * @since 9.7 + */ + public synchronized @Nullable T fetchOrCreateDataProvider(@NonNull ITmfTrace trace, String id, Class dataProviderClass) { + ITmfDataProvider dataProvider = fetchExistingDataProvider(trace, id, dataProviderClass); if (dataProvider != null) { return dataProviderClass.cast(dataProvider); } - if (isHidden(id, trace)) { - return null; - } String[] ids = id.split(DataProviderConstants.ID_SEPARATOR, 2); for (ITmfTrace opened : TmfTraceManager.getInstance().getOpenedTraces()) { if (TmfTraceManager.getTraceSetWithExperiment(opened).contains(trace)) { @@ -236,7 +260,7 @@ private void loadHiddenDataProviders() { */ IDataProviderFactory providerFactory = fDataProviderFactories.get(ids[0]); if (providerFactory != null) { - dataProvider = ids.length > 1 ? providerFactory.createProvider(trace, String.valueOf(ids[1])) : providerFactory.createProvider(trace); + dataProvider = ids.length > 1 ? providerFactory.createDataProvider(trace, String.valueOf(ids[1])) : providerFactory.createDataProvider(trace); if (dataProvider != null && id.equals(dataProvider.getId()) && dataProviderClass.isAssignableFrom(dataProvider.getClass())) { fInstances.put(trace, dataProvider); return dataProviderClass.cast(dataProvider); @@ -268,9 +292,36 @@ private void loadHiddenDataProviders() { * Returned data provider must extend this class * @return the data provider or null * @since 8.0 + * @deprecated As of version 9.7, use {@link #fetchExistingDataProvider(ITmfTrace, String, Class)} instead */ + @Deprecated(since = "9.7", forRemoval = true) public synchronized @Nullable > T getExistingDataProvider(@NonNull ITmfTrace trace, String id, Class dataProviderClass) { - for (ITmfTreeDataProvider dataProvider : fInstances.get(trace)) { + return fetchExistingDataProvider(trace, id, dataProviderClass); + } + + /** + * Get a data provider for the given trace if it already exists due to + * calling {@link #fetchOrCreateDataProvider(ITmfTrace, String, Class)} + * before. + * + *

+ * This method should never be called from within a + * {@link TmfSignalHandler}. + * + * @param trace + * An instance of {@link ITmfTrace}. Note, that trace can be an + * instance of TmfExperiment, too. + * @param id + * Id of the data provider. This ID can be the concatenation of a + * provider ID + ':' + a secondary ID used to differentiate + * multiple instances of a same provider. + * @param dataProviderClass + * Returned data provider must extend this class + * @return the data provider or null + * @since 9.7 + */ + public synchronized @Nullable T fetchExistingDataProvider(@NonNull ITmfTrace trace, String id, Class dataProviderClass) { + for (ITmfDataProvider dataProvider : fInstances.get(trace)) { if (id.equals(dataProvider.getId()) && dataProviderClass.isAssignableFrom(dataProvider.getClass()) && !isHidden(id, trace)) { return dataProviderClass.cast(dataProvider); } @@ -290,7 +341,7 @@ public void traceClosed(final TmfTraceClosedSignal signal) { new Thread(() -> { synchronized (DataProviderManager.this) { for (ITmfTrace trace : TmfTraceManager.getTraceSetWithExperiment(signal.getTrace())) { - fInstances.removeAll(trace).forEach(ITmfTreeDataProvider::dispose); + fInstances.removeAll(trace).forEach(ITmfDataProvider::dispose); } } }).start(); @@ -402,9 +453,9 @@ public > boolean rem * @since 9.7 */ public void removeDataProvider(ITmfTrace trace, String id) { - Iterator> iter = fInstances.get(trace).iterator(); + Iterator iter = fInstances.get(trace).iterator(); while (iter.hasNext()) { - ITmfTreeDataProvider dp = iter.next(); + ITmfDataProvider dp = iter.next(); if (dp.getId().equals(id)) { dp.dispose(); iter.remove(); @@ -487,9 +538,9 @@ public synchronized void removeDataProviderFactory(String id) { private void removeExistingDataProviders(IDataProviderFactory factory, String passedFactoryId) { if (factory != null) { for (ITmfTrace trace : fInstances.keySet()) { - Iterator> iter = fInstances.get(trace).iterator(); + Iterator iter = fInstances.get(trace).iterator(); while (iter.hasNext()) { - ITmfTreeDataProvider dp = iter.next(); + ITmfDataProvider dp = iter.next(); String factoryId = extractFactoryId(dp.getId()); if (passedFactoryId.equals(factoryId)) { dp.dispose(); diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/IDataProviderFactory.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/IDataProviderFactory.java index 9ae19e82cd..c14aef960c 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/IDataProviderFactory.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/IDataProviderFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Ericsson + * Copyright (c) 2017, 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 @@ -18,6 +18,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.tmf.core.config.ITmfDataProviderConfigurator; +import org.eclipse.tracecompass.tmf.core.model.ITmfDataProvider; import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; @@ -40,11 +41,28 @@ public interface IDataProviderFactory extends IAdaptable { * A trace * @return {@link ITmfTreeDataProvider} that can be use for the given trace * @since 4.0 + * @deprecated As of version 9.7, use {@link #createDataProvider(ITmfTrace)} instead */ - @Nullable ITmfTreeDataProvider createProvider(@NonNull ITmfTrace trace); + @Deprecated(since = "9.7", forRemoval = true) + @Nullable default ITmfTreeDataProvider createProvider(@NonNull ITmfTrace trace) { + return null; + } /** - * Create a {@link ITmfTreeDataProvider} for the given trace. If this factory + * Create a {@link ITmfDataProvider} for the given trace. If this factory + * does not know how to handle the given trace it will return null + * + * @param trace + * A trace + * @return {@link ITmfDataProvider} that can be use for the given trace + * @since 9.7 + */ + @Nullable default ITmfDataProvider createDataProvider(@NonNull ITmfTrace trace) { + return createProvider(trace); + } + + /** +D * Create a {@link ITmfTreeDataProvider} for the given trace. If this factory * does not know how to handle the given trace it will return null. The * resulting provider should have an ID that is an aggregate of the provider's * own ID and the secondaryId as such: : @@ -59,11 +77,34 @@ public interface IDataProviderFactory extends IAdaptable { * ID :, or null if no provider * is available for this trace and ID * @since 4.0 + * @deprecated As of version 9.7, use {@link #createDataProvider(ITmfTrace)} instead */ + @Deprecated(since = "9.7", forRemoval = true) default @Nullable ITmfTreeDataProvider createProvider(@NonNull ITmfTrace trace, @NonNull String secondaryId) { return createProvider(trace); } + /** + * Create a {@link ITmfDataProvider} for the given trace. If this factory + * does not know how to handle the given trace it will return null. The + * resulting provider should have an ID that is an aggregate of the provider's + * own ID and the secondaryId as such: : + * + * @param trace + * A trace + * @param secondaryId + * Additional ID to identify different instances of the same + * provider, for instance, when the same provider can be used for + * different analysis modules + * @return {@link ITmfDataProvider} that can be use for the given trace with + * ID :, or null if no provider + * is available for this trace and ID + * @since 9.7 + */ + default @Nullable ITmfDataProvider createDataProvider(@NonNull ITmfTrace trace, @NonNull String secondaryId) { + return createProvider(trace, secondaryId); + } + /** * Gets the collection of data provider descriptors for this trace that this * data provider factory can create, if the trace supports it, else diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/ITmfDataProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/ITmfDataProvider.java new file mode 100644 index 0000000000..a77f3ae189 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/ITmfDataProvider.java @@ -0,0 +1,76 @@ +/********************************************************************** + * 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.model; + +/** + * Base interface that each data provider has to implement. + * + * Each data provider needs to provide at least one fetch method, that is + * typical for this data provider type and which returns @link TmfModelResponse} + * with a defined serializable model. + * + *

+ * Example interface: + *

{@code
+ * public ICustomDataProvider implements ITmfDataProvider {
+ *   TmfModelResponse fetchCustomData(Map fetchParameters, @Nullable IProgressMonitor monitor);
+ * }
+ * }
+ *

+ * Example implementation: + *
{@code
+ *  public class CustomModel {
+ *    private final String fValue = value;
+ *    public CustomModel(String value) {
+ *      fValue = value;
+ *    }
+ *    String getValue() {
+ *      return fValue;
+ *    }
+ *  }
+ *
+ *  public class CustomDataProvider implements ICustomDataProvider {
+ *    // ITmfDataProvider
+ *    public String getId() {
+ *      return "customId";
+ *    }
+ *    public void dispose() {}
+ *
+ *    // ICustomDataProvider
+ *    TmfModelResponse fetchCustomData(Map fetchParameters, @Nullable IProgressMonitor monitor) {
+ *        CustomModel model = new CustomModel("my data");
+ *        return new TmfModelResponse<>(model, ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
+ *    }
+ *  }
+ * }
+ * + * + * @since 9.7 + * @author Matthew Khouzam + * @auther Bernd Hufmann + * + */ +public interface ITmfDataProvider { + /** + * This method return the extension point ID of this provider + * + * @return The ID + */ + String getId(); + + /** + * Dispose of the provider to avoid resource leakage. + */ + public default void dispose() { + // Do nothing for now + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/ITmfTreeDataProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/ITmfTreeDataProvider.java index f7056af531..809c01799a 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/ITmfTreeDataProvider.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/ITmfTreeDataProvider.java @@ -15,6 +15,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.model.ITmfDataProvider; import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse; /** @@ -26,7 +27,7 @@ * Tree model extending {@link ITmfTreeDataModel} * @since 4.0 */ -public interface ITmfTreeDataProvider { +public interface ITmfTreeDataProvider extends ITmfDataProvider{ /** * This methods computes a tree model. Then, it returns a @@ -42,19 +43,6 @@ public interface ITmfTreeDataProvider { * @since 5.0 */ TmfModelResponse> fetchTree(Map fetchParameters, @Nullable IProgressMonitor monitor); +} - /** - * This method return the extension point ID of this provider - * - * @return The ID - */ - String getId(); - /** - * Dispose of the provider to avoid resource leakage. - * - * @since 4.0 - */ - public default void dispose() { - } -}