From 76857cd6f38bdb4c5a8217443f0963dfff36a3a5 Mon Sep 17 00:00:00 2001 From: Simon Delisle Date: Wed, 12 Apr 2017 11:16:05 -0400 Subject: [PATCH] Introduce an API to download and import traces from HTTP/HTTPS This patch contains two parts: - A class to download a file from HTTP links - An import operation that use the download helper to import the dowloaded traces in the workspace Change-Id: I1b588b113e352630760a9cab0dfbfd0052368b29 Signed-off-by: Simon Delisle Reviewed-on: https://git.eclipse.org/r/94940 Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam Reviewed-by: Jean-Christian Kouame Tested-by: Jean-Christian Kouame --- .../META-INF/MANIFEST.MF | 3 +- .../actions/DownloadTraceHttpHelperTest.java | 133 ++++++++++++++ .../actions/HttpTraceImportOperationTest.java | 145 +++++++++++++++ .../META-INF/MANIFEST.MF | 7 +- .../importtrace/DownloadTraceHttpHelper.java | 154 ++++++++++++++++ .../importtrace/TraceDownloadStatus.java | 168 ++++++++++++++++++ .../ui/actions/HttpTraceImportOperation.java | 143 +++++++++++++++ 7 files changed, 750 insertions(+), 3 deletions(-) create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/DownloadTraceHttpHelperTest.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/HttpTraceImportOperationTest.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/DownloadTraceHttpHelper.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceDownloadStatus.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/actions/HttpTraceImportOperation.java diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.ui.tests/META-INF/MANIFEST.MF index 802c2cf569..824a451e56 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui.tests/META-INF/MANIFEST.MF +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/META-INF/MANIFEST.MF @@ -16,7 +16,8 @@ Require-Bundle: org.junit;bundle-version="4.0.0", org.eclipse.tracecompass.common.core, org.eclipse.tracecompass.tmf.core, org.eclipse.tracecompass.tmf.ui, - org.eclipse.tracecompass.tmf.core.tests + org.eclipse.tracecompass.tmf.core.tests, + org.apache.commons.io Export-Package: org.eclipse.tracecompass.tmf.ui.tests, org.eclipse.tracecompass.tmf.ui.tests.actions, org.eclipse.tracecompass.tmf.ui.tests.experiment.type, diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/DownloadTraceHttpHelperTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/DownloadTraceHttpHelperTest.java new file mode 100644 index 0000000000..ba67f92545 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/DownloadTraceHttpHelperTest.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2017 Ericsson + * + * 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 + * + * Contributors: + * Simon Delisle - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.tmf.ui.tests.actions; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.DownloadTraceHttpHelper; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceDownloadStatus; +import org.eclipse.tracecompass.tmf.ui.tests.TmfUITestPlugin; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test the {@link DownloadTraceHttpHelper} class + * + * @author Simon Delisle + */ +public class DownloadTraceHttpHelperTest { + + private static String fTestTrace1Url = "http://archive.eclipse.org/tracecompass/test-traces/tmf/syslog"; + private static String fTestTrace2Url = "http://archive.eclipse.org/tracecompass/test-traces/tmf/syslog_collapse"; + private static String fTraceArchiveUrl = "http://archive.eclipse.org/tracecompass/test-traces/tmf/syslogs.zip"; + private static String fDestinationDirectory; + + /** + * Setup class + * + * @throws Exception + * if an exception occurs + */ + @BeforeClass + public static void beforeClass() throws Exception { + fDestinationDirectory = TmfUITestPlugin.getDefault().getStateLocation().append("httpDownloadTestDirectory").toOSString(); + } + + /** + * Cleanup after each test + * + * @throws IOException + * if an exception occurs + */ + @After + public void afterTest() throws IOException { + File destFile = new File(fDestinationDirectory); + FileUtils.deleteDirectory(destFile); + } + + /** + * Test the download and import operation for a trace file + */ + @Test + public void testTraceDownload() { + TraceDownloadStatus status = DownloadTraceHttpHelper.downloadTrace(fTestTrace1Url, fDestinationDirectory); + assumeFalse(status.isTimeout()); + assertTrue(status.isOk()); + validateSingleDownload(status.getDownloadedFile(), "syslog"); + } + + /** + * Test the download and import operation for a trace file + */ + @Test + public void testMutlipleTracesDownload() { + List tracesUrl = new ArrayList<>(); + tracesUrl.add(fTestTrace1Url); + tracesUrl.add(fTestTrace2Url); + + TraceDownloadStatus multipleStatus = DownloadTraceHttpHelper.downloadTraces(tracesUrl, fDestinationDirectory); + assumeFalse(multipleStatus.isTimeout()); + assertTrue(multipleStatus.isOk()); + + List downloadedTraces = new ArrayList<>(); + for (TraceDownloadStatus status : multipleStatus.getChildren()) { + downloadedTraces.add(status.getDownloadedFile()); + } + + // Make sure that there is only two traces + assertEquals(2, downloadedTraces.size()); + validateMultipleDownload(downloadedTraces); + } + + /** + * Test the download and import operation for a trace file + */ + @Test + public void testArchiveTraceDownload() { + TraceDownloadStatus status = DownloadTraceHttpHelper.downloadTrace(fTraceArchiveUrl, fDestinationDirectory); + assumeFalse(status.isTimeout()); + assertTrue(status.isOk()); + validateSingleDownload(status.getDownloadedFile(), "syslogs.zip"); + } + + private static void validateSingleDownload(File downloadedFile, String expectedFileName) { + // Make sure that the name was correctly identify + assertEquals(expectedFileName, downloadedFile.getName()); + + // Check if the directory contains only one trace + File dest = new File(fDestinationDirectory); + File[] listFiles = dest.listFiles(); + assertEquals(1, listFiles.length); + assertEquals(expectedFileName, listFiles[0].getName()); + assertTrue(listFiles[0].exists()); + } + + private static void validateMultipleDownload(List downloadedFile) { + // Check if the directory contains two traces + File dest = new File(fDestinationDirectory); + File[] listFiles = dest.listFiles(); + assertEquals(2, listFiles.length); + for (File file : listFiles) { + assertTrue(file.exists()); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/HttpTraceImportOperationTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/HttpTraceImportOperationTest.java new file mode 100644 index 0000000000..1bdc8fbe2e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/actions/HttpTraceImportOperationTest.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2017 Ericsson + * + * 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 + * + * Contributors: + * Simon Delisle - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.tmf.ui.tests.actions; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.tracecompass.tmf.ui.actions.HttpTraceImportOperation; +import org.eclipse.tracecompass.tmf.ui.project.model.ITmfProjectModelElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test the {@link HttpTraceImportOperation} class + * + * @author Simon Delisle + */ +public class HttpTraceImportOperationTest { + + private static TmfTraceFolder fDestFolder; + private static String fTestTrace1Url = "http://archive.eclipse.org/tracecompass/test-traces/tmf/syslog"; + private static String fTestTrace2Url = "http://archive.eclipse.org/tracecompass/test-traces/tmf/syslog_collapse"; + private static String fTraceArchiveUrl = "http://archive.eclipse.org/tracecompass/test-traces/tmf/syslogs.zip"; + private static List fImportedTraceNameList; + + /** + * Setup class + * + * @throws Exception + * if an exception occurs + */ + @BeforeClass + public static void beforeClass() throws Exception { + // Create the destination folder/project + IProject project = TmfProjectRegistry.createProject("Test Project", null, null); + final TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true); + TmfTraceFolder tracesFolder = checkNotNull(projectElement.getTracesFolder()); + tracesFolder.getResource().getFolder("Folder").create(false, true, null); + fDestFolder = (TmfTraceFolder) tracesFolder.getChildren().stream() + .filter(element -> element.getName().equals("Folder")).findFirst().get(); + + fImportedTraceNameList = new ArrayList<>(); + fImportedTraceNameList.add("syslog"); + fImportedTraceNameList.add("syslog_collapse"); + } + + /** + * Cleanup class + * + * @throws CoreException + * if an exception occurs + */ + @AfterClass + public static void afterClass() throws CoreException { + if (fDestFolder != null) { + fDestFolder.getProject().getResource().delete(true, null); + } + } + + /** + * Test the download and import operation for a trace file + * + * @throws Exception + * if an exception occurs + */ + @Test + public void testTraceImport() throws Exception { + WorkspaceModifyOperation operation = new HttpTraceImportOperation(fTestTrace1Url, fDestFolder); + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + assumeTrue(false); + } + validateImport(Collections.singletonList("syslog")); + } + + /** + * Test the download and import operation for multiple traces + * + * @throws Exception + * if an exception occurs + */ + @Test + public void testMultipleTracesImport() throws Exception { + List tracesUrl = new ArrayList<>(); + tracesUrl.add(fTestTrace1Url); + tracesUrl.add(fTestTrace2Url); + WorkspaceModifyOperation operation = new HttpTraceImportOperation(tracesUrl, fDestFolder); + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + assumeTrue(false); + } + validateImport(fImportedTraceNameList); + } + + /** + * Test the download and import operation for an archive + * + * @throws Exception + * if an exception occurs + */ + @Test + public void testArchiveImport() throws Exception { + WorkspaceModifyOperation operation = new HttpTraceImportOperation(fTraceArchiveUrl, fDestFolder); + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + assumeTrue(false); + } + validateImport(fImportedTraceNameList); + } + + private static void validateImport(List expectedImportFiles) { + List destFolderChildren = fDestFolder.getChildren(); + assertEquals(expectedImportFiles.size(), destFolderChildren.size()); + for (ITmfProjectModelElement element : destFolderChildren) { + assertTrue(expectedImportFiles.contains(element.getName())); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF index 3fd77f549e..ada06ae016 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF +++ b/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF @@ -28,7 +28,9 @@ Require-Bundle: org.eclipse.core.expressions, org.apache.commons.compress, org.apache.commons.lang3, org.eclipse.wst.xml.ui, - org.eclipse.wst.xsd.core + org.eclipse.wst.xsd.core, + org.apache.commons.io, + com.google.guava Export-Package: org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse.tracecompass.tmf.ui.tests,org.eclipse.tracecompass.tmf.ctf.ui.tests", org.eclipse.tracecompass.internal.tmf.ui.commands;x-internal:=true, org.eclipse.tracecompass.internal.tmf.ui.dialogs;x-internal:=true, @@ -49,7 +51,8 @@ Export-Package: org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse org.eclipse.tracecompass.tmf.ui, org.eclipse.tracecompass.lttng2.control.ui, org.eclipse.tracecompass.tmf.remote.ui, - org.eclipse.tracecompass.tmf.ui.swtbot.tests", + org.eclipse.tracecompass.tmf.ui.swtbot.tests, + org.eclipse.tracecompass.tmf.ui.tests", org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg;x-friends:="org.eclipse.tracecompass.tmf.remote.ui,org.eclipse.tracecompass.tmf.remote.ui.tests,org.eclipse.tracecompass.lttng2.control.ui", org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport;x-friends:="org.eclipse.tracecompass.tmf.remote.ui", org.eclipse.tracecompass.internal.tmf.ui.symbols;x-internal:=true, diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/DownloadTraceHttpHelper.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/DownloadTraceHttpHelper.java new file mode 100644 index 0000000000..3b27d8c9d7 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/DownloadTraceHttpHelper.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2017 Ericsson 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Simon Delisle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.util.Collection; +import org.apache.commons.io.FileUtils; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +import com.google.common.net.MediaType; + +/** + * Helper to download traces from HTTP/HTTPS. + * + * @author Simon Delisle + * + */ +public class DownloadTraceHttpHelper { + private static final String CONTENT_DISPOSITION = "Content-Disposition"; //$NON-NLS-1$ + + /** + * Download trace from a HTTP/HTTPS source. + * + * @param traceUrl + * Trace url you want to download + * @param destinationDir + * Directory where the trace will be saved + * @return The downloaded trace or null if something went wrong + */ + public static TraceDownloadStatus downloadTrace(String traceUrl, String destinationDir) { + File destFile = null; + + try { + URL url = new URL(traceUrl); + HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection(); + httpConnection.setConnectTimeout(120000); // 2 minutes timeout + int responseCode = httpConnection.getResponseCode(); + + if (responseCode != HttpURLConnection.HTTP_OK) { + httpConnection.disconnect(); + return new TraceDownloadStatus(TraceDownloadStatus.ERROR, destFile, null); + } + + String fileName = getFileName(httpConnection); + destFile = new File(destinationDir, fileName); + + try { + FileUtils.copyURLToFile(url, destFile); + } catch (IOException e) { + Activator.getDefault().logError("Unable to download from " + url.toString() + " to " + destFile.toString()); //$NON-NLS-1$ //$NON-NLS-2$ + cleanDirectory(new File(destinationDir)); + return new TraceDownloadStatus(TraceDownloadStatus.ERROR, destFile, e); + } finally { + httpConnection.disconnect(); + } + } catch (SocketTimeoutException e) { + return new TraceDownloadStatus(TraceDownloadStatus.TIMEOUT, null, e); + } catch (IOException e) { + return new TraceDownloadStatus(TraceDownloadStatus.ERROR, null, e); + } + + return new TraceDownloadStatus(TraceDownloadStatus.OK, destFile, null); + } + + /** + * Download multiple traces from a list of HTTP/HTTPS sources. + * + * @param tracesUrl + * Collection of trace url + * @param destinationDir + * Directory where the traces will be saved + * @return List that contains downloaded traces or null if something went + * wrong + */ + public static TraceDownloadStatus downloadTraces(Collection tracesUrl, String destinationDir) { + TraceDownloadStatus status = new TraceDownloadStatus(TraceDownloadStatus.OK, null, null); + for (String traceUrl : tracesUrl) { + TraceDownloadStatus singleFileStatus = downloadTrace(traceUrl, destinationDir); + status.add(singleFileStatus); + } + return status; + } + + /** + * Try to find the name of the file by using connection information. + * + * @param connection + * HTTP connection + * @return File name + */ + private static String getFileName(HttpURLConnection connection) { + String fileName = getLastSegmentUrl(connection.getURL().toString()); + String contentType = connection.getContentType(); + + if (contentType != null) { + MediaType type = MediaType.parse(contentType); + if (type.is(MediaType.ANY_APPLICATION_TYPE)) { + String contentDisposition = connection.getHeaderField(CONTENT_DISPOSITION); + if (contentDisposition != null) { + String[] content = contentDisposition.split(";"); //$NON-NLS-1$ + for (String string : content) { + if (string.contains("filename=")) { //$NON-NLS-1$ + int index = string.indexOf('"'); + fileName = string.substring(index + 1, string.length() - 1); + } + } + } + } + } + + return fileName; + } + + /** + * Get the last part of a specific url (after the last '/'). + * + * @param url + * The url + * @return The last segment of the url + */ + private static String getLastSegmentUrl(String url) { + int indexFile = url.lastIndexOf('/'); + return url.substring(indexFile + 1, url.length()); + } + + /** + * Clean the destination directory in case something went wrong during the + * download. + * + * @param dir + * Directory to delete + */ + private static void cleanDirectory(File dir) { + try { + FileUtils.deleteDirectory(dir); + } catch (IOException e) { + Activator.getDefault().logError("Unable to delete: " + dir.toString(), e); //$NON-NLS-1$ + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceDownloadStatus.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceDownloadStatus.java new file mode 100644 index 0000000000..4b4ee62dfd --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceDownloadStatus.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2017 Ericsson 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Simon Delisle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Status of a trace download operation. Can contain multiple status to track + * mutliple download in the same operation. + * + * @author Simon Delisle + * + */ +public class TraceDownloadStatus { + + /** + * Status type severity indicating this status represents the normal case. + */ + public static final int OK = 0; + + /** + * Status type severity indicating this status represents a http/https + * connection timeout. + */ + public static final int TIMEOUT = 0x01; + + /** + * Status type severity indicating this status represents an error. + */ + public static final int ERROR = 0x02; + + private File fDownloadedFile; + private Throwable fException; + private int fSeverity; + private List fMultipleStatus; + + /** + * Constructor. + * + * @param severity + * Status severity + * @param file + * Downloaded file + * @param exception + * The exception that describe the problem + */ + public TraceDownloadStatus(int severity, File file, Throwable exception) { + fSeverity = severity; + fDownloadedFile = file; + fException = exception; + fMultipleStatus = new ArrayList<>(); + } + + /** + * Get the downloaded file if the operation was successful. Can be null if + * something went wrong during the download. + * + * @return The downloaded file + */ + public File getDownloadedFile() { + return fDownloadedFile; + } + + /** + * Get the wrapped exception. + * + * @return The exception that describe the problem + */ + public Throwable getException() { + return fException; + } + + /** + * Get the status severity (OK, TIMEOUT or ERROR). + * + * @return The status severity + */ + public int getSeverity() { + return fSeverity; + } + + /** + * Set the downloaded file. + * + * @param downloadedFile + * File to wrap in this status + */ + public void setDownloadedFile(File downloadedFile) { + fDownloadedFile = downloadedFile; + } + + /** + * Set the exception for this status. + * + * @param exception + * Exception to wrap in this status + */ + public void setException(Throwable exception) { + fException = exception; + } + + /** + * Set the status severity (OK, TIMEOUT or ERROR). + * + * @param severity + * The status severity + */ + public void setSeverity(int severity) { + fSeverity = severity; + } + + /** + * Check if the status as a severity of OK + * + * @return True if the status is OK + */ + public boolean isOk() { + return fSeverity == OK; + } + + /** + * Check if the status as a severity of TIMEOUT + * + * @return True if the status is a TIMEOUT + */ + public boolean isTimeout() { + return fSeverity == TIMEOUT; + } + + /** + * Get a list of children status in case it's a multiple status or an empty + * list if it's not the case. + * + * @return All the children status of this status + */ + public List getChildren() { + return fMultipleStatus; + } + + /** + * Add a status to this status and update the severity using the given + * status severity + * + * @param status + * Status to add + */ + public void add(TraceDownloadStatus status) { + fMultipleStatus.add(status); + if (status.getSeverity() == TIMEOUT) { + fSeverity = TIMEOUT; + fException = status.getException(); + } else if (fSeverity == OK && !status.isOk()) { + fSeverity = status.getSeverity(); + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/actions/HttpTraceImportOperation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/actions/HttpTraceImportOperation.java new file mode 100644 index 0000000000..e703f600f1 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/actions/HttpTraceImportOperation.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2017 Ericsson 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Simon Delisle - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.tmf.ui.actions; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ArchiveUtil; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.DownloadTraceHttpHelper; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.FileSystemObjectImportStructureProvider; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.IFileSystemObject; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportTraceWizardPage; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceDownloadStatus; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceFileSystemElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.TraceValidateAndImportOperation; +import org.eclipse.tracecompass.tmf.core.util.Pair; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider; + +/** + * An operation which downloads and imports traces from a http/https source. + * + * @author Simon Delisle + * @since 2.4 + * + */ +public class HttpTraceImportOperation extends WorkspaceModifyOperation { + + private static final String TRACE_HTTP_IMPORT_TEMP_FOLDER = ".traceHttpImport"; //$NON-NLS-1$ + + private final Collection fSourceUrl; + private final TmfTraceFolder fDestinationFolder; + + /** + * Constructor + * + * @param sourceUrl + * HTTP url for the trace you want to import + * @param destFolder + * The destination folder + */ + public HttpTraceImportOperation(String sourceUrl, TmfTraceFolder destFolder) { + fSourceUrl = Collections.singletonList(sourceUrl); + fDestinationFolder = destFolder; + } + + /** + * Constructor + * + * @param sourceUrl + * List of HTTP url for the traces you want to import + * @param destFolder + * The destination folder + */ + public HttpTraceImportOperation(Collection sourceUrl, TmfTraceFolder destFolder) { + fSourceUrl = sourceUrl; + fDestinationFolder = destFolder; + } + + @Override + protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { + int importOptionFlags = ImportTraceWizardPage.OPTION_IMPORT_UNRECOGNIZED_TRACES | ImportTraceWizardPage.OPTION_OVERWRITE_EXISTING_RESOURCES | + ImportTraceWizardPage.OPTION_PRESERVE_FOLDER_STRUCTURE; + + // Temporary directory to contain any downloaded files + IFolder tempDestination = fDestinationFolder.getProject().getResource().getFolder(TRACE_HTTP_IMPORT_TEMP_FOLDER); + String tempDestinationFolderPath = tempDestination.getLocation().toOSString(); + if (tempDestination.exists()) { + tempDestination.delete(true, monitor); + } + tempDestination.create(IResource.HIDDEN, true, monitor); + + // Download trace/traces + List downloadedTraceList = new ArrayList<>(); + TraceDownloadStatus status = DownloadTraceHttpHelper.downloadTraces(fSourceUrl, tempDestinationFolderPath); + if (status.isOk()) { + List children = status.getChildren(); + for (TraceDownloadStatus traceDownloadStatus : children) { + downloadedTraceList.add(traceDownloadStatus.getDownloadedFile()); + } + } else if (status.isTimeout()) { + if (tempDestination.exists()) { + tempDestination.delete(true, monitor); + } + throw new InterruptedException(); + } + + boolean isArchive = false; + if (!downloadedTraceList.isEmpty()) { + isArchive = ArchiveUtil.isArchiveFile(downloadedTraceList.get(0)); + } + + FileSystemObjectImportStructureProvider provider = null; + IFileSystemObject object = null; + + if (isArchive) { + // If it's an archive there is only 1 element in this list + Pair rootObjectAndProvider = ArchiveUtil.getRootObjectAndProvider(downloadedTraceList.get(0), null); + provider = rootObjectAndProvider.getSecond(); + object = rootObjectAndProvider.getFirst(); + } else { + provider = new FileSystemObjectImportStructureProvider(FileSystemStructureProvider.INSTANCE, null); + object = provider.getIFileSystemObject(new File(tempDestinationFolderPath)); + } + + TraceFileSystemElement root = TraceFileSystemElement.createRootTraceFileElement(object, provider); + + List fileSystemElements = new ArrayList<>(); + root.getAllChildren(fileSystemElements); + + IPath sourceContainerPath = new Path(tempDestinationFolderPath); + IPath destinationContainerPath = fDestinationFolder.getPath(); + + TraceValidateAndImportOperation validateAndImportOperation = new TraceValidateAndImportOperation(null, fileSystemElements, null, sourceContainerPath, destinationContainerPath, isArchive, importOptionFlags, fDestinationFolder); + validateAndImportOperation.run(monitor); + + // Clean the temporary directory + if (tempDestination.exists()) { + tempDestination.delete(true, monitor); + } + } + +} -- 2.34.1