trace_type="org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub">
</type>
</extension>
+ <extension
+ point="org.eclipse.tracecompass.tmf.core.analysis.ondemand">
+ <analysis
+ class="org.eclipse.tracecompass.tmf.tests.stubs.analysis.ondemand.OnDemandAnalysisStub"
+ id="org.eclipse.tracecompass.tmf.core.tests.analysis1">
+ </analysis>
+ </extension>
</plugin>
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.tests.analysis.ondemand;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.IOnDemandAnalysis;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.OnDemandAnalysisManager;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.tests.stubs.analysis.ondemand.OnDemandAnalysisStub;
+import org.eclipse.tracecompass.tmf.tests.stubs.trace.TmfTraceStub2;
+import org.eclipse.tracecompass.tmf.tests.stubs.trace.TmfTraceStub3;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Basic tests for {@link IOnDemandAnalysis}, {@link OnDemandAnalysisManager}
+ * and the related extension point.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class OnDemandAnalysisTest {
+
+ private IOnDemandAnalysis analysis = new OnDemandAnalysisStub();
+
+ private ITmfTrace fTraceThatApplies;
+ private ITmfTrace fTraceThatDoesntApply;
+
+ /**
+ * Test setup
+ */
+ @Before
+ public void setup() {
+ fTraceThatApplies = new TmfTraceStub2();
+ fTraceThatDoesntApply = new TmfTraceStub3();
+ }
+
+ /**
+ * Test cleanup
+ */
+ @After
+ public void teardown() {
+ if (fTraceThatApplies != null) {
+ fTraceThatApplies.dispose();
+ fTraceThatApplies = null;
+ }
+ if (fTraceThatDoesntApply != null) {
+ fTraceThatDoesntApply.dispose();
+ fTraceThatDoesntApply = null;
+ }
+ }
+
+ /**
+ * Test our stub analysis with a trace type on which it applies.
+ */
+ @Test
+ public void testApplies() {
+ ITmfTrace trace = fTraceThatApplies;
+ assertNotNull(trace);
+
+ assertTrue(analysis.appliesTo(trace));
+ }
+
+ /**
+ * Test our stub analysis with a trace type on which it does not apply.
+ */
+ @Test
+ public void testDoesNotApply() {
+ ITmfTrace trace = fTraceThatDoesntApply;
+ assertNotNull(trace);
+
+ assertFalse(analysis.appliesTo(trace));
+ }
+
+ /**
+ * Test getting an analysis via the manager. The expected way of doing
+ * things.
+ */
+ @Test
+ public void testGetAnalysisFromTrace() {
+ ITmfTrace trace = fTraceThatApplies;
+ assertNotNull(trace);
+
+ Set<IOnDemandAnalysis> set1 = OnDemandAnalysisManager.getInstance().getOndemandAnalyses(trace);
+
+ assertEquals(1, set1.size());
+ assertTrue(Iterables.getOnlyElement(set1) instanceof OnDemandAnalysisStub);
+
+ /* Make sure it is still true on a subsequent call */
+ Set<IOnDemandAnalysis> set2 = OnDemandAnalysisManager.getInstance().getOndemandAnalyses(trace);
+
+ assertTrue(set1.equals(set2));
+ }
+
+ /**
+ * Test querying the manager for analyses, but for a trace that does not
+ * support any.
+ */
+ @Test
+ public void testGetNoAnalysisFromTrace() {
+ ITmfTrace trace = fTraceThatDoesntApply;
+ assertNotNull(trace);
+
+ Set<IOnDemandAnalysis> set = OnDemandAnalysisManager.getInstance().getOndemandAnalyses(trace);
+ assertTrue(set.isEmpty());
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.tests.stubs.analysis.ondemand;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.IOnDemandAnalysis;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.tests.stubs.trace.TmfTraceStub2;
+
+/**
+ * Stub for on-demand analysis tests.
+ *
+ * It applies to trace type {@link TmfTraceStub2} only.
+ *
+ * @author Alexandre Montplaisir
+ */
+@NonNullByDefault
+public class OnDemandAnalysisStub implements IOnDemandAnalysis {
+
+ @Override
+ public String getName() {
+ return "Test On-Demand Analysis";
+ }
+
+ @Override
+ public boolean appliesTo(ITmfTrace trace) {
+ if (trace instanceof TmfTraceStub2) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean canExecute(ITmfTrace trace) {
+ return appliesTo(trace);
+ }
+
+ @Override
+ public Object execute(ITmfTrace trace, @Nullable TmfTimeRange range, String extraParams, @Nullable IProgressMonitor monitor) {
+ /* Do nothing */
+ return new Object();
+ }
+}
org.eclipse.tracecompass.internal.tmf.core.trace.indexer;x-friends:="org.eclipse.tracecompass.tmf.core.tests",
org.eclipse.tracecompass.tmf.core,
org.eclipse.tracecompass.tmf.core.analysis,
+ org.eclipse.tracecompass.tmf.core.analysis.ondemand,
org.eclipse.tracecompass.tmf.core.analysis.requirements,
org.eclipse.tracecompass.tmf.core.callstack,
org.eclipse.tracecompass.tmf.core.component,
org.eclipse.tracecompass.tmf.core.uml2sd,
org.eclipse.tracecompass.tmf.core.util
Import-Package: com.google.common.base,
+ com.google.common.cache,
com.google.common.collect,
com.google.common.hash;version="15.0.0",
org.apache.commons.io
# Extension points
extensionpoint.trace_type.name = Tmf Trace Type
extensionpoint.analysis_module.name = Trace Analysis Module
+extensionpoint.ondemand_analysis.name = On-demand Analysis
# Experiment type
experimenttype.type.generic = Generic Experiment
<plugin>
<extension-point id="org.eclipse.linuxtools.tmf.core.tracetype" name="%extensionpoint.trace_type.name" schema="schema/org.eclipse.linuxtools.tmf.core.tracetype.exsd"/>
<extension-point id="org.eclipse.linuxtools.tmf.core.analysis" name="%extensionpoint.analysis_module.name" schema="schema/org.eclipse.linuxtools.tmf.core.analysis.exsd"/>
+ <extension-point id="org.eclipse.tracecompass.tmf.core.analysis.ondemand" name="%extensionpoint.ondemand_analysis.name" schema="schema/org.eclipse.tracecompass.tmf.core.analysis.ondemand.exsd"/>
<extension
point="org.eclipse.core.runtime.preferences">
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.tracecompass.tmf.core" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.tracecompass.tmf.core" id="analysis.ondemand" name="On-demand Analysis"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to provide on-demand analyses. Unlike regular analyses, the on-demand ones are only executed when the user specifies it.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="analysis" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ A fully qualified identifier of the target extension point
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ An optional identifier of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ An optional name of the extension instance
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="analysis">
+ <annotation>
+ <documentation>
+ An on-demand analysis which can run on the traces it specifies
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ The unique ID that identifies this on-demand analysis
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The class implementing the on-demand analysis
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.tracecompass.tmf.core.analysis.ondemand.IOndemandAnalysis"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 2.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ <p>
+For an example implementation of an on-demand analysis see:
+<pre>
+plug-in: org.eclipse.linuxtools.tmf.core.tests
+package: org.eclipse.linuxtools.tmf.core.tests.stubs.analysis.ondemand
+class: OnDemandAnalysisStub
+</pre>
+</p>
+
+<p>
+The following is an example of the extension point usage:
+<pre>
+ <extension
+ point="org.eclipse.tracecompass.tmf.core.analysis.ondemand">
+ <analysis
+ class="org.eclipse.tracecompass.tmf.tests.stubs.analysis.ondemand.OnDemandAnalysisStub"
+ id="org.eclipse.tracecompass.tmf.core.tests.analysis1">
+ </analysis>
+ </extension>
+</pre>
+</p>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ Since 2.0
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2016 EfficiOS Inc. and others
+
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a
+href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+ </documentation>
+ </annotation>
+
+</schema>
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.analysis.ondemand;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * An on-demand analysis is an analysis run on a trace and started from an
+ * explicit action from the user.
+ *
+ * The on-demand analysis object should be stateless, meaning every call of the
+ * {@link #execute} method should be independant and not affect each other.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public interface IOnDemandAnalysis {
+
+ /**
+ * Get the displayed name of this analysis. It should usually be
+ * externalized.
+ *
+ * @return The name of this analysis
+ */
+ String getName();
+
+ /**
+ * Determine if the current analysis can run on the given trace.
+ *
+ * If it does not apply, then it should not be suggested for the given trace
+ * at all.
+ *
+ * This method should be a quick filter, and should not for instance call
+ * external processes.
+ *
+ * @param trace
+ * The trace to check for
+ * @return If this analysis applies to the trace
+ */
+ boolean appliesTo(ITmfTrace trace);
+
+ /**
+ * Second level of checking if an analysis can run on a trace.
+ *
+ * A analysis that {@link #appliesTo} a trace but whose {@link #canExecute}
+ * returns false should be suggested to the user, albeit unavailable. For
+ * example, striked-out in the UI.
+ *
+ * This will indicate to the user that in normal cases this analysis should
+ * work, but something (trace contents, environment, etc.) is preventing it.
+ *
+ * @param trace
+ * The trace to check for
+ * @return If this analysis can be run on this trace
+ */
+ boolean canExecute(ITmfTrace trace);
+
+ /**
+ * Execute the analysis on the given trace.
+ *
+ * It should have been ensured that the analysis can run first on this
+ * trace, by calling both {@link #appliesTo} and {@link #canExecute}.
+ *
+ * @param trace
+ * The trace on which to execute the analysis
+ * @param range
+ * The time range on which to execute the analysis
+ * @param extraParams
+ * Extra user-specified parameters to pass to the analysis
+ * @param monitor
+ * The progress monitor, can be null for a default monitor
+ * @return The results of this analysis. Exact object type is
+ * analysis-dependent, a more specific return type is encouraged.
+ */
+ Object execute(ITmfTrace trace, @Nullable TmfTimeRange range,
+ String extraParams, @Nullable IProgressMonitor monitor);
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.analysis.ondemand;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.core.Activator;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Manager for {@link IOnDemandAnalysis}.
+ *
+ * Takes care of reading the extension point information, and providing analyses
+ * for traces via the {@link #getOndemandAnalyses(ITmfTrace)} method.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public final class OnDemandAnalysisManager {
+
+ /** The singleton instance */
+ private static @Nullable OnDemandAnalysisManager INSTANCE;
+
+ private static final String EXTENSION_POINT_ID = "org.eclipse.tracecompass.tmf.core.analysis.ondemand"; //$NON-NLS-1$
+ private static final String ELEM_NAME_ANALYSIS = "analysis"; //$NON-NLS-1$
+
+ private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+
+ private final LoadingCache<ITmfTrace, Set<IOnDemandAnalysis>> analysisCache = checkNotNull(CacheBuilder.newBuilder()
+ .weakKeys()
+ .softValues()
+ .build(new CacheLoader<ITmfTrace, Set<IOnDemandAnalysis>>() {
+ @Override
+ public Set<IOnDemandAnalysis> load(ITmfTrace trace) {
+ return fAnalysisWrappers.stream()
+ .map(wrapper -> wrapper.analysis)
+ .filter(analysis -> analysis.appliesTo(trace))
+ .collect(Collectors.collectingAndThen(Collectors.toSet(), ImmutableSet::copyOf));
+ }
+ }));
+
+ private final List<OndemandAnalysisWrapper> fAnalysisWrappers;
+
+ /**
+ * Internal class used to store extension point information
+ */
+ private static class OndemandAnalysisWrapper {
+
+ public final IOnDemandAnalysis analysis;
+
+ public OndemandAnalysisWrapper(IOnDemandAnalysis analysis) {
+ this.analysis = analysis;
+ }
+ }
+
+ /**
+ * Get the instance of this manager.
+ *
+ * @return The singleton instance of this class
+ */
+ public static synchronized OnDemandAnalysisManager getInstance() {
+ OnDemandAnalysisManager inst = INSTANCE;
+ if (inst == null) {
+ inst = new OnDemandAnalysisManager();
+ INSTANCE = inst;
+ }
+ return inst;
+ }
+
+ /**
+ * Private constructor, should only be called via {@link #getInstance()}.
+ */
+ private OnDemandAnalysisManager() {
+ fAnalysisWrappers = new ArrayList<>();
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+
+ for (IConfigurationElement element : configElements) {
+ if (ELEM_NAME_ANALYSIS.equals(element.getName())) {
+ try {
+ Object extension = element.createExecutableExtension(ATTR_CLASS);
+ if (extension != null) {
+ fAnalysisWrappers.add(new OndemandAnalysisWrapper((IOnDemandAnalysis) extension));
+ }
+ } catch (CoreException | ClassCastException e) {
+ Activator.logError("Exception while loading extension point", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ /**
+ * Get all the registered on-demand analyses that apply to the given trace.
+ *
+ * @param trace
+ * The trace to get the analyses for
+ * @return The set of on-demand analyses that apply to this trace. It can be
+ * empty, but not null
+ */
+ public Set<IOnDemandAnalysis> getOndemandAnalyses(ITmfTrace trace) {
+ return checkNotNull(analysisCache.getUnchecked(trace));
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.tmf.core.analysis.ondemand;
\ No newline at end of file