blob: 60c7d56d2dd7338c8bf184379e27e935e89e3ed6 [file] [log] [blame]
Richard S. Hall2cd5bed2007-07-16 20:32:41 +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 - Launching and Embedding Apache Felix</title><link rel="stylesheet" href="launching-and-embedding-apache-felix_files/site.css" type="text/css" media="all"><link rel="stylesheet" href="launching-and-embedding-apache-felix_files/print.css" type="text/css" media="print"><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></head><body linkifying="true">&amp;t
3
4
5
6
7
8
9
10
11 <div class="title">
12 <a href="http://cwiki.apache.org/FELIX/index.html"><img alt="Apache Felix" src="launching-and-embedding-apache-felix_files/felix_logo.png" align="left" border="0"></a><a href="http://www.apache.org/"><img alt="Apache" src="launching-and-embedding-apache-felix_files/apache.png" align="right" border="0"></a>
13 </div>
14 <div class="menu">
15 <ul>
16 <li><a href="http://cwiki.apache.org/FELIX/index.html">home</a></li>
17 <li><a href="http://cwiki.apache.org/FELIX/news.html">news</a></li>
18 <li><a href="http://cwiki.apache.org/FELIX/status.html">status</a></li>
19 <li><a href="http://cwiki.apache.org/FELIX/license.html">license</a></li>
20 <li><a href="http://cwiki.apache.org/FELIX/downloads.html">downloads</a></li>
21 <li><a href="http://cwiki.apache.org/FELIX/documentation.html">documentation</a></li>
22 <li><a href="http://cwiki.apache.org/confluence/x/O-">wiki</a></li>
23 <li><a href="http://cwiki.apache.org/FELIX/committers.html">committers</a></li>
24 <li><a href="http://cwiki.apache.org/FELIX/mailinglists.html">mailing lists</a></li>
25 <li><a href="http://cwiki.apache.org/FELIX/faq.html">faq</a></li>
26 <li><a href="http://cwiki.apache.org/FELIX/roadmap.html">roadmap</a></li>
27 <li><a href="http://cwiki.apache.org/FELIX/sourcecode.html">source code</a></li>
28 <li><a href="http://cwiki.apache.org/FELIX/codingstandards.html">coding standards</a></li>
29 <li><a href="http://cwiki.apache.org/FELIX/issuetracking.html">issue tracking</a></li>
30 <li><a href="http://cwiki.apache.org/FELIX/dependencies.html">dependencies</a></li>
31 </ul>
32 </div>
33 <div class="main">
34<h1><a name="LaunchingandEmbeddingApacheFelix-LaunchingandEmbeddingApacheFelix"></a>Launching and Embedding Apache Felix</h1>
35
36<ul>
37 <li><a href="#LaunchingandEmbeddingApacheFelix-introduction" title="introduction on Launching and Embedding Apache Felix">Introduction</a></li>
38 <li><a href="#LaunchingandEmbeddingApacheFelix-overview" title="overview on Launching and Embedding Apache Felix">API Overview</a></li>
39 <li><a href="#LaunchingandEmbeddingApacheFelix-launching" title="launching on Launching and Embedding Apache Felix">Launching Felix</a>
40 <ul>
41 <li><a href="#LaunchingandEmbeddingApacheFelix-standardlauncher" title="standard-launcher on Launching and Embedding Apache Felix">Standard Felix Launcher</a></li>
42 <li><a href="#LaunchingandEmbeddingApacheFelix-customlauncher" title="custom-launcher on Launching and Embedding Apache Felix">Custom Felix Launcher</a></li>
43 </ul>
44 </li>
45 <li><a href="#LaunchingandEmbeddingApacheFelix-embedding" title="embedding on Launching and Embedding Apache Felix">Embedding Felix</a>
46 <ul>
47 <li><a href="#LaunchingandEmbeddingApacheFelix-configproperty" title="config-property on Launching and Embedding Apache Felix">Embedded Execution Configuration Property</a></li>
48 <li><a href="#LaunchingandEmbeddingApacheFelix-hostinteraction" title="host-interaction on Launching and Embedding Apache Felix">Host/Felix Interaction</a></li>
49 <li><a href="#LaunchingandEmbeddingApacheFelix-hostservices" title="host-services on Launching and Embedding Apache Felix">Providing Host Application Services</a></li>
50 <li><a href="#LaunchingandEmbeddingApacheFelix-hostserviceusage" title="host-service-usage on Launching and Embedding Apache Felix">Using Services Provided by Bundles</a>
51 <ul>
52 <li><a href="#LaunchingandEmbeddingApacheFelix-servicereflection" title="service-reflection on Launching and Embedding Apache Felix">Using Bundle Services via Reflection</a></li>
53 </ul>
54 </li>
55 </ul>
56 </li>
57 <li><a href="#LaunchingandEmbeddingApacheFelix-caveat" title="caveat on Launching and Embedding Apache Felix">Caveat</a></li>
58</ul>
59
60
61<p><a name="LaunchingandEmbeddingApacheFelix-introduction"></a></p>
62
63<h1><a name="LaunchingandEmbeddingApacheFelix-Introduction"></a>Introduction</h1>
64
65<p>The Apache Felix OSGi framework is intended to be easily launchable
66and embeddable. For example, Felix avoids the use of system properties
67for configuration, since these are globals that can cause interference
68if multiple framework instances are created in the same VM. Felix is
69also implemented to multiplex singleton facilities, like the URL stream
70handler factory. The goal is to make it possible to use Felix in as
71many scenarios as possible; however, this is still just a goal. In
72other words, this is a work in progress and if any issues arise, it
73would be greatly appreciated if they are brought to the attention of
74the Felix community. The next section provides a Felix API overview,
75while the remainder of the document is divided into two sections, one
76focusing on how to launch Felix and one focusing on how to embed Felix
77into a host application.</p>
78
79<p><a name="LaunchingandEmbeddingApacheFelix-overview"></a></p>
80
81<h1><a name="LaunchingandEmbeddingApacheFelix-APIOverview"></a>API Overview</h1>
82
83<p>The Felix class that implements the OSGi framework is <tt>org.apache.felix.framework.Felix</tt> or just <tt>Felix</tt> for short. The OSGi specification defines a special bundle, called the <em><b>System Bundle</b></em>,
84that represents the framework at run time and appears like any other
85bundle in the list of installed bundles. To make this notion even more
86intuitive, the <tt>Felix</tt> class implements the <tt>org.osgi.framework.Bundle</tt> interface, which is reiterated here:</p>
87
88<div class="code"><div class="codeContent">
89<pre class="code-java"><span class="code-keyword">public</span> <span class="code-keyword">interface</span> Bundle
90{
91 <span class="code-keyword">public</span> BundleContext getBundleContext();
92 <span class="code-keyword">public</span> <span class="code-object">long</span> getBundleId();
93 <span class="code-keyword">public</span> URL getEntry(<span class="code-object">String</span> name);
94 <span class="code-keyword">public</span> Enumeration getEntryPaths(<span class="code-object">String</span> path);
95 <span class="code-keyword">public</span> Enumeration findEntries(<span class="code-object">String</span> path, <span class="code-object">String</span> filePattern, <span class="code-object">boolean</span> recurse);
96 <span class="code-keyword">public</span> Dictionary getHeaders();
97 <span class="code-keyword">public</span> Dictionary getHeaders(<span class="code-object">String</span> locale);
98 <span class="code-keyword">public</span> <span class="code-object">long</span> getLastModified();
99 <span class="code-keyword">public</span> <span class="code-object">String</span> getLocation();
100 <span class="code-keyword">public</span> URL getResource(<span class="code-object">String</span> name);
101 <span class="code-keyword">public</span> Enumeration getResources(<span class="code-object">String</span> name) <span class="code-keyword">throws</span> IOException;
102 <span class="code-keyword">public</span> ServiceReference[] getRegisteredServices();
103 <span class="code-keyword">public</span> ServiceReference[] getServicesInUse();
104 <span class="code-keyword">public</span> <span class="code-object">int</span> getState();
105 <span class="code-keyword">public</span> <span class="code-object">String</span> getSymbolicName();
106 <span class="code-keyword">public</span> <span class="code-object">boolean</span> hasPermission(<span class="code-object">Object</span> obj);
107 <span class="code-keyword">public</span> <span class="code-object">Class</span> loadClass(<span class="code-object">String</span> name) <span class="code-keyword">throws</span> ClassNotFoundException;
108 <span class="code-keyword">public</span> void start() <span class="code-keyword">throws</span> BundleException;
109 <span class="code-keyword">public</span> void stop() <span class="code-keyword">throws</span> BundleException;
110 <span class="code-keyword">public</span> void uninstall() <span class="code-keyword">throws</span> BundleException;
111 <span class="code-keyword">public</span> void update() <span class="code-keyword">throws</span> BundleException;
112 <span class="code-keyword">public</span> void update(InputStream is) <span class="code-keyword">throws</span> BundleException;
113}</pre>
114</div></div>
115
116<p>When you instantiate the <tt>Felix</tt> class, the resulting object is actually the System Bundle and can be cast to the <tt>Bundle</tt> interface. The <tt>start()</tt> method is used to start the framework instance, while the <tt>stop()</tt> method is used to asynchronously stop the framework instance. The <tt>Felix</tt> class also includes the following two additional public methods:</p>
117
118<div class="code"><div class="codeContent">
119<pre class="code-java"><span class="code-keyword">public</span> class Felix <span class="code-keyword">extends</span> AbstractBundle
120{
121 <span class="code-keyword">public</span> Felix(Map configMutableMap, List activatorList);
122 <span class="code-keyword">public</span> void stopAndWait();
123}</pre>
124</div></div>
125
126<p>The first method is the constructor used to instantiate framework
127instances; the constructor accepts configuration properties and System
128Bundle activators, which are both described in more detail later. The <tt>stopAndWait()</tt> method is a synchronous version of the <tt>stop()</tt> method, used to stop the framework and block the calling thread until the framework is completely stopped.</p>
129
130<p><a name="LaunchingandEmbeddingApacheFelix-launching"></a></p>
131
132<h1><a name="LaunchingandEmbeddingApacheFelix-LaunchingFelix"></a>Launching Felix</h1>
133
134<p>Launching Felix is fairly simple and involves only three steps:</p>
135
136<ol>
137 <li>Defining some configuration properties.</li>
138 <li>Creating an instance of <tt>org.apache.felix.framework.Felix</tt> with the configuration properties.</li>
139 <li>Invoking the <tt>org.apache.felix.framework.Felix.start()</tt> method.</li>
140</ol>
141
142
143<p>The only configuration properties that are actually required to
144start Felix are ones that tell it where/how to locate the bundle cache
145profile directory where installed bundles will be cached. Felix' bundle
146cache implementation allows you to configure the location where bundles
147are cached using configuration properties. At a minimum, either a
148bundle cache profile name or directory must be specified; see the <a href="http://cwiki.apache.org/FELIX/apache-felix-bundle-cache.html" title="Apache Felix Bundle Cache">bundle cache document</a> for more detailed information on configuring the bundle cache.</p>
149
150<p>Besides configuration properties for the bundle cache, it is usually necessary to set the <tt>org.osgi.framework.system.packages</tt> configuration property to export packages from the class path, such as the OSGi interface classes (e.g., <tt>org.osgi.framework</tt>) on which all bundles depend. If you are creating a launcher for Felix, then the <tt>felix.auto.start</tt> configuration property may also be used to automatically install and start various bundles; see the <a href="http://cwiki.apache.org/FELIX/apache-felix-usage-documentation.html#ApacheFelixUsageDocumentation-configuringfelix" title="configuring-felix on Apache Felix Usage Documentation">usage document</a> for more information on configuring Felix and on the various configuration properties.</p>
151
152<p>The remainder of this section describes how the standard Felix
153launcher works as well as how to create a custom launcher for Felix.</p>
154
155<p><a name="LaunchingandEmbeddingApacheFelix-standardlauncher"></a></p>
156
157<h2><a name="LaunchingandEmbeddingApacheFelix-StandardFelixLauncher"></a>Standard Felix Launcher</h2>
158
159<p>The standard Felix launcher is very simple and is not intended to
160solve every possible requirement; it is intended to work for most
161standard situations. Most special launching requirements should be
162resolved by creating a custom launcher. This section describes how the
163standard launcher works. The following code represents the complete <tt>main()</tt> method of the standard launcher, each numbered comment will be described in more detail below:</p>
164
165<div class="code"><div class="codeContent">
166<pre class="code-java"><span class="code-keyword">public</span> <span class="code-keyword">static</span> void main(<span class="code-object">String</span>[] argv) <span class="code-keyword">throws</span> Exception
167{
168 <span class="code-comment">// (1) Load system properties.
169</span> Main.loadSystemProperties();
170
171 <span class="code-comment">// (2) Read configuration properties.
172</span> Properties configProps = Main.loadConfigProperties();
173
174 <span class="code-comment">// (3) Copy framework properties from the system properties.
175</span> Main.copySystemProperties(configProps);
176
177 <span class="code-comment">// (4) See <span class="code-keyword">if</span> the profile name property was specified.
178</span> <span class="code-object">String</span> profileName = configProps.getProperty(BundleCache.CACHE_PROFILE_PROP);
179
180 <span class="code-comment">// (4) See <span class="code-keyword">if</span> the profile directory property was specified.
181</span> <span class="code-object">String</span> profileDirName = configProps.getProperty(BundleCache.CACHE_PROFILE_DIR_PROP);
182
183 <span class="code-comment">// Print welcome banner.
184</span> <span class="code-object">System</span>.out.println(<span class="code-quote">"\nWelcome to Felix."</span>);
185 <span class="code-object">System</span>.out.println(<span class="code-quote">"=================\n"</span>);
186
187 <span class="code-comment">// (5) If no profile or profile directory is specified in the
188</span> <span class="code-comment">// properties, then ask <span class="code-keyword">for</span> a profile name.
189</span> <span class="code-keyword">if</span> ((profileName == <span class="code-keyword">null</span>) &amp;&amp; (profileDirName == <span class="code-keyword">null</span>))
190 {
191 <span class="code-object">System</span>.out.print(<span class="code-quote">"Enter profile name: "</span>);
192 BufferedReader in = <span class="code-keyword">new</span> BufferedReader(<span class="code-keyword">new</span> InputStreamReader(<span class="code-object">System</span>.in));
193 <span class="code-keyword">try</span>
194 {
195 profileName = in.readLine();
196 }
197 <span class="code-keyword">catch</span> (IOException ex)
198 {
199 <span class="code-object">System</span>.err.println(<span class="code-quote">"Could not read input."</span>);
200 <span class="code-object">System</span>.exit(-1);
201 }
202 <span class="code-object">System</span>.out.println("");
203 <span class="code-keyword">if</span> (profileName.length() != 0)
204 {
205 configProps.setProperty(BundleCache.CACHE_PROFILE_PROP, profileName);
206 }
207 }
208
209 <span class="code-comment">// (6) A profile directory or name must be specified.
210</span> <span class="code-keyword">if</span> ((profileDirName == <span class="code-keyword">null</span>) &amp;&amp; (profileName.length() == 0))
211 {
212 <span class="code-object">System</span>.err.println(<span class="code-quote">"You must specify a profile name or directory."</span>);
213 <span class="code-object">System</span>.exit(-1);
214 }
215
216 <span class="code-keyword">try</span>
217 {
218 <span class="code-comment">// (7) Now create an instance of the framework.
219</span> m_felix = <span class="code-keyword">new</span> Felix(<span class="code-keyword">new</span> StringMap(configProps, <span class="code-keyword">false</span>), <span class="code-keyword">null</span>);
220 m_felix.start();
221 }
222 <span class="code-keyword">catch</span> (Exception ex)
223 {
224 <span class="code-object">System</span>.err.println(<span class="code-quote">"Could not create framework: "</span> + ex);
225 ex.printStackTrace();
226 <span class="code-object">System</span>.exit(-1);
227 }
228}</pre>
229</div></div>
230
231<p>The general steps of the standard launcher are quite straightforward:</p>
232
233<ol>
234 <li>Load any system properties specified in the <tt>system.properties</tt> file; this file is typically located in the <tt>conf/</tt> directory of the Felix installation directory, but it can be specified directly using the <tt>felix.system.properties</tt>
235system property. This file is not needed to launch Felix and is
236provided merely for convenience when system properties must be
237specified. The file is a standard Java properties file, but it also
238supports property substitution using <tt>${&lt;property-name</tt>} syntax. Property substitution can be nested; only system properties will be used for substitution.</li>
239 <li>Load any configuration properties specified in the <tt>config.properties</tt> file; this file is typically located in the <tt>conf/</tt> directory of the Felix installation directory, but it can be specified directly using the <tt>felix.config.properties</tt>
240system property. This file is used to configure the Felix instance
241created by the launcher. The file is a standard Java properties file,
242but it also supports property substitution using "<tt>${&lt;property-name</tt>}"
243syntax. Property substitution can be nested; configuration and system
244properties will be used for substitution with configuration properties
245having precedence.</li>
246 <li>For convenience, any configuration
247properties that are set as system properties will be copied into the
248set of configuration properties to provide an easy way to add to or
249override configuration properties specified in the <tt>config.properties</tt> file.</li>
250 <li>Try to load the profile name or profile directory configuration properties. At least one of these must be specified so that the <a href="http://cwiki.apache.org/FELIX/apache-felix-bundle-cache.html" title="Apache Felix Bundle Cache">bundle cache</a> knows where to save installed bundles.</li>
251 <li>If
252either the profile name or profile directory configuration property has
253not been specified, then ask the user to specify a profile name and add
254it to the current set of configuration properties.</li>
255 <li>Error if there is no profile name or profile directory.</li>
256 <li>Create the Felix instance passing in the configuration properties and then call <tt>start()</tt>.</li>
257</ol>
258
259
260<p>The framework is not active until the <tt>start()</tt> method is called. If no shell bundles are specified in the <tt>config.properties</tt>
261file or if there is difficulty locating the shell bundles that are
262specified, then it will appear as if the framework is hung, but it is
263actually running without any way to interact with it since the shell
264bundles provide the only means of interaction.</p>
265
266<p><a name="LaunchingandEmbeddingApacheFelix-customlauncher"></a></p>
267
268<h2><a name="LaunchingandEmbeddingApacheFelix-CustomFelixLauncher"></a>Custom Felix Launcher</h2>
269
270<p>This section creates a bare-bones launcher to demonstrate the
271minimum requirements for creating an interactive launcher for the Felix
272framework. This example uses the standard Felix shell bundles for
273interactivity, but any other bundles could be used instead. For
274example, the shell service and telnet bundles could be used to launch
275Felix and make it remotely accessible.</p>
276
277<p>This example launcher project has the following directory structure:</p>
278
279<div class="preformatted"><div class="preformattedContent">
280<pre>launcher/
281 lib/
282 org.apache.felix.framework-1.0.0.jar
283 bundle/
284 org.apache.felix.shell-1.0.0.jar
285 org.apache.felix.shell.tui-1.0.0.jar
286 src/
287 example/
288 Main.java
289</pre>
290</div></div>
291
292<p>The <tt>lib/</tt> directory contains the framework JAR file, which also contains the OSGi core interfaces. The <tt>bundle/</tt>
293directory contains the shell service and textual shell interface
294bundles that will be used for interacting with the framework instance.
295Note: If you do not launch Felix with interactive bundles, it will
296appear as if the framework instance is hung, but it is actually just
297sitting there waiting for someone to tell it to do something. The <tt>src/example/</tt> directory contains the following <tt>Main.java</tt> file, which is a very simplistic Felix launcher.</p>
298
299<div class="code"><div class="codeContent">
300<pre class="code-java"><span class="code-keyword">package</span> example;
301
302<span class="code-keyword">import</span> java.util.Map;
303<span class="code-keyword">import</span> org.osgi.framework.Constants;
304<span class="code-keyword">import</span> org.apache.felix.framework.Felix;
305<span class="code-keyword">import</span> org.apache.felix.framework.cache.BundleCache;
306<span class="code-keyword">import</span> org.apache.felix.framework.util.StringMap;
307<span class="code-keyword">import</span> org.apache.felix.framework.util.FelixConstants;
308
309<span class="code-keyword">public</span> class Main
310{
311 <span class="code-keyword">private</span> <span class="code-keyword">static</span> Felix m_felix = <span class="code-keyword">null</span>;
312
313 <span class="code-keyword">public</span> <span class="code-keyword">static</span> void main(<span class="code-object">String</span>[] argv) <span class="code-keyword">throws</span> Exception
314 {
315 <span class="code-comment">// Print welcome banner.
316</span> <span class="code-object">System</span>.out.println(<span class="code-quote">"\nWelcome to Felix."</span>);
317 <span class="code-object">System</span>.out.println(<span class="code-quote">"=================\n"</span>);
318
319 Map configMap = <span class="code-keyword">new</span> StringMap(<span class="code-keyword">false</span>);
320 configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
321 <span class="code-quote">"org.osgi.framework; version=1.3.0,"</span> +
322 <span class="code-quote">"org.osgi.service.packageadmin; version=1.2.0,"</span> +
323 <span class="code-quote">"org.osgi.service.startlevel; version=1.0.0,"</span> +
324 <span class="code-quote">"org.osgi.service.url; version=1.0.0"</span>);
325 configMap.put(FelixConstants.AUTO_START_PROP + <span class="code-quote">".1"</span>,
326 <span class="code-quote">"file:bundle/org.apache.felix.shell-1.0.0.jar "</span> +
327 <span class="code-quote">"file:bundle/org.apache.felix.shell.tui-1.0.0.jar"</span>);
328 configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, <span class="code-quote">"cache"</span>);
329
330 <span class="code-keyword">try</span>
331 {
332 <span class="code-comment">// Now create an instance of the framework.
333</span> m_felix = <span class="code-keyword">new</span> Felix(configMap, <span class="code-keyword">null</span>);
334 m_felix.start();
335 }
336 <span class="code-keyword">catch</span> (Exception ex)
337 {
338 <span class="code-object">System</span>.err.println(<span class="code-quote">"Could not create framework: "</span> + ex);
339 ex.printStackTrace();
340 <span class="code-object">System</span>.exit(-1);
341 }
342 }
343}</pre>
344</div></div>
345
346<p>This launcher has all information hard coded in it, unlike the
347default Felix launcher, which loads configuration properties from files
348and performs variable substitution. This simple launcher provides a
349good starting point if the features of the default launcher are not
350necessary. For example, if you want to create a launcher that
351automatically deletes the bundle cache directory each time it starts,
352then it is quite easy to figure out how to do that with this simple
353launcher.</p>
354
355<p>By breaking down the above source code into small chunks, it is quite easy to see what is going on.</p>
356
357<div class="code"><div class="codeContent">
358<pre class="code-java">Map configMap = <span class="code-keyword">new</span> StringMap(<span class="code-keyword">false</span>);</pre>
359</div></div>
360
361<p>This simply creates a map to hold configuration properties where the keys are strings and lookups are case insensitive.</p>
362
363<div class="code"><div class="codeContent">
364<pre class="code-java">configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
365 <span class="code-quote">"org.osgi.framework; version=1.3.0,"</span> +
366 <span class="code-quote">"org.osgi.service.packageadmin; version=1.2.0,"</span> +
367 <span class="code-quote">"org.osgi.service.startlevel; version=1.0.0,"</span> +
368 <span class="code-quote">"org.osgi.service.url; version=1.0.0"</span>);</pre>
369</div></div>
370
371<p>This sets the <tt>Constants.FRAMEWORK_SYSTEMPACKAGES</tt> configuration property (string value "<tt>org.osgi.framework.system.packages</tt>"),
372which specifies the class path packages the system bundle should
373export; this is how classes on the class path are made available to
374bundles. This example only exports the core OSGi API packages, but
375other JRE packages could also be added, such as <tt>javax.swing</tt>.
376For example, the default Felix launcher defines properties for all
377packages in various JRE versions (e.g., 1.3.x, 1.4.x, 1.5.x) and
378appends them to this property using property substitution.</p>
379
380<div class="code"><div class="codeContent">
381<pre class="code-java">configMap.put(FelixConstants.AUTO_START_PROP + <span class="code-quote">".1"</span>,
382 <span class="code-quote">"file:bundle/org.apache.felix.shell-1.0.0.jar "</span> +
383 <span class="code-quote">"file:bundle/org.apache.felix.shell.tui-1.0.0.jar"</span>);</pre>
384</div></div>
385
386<p>This sets the <tt>FelixConstants.AUTO_START_PROP</tt> configuration property (string value "<tt>felix.auto.start</tt>"),
387which is a space-delimited list of bundle URLs that the framework will
388automatically install and start when the framework starts. However,
389this property key cannot be used as is; it must be appended with a "."
390and then a number, where the number represents the start level for the
391bundle when it is installed. In this particular example, ".1" is
392appended to the property name, thus the two bundles will be installed
393into start level one. This example uses relative <tt>file:</tt> URLs, which will load the bundles from the <tt>bundle/</tt>
394directory assuming that the launcher is started from the root directory
395of the launcher project. It is also possible to specify absolute URLs
396or remote URLs.</p>
397
398<div class="code"><div class="codeContent">
399<pre class="code-java">configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, <span class="code-quote">"cache"</span>);</pre>
400</div></div>
401
402<p>This sets the last configuration property, <tt>BundleCache.CACHE_PROFILE_DIR_PROP</tt> (string value "<tt>felix.cache.profiledir</tt>"),
403which is a string that specifies the precise directory to be used as
404the bundle cache profile directory; the Felix bundle cache supports
405other properties to configure its behavior, but those are not covered
406here. In this example, the bundle cache profile directory is specified
407as a relative directory called "<tt>cache</tt>". Assuming that the
408launcher is executed from the root directory of the launcher project,
409then the bundle cache profile directory will be created in the root
410directory of the project.</p>
411
412<div class="code"><div class="codeContent">
413<pre class="code-java">m_felix = <span class="code-keyword">new</span> Felix(configMap, <span class="code-keyword">null</span>);
414 m_felix.start();</pre>
415</div></div>
416
417<p>The last steps create the framework instance and start it. The configuration property map is passed into the <tt>Felix</tt> constructor.</p>
418
419<p>The following command compiles the launcher when run from the root directory of the launcher project:</p>
420
421<div class="preformatted"><div class="preformattedContent">
422<pre>javac -d . -classpath lib/org.apache.felix.framework-1.0.0.jar src/example/Main.java
423</pre>
424</div></div>
425
426<p>After executing this command, an <tt>example/</tt> directory is
427created in the current directory, which contains the generated class
428file. The following command executes the simple launcher when run from
429the root directory of the launcher project:</p>
430
431<div class="preformatted"><div class="preformattedContent">
432<pre>java -cp .:lib/org.apache.felix.framework-1.0.0.jar example.Main
433</pre>
434</div></div>
435
436<p>After executing this command, a <tt>cache/</tt> directory is created that contains the installed bundles, which were installed from the <tt>bundle/</tt> directory.</p>
437
438<p><a name="LaunchingandEmbeddingApacheFelix-embedding"></a></p>
439
440<h1><a name="LaunchingandEmbeddingApacheFelix-EmbeddingFelix"></a>Embedding Felix</h1>
441
442<p>Embedding Felix into a host application is a simple way to provide a
443sophisticated extensibility mechanism (i.e., plugin system) to the host
444application. Embedding Felix is very similar to launching Felix as
445described above, the main difference is that the host application
446typically wants to interact with the framework instance and/or
447installed bundles/services from the outside. This is fairly easy to
448achieve with Felix, but there are some subtle issues to understand.
449This section presents the mechanisms for embedding Felix into a host
450application and the issues in doing so.</p>
451
452<p><a name="LaunchingandEmbeddingApacheFelix-configproperty"></a></p>
453
454<h2><a name="LaunchingandEmbeddingApacheFelix-EmbeddedExecutionConfigurationProperty"></a>Embedded Execution Configuration Property</h2>
455
456<p>When a Felix instance is embedded in a host application, the host
457application must inform the Felix instance that it is embedded. To do
458this, the host application sets the "<tt>felix.embedded.execution</tt>" configuration property to "<tt>true</tt>";
459this can be accomplished in the same way that all configuration
460properties are set, i.e., passing it into the Felix constructor via a
461map. This property specifically controls whether or not the Felix
462instance will shutdown the JVM (i.e., call <tt>System.exit()</tt> when
463the framework is shutdown. When embedding Felix it is generally not
464desirable for Felix to shutdown the JVM; therefore, by setting this
465property to "<tt>true</tt>" it can be avoided.</p>
466
467<p><a name="LaunchingandEmbeddingApacheFelix-hostinteraction"></a></p>
468
469<h2><a name="LaunchingandEmbeddingApacheFelix-Host/FelixInteraction"></a>Host/Felix Interaction</h2>
470
471<p>In the section on <a href="#LaunchingandEmbeddingApacheFelix-launching" title="launching on Launching and Embedding Apache Felix">launching</a> Felix above, the <tt>Felix</tt>
472constructor accepts two arguments, the first being the configuration
473properties for the framework, the second being a list of bundle
474activator instances. These bundle activator instances provide a
475convenient way for host applications to interact with the Felix
476framework.</p>
477
478<p>Each bundle activator instance passed into the constructor
479effectively becomes part of the System Bundle. This means that the
480start()/stop() method of each bundle activator instance in the passed
481in list gets invoked when the System Bundle's activator start()/stop()
482method gets invoked. Consequently, each bundle activator instance will
483be given the system bundle's <tt>BundleContext</tt> object so that they can interact with the framework externally. While it is possible to get the System Bundle's <tt>BundleContext</tt> object directly by calling <tt>Felix.getBundleContext()</tt>,
484this is generally not as convenient since it requires that you monitor
485when the System Bundle starts and/or stops. Consider following snippet
486of a bundle activator:</p>
487
488<div class="code"><div class="codeContent">
489<pre class="code-java"><span class="code-keyword">public</span> class HostActivator <span class="code-keyword">implements</span> BundleActivator
490{
491 <span class="code-keyword">private</span> BundleContext m_context = <span class="code-keyword">null</span>;
492
493 <span class="code-keyword">public</span> void start(BundleContext context)
494 {
495 m_context = context;
496 }
497
498 <span class="code-keyword">public</span> void stop(BundleContext context)
499 {
500 m_context = <span class="code-keyword">null</span>;
501 }
502
503 <span class="code-keyword">public</span> Bundle[] getBundles()
504 {
505 <span class="code-keyword">if</span> (m_context != <span class="code-keyword">null</span>)
506 {
507 <span class="code-keyword">return</span> m_context.getBundles();
508 }
509 <span class="code-keyword">return</span> <span class="code-keyword">null</span>;
510 }
511}</pre>
512</div></div>
513
514<p>Given the above bundle activator, it is now possible to embed Felix
515into a host application and interact with it as the following snippet
516illustrates:</p>
517
518<div class="code"><div class="codeContent">
519<pre class="code-java"><span class="code-keyword">public</span> class HostApplication
520{
521 <span class="code-keyword">private</span> HostActivator m_activator = <span class="code-keyword">null</span>;
522 <span class="code-keyword">private</span> Felix m_felix = <span class="code-keyword">null</span>;
523
524 <span class="code-keyword">public</span> HostApplication()
525 {
526 <span class="code-comment">// Create a <span class="code-keyword">case</span>-insensitive configuration property map.
527</span> Map configMap = <span class="code-keyword">new</span> StringMap(<span class="code-keyword">false</span>);
528 <span class="code-comment">// Configure the Felix instance to be embedded.
529</span> configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, <span class="code-quote">"<span class="code-keyword">true</span>"</span>);
530 <span class="code-comment">// Add core OSGi packages to be exported from the class path
531</span> <span class="code-comment">// via the system bundle.
532</span> configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
533 <span class="code-quote">"org.osgi.framework; version=1.3.0,"</span> +
534 <span class="code-quote">"org.osgi.service.packageadmin; version=1.2.0,"</span> +
535 <span class="code-quote">"org.osgi.service.startlevel; version=1.0.0,"</span> +
536 <span class="code-quote">"org.osgi.service.url; version=1.0.0"</span>);
537 <span class="code-comment">// Explicitly specify the directory to use <span class="code-keyword">for</span> caching bundles.
538</span> configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, <span class="code-quote">"cache"</span>);
539
540 <span class="code-keyword">try</span>
541 {
542 <span class="code-comment">// Create host activator;
543</span> m_activator = <span class="code-keyword">new</span> HostActivator();
544 List list = <span class="code-keyword">new</span> ArrayList();
545 list.add(m_activator);
546
547 <span class="code-comment">// Now create an instance of the framework with
548</span> <span class="code-comment">// our configuration properties and activator.
549</span> m_felix = <span class="code-keyword">new</span> Felix(configMap, list);
550
551 <span class="code-comment">// Now start Felix instance.
552</span> m_felix.start();
553 }
554 <span class="code-keyword">catch</span> (Exception ex)
555 {
556 <span class="code-object">System</span>.err.println(<span class="code-quote">"Could not create framework: "</span> + ex);
557 ex.printStackTrace();
558 }
559 }
560
561 <span class="code-keyword">public</span> Bundle[] getInstalledBundles()
562 {
563 <span class="code-comment">// Use the system bundle activator to gain external
564</span> <span class="code-comment">// access to the set of installed bundles.
565</span> <span class="code-keyword">return</span> m_activator.getBundles();
566 }
567
568 <span class="code-keyword">public</span> void shutdownApplication()
569 {
570 <span class="code-comment">// Shut down the felix framework when stopping the
571</span> <span class="code-comment">// host application.
572</span> m_felix.shutdown();
573 }
574}</pre>
575</div></div>
576
577<p>Notice how the <tt>HostApplication.getInstalledBundles()</tt> method
578uses its activator instance to get access to the System Bundle's
579context in order to interact with the embedded Felix framework
580instance. This approach provides the foundation for all interaction
581between the host application and the embedded framework instance.</p>
582
583<p><a name="LaunchingandEmbeddingApacheFelix-hostservices"></a></p>
584
585<h2><a name="LaunchingandEmbeddingApacheFelix-ProvidingHostApplicationServices"></a>Providing Host Application Services</h2>
586
587<p>Providing services from the host application to bundles inside the
588embedded Felix framework instance follows the basic approach laid out
589in <a href="#LaunchingandEmbeddingApacheFelix-hostinteraction" title="host-interaction on Launching and Embedding Apache Felix">above</a>.
590The main complication for providing a host application service to
591bundles is the fact that both the host application and the bundles must
592be using the same class definitions for the service interface classes.
593Since the host application cannot import classes from a bundle, this
594means that the service interface classes <b>must</b> be accessible on
595the class path, typically as part of the host application itself. The
596host application then must export the service interface package via the
597system bundle so that bundles installed into the embedded framework
598instance can import it. This is achieved using the <tt>org.osgi.framework.system.packages</tt> configuration property previously presented.</p>
599
600<p>Consider the follow simple property lookup service:</p>
601
602<div class="code"><div class="codeContent">
603<pre class="code-java"><span class="code-keyword">package</span> host.service.lookup;
604
605<span class="code-keyword">public</span> class Lookup
606{
607 <span class="code-keyword">public</span> <span class="code-object">Object</span> lookup(<span class="code-object">String</span> name);
608}</pre>
609</div></div>
610
611<p>This package is simply part of the host application, which is potentially packaged into a JAR file and started with the "<tt>java -jar</tt>"
612command. Now consider the following host application bundle activator,
613which will be used to register/unregister the property lookup service
614when the embedded framework instance starts/stops:</p>
615
616<div class="code"><div class="codeContent">
617<pre class="code-java"><span class="code-keyword">package</span> host.core;
618
619<span class="code-keyword">import</span> java.util.Map;
620<span class="code-keyword">import</span> org.osgi.framework.BundleActivator;
621<span class="code-keyword">import</span> org.osgi.framework.BundleContext;
622<span class="code-keyword">import</span> org.osgi.framework.ServiceRegistration;
623<span class="code-keyword">import</span> host.service.lookup;
624
625<span class="code-keyword">public</span> class HostActivator <span class="code-keyword">implements</span> BundleActivator
626{
627 <span class="code-keyword">private</span> Map m_lookupMap = <span class="code-keyword">null</span>;
628 <span class="code-keyword">private</span> BundleContext m_context = <span class="code-keyword">null</span>;
629 <span class="code-keyword">private</span> ServiceRegistration m_registration = <span class="code-keyword">null</span>;
630
631 <span class="code-keyword">public</span> HostActivator(Map lookupMap)
632 {
633 <span class="code-comment">// Save a reference to the service's backing store.
634</span> m_lookupMap = lookupMap;
635 }
636
637 <span class="code-keyword">public</span> void start(BundleContext context)
638 {
639 <span class="code-comment">// Save a reference to the bundle context.
640</span> m_context = context;
641 <span class="code-comment">// Create a property lookup service implementation.
642</span> Lookup lookup = <span class="code-keyword">new</span> Lookup() {
643 <span class="code-keyword">public</span> <span class="code-object">Object</span> lookup(<span class="code-object">String</span> name)
644 {
645 <span class="code-keyword">return</span> m_lookupMap.get(name);
646 }
647 };
648 <span class="code-comment">// Register the property lookup service and save
649</span> <span class="code-comment">// the service registration.
650</span> m_registration = m_context.registerService(
651 Lookup.class.getName(), lookup, <span class="code-keyword">null</span>);
652 }
653
654 <span class="code-keyword">public</span> void stop(BundleContext context)
655 {
656 <span class="code-comment">// Unregister the property lookup service.
657</span> m_registration.unregister();
658 m_context = <span class="code-keyword">null</span>;
659 }
660}</pre>
661</div></div>
662
663<p>Given the above host application bundle activator, the following
664code snippet shows how the host application could create an embedded
665version of the Felix framework and provide the property lookup service
666to installed bundles:</p>
667
668<div class="code"><div class="codeContent">
669<pre class="code-java"><span class="code-keyword">package</span> host.core;
670
671<span class="code-keyword">import</span> java.util.List;
672<span class="code-keyword">import</span> java.util.ArrayList;
673<span class="code-keyword">import</span> java.util.Map;
674<span class="code-keyword">import</span> java.util.HashMap;
675<span class="code-keyword">import</span> host.service.lookup.Lookup;
676<span class="code-keyword">import</span> org.apache.felix.framework.Felix;
677<span class="code-keyword">import</span> org.apache.felix.framework.util.FelixConstants;
678<span class="code-keyword">import</span> org.apache.felix.framework.util.StringMap;
679<span class="code-keyword">import</span> org.apache.felix.framework.cache.BundleCache;
680
681<span class="code-keyword">public</span> class HostApplication
682{
683 <span class="code-keyword">private</span> HostActivator m_activator = <span class="code-keyword">null</span>;
684 <span class="code-keyword">private</span> Felix m_felix = <span class="code-keyword">null</span>;
685 <span class="code-keyword">private</span> Map m_lookupMap = <span class="code-keyword">new</span> HashMap();
686
687 <span class="code-keyword">public</span> HostApplication()
688 {
689 <span class="code-comment">// Initialize the map <span class="code-keyword">for</span> the property lookup service.
690</span> m_lookupMap.put(<span class="code-quote">"name1"</span>, <span class="code-quote">"value1"</span>);
691 m_lookupMap.put(<span class="code-quote">"name2"</span>, <span class="code-quote">"value2"</span>);
692 m_lookupMap.put(<span class="code-quote">"name3"</span>, <span class="code-quote">"value3"</span>);
693 m_lookupMap.put(<span class="code-quote">"name4"</span>, <span class="code-quote">"value4"</span>);
694
695 <span class="code-comment">// Create a <span class="code-keyword">case</span>-insensitive configuration property map.
696</span> Map configMap = <span class="code-keyword">new</span> StringMap(<span class="code-keyword">false</span>);
697 <span class="code-comment">// Configure the Felix instance to be embedded.
698</span> configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, <span class="code-quote">"<span class="code-keyword">true</span>"</span>);
699 <span class="code-comment">// Add the host provided service <span class="code-keyword">interface</span> <span class="code-keyword">package</span> and the core OSGi
700</span> <span class="code-comment">// packages to be exported from the class path via the system bundle.
701</span> configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
702 <span class="code-quote">"org.osgi.framework; version=1.3.0,"</span> +
703 <span class="code-quote">"org.osgi.service.packageadmin; version=1.2.0,"</span> +
704 <span class="code-quote">"org.osgi.service.startlevel; version=1.0.0,"</span> +
705 <span class="code-quote">"org.osgi.service.url; version=1.0.0,"</span> +
706 <span class="code-quote">"host.service.lookup; version=1.0.0"</span>);
707 <span class="code-comment">// Explicitly specify the directory to use <span class="code-keyword">for</span> caching bundles.
708</span> configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, <span class="code-quote">"cache"</span>);
709
710 <span class="code-keyword">try</span>
711 {
712 <span class="code-comment">// Create host activator;
713</span> m_activator = <span class="code-keyword">new</span> HostActivator(m_lookupMap);
714 List list = <span class="code-keyword">new</span> ArrayList();
715 list.add(m_activator);
716
717 <span class="code-comment">// Now create an instance of the framework with
718</span> <span class="code-comment">// our configuration properties and activator.
719</span> m_felix = <span class="code-keyword">new</span> Felix(configMap, list);
720
721 <span class="code-comment">// Now start Felix instance.
722</span> m_felix.start();
723 }
724 <span class="code-keyword">catch</span> (Exception ex)
725 {
726 <span class="code-object">System</span>.err.println(<span class="code-quote">"Could not create framework: "</span> + ex);
727 ex.printStackTrace();
728 }
729 }
730
731 <span class="code-keyword">public</span> void shutdownApplication()
732 {
733 <span class="code-comment">// Shut down the felix framework when stopping the
734</span> <span class="code-comment">// host application.
735</span> m_felix.shutdown();
736 }
737}</pre>
738</div></div>
739
740<p>Rather than having the host application bundle activator register
741the service, it is also possible for the the host application to simply
742get the bundle context from the bundle activator and register the
743service directly, but the presented approach is perhaps a little
744cleaner since it allows the host application to register/unregister the
745service when the system bundle starts/stops.</p>
746
747<p><a name="LaunchingandEmbeddingApacheFelix-hostserviceusage"></a></p>
748
749<h2><a name="LaunchingandEmbeddingApacheFelix-UsingServicesProvidedbyBundles"></a>Using Services Provided by Bundles</h2>
750
751<p>Using services provided by bundles follows the same general approach
752of using a host application bundle activator. The main complication for
753the host application using a service from a bundle is the fact that
754both the host application and the bundle must be using the same class
755definitions for the service interface classes. Since the host
756application cannot import classes from a bundle, this means that the
757service interface classes <b>must</b> be accessible on the class path,
758typically as part of the host application itself. The host application
759then must export the service interface package via the system bundle so
760that bundles installed into the embedded framework instance can import
761it. This is achieved using the <tt>org.osgi.framework.system.packages</tt> configuration property previously presented.</p>
762
763<p>Consider the following simple command service interface for which
764bundles provide implementations, such as might be used to create an
765extensible interactive shell:</p>
766
767<div class="code"><div class="codeContent">
768<pre class="code-java"><span class="code-keyword">package</span> host.service.command;
769
770<span class="code-keyword">public</span> class Command
771{
772 <span class="code-keyword">public</span> <span class="code-object">String</span> getName();
773 <span class="code-keyword">public</span> <span class="code-object">String</span> getDescription();
774 <span class="code-keyword">public</span> <span class="code-object">boolean</span> execute(<span class="code-object">String</span> commandline);
775}</pre>
776</div></div>
777
778<p>This package is simply part of the host application, which is potentially packaged into a JAR file and started with the "<tt>java -jar</tt>"
779command. Now consider the previously introduced host application bundle
780activator below, which simply provides access to the system bundle
781context:</p>
782
783<div class="code"><div class="codeContent">
784<pre class="code-java"><span class="code-keyword">package</span> host.core;
785
786<span class="code-keyword">import</span> org.osgi.framework.BundleActivator;
787<span class="code-keyword">import</span> org.osgi.framework.BundleContext;
788
789<span class="code-keyword">public</span> class HostActivator <span class="code-keyword">implements</span> BundleActivator
790{
791 <span class="code-keyword">private</span> BundleContext m_context = <span class="code-keyword">null</span>;
792
793 <span class="code-keyword">public</span> void start(BundleContext context)
794 {
795 m_context = context;
796 }
797
798 <span class="code-keyword">public</span> void stop(BundleContext context)
799 {
800 m_context = <span class="code-keyword">null</span>;
801 }
802
803 <span class="code-keyword">public</span> BundleContext getContext()
804 {
805 <span class="code-keyword">return</span> m_context;
806 }
807}</pre>
808</div></div>
809
810<p>With this bundle activator, the host application can command
811services provided by bundles installed inside its embedded Felix
812framework instance. The following code snippet illustrates one possible
813approach:</p>
814
815<div class="code"><div class="codeContent">
816<pre class="code-java"><span class="code-keyword">package</span> host.core;
817
818<span class="code-keyword">import</span> java.util.List;
819<span class="code-keyword">import</span> java.util.ArrayList;
820<span class="code-keyword">import</span> java.util.Map;
821<span class="code-keyword">import</span> host.service.command.Command;
822<span class="code-keyword">import</span> org.apache.felix.framework.Felix;
823<span class="code-keyword">import</span> org.apache.felix.framework.util.FelixConstants;
824<span class="code-keyword">import</span> org.apache.felix.framework.util.StringMap;
825<span class="code-keyword">import</span> org.apache.felix.framework.cache.BundleCache;
826<span class="code-keyword">import</span> org.osgi.util.tracker.ServiceTracker;
827
828<span class="code-keyword">public</span> class HostApplication
829{
830 <span class="code-keyword">private</span> HostActivator m_activator = <span class="code-keyword">null</span>;
831 <span class="code-keyword">private</span> Felix m_felix = <span class="code-keyword">null</span>;
832 <span class="code-keyword">private</span> ServiceTracker m_tracker = <span class="code-keyword">null</span>;
833
834 <span class="code-keyword">public</span> HostApplication()
835 {
836 <span class="code-comment">// Create a <span class="code-keyword">case</span>-insensitive configuration property map.
837</span> Map configMap = <span class="code-keyword">new</span> StringMap(<span class="code-keyword">false</span>);
838 <span class="code-comment">// Configure the Felix instance to be embedded.
839</span> configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, <span class="code-quote">"<span class="code-keyword">true</span>"</span>);
840 <span class="code-comment">// Add the bundle provided service <span class="code-keyword">interface</span> <span class="code-keyword">package</span> and the core OSGi
841</span> <span class="code-comment">// packages to be exported from the class path via the system bundle.
842</span> configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
843 <span class="code-quote">"org.osgi.framework; version=1.3.0,"</span> +
844 <span class="code-quote">"org.osgi.service.packageadmin; version=1.2.0,"</span> +
845 <span class="code-quote">"org.osgi.service.startlevel; version=1.0.0,"</span> +
846 <span class="code-quote">"org.osgi.service.url; version=1.0.0,"</span> +
847 <span class="code-quote">"host.service.command; version=1.0.0"</span>);
848 <span class="code-comment">// Explicitly specify the directory to use <span class="code-keyword">for</span> caching bundles.
849</span> configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, <span class="code-quote">"cache"</span>);
850
851 <span class="code-keyword">try</span>
852 {
853 <span class="code-comment">// Create host activator;
854</span> m_activator = <span class="code-keyword">new</span> HostActivator(m_lookupMap);
855 List list = <span class="code-keyword">new</span> ArrayList();
856 list.add(m_activator);
857
858 <span class="code-comment">// Now create an instance of the framework with
859</span> <span class="code-comment">// our configuration properties and activator.
860</span> m_felix = <span class="code-keyword">new</span> Felix(configMap, list);
861
862 <span class="code-comment">// Now start Felix instance.
863</span> m_felix.start();
864 }
865 <span class="code-keyword">catch</span> (Exception ex)
866 {
867 <span class="code-object">System</span>.err.println(<span class="code-quote">"Could not create framework: "</span> + ex);
868 ex.printStackTrace();
869 }
870
871 m_tracker = <span class="code-keyword">new</span> ServiceTracker(
872 m_activator.getContext(), Command.class.getName(), <span class="code-keyword">null</span>);
873 m_tracker.open();
874 }
875
876 <span class="code-keyword">public</span> <span class="code-object">boolean</span> execute(<span class="code-object">String</span> name, <span class="code-object">String</span> commandline)
877 {
878 <span class="code-comment">// See <span class="code-keyword">if</span> any of the currently tracked command services
879</span> <span class="code-comment">// match the specified command name, <span class="code-keyword">if</span> so then execute it.
880</span> <span class="code-object">Object</span>[] services = m_tracker.getServices();
881 <span class="code-keyword">for</span> (<span class="code-object">int</span> i = 0; (services != <span class="code-keyword">null</span>) &amp;&amp; (i &lt; services.length); i++)
882 {
883 <span class="code-keyword">try</span>
884 {
885 <span class="code-keyword">if</span> (((Command) services[i]).getName().equals(name))
886 {
887 <span class="code-keyword">return</span> ((Command) services[i]).execute(commandline);
888 }
889 }
890 <span class="code-keyword">catch</span> (Exception ex)
891 {
892 <span class="code-comment">// Since the services returned by the tracker could become
893</span> <span class="code-comment">// invalid at any moment, we will <span class="code-keyword">catch</span> all exceptions, log
894</span> <span class="code-comment">// a message, and then ignore faulty services.
895</span> <span class="code-object">System</span>.err.println(ex);
896 }
897 }
898 <span class="code-keyword">return</span> <span class="code-keyword">false</span>;
899 }
900
901 <span class="code-keyword">public</span> void shutdownApplication()
902 {
903 <span class="code-comment">// Shut down the felix framework when stopping the
904</span> <span class="code-comment">// host application.
905</span> m_felix.shutdown();
906 }
907}</pre>
908</div></div>
909
910<p>The above example is overly simplistic with respect to concurrency
911issues and error conditions, but it demonstrates the overall approach
912for using bundle-provided services from the host application. Note, to
913compile the above code you will need to compile against the Felix
914framework and Felix OSGi compendium JAR files, since the <tt>ServiceTracker</tt> classes are included in the compendium JAR file, not the framework JAR file.</p>
915
916<p><a name="LaunchingandEmbeddingApacheFelix-servicereflection"></a></p>
917
918<h3><a name="LaunchingandEmbeddingApacheFelix-UsingBundleServicesviaReflection"></a>Using Bundle Services via Reflection</h3>
919
920<p>It possible for the host application to use services provided by
921bundles without having access to the service interface classes and thus
922not needing to put the service interface classes on the class path. To
923do this, the host application uses the same general approach to acquire
924the system bundle context object, which it can use to look up service
925objects. Using either an LDAP filter or the service interface class
926name, the host application can retrieve the service object and then use
927standard Java reflection to invoke methods on the service object.</p>
928
929<p><a name="LaunchingandEmbeddingApacheFelix-caveat"></a></p>
930
931<h1><a name="LaunchingandEmbeddingApacheFelix-Caveat"></a>Caveat</h1>
932
933<p>The code in this document has not been thoroughly tested or even
934compiled and may be out of date with respect to the current Felix
935source code. If you find errors please report them so the that they can
936be corrected.</p>
937 </div>
938 </body></html>