Commit | Line | Data |
---|---|---|
eb1bab5b | 1 | /********************************************************************** |
ed902a2b | 2 | * Copyright (c) 2012, 2015 Ericsson |
ea21cd65 | 3 | * |
eb1bab5b 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 | |
ea21cd65 AM |
8 | * |
9 | * Contributors: | |
eb1bab5b BH |
10 | * Patrick Tasse - Initial API and implementation |
11 | * Bernd Hufmann - Updated using Executor Framework | |
b732adaa | 12 | * Markus Schorn - Bug 448058: Use org.eclipse.remote in favor of RSE |
533d0bc3 | 13 | * Bernd Hufmann - Update to org.eclipse.remote API 2.0 |
eb1bab5b | 14 | **********************************************************************/ |
13729cbc BH |
15 | package org.eclipse.tracecompass.internal.tmf.remote.core.shell; |
16 | ||
17 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; | |
eb1bab5b | 18 | |
eb1bab5b | 19 | import java.io.IOException; |
eb1bab5b | 20 | import java.util.concurrent.Callable; |
eb1bab5b BH |
21 | import java.util.concurrent.ExecutorService; |
22 | import java.util.concurrent.Executors; | |
23 | import java.util.concurrent.FutureTask; | |
24 | import java.util.concurrent.TimeUnit; | |
25 | import java.util.concurrent.TimeoutException; | |
26 | ||
27 | import org.eclipse.core.commands.ExecutionException; | |
28 | import org.eclipse.core.runtime.IProgressMonitor; | |
13729cbc | 29 | import org.eclipse.core.runtime.NullProgressMonitor; |
b732adaa | 30 | import org.eclipse.core.runtime.OperationCanceledException; |
f4648c68 | 31 | import org.eclipse.jdt.annotation.NonNull; |
b732adaa MS |
32 | import org.eclipse.remote.core.IRemoteConnection; |
33 | import org.eclipse.remote.core.IRemoteProcess; | |
533d0bc3 | 34 | import org.eclipse.remote.core.IRemoteProcessService; |
ec619615 BH |
35 | import org.eclipse.tracecompass.internal.tmf.remote.core.messages.Messages; |
36 | import org.eclipse.tracecompass.internal.tmf.remote.core.preferences.TmfRemotePreferences; | |
364dcfaf | 37 | import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandInput; |
13729cbc BH |
38 | import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandResult; |
39 | import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandShell; | |
eb1bab5b BH |
40 | |
41 | /** | |
eb1bab5b | 42 | * <p> |
b732adaa | 43 | * Implementation of remote command execution using IRemoteConnection. |
eb1bab5b | 44 | * </p> |
cfdb727a | 45 | * |
dbd4432d BH |
46 | * @author Patrick Tasse |
47 | * @author Bernd Hufmann | |
eb1bab5b BH |
48 | */ |
49 | public class CommandShell implements ICommandShell { | |
50 | ||
eb1bab5b BH |
51 | // ------------------------------------------------------------------------ |
52 | // Attributes | |
53 | // ------------------------------------------------------------------------ | |
13729cbc BH |
54 | private final IRemoteConnection fConnection; |
55 | private final ExecutorService fExecutor = checkNotNull(Executors.newFixedThreadPool(1)); | |
ea21cd65 | 56 | |
eb1bab5b BH |
57 | // ------------------------------------------------------------------------ |
58 | // Constructors | |
59 | // ------------------------------------------------------------------------ | |
ea21cd65 AM |
60 | |
61 | /** | |
62 | * Create a new command shell | |
63 | * | |
b732adaa | 64 | * @param connection the remote connection for this shell |
ea21cd65 | 65 | */ |
b732adaa MS |
66 | public CommandShell(IRemoteConnection connection) { |
67 | fConnection = connection; | |
eb1bab5b BH |
68 | } |
69 | ||
70 | // ------------------------------------------------------------------------ | |
71 | // Operations | |
72 | // ------------------------------------------------------------------------ | |
11252342 | 73 | |
eb1bab5b | 74 | @Override |
13729cbc | 75 | public void dispose() { |
b732adaa | 76 | fExecutor.shutdown(); |
eb1bab5b BH |
77 | } |
78 | ||
eb1bab5b | 79 | @Override |
364dcfaf BH |
80 | public ICommandInput createCommand() { |
81 | return new CommandInput(); | |
82 | } | |
83 | ||
84 | @Override | |
c07150f8 | 85 | public ICommandResult executeCommand(final ICommandInput command, final IProgressMonitor aMonitor) throws ExecutionException { |
b732adaa | 86 | if (fConnection.isOpen()) { |
e0838ca1 | 87 | FutureTask<CommandResult> future = new FutureTask<>(new Callable<CommandResult>() { |
eb1bab5b | 88 | @Override |
b732adaa | 89 | public CommandResult call() throws IOException, InterruptedException { |
13729cbc BH |
90 | IProgressMonitor monitor = aMonitor; |
91 | if (monitor == null) { | |
92 | monitor = new NullProgressMonitor(); | |
93 | } | |
94 | if (!monitor.isCanceled()) { | |
364dcfaf | 95 | IRemoteProcess process = fConnection.getService(IRemoteProcessService.class).getProcessBuilder(command.getInput()).start(); |
13729cbc BH |
96 | InputReader stdout = new InputReader(checkNotNull(process.getInputStream())); |
97 | InputReader stderr = new InputReader(checkNotNull(process.getErrorStream())); | |
b732adaa MS |
98 | |
99 | try { | |
100 | stdout.waitFor(monitor); | |
101 | stderr.waitFor(monitor); | |
13729cbc | 102 | if (!monitor.isCanceled()) { |
533d0bc3 | 103 | return createResult(process.waitFor(), stdout.toString(), stderr.toString()); |
1a18ada9 | 104 | } |
b732adaa MS |
105 | } catch (OperationCanceledException e) { |
106 | } catch (InterruptedException e) { | |
107 | return new CommandResult(1, new String[0], new String[] {e.getMessage()}); | |
108 | } finally { | |
109 | stdout.stop(); | |
110 | stderr.stop(); | |
111 | process.destroy(); | |
d6fc6e1b | 112 | } |
eb1bab5b | 113 | } |
b732adaa | 114 | return new CommandResult(1, new String[0], new String[] {"cancelled"}); //$NON-NLS-1$ |
eb1bab5b BH |
115 | } |
116 | }); | |
117 | ||
118 | fExecutor.execute(future); | |
119 | ||
120 | try { | |
13729cbc | 121 | return checkNotNull(future.get(TmfRemotePreferences.getCommandTimeout(), TimeUnit.SECONDS)); |
eb1bab5b BH |
122 | } catch (InterruptedException ex) { |
123 | throw new ExecutionException(Messages.TraceControl_ExecutionCancelled, ex); | |
124 | } catch (TimeoutException ex) { | |
125 | throw new ExecutionException(Messages.TraceControl_ExecutionTimeout, ex); | |
13729cbc BH |
126 | } catch (Exception ex) { |
127 | throw new ExecutionException(Messages.TraceControl_ExecutionFailure, ex); | |
128 | } | |
129 | finally { | |
b732adaa | 130 | future.cancel(true); |
eb1bab5b BH |
131 | } |
132 | } | |
133 | throw new ExecutionException(Messages.TraceControl_ShellNotConnected, null); | |
134 | } | |
cfdb727a | 135 | |
eb1bab5b BH |
136 | // ------------------------------------------------------------------------ |
137 | // Helper methods | |
138 | // ------------------------------------------------------------------------ | |
b732adaa | 139 | |
533d0bc3 | 140 | private static CommandResult createResult(int origResult, String origStdout, String origStderr) { |
b732adaa MS |
141 | final int result; |
142 | final String stdout, stderr; | |
533d0bc3 BH |
143 | result = origResult; |
144 | stdout = origStdout; | |
145 | stderr = origStderr; | |
b732adaa | 146 | String[] output = splitLines(stdout); |
5de50ac9 | 147 | String[] error = splitLines(stderr); |
b732adaa | 148 | return new CommandResult(result, output, error); |
eb1bab5b | 149 | } |
cfdb727a | 150 | |
c07150f8 | 151 | private static @NonNull String[] splitLines(String output) { |
13729cbc | 152 | return checkNotNull(output.split("\\r?\\n")); //$NON-NLS-1$ |
eb1bab5b | 153 | } |
eb1bab5b | 154 | } |