felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From build...@apache.org
Subject svn commit: r879235 - in /websites/staging/felix/trunk/content: ./ documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations/apache-felix-dependency-manager-using-annotations-quick-tour.html
Date Fri, 20 Sep 2013 20:06:56 GMT
Author: buildbot
Date: Fri Sep 20 20:06:56 2013
New Revision: 879235

Log:
Staging update by buildbot for felix

Modified:
    websites/staging/felix/trunk/content/   (props changed)
    websites/staging/felix/trunk/content/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations/apache-felix-dependency-manager-using-annotations-quick-tour.html

Propchange: websites/staging/felix/trunk/content/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Fri Sep 20 20:06:56 2013
@@ -1 +1 @@
-1525108
+1525122

Modified: websites/staging/felix/trunk/content/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations/apache-felix-dependency-manager-using-annotations-quick-tour.html
==============================================================================
--- websites/staging/felix/trunk/content/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations/apache-felix-dependency-manager-using-annotations-quick-tour.html
(original)
+++ websites/staging/felix/trunk/content/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations/apache-felix-dependency-manager-using-annotations-quick-tour.html
Fri Sep 20 20:06:56 2013
@@ -18,7 +18,7 @@
     limitations under the License.
 -->
   <head>
-    <title>Apache Felix - Apache Felix Dependency Manager - Using Annotations - Quick
Tour</title>
+    <title>Apache Felix - Dependency Manager Annotations Quick Tour</title>
     <link rel="icon" href="/res/favicon.ico">
     <link rel="stylesheet" href="/res/site.css" type="text/css" media="all">
     <link rel="stylesheet" href="/res/codehilite.css" type="text/css" media="all">
@@ -62,7 +62,7 @@
     
     <div class="main">
       <div class="breadcrump" style="font-size: 80%;">
-        <a href="/">Home</a>&nbsp;&raquo&nbsp;<a href="/documentation.html">Documentation</a>&nbsp;&raquo&nbsp;<a
href="/documentation/subprojects.html">Apache Felix Subproject Documentation</a>&nbsp;&raquo&nbsp;<a
href="/documentation/subprojects/apache-felix-dependency-manager.html">Apache Felix Dependency
Manager</a>&nbsp;&raquo&nbsp;<a href="/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations.html">Apache
Felix Dependency Manager - Using Annotations</a>
+        <a href="/">Home</a>&nbsp;&raquo&nbsp;<a href="/documentation.html">Documentation</a>&nbsp;&raquo&nbsp;<a
href="/documentation/subprojects.html">Apache Felix Subproject Documentation</a>&nbsp;&raquo&nbsp;<a
href="/documentation/subprojects/apache-felix-dependency-manager.html">Apache Felix Dependency
Manager</a>&nbsp;&raquo&nbsp;<a href="/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations.html">Dependency
Manager Annotations</a>
       </div>
 
       
@@ -72,10 +72,328 @@
       </div>
       
       
-      <h1>Apache Felix Dependency Manager - Using Annotations - Quick Tour</h1>
-      
+      <h1>Dependency Manager Annotations Quick Tour</h1>
+      <p>This section presents a quick overview of the capabilities and usage of the

+DependencyManager java 5 annotations. In particular, we will recap the DependencyManager

+annotation architecture, and identify some simple usage scenarios using a SpellChecker 
+sample application with annotated components. 
+The application is available from the felix trunk, in the dependencymanager/samples.annotation

+subproject.</p>
+<h2 id="architecture">Architecture</h2>
+<p>Instead of writing Activators which extends the DependencyActivatorBase class, service

