diff --git a/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/IReportDataProvider.java b/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/IReportDataProvider.java index 33f609bb6..c8bf19bf4 100644 --- a/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/IReportDataProvider.java +++ b/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/IReportDataProvider.java @@ -11,6 +11,7 @@ package org.eclipse.tracecompass.incubator.analysis.core.reports; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.internal.provisional.tmf.core.dataprovider.ITmfDataProviderDataFetcher; import org.eclipse.tracecompass.tmf.core.config.ITmfConfiguration; import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSourceType; import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor; @@ -25,7 +26,7 @@ * * @author Kaveh Shahedi */ -public interface IReportDataProvider { +public interface IReportDataProvider extends ITmfDataProviderDataFetcher { /** * Type identifier for report providers diff --git a/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ImageReportDataProvider.java b/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ImageReportDataProvider.java index 442fc53be..d4edf5ac5 100644 --- a/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ImageReportDataProvider.java +++ b/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ImageReportDataProvider.java @@ -15,6 +15,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; +import java.nio.file.Files; import java.util.List; import java.util.Map; import java.util.Objects; @@ -24,7 +25,9 @@ import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.incubator.internal.analysis.core.Activator; +import org.eclipse.tracecompass.internal.provisional.tmf.core.dataprovider.TmfDataProviderDataModel; import org.eclipse.tracecompass.tmf.core.config.ITmfConfigParamDescriptor; import org.eclipse.tracecompass.tmf.core.config.ITmfConfiguration; import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSourceType; @@ -33,9 +36,14 @@ import org.eclipse.tracecompass.tmf.core.config.TmfConfigurationSourceType; import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor; import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor.ProviderType; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderFactory; import org.eclipse.tracecompass.tmf.core.exceptions.TmfConfigurationException; import org.eclipse.tracecompass.tmf.core.model.DataProviderCapabilities; import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor; +import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; +import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider; +import org.eclipse.tracecompass.tmf.core.response.ITmfResponse; +import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; /** @@ -43,7 +51,7 @@ * * @author Kaveh Shahedi */ -public class ImageReportDataProvider implements IReportDataProvider { +public class ImageReportDataProvider implements IReportDataProvider, IDataProviderFactory { private static final String[] VALID_EXTENSIONS = { "png", "jpg", "jpeg", "svg" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ // //$NON-NLS-5$ @@ -251,4 +259,38 @@ public void validateConfiguration(@NonNull ITmfConfiguration configuration) thro return getDescriptorFromConfig(trace, configuration); } + + @SuppressWarnings("restriction") + @Override + public TmfModelResponse> getData(ITmfTrace trace, IDataProviderDescriptor descriptor) throws Exception { + ITmfConfiguration configuration = descriptor.getConfiguration(); + if (configuration == null) { + throw new TmfConfigurationException("Missing configuration for report"); //$NON-NLS-1$ + } + + // Get the image path from the configuration + String imagePath = (String) configuration.getParameters().get(PATH); + if (imagePath == null) { + throw new TmfConfigurationException("Image path not found in configuration"); //$NON-NLS-1$ + } + + File imageFile = new File(imagePath); + if (!imageFile.exists() || !imageFile.isFile()) { + throw new TmfConfigurationException("Image file not found"); //$NON-NLS-1$ + } + + String contentType = Files.probeContentType(imageFile.toPath()); + if (contentType == null) { + contentType = "application/octet-stream"; //$NON-NLS-1$ + } + + TmfDataProviderDataModel dataModel = new TmfDataProviderDataModel<>(imageFile, contentType, imageFile.getName()); + + return new TmfModelResponse<>(dataModel, ITmfResponse.Status.COMPLETED, configuration.getName()); + } + + @Override + public @Nullable ITmfTreeDataProvider createProvider(@NonNull ITmfTrace trace) { + return null; + } } \ No newline at end of file diff --git a/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ReportsDataProviderFactory.java b/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ReportsDataProviderFactory.java index b7fa6092a..9928af9ab 100644 --- a/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ReportsDataProviderFactory.java +++ b/callstack/org.eclipse.tracecompass.incubator.analysis.core/src/org/eclipse/tracecompass/incubator/analysis/core/reports/ReportsDataProviderFactory.java @@ -48,6 +48,7 @@ import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor; import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataProvider; +import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; @@ -55,6 +56,7 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.eclipse.tracecompass.incubator.internal.analysis.core.Activator; +import org.eclipse.tracecompass.internal.provisional.tmf.core.dataprovider.TmfDataProviderDataModel; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; @@ -726,4 +728,28 @@ public void dispose() { fTmfConfigurationHierarchy.clear(); } + @SuppressWarnings("restriction") + @Override + public TmfModelResponse> getData(ITmfTrace trace, IDataProviderDescriptor descriptor) throws Exception { + if (descriptor.getType() != ProviderType.NONE) { + throw new TmfConfigurationException("The requested output is not a MIME report"); //$NON-NLS-1$ + } + + ITmfConfiguration configuration = descriptor.getConfiguration(); + if (configuration == null) { + throw new TmfConfigurationException("Missing configuration for report"); //$NON-NLS-1$ " + } + + ReportProviderType reportType = getReportType(configuration); + IReportDataProvider provider = ReportsDataProviderRegistry.getProvider(reportType); + if (provider == null) { + throw new TmfConfigurationException("No provider found for report type"); //$NON-NLS-1$ + } + + if (provider instanceof ReportsDataProviderFactory) { + throw new TmfConfigurationException("Cannot get data from the report factory"); //$NON-NLS-1$ + } + + return provider.getData(trace, descriptor); + } } \ No newline at end of file diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/DataProvider.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/DataProvider.java index 20706c139..96443671a 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/DataProvider.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/DataProvider.java @@ -22,7 +22,7 @@ public interface DataProvider { * The provider types. */ enum ProviderType { - TABLE, TREE_TIME_XY, TIME_GRAPH, DATA_TREE, NONE + TABLE, TREE_TIME_XY, TIME_GRAPH, DATA_TREE, MIME, NONE } /** diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/DataProviderService.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/DataProviderService.java index 2ccf3721c..33973431f 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/DataProviderService.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/DataProviderService.java @@ -35,6 +35,7 @@ import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.EXP_UUID; import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.FILTER_QUERY_PARAMETERS; import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.FILTER_QUERY_PARAMETERS_EX; +import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.RPT; import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.INDEX; import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.INDEX_EX; import static org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.EndpointConstants.INVALID_PARAMETERS; @@ -133,6 +134,8 @@ import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.views.TreeModelWrapper; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.views.VirtualTableModelWrapper; import org.eclipse.tracecompass.internal.analysis.timing.core.event.matching.EventMatchingLatencyAnalysis; +import org.eclipse.tracecompass.internal.provisional.tmf.core.dataprovider.ITmfDataProviderDataFetcher; +import org.eclipse.tracecompass.internal.provisional.tmf.core.dataprovider.TmfDataProviderDataModel; import org.eclipse.tracecompass.internal.provisional.tmf.core.model.table.ITmfVirtualTableDataProvider; import org.eclipse.tracecompass.internal.provisional.tmf.core.model.table.ITmfVirtualTableModel; import org.eclipse.tracecompass.internal.provisional.tmf.core.model.table.IVirtualTableLine; @@ -1101,6 +1104,78 @@ private Response getTree(UUID expUUID, String outputId, QueryParameters queryPar } } + /** + * Query the provider for a MIME report. Based on the given output, this + * endpoint will return a specific report, which can be an image, a + * textual data, a HTML, etc. + * + * @param expUUID + * desired experiment UUID + * @param outputId + * Output ID for the data provider to query + * @return {@link Response} with the corresponding report data + */ + @GET + @Path("/report/{outputId}") + @Tag(name = RPT) + @Produces(MediaType.WILDCARD) + @Operation(summary = "API to get a MIME report", responses = { + @ApiResponse(responseCode = "200", description = "Returns the report data"), + @ApiResponse(responseCode = "400", description = MISSING_PARAMETERS, content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "404", description = "Provider not found, missing subtype, or requested resource not found", content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "500", description = "Error retrieving the report data", content = @Content(schema = @Schema(implementation = String.class))), + }) + public Response getReport( + @Parameter(description = EXP_UUID) @PathParam("expUUID") UUID expUUID, + @Parameter(description = OUTPUT_ID) @PathParam("outputId") String outputId) { + + if (outputId == null) { + return Response.status(Status.BAD_REQUEST).entity(MISSING_OUTPUTID).build(); + } + + TmfExperiment experiment = ExperimentManagerService.getExperimentByUUID(expUUID); + if (experiment == null) { + return Response.status(Status.NOT_FOUND).entity(NO_SUCH_TRACE).build(); + } + + IDataProviderDescriptor descriptor = getDescriptor(experiment, outputId); + if (descriptor == null) { + return Response.status(Status.NOT_FOUND).entity(NO_SUCH_PROVIDER).build(); + } + + IDataProviderFactory factory = manager.getFactory(REPORTS_FACTORY_ID); + if (factory == null) { + return Response.status(Status.NOT_FOUND).entity(NO_SUCH_PROVIDER).build(); + } + + ITmfDataProviderDataFetcher dataFetcher = factory.getAdapter(ITmfDataProviderDataFetcher.class); + if (dataFetcher == null) { + return Response.status(Status.NOT_FOUND).entity("Report data fetcher not found").build(); //$NON-NLS-1$ " + } + + try { + TmfModelResponse> reportResponse = dataFetcher.getData(experiment, descriptor); + if (reportResponse == null) { + return Response.status(Status.NOT_FOUND).entity("Report data not found").build(); //$NON-NLS-1$ + } + + if (reportResponse.getStatus() != ITmfResponse.Status.COMPLETED) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(reportResponse.getStatusMessage()).build(); + } + + TmfDataProviderDataModel responseModel = reportResponse.getModel(); + if (responseModel == null) { + return Response.status(Status.NOT_FOUND).entity("Report data model not found").build(); //$NON-NLS-1$ + } + + return Response.ok(responseModel.getContent(), responseModel.getContentType()).build(); + } catch (TmfConfigurationException e) { + return Response.status(Status.NOT_FOUND).entity(e.getMessage()).build(); + } catch (Exception e) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } + /** * Query the provider for styles * diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/EndpointConstants.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/EndpointConstants.java index b56ab6eeb..2e2bb68df 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/EndpointConstants.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/EndpointConstants.java @@ -99,6 +99,7 @@ public final class EndpointConstants { static final String EXP = "Experiments"; //$NON-NLS-1$ static final String IDF = "Identifier"; //$NON-NLS-1$ static final String OCG = "Output Configurations"; //$NON-NLS-1$ + static final String RPT = "Report"; //$NON-NLS-1$ static final String STY = "Styles"; //$NON-NLS-1$ static final String TGR = "TimeGraph"; //$NON-NLS-1$ static final String TRA = "Traces"; //$NON-NLS-1$