The idea is to use the object from the service only as a prototype. So
we would retrieve the object from the service and clone it in some way.
If the action is defined in blueprint we could use the blueprint
prototype support for that.
Perhaps we can even do that without the service publishing. Is it
possible to react on the blueprint context that is created and check for
beans of type action?
That would make the syntax even simpler as we then only have the bean
definition.
Perhaps the cleanest way would be to use:
<actions xmlns="...">
<bean class="MyAction>
</bean>
</actions>
So we would use a BP namespace but inside use plain beans which people
understand easily. As the beans would be inlined I think they would even
default to prototype scope. Honestly this is not too far from what we
have now...
Btw. Is it possible to use a bean as a kind of template like in spring?
We have many cases where many commands need the same injections and
currently we have to define the injects for each bean.
Christian
Am 09.05.2012 17:24, schrieb Guillaume Nodet:
Second point, the action is purposely not published as an OSGi service
because it would have a big incompatible consequence, which is that the
action would have to be stateless and thread safe. Given the action
parameters are injected when the action is created, I don't really see how
it could be done.
On Wed, May 9, 2012 at 5:08 PM, Christian Schneider<[email protected]
wrote:
We currently either use the blueprint namespace or the AbstractCommand and
a service definition to define commands. This has some shortcomings:
- The blueprint namespace definition is a bit verbose and at first I did
not understand that actions in the xml can be injected like beans
Example:
<command-bundle
xmlns="http://karaf.apache.**org/xmlns/shell/v1.1.0<http://karaf.apache.org/xmlns/shell/v1.1.0>
">
<command>
<action class="org.apache.karaf.shell.**
commands.impl.WatchAction">
<property name="commandProcessor" ref="commandProcessor"/>
</action>
<completers>
<ref component-id="**commandCompleter" />
<null/>
</completers>
</command>
</command-bundle>
- The other way using AbstractCommand and a service def is even more
verbose and exposes a lot of implementation details like the
DefaultActionPreparator
<bean id="commandCompleter" class="org.apache.karaf.shell.**
console.completer.**CommandsCompleter"/>
<service>
<interfaces>
<value>org.apache.felix.**service.command.Function</**value>
<value>org.apache.karaf.shell.**console.CompletableFunction</**
value>
</interfaces>
<service-properties>
<entry key="osgi.command.scope" value="*"/>
<entry key="osgi.command.function" value="help"/>
</service-properties>
<bean class="org.apache.karaf.shell.**console.commands.**
BlueprintCommand">
<property name="blueprintContainer" ref="blueprintContainer"/>
<property name="blueprintConverter" ref="blueprintConverter"/>
<property name="actionId" value="help"/>
<property name="completers">
<list>
<bean class="org.apache.karaf.shell.**
console.completer.**CommandNamesCompleter"/>
</list>
</property>
</bean>
</service>
<bean id="help" class="org.apache.karaf.shell.**help.impl.HelpAction"
activation="lazy" scope="prototype">
<property name="provider" ref="helpSystem"/>
</bean>
So here is what I propose:
The first thing is to add a complerers property to the @Commands
annotation. This is the last bit we need to make sure the annotations
provide all metadata of an action.
Then the idea is to simply define the action as a blueprint bean and
publish it as an OSGi service. We then have an extender that adapts these
to the felix gogo commands.
So the blueprint code for the help example above would look like:
<service interface="org.apache.karaf.**shell.commands.Action">
<bean id="help" class="org.apache.karaf.shell.**help.impl.HelpAction"
activation="lazy" scope="prototype">
<property name="provider" ref="helpSystem"/>
</bean>
</service>
With the upcoming blueprint annotations we could simply annotate the
Action class and need no blueprint code at all. The above style would also
work much better with declarative services. If you look at the scr module
in karaf you see how complicated it is till now to create a command in ds.
One problem with the aproach is of course that the Action has to be
created per execution. So we need to find a good way to clone the Action
object. To a degree this problem is already present int the current
solution.
So what are the advantages:
- The user code only depends on some very few interfaces like Action and
the annotations. AbstractCommand and similar are not needed anymore and the
impls can be private
- The blueprint syntax is quite concise and does not need a special
namespace
- Using BP annotations the syntax is even more concise as no xml is
needed. This would not be possible with the current way
So what do you think?
Christian
--
Christian Schneider
http://www.liquid-reality.de
Open Source Architect
Talend Application Integration Division http://www.talend.com
--
Christian Schneider
http://www.liquid-reality.de
Open Source Architect
Talend Application Integration Division http://www.talend.com