+components can now be annotated using the annotations provided by the 
+<em>org.apache.felix.dependencymanager.annotation</em> bundle. Annotations are
not reflectively 
+parsed at runtime; but we use a BND plugin which scans annotations at compilation phase 
+and generates a compact metadata file in the bundle's META-INF/dependencymanager 
+subdirectory. This has the following benefits:</p>
+<ul>
+<li>JVM startup speed is not affected, and class files are not parsed when the framework
is starting</li>
+<li>Moreover, since the annotations are not retained by the VM at runtime, it is not
necessary to load the annotation API bundle at runtime.</li>
+</ul>
+<p>At runtime, the metadata generated during the compilation phase are processed by
a 
+specific DependencyManager Runtime bundle, which is in charge of managing the service 
+component lifecycle and dependencies. This Runtime bundle actually uses the 
+DependencyManager programmatic API in order to manage the annotated components. 
+Annotated components can then be inspected with the DependencyManager Gogo shell, as it is
+the case with DM components declared through the programmatic DM API.</p>
+<h2 id="registering-a-service">Registering a Service</h2>
+<p>To register a service, your can annotate your class with a <em>@Component</em>
annotation, and 
+an instance of your class will be registered under all directly implemented interfaces 
+into the OSGi registry. You can however take control on the interfaces to be exposed, and

