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 public final static String SHELL_ECHO_CMD
= " echo "; //$NON-NLS-1$
57 private final static int DEFAULT_TIMEOUT_VALUE
= 15000; // in milliseconds
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
62 private IRemoteSystemProxy fProxy
= null;
63 private IHostShell fHostShell
= null;
64 private BufferedReader fBufferReader
= null;
65 private ExecutorService fExecutor
= Executors
.newFixedThreadPool(1);
66 private boolean fIsConnected
= false;
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
71 public CommandShell(IRemoteSystemProxy proxy
) {
75 // ------------------------------------------------------------------------
77 // ------------------------------------------------------------------------
80 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#connect()
83 public void connect() throws ExecutionException
{
84 IShellService shellService
= fProxy
.getShellService();
87 fHostShell
= shellService
.launchShell("", new String
[0], new NullProgressMonitor()); //$NON-NLS-1$
88 p
= new HostShellProcessAdapter(fHostShell
);
89 } catch (Exception e
) {
90 throw new ExecutionException(Messages
.TraceControl_CommandShellError
, e
);
92 fBufferReader
= new BufferedReader(new InputStreamReader(p
.getInputStream()));
95 // Flush Login messages
96 executeCommand(" ", new NullProgressMonitor(), false); //$NON-NLS-1$
101 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#disconnect()
104 public void disconnect() {
105 fIsConnected
= false;
107 fBufferReader
.close();
108 } catch (IOException e
) {
115 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
118 public ICommandResult
executeCommand(String command
, IProgressMonitor monitor
) throws ExecutionException
{
119 return executeCommand(command
, monitor
, true);
124 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor, boolean)
127 public ICommandResult
executeCommand(final String command
, final IProgressMonitor monitor
, final boolean checkReturnValue
) throws ExecutionException
{
129 FutureTask
<CommandResult
> future
= new FutureTask
<CommandResult
>(new Callable
<CommandResult
>() {
131 public CommandResult
call() throws IOException
, CancellationException
{
132 final ArrayList
<String
> result
= new ArrayList
<String
>();
135 synchronized (fHostShell
) {
136 fHostShell
.writeToShell(formatShellCommand(command
));
138 while ((nextLine
= fBufferReader
.readLine()) != null) {
140 if (monitor
.isCanceled()) {
142 throw new CancellationException();
145 if (nextLine
.contains(DONE_MARKUP_STRING
) && nextLine
.contains(SHELL_ECHO_CMD
)) {
150 while ((nextLine
= fBufferReader
.readLine()) != null) {
151 // check if job was cancelled
152 if (monitor
.isCanceled()) {
154 throw new CancellationException();
157 if (!nextLine
.contains(DONE_MARKUP_STRING
)) {
158 result
.add(nextLine
);
160 if (checkReturnValue
) {
161 returnValue
= Integer
.valueOf(nextLine
.substring(DONE_MARKUP_STRING
.length()+1));
169 return new CommandResult(returnValue
, result
.toArray(new String
[result
.size()]));
173 fExecutor
.execute(future
);
176 return future
.get(DEFAULT_TIMEOUT_VALUE
, TimeUnit
.MILLISECONDS
);
177 } catch (java
.util
.concurrent
.ExecutionException ex
) {
178 throw new ExecutionException(Messages
.TraceControl_ExecutionFailure
, ex
);
179 } catch (InterruptedException ex
) {
180 throw new ExecutionException(Messages
.TraceControl_ExecutionCancelled
, ex
);
181 } catch (TimeoutException ex
) {
182 throw new ExecutionException(Messages
.TraceControl_ExecutionTimeout
, ex
);
185 throw new ExecutionException(Messages
.TraceControl_ShellNotConnected
, null);
188 // ------------------------------------------------------------------------
190 // ------------------------------------------------------------------------
192 * Flushes the buffer reader
193 * @throws IOException
195 private void flushInput() throws IOException
{
196 char[] cbuf
= new char[1];
197 while (fBufferReader
.ready()) {
198 if (fBufferReader
.read(cbuf
, 0, 1) == -1) {
205 * format the command to be sent into the shell command with the done markup string.
206 * The done markup string is needed so we can tell that end of output has been reached.
209 * @return formatted command string
211 private String
formatShellCommand(String cmd
) {
212 if (cmd
== null || cmd
.equals("")) //$NON-NLS-1$
214 StringBuffer formattedCommand
= new StringBuffer();
215 // Make a multi line command by using \ and \r. This is needed for matching
216 // the DONE_MARKUP_STRING in echoed command when having a long command
217 // (bigger than max SSH line)
218 formattedCommand
.append(cmd
).append("\\\r;"); //$NON-NLS-1$
219 formattedCommand
.append(SHELL_ECHO_CMD
).append(DONE_MARKUP_STRING
);
220 formattedCommand
.append(" $?"); //$NON-NLS-1$
221 formattedCommand
.append(CMD_DELIMITER
);
222 return formattedCommand
.toString();