Instantiate component with property selectors?

瀏覽次數:10 次
跳到第一則未讀訊息

project2501

未讀,
2017年4月9日 下午6:52:542017/4/9
收件者: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

未讀,
2017年4月12日 上午10:50:502017/4/12
收件者: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

未讀,
2017年4月12日 上午10:53:202017/4/12
收件者: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

未讀,
2017年4月12日 上午11:11:402017/4/12
收件者: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

未讀,
2017年4月12日 上午11:49:322017/4/12
收件者: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

未讀,
2017年4月12日 中午12:31:002017/4/12
收件者: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

未讀,
2017年4月12日 下午1:03:102017/4/12
收件者: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

未讀,
2017年4月13日 清晨5:45:302017/4/13
收件者: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

回覆所有人
回覆作者
轉寄
0 則新訊息