felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Felix > Apache Felix Dependency Manager - Using Annotations - Quick Tour
Date Wed, 08 Sep 2010 20:02:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/1/_/styles/combined.css?spaceKey=FELIX&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/FELIX/Apache+Felix+Dependency+Manager+-+Using+Annotations+-+Quick+Tour">Apache
Felix Dependency Manager - Using Annotations - Quick Tour</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~pderop">Pierre
De Rop</a>
    </h4>
        <br/>
                         <h4>Changes (12)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >h2. Registering a Service <br>
<br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">To
register a service, your can annotate your class with a _@Service_ 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 _provides_ attribute, which takes a list of classes to  expose from the
registry. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">To
register a service, your can annotate your class with a _@Component_ 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 _provides_ attribute, which takes a list of classes to expose from the registry. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" >To illustrate this, we are now
introducing a SpellChecker application <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> which provides a Felix &quot;spellcheck&quot; Gogo shell command. Gogo
is the  new <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> shell supported by the Felix Framework. Our &quot;spellcheck&quot; command
is <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> 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) <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> dependency over every available DictionaryService services. Such <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> DictionaryService represents a real dictionary for a given langage (it  has
a _lang_ service property), and is configurable/instantiable from Configuration Admin. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" >The OSGi Configuration Admin service
provides a mechanism for <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> configuring components (using ManagedService interfaces), and WebConsole <span
class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> actually implements this service. ConfigAdmin is also able to <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> instantiate some Services (using ManagedServiceFactory interfaces). <br></td></tr>
            <tr><td class="diff-unchanged" > <br>Now we have introduced
the background, here is the SpellCheck component: <br> <br>{code} <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">@Service(provides={SpellChecker.class},</span>
<span class="diff-added-words"style="background-color: #dfd;">@Component(provides={SpellChecker.class},</span>
<br></td></tr>
            <tr><td class="diff-changed-lines" >         <span class="diff-added-words"style="background-color:
#dfd;"> </span> properties={@Property(name=CommandProcessor.COMMAND_SCOPE, value=&quot;dmsample.annotation&quot;),
<br></td></tr>
            <tr><td class="diff-changed-lines" >                    
<span class="diff-added-words"style="background-color: #dfd;"> </span> @Property(name=CommandProcessor.COMMAND_FUNCTION,
values={&quot;spellcheck&quot;})}) <br></td></tr>
            <tr><td class="diff-unchanged" >public class SpellChecker { <br>
   // --- Gogo Shell command <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >In the code above, you see that
the SpellCheck is annotated with the <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">_@Service_</span>
<span class="diff-added-words"style="background-color: #dfd;">_@Component_</span>
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. <br></td></tr>
            <tr><td class="diff-unchanged" > <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>{code} <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">@Service(provides={SpellChecker.class},</span>
<span class="diff-added-words"style="background-color: #dfd;">@Component(provides={SpellChecker.class},</span>
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-changed-words">      <span
class="diff-added-chars"style="background-color: #dfd;"> </span> <span class="diff-added-chars"style="background-color:
#dfd;"> </span> </span> properties={@Property(name=CommandProcessor.COMMAND_SCOPE,
value=&quot;dmsample.annotation&quot;), <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-changed-words">                    <span
class="diff-added-chars"style="background-color: #dfd;">  </span></span>
@Property(name=CommandProcessor.COMMAND_FUNCTION, values={&quot;spellcheck&quot;})})
<br></td></tr>
            <tr><td class="diff-unchanged" >public class SpellChecker { <br>   
@ServiceDependency(required = false) <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >h2. Creating a Service from ConfigAdmin
<br> <br></td></tr>
            <tr><td class="diff-changed-lines" >The <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">_@Service_</span>
<span class="diff-added-words"style="background-color: #dfd;">_@Component_</span>
annotation is not the only one for creating services. Another one is the _@FactoryConfigurationAdapterService_
annotation which allows to instantiate many instances of the same   annotated service class
from ConfigAdmin (and WebConsole). To illustrate  this, let&#39;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 ... <br></td></tr>
            <tr><td class="diff-unchanged" > <br>{code} <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-QuickTour"></a>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&nbsp;  simple usage  scenarios using a SpellChecker sample application
with  annotated  components (the application is available from the felix  trunk, in the  dependencymanager/samples.annotation
maven subproject).</p>

<h2><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-Architecture"></a>Architecture</h2>

<p>Instead of writing Activators which extends the   DependencyActivatorBase, 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
  OSGI-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 bundle at runtime.</li>
</ul>


<p>At runtime, the metada 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><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-RegisteringaService"></a>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 langage (it  has
a <em>lang</em> service property), and is configurable/instantiable from Configuration
Admin.</p>

