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
.service
;
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
;
31 import org
.eclipse
.linuxtools
.internal
.lttng2
.ui
.views
.control
.remote
.IRemoteSystemProxy
;
32 import org
.eclipse
.rse
.services
.shells
.HostShellProcessAdapter
;
33 import org
.eclipse
.rse
.services
.shells
.IHostShell
;
34 import org
.eclipse
.rse
.services
.shells
.IShellService
;
37 * <b><u>CommandShell</u></b>
39 * Implementation of remote command execution using RSE's shell service.
42 public class CommandShell
implements ICommandShell
{
44 // ------------------------------------------------------------------------
46 // ------------------------------------------------------------------------
48 // string to be echo'ed when running command in shell, used to indicate that the command has finished running
49 public final static String DONE_MARKUP_STRING
= "--RSE:donedonedone:--"; //$NON-NLS-1$
51 //command delimiter for shell
52 public final static String CMD_DELIMITER
= "\n"; //$NON-NLS-1$
54 public final static String SHELL_ECHO_CMD
= " echo "; //$NON-NLS-1$
56 private final static int DEFAULT_TIMEOUT_VALUE
= 15000; // in milliseconds
58 // ------------------------------------------------------------------------
60 // ------------------------------------------------------------------------
61 private IRemoteSystemProxy fProxy
= null;
62 private IHostShell fHostShell
= null;
63 private BufferedReader fBufferReader
= null;
64 private ExecutorService fExecutor
= Executors
.newFixedThreadPool(1);
65 private boolean fIsConnected
= false;
67 // ------------------------------------------------------------------------
69 // ------------------------------------------------------------------------
70 public CommandShell(IRemoteSystemProxy proxy
) {
74 // ------------------------------------------------------------------------
76 // ------------------------------------------------------------------------
79 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#connect()
82 public void connect() throws ExecutionException
{
83 IShellService shellService
= fProxy
.getShellService();
86 fHostShell
= shellService
.launchShell("", new String
[0], new NullProgressMonitor()); //$NON-NLS-1$
87 p
= new HostShellProcessAdapter(fHostShell
);
88 } catch (Exception e
) {
89 throw new ExecutionException(Messages
.TraceControl_CommandShellError
, e
);
91 fBufferReader
= new BufferedReader(new InputStreamReader(p
.getInputStream()));
94 // Flush Login messages
95 executeCommand(" ", new NullProgressMonitor(), false); //$NON-NLS-1$
100 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#disconnect()
103 public void disconnect() {
104 fIsConnected
= false;
106 fBufferReader
.close();
107 } catch (IOException e
) {
114 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
117 public ICommandResult
executeCommand(String command
, IProgressMonitor monitor
) throws ExecutionException
{
118 return executeCommand(command
, monitor
, true);
123 * @see org.eclipse.linuxtools.internal.lttng2.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor, boolean)
126 public ICommandResult
executeCommand(final String command
, final IProgressMonitor monitor
, final boolean checkReturnValue
) throws ExecutionException
{
128 FutureTask
<CommandResult
> future
= new FutureTask
<CommandResult
>(new Callable
<CommandResult
>() {
130 public CommandResult
call() throws IOException
, CancellationException
{
131 final ArrayList
<String
> result
= new ArrayList
<String
>();
134 synchronized (fHostShell
) {
135 fHostShell
.writeToShell(formatShellCommand(command
));
137 while ((nextLine
= fBufferReader
.readLine()) != null) {
139 if (monitor
.isCanceled()) {
141 throw new CancellationException();
144 if (nextLine
.contains(DONE_MARKUP_STRING
) && nextLine
.contains(SHELL_ECHO_CMD
)) {
149 while ((nextLine
= fBufferReader
.readLine()) != null) {
150 // check if job was cancelled
151 if (monitor
.isCanceled()) {
153 throw new CancellationException();
156 if (!nextLine
.contains(DONE_MARKUP_STRING
)) {
157 result
.add(nextLine
);
159 if (checkReturnValue
) {
160 returnValue
= Integer
.valueOf(nextLine
.substring(DONE_MARKUP_STRING
.length()+1));
168 return new CommandResult(returnValue
, result
.toArray(new String
[result
.size()]));
172 fExecutor
.execute(future
);
175 return future
.get(DEFAULT_TIMEOUT_VALUE
, TimeUnit
.MILLISECONDS
);
176 } catch (java
.util
.concurrent
.ExecutionException ex
) {
177 throw new ExecutionException(Messages
.TraceControl_ExecutionFailure
, ex
);
178 } catch (InterruptedException ex
) {
179 throw new ExecutionException(Messages
.TraceControl_ExecutionCancelled
, ex
);
180 } catch (TimeoutException ex
) {
181 throw new ExecutionException(Messages
.TraceControl_ExecutionTimeout
, ex
);
184 throw new ExecutionException(Messages
.TraceControl_ShellNotConnected
, null);
187 // ------------------------------------------------------------------------
189 // ------------------------------------------------------------------------
191 * Flushes the buffer reader
192 * @throws IOException
194 private void flushInput() throws IOException
{
195 char[] cbuf
= new char[1];
196 while (fBufferReader
.ready()) {
197 if (fBufferReader
.read(cbuf
, 0, 1) == -1) {
204 * format the command to be sent into the shell command with the done markup string.
205 * The done markup string is needed so we can tell that end of output has been reached.
208 * @return formatted command string
210 private String
formatShellCommand(String cmd
) {
211 if (cmd
== null || cmd
.equals("")) //$NON-NLS-1$
213 StringBuffer formattedCommand
= new StringBuffer();
214 // Make a multi line command by using \ and \r. This is needed for matching
215 // the DONE_MARKUP_STRING in echoed command when having a long command
216 // (bigger than max SSH line)
217 formattedCommand
.append(cmd
).append("\\\r;"); //$NON-NLS-1$
218 formattedCommand
.append(SHELL_ECHO_CMD
).append(DONE_MARKUP_STRING
);
219 formattedCommand
.append(" $?"); //$NON-NLS-1$
220 formattedCommand
.append(CMD_DELIMITER
);
221 return formattedCommand
.toString();