Commit | Line | Data |
---|---|---|
291cbdbf | 1 | /********************************************************************** |
60ae41e1 | 2 | * Copyright (c) 2012, 2014 Ericsson |
cfdb727a | 3 | * |
291cbdbf BH |
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 | |
cfdb727a AM |
8 | * |
9 | * Contributors: | |
291cbdbf | 10 | * Bernd Hufmann - Initial API and implementation |
ba3a9bd2 | 11 | * Bernd Hufmann - Updated for support of streamed traces |
89730b51 | 12 | * Patrick Tasse - Add support for source location |
b732adaa | 13 | * Markus Schorn - Bug 448058: Use org.eclipse.remote in favor of RSE |
291cbdbf | 14 | **********************************************************************/ |
9bc60be7 | 15 | package org.eclipse.tracecompass.internal.lttng2.control.ui.views.handlers; |
291cbdbf | 16 | |
b732adaa MS |
17 | import java.io.FileOutputStream; |
18 | import java.io.IOException; | |
19 | import java.io.InputStream; | |
20 | import java.io.OutputStream; | |
89730b51 | 21 | import java.net.URI; |
291cbdbf BH |
22 | import java.util.Iterator; |
23 | import java.util.List; | |
24 | ||
25 | import org.eclipse.core.commands.ExecutionEvent; | |
26 | import org.eclipse.core.commands.ExecutionException; | |
b732adaa MS |
27 | import org.eclipse.core.filesystem.EFS; |
28 | import org.eclipse.core.filesystem.IFileInfo; | |
29 | import org.eclipse.core.filesystem.IFileStore; | |
291cbdbf BH |
30 | import org.eclipse.core.resources.IFolder; |
31 | import org.eclipse.core.resources.IProject; | |
a6e37e4c | 32 | import org.eclipse.core.resources.IResource; |
6fd3c6e9 | 33 | import org.eclipse.core.resources.ResourcesPlugin; |
291cbdbf | 34 | import org.eclipse.core.runtime.CoreException; |
89730b51 | 35 | import org.eclipse.core.runtime.IPath; |
291cbdbf BH |
36 | import org.eclipse.core.runtime.IProgressMonitor; |
37 | import org.eclipse.core.runtime.IStatus; | |
cd9821de | 38 | import org.eclipse.core.runtime.MultiStatus; |
291cbdbf | 39 | import org.eclipse.core.runtime.NullProgressMonitor; |
6fd3c6e9 | 40 | import org.eclipse.core.runtime.Path; |
291cbdbf | 41 | import org.eclipse.core.runtime.Status; |
374565c6 | 42 | import org.eclipse.core.runtime.SubMonitor; |
89730b51 | 43 | import org.eclipse.core.runtime.URIUtil; |
291cbdbf | 44 | import org.eclipse.core.runtime.jobs.Job; |
81d5dc3a MAL |
45 | import org.eclipse.jface.dialogs.MessageDialogWithToggle; |
46 | import org.eclipse.jface.preference.IPreferenceStore; | |
291cbdbf BH |
47 | import org.eclipse.jface.viewers.ISelection; |
48 | import org.eclipse.jface.viewers.StructuredSelection; | |
49 | import org.eclipse.jface.window.Window; | |
cd9821de | 50 | import org.eclipse.jface.wizard.WizardDialog; |
6fd3c6e9 | 51 | import org.eclipse.swt.widgets.Display; |
9bc60be7 AM |
52 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceSessionState; |
53 | import org.eclipse.tracecompass.internal.lttng2.control.ui.Activator; | |
54 | import org.eclipse.tracecompass.internal.lttng2.control.ui.relayd.LttngRelaydConnectionInfo; | |
55 | import org.eclipse.tracecompass.internal.lttng2.control.ui.relayd.LttngRelaydConnectionManager; | |
56 | import org.eclipse.tracecompass.internal.lttng2.control.ui.relayd.LttngRelaydConsumer; | |
57 | import org.eclipse.tracecompass.internal.lttng2.control.ui.views.ControlView; | |
58 | import org.eclipse.tracecompass.internal.lttng2.control.ui.views.dialogs.IImportDialog; | |
59 | import org.eclipse.tracecompass.internal.lttng2.control.ui.views.dialogs.ImportFileInfo; | |
60 | import org.eclipse.tracecompass.internal.lttng2.control.ui.views.dialogs.TraceControlDialogFactory; | |
61 | import org.eclipse.tracecompass.internal.lttng2.control.ui.views.messages.Messages; | |
62 | import org.eclipse.tracecompass.internal.lttng2.control.ui.views.model.impl.TraceSessionComponent; | |
2bdf0193 AM |
63 | import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportTraceWizard; |
64 | import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; | |
65 | import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException; | |
66 | import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; | |
67 | import org.eclipse.tracecompass.tmf.ctf.core.CtfConstants; | |
68 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper; | |
69 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; | |
70 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; | |
71 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; | |
72 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; | |
73 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils; | |
74 | import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder; | |
75 | import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; | |
291cbdbf BH |
76 | import org.eclipse.ui.IWorkbenchPage; |
77 | import org.eclipse.ui.IWorkbenchWindow; | |
78 | import org.eclipse.ui.PlatformUI; | |
79 | ||
80 | /** | |
291cbdbf | 81 | * <p> |
6fd3c6e9 MAL |
82 | * Command handler implementation to import traces from a (remote) session to a |
83 | * tracing project. | |
291cbdbf | 84 | * </p> |
cfdb727a | 85 | * |
dbd4432d | 86 | * @author Bernd Hufmann |
291cbdbf BH |
87 | */ |
88 | public class ImportHandler extends BaseControlViewHandler { | |
89 | ||
65e28a02 MK |
90 | private static final int BUFFER_IN_KB = 16; |
91 | ||
92 | private static final int BYTES_PER_KB = 1024; | |
93 | ||
cd9821de BH |
94 | // ------------------------------------------------------------------------ |
95 | // Constants | |
96 | // ------------------------------------------------------------------------ | |
cd9821de BH |
97 | /** Name of default project to import traces to */ |
98 | public static final String DEFAULT_REMOTE_PROJECT_NAME = "Remote"; //$NON-NLS-1$ | |
99 | ||
81d5dc3a MAL |
100 | /** The preference key to remeber whether or not the user wants the notification shown next time **/ |
101 | private static final String NOTIFY_IMPORT_STREAMED_PREF_KEY = "NOTIFY_IMPORT_STREAMED"; //$NON-NLS-1$ | |
102 | ||
291cbdbf BH |
103 | // ------------------------------------------------------------------------ |
104 | // Attributes | |
105 | // ------------------------------------------------------------------------ | |
6f4e8ec0 AM |
106 | |
107 | /** | |
108 | * The command parameter | |
109 | */ | |
291cbdbf | 110 | protected CommandParameter fParam; |
cfdb727a | 111 | |
291cbdbf BH |
112 | // ------------------------------------------------------------------------ |
113 | // Operations | |
114 | // ------------------------------------------------------------------------ | |
cfdb727a | 115 | |
291cbdbf BH |
116 | @Override |
117 | public Object execute(ExecutionEvent event) throws ExecutionException { | |
118 | ||
119 | IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); | |
120 | ||
121 | if (window == null) { | |
122 | return false; | |
123 | } | |
124 | ||
125 | fLock.lock(); | |
126 | try { | |
127 | final CommandParameter param = fParam.clone(); | |
cfdb727a | 128 | |
cd9821de BH |
129 | // create default project |
130 | IProject project = TmfProjectRegistry.createProject(DEFAULT_REMOTE_PROJECT_NAME, null, null); | |
cd9821de | 131 | |
6fd3c6e9 MAL |
132 | if (param.getSession().isLiveTrace()) { |
133 | importLiveTrace(new LttngRelaydConnectionInfo(param.getSession().getLiveUrl(), param.getSession().getLivePort(), param.getSession().getName()), project); | |
134 | return null; | |
135 | } else if (param.getSession().isStreamedTrace()) { | |
81d5dc3a MAL |
136 | |
137 | IPreferenceStore store = Activator.getDefault().getPreferenceStore(); | |
138 | String notify = store.getString(NOTIFY_IMPORT_STREAMED_PREF_KEY); | |
139 | if (!MessageDialogWithToggle.ALWAYS.equals(notify)) { | |
140 | MessageDialogWithToggle.openInformation(window.getShell(), null, Messages.TraceControl_ImportDialogStreamedTraceNotification, Messages.TraceControl_ImportDialogStreamedTraceNotificationToggle, false, store, NOTIFY_IMPORT_STREAMED_PREF_KEY); | |
141 | } | |
142 | ||
cd9821de | 143 | // Streamed trace |
f537c959 | 144 | TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true); |
cd9821de BH |
145 | TmfTraceFolder traceFolder = projectElement.getTracesFolder(); |
146 | ||
10a4498a | 147 | ImportTraceWizard wizard = new ImportTraceWizard(); |
cd9821de BH |
148 | wizard.init(PlatformUI.getWorkbench(), new StructuredSelection(traceFolder)); |
149 | WizardDialog dialog = new WizardDialog(window.getShell(), wizard); | |
150 | dialog.open(); | |
cd9821de BH |
151 | return null; |
152 | } | |
153 | ||
154 | // Remote trace | |
291cbdbf BH |
155 | final IImportDialog dialog = TraceControlDialogFactory.getInstance().getImportDialog(); |
156 | dialog.setSession(param.getSession()); | |
cd9821de | 157 | dialog.setDefaultProject(DEFAULT_REMOTE_PROJECT_NAME); |
291cbdbf | 158 | |
cd9821de | 159 | if (dialog.open() != Window.OK) { |
291cbdbf BH |
160 | return null; |
161 | } | |
162 | ||
163 | Job job = new Job(Messages.TraceControl_ImportJob) { | |
164 | @Override | |
165 | protected IStatus run(IProgressMonitor monitor) { | |
cfdb727a | 166 | |
cd9821de BH |
167 | MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, Messages.TraceControl_ImportFailure, null); |
168 | List<ImportFileInfo> traces = dialog.getTracePathes(); | |
169 | IProject selectedProject = dialog.getProject(); | |
170 | for (Iterator<ImportFileInfo> iterator = traces.iterator(); iterator.hasNext();) { | |
171 | try { | |
374565c6 | 172 | |
f537c959 | 173 | if (monitor.isCanceled()) { |
374565c6 BH |
174 | status.add(Status.CANCEL_STATUS); |
175 | break; | |
176 | } | |
177 | ||
67c7236e BH |
178 | ImportFileInfo remoteFile = iterator.next(); |
179 | ||
180 | downloadTrace(remoteFile, selectedProject, monitor); | |
181 | ||
182 | // Set trace type | |
183 | IFolder traceFolder = remoteFile.getDestinationFolder(); | |
184 | ||
a6e37e4c | 185 | IResource file = traceFolder.findMember(remoteFile.getLocalTraceName()); |
cd9821de | 186 | |
67c7236e BH |
187 | if (file != null) { |
188 | TraceTypeHelper helper = null; | |
cd9821de | 189 | |
80c7ca57 | 190 | try { |
4b677ea9 | 191 | helper = TmfTraceTypeUIUtils.selectTraceType(file.getLocation().toOSString(), null, null); |
80c7ca57 BH |
192 | } catch (TmfTraceImportException e) { |
193 | // the trace did not match any trace type | |
67c7236e | 194 | } |
cd9821de | 195 | |
67c7236e BH |
196 | if (helper != null) { |
197 | status.add(TmfTraceTypeUIUtils.setTraceType(file, helper)); | |
198 | } | |
89730b51 | 199 | |
b732adaa MS |
200 | URI uri = remoteFile.getImportFile().toURI(); |
201 | String sourceLocation = URIUtil.toUnencodedString(uri); | |
202 | file.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); | |
89730b51 | 203 | } |
cd9821de BH |
204 | } catch (ExecutionException e) { |
205 | status.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.TraceControl_ImportFailure, e)); | |
206 | } catch (CoreException e) { | |
207 | status.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.TraceControl_ImportFailure, e)); | |
208 | } | |
cfdb727a | 209 | } |
cd9821de | 210 | return status; |
291cbdbf BH |
211 | } |
212 | }; | |
213 | job.setUser(true); | |
214 | job.schedule(); | |
215 | } finally { | |
216 | fLock.unlock(); | |
217 | } | |
218 | return null; | |
219 | } | |
220 | ||
291cbdbf BH |
221 | @Override |
222 | public boolean isEnabled() { | |
223 | // Get workbench page for the Control View | |
224 | IWorkbenchPage page = getWorkbenchPage(); | |
225 | if (page == null) { | |
226 | return false; | |
227 | } | |
228 | ||
229 | // Check if one or more session are selected | |
230 | ISelection selection = page.getSelection(ControlView.ID); | |
231 | TraceSessionComponent session = null; | |
232 | if (selection instanceof StructuredSelection) { | |
233 | StructuredSelection structered = ((StructuredSelection) selection); | |
234 | for (Iterator<?> iterator = structered.iterator(); iterator.hasNext();) { | |
cfdb727a | 235 | Object element = iterator.next(); |
291cbdbf | 236 | if (element instanceof TraceSessionComponent) { |
6fd3c6e9 MAL |
237 | // Add only TraceSessionComponents that are inactive and not |
238 | // destroyed | |
291cbdbf | 239 | TraceSessionComponent tmpSession = (TraceSessionComponent) element; |
6fd3c6e9 | 240 | if ((tmpSession.isSnapshotSession() || tmpSession.isLiveTrace() || (tmpSession.getSessionState() == TraceSessionState.INACTIVE)) && (!tmpSession.isDestroyed())) { |
291cbdbf BH |
241 | session = tmpSession; |
242 | } | |
243 | } | |
244 | } | |
245 | } | |
246 | boolean isEnabled = session != null; | |
247 | ||
248 | fLock.lock(); | |
249 | try { | |
250 | fParam = null; | |
251 | if (isEnabled) { | |
252 | fParam = new CommandParameter(session); | |
253 | } | |
254 | } finally { | |
255 | fLock.unlock(); | |
256 | } | |
257 | return isEnabled; | |
258 | } | |
cfdb727a | 259 | |
291cbdbf BH |
260 | // ------------------------------------------------------------------------ |
261 | // Helper methods | |
262 | // ------------------------------------------------------------------------ | |
11252342 | 263 | |
291cbdbf BH |
264 | /** |
265 | * Downloads a trace from the remote host to the given project. | |
cfdb727a AM |
266 | * |
267 | * @param trace | |
268 | * - trace information of trace to import | |
269 | * @param project | |
270 | * - project to import to | |
374565c6 BH |
271 | * @param monitor |
272 | * - a progress monitor | |
291cbdbf BH |
273 | * @throws ExecutionException |
274 | */ | |
374565c6 | 275 | private static void downloadTrace(ImportFileInfo trace, IProject project, IProgressMonitor monitor) |
0a78d11a | 276 | throws ExecutionException { |
291cbdbf | 277 | try { |
b732adaa | 278 | IFileStore importRoot = trace.getImportFile(); |
cfdb727a | 279 | |
339d539c | 280 | IFolder traceFolder = project.getFolder(TmfTracesFolder.TRACES_FOLDER_NAME); |
291cbdbf | 281 | if (!traceFolder.exists()) { |
6fd3c6e9 | 282 | throw new ExecutionException(Messages.TraceControl_ImportDialogInvalidTracingProject + " (" + TmfTracesFolder.TRACES_FOLDER_NAME + ")"); //$NON-NLS-1$//$NON-NLS-2$ |
291cbdbf BH |
283 | } |
284 | ||
67c7236e BH |
285 | IFolder destinationFolder = trace.getDestinationFolder(); |
286 | TraceUtils.createFolder(destinationFolder, monitor); | |
287 | ||
291cbdbf | 288 | String traceName = trace.getLocalTraceName(); |
67c7236e | 289 | IFolder folder = destinationFolder.getFolder(traceName); |
291cbdbf | 290 | if (folder.exists()) { |
6fd3c6e9 | 291 | if (!trace.isOverwrite()) { |
291cbdbf BH |
292 | throw new ExecutionException(Messages.TraceControl_ImportDialogTraceAlreadyExistError + ": " + traceName); //$NON-NLS-1$ |
293 | } | |
294 | } else { | |
295 | folder.create(true, true, null); | |
296 | } | |
297 | ||
b732adaa | 298 | IFileStore[] sources = importRoot.childStores(EFS.NONE, new NullProgressMonitor()); |
374565c6 BH |
299 | SubMonitor subMonitor = SubMonitor.convert(monitor, sources.length); |
300 | subMonitor.beginTask(Messages.TraceControl_DownloadTask, sources.length); | |
291cbdbf | 301 | |
b732adaa | 302 | for (IFileStore source : sources) { |
374565c6 BH |
303 | if (subMonitor.isCanceled()) { |
304 | monitor.setCanceled(true); | |
305 | return; | |
306 | } | |
b732adaa MS |
307 | SubMonitor childMonitor = subMonitor.newChild(1); |
308 | IFileInfo info = source.fetchInfo(); | |
309 | if (!info.isDirectory()) { | |
310 | IPath destination = folder.getLocation().addTrailingSeparator().append(source.getName()); | |
311 | subMonitor.setTaskName(Messages.TraceControl_DownloadTask + ' ' + traceName + '/' + source.getName()); | |
312 | try (InputStream in = source.openInputStream(EFS.NONE, new NullProgressMonitor())) { | |
313 | copy(in, destination, childMonitor, info.getLength()); | |
314 | } | |
315 | } | |
291cbdbf | 316 | } |
b732adaa | 317 | } catch (IOException e) { |
9fa32496 | 318 | throw new ExecutionException(e.toString(), e); |
291cbdbf | 319 | } catch (CoreException e) { |
9fa32496 | 320 | throw new ExecutionException(e.toString(), e); |
291cbdbf BH |
321 | } |
322 | } | |
6fd3c6e9 | 323 | |
b732adaa MS |
324 | private static void copy(InputStream in, IPath destination, SubMonitor monitor, long length) throws IOException { |
325 | try (OutputStream out = new FileOutputStream(destination.toFile())) { | |
65e28a02 MK |
326 | monitor.setWorkRemaining((int) (length / BYTES_PER_KB)); |
327 | byte[] buf = new byte[BYTES_PER_KB * BUFFER_IN_KB]; | |
b732adaa MS |
328 | int counter = 0; |
329 | for (;;) { | |
330 | int n = in.read(buf); | |
331 | if (n <= 0) { | |
332 | return; | |
333 | } | |
334 | out.write(buf, 0, n); | |
65e28a02 MK |
335 | counter = (counter % BYTES_PER_KB) + n; |
336 | monitor.worked(counter / BYTES_PER_KB); | |
b732adaa MS |
337 | } |
338 | } | |
339 | } | |
340 | ||
6fd3c6e9 MAL |
341 | private static void importLiveTrace(final LttngRelaydConnectionInfo connectionInfo, final IProject project) { |
342 | Job job = new Job(Messages.TraceControl_ImportJob) { | |
343 | ||
344 | @Override | |
345 | protected IStatus run(final IProgressMonitor monitor) { | |
346 | try { | |
347 | // We initiate the connection first so that we can retrieve the trace path | |
348 | LttngRelaydConsumer lttngRelaydConsumer = LttngRelaydConnectionManager.getInstance().getConsumer(connectionInfo); | |
349 | try { | |
350 | lttngRelaydConsumer.connect(); | |
351 | } catch (CoreException e) { | |
92fe6900 | 352 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.lttng2.control.ui.relayd.Messages.LttngRelaydConnectionManager_ConnectionError, e); |
6fd3c6e9 MAL |
353 | } |
354 | initializeTraceResource(connectionInfo, lttngRelaydConsumer.getTracePath(), project); | |
355 | return Status.OK_STATUS; | |
356 | } catch (CoreException | TmfTraceImportException e) { | |
357 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ImportHandler_LiveTraceInitError, e); | |
358 | } | |
359 | } | |
360 | ||
361 | }; | |
362 | job.setSystem(true); | |
363 | job.schedule(); | |
364 | } | |
365 | ||
366 | ||
367 | private static void initializeTraceResource(final LttngRelaydConnectionInfo connectionInfo, final String tracePath, final IProject project) throws CoreException, TmfTraceImportException { | |
368 | IFolder folder = project.getFolder(TmfTracesFolder.TRACES_FOLDER_NAME); | |
369 | IFolder traceFolder = folder.getFolder(connectionInfo.getSessionName()); | |
370 | Path location = new Path(tracePath); | |
371 | IStatus result = ResourcesPlugin.getWorkspace().validateLinkLocation(folder, location); | |
372 | if (result.isOK()) { | |
373 | traceFolder.createLink(location, IResource.REPLACE, new NullProgressMonitor()); | |
374 | } else { | |
375 | throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, result.getMessage())); | |
376 | } | |
377 | ||
378 | TraceTypeHelper selectedTraceType = TmfTraceTypeUIUtils.selectTraceType(location.toOSString(), null, null); | |
379 | // No trace type was determined. | |
380 | TmfTraceTypeUIUtils.setTraceType(traceFolder, selectedTraceType); | |
381 | ||
382 | final TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true); | |
383 | final TmfTraceFolder tracesFolder = projectElement.getTracesFolder(); | |
384 | final List<TmfTraceElement> traces = tracesFolder.getTraces(); | |
385 | TmfTraceElement found = null; | |
386 | for (TmfTraceElement candidate : traces) { | |
387 | if (candidate.getName().equals(connectionInfo.getSessionName())) { | |
388 | found = candidate; | |
389 | } | |
390 | } | |
391 | ||
392 | if (found == null) { | |
393 | throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ImportHandler_LiveTraceElementError)); | |
394 | } | |
395 | ||
396 | // Properties used to be able to reopen a trace in live mode | |
397 | traceFolder.setPersistentProperty(CtfConstants.LIVE_HOST, connectionInfo.getHost()); | |
398 | traceFolder.setPersistentProperty(CtfConstants.LIVE_PORT, Integer.toString(connectionInfo.getPort())); | |
399 | traceFolder.setPersistentProperty(CtfConstants.LIVE_SESSION_NAME, connectionInfo.getSessionName()); | |
400 | ||
401 | final TmfTraceElement finalTrace = found; | |
402 | Display.getDefault().syncExec(new Runnable() { | |
403 | ||
404 | @Override | |
405 | public void run() { | |
406 | TmfOpenTraceHelper.openTraceFromElement(finalTrace); | |
407 | } | |
408 | }); | |
409 | } | |
291cbdbf | 410 | } |