forked from bndtools/bndtools.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tutorial.html
417 lines (389 loc) · 29.2 KB
/
tutorial.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bndtools</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content>
<meta name="author" content>
<!-- Le styles -->
<link href="css/bootstrap.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
.sidebar-nav {
padding: 9px 0;
}
</style>
<!--<link href="css/bootstrap-responsive.css" rel="stylesheet">-->
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!-- Le fav and touch icons -->
<link rel="shortcut icon" href="images/favicon.ico">
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="./index.html"><img src="./images/logo-topbar.png"></img></a>
<!--
<div class="btn-group pull-right">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
<i class="icon-user"></i> Username
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">Profile</a></li>
<li class="divider"></li>
<li><a href="#">Sign Out</a></li>
</ul>
</div>
-->
<div class="nav-collapse">
<ul class="nav">
<li><a href="./index.html">Home</a></li>
<li><a href="./installation.html">Install</a></li>
<li><a href="./tutorial.html">Tutorial</a></li>
<li><a href="./help.html">Get Help</a></li>
<li><a href="./faq.html">FAQ</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span2">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li><a href="./">Home</a></li>
<li><a href="./licence.html">Licence</a></li>
<li><a href="./community.html">Get Involved</a></li>
<li><a href="./training.html">Training</a></li>
<li><a href="./#donate">Donate</a></li>
<li class="divider"></li>
<li class="nav-header">Documentation</li>
<li><a href="./installation.html">Installation</a></li>
<li><a href="./tutorial.html">Tutorial</a></li>
<li><a href="./concepts.html">Concepts Guide</a></li>
<li><a href="./faq.html">FAQ</a></li>
<li><a href="./whatsnew.html">What's New</a></li>
<li class="divider"></li>
<li class="nav-header">Development</h1>
<li><a class="external-left" href="https://github.com/bndtools/bndtools/issues">Bug Reports</a></li>
<li><a class="external-left" href="https://bndtools.ci.cloudbees.com/job/bndtools.master/">Build Status</a></li>
<li><a href="./development.html">Developer Guide</a></li>
<li><a href="./acknowledge.html">Acknowledgements</a></li>
</ul>
</div><!--/.well -->
</div><!--/span-->
<div class="span10">
<div class="hero-unit">
<h1>Bndtools Tutorial</h1>
<p>Introduction to component development with Bndtools.</p>
</div>
<h1 id="TOC">Table of Contents</h1><ul>
<li><a href="#introduction"><span class="toc-section-number">1</span> Introduction</a></li>
<li><a href="#installing-bndtools"><span class="toc-section-number">2</span> Installing Bndtools</a></li>
<li><a href="#create-an-api-project"><span class="toc-section-number">3</span> Create an API Project</a><ul>
<li><a href="#write-and-export-the-api"><span class="toc-section-number">3.1</span> Write and Export the API</a></li>
<li><a href="#define-the-bundle"><span class="toc-section-number">3.2</span> Define the Bundle</a></li>
</ul></li>
<li><a href="#create-an-implementation-project"><span class="toc-section-number">4</span> Create an Implementation Project</a><ul>
<li><a href="#create-the-project"><span class="toc-section-number">4.1</span> Create the Project</a></li>
<li><a href="#add-the-api-as-a-build-dependency"><span class="toc-section-number">4.2</span> Add the API as a Build Dependency</a></li>
<li><a href="#write-an-implementation"><span class="toc-section-number">4.3</span> Write an Implementation</a></li>
<li><a href="#test-the-implementation"><span class="toc-section-number">4.4</span> Test the Implementation</a></li>
<li><a href="#build-the-implementation-bundle"><span class="toc-section-number">4.5</span> Build the Implementation Bundle</a></li>
</ul></li>
<li><a href="#run-an-osgi-framework"><span class="toc-section-number">5</span> Run an OSGi Framework</a></li>
<li><a href="#write-a-command-component"><span class="toc-section-number">6</span> Write a Command Component</a><ul>
<li><a href="#create-a-bundle-for-the-command-component"><span class="toc-section-number">6.1</span> Create a Bundle for the Command Component</a></li>
<li><a href="#add-the-command-bundle-to-the-runtime"><span class="toc-section-number">6.2</span> Add the Command Bundle to the Runtime</a></li>
</ul></li>
</ul>
<h1 id="introduction"><a href="#TOC"><span class="header-section-number">1</span> Introduction</a></h1>
<p>In this tutorial we will build a sample application composed of two components and an API. The following diagram shows the bundle architecture (simplified):</p>
<div class="figure">
<img src="./images/tutorial/bundles.png"></img><p class="caption"></p>
</div>
<p>In the tutorial we create the top three bundles (rectangles):</p>
<ul>
<li>The API bundle exports a service interface, <code>Greeting</code>.</li>
<li>The Provider bundle imports the interface and publishes an instance of the service.</li>
<li>The Command bundle imports the interface and binds to the service instance, and also publishes a <code>Command</code> service that is used by the Felix Shell bundle.</li>
</ul>
<h1 id="installing-bndtools"><a href="#TOC"><span class="header-section-number">2</span> Installing Bndtools</a></h1>
<p>Please refer to the <a href="installation.html">Installation Instructions</a>.</p>
<h1 id="create-an-api-project"><a href="#TOC"><span class="header-section-number">3</span> Create an API Project</a></h1>
<p>First we need to create a Bndtools OSGi Project. This is just a standard Eclipse Java Project, with an additional builder for constructing OSGi bundles.</p>
<ol style="list-style-type: decimal">
<li><p>From the File menu, select <strong>New -> Bndtools OSGi Project</strong>.</p>
<div class="figure">
<img src="./images/tutorial/01.png"></img><p class="caption"></p>
</div></li>
<li><p>On the next page, enter <code>org.example.api</code> as the name of the project. Select at least J2SE-1.5 for the JRE execution environment.</p>
<div class="figure">
<img src="./images/tutorial/02.png"></img><p class="caption"></p>
</div></li>
<li><p>Next you are offered a choice of project templates to start off your project. Select <strong>Empty Project</strong> and click <strong>Finish</strong>. The new project will be created.</p>
<div class="figure">
<img src="./images/tutorial/03.png"></img><p class="caption"></p>
</div></li>
<li><p>If this is the first time you have used Bndtools in this workspace, you will now see the “Welcome” dialog. Click <strong>Next</strong> followed by <strong>Finish</strong> to allow Bndtools to setup a configuration project and import a basic repository. A repository is a place where bundles that you use in your projects are stored. A remote “BndTools hub” repository is created by default that contains some often used bundles.</p>
<div class="figure">
<img src="./images/tutorial/04.png"></img><p class="caption"></p>
</div>
<div class="figure">
<img src="./images/tutorial/05.png"></img><p class="caption"></p>
</div></li>
</ol>
<p><em>Important Points:</em></p>
<ul>
<li>Bndtools projects are based on standard Eclipse Java (JDT) projects.</li>
<li>Bndtools uses a <code>cnf</code> project containing workspace-wide configuration that is normally shared between developers. It may also contain a repository of bundles.</li>
<li>A file named <code>bnd.bnd</code> is created at the top of each Bndtools project, which controls the settings for the project. The same settings are used by bnd when it is invoked from an offline ANT build.</li>
</ul>
<h2 id="write-and-export-the-api"><a href="#TOC"><span class="header-section-number">3.1</span> Write and Export the API</a></h2>
<p>OSGi offers strong decoupling of producers and consumers of functionality. This is done by encouraging an API-based (or in Java terms, interface-based) programming model, where producers of functionality implement APIs and the consumers of functionality bind only to APIs, not any particular implementation. For our example we will use a fairly trivial API.</p>
<p>In the <code>src</code> directory of the new project, create a package named <code>org.example.api</code>. In the new package create a Java interface named <code>Greeting</code>, as follows:</p>
<pre class="sourceCode Java"><code class="sourceCode java"><span class="kw">package org.example.api;</span>
<span class="kw">public</span> <span class="kw">interface</span> Greeting {
String <span class="fu">sayHello</span>(String name);
}</code></pre>
<h2 id="define-the-bundle"><a href="#TOC"><span class="header-section-number">3.2</span> Define the Bundle</a></h2>
<p>The project we have created defines a single bundle with a Bundle Symbolic Name (BSN) of <code>org.example.api</code> (i.e., the same as the project name). As soon as we created the project, a bundle file named <code>org.example.api.jar</code> was created in the <code>generated</code> directory, and it will be rebuilt every time we change the bundle definition or its source code.</p>
<p>However, the bundle is currently empty, because we have not defined any Java packages to include in the bundle. This is an important difference of Bndtools with respect to other tools: bundles are always empty until we explicitly add some content. You can verify this by double-clicking the bundle file and viewing its contents: it will only have an <code>META-INF/MANIFEST.MF</code> entry.</p>
<p>We want to add the package <code>org.example.api</code> to the exported packages of the bundle. So open the <code>bnd.bnd</code> file at the top of the project and select the <strong>Contents</strong> tab. Now the package can be added in one of two ways:</p>
<ul>
<li>Click the “+” icon in the header of the <strong>Export Packages</strong> section, then select <code>org.example.api</code> from the dialog and click <strong>OK</strong>… <em>or</em></li>
<li>Drag-and-drop the package <code>org.example.api</code> from Eclipse’s Package Explorer view into the <strong>Export Packages</strong> list.</li>
</ul>
<p>(TIP: Advanced users may prefer to enter <code>Export-Package: org.example.api</code> manually in the <strong>Source</strong> tab).</p>
<p>As soon as this is done, a popup dialog appears titled “Missing Package Info”. This dialog is related to package versioning: it is asking us to declare the version of this exported package. Click <strong>OK</strong>.</p>
<div class="figure">
<img src="./images/tutorial/06.png"></img><p class="caption"></p>
</div>
<p>The <strong>Contents</strong> tab should now appear as in the following screenshot:</p>
<div class="figure">
<img src="./images/tutorial/07.png"></img><p class="caption"></p>
</div>
<p>Save the file, and the bundle will be rebuilt to include the selected export. We can confirm by opening the <strong>Imports/Exports</strong> view and selecting the bundle file in the <strong>Package Explorer</strong>. Note the package has been assigned version 1.0.0:</p>
<div class="figure">
<img src="./images/tutorial/08.png"></img><p class="caption"></p>
</div>
<p><em>Important Points:</em></p>
<ul>
<li>The project configuration and the bundle contents are defined by <code>bnd.bnd</code>.</li>
<li>The identity of a bundle – its “Bundle Symbolic Name” or BSN – is controlled by the project name. In this case, the bundle’s BSN is equal to the project name.</li>
<li>Bundles are always empty until we explicitly add contents to them. Adding a package to the <strong>Export Packages</strong> panel included that package in the bundle, and also declared it as an export in the <code>META-INF/MANIFEST.MF</code>.</li>
<li><em>Normally</em> bundles contain more than just a single interface. This example is intentionally simplistic.</li>
</ul>
<h1 id="create-an-implementation-project"><a href="#TOC"><span class="header-section-number">4</span> Create an Implementation Project</a></h1>
<p>We will now create another project that defines two bundles: a provider and a client of the <code>Greeting</code> API.</p>
<h2 id="create-the-project"><a href="#TOC"><span class="header-section-number">4.1</span> Create the Project</a></h2>
<p>Create another Bndtools project, named <code>org.example.impls</code>. At the <strong>Project Templates</strong> step, select <strong>Component Development (Declarative Services)</strong> and click <strong>Finish</strong>.</p>
<div class="figure">
<img src="./images/tutorial/09.png"></img><p class="caption"></p>
</div>
<h2 id="add-the-api-as-a-build-dependency"><a href="#TOC"><span class="header-section-number">4.2</span> Add the API as a Build Dependency</a></h2>
<p>We need to add the API project as a build-time dependency of this new project.</p>
<p>The <code>bnd.bnd</code> file of the newly created project will have opened automatically. Click the <strong>Build</strong> tab and add <code>org.example.api</code> in either of the following ways:</p>
<ul>
<li><p>Click the “+” icon in the toolbar of the <strong>Build Path</strong> panel. Double-click <code>org.example.api</code> under “Workspace” in the resulting dialog; it will move over to the right-hand side. Click <strong>Finish</strong></p>
<div class="figure">
<img src="./images/tutorial/10.png"></img><p class="caption"></p>
</div></li>
<li><p><strong>OR</strong> drag-and-drop <code>org.example.api</code> from the <strong>Repositories</strong> view into the <strong>Build Path</strong> panel.</p></li>
</ul>
<p>In either case, the <code>org.example.api</code> bundle will appear in the <strong>Build Path</strong> panel with the version annotation “latest”:</p>
<div class="figure">
<img src="./images/tutorial/11.png"></img><p class="caption"></p>
</div>
<p>Save the file.</p>
<p><em>Important Points:</em></p>
<ul>
<li>Build-time dependencies of the project can be added in the <strong>Build Path</strong> panel of the <code>bnd.bnd</code> editor.</li>
<li>Adding dependencies in this way (i.e. rather than via Eclipse’s existing “Add to Build Path” menu) ensures that exactly the same dependencies are used when building offline with ANT.</li>
</ul>
<h2 id="write-an-implementation"><a href="#TOC"><span class="header-section-number">4.3</span> Write an Implementation</a></h2>
<p>We will write a class that implements the <code>Greeting</code> interface. When the project was created from the template, Java source for a class named <code>org.example.ExampleComponent</code> was generated. Open this source file now and make it implement <code>Greeting</code>:</p>
<pre class="sourceCode Java"><code class="sourceCode java"><span class="kw">package org.example;</span>
<span class="kw">import org.example.api.Greeting;</span>
<span class="kw">import aQute.bnd.annotation.component.Component;</span>
@Component
<span class="kw">public</span> <span class="kw">class</span> ExampleComponent <span class="kw">implements</span> Greeting {
<span class="kw">public</span> String <span class="fu">sayHello</span>(String name) {
<span class="kw">return</span> <span class="st">"Hello "</span> + name;
}
}</code></pre>
<p>Note the use of the <code>@Component</code> annotation. This enables our bundle to use OSGi Declarative Services to declare the API implementation class. This means that instances of the class will be automatically created and registered with the OSGi service registry. The annotation is build-time only, and does not pollute our class with runtime dependencies – in other words, this is a “Plain Old Java Object” or POJO.</p>
<h2 id="test-the-implementation"><a href="#TOC"><span class="header-section-number">4.4</span> Test the Implementation</a></h2>
<p>We should write a test case to ensure the implementation class works as expected. In the <code>test</code> folder, a test case class already exists named <code>org.example.ExampleComponentTest</code>. Write a test method as follows:</p>
<pre class="sourceCode Java"><code class="sourceCode java"><span class="kw">package org.example;</span>
<span class="kw">import junit.framework.TestCase;</span>
<span class="kw">public</span> <span class="kw">class</span> ExampleComponentTest <span class="kw">extends</span> TestCase {
<span class="kw">public</span> <span class="dt">void</span> <span class="fu">testSaysHello</span>() <span class="kw">throws</span> Exception {
String result = <span class="kw">new</span> <span class="fu">ExampleComponent</span>().<span class="fu">sayHello</span>(<span class="st">"Bob"</span>);
<span class="fu">assertEquals</span>(<span class="st">"Hello Bob"</span>, result);
}
}</code></pre>
<p>Now right-click on the file and select <strong>Run As > JUnit Test</strong>.</p>
<div class="figure">
<img src="./images/tutorial/12.png"></img><p class="caption"></p>
</div>
<p>Verify that the <strong>JUnit</strong> view shows a green bar. If not, go back and fix the code!</p>
<p>Note that, since this is a unit test rather than an integration test, we did not need to run an OSGi Framework; the standard JUnit launcher is used. Again, this is possible because the component under test is a POJO.</p>
<h2 id="build-the-implementation-bundle"><a href="#TOC"><span class="header-section-number">4.5</span> Build the Implementation Bundle</a></h2>
<p>As in the previous project, a bundle is automatically built based on the content of <code>bnd.bnd</code>. In the current project however, we want to build <em>two</em> separate bundles. To achieve this we need to enable a feature called “sub-bundles”.</p>
<p>Right-click on the project <code>org.example.impls</code> and select <strong>New > Bundle Descriptor</strong>. In the resulting dialog, type the name <code>provider</code> and click <strong>Finish</strong>.</p>
<p>A popup dialog will ask whether to enable sub-bundles. Click <strong>OK</strong>.</p>
<div class="figure">
<img src="./images/tutorial/13.png"></img><p class="caption"></p>
</div>
<p>Some settings will be moved from <code>bnd.bnd</code> into the new <code>provider.bnd</code> file. You should now find a bundle in <code>generated</code> named <code>org.example.impls.provider.jar</code> which contains the <code>org.example</code> package and a Declarative Services component declaration in <code>OSGI-INF/org.example.ExampleComponent.xml</code>.</p>
<p><em>Important Points:</em></p>
<ul>
<li>Bndtools project can output either a single bundle or multiple bundles.</li>
<li>In the case of single-bundle projects, the contents of that bundle are defined in <code>bnd.bnd</code>.</li>
<li>In the case of multi-bundle projects, the contents of each bundle is defined in a separate <code>.bnd</code> file. The <code>bnd.bnd</code> file is still used to define project-wide settings, such as build dependencies.</li>
</ul>
<h1 id="run-an-osgi-framework"><a href="#TOC"><span class="header-section-number">5</span> Run an OSGi Framework</a></h1>
<p>We’d now like to run OSGi. To achieve this we need to create a “Run Descriptor” that defines the collection of bundles to run, along with some other run-time settings.</p>
<p>Right-click on the project <code>org.example.impls</code> and select <strong>New > Run Descriptor</strong>. In the resulting dialog, enter <code>run</code> as the file name and click <strong>Next</strong>. The next page of the dialog asks us to select a template; choose <strong>Apache Felix 4 with Gogo Shell</strong> and click <strong>Finish</strong>.</p>
<div class="figure">
<img src="./images/tutorial/14.png"></img><p class="caption"></p>
</div>
<p>In the editor for the new <code>run.bndrun</code> file, click on <strong>Run OSGi</strong> near the top-right corner. Shortly, the Felix Shell prompt “<code>g!</code>” will appear in the <strong>Console</strong> view. Type the <code>lb</code> command to view the list of bundles:</p>
<pre><code>g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (4.0.3)
1|Active | 1|Apache Felix Gogo Runtime (0.10.0)
2|Active | 1|Apache Felix Gogo Shell (0.10.0)
3|Active | 1|Apache Felix Gogo Command (0.12.0)
g!</code></pre>
<p>Next we want to include the <code>org.example.impls.provider</code> and <code>osgi.cmpn</code> bundles. This can be done as follows:</p>
<ul>
<li>Click the “+” icon in the toolbar of the <strong>Run Requirements</strong> panel to open the ‘Add Bundle Requirement’ dialog.</li>
<li>Under “Workspace”, double-click <code>org.example.impls.provider</code>.</li>
<li>Under “Bndtools Hub”, double-click <code>osgi.cmpn</code>.</li>
<li>Click <strong>Finish</strong>.</li>
</ul>
<p>The <strong>Run Requirements</strong> panel should now look like this:</p>
<div class="figure">
<img src="./images/tutorial/15.png"></img><p class="caption"></p>
</div>
<p>Check <strong>Auto-resolve on save</strong> and then save the file. Returning to the <strong>Console</strong> view, type <code>lb</code> again:</p>
<pre><code>g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (4.0.3)
1|Active | 1|Apache Felix Gogo Runtime (0.10.0)
2|Active | 1|Apache Felix Gogo Shell (0.10.0)
3|Active | 1|Apache Felix Gogo Command (0.12.0)
4|Active | 1|Apache Felix Configuration Admin Service (1.4.0)
5|Active | 1|Apache Felix Log Service (1.0.1)
6|Active | 1|Apache Felix Declarative Services (1.6.2)
7|Active | 1|org.example.api (0.0.0)
8|Active | 1|org.example.impls.provider (0.0.0)
9|Active | 1|osgi.cmpn (4.2.0.200908310645)
g!</code></pre>
<p>The provider bundle has been added to the runtime dynamically. Note that the API bundle and Apache Felix Declarative Services are also added because they resolved as dependencies of the provider.</p>
<p>We can now look at the services published by our provider bundle using the command <code>inspect capability service 8</code>:</p>
<pre><code>g! inspect capability service 8
org.example.impls.provider [8] provides:
----------------------------------------
service; org.example.api.Greeting with properties:
component.id = 0
component.name = org.example.ExampleComponent
service.id = 24
g!</code></pre>
<p>Our bundle now publishes a service under the <code>Greeting</code> interface.</p>
<p><em>Important Points:</em></p>
<ul>
<li>Run-time configurations can be defined in a <code>.bndrun</code> file. Multiple different run configurations can be used, resulting in different sets of bundles, different OSGi Framework implementations etc.</li>
<li>The set of bundles to include is derived from the <strong>Run Requirements</strong> list. Bndtools uses OBR resolution to resolve a list of bundles including their static dependencies.</li>
<li>If the OSGi Framework is still running, then saving the <code>bndrun</code> file will cause the list of bundles to be dynamically updated. So we can add and remove bundles without restarting.</li>
<li>Editing an existing bundle – including editing the Java code that comprises it – will also result in the bundle being dynamically updated in the runtime.</li>
</ul>
<h1 id="write-a-command-component"><a href="#TOC"><span class="header-section-number">6</span> Write a Command Component</a></h1>
<p>Finally we will write a component that consumes the Greeting service and publishes a shell command that can be invoked from the Felix shell.</p>
<p>First we need to make the Felix shell API available to compile against. Open <code>bnd.bnd</code> and change to the <strong>Build</strong> tab. Add <code>org.apache.felix.gogo.runtime</code> to the list of build dependencies, and save the file:</p>
<div class="figure">
<img src="./images/tutorial/17.png"></img><p class="caption"></p>
</div>
<p>Now create a new Java package under the <code>src</code> folder named <code>org.example.command</code>. In this package create a class <code>GreetingCommand</code> as follows:</p>
<pre class="sourceCode Java"><code class="sourceCode java"><span class="kw">package org.example.command;</span>
<span class="kw">import org.apache.felix.service.command.CommandProcessor;</span>
<span class="kw">import org.example.api.Greeting;</span>
<span class="kw">import aQute.bnd.annotation.component.Component;</span>
<span class="kw">import aQute.bnd.annotation.component.Reference;</span>
@<span class="fu">Component</span>(properties = {
<span class="co">/* Felix GoGo Shell Commands */</span>
CommandProcessor.<span class="fu">COMMAND_SCOPE</span> + <span class="st">":String=example"</span>,
CommandProcessor.<span class="fu">COMMAND_FUNCTION</span> + <span class="st">":String=greet"</span>
},
provide = Object.<span class="fu">class</span>
)
<span class="kw">public</span> <span class="kw">class</span> GreetingCommand {
<span class="kw">private</span> Greeting greetingSvc;
@Reference
<span class="kw">public</span> <span class="dt">void</span> <span class="fu">setGreeting</span>(Greeting greetingSvc) {
<span class="kw">this</span>.<span class="fu">greetingSvc</span> = greetingSvc;
}
<span class="kw">public</span> <span class="dt">void</span> <span class="fu">greet</span>(String name) {
System.<span class="fu">out</span>.<span class="fu">println</span>(greetingSvc.<span class="fu">sayHello</span>(name));
}
}</code></pre>
<h2 id="create-a-bundle-for-the-command-component"><a href="#TOC"><span class="header-section-number">6.1</span> Create a Bundle for the Command Component</a></h2>
<p>The command component is not part of the provider bundle, because it lives in a package that was not included. We could add it to the provider bundle, but it would make more sense to create a separate bundle for it.</p>
<p>Right-click again on the <code>org.example.impls</code> project and select <strong>New > Bundle Descriptor</strong> again. Enter the name as <code>command</code> and click <strong>Finish</strong>.</p>
<p>Add the package <code>org.example.command</code> to the <strong>Private Packages</strong> panel of the newly created file. As before, this can be done using the “+” button in the toolbar or by drag-and-drop.</p>
<p>We also need to declare that the bundle contains Declarative Services components. Change to the <strong>Contents</strong> tab of the editor and in the <strong>Declarative Services</strong> drop-down select <strong>Bnd Annotations</strong>. Now save the file.</p>
<h2 id="add-the-command-bundle-to-the-runtime"><a href="#TOC"><span class="header-section-number">6.2</span> Add the Command Bundle to the Runtime</a></h2>
<p>Switch back to the editor for <code>run.bndrun</code>. In the <strong>Run Requirements</strong> tab, add the <code>org.example.impls.command</code> bundle, and save the file.</p>
<p>The command bundle will now appear in the list of bundles when typing <code>lb</code>:</p>
<pre><code>g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (4.0.3)
1|Active | 1|Apache Felix Gogo Runtime (0.10.0)
2|Active | 1|Apache Felix Gogo Shell (0.10.0)
3|Active | 1|Apache Felix Gogo Command (0.12.0)
4|Active | 1|Apache Felix Configuration Admin Service (1.4.0)
5|Active | 1|Apache Felix Log Service (1.0.1)
6|Active | 1|Apache Felix Declarative Services (1.6.2)
7|Active | 1|org.example.api (0.0.0)
8|Active | 1|org.example.impls.provider (0.0.0)
9|Active | 1|osgi.cmpn (4.2.0.200908310645)
10|Active | 1|org.example.impls.command (0.0.0)
g!</code></pre>
<p>Finally, the <code>greet</code> command will now be available from the Gogo shell:</p>
<pre><code>g! greet BndTools
Hello BndTools
g!</code></pre>
</div><!--/span-->
</div><!--/row-->
</div><!--/.fluid-container-->
<footer>
<div class="well">
<p>© <a href="mailto:njbartlett@gmail.com">Neil Bartlett</a> 2011. Built with <a href="http://twitter.github.com/bootstrap/">Bootstrap</a> and <a href="http://jaspervdj.be/hakyll/index.html">Hakyll</a>.</p>
</div>
</footer>
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="js/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html>