<p>The OSGi 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="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">@Component(provides={SpellChecker.class},
           properties={@Property(name=CommandProcessor.COMMAND_SCOPE, value=<span
class="code-quote">"dmsample.annotation"</span>),
                       @Property(name=CommandProcessor.COMMAND_FUNCTION,
values={<span class="code-quote">"spellcheck"</span>})})
<span class="code-keyword">public</span> class SpellChecker {
    <span class="code-comment">// --- Gogo Shell command
</span>
    @Descriptor(<span class="code-quote">"checks <span class="code-keyword">if</span>
word is found from an available dictionary"</span>)
    <span class="code-keyword">public</span> void spellcheck(@Descriptor(<span
class="code-quote">"the word to check"</span>)<span class="code-object">String</span>
word) {
       <span class="code-comment">// Check the proper existence of the word parameter,
using injected DictionaryService instances
</span>       <span class="code-comment">// ...
</span>    }
}
</pre>
</div></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><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-DependingonaService"></a>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&nbsp; 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="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"> <span class="code-keyword">public</span> <span
class="code-keyword">interface</span> DictionaryService {
    /**
     * Check <span class="code-keyword">for</span> the existence of a word.
     * @param word the word to be checked.
     * @<span class="code-keyword">return</span> <span class="code-keyword">true</span>
<span class="code-keyword">if</span> the word is in the dictionary, <span class="code-keyword">false</span>
otherwise.
     */
    <span class="code-keyword">public</span> <span class="code-object">boolean</span>
checkWord(<span class="code-object">String</span> word);
}
</pre>
</div></div>
<p>And here is our previous SpellChecker component, augmented with two new ServiceDependency
annotations:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">@Component(provides={SpellChecker.class},
           properties={@Property(name=CommandProcessor.COMMAND_SCOPE, value=<span
class="code-quote">"dmsample.annotation"</span>),
                       @Property(name=CommandProcessor.COMMAND_FUNCTION,
values={<span class="code-quote">"spellcheck"</span>})})
<span class="code-keyword">public</span> class SpellChecker {
    @ServiceDependency(required = <span class="code-keyword">false</span>)
    <span class="code-keyword">private</span> LogService m_log;

    <span class="code-keyword">private</span> CopyOnWriteArrayList&lt;DictionaryService&gt;
m_dictionaries = <span class="code-keyword">new</span> CopyOnWriteArrayList&lt;DictionaryService&gt;();

    @ServiceDependency(removed = <span class="code-quote">"removeDictionary"</span>)
    <span class="code-keyword">protected</span> void addDictionary(DictionaryService
dictionary) {
        m_dictionaries.add(dictionary);
    }
    
    <span class="code-keyword">protected</span> void removeDictionary(DictionaryService
dictionary) {
        m_dictionaries.remove(dictionary);
    }

    <span class="code-comment">// --- Gogo Shell command
</span>
    @Descriptor(<span class="code-quote">"checks <span class="code-keyword">if</span>
word is found from an available dictionary"</span>)
    <span class="code-keyword">public</span> void spellcheck(@Descriptor(<span
class="code-quote">"the word to check"</span>)<span class="code-object">String</span>
word)
    {
        m_log.log(LogService.LOG_INFO, <span class="code-quote">"Checking spelling
of word \"</span>" + word
            + <span class="code-quote">"\"</span> using the following
dictionaries: " + m_dictionaries);

        <span class="code-keyword">for</span> (DictionaryService dictionary
: m_dictionaries)
        {
            <span class="code-keyword">if</span> (dictionary.checkWord(word))
            {
                <span class="code-object">System</span>.out.println(<span
class="code-quote">"word "</span> + word + <span class="code-quote">" is correct"</span>);
                <span class="code-keyword">return</span>;
            }
        }
        <span class="code-object">System</span>.err.println(<span class="code-quote">"word
"</span> + word + <span class="code-quote">" is incorrect"</span>);
    }
}
</pre>
</div></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><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-CreatingaServicefromConfigAdmin"></a>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="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">@FactoryConfigurationAdapterService(factoryPid=<span class="code-quote">"DictionaryServiceFactory"</span>,
updated=<span class="code-quote">"updated"</span>)  
<span class="code-keyword">public</span> class DictionaryImpl <span class="code-keyword">implements</span>
DictionaryService {
    /**
     * We store all configured words in a thread-safe data structure, because ConfigAdmin
     * may invoke our updated method at any time.
     */
    <span class="code-keyword">private</span> CopyOnWriteArrayList&lt;<span
class="code-object">String</span>&gt; m_words = <span class="code-keyword">new</span>
CopyOnWriteArrayList&lt;<span class="code-object">String</span>&gt;();

    /**
     * Our Dictionary language.
     */
    <span class="code-keyword">private</span> <span class="code-object">String</span>
m_lang;

    /**
     * Our service will be initialized from ConfigAdmin, and we also handle updates in
<span class="code-keyword">this</span> method.
     * @param config The configuration where we'll lookup our words list (key=<span
class="code-quote">"words"</span>).
     */
    <span class="code-keyword">protected</span> void updated(Dictionary&lt;<span
class="code-object">String</span>, ?&gt; config) {
        m_lang = (<span class="code-object">String</span>) config.get(<span
class="code-quote">"lang"</span>);
        m_words.clear();
        <span class="code-object">String</span>[] words = (<span class="code-object">String</span>[])
config.get(<span class="code-quote">"words"</span>);
        <span class="code-keyword">for</span> (<span class="code-object">String</span>
word : words) {
            m_words.add(word);
        }
    }
           
    /**
     * Check <span class="code-keyword">if</span> a word exists <span class="code-keyword">if</span>
the list of words we have been configured from ConfigAdmin/WebConsole.
     */
    <span class="code-keyword">public</span> <span class="code-object">boolean</span>
checkWord(<span class="code-object">String</span> word) {
        <span class="code-keyword">return</span> m_words.contains(word);
    }
}
</pre>
</div></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 "DictionaryServiceFactory"  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="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">  @FactoryConfigurationAdapterService(factoryPid=<span class="code-quote">"DictionaryServiceFactory"</span>,
    propagate=<span class="code-keyword">true</span>,
    updated=<span class="code-quote">"updated"</span>,
    heading=<span class="code-quote">"Dictionary Services"</span>,
    description=<span class="code-quote">"Declare here some Dictionary instances,
allowing to instantiates some DictionaryService services <span class="code-keyword">for</span>
a given dictionary language"</span>,
    metadata={
        @PropertyMetaData(
            heading=<span class="code-quote">"Dictionary Language"</span>,
            description=<span class="code-quote">"Declare here the language
supported by <span class="code-keyword">this</span> dictionary. "</span>
+
                <span class="code-quote">"This property will be propagated
with the Dictionary Service properties."</span>,
            defaults={<span class="code-quote">"en"</span>},
            id=<span class="code-quote">"lang"</span>,
            cardinality=0),
        @PropertyMetaData(
            heading=<span class="code-quote">"Dictionary words"</span>,
            description=<span class="code-quote">"Declare here the list of
words supported by <span class="code-keyword">this</span> dictionary."</span>,
            defaults={<span class="code-quote">"hello"</span>, <span
class="code-quote">"world"</span>},
            id=<span class="code-quote">"words"</span>,
            cardinality=<span class="code-object">Integer</span>.MAX_VALUE)
    }
)  
<span class="code-keyword">public</span> class DictionaryImpl <span class="code-keyword">implements</span>
DictionaryService {
    ... code same as before
}
</pre>
</div></div>

<h2><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-"></a></h2>


<h2><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-ProvidinganAspect"></a>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 <b>decorate</b> 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.
  That's why the class also uses a <em>@ConfigurationDependency</em> annotation:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">@AspectService(ranking = 10, filter = <span class="code-quote">"(lang=en)"</span>)
<span class="code-keyword">public</span> class DictionaryAspect <span class="code-keyword">implements</span>
DictionaryService {
    /**
     * This is the service <span class="code-keyword">this</span> aspect is
applying to.
     */
    <span class="code-keyword">private</span> DictionaryService m_originalDictionary;

    /**
     * We store all configured words in a thread-safe data structure, because ConfigAdmin
may
     * invoke our updated method at any time.
     */
    <span class="code-keyword">private</span> CopyOnWriteArrayList&lt;<span
class="code-object">String</span>&gt; m_words = <span class="code-keyword">new</span>
CopyOnWriteArrayList&lt;<span class="code-object">String</span>&gt;();

    /**
     * Defines a configuration dependency <span class="code-keyword">for</span>
retrieving our english custom words (by <span class="code-keyword">default</span>,
     * our PID is our full class name).
     */
    @ConfigurationDependency
    <span class="code-keyword">protected</span> void updated(Dictionary&lt;<span
class="code-object">String</span>, ?&gt; config) {
        m_words.clear();
        <span class="code-object">String</span>[] words = (<span class="code-object">String</span>[])
config.get(<span class="code-quote">"words"</span>);
        <span class="code-keyword">for</span> (<span class="code-object">String</span>
word : words) {
            m_words.add(word);
        }
    }

    /**
     * Checks <span class="code-keyword">if</span> a word is found from our
custom word list. <span class="code-keyword">if</span> not, delegate to the decorated
     * dictionary.
     */
    <span class="code-keyword">public</span> <span class="code-object">boolean</span>
checkWord(<span class="code-object">String</span> word) {
        <span class="code-keyword">if</span> (m_words.contains(word)) {
            <span class="code-keyword">return</span> <span class="code-keyword">true</span>;
        }
        <span class="code-keyword">return</span> m_originalDictionary.checkWord(word);
    }
}
</pre>
</div></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 <em>field</em> 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><a name="ApacheFelixDependencyManager-UsingAnnotations-QuickTour-Howtorunthesamplecode"></a>How
to run the sample code</h2>

<ul>
	<li>Install the following bundles:</li>
</ul>


<p>&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.configadmin<br/>
&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.metatype<br/>
&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.http.jetty<br/>
&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.webconsole</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.dependencymanager<br/>
&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.dependencymanager.shell<br/>
&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.dependencymanager.runtime<br/>
&nbsp;&nbsp;&nbsp;&nbsp; org.apache.felix.dependencymanager.samples.annotation</p>


<ul>
	<li>Start felix</li>
	<li>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.</li>
	<li>Just type "spellcheck hello", and the command should reply a fantastic message,
like "word hello is correct".</li>
	<li>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.</li>
</ul>

    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/FELIX/Apache+Felix+Dependency+Manager+-+Using+Annotations+-+Quick+Tour">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23334956&revisedVersion=6&originalVersion=5">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/FELIX/Apache+Felix+Dependency+Manager+-+Using+Annotations+-+Quick+Tour?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message