1 /**********************************************************************
2 * Copyright (c) 2012 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 **********************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.views
.control
.remote
;
15 import java
.io
.BufferedReader
;
16 import java
.io
.IOException
;
17 import java
.io
.InputStreamReader
;
18 import java
.util
.ArrayList
;
19 import java
.util
.concurrent
.Callable
;
20 import java
.util
.concurrent
.CancellationException
;
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
;
27 import org
.eclipse
.core
.commands
.ExecutionException
;
28 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
29 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
30 import org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.views
.control
.messages
.Messages
;
31 import org
.eclipse
.rse
.services
.shells
.HostShellProcessAdapter
;
32 import org
.eclipse
.rse
.services
.shells
.IHostShell
;
33 import org
.eclipse
.rse
.services
.shells
.IShellService
;
37 * Implementation of remote command execution using RSE's shell service.
40 * @author Patrick Tasse
41 * @author Bernd Hufmann
43 public class CommandShell
implements ICommandShell
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 /** String to be echo'ed when running command in shell, used to indicate that the command has finished running */
50 public final static String DONE_MARKUP_STRING
= "--RSE:donedonedone:--"; //$NON-NLS-1$
52 /** Command delimiter for shell */
53 public final static String CMD_DELIMITER
= "\n"; //$NON-NLS-1$
55 /** Shell "echo" command */
56 public final static String SHELL_ECHO_CMD
= " echo "; //$NON-NLS-1$
58 /** Default timeout, in milliseconds */
59 private final static int DEFAULT_TIMEOUT_VALUE
= 15000;
61 // ------------------------------------------------------------------------
63 // ------------------------------------------------------------------------
64 private IRemoteSystemProxy fProxy
= null;
65 private IHostShell fHostShell
= null;
66 private BufferedReader fBufferReader
= null;
67 private final ExecutorService fExecutor
= Executors
.newFixedThreadPool(1);
68 private boolean fIsConnected
= false;
70 // ------------------------------------------------------------------------
72 // ------------------------------------------------------------------------
78 * The Remote System proxy
80 public CommandShell(IRemoteSystemProxy proxy
) {
84 // ------------------------------------------------------------------------
86 // ------------------------------------------------------------------------
89 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#connect()
92 public void connect() throws ExecutionException
{
93 IShellService shellService
= fProxy
.getShellService();
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
);
101 fBufferReader
= new BufferedReader(new InputStreamReader(p
.getInputStream()));
104 // Flush Login messages
105 executeCommand(" ", new NullProgressMonitor(), false); //$NON-NLS-1$
110 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#disconnect()
113 public void disconnect() {
114 fIsConnected
= false;
116 fBufferReader
.close();
117 } catch (IOException e
) {
124 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
127 public ICommandResult
executeCommand(String command
, IProgressMonitor monitor
) throws ExecutionException
{
128 return executeCommand(command
, monitor
, true);
133 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor, boolean)
136 public ICommandResult
executeCommand(final String command
, final IProgressMonitor monitor
, final boolean checkReturnValue
) throws ExecutionException
{
138 FutureTask
<CommandResult
> future
= new FutureTask
<CommandResult
>(new Callable
<CommandResult
>() {
140 public CommandResult
call() throws IOException
, CancellationException
{
141 final ArrayList
<String
> result
= new ArrayList
<String
>();
144 synchronized (fHostShell
) {
145 fHostShell
.writeToShell(formatShellCommand(command
));
147 while ((nextLine
= fBufferReader
.readLine()) != null) {
149 if (monitor
.isCanceled()) {
151 throw new CancellationException();
154 if (nextLine
.contains(DONE_MARKUP_STRING
) && nextLine
.contains(SHELL_ECHO_CMD
)) {
159 while ((nextLine
= fBufferReader
.readLine()) != null) {
160 // check if job was cancelled
161 if (monitor
.isCanceled()) {
163 throw new CancellationException();
166 if (!nextLine
.contains(DONE_MARKUP_STRING
)) {
167 result
.add(nextLine
);
169 if (checkReturnValue
) {
170 returnValue
= Integer
.valueOf(nextLine
.substring(DONE_MARKUP_STRING
.length()+1));
178 return new CommandResult(returnValue
, result
.toArray(new String
[result
.size()]));
182 fExecutor
.execute(future
);
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
);
194 throw new ExecutionException(Messages
.TraceControl_ShellNotConnected
, null);
197 // ------------------------------------------------------------------------
199 // ------------------------------------------------------------------------
201 * Flushes the buffer reader
202 * @throws IOException
204 private void flushInput() throws IOException
{
205 char[] cbuf
= new char[1];
206 while (fBufferReader
.ready()) {
207 if (fBufferReader
.read(cbuf
, 0, 1) == -1) {
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.
219 * The original command
220 * @return formatted command string
222 private String
formatShellCommand(String cmd
) {
223 if (cmd
== null || cmd
.equals("")) { //$NON-NLS-1$
226 StringBuffer formattedCommand
= new StringBuffer();
227 // Make a multi line command by using \ and \r. This is needed for matching
228 // the DONE_MARKUP_STRING in echoed command when having a long command
229 // (bigger than max SSH line)
230 formattedCommand
.append(cmd
).append("\\\r;"); //$NON-NLS-1$
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();