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

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

I'm not sure I fully understand the described issue.
May be you could attach a sample code reproducing the exact problem you are 
describing ?

In the mean time, here is more information about the @Init annotation, and also 
about the @ServiceDependency used with a "name" attribute:

1- @Init annotation:
==============

>From the method annotated with @Init, you are allowed to dynamically add 
>dependencies using the API.
For instance, assuming that S depends on S1/S2/S3, you can then declare "S" as 
in the following example:

@Component
public class S {
    
    // required dependency on service "S1"
    @ServiceDependency
    S1 _s1;
    
    // S2, which dependency is dynamically added in init() method
    S2 _s2;

    // S3, which dependency is dynamically added in init() mehtod
    S3 _s3;
    
    // Inject the API, used by our init() method
    @Inject
    org.apache.felix.dm.Component _c;
    
    // Atomically adds dependencies on S2/S3
    @Init
    void init() {
        List l = new ArrayList();
        l.add(_c.getDependencyManager().createServiceDependency()
                .setService(S2.class)
                .setRequired(true)
                .setAutoConfig("_s2")
                .setInstanceBound(true));
        l.add(_c.getDependencyManager().createServiceDependency()
                .setService(S3.class, "(foo=bar)")
                .setRequired(true)
                .setAutoConfig("_s3")
                .setInstanceBound(true));
        
         _c.add(l);
    }
    
    @Start
    void start() {
       System.out.println("started: s2=" + _s2 + ", s3=" + _s3); 
    }
}


In the init() method, notice the following important points:

- S2/S3 dependencies are added atomically, using Component.add(List) method. 
When more than one dependency is added from the init() method, it is better to 
add them using a List, because List of Dependencies are
added atomically: doing so prevent the @Start method to be called if the first 
dependency (S2) is available before we add the last dependency S3.

Here, the @Start method will be called only after S2 and S3 dependencies have 
been added and are available.

- the S2/S3 extra dependencies are "instance bound": it means that even if S2 
and/or S3 are not available, then "S" component won't be
destroyed immediately.

You can refer to the following post, where Marcel explains "instance bound" 
dependencies:

   http://www.mail-archive.com/[email protected]/msg09314.html

2- Named @ServiceDependencies
=========================

Now, let's describe when to declare a @ServiceDependency with a "name" 
attribute:

"named" dependencies are only available using the annotations, not using the 
API.
When you declare a @ServiceDependency with a "name" attribute, you can 
configure its 'required' flag and its filter by returning a Map from the @Init 
method.

For instance, assuming that you want to configure the S2 'required' flag and 
also its filter from ConfigAdmin, then you can do it like this:

@Component
public class S {
    // Config Admin properties, where the S2 'required' flag and filter is 
configured
    private Dictionary config; 
    
    // Inject our configuration
    @ConfigurationDependency(pid="MyPid")
    void configure(Dictionary config) {
         this.config = config;
    }

    // S2 dependency, whose 'required' flag and filter is dynamically 
configured from init() method.
    @ServiceDependency(name="S2")
    S2 s2;
    
    /**
     * Configure our "S2" dependency, using the already injected configuration.
     * The returned Map will be used to configure our "S2" Dependency (see 
above).
     * The convention is: each Map keys must be prefixed with a dependency 
name, and must then
     * be suffixed with either "filter" (for the dependency filter) or 
"required" (for the dependency 'required' flag).
     */
    @Init
    Map init() {
        return new HashMap() {{
            put("S2.filter", m_config.get("filter"));
            put("S2.required", m_config.get("required"));
        }};
    }

    @Start
    void start() {
       System.out.println("started: s2=" + _s2 + ", s3=" + _s3); 
    }
}

You can refer to the following documentation for more information about named 
dependencies:

       
http://felix.apache.org/site/apache-felix-dependency-manager-using-annotations-lifecycle.html

Please, check "Dynamic Dependency Configuration" section.


by the way, I just saw that dependencymanager documentation is somewhat broken 
from URL:
   
http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/apache-felix-dependency-manager-using-annotations.html

Please refer to the old site for dm annotation documentation:
   
http://felix.apache.org/site/apache-felix-dependency-manager-using-annotations.html

(I will fix the doc from http://felix.apache.org/documentation asap).

                
> Named dependencies are not injected if new dependencies are added at init 
> phase.
> --------------------------------------------------------------------------------
>
>                 Key: FELIX-4050
>                 URL: https://issues.apache.org/jira/browse/FELIX-4050
>             Project: Felix
>          Issue Type: Bug
>          Components: Dependency Manager
>    Affects Versions: dependencymanager-3.1.0
>            Reporter: Tuomas Kiviaho
>
> Spec says that "In the Init method, you are yet allowed to add some 
> additional dependencies (but using the API)."
> I guess this means that I am allowed to call Component.add(). This leads to 
> state transition for instance when new service dependency is added since it's 
> started right away because component is already instantiated at this point. 
> Component.dependencyAvailable() is called if service tracker finds a match 
> right away and this in turn starts the state change calculation.
> Problem is that State uses components current instantiated status to 
> determinate whether it is bound or not and not the status what the component 
> was given to the activateService() method. State change calculation 
> transitions to bound state prematurely because component is now instantiated. 
> All required dependencies are available, because component is still unaware 
> of forthcoming named dependencies at this point.
> I suggest that some sort of placeholder dependencies are used which the named 
> dependencies will replace when they are created/configured. This also 
> approach also preserves the order in which dependencies were actually added 
> to the component. In the future there could be a new is/SetActive property to 
> DependencyActivation which could be used to turn on/off an already added 
> dependencies. Then named dependencies could be used as such instead of 
> placeholders and user could even configure them directly.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to