diff --git a/tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/analysis/AnalysisModuleTest.java b/tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/analysis/AnalysisModuleTest.java index 865942e959..eab4c8e16b 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/analysis/AnalysisModuleTest.java +++ b/tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/analysis/AnalysisModuleTest.java @@ -331,7 +331,7 @@ public void testDependentAnalyses() { final TestAnalysis depModule = new TestAnalysis() { @Override - protected boolean executeAnalysis(IProgressMonitor monitor) { + protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -460,6 +460,70 @@ protected Iterable getDependentAnalyses() { } + /** + * Test that the failure of the dependent analysis is propagated to the + * parent analysis by the {@link TmfAbstractAnalysisModule} + */ + @Test + public void testFailedDependentAnalyses() { + + ITmfTrace trace = TmfTestTrace.A_TEST_10K.getTrace(); + int paramAndResult = 5; + + /* Setup the dependent module */ + final String suffix = " dep"; + final TestAnalysis depModule = new TestAnalysis() { + + @Override + protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return false; + } + return super.executeAnalysis(monitor); + } + + }; + depModule.setName(MODULE_GENERIC_NAME + suffix); + depModule.setId(MODULE_GENERIC_ID + suffix); + depModule.addParameter(TestAnalysis.PARAM_TEST); + depModule.setParameter(TestAnalysis.PARAM_TEST, 1999); + + /* Prepare the main analysis with a dependent analysis */ + TestAnalysis module = new TestAnalysis() { + + @Override + protected Iterable getDependentAnalyses() { + Set modules = new HashSet<>(); + modules.add(depModule); + return modules; + } + + }; + + module.setName(MODULE_GENERIC_NAME); + module.setId(MODULE_GENERIC_ID); + module.addParameter(TestAnalysis.PARAM_TEST); + module.setParameter(TestAnalysis.PARAM_TEST, paramAndResult); + + try { + assertTrue(depModule.setTrace(trace)); + assertTrue(module.setTrace(trace)); + } catch (TmfAnalysisException e) { + fail(e.getMessage()); + } + + module.schedule(); + + /* Verify that failure of the dependent analysis is propagated to the parent */ + assertFalse(module.waitForCompletion()); + + module.dispose(); + depModule.dispose(); + trace.dispose(); + } + /** * Test configurable analysis * diff --git a/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/analysis/TestAnalysis.java b/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/analysis/TestAnalysis.java index b6de8bee48..ee8b1700da 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/analysis/TestAnalysis.java +++ b/tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/analysis/TestAnalysis.java @@ -17,6 +17,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; /** @@ -44,7 +45,7 @@ public boolean canExecute(ITmfTrace trace) { } @Override - protected boolean executeAnalysis(final IProgressMonitor monitor) { + protected boolean executeAnalysis(final IProgressMonitor monitor) throws TmfAnalysisException { Object parameter = getParameter(PARAM_TEST); if (!(parameter instanceof Integer)) { throw new RuntimeException("The parameter should be set"); @@ -64,6 +65,8 @@ protected boolean executeAnalysis(final IProgressMonitor monitor) { } } return !monitor.isCanceled(); + } else if (integer == 1999) { + throw new TmfAnalysisException("Failure"); } return true; } diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/IAnalysisModule.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/IAnalysisModule.java index 7a46e1f621..0c53b0da94 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/IAnalysisModule.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/IAnalysisModule.java @@ -286,6 +286,16 @@ default void fail(@NonNull Throwable cause) { // Do nothing by default. } + /** + * Gets the error cause in case of failure + * + * @return the error cause + * @since 10.1 + */ + default @Nullable Throwable getFailureCause() { + return null; + } + // ----------------------------------------------------- // Utilities // ----------------------------------------------------- diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/TmfAbstractAnalysisModule.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/TmfAbstractAnalysisModule.java index 2138e92d9b..ec418cff14 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/TmfAbstractAnalysisModule.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/TmfAbstractAnalysisModule.java @@ -299,6 +299,14 @@ public final void fail(Throwable cause) { onFail(); } + /** + * @since 10.1 + */ + @Override + public @Nullable Throwable getFailureCause() { + return fFailureCause; + } + /** * Method executed when the analysis has failed, so that analysis can * rectify their state. For instance, if the analysis had not been @@ -383,7 +391,7 @@ private void execute(final ITmfTrace trace) { * Actual analysis will be run on a separate thread */ String jobName = checkNotNull(NLS.bind(Messages.TmfAbstractAnalysisModule_RunningAnalysis, getName())); - fJob = new Job(jobName) { + Job job = new Job(jobName) { @Override protected @Nullable IStatus run(final @Nullable IProgressMonitor monitor) { try (FlowScopeLog jobLog = new FlowScopeLogBuilder(LOGGER, Level.FINE, "TmfAbstractAnalysis:executing").setParentScope(analysisLog).build()) { //$NON-NLS-1$ @@ -393,11 +401,16 @@ private void execute(final ITmfTrace trace) { TmfCoreTracer.traceAnalysis(TmfAbstractAnalysisModule.this.getId(), TmfAbstractAnalysisModule.this.getTrace(), "started"); //$NON-NLS-1$ fAnalysisCancelled = !executeAnalysis(mon); for (IAnalysisModule module : dependentAnalyses) { - module.waitForCompletion(mon); + boolean isModuleCancelled = !module.waitForCompletion(mon); + if (isModuleCancelled) { + Throwable cause = module.getFailureCause(); + if (cause != null) { + throw new TmfAnalysisException("Dependent analysis '" + module.getName() + "' failed.", cause); //$NON-NLS-1$ //$NON-NLS-2$ + } + fAnalysisCancelled |= isModuleCancelled; + } } TmfCoreTracer.traceAnalysis(TmfAbstractAnalysisModule.this.getId(), TmfAbstractAnalysisModule.this.getTrace(), "finished"); //$NON-NLS-1$ - } catch (TmfAnalysisException e) { - Activator.logError("Error executing analysis with trace " + trace.getName(), e); //$NON-NLS-1$ } catch (OperationCanceledException e) { // Analysis was canceled } catch (Exception e) { @@ -428,6 +441,7 @@ protected void canceling() { } }; + fJob = job; fJob.schedule(); } } diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/exceptions/TmfAnalysisException.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/exceptions/TmfAnalysisException.java index 38e309b4a5..174d06281f 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/exceptions/TmfAnalysisException.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/exceptions/TmfAnalysisException.java @@ -56,4 +56,15 @@ public TmfAnalysisException(Throwable cause) { super(cause); } + /** + * Constructs a new exception with a message and with the specified cause. + * + * @param cause + * The cause + * @since 10.1 + */ + public TmfAnalysisException(String message, Throwable cause) { + super(message, cause); + } + }