Skip to content

Commit 7074455

Browse files
committed
doc: Add global configuration to trace-server developer guide
Signed-off-by: Bernd Hufmann <[email protected]>
1 parent c4c7602 commit 7074455

File tree

1 file changed

+241
-3
lines changed

1 file changed

+241
-3
lines changed

doc/trace-server/trace-server-dev-guide.md

Lines changed: 241 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ An `analysis` module in Trace Compass is an entity that consumes trace events of
1313

1414
A `configuration` is the data structure to configure and customize the trace server back-end globally (e.g. load XML analysis) or to configure data providers with parameters.
1515

16+
### Configuration source
17+
18+
A configuration source is a source of configurations. It is responsible to manage global configurations (e.g. create, delete, update etc).
19+
1620
### Configuration source type
1721

1822
A configuration source type describes the input parameters to provide when creating a new data provider or to configure the trace server globally.
@@ -224,6 +228,238 @@ A trace type defines a parser for the raw trace file(s). It will parse the raw t
224228

225229
Trace compass provides a mechanism for different components to interact with each other using signals. The signals can carry information that is specific to each signal. In the Trace Server only uses a subset of the available signals, where `TmfTraceOpenedSignal` and `TmfTraceClosedSignal` are the most important signals, some other signals are not applicable when running in the trace server context. See the [Trace Compass Developer Guide for Eclipse](https://archive.eclipse.org/tracecompass/doc/nightly/org.eclipse.tracecompass.doc.dev/Component-Interaction.html#Component_Interaction) for more information about signals and how to send and receive them.
226230

231+
## Implementing a global configuration
232+
233+
Global configurations are used to load configuration parameters that configures the trace server application. For example, one can load XML analysis defintions using the global configuartion interface.
234+
235+
### Implementing a configuration source
236+
237+
To implement a configuration source use the extension point for configuration source with id `org.eclipse.tracecompass.tmf.core.config`. The following example explains for the XML anlaysis available in the Trace Compass core code base.
238+
239+
```xml
240+
<extension
241+
point="org.eclipse.tracecompass.tmf.core.config">
242+
<source
243+
id="org.eclipse.tracecompass.tmf.core.config.xmlsourcetype"
244+
class="org.eclipse.tracecompass.internal.tmf.analysis.xml.core.config.XmlConfigurationSource">
245+
</source>
246+
</extension>
247+
</extension>
248+
```
249+
250+
After that implement the `ITmfConfigurationSource` interface. Implement the following methods:
251+
252+
- `ITmfConfigurationSourceType getConfigurationSourceType()`
253+
Return the configuration source type that this configuration source can handle. The configuration source type descibes the input parameter to pass when creating a global configuration. See chapter [Implementing a configuration source type](#implementing-a-configuration-source-type) about the class to return.
254+
- `ITmfConfiguration create(ITmfConfiguration configuration)`
255+
This method is called to create a global configuration base on the input configuration. It returns a `ITmfConfiguration` instance. It is repsonsible to persist the configuration in memory and on disk so that it is available after a server restart. To persist to disk the plug-in state location of workspace can be used which is accessible using Eclipse platform APIs.
256+
- `ITmfConfiguration update(String id, ITmfConfiguration configuration)`
257+
This method is called to update an existing configuration with new parameters.
258+
- `ITmfConfiguration remove(String id)`
259+
This method is called to remove an existing configuration by ID. If the configuration exisits, this method is responsible to clean-up the peristed data. If, for example, analysis modules with state systems or other persisted data were created as result of an configuration, this method needs to make sure that those are clean-up.
260+
- `List<ITmfConfiguration> getConfigurations()`
261+
Gets all configuration instances.
262+
- `boolean contains(String id)`
263+
Method to check if a configuration with given ID exists
264+
- `ITmfConfiguration get(String id)`
265+
Returns a configuration with given ID if it exists
266+
- `void dispose()`
267+
Disposes the configuration source
268+
269+
The below the code for the `XmlConfigurationSource`. Note it reuses utilities that already existed for the integration with Eclipse Trace Compass.
270+
271+
```java
272+
/*******************************************************************************
273+
* Copyright (c) 2023 Ericsson
274+
*
275+
* All rights reserved. This program and the accompanying materials are
276+
* made available under the terms of the Eclipse Public License 2.0 which
277+
* accompanies this distribution, and is available at
278+
* https://www.eclipse.org/legal/epl-2.0/
279+
*
280+
* SPDX-License-Identifier: EPL-2.0
281+
*******************************************************************************/
282+
package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.config;
283+
284+
import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
285+
286+
import java.io.File;
287+
import java.util.List;
288+
import java.util.Map;
289+
import java.util.Map.Entry;
290+
import java.util.concurrent.ConcurrentHashMap;
291+
292+
import org.eclipse.core.runtime.IStatus;
293+
import org.eclipse.core.runtime.Path;
294+
import org.eclipse.jdt.annotation.NonNull;
295+
import org.eclipse.jdt.annotation.Nullable;
296+
import org.eclipse.osgi.util.NLS;
297+
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlAnalysisModuleSource;
298+
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
299+
import org.eclipse.tracecompass.tmf.core.config.ITmfConfiguration;
300+
import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSource;
301+
import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSourceType;
302+
import org.eclipse.tracecompass.tmf.core.config.TmfConfigParamDescriptor;
303+
import org.eclipse.tracecompass.tmf.core.config.TmfConfiguration;
304+
import org.eclipse.tracecompass.tmf.core.config.TmfConfigurationSourceType;
305+
import org.eclipse.tracecompass.tmf.core.exceptions.TmfConfigurationException;
306+
307+
import com.google.common.collect.ImmutableList;
308+
309+
/**
310+
* Implementation of {@link ITmfConfigurationSource} for managing data
311+
* driven-analysis in XML files.
312+
*
313+
* @author Bernd Hufmann
314+
*/
315+
public class XmlConfigurationSource implements ITmfConfigurationSource {
316+
317+
private static final ITmfConfigurationSourceType fType;
318+
319+
private static final String XML_ANALYSIS_TYPE_ID = "org.eclipse.tracecompass.tmf.core.config.xmlsourcetype"; //$NON-NLS-1$
320+
private static final String NAME = nullToEmptyString(Messages.XmlConfigurationSource_Name);
321+
private static final String DESCRIPTION = nullToEmptyString(Messages.XmlConfigurationSource_Description);
322+
private static final String PATH_KEY = "path"; //$NON-NLS-1$
323+
private static final String PATH_DESCRIPTION = nullToEmptyString(Messages.XmlConfigurationSource_PathDescription);
324+
private Map<String, ITmfConfiguration> fConfigurations = new ConcurrentHashMap<>();
325+
326+
static {
327+
TmfConfigParamDescriptor.Builder descriptorBuilder = new TmfConfigParamDescriptor.Builder()
328+
.setKeyName(PATH_KEY)
329+
.setDescription(PATH_DESCRIPTION);
330+
331+
fType = new TmfConfigurationSourceType.Builder()
332+
.setId(XML_ANALYSIS_TYPE_ID)
333+
.setDescription(DESCRIPTION)
334+
.setName(NAME)
335+
.setConfigParamDescriptors(ImmutableList.of(descriptorBuilder.build())).build();
336+
}
337+
338+
/**
339+
* Default Constructor
340+
*/
341+
@SuppressWarnings("null")
342+
public XmlConfigurationSource() {
343+
for (Entry<@NonNull String, @NonNull File> entry : XmlUtils.listFiles().entrySet()) {
344+
ITmfConfiguration config = createConfiguration(entry.getValue());
345+
fConfigurations.put(config.getId(), config);
346+
}
347+
}
348+
349+
@Override
350+
public ITmfConfigurationSourceType getConfigurationSourceType() {
351+
return fType;
352+
}
353+
354+
@Override
355+
public ITmfConfiguration create(Map<String, Object> parameters) throws TmfConfigurationException {
356+
return createOrUpdateXml(null, parameters);
357+
}
358+
359+
@Override
360+
public @Nullable ITmfConfiguration get(String id) {
361+
return fConfigurations.get(id);
362+
}
363+
364+
@Override
365+
public ITmfConfiguration update(String id, Map<String, Object> parameters) throws TmfConfigurationException {
366+
ITmfConfiguration config = fConfigurations.get(id);
367+
if (config == null) {
368+
throw new TmfConfigurationException("No such configuration with ID: " + id); //$NON-NLS-1$
369+
}
370+
return createOrUpdateXml(config, parameters);
371+
}
372+
373+
@Override
374+
public @Nullable ITmfConfiguration remove(String id) {
375+
if (fConfigurations.get(id) == null) {
376+
return null;
377+
}
378+
379+
if (!XmlUtils.listFiles().containsKey(id)) {
380+
return null;
381+
}
382+
383+
XmlUtils.deleteFiles(ImmutableList.of(id));
384+
XmlUtils.saveFilesStatus();
385+
XmlAnalysisModuleSource.notifyModuleChange();
386+
return fConfigurations.remove(id);
387+
}
388+
389+
@Override
390+
public List<ITmfConfiguration> getConfigurations() {
391+
return ImmutableList.copyOf(fConfigurations.values());
392+
}
393+
394+
@Override
395+
public boolean contains(String id) {
396+
return fConfigurations.containsKey(id);
397+
}
398+
399+
@Override
400+
public void dispose() {
401+
fConfigurations.clear();
402+
}
403+
404+
private static @Nullable File getFile(Map<String, Object> parameters) {
405+
String path = (String) parameters.get(PATH_KEY);
406+
if (path == null) {
407+
return null;
408+
}
409+
return new File(path);
410+
}
411+
412+
private ITmfConfiguration createOrUpdateXml(@Nullable ITmfConfiguration existingConfig, Map<String, Object> parameters) throws TmfConfigurationException {
413+
File file = getFile(parameters);
414+
if (file == null) {
415+
throw new TmfConfigurationException("Missing path"); //$NON-NLS-1$
416+
}
417+
418+
ITmfConfiguration config = createConfiguration(file);
419+
420+
IStatus status = XmlUtils.xmlValidate(file);
421+
if (status.isOK()) {
422+
if (existingConfig == null) {
423+
status = XmlUtils.addXmlFile(file);
424+
} else {
425+
if (!existingConfig.getId().equals(config.getId())) {
426+
throw new TmfConfigurationException("File mismatch"); //$NON-NLS-1$
427+
}
428+
XmlUtils.updateXmlFile(file);
429+
}
430+
if (status.isOK()) {
431+
XmlAnalysisModuleSource.notifyModuleChange();
432+
XmlUtils.saveFilesStatus();
433+
fConfigurations.put(config.getId(), config);
434+
return config;
435+
}
436+
}
437+
String statusMessage = status.getMessage();
438+
String message = statusMessage != null? statusMessage : "Failed to update xml analysis configuration"; //$NON-NLS-1$
439+
if (status.getException() != null) {
440+
throw new TmfConfigurationException(message, status.getException());
441+
}
442+
throw new TmfConfigurationException(message);
443+
}
444+
445+
@SuppressWarnings("null")
446+
private static String getName(String file) {
447+
return new Path(file).removeFileExtension().toString();
448+
}
449+
450+
private static ITmfConfiguration createConfiguration(File file) {
451+
String id = file.getName();
452+
String name = getName(file.getName());
453+
String description = NLS.bind(Messages.XmlConfigurationSource_ConfigDescription, name);
454+
TmfConfiguration.Builder builder = new TmfConfiguration.Builder()
455+
.setName(name)
456+
.setId(id)
457+
.setDescription(description.toString())
458+
.setSourceTypeId(XML_ANALYSIS_TYPE_ID);
459+
return builder.build();
460+
}
461+
}
462+
```
227463

228464
## Implementing an analysis module
229465

@@ -1285,7 +1521,7 @@ Using data provider configurators this is possible. Note that this interface is
12851521
A data provider configurator needs to implement the `ITmfDataProviderConfigurator` interface. Implement the following methods
12861522

12871523
- `List<ITmfConfigurationSourceType> getConfigurationSourceTypes()`
1288-
Return one or more configuration source type that this configurator can handle. The configuration source type descibes the input parameter to pass when creating a data provider
1524+
Return one or more configuration source type that this configurator can handle. The configuration source type describes the input parameter to pass when creating a data provider
12891525
- `IDataProviderDescriptor createDataProviderDescriptors(ITmfTrace trace, ITmfConfiguration configuration)`
12901526
This method is called to create derived data providers base on the input configuration. It returns a data provider descriptor of the derived data provider. The descriptor has to have the configuration set, has to have the capability of `canDelete` (so that it can be deleted) as well as it has to have an ID that has the configuration ID appended, which will be used by the corresponding data provider factory to create an instance of the data provider. It is responsible to create and manage analysis modules (e.g. add to ITmfTrace object) and persist the configuration in memory and disk so that it available after a server restart.
12911527
- `removeDataProviderDescriptor(ITmfTrace trace, IDataProviderDescriptor descriptor) throws TmfConfigurationException`
@@ -1306,7 +1542,11 @@ The actual data provider needs to apply the configuration. The easiest way is to
13061542

13071543
### Implementing a configuration source type
13081544

1545+
<<<<<<< HEAD
13091546
The configuration source type describes the input parameters to provide when to pass when creating a new data provider or global configuration.
1547+
=======
1548+
The configuration source type descibes the input parameters to provide when to pass when creating a new data provider or global configuration.
1549+
>>>>>>> 222504c42f (doc: Add global configuration to trace-server developer guide)
13101550
13111551
The interface to implement is `ITmfConfigurationSourceType`. You can use the `TmfConfigurationSourceType.Builder` class to build such type. It has name, description, unique ID, an optional JSON schema file or a list of simple `TmfConfigurationParameter` instances. Use schema as much as you can. The schema will describe the JSON parameters, that `ITmfConfiguration.getParameters()` will return when passed to the configurator.
13121552

@@ -1323,7 +1563,6 @@ The interface to implement is `ITmfConfigurationSourceType`. You can use the `Tm
13231563
}
13241564
```
13251565

1326-
13271566
### Implementing a configurable data provider without analysis module
13281567

13291568
To demonstrate how to implement a configurable data provider that doesn't use an analyis module, we will modify the data provider of chapter [Implementing data provider without analysis module](#implementing-a-data-provider-without-analysis-module). Please note that the class name and package names are different to be able to have independent examples in the example plug-in.
@@ -2912,7 +3151,6 @@ The interfaces for configurable data providers gives the developer the freedom t
29123151

29133152
## To Do
29143153
Provide guides for other features relevant for developing a custom trace server using Trace Compass core APIs, e.g.
2915-
- Global configuration
29163154
- Trace annotation provider (Marker sets, requested_marker_set etc)
29173155
- Time Range columns (e.g. for data tree)
29183156
- Data Types in general (e.g. in data tree, events table)

0 commit comments

Comments
 (0)