blob: f2198d856bb470aeb84f612d5b271f9bb4578719 [file] [log] [blame]
Karl Paulsc6eda452010-02-14 22:52:56 +00001<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2<html><head>
3
4
5
6 <title>Apache Felix - Apache Felix Shell Service</title>
7 <link rel="stylesheet" href="apache-felix-shell-service_files/site.css" type="text/css" media="all">
8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
9 </head><body>
10 <div class="title"><div class="logo"><a href="http://felix.apache.org/site/index.html"><img alt="Apache Felix" src="apache-felix-shell-service_files/logo.png" border="0"></a></div><div class="header"><a href="http://www.apache.org/"><img alt="Apache" src="apache-felix-shell-service-Dateien/apache.png" border="0"></a></div></div>
11 <div class="menu">
12<ul>
13 <li><a href="http://felix.apache.org/site/news.html" title="news">news</a></li>
14 <li><a href="http://felix.apache.org/site/license.html" title="license">license</a></li>
15 <li><a href="http://felix.apache.org/site/downloads.cgi" rel="nofollow">downloads</a></li>
16 <li><a href="http://felix.apache.org/site/documentation.html" title="documentation">documentation</a></li>
17 <li><a href="http://felix.apache.org/site/mailinglists.html" title="mailinglists">mailing lists</a></li>
18 <li><a href="http://felix.apache.org/site/contributing.html" title="Contributing">contributing</a></li>
19 <li><a href="http://www.apache.org/" rel="nofollow">asf</a></li>
20 <li><a href="http://www.apache.org/foundation/sponsorship.html" rel="nofollow">sponsorship</a></li>
21 <li><a href="http://www.apache.org/foundation/thanks.html" rel="nofollow">sponsors</a>
22<!-- ApacheCon Ad -->
23<iframe src="apache-felix-shell-service_files/button.html" style="border-width: 0pt; float: left;" frameborder="0" height="135" scrolling="no" width="135"></iframe>
24<p style="height: 100px;">
25<!-- ApacheCon Ad -->
26</p></li></ul> </div>
27 <div class="main">
28<h1><a name="ApacheFelixShellService-ApacheFelixShellService"></a>Apache Felix Shell Service</h1>
29
30<ul>
31 <li><a href="#ApacheFelixShellService-overview">Overview</a></li>
32 <li><a href="#ApacheFelixShellService-service">How the Shell Service Works</a></li>
33 <li><a href="#ApacheFelixShellService-commands">How Commands Work</a></li>
34 <li><a href="#ApacheFelixShellService-creating">Creating a Command</a></li>
35 <li><a href="#ApacheFelixShellService-security">Security and the Shell Service</a></li>
36 <li><a href="#ApacheFelixShellService-feedback">Feedback</a></li>
37</ul>
38
39
40<p><a name="ApacheFelixShellService-overview"></a></p>
41
42<h2><a name="ApacheFelixShellService-Overview"></a>Overview</h2>
43
44<p>In order to interact with Felix it is necessary to have some sort of
45interactive shell that allows you to issue commands to the framework
46and to obtain information from it. The OSGi specification does not
47define how an OSGi framework should provide this interactivity. Felix
48defines a shell service for creating and executing arbitrary commands.
49The shell service does not define a user interface, only a service API.</p>
50
51<p>The benefit of the Felix shell service approach is that it is possible to:</p>
52
53<ul>
54 <li>have multiple shell user interfaces (e.g., textual and graphical),</li>
55 <li>add custom commands to the shell (i.e., bundles can make commands available via the shell service), and</li>
56 <li>use the shell service from other bundles/services.</li>
57</ul>
58
59
60<p>The remainder of this document describes how the shell service works
61and how to create custom commands for it. This document does not
62describe how to use the command shell, nor does it describe the
63text-based or GUI-based user interfaces that are available for the
64shell.</p>
65
66<p><a name="ApacheFelixShellService-service"></a></p>
67
68<h2><a name="ApacheFelixShellService-HowtheShellServiceWorks"></a>How the Shell Service Works</h2>
69
70<p>The Felix shell service is intended to be a simple, but extensible
71shell service that can have multiple user interface implementations,
72all of which are independent from the Felix framework. The shell
73service is currently not intended to be sophisticated, rather it is
74just a mechanism to execute commands. The shell service maintains a
75list of command services, each of which have a unique command name. The
76shell service is defined by the following service interface:</p>
77
78<style type="text/css">
79@import url(/confluence/download/resources/confluence.ext.code:code/shStyles.css);
80</style>
81<!--[if IE]>
82<style type="text/css">
83 .code textarea, .code input { padding: 0 !important; }
84</style>
85<![endif]-->
86<script class="javascript" src="apache-felix-shell-service_files/shCore.js"></script>
87<script class="javascript" src="apache-felix-shell-service_files/shBrushCSharp.js"></script>
88<script class="javascript" src="apache-felix-shell-service_files/shBrushPhp.js"></script>
89<script class="javascript" src="apache-felix-shell-service_files/shBrushJScript.js"></script>
90<script class="javascript" src="apache-felix-shell-service_files/shBrushVb.js"></script>
91<script class="javascript" src="apache-felix-shell-service_files/shBrushSql.js"></script>
92<script class="javascript" src="apache-felix-shell-service_files/shBrushXml.js"></script>
93<script class="javascript" src="apache-felix-shell-service_files/shBrushShell.html"></script>
94<script class="javascript" src="apache-felix-shell-service_files/shBrushDelphi.js"></script>
95<script class="javascript" src="apache-felix-shell-service_files/shBrushPython.js"></script>
96<script class="javascript" src="apache-felix-shell-service_files/shBrushJava.js"></script>
97<div class="code">
98<textarea name="newcodemacro" class="java:nocontrols:nogutter" rows="10" readonly="readonly">package org.apache.felix.shell;
99
100public interface ShellService
101{
102 public String[] getCommands();
103 public String getCommandUsage(String name);
104 public String getCommandDescription(String name);
105 public ServiceReference getCommandReference(String name);
106 public void executeCommand(
107 String commandLine, PrintStream out, PrintStream err)
108 throws Exception;
109}</textarea>
110<script class="javascript">
111 if(!window.newcodemacro_initialised)
112 {
113 window.newcodemacro_initialised = true;
114 window.oldonloadmethod = window.onload;
115 window.onload = function(){
116 dp.SyntaxHighlighter.HighlightAll('newcodemacro');
117 if(window.oldonloadmethod)
118 {
119 window.oldonloadmethod();
120 }
121 }
122 }
123
124</script>
125</div>
126
127
128<p>Using the shell service interface, it is possible to access and
129execute available commands. The shell service methods perform the
130following functions:</p>
131
132<ul>
133 <li><tt>getCommands()</tt> - returns an array of strings that correspond to the names of the installed shell commands.</li>
134 <li><tt>getCommandUsage()</tt> - returns the command usage string for a particular command name</li>
135 <li><tt>getCommandDescription()</tt> - returns a short description for a particular command name.</li>
136 <li><tt>getCommandReference()</tt> - returns the service reference for a particular command name.</li>
137 <li><tt>executeCommand()</tt> - executes a particular command using the specified command line and print streams.</li>
138</ul>
139
140
141<p>Most of the shell service methods require no explanation except for
142the executeCommand() method. Even though this method is the most
143complex, it is still fairly simplistic. The assumption of the shell
144service is that a command line will be typed by the user (or perhaps
145constructed by a GUI) and passed into it for execution. The shell
146service interprets the command line in a very simplistic fashion; it
147takes the leading string of characters terminated by a space character
148(not including it) and assumes that this leading token is the command
149name. Consider the following command line:</p>
150
151<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
152<pre>update 3 http://www.foo.com/bar.jar
153</pre>
154</div></div>
155
156<p>The shell service interprets this as an <tt>update</tt> command and
157will search for a command service with the same name. If a
158corresponding command service is not found, then it will print an error
159message to the error print stream. If a corresponding command service
160is found, then it will pass the entire command line string and the
161print streams into the <tt>executeCommand()</tt> method of the command service (for a more detailed description of command services, see the next section).</p>
162
163<p>Notice that there is no method to add commands to the shell service
164interface. This is because commands are implemented as OSGi services
165and the shell service listens for service events and when a command
166service registers/unregisters it automatically updates its list of
167commands accordingly.</p>
168
169<p><a name="ApacheFelixShellService-commands"></a></p>
170
171<h2><a name="ApacheFelixShellService-HowCommandsWork"></a>How Commands Work</h2>
172
173<p>All commands available in the shell service are implemented as OSGi
174services. The advantage of this approach is two-fold: the shell service
175can leverage OSGi service events to maintain its list of available
176commands and the set available commands is dynamically extendable by
177installed bundles. The command service interface is defined as follows:</p>
178
179<div class="code">
180<textarea name="newcodemacro" class="java:nocontrols:nogutter" rows="10" readonly="readonly">package org.apache.felix.shell;
181
182public interface Command
183{
184 public String getName();
185 public String getUsage();
186 public String getShortDescription();
187 public void execute(String line, PrintStream out, PrintStream err);
188}</textarea>
189<script class="javascript">
190 if(!window.newcodemacro_initialised)
191 {
192 window.newcodemacro_initialised = true;
193 window.oldonloadmethod = window.onload;
194 window.onload = function(){
195 dp.SyntaxHighlighter.HighlightAll('newcodemacro');
196 if(window.oldonloadmethod)
197 {
198 window.oldonloadmethod();
199 }
200 }
201 }
202
203</script>
204</div>
205
206
207<p>The semantics of the command service methods are:</p>
208
209<ul>
210 <li><tt>getName()</tt> - returns the name of the command; this must not contain whitespace and must be unique.</li>
211 <li><tt>getUsage()</tt>
212- returns the usage string of the command; this should be one line and
213as short as possible (this is used for generating the help command
214output).</li>
215 <li><tt>getShortDescription()</tt> - returns a short
216description of the command; this should be one line and as short as
217possible (this is used for generating the help command output).</li>
218 <li><tt>execute()</tt> - executes the command's functionality using supplied command line and print streams.</li>
219</ul>
220
221
222<p><a name="ApacheFelixShellService-creating"></a></p>
223
224<h2><a name="ApacheFelixShellService-CreatingaCommand"></a>Creating a Command</h2>
225
226<p>The following example creates a simple version of the <tt>start</tt> command.</p>
227
228<div class="code">
229<textarea name="newcodemacro" class="java:nocontrols:nogutter" rows="10" readonly="readonly">package test;
230
231import java.io.PrintStream;
232import java.net.URL;
233import java.net.MalformedURLException;
234import java.util.StringTokenizer;
235
236import org.osgi.framework.*;
237import org.apache.felix.shell.ShellService;
238import org.apache.felix.shell.Command;
239
240public class MyStartCommandImpl implements Command
241{
242 private BundleContext m_context = null;
243
244 public MyStartCommandImpl(BundleContext context)
245 {
246 m_context = context;
247 }
248
249 public String getName()
250 {
251 return "mystart";
252 }
253
254 public String getUsage()
255 {
256 return "mystart &lt;id&gt; [&lt;id&gt; ...]";
257 }
258
259 public String getShortDescription()
260 {
261 return "start bundle(s).";
262 }
263
264 public void execute(String s, PrintStream out, PrintStream err)
265 {
266 StringTokenizer st = new StringTokenizer(s, " ");
267
268 // Ignore the command name.
269 st.nextToken();
270
271 // There should be at least one bundle id.
272 if (st.countTokens() &gt;= 1)
273 {
274 while (st.hasMoreTokens())
275 {
276 String id = st.nextToken().trim();
277
278 try {
279 long l = Long.valueOf(id).longValue();
280 Bundle bundle = m_context.getBundle(l);
281 if (bundle != null)
282 {
283 bundle.start();
284 }
285 else
286 {
287 err.println("Bundle ID " + id + " is invalid.");
288 }
289 } catch (NumberFormatException ex) {
290 err.println("Unable to parse id '" + id + "'.");
291 } catch (BundleException ex) {
292 if (ex.getNestedException() != null)
293 err.println(ex.getNestedException().toString());
294 else
295 err.println(ex.toString());
296 } catch (Exception ex) {
297 err.println(ex.toString());
298 }
299 }
300 }
301 else
302 {
303 err.println("Incorrect number of arguments");
304 }
305 }
306}</textarea>
307<script class="javascript">
308 if(!window.newcodemacro_initialised)
309 {
310 window.newcodemacro_initialised = true;
311 window.oldonloadmethod = window.onload;
312 window.onload = function(){
313 dp.SyntaxHighlighter.HighlightAll('newcodemacro');
314 if(window.oldonloadmethod)
315 {
316 window.oldonloadmethod();
317 }
318 }
319 }
320
321</script>
322</div>
323
324
325<p>A bundle activator class is needed for packaging the command servce; the bundle activator registers the command service in its <tt>start()</tt> method. Note: You do not need one activator per command, a single activator can register any number of commands.</p>
326
327<div class="code">
328<textarea name="newcodemacro" class="java:nocontrols:nogutter" rows="10" readonly="readonly">package test;
329
330import org.osgi.framework.BundleActivator;
331import org.osgi.framework.BundleContext;
332
333public class MyStartActivator implements BundleActivator
334{
335 private transient BundleContext m_context = null;
336
337 public void start(BundleContext context)
338 {
339 m_context = context;
340
341 // Register the command service.
342 context.registerService(
343 org.apache.felix.shell.Command.class.getName(),
344 new MyStartCommandImpl(m_context), null);
345 }
346
347 public void stop(BundleContext context)
348 {
349 // Services are automatically unregistered so
350 // we don't have to unregister the factory here.
351 }
352}</textarea>
353<script class="javascript">
354 if(!window.newcodemacro_initialised)
355 {
356 window.newcodemacro_initialised = true;
357 window.oldonloadmethod = window.onload;
358 window.onload = function(){
359 dp.SyntaxHighlighter.HighlightAll('newcodemacro');
360 if(window.oldonloadmethod)
361 {
362 window.oldonloadmethod();
363 }
364 }
365 }
366
367</script>
368</div>
369
370
371<p>To compile these classes you will need to have the <tt>framework.jar</tt> file on your class path. Compile all of the source files using a command like:</p>
372
373<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
374<pre>java -d c:\classes *.java
375</pre>
376</div></div>
377
378<p>This command compiles all of the source files and outputs the generated class files into a subdirectory of the <tt>c:\classes</tt> directory, called test, named after the package of the source files; for the above command to work, the <tt>c:\classes</tt>
379directory must exist. Once you have compiled all of the above classes,
380you need to create a bundle JAR file of the generated package
381directory. The bundle JAR file needs a manifest, so create a file
382called <tt>manifest.mf</tt> with the following contents:</p>
383
384<div class="code">
385<textarea name="newcodemacro" class="java:nocontrols:nogutter" rows="10" readonly="readonly">Bundle-Name: My Start Command
386Bundle-Description: A 'start' command for the shell service.
387Bundle-Activator: test.MyStartActivator
388Bundle-ClassPath: .
389Import-Package: org.apache.felix.shell</textarea>
390<script class="javascript">
391 if(!window.newcodemacro_initialised)
392 {
393 window.newcodemacro_initialised = true;
394 window.oldonloadmethod = window.onload;
395 window.onload = function(){
396 dp.SyntaxHighlighter.HighlightAll('newcodemacro');
397 if(window.oldonloadmethod)
398 {
399 window.oldonloadmethod();
400 }
401 }
402 }
403
404</script>
405</div>
406
407
408<p>To create the bundle JAR file, issue the command:</p>
409
410<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
411<pre>jar cfm mystart.jar manifest.mf -C c:\classes test
412</pre>
413</div></div>
414
415<p>This command creates a JAR file using the manifest you created and
416includes all of the classes in the test directory inside of the <tt>c:\classes</tt>
417directory. Once the bundle JAR file is created, you are ready to add
418the command service to the shell service; simply start Felix and
419install and start the bundle created by the above command. By doing so,
420the new <tt>mystart</tt> command is made available via the shell service.</p>
421
422<p><a name="ApacheFelixShellService-security"></a></p>
423
424<h2><a name="ApacheFelixShellService-SecurityandtheShellService"></a>Security and the Shell Service</h2>
425
426<p>The shell service security handling is quite simple, all security is
427handled by the standard OSGi framework mechanisms. For example, if a
428bundle should not be able to register a shell service, then it should
429not be given the corresponding service permission. Security handling
430may change in future release after some experience is gained through
431usage.</p>
432
433<p><a name="ApacheFelixShellService-feedback"></a></p>
434
435<h2><a name="ApacheFelixShellService-Feedback"></a>Feedback</h2>
436
437<p>Subscribe to the Felix users mailing list by sending a message to <a href="mailto:users-subscribe@felix.apache.org" rel="nofollow">users-subscribe@felix.apache.org</a>; after subscribing, email questions or feedback to <a href="mailto:users@felix.apache.org" rel="nofollow">users@felix.apache.org</a>.</p>
438 </div>
439 </body></html>