blob: f7e97d9dd8e7ae962b98dd4c3e45d760722ddf6e [file] [log] [blame]
Clement Escoffier6b928e92008-05-16 20:33:54 +00001<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Clement Escoffier8251f602009-01-15 15:35:17 +00002<html><head>
3
4
Clement Escoffier6b928e92008-05-16 20:33:54 +00005
Clement Escoffier8251f602009-01-15 15:35:17 +00006 <title>Apache Felix - iPOJO in 10 minutes</title>
7 <link rel="stylesheet" href="ipojo-in-10-minutes_files/site.css" type="text/css" media="all">
8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
9 </head><body>
10 <div class="title"><div class="logo"><a href="http://felix.apache.org/site/index.html"><img alt="Apache Felix" src="ipojo-in-10-minutes_files/logo.png" border="0"></a></div><div class="header"><a href="http://www.apache.org/"><img alt="Apache" src="ipojo-in-10-minutes_files/apache.png" border="0"></a></div></div>
11 <div class="menu">
12<ul>
13 <li><a href="http://felix.apache.org/site/news.html" title="news">news</a></li>
14 <li><a href="http://felix.apache.org/site/license.html" title="license">license</a></li>
15 <li><span class="nobr"><a href="http://felix.apache.org/site/downloads.cgi" title="Visit page outside Confluence" rel="nofollow">downloads<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span></li>
16 <li><a href="http://felix.apache.org/site/documentation.html" title="documentation">documentation</a></li>
17 <li><a href="http://felix.apache.org/site/mailinglists.html" title="mailinglists">mailing lists</a></li>
18 <li><a href="http://felix.apache.org/site/contributing.html" title="Contributing">contributing</a></li>
19 <li><span class="nobr"><a href="http://www.apache.org/" title="Visit page outside Confluence" rel="nofollow">asf<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span></li>
20 <li><span class="nobr"><a href="http://www.apache.org/foundation/sponsorship.html" title="Visit page outside Confluence" rel="nofollow">sponsorship<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span></li>
21 <li><span class="nobr"><a href="http://www.apache.org/foundation/thanks.html" title="Visit page outside Confluence" rel="nofollow">sponsors<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span>
Clement Escoffier6b928e92008-05-16 20:33:54 +000022<!-- ApacheCon Ad -->
Clement Escoffier8251f602009-01-15 15:35:17 +000023<iframe src="ipojo-in-10-minutes_files/button.html" style="border-width: 0pt; float: left;" scrolling="no" width="135" frameborder="0" height="135"></iframe>
24<p style="height: 100px;">
25<!-- ApacheCon Ad -->
26</p></li></ul> </div>
27 <div class="main">
28<table class="sectionMacro" border="0" cellpadding="5" cellspacing="0" width="100%"><tbody><tr>
29<td class="confluenceTd" valign="top" width="80%">
30<h1><a name="iPOJOin10minutes-iPOJOin10minutes"></a>iPOJO in 10 minutes</h1>
Clement Escoffier6b928e92008-05-16 20:33:54 +000031
Clement Escoffier8251f602009-01-15 15:35:17 +000032<p><em>This page presents how to use the</em> <em>iPOJO</em> <em>runtime
33and its associated service component model. The concepts of the service
34component model are introduced, followed by a simple example that
35demonstrates the features of iPOJO.</em></p>
Clement Escoffier6b928e92008-05-16 20:33:54 +000036
Clement Escoffier8251f602009-01-15 15:35:17 +000037<h2><a name="iPOJOin10minutes-Introduction"></a>Introduction</h2>
Clement Escoffier6b928e92008-05-16 20:33:54 +000038
Clement Escoffier8251f602009-01-15 15:35:17 +000039<p>iPOJO aims to simplify service-oriented programming on OSGi frameworks; the name iPOJO is an abbreviation for <em>injected POJO</em>.
40iPOJO provides a new way to develop OSGi service components with the
41main goal being to simplify service component implementation by
42transparently managing the dynamics of the environment as well as other
43non-functional requirements. The iPOJO framework allows developers to
44more clearly separate functional code (i.e., the POJO) from the
45non-functional code (i.e., dependency management, service provision,
46configuration, etc.). iPOJO combines the functional and non-functional
47aspects at run time. To achieve this, iPOJO provides a simple and
48extensible service component model based on POJOs.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +000049
Clement Escoffier8251f602009-01-15 15:35:17 +000050<h2><a name="iPOJOin10minutes-ThePOJOconcept"></a>The POJO concept</h2>
Clement Escoffier6b928e92008-05-16 20:33:54 +000051
Clement Escoffier8251f602009-01-15 15:35:17 +000052<p>POJO is an acronym for Plain Old Java Object, but it embodies a
53concept that the simpler and less intrusive the design of a given
54framework, the better. The name is used to emphasize that a given
55object is not somehow special, but is an ordinary Java Object. Martin
56Fowler, Rebecca Parsons and Josh Mackenzie coined the term POJO in
57September 2000: "We wondered why people were so against using regular
58objects in their systems and concluded that it was because simple
59objects lacked a fancy name. So we gave them one, and it's caught on
60very nicely." From the developer's perspective, the iPOJO framework
61strives to only require POJOs in as much as it is possible.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +000062
Clement Escoffier8251f602009-01-15 15:35:17 +000063<h2><a name="iPOJOin10minutes-iPOJOservicecomponentoverview"></a>iPOJO service component overview</h2>
Clement Escoffier6b928e92008-05-16 20:33:54 +000064
Clement Escoffier8251f602009-01-15 15:35:17 +000065<p>A service component is able to provide and/or require services,
66where a service is an object that implements a given service interface
67embodied as a Java interface. In addition, iPOJO introduces a callback
68concept to notify a component about various state changes.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +000069
Clement Escoffier8251f602009-01-15 15:35:17 +000070<p>The component is the central concept in iPOJO. In the core iPOJO
71model, a component describes service dependencies, provided services,
72and callbacks; this information is recorded in the component's
73metadata. Then, the second important concept in iPOJO is component
74instances. A component instances is a special <em>version</em> of the
75component. By merging component metadata and instance configuration,
76the iPOJO runtime is able to manage the component, i.e., manage its
77life cycle, inject required services, publish provided services,
78discover needed services.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +000079
Clement Escoffier8251f602009-01-15 15:35:17 +000080<h2><a name="iPOJOin10minutes-Asimpleexample"></a>A simple example</h2>
Clement Escoffier6b928e92008-05-16 20:33:54 +000081
Clement Escoffier8251f602009-01-15 15:35:17 +000082<p>In this tutorial we will present how to:</p>
83<ul>
84 <li>Publish an OSGi service</li>
85 <li>Require an OSGi service</li>
86 <li>Use lifecycle callbacks to activate and deactivate components</li>
87</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +000088
89
Clement Escoffier8251f602009-01-15 15:35:17 +000090<h3><a name="iPOJOin10minutes-PresentationoftheSpellapplication"></a>Presentation of the <em>Spell</em> application</h3>
Clement Escoffier6b928e92008-05-16 20:33:54 +000091
Clement Escoffier8251f602009-01-15 15:35:17 +000092<p>To illustrate iPOJO features, we will implement a very simple application. This application is composed by three components:</p>
93<ul>
94 <li>A component implementing a dictionary service</li>
95 <li>A component requiring the dictionary service and providing a spellchecker service</li>
96 <li>A component requiring the spellchecker and providing an user interface</li>
97</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +000098
99
Clement Escoffier8251f602009-01-15 15:35:17 +0000100<p><img src="ipojo-in-10-minutes_files/spell.png" align="absmiddle" border="0"></p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000101
Clement Escoffier8251f602009-01-15 15:35:17 +0000102<h3><a name="iPOJOin10minutes-Preparingthetutorial"></a>Preparing the tutorial</h3>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000103
Clement Escoffier8251f602009-01-15 15:35:17 +0000104<p>This tutorial is based on Ant. So, you need to have the Ant program accessible in your path (see <span class="nobr"><a href="http://ant.apache.org/" title="Visit page outside Confluence" rel="nofollow">here<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span> to download and install Ant). Download the tutorial archive available <span class="nobr"><a href="http://people.apache.org/%7Eclement/ipojo/tutorials/10min/tutorial.zip" title="Visit page outside Confluence" rel="nofollow">here<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span> and then unzip it. The archive is composed by seven directories:</p>
105<ul>
106 <li>spell.services contains service interfaces used by the applications</li>
107 <li>spell.english contains an implementation of the Dictionary service (containing English words)</li>
108 <li>spell.checker
109contains an implementation of a Spell Checker. The spell checker
110requires a dictionary service and check if an input passage is correct
111(according to the words contained in the dictionary).</li>
112 <li>spell.gui
113contains a very simple user interface. This component uses a spell
114checker service. Then the user can interact with the spell checker with
115this user interface.</li>
116 <li>The task directory contains Ant tasks used to build the project</li>
117 <li>The solution directory contains an already developed version of the application.</li>
118 <li>Finally, the felix folder contains a configured version of the Felix runtime</li>
119</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000120
121
Clement Escoffier8251f602009-01-15 15:35:17 +0000122<h3><a name="iPOJOin10minutes-Thespell.servicesproject"></a>The spell.services project</h3>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000123
Clement Escoffier8251f602009-01-15 15:35:17 +0000124<p>The spell.services project contains only service interfaces. It is not an iPOJO powered bundle.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000125
Clement Escoffier8251f602009-01-15 15:35:17 +0000126<p>Go inside the Spell.services directory and create the file "src/spell/services/DictionaryService.java" for the following <em>Dictionary</em> service interface:</p>
127<div class="code"><div class="codeContent">
128<pre class="code-java"><span class="code-keyword">package</span> spell.services;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000129/**
Clement Escoffier8251f602009-01-15 15:35:17 +0000130 * A simple service <span class="code-keyword">interface</span> that defines a dictionary service.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000131 * A dictionary service simply verifies the existence of a word.
132**/
Clement Escoffier8251f602009-01-15 15:35:17 +0000133<span class="code-keyword">public</span> <span class="code-keyword">interface</span> DictionaryService {
Clement Escoffier6b928e92008-05-16 20:33:54 +0000134 /**
Clement Escoffier8251f602009-01-15 15:35:17 +0000135 * Check <span class="code-keyword">for</span> the existence of a word.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000136 * @param word the word to be checked.
Clement Escoffier8251f602009-01-15 15:35:17 +0000137 * @<span class="code-keyword">return</span> <span class="code-keyword">true</span> <span class="code-keyword">if</span> the word is in the dictionary,
138 * <span class="code-keyword">false</span> otherwise.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000139 **/
Clement Escoffier8251f602009-01-15 15:35:17 +0000140 <span class="code-keyword">public</span> <span class="code-object">boolean</span> checkWord(<span class="code-object">String</span> word);
141}</pre>
142</div></div>
143<p>Then, create the file "src/spell/services/SpellChecker.java" for the following <em>Spell Checker</em> service interface:</p>
144<div class="code"><div class="codeContent">
145<pre class="code-java"><span class="code-keyword">package</span> spell.services;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000146/**
Clement Escoffier8251f602009-01-15 15:35:17 +0000147 * A simple service <span class="code-keyword">interface</span> that defines a spell checker service.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000148 * A spell checker service checks the spelling of all words in a
149 * given passage. A passage is any number of words separated by
150 * a space character and the following punctuation marks: comma,
151 * period, exclamation mark, question mark, semi-colon, and colon.
152**/
Clement Escoffier8251f602009-01-15 15:35:17 +0000153<span class="code-keyword">public</span> <span class="code-keyword">interface</span> SpellChecker {
Clement Escoffier6b928e92008-05-16 20:33:54 +0000154 /**
Clement Escoffier8251f602009-01-15 15:35:17 +0000155 * Checks a given passage <span class="code-keyword">for</span> spelling errors. A passage is any
Clement Escoffier6b928e92008-05-16 20:33:54 +0000156 * number of words separated by a space and any of the following
157 * punctuation marks: comma (,), period (.), exclamation mark (!),
158 * question mark (?), semi-colon (;), and colon(:).
159 * @param passage the passage to spell check.
Clement Escoffier8251f602009-01-15 15:35:17 +0000160 * @<span class="code-keyword">return</span> An array of misspelled words or <span class="code-keyword">null</span> <span class="code-keyword">if</span> no
Clement Escoffier6b928e92008-05-16 20:33:54 +0000161 * words are misspelled.
162 **/
Clement Escoffier8251f602009-01-15 15:35:17 +0000163 <span class="code-keyword">public</span> <span class="code-object">String</span>[] check(<span class="code-object">String</span> passage);
164}</pre>
165</div></div>
166<p>Once created, you can build the project by launching Ant from the project directory.</p>
167<div class="code"><div class="codeContent">
168<pre class="code-java">$ ant
Clement Escoffier6b928e92008-05-16 20:33:54 +0000169Buildfile: build.xml
170clean:
171compile:
Clement Escoffier83507512008-10-13 07:33:03 +0000172 [mkdir] Created dir: d:\clement\workspaces\sandbox\ipojo\examples\tutorial-ant\
173 spell.services\output
174 [mkdir] Created dir: d:\clement\workspaces\sandbox\ipojo\examples\tutorial-ant\
175 spell.services\output\classes
176 [javac] Compiling 2 source files to d:\clement\workspaces\sandbox\ipojo\examples\
177 tutorial-ant\spell.services\output\classes
Clement Escoffier8251f602009-01-15 15:35:17 +0000178<span class="code-keyword">package</span>:
Clement Escoffier6b928e92008-05-16 20:33:54 +0000179 [bnd] spell.services 2
180BUILD SUCCESSFUL
Clement Escoffier8251f602009-01-15 15:35:17 +0000181Total time: 0 seconds</pre>
182</div></div>
183<p>The created bundle is inside the output directory (spell.services.jar). The build process use <span class="nobr"><a href="http://www.aqute.biz/Code/Bnd" title="Visit page outside Confluence" rel="nofollow">BND<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span>. The bundle manifest is described in the spell.services.bnd file.<br>
184Once this project is done, we are able to implement a Dictionary service.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000185
Clement Escoffier8251f602009-01-15 15:35:17 +0000186<h3><a name="iPOJOin10minutes-Thespell.englishproject:ProvidinganOSGiservice"></a>The spell.english project: Providing an OSGi service</h3>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000187
Clement Escoffier8251f602009-01-15 15:35:17 +0000188<p>The spell.english project is a simple dictionary implementation of
189the Dictionary service. It contains few English words. This
190implementation is an iPOJO component.<br>
191The first step is to implement the service. Create the "src/spell/english/EnglishDictionary.java" file for the following <em>Dictionary service</em> implementation:</p>
192<div class="code"><div class="codeContent">
193<pre class="code-java"><span class="code-keyword">package</span> spell.english;
194<span class="code-keyword">import</span> spell.services.DictionaryService;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000195/**
196 * An implementation of the Dictionary service containing English words
Clement Escoffier8251f602009-01-15 15:35:17 +0000197 * see DictionaryService <span class="code-keyword">for</span> details of the service.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000198 **/
Clement Escoffier8251f602009-01-15 15:35:17 +0000199<span class="code-keyword">public</span> class EnglishDictionary <span class="code-keyword">implements</span> DictionaryService {
200 <span class="code-comment">// The set of words contained in the dictionary.
201</span> <span class="code-object">String</span>[] m_dictionary = { <span class="code-quote">"welcome"</span>, <span class="code-quote">"to"</span>, <span class="code-quote">"the"</span>, <span class="code-quote">"ipojo"</span>, <span class="code-quote">"tutorial"</span> };
Clement Escoffier6b928e92008-05-16 20:33:54 +0000202 /**
203 * Implements DictionaryService.checkWord(). Determines
Clement Escoffier8251f602009-01-15 15:35:17 +0000204 * <span class="code-keyword">if</span> the passed in word is contained in the dictionary.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000205 * @param word the word to be checked.
Clement Escoffier8251f602009-01-15 15:35:17 +0000206 * @<span class="code-keyword">return</span> <span class="code-keyword">true</span> <span class="code-keyword">if</span> the word is in the dictionary,
207 * <span class="code-keyword">false</span> otherwise.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000208 **/
Clement Escoffier8251f602009-01-15 15:35:17 +0000209 <span class="code-keyword">public</span> <span class="code-object">boolean</span> checkWord(<span class="code-object">String</span> word) {
Clement Escoffier6b928e92008-05-16 20:33:54 +0000210 word = word.toLowerCase();
Clement Escoffier8251f602009-01-15 15:35:17 +0000211 <span class="code-comment">// This is very inefficient
212</span> <span class="code-keyword">for</span> (<span class="code-object">int</span> i = 0; i &lt; m_dictionary.length; i++) {
213 <span class="code-keyword">if</span> (m_dictionary[i].equals(word)) {
214 <span class="code-keyword">return</span> <span class="code-keyword">true</span>;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000215 }
216 }
Clement Escoffier8251f602009-01-15 15:35:17 +0000217 <span class="code-keyword">return</span> <span class="code-keyword">false</span>;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000218 }
Clement Escoffier8251f602009-01-15 15:35:17 +0000219}</pre>
220</div></div>
221<p>Notice that this class does not contains neither OSGi nor iPOJO
222specific code. It is just an implementation of the Dictionary Service
223interface.<br>
224Once created, we need to describe this component to ask iPOJO to manage
225it. To achieve this, create the "metadata.xml" file in the
226spell.english directory:</p>
227<div class="code"><div class="codeContent">
228<pre class="code-xml"><span class="code-tag">&lt;ipojo&gt;</span>
229<span class="code-tag">&lt;component classname=<span class="code-quote">"spell.english.EnglishDictionary"</span>&gt;</span>
230 <span class="code-tag">&lt;provides/&gt;</span>
231<span class="code-tag">&lt;/component&gt;</span>
232<span class="code-tag">&lt;instance component=<span class="code-quote">"spell.english.EnglishDictionary"</span>/&gt;</span>
233<span class="code-tag">&lt;/ipojo&gt;</span></pre>
234</div></div>
235<p>This file describes the Dictionary service implementation. First it creates a <em>component</em>. This component has a <em>classname</em> attribute containing the implementation class name. The <em>'provides'</em>
236element indicates that the component provide a service. Provided
237service interfaces are computed by iPOJO, so it is not necessary to
238indicate them. The <em>instance</em> element asks iPOJO to create an
239instance of the described component when the bundle starts. The
240relation between components and instances is the same than between
241classes and objects in the object oriented programming. The <em>component</em>
242attribute indicates which component needs to be instantiated. By
243default, component type name is the implementation class (i.e. the
244classname attribute).</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000245
Clement Escoffier8251f602009-01-15 15:35:17 +0000246<p>Then, we are able to create the bundle. In the spell.english directory launch the ant command:</p>
247<div class="code"><div class="codeContent">
248<pre class="code-java">$ ant
Clement Escoffier6b928e92008-05-16 20:33:54 +0000249Buildfile: build.xml
250clean:
Clement Escoffier83507512008-10-13 07:33:03 +0000251 [delete] Deleting directory d:\clement\workspaces\sandbox\ipojo\examples\
252 tutorial-ant\spell.english\output\classes
253 [delete] Deleting directory d:\clement\workspaces\sandbox\ipojo\examples\
254 tutorial-ant\spell.english\output
Clement Escoffier6b928e92008-05-16 20:33:54 +0000255buildclasspath:
256compile:
Clement Escoffier83507512008-10-13 07:33:03 +0000257 [mkdir] Created dir: d:\clement\workspaces\sandbox\ipojo\examples\
258 tutorial-ant\spell.english\output
259 [mkdir] Created dir: d:\clement\workspaces\sandbox\ipojo\examples\
260 tutorial-ant\spell.english\output\classes
261 [javac] Compiling 1 source file to d:\clement\workspaces\sandbox\ipojo\examples\
262 tutorial-ant\spell.english\output\classes
Clement Escoffier8251f602009-01-15 15:35:17 +0000263<span class="code-keyword">package</span>:
Clement Escoffier6b928e92008-05-16 20:33:54 +0000264 [bnd] spell.english 1
Clement Escoffier83507512008-10-13 07:33:03 +0000265 [ipojo] Input Bundle File : d:\clement\workspaces\sandbox\ipojo\examples\
266 tutorial-ant\spell.english\output\spell.english.jar
267 [ipojo] Metadata File : d:\clement\workspaces\sandbox\ipojo\examples\
268 tutorial-ant\spell.english\metadata.xml
Clement Escoffier6b928e92008-05-16 20:33:54 +0000269 [ipojo] Start bundle manipulation
270 [ipojo] Bundle manipulation - SUCCESS
Clement Escoffier83507512008-10-13 07:33:03 +0000271 [ipojo] Output File : d:\clement\workspaces\sandbox\ipojo\examples\
272 tutorial-ant\spell.english\output\spell.english.jar
Clement Escoffier6b928e92008-05-16 20:33:54 +0000273BUILD SUCCESSFUL
Clement Escoffier8251f602009-01-15 15:35:17 +0000274Total time: 1 second</pre>
275</div></div>
276<p>The created bundle is inside the output directory
277(spell.english.jar). The build process is based on BND and on the iPOJO
278Ant task. The manifest of the bundle is described in the
279spell.english.bnd file.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000280
Clement Escoffier8251f602009-01-15 15:35:17 +0000281<h3><a name="iPOJOin10minutes-Thespell.checkerproject:RequiringanOSGiservice"></a>The spell.checker project: Requiring an OSGi service</h3>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000282
Clement Escoffier8251f602009-01-15 15:35:17 +0000283<p>The spell.checker project aims to provide a <em>spell checker</em> service. However, to serve this service, this implementation requires a <em>dictionary</em>
284service. During this step, we will create an iPOJO component requiring
285a Dictionary service and providing the Spell Checker service.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000286
Clement Escoffier8251f602009-01-15 15:35:17 +0000287<p>First create the file "src/spell/checker/SpellCheck.java" in the spell.checker directory for the following <em>Check Speller service</em> implementation:</p>
288<div class="code"><div class="codeContent">
289<pre class="code-java"><span class="code-keyword">package</span> spell.checker;
290<span class="code-keyword">import</span> java.util.ArrayList;
291<span class="code-keyword">import</span> java.util.List;
292<span class="code-keyword">import</span> java.util.StringTokenizer;
293<span class="code-keyword">import</span> spell.services.DictionaryService;
294<span class="code-keyword">import</span> spell.services.SpellChecker;
295<span class="code-keyword">public</span> class SpellCheck <span class="code-keyword">implements</span> SpellChecker {
296 <span class="code-keyword">private</span> DictionaryService m_dictionary;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000297 /**
Clement Escoffier8251f602009-01-15 15:35:17 +0000298 * Implements SpellChecker.check(). Checks the given passage <span class="code-keyword">for</span> misspelled words.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000299 * @param passage the passage to spell check.
Clement Escoffier8251f602009-01-15 15:35:17 +0000300 * @<span class="code-keyword">return</span> An array of misspelled words or <span class="code-keyword">null</span> <span class="code-keyword">if</span> no words are misspelled.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000301 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000302 <span class="code-keyword">public</span> <span class="code-object">String</span>[] check(<span class="code-object">String</span> passage) {
303 <span class="code-comment">// No misspelled words <span class="code-keyword">for</span> an empty string.
304</span> <span class="code-keyword">if</span> ((passage == <span class="code-keyword">null</span>) || (passage.length() == 0)) { <span class="code-keyword">return</span> <span class="code-keyword">null</span>; }
305 List errorList = <span class="code-keyword">new</span> ArrayList();
306 <span class="code-comment">// Tokenize the passage using spaces and punctuation.
307</span> StringTokenizer st = <span class="code-keyword">new</span> StringTokenizer(passage, <span class="code-quote">" ,.!?;:"</span>);
308 <span class="code-comment">// Loop through each word in the passage.
309</span> <span class="code-keyword">while</span> (st.hasMoreTokens()) {
310 <span class="code-object">String</span> word = st.nextToken();
311 <span class="code-comment">// Check the current word.
312</span> <span class="code-keyword">if</span> (! m_dictionary.checkWord(word)) {
313 <span class="code-comment">// If the word is not correct, then add it
314</span> <span class="code-comment">// to the incorrect word list.
315</span> errorList.add(word);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000316 }
317 }
Clement Escoffier8251f602009-01-15 15:35:17 +0000318 <span class="code-comment">// Return <span class="code-keyword">null</span> <span class="code-keyword">if</span> no words are incorrect.
319</span> <span class="code-keyword">if</span> (errorList.size() == 0) { <span class="code-keyword">return</span> <span class="code-keyword">null</span>; }
320 <span class="code-comment">// Return the array of incorrect words.
321</span> <span class="code-keyword">return</span> (<span class="code-object">String</span>[]) errorList.toArray(<span class="code-keyword">new</span> <span class="code-object">String</span>[errorList.size()]);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000322 }
Clement Escoffier8251f602009-01-15 15:35:17 +0000323}</pre>
324</div></div>
325<p>This class implements the SpellChecker service interface as it will provide it. Moreover, it has a <em>special</em>
326field "_m_dictionary_". This field represents the required service.
327iPOJO will inject a Dictionary service when needed. So, the class can
328use it directly. Notice that this class as no OSGi specific code, both
329the service providing and the requiring are managed by iPOJO. If the
330used dictionary service leaves, iPOJO will try to find another
331provider. If no more providers are available, the instance is
332invalidated, and the provided service is withdrawn from the service
333registry.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000334
Clement Escoffier8251f602009-01-15 15:35:17 +0000335<p>Once implemented, we need to describe this component. Create the
336"metadata.xml" file in the spell.checker directory for the following
337component descriptor:</p>
338<div class="code"><div class="codeContent">
339<pre class="code-xml"><span class="code-tag">&lt;ipojo&gt;</span>
340<span class="code-tag">&lt;component classname=<span class="code-quote">"spell.checker.SpellCheck"</span>&gt;</span>
341 <span class="code-tag">&lt;requires field=<span class="code-quote">"m_dictionary"</span>/&gt;</span>
342 <span class="code-tag">&lt;provides/&gt;</span>
343<span class="code-tag">&lt;/component&gt;</span>
344<span class="code-tag">&lt;instance component=<span class="code-quote">"spell.checker.SpellCheck"</span>/&gt;</span>
345<span class="code-tag">&lt;/ipojo&gt;</span></pre>
346</div></div>
347<p>This description contains a '<em>requires'</em> element. This element indicates to iPOJO to manage the service dependency. The <em>field</em>
348attributes describe in which member of the class the service need to be
349injected. It is not necessary to write the required service as it is
350computed by iPOJO. Notice that iPOJO can inject required service by
351invoking methods too.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000352
Clement Escoffier8251f602009-01-15 15:35:17 +0000353<p>Finally, we are able to build the bundle. As for previous projects, launch Ant from the project directory.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000354
Clement Escoffier8251f602009-01-15 15:35:17 +0000355<h3><a name="iPOJOin10minutes-Thespell.checker.guiproject"></a>The spell.checker.gui project</h3>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000356
Clement Escoffier8251f602009-01-15 15:35:17 +0000357<p>The spell.check.gui project contains a very simple user interface (in Swing) allowing a user to interact with a <em>spell checker</em> service.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000358
Clement Escoffier8251f602009-01-15 15:35:17 +0000359<p>Create the "src\spell\gui\SpellCheckerGui.java" for the following implementation:</p>
360<div class="code"><div class="codeContent">
361<pre class="code-java"><span class="code-keyword">package</span> spell.gui;
362<span class="code-keyword">import</span> javax.swing.JButton;
363<span class="code-keyword">import</span> javax.swing.JFrame;
364<span class="code-keyword">import</span> javax.swing.JLabel;
365<span class="code-keyword">import</span> javax.swing.JTextField;
366<span class="code-keyword">import</span> spell.services.SpellChecker;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000367/**
368 * A very simple Gui interacting with the CheckSpeller service
369 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000370<span class="code-keyword">public</span> class SpellCheckerGui <span class="code-keyword">extends</span> JFrame {
Clement Escoffier6b928e92008-05-16 20:33:54 +0000371 /**
372 * Swing component where the user write the passage to check.
373 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000374 <span class="code-keyword">private</span> JTextField m_passage = <span class="code-keyword">null</span>;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000375
376 /**
377 * Check button
378 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000379 <span class="code-keyword">private</span> JButton m_checkButton = <span class="code-keyword">null</span>;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000380
381 /**
382 * Area where the result is displayed.
383 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000384 <span class="code-keyword">private</span> JLabel m_result = <span class="code-keyword">null</span>;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000385 /**
386 * Service dependency on the SpellChecker.
387 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000388 <span class="code-keyword">private</span> SpellChecker m_checker;
Clement Escoffier6b928e92008-05-16 20:33:54 +0000389
390 /**
391 * Constructor.
392 * Initialize the GUI.
393 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000394 <span class="code-keyword">public</span> SpellCheckerGui() {
395 <span class="code-keyword">super</span>();
Clement Escoffier6b928e92008-05-16 20:33:54 +0000396 initComponents();
Clement Escoffier8251f602009-01-15 15:35:17 +0000397 <span class="code-keyword">this</span>.setTitle(<span class="code-quote">"Spellchecker Gui"</span>);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000398 }
399 /**
400 * Initialize the Swing Gui.
401 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000402 <span class="code-keyword">private</span> void initComponents() {
Clement Escoffier6b928e92008-05-16 20:33:54 +0000403 java.awt.GridBagConstraints gridBagConstraints;
Clement Escoffier8251f602009-01-15 15:35:17 +0000404 m_checkButton = <span class="code-keyword">new</span> javax.swing.JButton();
405 m_result = <span class="code-keyword">new</span> javax.swing.JLabel();
406 m_passage = <span class="code-keyword">new</span> javax.swing.JTextField();
407 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); <span class="code-comment">//Stop Felix
408</span> getContentPane().setLayout(<span class="code-keyword">new</span> java.awt.GridBagLayout());
409 m_checkButton.setText(<span class="code-quote">"Check"</span>);
410 m_checkButton.addActionListener(<span class="code-keyword">new</span> java.awt.event.ActionListener() {
411 <span class="code-keyword">public</span> void actionPerformed(java.awt.event.ActionEvent e) {
Clement Escoffier6b928e92008-05-16 20:33:54 +0000412 check();
413 }
414 });
Clement Escoffier8251f602009-01-15 15:35:17 +0000415 gridBagConstraints = <span class="code-keyword">new</span> java.awt.GridBagConstraints();
Clement Escoffier6b928e92008-05-16 20:33:54 +0000416 gridBagConstraints.gridx = 0;
417 gridBagConstraints.gridy = 1;
Clement Escoffier8251f602009-01-15 15:35:17 +0000418 gridBagConstraints.insets = <span class="code-keyword">new</span> java.awt.Insets(2, 2, 2, 2);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000419 getContentPane().add(m_checkButton, gridBagConstraints);
Clement Escoffier8251f602009-01-15 15:35:17 +0000420 m_result.setPreferredSize(<span class="code-keyword">new</span> java.awt.Dimension(175, 20));
421 gridBagConstraints = <span class="code-keyword">new</span> java.awt.GridBagConstraints();
Clement Escoffier6b928e92008-05-16 20:33:54 +0000422 gridBagConstraints.gridx = 0;
423 gridBagConstraints.gridy = 2;
424 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
Clement Escoffier8251f602009-01-15 15:35:17 +0000425 gridBagConstraints.insets = <span class="code-keyword">new</span> java.awt.Insets(2, 2, 2, 2);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000426 getContentPane().add(m_result, gridBagConstraints);
Clement Escoffier8251f602009-01-15 15:35:17 +0000427 m_passage.setPreferredSize(<span class="code-keyword">new</span> java.awt.Dimension(175, 20));
428 gridBagConstraints = <span class="code-keyword">new</span> java.awt.GridBagConstraints();
Clement Escoffier6b928e92008-05-16 20:33:54 +0000429 gridBagConstraints.gridx = 0;
430 gridBagConstraints.gridy = 0;
431 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
Clement Escoffier8251f602009-01-15 15:35:17 +0000432 gridBagConstraints.insets = <span class="code-keyword">new</span> java.awt.Insets(2, 2, 2, 2);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000433 getContentPane().add(m_passage, gridBagConstraints);
434 pack();
435 }
436 /**
437 * Check Button action.
438 * Collects the user input and checks it.
439 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000440 <span class="code-keyword">private</span> void check() {
441 <span class="code-object">String</span>[] result = m_checker.check(m_passage.getText());
442 <span class="code-keyword">if</span> (result != <span class="code-keyword">null</span>) {
443 m_result.setText(result.length + <span class="code-quote">" word(s) are mispelled"</span>);
444 } <span class="code-keyword">else</span> {
445 m_result.setText(<span class="code-quote">"All words are correct"</span>);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000446 }
447 }
448 /**
449 * Start callback.
450 * This method will be called when the instance becomes valid.
Clement Escoffier8251f602009-01-15 15:35:17 +0000451 * It set the Gui visibility to <span class="code-keyword">true</span>.
Clement Escoffier6b928e92008-05-16 20:33:54 +0000452 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000453 <span class="code-keyword">public</span> void start() {
454 <span class="code-keyword">this</span>.setVisible(<span class="code-keyword">true</span>);
Clement Escoffier6b928e92008-05-16 20:33:54 +0000455 }
456 /**
457 * Stop callback.
458 * This method will be called when the instance becomes invalid or stops.
459 * It deletes the Gui.
460 */
Clement Escoffier8251f602009-01-15 15:35:17 +0000461 <span class="code-keyword">public</span> void stop() {
462 <span class="code-keyword">this</span>.dispose();
Clement Escoffier6b928e92008-05-16 20:33:54 +0000463 }
Clement Escoffier8251f602009-01-15 15:35:17 +0000464}</pre>
465</div></div>
466<p>Look at the three last methods. The <em>check</em> methods collect the user input and use a <em>Check speller</em> service to check this input. This method is called when the button is pressed by the user. The <em>start</em> and <em>stop</em>
467methods are lifecycle callbacks. As we need to display the user
468interface when the instance is created and to delete it when the
469instance stops, we need a way to be notified when we need to execute
470these actions. iPOJO provide an easy way to do this. The component
471provides two callback methods for its activation and deactivation,
472start and stop, respectively. Callbacks are used when the component
473needs to be informed about a component state change. In iPOJO, the
474component state is either <b>INVALID</b> (i.e., not all of the component's constraints are satisfied) or <b>VALID</b>
475(i.e., all of the component's constraints are satisfied). In this
476example, the start callback method set the GUI visibility to true; the
477stop callback method deletes the GUI. The component metadata will
478instruct iPOJO to invoke these methods when the component's state
479changes to <b>VALID</b> or <b>INVALID</b> respectively.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000480
Clement Escoffier8251f602009-01-15 15:35:17 +0000481<p>Create the <em>metadata.xml</em> file in the spell.chercker.gui directory with the following content:</p>
482<div class="code"><div class="codeContent">
483<pre class="code-xml"><span class="code-tag">&lt;ipojo&gt;</span>
484<span class="code-tag">&lt;component classname=<span class="code-quote">"spell.gui.SpellCheckerGui"</span>&gt;</span>
485 <span class="code-tag">&lt;requires field=<span class="code-quote">"m_checker"</span>/&gt;</span>
486 <span class="code-tag">&lt;callback transition=<span class="code-quote">"validate"</span> method=<span class="code-quote">"start"</span>/&gt;</span>
487 <span class="code-tag">&lt;callback transition=<span class="code-quote">"invalidate"</span> method=<span class="code-quote">"stop"</span>/&gt;</span>
488<span class="code-tag">&lt;/component&gt;</span>
489<span class="code-tag">&lt;instance component=<span class="code-quote">"spell.gui.SpellCheckerGui"</span>/&gt;</span>
490<span class="code-tag">&lt;/ipojo&gt;</span></pre>
491</div></div>
492<p>The component element again has the '<em>classname'</em> attribute that refers to the component implementation class. The '<em>requires</em>' element describes the <em>Check Speller</em> service dependency by simply specifying its associated component field. The '<em>callback'</em> elements describe which method to invoke when the component's state changes. Then the <em>'instance'</em> element asks iPOJO to create an instance of the component.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000493
Clement Escoffier8251f602009-01-15 15:35:17 +0000494<p>Once this file is created, you can compile the project by launching <em>ant</em> in the spell.checker.gui directory.</p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000495
Clement Escoffier8251f602009-01-15 15:35:17 +0000496<h2><a name="iPOJOin10minutes-Runningtheapplication"></a>Running the application</h2>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000497
Clement Escoffier8251f602009-01-15 15:35:17 +0000498<p>To run the example, start Felix. A distribution of Felix is provided
499in the felix directory. This version is configured to launch iPOJO
500automatically. From the Felix directory, launch the following command
501to start the framework. Then enter a profile name.</p>
502<div class="code"><div class="codeContent">
503<pre class="code-java">java -jar bin/felix.jar</pre>
504</div></div>
505<p>You can check installed bundles by using the '<em>ps</em>' command:</p>
506<div class="code"><div class="codeContent">
507<pre class="code-java">-&gt; ps
Clement Escoffier6b928e92008-05-16 20:33:54 +0000508START LEVEL 1
509 ID State Level Name
Clement Escoffier8251f602009-01-15 15:35:17 +0000510[ 0] [Active ] [ 0] <span class="code-object">System</span> Bundle (1.0.3)
Clement Escoffier6b928e92008-05-16 20:33:54 +0000511[ 1] [Active ] [ 1] Apache Felix Shell Service (1.0.0)
512[ 2] [Active ] [ 1] Apache Felix Shell TUI (1.0.0)
513[ 3] [Active ] [ 1] Apache Felix Bundle Repository (1.0.2)
Clement Escoffier8251f602009-01-15 15:35:17 +0000514[ 4] [Active ] [ 1] iPOJO (1.0.0)
515-&gt;</pre>
516</div></div>
517<p>iPOJO runtime is the bundle 4. Once started, install the four created bundles as above:</p>
518<div class="code"><div class="codeContent">
519<pre class="code-java">start file:../spell.services/output/spell.services.jar
Clement Escoffier6b928e92008-05-16 20:33:54 +0000520start file:../spell.english/output/spell.english.jar
521start file:../spell.checker/output/spell.checker.jar
Clement Escoffier8251f602009-01-15 15:35:17 +0000522start file:../spell.checker.gui/output/spell.checker.gui.jar</pre>
523</div></div>
524<p>When starting the GUI bundle, the user interface appears. Indeed, the <em>Check Speller</em> service is provided. You can interact with this service by entering a passage and clicking on the check button:<br>
525<img src="ipojo-in-10-minutes_files/ss.png" align="absmiddle" border="0"><br>
526Then, stop the <em>Dictionary</em> service provider (with the <em>stop 6</em>) command. The GUI disappears. Indeed, Spell Checker service cannot be provided as it depends on the Dictionary service.<br>
527<img src="ipojo-in-10-minutes_files/spell2.png" align="absmiddle" border="0"><br>
528Then, restart the Dictionary service provider with the <em>start 6</em> command. The GUI reappears immediately. You can try to stop the <em>check speller</em> service provider without stopping the <em>dictionary</em> service provider with the <em>stop 7</em> command. As for the last manipulation, the GUI disappears.<br>
529<img src="ipojo-in-10-minutes_files/spell3.png" align="absmiddle" border="0"><br>
530To go further in the exploration, modify the spell.cheker implementation. For example, add a simple trace, printing wrong words:</p>
531<div class="code"><div class="codeContent">
532<pre class="code-java"><span class="code-comment">// ...
533</span> <span class="code-comment">// Return <span class="code-keyword">null</span> <span class="code-keyword">if</span> no words are incorrect.
534</span> <span class="code-keyword">if</span> (errorList.size() == 0) { <span class="code-keyword">return</span> <span class="code-keyword">null</span>; }
Clement Escoffier83507512008-10-13 07:33:03 +0000535
Clement Escoffier8251f602009-01-15 15:35:17 +0000536 <span class="code-comment">// Return the array of incorrect words.
537</span> <span class="code-object">System</span>.out.println(<span class="code-quote">"Wrong words:"</span> + errorList); <span class="code-comment">// &lt;-- Add <span class="code-keyword">this</span> line
538</span> <span class="code-keyword">return</span> (<span class="code-object">String</span>[]) errorList.toArray(<span class="code-keyword">new</span> <span class="code-object">String</span>[errorList.size()]);</pre>
539</div></div>
Clement Escoffier83507512008-10-13 07:33:03 +0000540
Clement Escoffier8251f602009-01-15 15:35:17 +0000541<p>Then rebuild the spell.checker bundle and update it (with the
542'update 7' command). You will see the gui "blinking". In fact, the gui
543was stopped as the required spell checker service was no more
544available. As soon as it was back, the gui restarts. The gui didn't
545lose its state. The other services weren't stopped during the update.<br>
546You can uninstall the check service bundle and then re-install a new one (or the same one), you will see the same behavior. </p>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000547
Clement Escoffier8251f602009-01-15 15:35:17 +0000548<h2><a name="iPOJOin10minutes-Conclusion"></a>Conclusion</h2>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000549
Clement Escoffier8251f602009-01-15 15:35:17 +0000550<p>We saw how to use easily iPOJO to build service-oriented component. In this tutorial, we have demonstrated how to:</p>
551<ul>
552 <li>Publish OSGi services</li>
553 <li>Require OSGi services</li>
554 <li>Use lifecycle callbacks to activate and deactivate components</li>
555</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000556
557
Clement Escoffier8251f602009-01-15 15:35:17 +0000558<p>iPOJO provides a lot of others features that you can try in the
559others available tutorials. Subscribe to the Felix users mailing list
560by 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="ipojo-in-10-minutes_files/mail_small.gif" alt="" align="absmiddle" border="0" width="13" height="12"></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="ipojo-in-10-minutes_files/mail_small.gif" alt="" align="absmiddle" border="0" width="13" height="12"></sup></a></span>.</p>
561</td>
562<td class="confluenceTd" valign="top" width="20%">
563<h6><a name="iPOJOin10minutes-Overview"></a><b>Overview</b></h6>
564<ul>
565 <li><a href="http://felix.apache.org/site/apache-felix-ipojo.html" title="Apache Felix iPOJO">Home Page</a></li>
566 <li><a href="http://felix.apache.org/site/apache-felix-ipojo-feature-overview.html" title="Apache Felix iPOJO Feature Overview">iPOJO Feature Overview</a></li>
567 <li><a href="http://felix.apache.org/site/download.html" title="Download">Download &amp; Install </a></li>
568</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000569
570
Clement Escoffier8251f602009-01-15 15:35:17 +0000571<h6><a name="iPOJOin10minutes-GettingStarted"></a><b>Getting Started</b></h6>
572<ul>
573 <li><a href="" title="iPOJO in 10 minutes">iPOJO in 10 minutes</a></li>
574 <li><a href="http://felix.apache.org/site/how-to-use-ipojo-annotations.html" title="How to use iPOJO Annotations">How to use iPOJO Annotations</a></li>
575 <li><a href="http://felix.apache.org/site/ipojo-hello-word-maven-based-tutorial.html" title="iPOJO Hello Word (Maven-Based) tutorial">iPOJO Hello Word (Maven-Based) tutorial</a></li>
576 <li><a href="http://felix.apache.org/site/ipojo-advanced-tutorial.html" title="iPOJO Advanced Tutorial">iPOJO Advanced Tutorial</a></li>
577 <li><a href="http://felix.apache.org/site/ipojo-composition-tutorial.html" title="iPOJO Composition Tutorial">iPOJO Composition Tutorial</a></li>
578</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000579
580
Clement Escoffier8251f602009-01-15 15:35:17 +0000581<h6><a name="iPOJOin10minutes-UserGuide"></a><b>User Guide</b></h6>
582<ul>
583 <li><a href="http://felix.apache.org/site/describing-components.html" title="Describing components">Describing components (handler list) </a></li>
584 <li><a href="http://felix.apache.org/site/using-xml-schemas.html" title="Using XML Schemas">Using XML Schemas</a></li>
585 <li><a href="http://felix.apache.org/site/apache-felix-ipojo-testing-components.html" title="apache-felix-ipojo-testing-components">Testing components</a></li>
586 <li><a href="http://felix.apache.org/site/ipojo-advanced-topics.html" title="iPOJO Advanced Topics">Advanced Topics</a></li>
587 <li><a href="http://felix.apache.org/site/ipojo-faq.html" title="iPOJO FAQ">FAQ</a></li>
588</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000589
590
Clement Escoffier8251f602009-01-15 15:35:17 +0000591<h6><a name="iPOJOin10minutes-Tools"></a><b>Tools</b></h6>
592<ul>
593 <li><a href="http://felix.apache.org/site/ipojo-eclipse-plug-in.html" title="iPOJO Eclipse Plug-in">iPOJO Eclipse Plug-in</a></li>
594 <li><a href="http://felix.apache.org/site/ipojo-ant-task.html" title="iPOJO Ant Task">iPOJO Ant Task</a></li>
595 <li><a href="http://felix.apache.org/site/ipojo-maven-plug-in.html" title="iPOJO Maven Plug-in">iPOJO Maven Plug-in</a></li>
596 <li><a href="http://felix.apache.org/site/apache-felix-ipojo-junit4osgi.html" title="apache-felix-ipojo-junit4osgi">Junit4OSGi</a></li>
597 <li><a href="http://felix.apache.org/site/ipojo-concepts-overview.html" title="iPOJO Concepts Overview">iPOJO concepts overview</a></li>
598</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000599
600
Clement Escoffier8251f602009-01-15 15:35:17 +0000601<h6><a name="iPOJOin10minutes-DeveloperGuide"></a><b>Developer Guide</b></h6>
602<ul>
603 <li>API: <span class="nobr"><a href="http://people.apache.org/%7Eclement/ipojo/api/1.0/" title="Visit page outside Confluence" rel="nofollow">1.0<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span></li>
604 <li><a href="http://felix.apache.org/site/how-to-write-your-own-handler.html" title="How to write your own handler">How to write your own handler</a></li>
605 <li><a href="http://felix.apache.org/site/how-to-use-ipojo-manipulation-metadata.html" title="How to use iPOJO Manipulation Metadata">How to use iPOJO Manipulation Metadata</a></li>
606 <li><a href="http://felix.apache.org/site/dive-into-the-ipojo-manipulation-depths.html" title="Dive into the iPOJO Manipulation depths">Dive into the iPOJO Manipulation depths</a></li>
607</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000608
609
Clement Escoffier8251f602009-01-15 15:35:17 +0000610<h6><a name="iPOJOin10minutes-Misc&amp;Contact"></a><b>Misc &amp; Contact</b></h6>
611<ul>
612 <li><a href="http://felix.apache.org/site/apache-felix-ipojo-issuestracker.html" title="apache-felix-ipojo-issuestracker">Issues Tracker</a></li>
613 <li><a href="http://felix.apache.org/site/apache-felix-ipojo-supportedvms.html" title="apache-felix-ipojo-supportedVMs">Supported JVMs</a></li>
614 <li><a href="http://felix.apache.org/site/apache-felix-ipojo-supportedosgi.html" title="apache-felix-ipojo-supportedOSGi">Supported OSGi Implementations</a></li>
615 <li><span class="nobr"><a href="http://ipojo-dark-side.blogspot.com/" title="Visit page outside Confluence" rel="nofollow">iPOJO's Dark Side Blog<sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span></li>
616 <li><a href="http://felix.apache.org/site/future-ideas.html" title="Future Ideas">Future Ideas</a></li>
617 <li><a href="http://felix.apache.org/site/contact.html" title="Contact">Contact</a></li>
618 <li><a href="http://felix.apache.org/site/related-works.html" title="Related Works">Related Works</a></li>
619 <li><a href="http://felix.apache.org/site/article-presentations.html" title="Article &amp; Presentations">Article &amp; Presentations</a></li>
620</ul>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000621
622
Clement Escoffier8251f602009-01-15 15:35:17 +0000623<hr>
624<div class="" align="center">
625<p><span class="nobr"><a href="http://cwiki.apache.org/confluence/createrssfeed.action?types=blogpost&amp;statuses=created&amp;statuses=modified&amp;spaces=FELIX&amp;labelString=iPOJO&amp;rssType=atom&amp;maxResults=10&amp;timeSpan=5&amp;publicFeed=true&amp;title=iPOJO%20Atom%20Feed" title="Stay tuned!" rel="nofollow"><img src="ipojo-in-10-minutes_files/feed-icon-32x32.png" align="absmiddle" border="0"><sup><img class="rendericon" src="ipojo-in-10-minutes_files/linkext7.gif" alt="" align="absmiddle" border="0" width="7" height="7"></sup></a></span></p></div>
Clement Escoffier6b928e92008-05-16 20:33:54 +0000626
Clement Escoffier8251f602009-01-15 15:35:17 +0000627<script type="text/javascript">
628var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
629document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
630</script><script src="ipojo-in-10-minutes_files/ga.js" type="text/javascript"></script>
631<script type="text/javascript">
632var pageTracker = _gat._getTracker("UA-1518442-4");
633pageTracker._trackPageview();
634</script>
635</td></tr></tbody></table>
636 </div>
637 </body></html>