Merge branch 'master' into lttng_2_0_control_dev
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng.ui / src / org / eclipse / linuxtools / internal / lttng / ui / views / control / service / CommandShell.java
1 /**********************************************************************
2 * Copyright (c) 2012 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated using Executor Framework
12 **********************************************************************/
13 package org.eclipse.linuxtools.internal.lttng.ui.views.control.service;
14
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;
26
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.lttng.ui.views.control.Messages;
31 import org.eclipse.linuxtools.internal.lttng.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;
35
36 /**
37 * <b><u>CommandShell</u></b>
38 * <p>
39 * Implementation of remote command execution using RSE's shell service.
40 * </p>
41 */
42 public class CommandShell implements ICommandShell {
43
44 // ------------------------------------------------------------------------
45 // Constants
46 // ------------------------------------------------------------------------
47
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$
50
51 //command delimiter for shell
52 public final static String CMD_DELIMITER = "\n"; //$NON-NLS-1$
53
54 public final static String SHELL_ECHO_CMD = " echo "; //$NON-NLS-1$
55
56 private final static int DEFAULT_TIMEOUT_VALUE = 15000; // in milliseconds
57
58 // ------------------------------------------------------------------------
59 // Attributes
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;
66
67 // ------------------------------------------------------------------------
68 // Constructors
69 // ------------------------------------------------------------------------
70 public CommandShell(IRemoteSystemProxy proxy) {
71 fProxy = proxy;
72 }
73
74 // ------------------------------------------------------------------------
75 // Operations
76 // ------------------------------------------------------------------------
77 /*
78 * (non-Javadoc)
79 * @see org.eclipse.linuxtools.internal.lttng.ui.views.control.service.ICommandShell#connect()
80 */
81 @Override
82 public void connect() throws ExecutionException {
83 IShellService shellService = fProxy.getShellService();
84 Process p = null;
85 try {
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);
90 }
91 fBufferReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
92 fIsConnected = true;
93
94 // Flush Login messages
95 executeCommand(" ", new NullProgressMonitor(), false); //$NON-NLS-1$
96 }
97
98 /*
99 * (non-Javadoc)
100 * @see org.eclipse.linuxtools.internal.lttng.ui.views.control.service.ICommandShell#disconnect()
101 */
102 @Override
103 public void disconnect() {
104 fIsConnected = false;
105 try {
106 fBufferReader.close();
107 } catch (IOException e) {
108 // ignore
109 }
110 }
111
112 /*
113 * (non-Javadoc)
114 * @see org.eclipse.linuxtools.internal.lttng.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
115 */
116 @Override
117 public ICommandResult executeCommand(String command, IProgressMonitor monitor) throws ExecutionException {
118 return executeCommand(command, monitor, true);
119 }
120
121 /*
122 * (non-Javadoc)
123 * @see org.eclipse.linuxtools.internal.lttng.ui.views.control.service.ICommandShell#executeCommand(java.lang.String, org.eclipse.core.runtime.IProgressMonitor, boolean)
124 */
125 @Override
126 public ICommandResult executeCommand(final String command, final IProgressMonitor monitor, final boolean checkReturnValue) throws ExecutionException {
127 if (fIsConnected) {
128 FutureTask<CommandResult> future = new FutureTask<CommandResult>(new Callable<CommandResult>() {
129 @Override
130 public CommandResult call() throws IOException, CancellationException {
131 final ArrayList<String> result = new ArrayList<String>();
132 int returnValue = 0;
133
134 synchronized (fHostShell) {
135 fHostShell.writeToShell(formatShellCommand(command));
136 String nextLine;
137 while ((nextLine = fBufferReader.readLine()) != null) {
138
139 if (monitor.isCanceled()) {
140 flushInput();
141 throw new CancellationException();
142 }
143
144 if (nextLine.contains(DONE_MARKUP_STRING) && nextLine.contains(SHELL_ECHO_CMD)) {
145 break;
146 }
147 }
148
149 while ((nextLine = fBufferReader.readLine()) != null) {
150 // check if job was cancelled
151 if (monitor.isCanceled()) {
152 flushInput();
153 throw new CancellationException();
154 }
155
156 if (!nextLine.contains(DONE_MARKUP_STRING)) {
157 result.add(nextLine);
158 } else {
159 if (checkReturnValue) {
160 returnValue = Integer.valueOf(nextLine.substring(DONE_MARKUP_STRING.length()+1));
161 }
162 break;
163 }
164 }
165
166 flushInput();
167 }
168 return new CommandResult(returnValue, result.toArray(new String[result.size()]));
169 }
170 });
171
172 fExecutor.execute(future);
173
174 try {
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);
182 }
183 }
184 throw new ExecutionException(Messages.TraceControl_ShellNotConnected, null);
185 }
186
187 // ------------------------------------------------------------------------
188 // Helper methods
189 // ------------------------------------------------------------------------
190 /**
191 * Flushes the buffer reader
192 * @throws IOException
193 */
194 private void flushInput() throws IOException {
195 char[] cbuf = new char[1];
196 while (fBufferReader.ready()) {
197 if (fBufferReader.read(cbuf, 0, 1) == -1) {
198 break;
199 }
200 }
201 }
202
203 /**
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.
206 *
207 * @param cmd
208 * @return formatted command string
209 */
210 private String formatShellCommand(String cmd) {
211 if (cmd == null || cmd.equals("")) //$NON-NLS-1$
212 return cmd;
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();
222 }
223
224 }
This page took 0.03629 seconds and 5 git commands to generate.