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