1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Bernd Hufmann - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.tmf
.remote
.ui
.wizards
.fetch
.model
;
15 import java
.io
.FileOutputStream
;
16 import java
.io
.IOException
;
17 import java
.io
.InputStream
;
18 import java
.io
.OutputStream
;
19 import java
.lang
.reflect
.InvocationTargetException
;
21 import java
.util
.Arrays
;
23 import org
.eclipse
.core
.commands
.ExecutionException
;
24 import org
.eclipse
.core
.filesystem
.EFS
;
25 import org
.eclipse
.core
.filesystem
.IFileInfo
;
26 import org
.eclipse
.core
.filesystem
.IFileStore
;
27 import org
.eclipse
.core
.resources
.IFolder
;
28 import org
.eclipse
.core
.resources
.IResource
;
29 import org
.eclipse
.core
.runtime
.CoreException
;
30 import org
.eclipse
.core
.runtime
.IPath
;
31 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
32 import org
.eclipse
.core
.runtime
.IStatus
;
33 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
34 import org
.eclipse
.core
.runtime
.Path
;
35 import org
.eclipse
.core
.runtime
.Status
;
36 import org
.eclipse
.core
.runtime
.SubMonitor
;
37 import org
.eclipse
.core
.runtime
.URIUtil
;
38 import org
.eclipse
.jface
.operation
.ModalContext
;
39 import org
.eclipse
.osgi
.util
.NLS
;
40 import org
.eclipse
.swt
.widgets
.Shell
;
41 import org
.eclipse
.tracecompass
.internal
.tmf
.remote
.ui
.Activator
;
42 import org
.eclipse
.tracecompass
.internal
.tmf
.remote
.ui
.messages
.RemoteMessages
;
43 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.operations
.TmfWorkspaceModifyOperation
;
44 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.importtrace
.ImportConfirmation
;
45 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.importtrace
.ImportConflictHandler
;
46 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageElement
;
47 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.project
.wizards
.tracepkg
.TracePackageTraceElement
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceCoreUtils
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceImportException
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TraceTypeHelper
;
53 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceFolder
;
54 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTraceTypeUIUtils
;
55 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TmfTracesFolder
;
56 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TraceUtils
;
59 * Operation to import a set of traces from a remote node into a tracing project.
61 * @author Bernd Hufmann
63 public class RemoteImportTracesOperation
extends TmfWorkspaceModifyOperation
{
65 // ------------------------------------------------------------------------
67 // ------------------------------------------------------------------------
68 private static final int BUFFER_IN_KB
= 16;
69 private static final int BYTES_PER_KB
= 1024;
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
74 private IStatus fStatus
;
75 final private Shell fShell
;
76 final private TmfTraceFolder fDestination
;
77 final private Object
[] fTraceElements
;
78 final private ImportConflictHandler fConflictHandler
;
80 // ------------------------------------------------------------------------
82 // ------------------------------------------------------------------------
84 * Operation to import a set of traces from a remote node into a tracing project.
86 * shell to display confirmation dialog
88 * The destination traces folder
90 * The trace model elements describing the traces to import
92 * Flag to indicate to overwrite all existing traces
94 public RemoteImportTracesOperation(Shell shell
, TmfTraceFolder destination
, Object
[] elements
, boolean overwriteAll
) {
97 fDestination
= destination
;
98 fTraceElements
= Arrays
.copyOf(elements
, elements
.length
);
100 fConflictHandler
= new ImportConflictHandler(fShell
, destination
, ImportConfirmation
.OVERWRITE_ALL
);
102 fConflictHandler
= new ImportConflictHandler(fShell
, destination
, ImportConfirmation
.SKIP
);
106 // ------------------------------------------------------------------------
108 // ------------------------------------------------------------------------
110 protected void execute(IProgressMonitor monitor
) throws CoreException
,
111 InvocationTargetException
, InterruptedException
{
115 setStatus(Status
.OK_STATUS
);
116 } catch (InterruptedException e
) {
117 setStatus(Status
.CANCEL_STATUS
);
119 } catch (Exception e
) {
120 setStatus(new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, RemoteMessages
.RemoteImportTracesOperation_ImportFailure
, e
));
121 throw new InvocationTargetException(e
);
125 // ------------------------------------------------------------------------
127 // ------------------------------------------------------------------------
128 private void doRun(IProgressMonitor monitor
) throws ExecutionException
, CoreException
, IOException
, InterruptedException
{
130 IFolder destinationFolder
= fDestination
.getResource();
131 if (!destinationFolder
.exists()) {
132 throw new ExecutionException(RemoteMessages
.RemoteImportTracesOperation_ImportDialogInvalidTracingProject
+ " (" + TmfTracesFolder
.TRACES_FOLDER_NAME
+ ")"); //$NON-NLS-1$//$NON-NLS-2$
135 SubMonitor subMonitor
= SubMonitor
.convert(monitor
, fTraceElements
.length
* 4);
136 subMonitor
.beginTask(RemoteMessages
.RemoteImportTracesOperation_DownloadTask
, fTraceElements
.length
* 4);
138 for (Object packageElement
: fTraceElements
) {
139 if (!(packageElement
instanceof TracePackageTraceElement
)) {
142 TracePackageTraceElement traceElement
= (TracePackageTraceElement
) packageElement
;
143 TracePackageElement parentElement
= traceElement
.getParent();
144 while (parentElement
!= null) {
145 if (parentElement
instanceof RemoteImportTraceGroupElement
) {
148 parentElement
= parentElement
.getParent();
151 if (parentElement
== null) {
155 RemoteImportTraceGroupElement traceGroup
= (RemoteImportTraceGroupElement
) parentElement
;
156 String rootPath
= traceGroup
.getRootImportPath();
158 // Create folder with node name in destination folder
159 RemoteImportConnectionNodeElement nodeElement
= (RemoteImportConnectionNodeElement
) traceGroup
.getParent();
160 String nodeName
= nodeElement
.getName();
161 IFolder nodeFolder
= destinationFolder
.getFolder(nodeName
);
163 TracePackageElement
[] children
= traceElement
.getChildren();
164 SubMonitor childMonitor
= subMonitor
.newChild(1);
165 TraceUtils
.createFolder(nodeFolder
, childMonitor
);
167 for (TracePackageElement element
: children
) {
168 ModalContext
.checkCanceled(monitor
);
170 if (element
instanceof RemoteImportTraceFilesElement
) {
171 RemoteImportTraceFilesElement traceFilesElement
= (RemoteImportTraceFilesElement
) element
;
173 IFileStore remoteFile
= traceFilesElement
.getRemoteFile();
175 // Preserve folder structure
176 IPath sessionParentPath
= TmfTraceCoreUtils
.newSafePath(rootPath
);
177 IPath traceParentPath
= TmfTraceCoreUtils
.newSafePath(remoteFile
.getParent().toURI().getPath());
178 IPath relativeTracePath
= Path
.EMPTY
;
179 if (sessionParentPath
.isPrefixOf(traceParentPath
)) {
180 relativeTracePath
= traceParentPath
.makeRelativeTo(sessionParentPath
);
183 String
[] segments
= relativeTracePath
.segments();
184 for (int i
= 0; i
< segments
.length
; i
++) {
185 String segment
= TmfTraceCoreUtils
.validateName(TmfTraceCoreUtils
.safePathToString(segments
[i
]));
187 relativeTracePath
= new Path(segment
);
189 relativeTracePath
= relativeTracePath
.append(segment
);
193 IFolder traceFolder
= nodeFolder
.getFolder(new Path(relativeTracePath
.toOSString()));
194 childMonitor
= subMonitor
.newChild(1);
195 TraceUtils
.createFolder(traceFolder
, childMonitor
);
199 IResource traceRes
= null;
200 IFileInfo info
= remoteFile
.fetchInfo();
201 if (info
.isDirectory()) {
202 traceRes
= downloadDirectoryTrace(remoteFile
, traceFolder
, subMonitor
.newChild(1));
204 traceRes
= downloadFileTrace(remoteFile
, traceFolder
, subMonitor
.newChild(1));
207 String traceName
= traceElement
.getText();
208 if (traceRes
== null || !traceRes
.exists()) {
213 TraceTypeHelper traceTypeHelper
= null;
214 String traceTypeStr
= traceElement
.getTraceType();
215 if (traceTypeStr
!= null) {
216 traceTypeHelper
= TmfTraceType
.getTraceType(traceTypeStr
);
219 // no specific trace type found
220 if (traceTypeHelper
== null) {
222 // Try to auto-detect the trace typ
223 childMonitor
= subMonitor
.newChild(1);
224 childMonitor
.setTaskName(NLS
.bind(RemoteMessages
.RemoteImportTracesOperation_DetectingTraceType
, traceName
));
226 traceTypeHelper
= TmfTraceTypeUIUtils
.selectTraceType(traceRes
.getLocation().toOSString(), null, null);
227 } catch (TmfTraceImportException e
) {
228 //Could not figure out the type
232 if (traceTypeHelper
!= null) {
233 TmfTraceTypeUIUtils
.setTraceType(traceRes
, traceTypeHelper
);
236 // Set source location
237 URI uri
= remoteFile
.toURI();
238 String sourceLocation
= URIUtil
.toUnencodedString(uri
);
239 traceRes
.setPersistentProperty(TmfCommonConstants
.SOURCE_LOCATION
, sourceLocation
);
245 // Download a directory trace
246 private IResource
downloadDirectoryTrace(IFileStore trace
, IFolder traceFolder
, IProgressMonitor monitor
) throws CoreException
, IOException
, InterruptedException
{
248 IFileStore
[] sources
= trace
.childStores(EFS
.NONE
, monitor
);
250 // Don't import just the metadata file
251 if (sources
.length
> 1) {
252 String traceName
= trace
.getName();
254 traceName
= TmfTraceCoreUtils
.validateName(traceName
);
256 IFolder folder
= traceFolder
.getFolder(traceName
);
257 String newName
= fConflictHandler
.checkAndHandleNameClash(folder
.getFullPath(), monitor
);
258 if (newName
== null) {
262 folder
= traceFolder
.getFolder(newName
);
263 folder
.create(true, true, null);
265 SubMonitor subMonitor
= SubMonitor
.convert(monitor
, sources
.length
);
266 subMonitor
.beginTask(RemoteMessages
.RemoteImportTracesOperation_DownloadTask
, sources
.length
);
268 for (IFileStore source
: sources
) {
269 if (subMonitor
.isCanceled()) {
270 throw new InterruptedException();
273 IPath destination
= folder
.getLocation().addTrailingSeparator().append(source
.getName());
274 IFileInfo info
= source
.fetchInfo();
275 // TODO allow for downloading index directory and files
276 if (!info
.isDirectory()) {
277 SubMonitor childMonitor
= subMonitor
.newChild(1);
278 childMonitor
.setTaskName(RemoteMessages
.RemoteImportTracesOperation_DownloadTask
+ ' ' + trace
.getName()+ '/' + source
.getName());
280 try (InputStream in
= source
.openInputStream(EFS
.NONE
, new NullProgressMonitor())) {
281 copy(in
, destination
, childMonitor
, info
.getLength());
285 folder
.refreshLocal(IResource
.DEPTH_INFINITE
, null);
291 // Download file trace
292 private IResource
downloadFileTrace(IFileStore trace
, IFolder traceFolder
, IProgressMonitor monitor
) throws CoreException
, IOException
, InterruptedException
{
294 IFolder folder
= traceFolder
;
295 String traceName
= trace
.getName();
297 traceName
= TmfTraceCoreUtils
.validateName(traceName
);
299 IResource resource
= folder
.findMember(traceName
);
300 if ((resource
!= null) && resource
.exists()) {
301 String newName
= fConflictHandler
.checkAndHandleNameClash(resource
.getFullPath(), monitor
);
302 if (newName
== null) {
307 SubMonitor subMonitor
= SubMonitor
.convert(monitor
, 1);
308 subMonitor
.beginTask(RemoteMessages
.RemoteImportTracesOperation_DownloadTask
, 1);
310 IPath destination
= folder
.getLocation().addTrailingSeparator().append(traceName
);
311 IFileInfo info
= trace
.fetchInfo();
312 subMonitor
.setTaskName(RemoteMessages
.RemoteImportTracesOperation_DownloadTask
+ ' ' + trace
.getName()+ '/' +trace
.getName());
313 try (InputStream in
= trace
.openInputStream(EFS
.NONE
, new NullProgressMonitor())) {
314 copy(in
, destination
, subMonitor
, info
.getLength());
316 folder
.refreshLocal(IResource
.DEPTH_INFINITE
, null);
317 return folder
.findMember(traceName
);
321 private static void copy(InputStream in
, IPath destination
, SubMonitor monitor
, long length
) throws IOException
{
322 try (OutputStream out
= new FileOutputStream(destination
.toFile())) {
323 monitor
.setWorkRemaining((int) (length
/ BYTES_PER_KB
));
324 byte[] buf
= new byte[BYTES_PER_KB
* BUFFER_IN_KB
];
327 int n
= in
.read(buf
);
331 out
.write(buf
, 0, n
);
332 counter
= (counter
% BYTES_PER_KB
) + n
;
333 monitor
.worked(counter
/ BYTES_PER_KB
);
339 * Set the result status for this operation
344 protected void setStatus(IStatus status
) {
349 * Gets the result of the operation.
351 * @return result status of operation
353 public IStatus
getStatus() {