blob: 0b987f47b04dfcc472871952bd6487e0a15c9a67 [file] [log] [blame]
Richard S. Hall677f5892007-07-10 15:29:11 +00001<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2<html><head><title>Apache Felix</title>
3
4
5
6
7 <link rel="stylesheet" href="apache-felix-shell-service_files/site.css" type="text/css" media="all">
8 <link rel="stylesheet" href="apache-felix-shell-service_files/print.css" type="text/css" media="print">
9 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></head><body linkifytime="77" linkified="1" linkifying="false">
10 <div class="title">
11 <img alt="Logo" src="apache-felix-shell-service_files/apache-felix-small.png" align="right">
12 </div>
13 <div class="menu">
14 <ul>
15 <li><a href="http://cwiki.apache.org/FELIX/index.html">home</a></li>
16 <li><a href="http://cwiki.apache.org/FELIX/news.html">news</a></li>
17 <li><a href="http://cwiki.apache.org/FELIX/status.html">status</a></li>
18 <li><a href="http://cwiki.apache.org/FELIX/license.html">license</a></li>
19 <li><a href="http://cwiki.apache.org/FELIX/downloads.html">downloads</a></li>
20 <li><a href="http://cwiki.apache.org/FELIX/documentation.html">documentation</a></li>
21 <li><a href="http://cwiki.apache.org/FELIX/committers.html">committers</a></li>
22 <li><a href="http://cwiki.apache.org/FELIX/mailinglists.html">mailing lists</a></li>
23 <li><a href="http://cwiki.apache.org/FELIX/faq.html">faq</a></li>
24 <li><a href="http://cwiki.apache.org/FELIX/roadmap.html">roadmap</a></li>
25 <li><a href="http://cwiki.apache.org/FELIX/sourcecode.html">source code</a></li>
26 <li><a href="http://cwiki.apache.org/FELIX/codingstandards.html">coding standards</a></li>
27 <li><a href="http://cwiki.apache.org/FELIX/issuetracking.html">issue tracking</a></li>
28 <li><a href="http://cwiki.apache.org/FELIX/dependencies.html">dependencies</a></li>
29 </ul>
30 </div>
31 <div class="main">
32<h1><a name="ApacheFelixShellService-ApacheFelixShellService"></a>Apache Felix Shell Service</h1>
33
34<ul>
35 <li><a href="#ApacheFelixShellService-overview" title="overview on Apache Felix Shell Service">Overview</a></li>
36 <li><a href="#ApacheFelixShellService-service" title="service on Apache Felix Shell Service">How the Shell Service Works</a></li>
37 <li><a href="#ApacheFelixShellService-commands" title="commands on Apache Felix Shell Service">How Commands Work</a></li>
38 <li><a href="#ApacheFelixShellService-creating" title="creating on Apache Felix Shell Service">Creating a Command</a></li>
39 <li><a href="#ApacheFelixShellService-security" title="security on Apache Felix Shell Service">Security and the Shell Service</a></li>
40 <li><a href="#ApacheFelixShellService-feedback" title="feedback on Apache Felix Shell Service">Feedback</a></li>
41</ul>
42
43
44<p><a name="ApacheFelixShellService-overview"></a></p>
45
46<h2><a name="ApacheFelixShellService-Overview"></a>Overview</h2>
47
48<p>In order to interact with Felix it is necessary to have some sort of
49interactive shell that allows you to issue commands to the framework
50and to obtain information from it. The OSGi specification does not
51define how an OSGi framework should provide this interactivity. Felix
52defines a shell service for creating and executing arbitrary commands.
53The shell service does not define a user interface, only a service API.</p>
54
55<p>The benefit of the Felix shell service approach is that it is possible to:</p>
56
57<ul>
58 <li>have multiple shell user interfaces (e.g., textual and graphical),</li>
59 <li>add custom commands to the shell (i.e., bundles can make commands available via the shell service), and</li>
60 <li>use the shell service from other bundles/services.</li>
61</ul>
62
63
64<p>The remainder of this document describes how the shell service works
65and how to create custom commands for it. This document does not
66describe how to use the command shell, nor does it describe the
67text-based or GUI-based user interfaces that are available for the
68shell.</p>
69
70<p><a name="ApacheFelixShellService-service"></a></p>
71
72<h2><a name="ApacheFelixShellService-HowtheShellServiceWorks"></a>How the Shell Service Works</h2>
73
74<p>The Felix shell service is intended to be a simple, but extensible
75shell service that can have multiple user interface implementations,
76all of which are independent from the Felix framework. The shell
77service is currently not intended to be sophisticated, rather it is
78just a mechanism to execute commands. The shell service maintains a
79list of command services, each of which have a unique command name. The
80shell service is defined by the following service interface:</p>
81
82<div class="code"><div class="codeContent">
83<pre class="code-java"><span class="code-keyword">package</span> org.apache.felix.shell;
84
85<span class="code-keyword">public</span> <span class="code-keyword">interface</span> ShellService
86{
87 <span class="code-keyword">public</span> <span class="code-object">String</span>[] getCommands();
88 <span class="code-keyword">public</span> <span class="code-object">String</span> getCommandUsage(<span class="code-object">String</span> name);
89 <span class="code-keyword">public</span> <span class="code-object">String</span> getCommandDescription(<span class="code-object">String</span> name);
90 <span class="code-keyword">public</span> ServiceReference getCommandReference(<span class="code-object">String</span> name);
91 <span class="code-keyword">public</span> void executeCommand(
92 <span class="code-object">String</span> commandLine, PrintStream out, PrintStream err)
93 <span class="code-keyword">throws</span> Exception;
94}</pre>
95</div></div>
96
97<p>Using the shell service interface, it is possible to access and
98execute available commands. The shell service methods perform the
99following functions:</p>
100
101<ul>
102 <li><tt>getCommands()</tt> - returns an array of strings that correspond to the names of the installed shell commands.</li>
103 <li><tt>getCommandUsage()</tt> - returns the command usage string for a particular command name</li>
104 <li><tt>getCommandDescription()</tt> - returns a short description for a particular command name.</li>
105 <li><tt>getCommandReference()</tt> - returns the service reference for a particular command name.</li>
106 <li><tt>executeCommand()</tt> - executes a particular command using the specified command line and print streams.</li>
107</ul>
108
109
110<p>Most of the shell service methods require no explanation except for
111the executeCommand() method. Even though this method is the most
112complex, it is still fairly simplistic. The assumption of the shell
113service is that a command line will be typed by the user (or perhaps
114constructed by a GUI) and passed into it for execution. The shell
115service interprets the command line in a very simplistic fashion; it
116takes the leading string of characters terminated by a space character
117(not including it) and assumes that this leading token is the command
118name. Consider the following command line:</p>
119
120<div class="preformatted"><div class="preformattedContent">
121<pre>update 3 <a style="color: rgb(0, 102, 32); background-color: rgb(255, 249, 171);" class="linkification-ext" href="http://www.foo.com/bar.jar" title="Linkification: http://www.foo.com/bar.jar">http://www.foo.com/bar.jar</a>
122</pre>
123</div></div>
124
125<p>The shell service interprets this as an <tt>update</tt> command and
126will search for a command service with the same name. If a
127corresponding command service is not found, then it will print an error
128message to the error print stream. If a corresponding command service
129is found, then it will pass the entire command line string and the
130print streams into the <tt>executeCommand()</tt> method of the command service (for a more detailed description of command services, see the next section).</p>
131
132<p>Notice that there is no method to add commands to the shell service
133interface. This is because commands are implemented as OSGi services
134and the shell service listens for service events and when a command
135service registers/unregisters it automatically updates its list of
136commands accordingly.</p>
137
138<p><a name="ApacheFelixShellService-commands"></a></p>
139
140<h2><a name="ApacheFelixShellService-HowCommandsWork"></a>How Commands Work</h2>
141
142<p>All commands available in the shell service are implemented as OSGi
143services. The advantage of this approach is two-fold: the shell service
144can leverage OSGi service events to maintain its list of available
145commands and the set available commands is dynamically extendable by
146installed bundles. The command service interface is defined as follows:</p>
147
148<div class="code"><div class="codeContent">
149<pre class="code-java"><span class="code-keyword">package</span> org.ungoverned.osgi.service.shell;
150
151<span class="code-keyword">public</span> <span class="code-keyword">interface</span> Command
152{
153 <span class="code-keyword">public</span> <span class="code-object">String</span> getName();
154 <span class="code-keyword">public</span> <span class="code-object">String</span> getUsage();
155 <span class="code-keyword">public</span> <span class="code-object">String</span> getShortDescription();
156 <span class="code-keyword">public</span> void execute(<span class="code-object">String</span> line, PrintStream out, PrintStream err);
157}</pre>
158</div></div>
159
160<p>The semantics of the command service methods are:</p>
161
162<ul>
163 <li><tt>getName()</tt> - returns the name of the command; this must not contain whitespace and must be unique.</li>
164 <li><tt>getUsage()</tt>
165- returns the usage string of the command; this should be one line and
166as short as possible (this is used for generating the help command
167output).</li>
168 <li><tt>getShortDescription()</tt> - returns a short
169description of the command; this should be one line and as short as
170possible (this is used for generating the help command output).</li>
171 <li><tt>execute()</tt> - executes the command's functionality using supplied command line and print streams.</li>
172</ul>
173
174
175<p><a name="ApacheFelixShellService-creating"></a></p>
176
177<h2><a name="ApacheFelixShellService-CreatingaCommand"></a>Creating a Command</h2>
178
179<p>The following example creates a simple version of the <tt>start</tt> command.</p>
180
181<div class="code"><div class="codeContent">
182<pre class="code-java"><span class="code-keyword">package</span> test;
183
184<span class="code-keyword">import</span> java.io.PrintStream;
185<span class="code-keyword">import</span> java.net.URL;
186<span class="code-keyword">import</span> java.net.MalformedURLException;
187<span class="code-keyword">import</span> java.util.StringTokenizer;
188
189<span class="code-keyword">import</span> org.osgi.framework.*;
190<span class="code-keyword">import</span> org.apache.felix.shell.ShellService;
191<span class="code-keyword">import</span> org.apache.felix.shell.Command;
192
193<span class="code-keyword">public</span> class MyStartCommandImpl <span class="code-keyword">implements</span> Command
194{
195 <span class="code-keyword">private</span> BundleContext m_context = <span class="code-keyword">null</span>;
196
197 <span class="code-keyword">public</span> MyStartCommandImpl(BundleContext context)
198 {
199 m_context = context;
200 }
201
202 <span class="code-keyword">public</span> <span class="code-object">String</span> getName()
203 {
204 <span class="code-keyword">return</span> <span class="code-quote">"mystart"</span>;
205 }
206
207 <span class="code-keyword">public</span> <span class="code-object">String</span> getUsage()
208 {
209 <span class="code-keyword">return</span> <span class="code-quote">"mystart &lt;id&gt; [&lt;id&gt; ...]"</span>;
210 }
211
212 <span class="code-keyword">public</span> <span class="code-object">String</span> getShortDescription()
213 {
214 <span class="code-keyword">return</span> <span class="code-quote">"start bundle(s)."</span>;
215 }
216
217 <span class="code-keyword">public</span> void execute(<span class="code-object">String</span> s, PrintStream out, PrintStream err)
218 {
219 StringTokenizer st = <span class="code-keyword">new</span> StringTokenizer(s, <span class="code-quote">" "</span>);
220
221 <span class="code-comment">// Ignore the command name.
222</span> st.nextToken();
223
224 <span class="code-comment">// There should be at least one bundle id.
225</span> <span class="code-keyword">if</span> (st.countTokens() &gt;= 1)
226 {
227 <span class="code-keyword">while</span> (st.hasMoreTokens())
228 {
229 <span class="code-object">String</span> id = st.nextToken().trim();
230
231 <span class="code-keyword">try</span> {
232 <span class="code-object">long</span> l = <span class="code-object">Long</span>.valueOf(id).longValue();
233 Bundle bundle = m_context.getBundle(l);
234 <span class="code-keyword">if</span> (bundle != <span class="code-keyword">null</span>)
235 {
236 bundle.start();
237 }
238 <span class="code-keyword">else</span>
239 {
240 err.println(<span class="code-quote">"Bundle ID "</span> + id + <span class="code-quote">" is invalid."</span>);
241 }
242 } <span class="code-keyword">catch</span> (NumberFormatException ex) {
243 err.println(<span class="code-quote">"Unable to parse id '"</span> + id + <span class="code-quote">"'."</span>);
244 } <span class="code-keyword">catch</span> (BundleException ex) {
245 <span class="code-keyword">if</span> (ex.getNestedException() != <span class="code-keyword">null</span>)
246 err.println(ex.getNestedException().toString());
247 <span class="code-keyword">else</span>
248 err.println(ex.toString());
249 } <span class="code-keyword">catch</span> (Exception ex) {
250 err.println(ex.toString());
251 }
252 }
253 }
254 <span class="code-keyword">else</span>
255 {
256 err.println(<span class="code-quote">"Incorrect number of arguments"</span>);
257 }
258 }
259}</pre>
260</div></div>
261
262<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>
263
264<div class="code"><div class="codeContent">
265<pre class="code-java"><span class="code-keyword">package</span> test;
266
267<span class="code-keyword">import</span> org.osgi.framework.BundleActivator;
268<span class="code-keyword">import</span> org.osgi.framework.BundleContext;
269
270<span class="code-keyword">public</span> class MyStartActivator <span class="code-keyword">implements</span> BundleActivator
271{
272 <span class="code-keyword">private</span> <span class="code-keyword">transient</span> BundleContext m_context = <span class="code-keyword">null</span>;
273
274 <span class="code-keyword">public</span> void start(BundleContext context)
275 {
276 m_context = context;
277
278 <span class="code-comment">// Register the command service.
279</span> context.registerService(
280 org.apache.felix.shell.Command.class.getName(),
281 <span class="code-keyword">new</span> MyStartCommandImpl(m_context), <span class="code-keyword">null</span>);
282 }
283
284 <span class="code-keyword">public</span> void stop(BundleContext context)
285 {
286 <span class="code-comment">// Services are automatically unregistered so
287</span> <span class="code-comment">// we don't have to unregister the factory here.
288</span> }
289}</pre>
290</div></div>
291
292<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>
293
294<div class="preformatted"><div class="preformattedContent">
295<pre>java -d c:\classes *.java
296</pre>
297</div></div>
298
299<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>
300directory must exist. Once you have compiled all of the above classes,
301you need to create a bundle JAR file of the generated package
302directory. The bundle JAR file needs a manifest, so create a file
303called <tt>manifest.mf</tt> with the following contents:</p>
304
305<div class="code"><div class="codeContent">
306<pre class="code-java">Bundle-Name: My Start Command
307Bundle-Description: A 'start' command <span class="code-keyword">for</span> the shell service.
308Bundle-Activator: test.MyStartActivator
309Bundle-ClassPath: .
310Import-Package: org.apache.felix.shell</pre>
311</div></div>
312
313<p>To create the bundle JAR file, issue the command:</p>
314
315<div class="preformatted"><div class="preformattedContent">
316<pre>jar cfm mystart.jar manifest.mf -C c:\classes test
317</pre>
318</div></div>
319
320<p>This command creates a JAR file using the manifest you created and
321includes all of the classes in the test directory inside of the <tt>c:\classes</tt>
322directory. Once the bundle JAR file is created, you are ready to add
323the command service to the shell service; simply start Felix and
324install and start the bundle created by the above command. By doing so,
325the new <tt>mystart</tt> command is made available via the shell service.</p>
326
327<p><a name="ApacheFelixShellService-security"></a></p>
328
329<h2><a name="ApacheFelixShellService-SecurityandtheShellService"></a>Security and the Shell Service</h2>
330
331<p>The shell service security handling is quite simple, all security is
332handled by the standard OSGi framework mechanisms. For example, if a
333bundle should not be able to register a shell service, then it should
334not be given the corresponding service permission. Security handling
335may change in future release after some experience is gained through
336usage.</p>
337
338<p><a name="ApacheFelixShellService-feedback"></a></p>
339
340<h2><a name="ApacheFelixShellService-Feedback"></a>Feedback</h2>
341
342<p>Subscribe to the Felix users mailing list by sending a message to <span class="nobr"><a href="mailto:users-subscribe@felix.apache.org" title="Send mail to users-subscribe@felix.apache.org" rel="nofollow">users-subscribe@felix.apache.org<sup><img class="rendericon" src="apache-felix-shell-service_files/mail_small.gif" alt="" align="absmiddle" border="0" height="12" width="13"></sup></a></span>; after subscribing, email questions or feedback to <span class="nobr"><a href="mailto:users@felix.apache.org" title="Send mail to users@felix.apache.org" rel="nofollow">users@felix.apache.org<sup><img class="rendericon" src="apache-felix-shell-service_files/mail_small.gif" alt="" align="absmiddle" border="0" height="12" width="13"></sup></a></span>.</p>
343 </div>
344
345</body></html>