Instantiate component with property selectors?

10 views
Skip to first unread message

project2501

unread,
Apr 9, 2017, 6:52:54 PM4/9/17
to ipopo-users
Hi,
  Pardon the potentially dumb question. When using:

from pelix.ipopo.constants import use_ipopo

# ... considering "context" being a BundleContext object
with use_ipopo(context) as ipopo:
    # use the iPOPO core service with the "ipopo" variable
    ipopo.instantiate("my.factory", "my.component",
                      {"some.property": [1, 2, 3], "answer": 42})

Is it possible to declare properties to select the appropriate instance factory? Since this works
in the decorator I'm wondering how this is done programmatically.

Thank you.

Thomas Calmant

unread,
Apr 12, 2017, 10:50:50 AM4/12/17
to ipopo...@googlegroups.com
Hi,

Could you detail a bit more what you want to do ?

Cheers,
Thomas


--
Vous recevez ce message, car vous êtes abonné au groupe Google Groupes "ipopo-users".
Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse ipopo-users+unsubscribe@googlegroups.com.
Pour obtenir davantage d'options, consultez la page https://groups.google.com/d/optout.

Darren G

unread,
Apr 12, 2017, 10:53:20 AM4/12/17
to ipopo...@googlegroups.com
Let's say I have two components of same factory. They have different properties.

How do I select which one to instantiate?


Thomas Calmant

unread,
Apr 12, 2017, 11:11:40 AM4/12/17
to ipopo...@googlegroups.com
Hi,

Let's say you have the following factory:

    @ComponentFactory("sample-factory")
    @Provides("my.service")
    @Property("_var_a", "var.A")
    @Property("_var_b", "var.B")
    @Instantiate("instance_1", {"var.A": "from @Instantiate"})
    class MyFactory(object):
        def __init__(self):
            self._var_a = None
            self._var_b = None

        def show(self):
            print("A:", self._var_a, "- B:", self._var_b)

Then, you instantiate new components from this factory:

    with use_ipopo(context) as ipopo:
        instance_2 = ipopo.instantiate(
            "sample-factory", "instance_2",
            {"var.A": "from instantiate()", "var.B": 1})

        instance_3 = ipopo.instantiate(
            "sample-factory", "instance_2",
            {"var.A": "from instantiate()", "var.B": 2})

Those three components (instances) are from the same factory,
with different properties.

If you want to access them, you have two solutions:

1. If the components provide a service, simply use the LDAP filter:

    instance_3 = context.get_service_reference(
        "my.service", "(var.B==2)")

2. Look for the properties in the iPOPO components details

    with use_ipopo(context) as ipopo:
        for name, factory, state in ipopo.get_instances():
            if factory != "sample-factory":
                continue

            details = ipopo.get_instance_details(name)
            properties = details["properties"]
            if properties["var.B"] == 2:
                # Found it
                instance_3 = ipopo.get_instance(name)
                break

Hoping I've answered your question correctly,
Cheers,
Thomas

Darren G

unread,
Apr 12, 2017, 11:49:32 AM4/12/17
to ipopo...@googlegroups.com
Thanks for the info. Let me add a more clear example and see if your answer still applies.

Consider below:

@ComponentFactory(name="SomeComponentFactory")
@Property("part","part", "A")
@Property("type", "type", "json")
@Requires("config", "config", spec_filter="(usable=True)")
@Provides(specifications="some.component")
class SomeComponentA(object):
   ...

@ComponentFactory(name="SomeComponentFactory")
@Property("part", "part", "B")
@Property("type", "type", "json")
@Requires("config", "config", spec_filter="(usable=True)")
@Provides(specifications="some.component")
class SomeComponentB(object):
   ...

@ComponentFactory(name="UserComponentFactory")
@Requires("comp", "some.component", spec_filter="(part=A)")
class UserComponent:
   ...


In UserComponent I can add a selector (part=A) to select the appropriate Factory and instantiate SomeComponentA.

Using 

ipopo.instantiate("SomeComponentFactory","comp.a",{"part":"A"})

It sets part=A on the new instance which could be SomeComponentB. It doesn't use the passed in properties as a selector the way the decorator does.
I couldn't see a way to provide property selectors using ipopo.instantiate.

Hope this helps. Thanks for your suggestions.

Thomas Calmant

unread,
Apr 12, 2017, 12:31:00 PM4/12/17
to ipopo...@googlegroups.com
Hi,

You can't have two implementations of a factory with the same name: they can provide the same service (which is the link between components), but they must have different names.
The value given in @Property is the default value, not a constant one (although, an @ConstantProperty decorator could be an interesting feature)
In your example, you should have the factory names "SomeComponentFactoryA" and "SomeComponentFactoryB", for example.

Concerning the setup of the service filter at instantiation time, you have two solutions:

1/ use the special property "requires.filters", which must contain a dictionary associating the name of an injected field to its LDAP filter:

    ipopo.instantiate("SomeComponentFactory","comp.a",{"requires.filters": {"comp": "(part=A)"}})

2/ use the decorator @RequiresVarFilter

@ComponentFactory(name="UserComponentFactory")
@RequiresVarFilter("comp", "some.component", spec_filter="(part={part.name})")
@Property('_part', 'part.name', 'A')
class UserComponent:
...

Then instantiate with:
ipopo.instantiate("SomeComponentFactory","comp.a",{"part.name": "A"})

Cheers,
Thomas

Darren G

unread,
Apr 12, 2017, 1:03:10 PM4/12/17
to ipopo...@googlegroups.com
Hi

Since ipopo.instantiate takes a factory it seems to lack the abstraction of requesting a component by specification and spec filter the way it works in the decorators. Thus I'm not sure we can benefit from AbstractFactory pattern instantiating components directly. 

A better approach IMO is something like this.

comp = ipopo.require ("some.spec.ns",{"part":"A"})

Then the framework can satisfy it consistent with how @Requires works. I Don't need to know the exact factory. And the other machinery such as filter classes etc isn't necessary. 

:)

Thomas Calmant

unread,
Apr 13, 2017, 5:45:30 AM4/13/17
to ipopo...@googlegroups.com
Hi,

If I understand correctly, you want to instantiate a component which factory matches a set of requirements, without knowing the name of its factory, am I right ?

This is not how iPOPO is supposed to work, but a new set of decorators and a utility API could do the trick.

This could be done by having some kind of "@FactoryProperty" decorator, allowing to have the same name for two factories, with a distinct set of properties.
It would be necessary to declare a default factory (when instantiate() is called using the standard concepts) and to ensure that all factories with the same name have the same set of properties.

Cheers,
Thomas

Reply all
Reply to author
Forward
0 new messages