tmf: Clean up the ctfAdaptor unit tests
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng2.ui / src / org / eclipse / linuxtools / internal / lttng2 / ui / views / control / remote / CommandShell.java
CommitLineData
eb1bab5b
BH
1/**********************************************************************
2 * Copyright (c) 2012 Ericsson
cfdb727a 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
cfdb727a
AM
8 *
9 * Contributors:
eb1bab5b
BH
10 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated using Executor Framework
12 **********************************************************************/
9315aeee 13package org.eclipse.linuxtools.internal.lttng2.ui.views.control.remote;
eb1bab5b
BH
14
15import java.io.BufferedReader;
16import java.io.IOException;
17import java.io.InputStreamReader;
18import java.util.ArrayList;
19import java.util.concurrent.Callable;
20import java.util.concurrent.CancellationException;
21import java.util.concurrent.ExecutorService;
22import java.util.concurrent.Executors;
23import java.util.concurrent.FutureTask;
24import java.util.concurrent.TimeUnit;
25import java.util.concurrent.TimeoutException;
26
27import org.eclipse.core.commands.ExecutionException;
28import org.eclipse.core.runtime.IProgressMonitor;
29import org.eclipse.core.runtime.NullProgressMonitor;
9315aeee 30import org.eclipse.linuxtools.internal.lttng2.ui.views.control.messages.Messages;
eb1bab5b
BH
31import org.eclipse.rse.services.shells.HostShellProcessAdapter;
32import org.eclipse.rse.services.shells.IHostShell;
33import org.eclipse.rse.services.shells.IShellService;
34
35/**
eb1bab5b 36 * <p>
cfdb727a 37 * Implementation of remote command execution using RSE's shell service.
eb1bab5b 38 * </p>
cfdb727a 39 *
dbd4432d
BH
40 * @author Patrick Tasse
41 * @author Bernd Hufmann
eb1bab5b
BH
42 */
43public class CommandShell implements ICommandShell {
44
45 // ------------------------------------------------------------------------
46 // Constants
47 // ------------------------------------------------------------------------
48
cfdb727a 49 /** String to be echo'ed when running command in shell, used to indicate that the command has finished running */
eb1bab5b 50 public final static String DONE_MARKUP_STRING = "--RSE:donedonedone:--"; //$NON-NLS-1$
cfdb727a
AM
51
52 /** Command delimiter for shell */
eb1bab5b
BH
53 public final static String CMD_DELIMITER = "\n"; //$NON-NLS-1$
54
cfdb727a 55 /** Shell "echo" command */
eb1bab5b
BH
56 public final static String SHELL_ECHO_CMD = " echo "; //$NON-NLS-1$
57
cfdb727a
AM
58 /** Default timeout, in milliseconds */
59 private final static int DEFAULT_TIMEOUT_VALUE = 15000;
eb1bab5b
BH
60
61 // ------------------------------------------------------------------------
62 // Attributes
63 // ------------------------------------------------------------------------
64 private IRemoteSystemProxy fProxy = null;
65 private IHostShell fHostShell = null;
66 private BufferedReader fBufferReader = null;
cfdb727a 67 private final ExecutorService fExecutor = Executors.newFixedThreadPool(1);
eb1bab5b 68 private boolean fIsConnected = false;
cfdb727a 69
eb1bab5b
BH
70 // ------------------------------------------------------------------------
71 // Constructors
72 // ------------------------------------------------------------------------
cfdb727a
AM
73
74 /**
75 * Constructor
76 *
77 * @param proxy
78 * The Remote System proxy
79 */
eb1bab5b
BH
80 public CommandShell(IRemoteSystemProxy proxy) {
81 fProxy = proxy;
82 }
83
84 // ------------------------------------------------------------------------
85 // Operations
86 // ------------------------------------------------------------------------
87 /*
88 * (non-Javadoc)
115b4a01 89 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#connect()
eb1bab5b
BH
90 */
91 @Override
92 public void connect() throws ExecutionException {
93 IShellService shellService = fProxy.getShellService();
94 Process p = null;
95 try {
96 fHostShell = shellService.launchShell("", new String[0], new NullProgressMonitor()); //$NON-NLS-1$
97 p = new HostShellProcessAdapter(fHostShell);
98 } catch (Exception e) {
99 throw new ExecutionException(Messages.TraceControl_CommandShellError, e);
100 }
101 fBufferReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
102 fIsConnected = true;
103
104 // Flush Login messages
105 executeCommand(" ", new NullProgressMonitor(), false); //$NON-NLS-1$
106 }
107
108 /*
109 * (non-Javadoc)
115b4a01 110 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#disconnect()
eb1bab5b
BH
111 */
112 @Override
113 public void disconnect() {
114 fIsConnected = false;
115 try {
116 fBufferReader.close();
117 } catch (IOException e) {
118 // ignore
119 }
120 }
121
122 /*
123 * (non-Javadoc)
115b4a01 124 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
eb1bab5b
BH
125 */
126 @Override
127 public ICommandResult executeCommand(String command, IProgressMonitor monitor) throws ExecutionException {
128 return executeCommand(command, monitor, true);
129 }
130
131 /*
132 * (non-Javadoc)
115b4a01 133 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor, boolean)
eb1bab5b
BH
134 */
135 @Override
136 public ICommandResult executeCommand(final String command, final IProgressMonitor monitor, final boolean checkReturnValue) throws ExecutionException {
137 if (fIsConnected) {
138 FutureTask<CommandResult> future = new FutureTask<CommandResult>(new Callable<CommandResult>() {
139 @Override
140 public CommandResult call() throws IOException, CancellationException {
141 final ArrayList<String> result = new ArrayList<String>();
142 int returnValue = 0;
143
144 synchronized (fHostShell) {
145 fHostShell.writeToShell(formatShellCommand(command));
146 String nextLine;
147 while ((nextLine = fBufferReader.readLine()) != null) {
148
149 if (monitor.isCanceled()) {
150 flushInput();
cfdb727a 151 throw new CancellationException();
eb1bab5b
BH
152 }
153
154 if (nextLine.contains(DONE_MARKUP_STRING) && nextLine.contains(SHELL_ECHO_CMD)) {
155 break;
156 }
157 }
158
159 while ((nextLine = fBufferReader.readLine()) != null) {
160 // check if job was cancelled
161 if (monitor.isCanceled()) {
162 flushInput();
cfdb727a 163 throw new CancellationException();
eb1bab5b
BH
164 }
165
166 if (!nextLine.contains(DONE_MARKUP_STRING)) {
167 result.add(nextLine);
168 } else {
169 if (checkReturnValue) {
170 returnValue = Integer.valueOf(nextLine.substring(DONE_MARKUP_STRING.length()+1));
171 }
172 break;
173 }
174 }
175
176 flushInput();
177 }
178 return new CommandResult(returnValue, result.toArray(new String[result.size()]));
179 }
180 });
181
182 fExecutor.execute(future);
183
184 try {
185 return future.get(DEFAULT_TIMEOUT_VALUE, TimeUnit.MILLISECONDS);
186 } catch (java.util.concurrent.ExecutionException ex) {
187 throw new ExecutionException(Messages.TraceControl_ExecutionFailure, ex);
188 } catch (InterruptedException ex) {
189 throw new ExecutionException(Messages.TraceControl_ExecutionCancelled, ex);
190 } catch (TimeoutException ex) {
191 throw new ExecutionException(Messages.TraceControl_ExecutionTimeout, ex);
192 }
193 }
194 throw new ExecutionException(Messages.TraceControl_ShellNotConnected, null);
195 }
cfdb727a 196
eb1bab5b
BH
197 // ------------------------------------------------------------------------
198 // Helper methods
199 // ------------------------------------------------------------------------
200 /**
cfdb727a 201 * Flushes the buffer reader
eb1bab5b
BH
202 * @throws IOException
203 */
204 private void flushInput() throws IOException {
205 char[] cbuf = new char[1];
206 while (fBufferReader.ready()) {
207 if (fBufferReader.read(cbuf, 0, 1) == -1) {
208 break;
209 }
210 }
211 }
cfdb727a 212
eb1bab5b 213 /**
cfdb727a
AM
214 * Format the command to be sent into the shell command with the done markup
215 * string. The done markup string is needed so we can tell that end of
216 * output has been reached.
217 *
eb1bab5b 218 * @param cmd
cfdb727a 219 * The original command
eb1bab5b
BH
220 * @return formatted command string
221 */
0a78d11a 222 private static String formatShellCommand(String cmd) {
cfdb727a 223 if (cmd == null || cmd.equals("")) { //$NON-NLS-1$
eb1bab5b 224 return cmd;
cfdb727a 225 }
eb1bab5b 226 StringBuffer formattedCommand = new StringBuffer();
4775bcbf 227 // Make a multi line command by using \ and \r. This is needed for matching
cfdb727a 228 // the DONE_MARKUP_STRING in echoed command when having a long command
4775bcbf 229 // (bigger than max SSH line)
cfdb727a 230 formattedCommand.append(cmd).append("\\\r;"); //$NON-NLS-1$
eb1bab5b
BH
231 formattedCommand.append(SHELL_ECHO_CMD).append(DONE_MARKUP_STRING);
232 formattedCommand.append(" $?"); //$NON-NLS-1$
233 formattedCommand.append(CMD_DELIMITER);
234 return formattedCommand.toString();
235 }
236
237}
This page took 0.042048 seconds and 5 git commands to generate.