[ 
https://issues.apache.org/jira/browse/FELIX-5320?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15422636#comment-15422636
 ] 

Pierre De Rop commented on FELIX-5320:
--------------------------------------

Hello Andrea;

You normally use an Adapter in order to create another component on top of an 
existing one. Typically, for example you want to create a management component 
(like a servlet, or an amdatu restful web service) on top of an existing 
service component. 

say you are developing a nosql database, and you have for instance a 
"MyNoSqlDatabase" service component:

{code}
dm.add(createComponent()
    .setImplementation(MyNoSqlDatabaseImpl.class)
    .setInterface(MyNoSqlDatabase.class.getName(), null));
{code}

Now, assume you wan to make a restful web service which allows to administer 
your database. To do so, you wan to be modular and you want to make (for 
example) a jax rs web component, which would allow for example to display the 
number of transactions performed, or tune your nosql database from the web. 
So, you would in this case write an adapter component, like the following, 
which creates an amdatu web service component on top of the existing 
MyNoSqlDatabase service component:

{code}
dm.add(createAdapterService(MyNoSqlDatabase.class, null)
    .setImplementation(MyNoSqlDatabaseAdmin.class)
    .setInterface(Object.class.getName(), null));
{code}

and your jax rs amdatu web service used to aminister your no sql database:

{code}
@Path("mynosql")
class MyNoSqlDatabaseAdmin {
    volatile MyNoSqlDatabase database; // original database component, injected

    @GET
    @Produces("text/plain")
    public int transactions()  {
          return database.getTransactions();
     }
}
{code}

I don't know if you need or not adapter, but let's assume that yes, you need an 
adapter. 
So, getting back to your initial question: your want to add a dynamic 
dependency for your adapter, based on the adaptee.

So, in our example, the adaptee is "MyNoSqlDatabase". Now, assume that the  
MyNoSqlDatabase has some services properties. These service properties are by 
default propagated to the adaptee service properties (MyNoSqlDatabaseAdmin). 
Now, if you want to get access to the adaptee service properties, you can 
simply define a callback for the adaptee, instead of inject it in a compatible 
map field.
And the callback may then use a signature which takes the adaptee, as well as a 
map for the adaptee service properties. You can then just keep the adaptee 
service properties and use it from your adapter init method in order to decide 
to add (or not) an additiona adapter dependency.

let's see this a a concrete example. First, let's redefine the adapter 
Activator:

{code}
dm.add(createAdapterService(MyNoSqlDatabase.class, null, "setDatabase", null /* 
no change callback */, null /* no remove callback */)
    .setImplementation(MyNoSqlDatabaseAdmin.class)
    .setInterface(Object.class.getName(), null));
{code}

and let's refactor the adapter with the "setDatabase" callback

{code}
@Path("mynosql")
class MyNoSqlDatabaseAdmin {
    volatile MyNoSqlDatabase database; // original database component
    volatile Map databaseProperties; // original database service properties
    volatile SomeOtherService otherService; // dependency dynamically added 
from init method

    void setDatabase(MyNoSqlDatabase, Map properties) {
        this.database = database;
        this.databaseProperties = properties;
   }

   void init(Component comp) {
       // at this point, the database and database properties have been 
injected: then depending on the database service properties (which are by 
default 
       // propagated to our adapter service properties), then possibly add one 
more service dependency:

       if 
(databasePropertiesRequiresAnotherDependency(this.databaseProperties)) {
          DependencyManager dm = c.getDependencyManager();
          String filter = getFilter(databaseProperties);
          
comp.add(dm.createServiceDependency().setService(SomeOtherService.class, 
filter).setRequired(true));
       }
   }

    @GET
    @Produces("text/plain")
    public int transactions()  {
          return database.getTransactions();
     }
}
{code}

so, in the above example, the database (adaptee) is injected using the 
setDatabase method and the service properties are kept in the 
"databaseProperties", which is then reused in the init method, in order to 
possibly add an extra dependency.

Notice that if you don't need an adapter at all, you can do the same with a 
regular Component.

does this help ?



> Dependency Manager: adapter service propagates adaptee properties *after* the 
> init (and start) callbacks are called
> -------------------------------------------------------------------------------------------------------------------
>
>                 Key: FELIX-5320
>                 URL: https://issues.apache.org/jira/browse/FELIX-5320
>             Project: Felix
>          Issue Type: Bug
>          Components: Dependency Manager
>    Affects Versions: org.apache.felix.dependencymanager-r8
>            Reporter: Andrea Leofreddi
>
> In an adapter service, created using the createAdapterService method of 
> DependencyManager class, one would expect to find the adaptee's properties 
> being propagated to the adapter service itself, as stated in the 
> documentation 
> (http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/component-adapter.html).
> Instead no propagation happens, and both init and start methods won't see any 
> propagated properties.
> After investigating I've found that propagations indeed happens (via 
> AdapterServiceImpl's propagateAdapteeProperties) only after the callbacks are 
> called.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to