View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.gshell.commands.ssh;
21  
22  import com.google.code.sshd.server.ShellFactory;
23  import jline.Completor;
24  import jline.History;
25  import org.apache.geronimo.gshell.command.Variables;
26  import org.apache.geronimo.gshell.commandline.CommandLineExecutor;
27  import org.apache.geronimo.gshell.console.Console;
28  import org.apache.geronimo.gshell.console.JLineConsole;
29  import org.apache.geronimo.gshell.console.completer.AggregateCompleter;
30  import org.apache.geronimo.gshell.io.Closer;
31  import org.apache.geronimo.gshell.io.IO;
32  import org.apache.geronimo.gshell.notification.ExitNotification;
33  import org.apache.geronimo.gshell.shell.ShellContext;
34  import org.apache.geronimo.gshell.shell.ShellContextHolder;
35  import org.apache.geronimo.gshell.registry.CommandResolver;
36  import org.apache.geronimo.gshell.application.Application;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  import java.io.IOException;
41  import java.io.InputStream;
42  import java.io.OutputStream;
43  import java.util.List;
44  import java.util.Map;
45  
46  /**
47   * SSHD {@link ShellFactory} which provides access to GShell.
48   *
49   * @version $Rev: 731517 $ $Date: 2009-01-05 11:25:19 +0100 (Mon, 05 Jan 2009) $
50   */
51  public class ShellFactoryImpl
52      implements ShellFactory
53  {
54      private final Logger log = LoggerFactory.getLogger(getClass());
55  
56      private Application application;
57  
58      private Console.Prompter prompter;
59  
60      private CommandLineExecutor executor;
61  
62      private History history;
63  
64      private List<Completor> completers;
65  
66      private Console.ErrorHandler errorHandler;
67  
68      public Console.Prompter getPrompter() {
69          return prompter;
70      }
71  
72      public void setPrompter(final Console.Prompter prompter) {
73          this.prompter = prompter;
74      }
75  
76      public CommandLineExecutor getExecutor() {
77          return executor;
78      }
79  
80      public void setExecutor(final CommandLineExecutor executor) {
81          this.executor = executor;
82      }
83  
84      public History getHistory() {
85          return history;
86      }
87  
88      public void setHistory(final History history) {
89          this.history = history;
90      }
91  
92      public List<Completor> getCompleters() {
93          return completers;
94      }
95  
96      public void setCompleters(final List<Completor> completers) {
97          this.completers = completers;
98      }
99  
100     public Console.ErrorHandler getErrorHandler() {
101         return errorHandler;
102     }
103 
104     public void setErrorHandler(final Console.ErrorHandler errorHandler) {
105         this.errorHandler = errorHandler;
106     }
107 
108     public Application getApplication() {
109         return application;
110     }
111 
112     public void setApplication(Application application) {
113         this.application = application;
114     }
115 
116     public Shell createShell() {
117         return new ShellImpl();
118     }
119 
120     public class ShellImpl
121         implements ShellFactory.DirectShell, org.apache.geronimo.gshell.shell.Shell, ShellContext, Runnable
122     {
123         private InputStream in;
124 
125         private OutputStream out;
126 
127         private OutputStream err;
128 
129         private ExitCallback callback;
130 
131         private IO io;
132 
133         private Variables variables;
134 
135         private boolean closed;
136 
137         public void setInputStream(final InputStream in) {
138             this.in = in;
139         }
140 
141         public void setOutputStream(final OutputStream out) {
142             this.out = out;
143         }
144 
145         public void setErrorStream(final OutputStream err) {
146             this.err = err;
147         }
148 
149         public void setExitCallback(ExitCallback callback) {
150             this.callback = callback;
151         }
152 
153         public void start(final Map<String,String> env) throws IOException {
154             this.io = new IO(in, out, err, false);
155 
156             // Create variables, inheriting the application ones
157             this.variables = new Variables(application.getVariables());
158             // Set up additional env
159             if (env != null) {
160                 for (Map.Entry<String,String> entry : env.entrySet()) {
161                     this.variables.set(entry.getKey(), entry.getValue());
162                 }
163             }
164             this.variables.set("gshell.prompt", application.getModel().getBranding().getPrompt());
165             this.variables.set(CommandResolver.GROUP, "/");
166             this.variables.set("gshell.username", env.get("USER"));
167             this.variables.set("gshell.hostname", application.getLocalHost());
168             // HACK: Add history for the 'history' command, since its not part of the Shell intf it can't really access it
169             this.variables.set("gshell.internal.history", getHistory(), true);
170             new Thread(this).start();
171         }
172 
173         public void destroy() {
174             close();
175         }
176 
177         public ShellContext getContext() {
178             return this;
179         }
180 
181         public Object execute(final String line) throws Exception {
182 
183             return executor.execute(getContext(), line);
184         }
185 
186         public Object execute(final String command, final Object[] args) throws Exception {
187             return executor.execute(getContext(), args);
188         }
189 
190         public Object execute(final Object... args) throws Exception {
191             return executor.execute(getContext(), args);
192         }
193 
194         public boolean isOpened() {
195             return !closed;
196         }
197 
198         public void close() {
199             closed = true;
200             Closer.close(in, out, err);
201             callback.onExit(0);
202         }
203 
204         public boolean isInteractive() {
205             return false;
206         }
207 
208         public void run(final Object... args) throws Exception {
209             Console.Executor executor = new Console.Executor()
210             {
211                 public Result execute(final String line) throws Exception {
212                     assert line != null;
213                     try {
214                         ShellImpl.this.execute(line);
215                     }
216                     catch (ExitNotification n) {
217                         return Result.STOP;
218                     }
219                     return Result.CONTINUE;
220                 }
221             };
222 
223             IO io = getContext().getIo();
224 
225             // Setup the console runner
226             JLineConsole console = new JLineConsole(executor, io);
227             console.setPrompter(getPrompter());
228             console.setErrorHandler(getErrorHandler());
229             console.setHistory(getHistory());
230 
231             if (completers != null) {
232                 // Have to use aggregate here to get the completion list to update properly
233                 console.addCompleter(new AggregateCompleter(completers));
234             }
235             
236             console.run();
237         }
238 
239         public org.apache.geronimo.gshell.shell.Shell getShell() {
240             return this;
241         }
242 
243         public IO getIo() {
244             return io;
245         }
246 
247         public Variables getVariables() {
248             return variables;
249         }
250 
251         public void run() {
252             ShellContext ctx = ShellContextHolder.get(true);
253 
254             try {
255                 ShellContextHolder.set(getContext());
256                 run(new Object[0]);
257             }
258             catch (Exception e) {
259                 log.error("Unhandled failure: " + e, e);
260             }
261             finally {
262                 ShellContextHolder.set(ctx);
263                 close();
264             }
265         }
266     }
267 }