1 /**********************************************************************
2 * Copyright (c) 2012, 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 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated using Executor Framework
12 * Markus Schorn - Bug 448058: Use org.eclipse.remote in favor of RSE
13 * Bernd Hufmann - Update to org.eclipse.remote API 2.0
14 **********************************************************************/
15 package org
.eclipse
.tracecompass
.internal
.tmf
.remote
.core
.shell
;
17 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
18 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.nullToEmptyString
;
20 import java
.io
.IOException
;
21 import java
.util
.concurrent
.Callable
;
22 import java
.util
.concurrent
.ExecutorService
;
23 import java
.util
.concurrent
.Executors
;
24 import java
.util
.concurrent
.FutureTask
;
25 import java
.util
.concurrent
.TimeUnit
;
26 import java
.util
.concurrent
.TimeoutException
;
28 import org
.eclipse
.core
.commands
.ExecutionException
;
29 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
30 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
31 import org
.eclipse
.core
.runtime
.OperationCanceledException
;
32 import org
.eclipse
.jdt
.annotation
.NonNull
;
33 import org
.eclipse
.remote
.core
.IRemoteConnection
;
34 import org
.eclipse
.remote
.core
.IRemoteProcess
;
35 import org
.eclipse
.remote
.core
.IRemoteProcessService
;
36 import org
.eclipse
.tracecompass
.internal
.tmf
.remote
.core
.messages
.Messages
;
37 import org
.eclipse
.tracecompass
.internal
.tmf
.remote
.core
.preferences
.TmfRemotePreferences
;
38 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandInput
;
39 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandOutputListener
;
40 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandResult
;
41 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandShell
;
45 * Implementation of remote command execution using IRemoteConnection.
48 * @author Patrick Tasse
49 * @author Bernd Hufmann
51 public class CommandShell
implements ICommandShell
{
53 // ------------------------------------------------------------------------
55 // ------------------------------------------------------------------------
56 private final IRemoteConnection fConnection
;
57 private final ExecutorService fExecutor
= checkNotNull(Executors
.newFixedThreadPool(1));
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
64 * Create a new command shell
66 * @param connection the remote connection for this shell
68 public CommandShell(IRemoteConnection connection
) {
69 fConnection
= connection
;
72 // ------------------------------------------------------------------------
74 // ------------------------------------------------------------------------
77 public void dispose() {
82 public ICommandInput
createCommand() {
83 return new CommandInput();
87 public ICommandResult
executeCommand(final ICommandInput command
, final IProgressMonitor aMonitor
) throws ExecutionException
{
88 return executeCommand(command
, aMonitor
, null);
92 public ICommandResult
executeCommand(final ICommandInput command
, final IProgressMonitor aMonitor
, ICommandOutputListener listener
) throws ExecutionException
{
93 if (fConnection
.isOpen()) {
94 FutureTask
<CommandResult
> future
= new FutureTask
<>(new Callable
<CommandResult
>() {
96 public CommandResult
call() throws IOException
, InterruptedException
{
97 IProgressMonitor monitor
= aMonitor
;
98 if (monitor
== null) {
99 monitor
= new NullProgressMonitor();
101 if (!monitor
.isCanceled()) {
102 IRemoteProcessService service
= fConnection
.getService(IRemoteProcessService
.class);
103 if (service
== null) {
104 return new CommandResult(1, new @NonNull String
[0], new @NonNull String
[] { nullToEmptyString(Messages
.RemoteConnection_ServiceNotDefined
) });
106 IRemoteProcess process
= service
.getProcessBuilder(command
.getInput()).start();
107 InputReader stdout
= new InputReader(checkNotNull(process
.getInputStream()), listener
, true);
108 InputReader stderr
= new InputReader(checkNotNull(process
.getErrorStream()), listener
, false);
111 stdout
.waitFor(monitor
);
112 stderr
.waitFor(monitor
);
113 if (!monitor
.isCanceled()) {
114 return createResult(process
.waitFor(), stdout
.toString(), stderr
.toString());
116 } catch (OperationCanceledException e
) {
117 } catch (InterruptedException e
) {
118 return new CommandResult(1, new String
[0], new String
[] {e
.getMessage()});
125 return new CommandResult(1, new String
[0], new String
[] {"cancelled"}); //$NON-NLS-1$
129 fExecutor
.execute(future
);
132 return checkNotNull(future
.get(TmfRemotePreferences
.getCommandTimeout(), TimeUnit
.SECONDS
));
133 } catch (InterruptedException ex
) {
134 throw new ExecutionException(Messages
.RemoteConnection_ExecutionCancelled
, ex
);
135 } catch (TimeoutException ex
) {
136 throw new ExecutionException(Messages
.RemoteConnection_ExecutionTimeout
, ex
);
137 } catch (Exception ex
) {
138 throw new ExecutionException(Messages
.RemoteConnection_ExecutionFailure
, ex
);
144 throw new ExecutionException(Messages
.RemoteConnection_ShellNotConnected
, null);
147 // ------------------------------------------------------------------------
149 // ------------------------------------------------------------------------
151 private static CommandResult
createResult(int origResult
, String origStdout
, String origStderr
) {
153 final String stdout
, stderr
;
157 String
[] output
= splitLines(stdout
);
158 String
[] error
= splitLines(stderr
);
159 return new CommandResult(result
, output
, error
);
162 private static String
@NonNull [] splitLines(String output
) {
163 return checkNotNull(output
.split("\\r?\\n")); //$NON-NLS-1$