+in this case, you can use the <em>provides</em> attribute, which takes a list
of classes to
+expose from the registry.</p>
+<p>To illustrate this, we are now introducing a SpellChecker application which provides
a 
+Felix "spellcheck" Gogo shell command. Gogo is the  new shell supported by the Felix
+Framework. Our "spellcheck" command is implemented by the SpellChecker component which 
+accepts a string as  parameter. This string is then checked for proper existence. To do 
+the  checking, The SpellChecker class has a required/multiple (1..N) dependency over 
+every available DictionaryService services. Such DictionaryService represents a real 
+dictionary for a given language (it  has a <em>lang</em> service property), and
is 
+configurable/instantiable from the OSGi Configuration Admin Service.</p>
+<p>Configuration Admin service provides a mechanism for configuring components 
+(using ManagedService interfaces), and WebConsole actually implements this service. 
+ConfigAdmin is also able to instantiate some Services (using ManagedServiceFactory 
+interfaces).</p>
+<p>Now we have introduced the background, here is the SpellCheck component:</p>
+<div class="codehilite"><pre><span class="nd">@Component</span><span
class="o">(</span><span class="n">provides</span><span class="o">={</span><span
class="n">SpellChecker</span><span class="o">.</span><span class="na">class</span><span
class="o">},</span>
+           <span class="n">properties</span><span class="o">={</span><span
class="nd">@Property</span><span class="o">(</span><span class="n">name</span><span
class="o">=</span><span class="n">CommandProcessor</span><span class="o">.</span><span
class="na">COMMAND_SCOPE</span><span class="o">,</span> <span class="n">value</span><span
class="o">=</span><span class="s">&quot;dmsample.annotation&quot;</span><span
class="o">),</span>
+                       <span class="nd">@Property</span><span class="o">(</span><span
class="n">name</span><span class="o">=</span><span class="n">CommandProcessor</span><span
class="o">.</span><span class="na">COMMAND_FUNCTION</span><span class="o">,</span>
<span class="n">values</span><span class="o">={</span><span class="s">&quot;spellcheck&quot;</span><span
class="o">})})</span>
+<span class="kd">public</span> <span class="kd">class</span> <span
class="nc">SpellChecker</span> <span class="o">{</span>
+    <span class="c1">// --- Gogo Shell command</span>
+
+    <span class="nd">@Descriptor</span><span class="o">(</span><span
class="s">&quot;checks if word is found from an available dictionary&quot;</span><span
class="o">)</span>
+    <span class="kd">public</span> <span class="kt">void</span> <span
class="nf">spellcheck</span><span class="o">(</span><span class="nd">@Descriptor</span><span
class="o">(</span><span class="s">&quot;the word to check&quot;</span><span
class="o">)</span><span class="n">String</span> <span class="n">word</span><span
class="o">)</span> <span class="o">{</span>
+       <span class="c1">// Check the proper existence of the word parameter, using
injected DictionaryService instances</span>
+       <span class="c1">// ...</span>
+    <span class="o">}</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>In the code above, you see that the SpellCheck is annotated with the <em>@Component</em>

+annotation. Gogo runtime does not required shell commands to implement a  specific 
+interface. Commands just have to register some Pojos in the  OSGi registry, but the only

+thing required is to provide the Pojos with two service properties ( COMMAND_SCOPE, and 
+COMMAND_FUNCTION) which will  be used by the Gogo runtime when instropecting the Pojo 
+for invoking  the proper functions.</p>
+<p>So, coming back to the sample code, the SpellChecker class registers  itself into
the OSGi registry, using the <em>provides</em> attribute, which just refer to
our SpellChecker class, and the two  mandatory Gogo service properties are also specified
using the <em>@Property</em> annotation. It is not shown here, but service properties
can also be  provided dynamically from a method that can return a Map, and annotated  with
the <em>@Start</em> lifecycle callback, but we will see this feature in a another
section.</p>
+<h2 id="depending-on-a-service">Depending on a Service</h2>
+<p>Our SpellChecker component can expose itself as a Gogo shell command, but before
being 
+registered into the OSGi registry, we also need to be   injected with two dependencies: 
+one required dependency (at minimum) on a DictionaryService, and another optional one on

+a LogService.  First, let's look at the DictionaryService, which is a simple interface:</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kd">interface</span> <span class="nc">DictionaryService</span>
<span class="o">{</span>
+    <span class="cm">/**</span>
+<span class="cm">     * Check for the existence of a word.</span>
+<span class="cm">     * @param word the word to be checked.</span>
+<span class="cm">     * @return true if the word is in the dictionary, false otherwise.</span>
+<span class="cm">     */</span>
+    <span class="kd">public</span> <span class="kt">boolean</span>
<span class="nf">checkWord</span><span class="o">(</span><span
class="n">String</span> <span class="n">word</span><span class="o">);</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>And here is our previous SpellChecker component, augmented with two new ServiceDependency

+annotations:</p>
+<div class="codehilite"><pre><span class="nd">@Component</span><span
class="o">(</span><span class="n">provides</span><span class="o">={</span><span
class="n">SpellChecker</span><span class="o">.</span><span class="na">class</span><span
class="o">},</span>
+           <span class="n">properties</span><span class="o">={</span><span
class="nd">@Property</span><span class="o">(</span><span class="n">name</span><span
class="o">=</span><span class="n">CommandProcessor</span><span class="o">.</span><span
class="na">COMMAND_SCOPE</span><span class="o">,</span> <span class="n">value</span><span
class="o">=</span><span class="s">&quot;dmsample.annotation&quot;</span><span
class="o">),</span>
+                       <span class="nd">@Property</span><span class="o">(</span><span
class="n">name</span><span class="o">=</span><span class="n">CommandProcessor</span><span
class="o">.</span><span class="na">COMMAND_FUNCTION</span><span class="o">,</span>
<span class="n">values</span><span class="o">={</span><span class="s">&quot;spellcheck&quot;</span><span
class="o">})})</span>
+<span class="kd">public</span> <span class="kd">class</span> <span
class="nc">SpellChecker</span> <span class="o">{</span>
+    <span class="nd">@ServiceDependency</span><span class="o">(</span><span
class="n">required</span> <span class="o">=</span> <span class="kc">false</span><span
class="o">)</span>
+    <span class="kd">private</span> <span class="n">LogService</span>
<span class="n">m_log</span><span class="o">;</span>
+
+    <span class="kd">private</span> <span class="n">CopyOnWriteArrayList</span><span
class="o">&lt;</span><span class="n">DictionaryService</span><span
class="o">&gt;</span> <span class="n">m_dictionaries</span> <span
class="o">=</span> <span class="k">new</span> <span class="n">CopyOnWriteArrayList</span><span
class="o">&lt;</span><span class="n">DictionaryService</span><span
class="o">&gt;();</span>
+
+    <span class="nd">@ServiceDependency</span><span class="o">(</span><span
class="n">removed</span> <span class="o">=</span> <span class="s">&quot;removeDictionary&quot;</span><span
class="o">)</span>
+    <span class="kd">protected</span> <span class="kt">void</span>
<span class="nf">addDictionary</span><span class="o">(</span><span
class="n">DictionaryService</span> <span class="n">dictionary</span><span
class="o">)</span> <span class="o">{</span>
+       <span class="n">m_dictionaries</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span class="n">dictionary</span><span
class="o">);</span>
+    <span class="o">}</span>
+
+    <span class="kd">protected</span> <span class="kt">void</span>
<span class="nf">removeDictionary</span><span class="o">(</span><span
class="n">DictionaryService</span> <span class="n">dictionary</span><span
class="o">)</span> <span class="o">{</span>
+       <span class="n">m_dictionaries</span><span class="o">.</span><span
class="na">remove</span><span class="o">(</span><span class="n">dictionary</span><span
class="o">);</span>
+    <span class="o">}</span>
+
+    <span class="c1">// --- Gogo Shell command</span>
+
+    <span class="nd">@Descriptor</span><span class="o">(</span><span
class="s">&quot;checks if word is found from an available dictionary&quot;</span><span
class="o">)</span>
+    <span class="kd">public</span> <span class="kt">void</span> <span
class="nf">spellcheck</span><span class="o">(</span><span class="nd">@Descriptor</span><span
class="o">(</span><span class="s">&quot;the word to check&quot;</span><span
class="o">)</span><span class="n">String</span> <span class="n">word</span><span
class="o">)</span> <span class="o">{</span>
+       <span class="n">m_log</span><span class="o">.</span><span
class="na">log</span><span class="o">(</span><span class="n">LogService</span><span
class="o">.</span><span class="na">LOG_INFO</span><span class="o">,</span>
<span class="s">&quot;Checking spelling of word \&quot;&quot;</span>
<span class="o">+</span> <span class="n">word</span>
+          <span class="o">+</span> <span class="s">&quot;\&quot;
using the following dictionaries: &quot;</span> <span class="o">+</span>
<span class="n">m_dictionaries</span><span class="o">);</span>
+
+       <span class="k">for</span> <span class="o">(</span><span
class="n">DictionaryService</span> <span class="n">dictionary</span>
<span class="o">:</span> <span class="n">m_dictionaries</span><span
class="o">)</span> <span class="o">{</span>
+          <span class="k">if</span> <span class="o">(</span><span
class="n">dictionary</span><span class="o">.</span><span class="na">checkWord</span><span
class="o">(</span><span class="n">word</span><span class="o">))</span>
<span class="o">{</span>
+             <span class="n">System</span><span class="o">.</span><span
class="na">out</span><span class="o">.</span><span class="na">println</span><span
class="o">(</span><span class="s">&quot;word &quot;</span> <span
class="o">+</span> <span class="n">word</span> <span class="o">+</span>
<span class="s">&quot; is correct&quot;</span><span class="o">);</span>
+             <span class="k">return</span><span class="o">;</span>
+          <span class="o">}</span>
+       <span class="o">}</span>
+       <span class="n">System</span><span class="o">.</span><span
class="na">err</span><span class="o">.</span><span class="na">println</span><span
class="o">(</span><span class="s">&quot;word &quot;</span> <span
class="o">+</span> <span class="n">word</span> <span class="o">+</span>
<span class="s">&quot; is incorrect&quot;</span><span class="o">);</span>
+    <span class="o">}</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>There are many things to describe in the code above:</p>
+<p>First, we define an optional dependency on the LogService, by defining a 
+<em>@ServiceDependency(required=false)</em> annotation on our m_logService field:
This
+means that our component will be provided into the OSGi registry even if there 
+is no available LogService, and in this case, a NullObject will be injected in 
+our class field; 
+This will avoid to check for nullability, when using the m_logService field. 
+All optional dependencies applied on class fields are injected with a 
+NullObject (when not available). 
+The NullObject can be invoked and will do nothing. For a lot of cases that is 
+good enough to handle optional dependencies. But when you really want to check 
+if an optional service is there or not, then you have to apply the optional 
+dependency on a callback method, which will be called when the optional 
+service is available.</p>
+<p>Next comes the dependency on the DictionaryService. Here, we use a <em>ServiceDependency</em>

+annotation, but this time we apply it on a method (<em>add/removeDictionary</em>).
There is no 
+need to specify the "<em>required=true</em>"  flag because it is the default
value. Notice that 
+this behavior is different from the API, where service dependencies are optional by default
+. We use a callback method, because we just need to register all available 
+DictionaryService services in our dictionary list, which is used when checking word 
+existence. This list is a copy on write list because the dependency may be injected at 
+any time, possibly from   another thread. So, using a copy on write list avoid us to use
  synchronized methods.</p>
+<h2 id="creating-a-service-from-configadmin">Creating a Service from ConfigAdmin</h2>
+<p>The <em>@Component</em> annotation is not the only one for creating
services. Another one is 
+the <em>@FactoryConfigurationAdapterService</em> annotation which allows to instantiate
many 
+instances of the same annotated service class from ConfigAdmin (and WebConsole). 
+To illustrate this, let's take a look at our DictionaryImpl class which is part of the 
+SpellChecker sample. This service is required by the SpellChecker component, when 
+checking for proper word existence. And you can instantiate as many DictionaryService as

+you want, from ConfigAdmin ...</p>
+<div class="codehilite"><pre><span class="nd">@FactoryConfigurationAdapterService</span><span
class="o">(</span><span class="n">factoryPid</span><span class="o">=</span><span
class="s">&quot;DictionaryImplFactoryPid&quot;</span><span class="o">,</span>
<span class="n">updated</span><span class="o">=</span><span class="s">&quot;updated&quot;</span><span
class="o">)</span>
+<span class="kd">public</span> <span class="kd">class</span> <span
class="nc">DictionaryImpl</span> <span class="kd">implements</span> <span
class="n">DictionaryService</span> <span class="o">{</span>
+   <span class="cm">/**</span>
+<span class="cm">    * We store all configured words in a thread-safe data structure,
because ConfigAdmin</span>
+<span class="cm">    * may invoke our updated method at any time.</span>
+<span class="cm">    */</span>
+   <span class="kd">private</span> <span class="n">CopyOnWriteArrayList</span><span
class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span>
<span class="n">m_words</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">CopyOnWriteArrayList</span><span class="o">&lt;</span><span
class="n">String</span><span class="o">&gt;();</span>
+
+   <span class="cm">/**</span>
+<span class="cm">    * Our Dictionary language.</span>
+<span class="cm">    */</span>
+   <span class="kd">private</span> <span class="n">String</span>
<span class="n">m_lang</span><span class="o">;</span>
+
+   <span class="cm">/**</span>
+<span class="cm">    * Our service will be initialized from ConfigAdmin, and we also
handle updates in this method.</span>
+<span class="cm">    * @param config The configuration where we&#39;ll lookup our
words list (key=&quot;words&quot;).</span>
+<span class="cm">    */</span>
+   <span class="kd">protected</span> <span class="kt">void</span>
<span class="nf">updated</span><span class="o">(</span><span class="n">Dictionary</span><span
class="o">&lt;</span><span class="n">String</span><span class="o">,</span>
<span class="o">?&gt;</span> <span class="n">config</span><span
class="o">)</span> <span class="o">{</span>
+      <span class="n">m_lang</span> <span class="o">=</span> <span
class="o">(</span><span class="n">String</span><span class="o">)</span>
<span class="n">config</span><span class="o">.</span><span class="na">get</span><span
class="o">(</span><span class="s">&quot;lang&quot;</span><span
class="o">);</span>
+      <span class="n">m_words</span><span class="o">.</span><span
class="na">clear</span><span class="o">();</span>
+      <span class="n">String</span><span class="o">[]</span> <span
class="n">words</span> <span class="o">=</span> <span class="o">(</span><span
class="n">String</span><span class="o">[])</span> <span class="n">config</span><span
class="o">.</span><span class="na">get</span><span class="o">(</span><span
class="s">&quot;words&quot;</span><span class="o">);</span>
+      <span class="k">for</span> <span class="o">(</span><span
class="n">String</span> <span class="n">word</span> <span class="o">:</span>
<span class="n">words</span><span class="o">)</span> <span class="o">{</span>
+         <span class="n">m_words</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span class="n">word</span><span
class="o">);</span>
+      <span class="o">}</span>
+   <span class="o">}</span>
+
+   <span class="cm">/**</span>
+<span class="cm">    * Check if a word exists if the list of words we have been configured
from ConfigAdmin/WebConsole.</span>
+<span class="cm">    */</span>
+   <span class="kd">public</span> <span class="kt">boolean</span>
<span class="nf">checkWord</span><span class="o">(</span><span
class="n">String</span> <span class="n">word</span><span class="o">)</span>
<span class="o">{</span>
+      <span class="k">return</span> <span class="n">m_words</span><span
class="o">.</span><span class="na">contains</span><span class="o">(</span><span
class="n">word</span><span class="o">);</span>
+   <span class="o">}</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>Our DictionaryImpl class implements a DictionaryService, and our class will be registered

+under that interface (all directly implemented  interfaces are used when registering the

+service, but you can select  some others using the <em>provides</em> attribute).

+The <em>@FactoryConfigurationAdapterService</em> annotation will instantiate
our service for 
+each configuration created  from web console (and matching our "DictionaryImplFactoryPid"

+factoryPid).</p>
+<p>We also use the <em>updated</em> attribute, which specifies a callback
 method which will handle
+properties configured by ConfigAdmin. The  updated callback will also be called when our

+properties are changing.  Every properties are propagated to our service properties, 
+unless the  properties starting with a dot ("."). Configuration properties starting  with

+a dot (".") are considered private and are not propagated.</p>
+<p>Notice that this annotation also supports optional meta type attributes, which allow
to 
+customize the ConfigAdmin GUI, with custom  messages, like heading/property title,
+property type, property  description, etc ...). So, let's revisit our DisctionaryImpl 
+service,  but this time with meta type support:</p>
+<div class="codehilite"><pre><span class="nd">@FactoryConfigurationAdapterService</span><span
class="o">(</span><span class="n">factoryPid</span><span class="o">=</span><span
class="s">&quot;DictionaryImplFactoryPid&quot;</span><span class="o">,</span>
+    <span class="n">propagate</span><span class="o">=</span><span
class="kc">true</span><span class="o">,</span>
+    <span class="n">updated</span><span class="o">=</span><span
class="s">&quot;updated&quot;</span><span class="o">,</span>
+    <span class="n">heading</span><span class="o">=</span><span
class="s">&quot;Dictionary Services&quot;</span><span class="o">,</span>
+    <span class="n">description</span><span class="o">=</span><span
class="s">&quot;Declare here some Dictionary instances, allowing to instantiates some
DictionaryService services for a given dictionary language&quot;</span><span
class="o">,</span>
+    <span class="n">metadata</span><span class="o">={</span>
+       <span class="nd">@PropertyMetaData</span><span class="o">(</span>
+           <span class="n">heading</span><span class="o">=</span><span
class="s">&quot;Dictionary Language&quot;</span><span class="o">,</span>
+           <span class="n">description</span><span class="o">=</span><span
class="s">&quot;Declare here the language supported by this dictionary. &quot;</span>
<span class="o">+</span>
+              <span class="s">&quot;This property will be propagated with the Dictionary
Service properties.&quot;</span><span class="o">,</span>
+           <span class="n">defaults</span><span class="o">={</span><span
class="s">&quot;en&quot;</span><span class="o">},</span>
+           <span class="n">id</span><span class="o">=</span><span
class="s">&quot;lang&quot;</span><span class="o">,</span>
+           <span class="n">cardinality</span><span class="o">=</span><span
class="mi">0</span><span class="o">),</span>
+       <span class="nd">@PropertyMetaData</span><span class="o">(</span>
+           <span class="n">heading</span><span class="o">=</span><span
class="s">&quot;Dictionary words&quot;</span><span class="o">,</span>
+           <span class="n">description</span><span class="o">=</span><span
class="s">&quot;Declare here the list of words supported by this dictionary.&quot;</span><span
class="o">,</span>
+           <span class="n">defaults</span><span class="o">={</span><span
class="s">&quot;hello&quot;</span><span class="o">,</span> <span
class="s">&quot;world&quot;</span><span class="o">},</span>
+           <span class="n">id</span><span class="o">=</span><span
class="s">&quot;words&quot;</span><span class="o">,</span>
+           <span class="n">cardinality</span><span class="o">=</span><span
class="n">Integer</span><span class="o">.</span><span class="na">MAX_VALUE</span><span
class="o">)</span>
+    <span class="o">}</span>
+<span class="o">)</span>
+<span class="kd">public</span> <span class="kd">class</span> <span
class="nc">DictionaryImpl</span> <span class="kd">implements</span> <span
class="n">DictionaryService</span> <span class="o">{</span>
+    <span class="o">...</span> <span class="n">code</span> <span
class="n">same</span> <span class="n">as</span> <span class="n">before</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h2 id="providing-an-aspect">Providing an Aspect</h2>
+<p>As we have seen in the previous section, there are many annotations  that can be
used 
+to specify a service. Another one is the <em>@AspectService</em> annotation.
This annotation 
+allows to <em>decorate</em> an existing service in  order to add certain "capabilities"
to it, 
+like  adding a specific caching mechanism to a storage  service or implementing logging.

+Aspects can be plugged to an existing service at   runtime, and can also be removed 
+dynamically. This is transparent, and   the clients using the existing service are not 
+interrupted, they are  just rebound with the aspect service.</p>
+<p>As an example, we go back to our SpellChecker application, and we are now looking
at the 
+DictionaryAspect class. This class uses the <em>@Aspect{</em>}Service annotation
in order to add 
+some custom words to an English   DictionaryService (with the service property lang=en).

+The Extra words   to add to the English Dictionary will be configured from ConfigAdmin.<br
/>
+That's why the class also uses a <em>@ConfigurationDependency</em> annotation:</p>
+<div class="codehilite"><pre><span class="nd">@AspectService</span><span
class="o">(</span><span class="n">ranking</span> <span class="o">=</span>
<span class="mi">10</span><span class="o">,</span> <span class="n">filter</span>
<span class="o">=</span> <span class="s">&quot;(lang=en)&quot;</span><span
class="o">)</span>
+<span class="kd">public</span> <span class="kd">class</span> <span
class="nc">DictionaryAspect</span> <span class="kd">implements</span>
<span class="n">DictionaryService</span> <span class="o">{</span>
+   <span class="cm">/**</span>
+<span class="cm">    * This is the service this aspect is applying to.</span>
+<span class="cm">    */</span>
+   <span class="kd">private</span> <span class="n">DictionaryService</span>
<span class="n">m_originalDictionary</span><span class="o">;</span>
+
+   <span class="cm">/**</span>
+<span class="cm">    * We store all configured words in a thread-safe data structure,
because ConfigAdmin may</span>
+<span class="cm">    * invoke our updated method at any time.</span>
+<span class="cm">    */</span>
+   <span class="kd">private</span> <span class="n">CopyOnWriteArrayList</span><span
class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span>
<span class="n">m_words</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">CopyOnWriteArrayList</span><span class="o">&lt;</span><span
class="n">String</span><span class="o">&gt;();</span>
+
+   <span class="cm">/**</span>
+<span class="cm">    * Defines a configuration dependency for retrieving our english
custom words (by default,</span>
+<span class="cm">    * our PID is our full class name).</span>
+<span class="cm">    */</span>
+   <span class="nd">@ConfigurationDependency</span>
+   <span class="kd">protected</span> <span class="kt">void</span>
<span class="nf">updated</span><span class="o">(</span><span class="n">Dictionary</span><span
class="o">&lt;</span><span class="n">String</span><span class="o">,</span>
<span class="o">?&gt;</span> <span class="n">config</span><span
class="o">)</span> <span class="o">{</span>
+      <span class="n">m_words</span><span class="o">.</span><span
class="na">clear</span><span class="o">();</span>
+      <span class="n">String</span><span class="o">[]</span> <span
class="n">words</span> <span class="o">=</span> <span class="o">(</span><span
class="n">String</span><span class="o">[])</span> <span class="n">config</span><span
class="o">.</span><span class="na">get</span><span class="o">(</span><span
class="s">&quot;words&quot;</span><span class="o">);</span>
+      <span class="k">for</span> <span class="o">(</span><span
class="n">String</span> <span class="n">word</span> <span class="o">:</span>
<span class="n">words</span><span class="o">)</span> <span class="o">{</span>
+         <span class="n">m_words</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span class="n">word</span><span
class="o">);</span>
+      <span class="o">}</span>
+   <span class="o">}</span>
+
+  <span class="cm">/**</span>
+<span class="cm">    * Checks if a word is found from our custom word list. if not,
delegate to the decorated</span>
+<span class="cm">    * dictionary.</span>
+<span class="cm">    */</span>
+   <span class="kd">public</span> <span class="kt">boolean</span>
<span class="nf">checkWord</span><span class="o">(</span><span
class="n">String</span> <span class="n">word</span><span class="o">)</span>
<span class="o">{</span>
+      <span class="k">if</span> <span class="o">(</span><span
class="n">m_words</span><span class="o">.</span><span class="na">contains</span><span
class="o">(</span><span class="n">word</span><span class="o">))</span>
<span class="o">{</span>
+        <span class="k">return</span> <span class="kc">true</span><span
class="o">;</span>
+      <span class="o">}</span>
+      <span class="k">return</span> <span class="n">m_originalDictionary</span><span
class="o">.</span><span class="na">checkWord</span><span class="o">(</span><span
class="n">word</span><span class="o">);</span>
+    <span class="o">}</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>The annotation does the following: because our class implements the  DictionaryService

+contract, it will instantiate our service each time it finds another existing 
+DictionaryService matching the filter attribute  we provide in the annotation 
+(filter="(lang=en)"). And it will inject the existing service in our 
+m_originalDictionary field, by reflection. But we can also specify a field attribute in 
+the annotation, if  we  want to explicitly inject the existing service in a given class 
+field. So, any client depending on an English DictionaryService will be transparently 
+rebound to our aspect Dictionary.</p>
+<p>In the Annotation, also notice the <em>ranking</em> attribute: It is
 the level used to organize 
+the aspect chain ordering (multiple aspects  may be applied on a given service).</p>
+<p>The <em>ConfigurationDependency</em> is another dependency that we have
 not seen before: it is 
+used to configure the extra English words from  ConfigAdmin. This annotation normally 
+requires a pid parameter, which is  a persistent identifier uniquely identifying our 
+component, but by  default, the pid is set to the fully qualified name of our class.</p>
+<p>Notice that like the <em>@FactoryConfigurationAdapterService</em>, the
<em>@ConfigurationDependency</em>
+annotation also supports meta type attributes.</p>
+<h2 id="how-to-run-the-sample-code">How to run the sample code</h2>
+<p>Install the following bundles:</p>
+<div class="codehilite"><pre><span class="n">org</span><span class="p">.</span><span
class="n">apache</span><span class="p">.</span><span class="n">felix</span><span
class="p">.</span><span class="n">configadmin</span>
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">metatype</span>
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">http</span><span class="p">.</span><span class="n">jetty</span>
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">webconsole</span>
+
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">dependencymanager</span>
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">dependencymanager</span><span class="p">.</span><span class="n">shell</span>
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">dependencymanager</span><span class="p">.</span><span class="n">runtime</span>
+<span class="n">org</span><span class="p">.</span><span class="n">apache</span><span
class="p">.</span><span class="n">felix</span><span class="p">.</span><span
class="n">dependencymanager</span><span class="p">.</span><span class="n">samples</span><span
class="p">.</span><span class="n">annotation</span>
+</pre></div>
+
+
+<p>Start felix.</p>
+<p>Go to web console: in the Configuration panel, edit the "Dictionary  Services" Configuration.
By default, an English  dictionary is displayed. Just&nbsp; click on "save", then refresh
your web  browser (click on refresh): you will see a new dictionary service  instance. At
this point, a DictionaryService service will be enabled  (with the service property "lang=en"),&nbsp;
and the SpellCheck component  will be injected with it. Then you should see the "spellcheck"
command,  when typing&nbsp; "help" on the gogo shell.</p>
+<p>Just type "spellcheck hello", and the command should reply a fantastic message,
like "word hello is correct".</p>
+<p>You can also click on the "Aspect Dictionary" button, in order to decorate the 
+English dictionary with some custom words. By default, the  "aspect" word is 
+pre configured, but you can click on the "+" button in  order to add more words. 
+Then click on Save. At this point, the English  DictionaryService will be decorated with

+the aspect service. So, now, if  you type "spellcheck aspect", then the message 
+"word aspect is  correct" should be displayed.</p>
       <div class="timestamp" style="margin-top: 30px; font-size: 80%; text-align: right;">
-        Rev. 1422427 by fmeschbe on Sun, 16 Dec 2012 00:36:51 +0000
+        Rev. 1525122 by pderop on Fri, 20 Sep 2013 20:06:44 +0000
       </div>
       <div class="trademarkFooter"> 
         Apache Felix, Felix, Apache, the Apache feather logo, and the Apache Felix project



Mime
View raw message